Commit 0d3e2057 authored by Winstead, Chris's avatar Winstead, Chris
Browse files

initial commit

parent 5263ea0f
Loading
Loading
Loading
Loading
+261 −0
Original line number Diff line number Diff line
import logging
import sys
from datetime import datetime
from volttron.platform.agent import utils
from volttron.platform.vip.agent import Core, PubSub
from volttron.platform.messaging import headers as headers_mod
from pnnl.pubsubagent.pubsub.agent import SynchronizingPubSubAgent
import time
import math
import json

utils.setup_logging()
log = logging.getLogger(__name__)

class Tstat():

    def __init__(self, devID, current_priority, is_on, switch_ok):
		self.devID = devID
		self.priority = current_priority
		self.is_on = is_on
		self.can_switch = switch_ok


class PBCcontrolAgent(SynchronizingPubSubAgent):

    def __init__(self, config_path, **kwargs):
        super(PBCcontrolAgent, self).__init__(config_path, **kwargs)

        zone_cfg = json.load(open('./zones.config','r'))
        self.numZones = zonecfg["numZones"]
        self.maxZones = zonecfg["maxZones"]

        self.buildings=['building'+str(i) for i in range(0,self.numZones)]
        self.setpoints=["CoolSched"+str(i) for i in range(0,self.numZones)]

        self.t0 = [0 for i in self.buildings]
        self.control = [30.0 for i in self.buildings]
        self.ZNcount = 0
        self.temps = [None for i in range(0,self.numZones)]
        self.updated = []

        self.all_updates = [i for i in range(0,self.numZones)]

    @Core.receiver('onsetup')
    def setup(self, sender, **kwargs):
        super(PBCcontrolAgent, self).setup(sender, **kwargs)
        print('setup')

    @PubSub.subscribe('pubsub','temps')
    def onUpdateTopic2(self, peer, sender, bus, topic, headers, message):
        for idx,i in enumerate(self.buildings):
            if topic == 'temps/'+str(i):
                newTemp = message[0]['temp']

                if idx not in self.updated and newTemp!=self.temps[idx]:
                    self.temps[idx] = newTemp
                    self.updated.append(idx)
                    self.ZNcount += 1
                    self.t0[idx] += 1 

            if self.ZNcount == self.numZones:
                self.ZNcount = 0
                self.updated = []

                control2 = self.run_control(self.temps, self.t0, self.control)

                for idx in range(0, len(control2)):
                    if control2[idx] != self.control[idx]:
                        self.t0[idx] = 0
    
                self.control = control2[:]

                for ids in range(0,self.numZones):
                    self.vip.pubsub.publish('pubsub', 'setp/'+str(self.buildings[ids]),
                                            {'header':'no'}, [self.control[ids], 1])
        

    def calculate_priority(self, temp):
		
        min_prior = 0
        max_prior = 10

        tempData = temp*(9.0/5.0)+32.0
        setP = 80.0
		
        current_priority = 0
        temp_per_priority = 1.5/(max_prior-min_prior)
        temp_diff = tempData - setP

        current_priority = min_prior+math.ceil(temp_diff/temp_per_priority);

        if (current_priority > max_prior):
            current_priority = max_prior

        if (current_priority < min_prior):
            current_priority = min_prior


        #was causing an issue distinguishing between floats and ints
        if(current_priority == max_prior):
            current_priority = int(current_priority)

        return current_priority

    def run_control(self, temps, t0, is_on):
            
        equip = []
        ctrl = is_on[:]

        for idx, t in enumerate(temps):
            priority = self.calculate_priority(t)

            tmp_isOn = is_on[idx]
            if tmp_isOn == 35.0:
                tmp_isOn = 0
            elif tmp_isOn == 16.0:
                tmp_isOn = 1
    
            sw = t0[idx]
            
            if sw > 1:
                sw = 1
            else:
                sw = 0
            
            equip.append(Tstat(idx+1, priority, tmp_isOn, sw))

        tmp = self.run_scheduler(equip, self.maxZones)

        for idx in range(len(tmp)):
            if tmp[idx] == 'activate':
                ctrl[idx] = 16.0
            elif tmp[idx] == 'shutdown':
                ctrl[idx] = 35.0
            
        return ctrl

    # Activate or deactivate equipment according to the control rule
    def run_scheduler(self, equip, N):

        status = []

        for i in range(0,len(equip)):
            status.append(None)

        skip_list = [] 
        activate_list = []
        deactivate_list = []
        count = 0
        active_count = 0
        pending_active = 0
        pending_deactive = 0
        MIN_PRIORITY = 0
        MAX_PRIORITY = 10
	
        switched_device = False

        # Scan all of the devices, discarded devices that fail to respond
        if not equip:
            assert(False)

        # Sort the devices by priority
        equip.sort(key = lambda tstat: tstat.priority, reverse=True)

        for i in range(0,len(equip)):
            for j in range(0, len(equip)):
                if equip[i].priority == equip[j].priority and i != j:
                    if equip[i].can_switch > equip[j].can_switch:
                        equip[i], equip[j] = equip[j],equip[i]
                    else:
                        pass
                else:
                    pass

        if equip[0].priority < equip[len(equip)-1].priority:
            assert(False)

        active_count = 0
        for tstat in equip:
            if tstat.is_on and not tstat.can_switch:
                active_count+=1	

        for tstat in equip:
            if tstat.is_on:
                if tstat.can_switch:
                    if tstat.priority != MIN_PRIORITY:
                        if active_count < N or tstat.priority == MAX_PRIORITY:
                            activate_list.append(tstat)
                            active_count+=1
                        elif active_count >= N and tstat.priority!=MAX_PRIORITY:
                            deactivate_list.insert(0,tstat)
                    elif tstat.priority == MIN_PRIORITY:
                        deactivate_list.insert(0,tstat)

            elif not tstat.is_on:
                if tstat.can_switch:			
                    if tstat.priority != MIN_PRIORITY:
                        if active_count < N or tstat.priority == MAX_PRIORITY:
                            activate_list.append(tstat)
                            active_count+=1

        if deactivate_list and len(deactivate_list) != 1 and \
            (deactivate_list[0].priority > deactivate_list[len(deactivate_list)-1].priority):
            assert(False)
	
        if activate_list != [] and (len(activate_list) != 1 and \
            activate_list[0].priority < activate_list[len(activate_list)-1].priority):
            assert(False)

        # Shutdown priority zero devices and as many others as are needed to
        # enable the new devices to run or get below our limit
        for tstat in deactivate_list:

            if tstat.priority >= MAX_PRIORITY:
                assert(False);
            status[tstat.devID-1] = 'shutdown'
		
            switched_device = True
	
	    # Active as many devices as we can
        for tstat in activate_list:

            status[tstat.devID-1] = 'activate'		
            switched_device = True

        my_slot = 0
        for tstat in equip:

            my_slot =+ 1

            if (my_slot > N and tstat.priority < MAX_PRIORITY \
                and tstat.is_on == 1 and tstat.can_switch == 1):
		
                slot = 0
                for other in equip:
			
                    slot =+ 1
                    assert(other.priority >= tstat.priority)
                    if (slot <= N):
				
                        assert(other != tstat)
                        assert(other.priority == tstat.priority \
                                or other.is_on or other.can_switch == 0)
				
                    else: 
                        break		

        return status


def main(argv=sys.argv):
    '''Main method called by the eggsecutable.'''
    try:
        utils.vip_main(PBCcontrolAgent)
    except Exception as e:
        log.exception(e)


if __name__ == '__main__':
    # Entry point for script
    sys.exit(main())
+1 −0
Original line number Diff line number Diff line
{"maxZones": 72, "numZones": 146}
 No newline at end of file
+0 −0

Empty file added.

+74 −0
Original line number Diff line number Diff line
# -*- coding: utf-8 -*- {{{
# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et:
#
# Copyright (c) 2016, Battelle Memorial Institute
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
#    list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and documentation are those
# of the authors and should not be interpreted as representing official policies,
# either expressed or implied, of the FreeBSD Project.
#

# This material was prepared as an account of work sponsored by an
# agency of the United States Government.  Neither the United States
# Government nor the United States Department of Energy, nor Battelle,
# nor any of their employees, nor any jurisdiction or organization
# that has cooperated in the development of these materials, makes
# any warranty, express or implied, or assumes any legal liability
# or responsibility for the accuracy, completeness, or usefulness or
# any information, apparatus, product, software, or process disclosed,
# or represents that its use would not infringe privately owned rights.
#
# Reference herein to any specific commercial product, process, or
# service by trade name, trademark, manufacturer, or otherwise does
# not necessarily constitute or imply its endorsement, recommendation,
# r favoring by the United States Government or any agency thereof,
# or Battelle Memorial Institute. The views and opinions of authors
# expressed herein do not necessarily state or reflect those of the
# United States Government or any agency thereof.
#
# PACIFIC NORTHWEST NATIONAL LABORATORY
# operated by BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY
# under Contract DE-AC05-76RL01830

#}}}

from setuptools import setup, find_packages


#get environ for agent name/identifier
packages = find_packages('.')
package = packages[0]

setup(
    name = package,
    version = "0.1",
    install_requires = ['volttron','./zones.config'],
    packages = packages,
    entry_points = {
        'setuptools.installation': [
            'eggsecutable = ' + package + '.agent:main',
        ]
    }
)
+0 −0

Empty file added.

Loading