Page MenuHomec4science

ems_main.py
No OneTemporary

File Metadata

Created
Thu, Aug 29, 17:20

ems_main.py

__author__ = 'Olivier Van Cutsem'
from threading import Thread
from ems_config import *
from building_data_management.bdms_main import BuildingDataManagementSystem
from building_data_management.signal_and_constraint_management.signal_data import PiecewiseConstantSignal
from building_data_management.category_management.category_config import *
from rtevents_interface.rtevents_interf import *
from ems_gui.gui import *
import json
from abc import abstractmethod
import time
from multiprocessing import Queue
from building_data_management.ambient_data import EnvironmentalDataManagement
from building_data_management.room_data import BuildingRoomData
## Various strategies
class EnergyManagementSystem(Thread):
def __init__(self, in_q, out_q, gui_q):
"""
Initialize ClusteringManagementSystem object.
Read messages from the BMS interface bubble messages through a Queue
"""
Thread.__init__(self)
self.in_stream = in_q
self.out_stream = out_q
self.gui_data = gui_q
## Clustering and Data Structure system
self.building_data = BuildingDataManagementSystem() # The empty BD-MS
## Environmental data storage
self.environment_data = EnvironmentalDataManagement()
## EMS running mode and time configuratin
# In RT control mode, keep track of the current time ; In simulation mode, keep track of the simulation time
if EMS_MODE != EMS_MODE_VE_SIMULATION:
self.current_time = time.time()
else:
self.current_time = SIMULATION_DAY * 24 * 60 * 60
if EMS_MODE == EMS_MODE_VE_SIMULATION:
self.simu_param = None
self.simu_status_run = True # run the simulation
self.last_ems_step = self.current_time
def run(self):
"""
EMS main loop:
@init: BMS request for CMS data structure filling
@main_loop: check the incoming message to update CMS and then run the EMS control step
"""
# INITIALIZATION of the models
ret_code = self.init_cms()
if ret_code != 0:
print("An error occurred during CMS initialization, shutting down EMS thread ...")
return
else:
print("CMS initialized with success")
while True:
# This boolean decides whether to run the next EMS control step or not within this loop iteration
run_ems_step = False
if EMS_MODE == EMS_MODE_RT_SAMPLED: # The EMS is in Sampled mode
if time.time() - self.last_ems_step >= EMS_TIME_STEP:
run_ems_step = True
# CHECK FOR NEW MESSAGE
try:
msg = self.in_stream.get(EMS_MODE == EMS_MODE_VE_SIMULATION) # block in simulation mode
except Queue.empty():
msg = None
if msg is not None:
if RT_EVENT_MSG_TYPE_KEY in msg:
if msg[RT_EVENT_MSG_TYPE_KEY] == RT_EVENT_MSG_TYPE_MEASURE_STATUS: # new measure/status for the CMS
if EMS_MODE == EMS_MODE_RT_EVENT_DRIVEN:
run_ems_step = True
print("[{1}s] EMS received: {0}".format(msg, self.current_time))
# Process this event in order to update the appropriate structures
self.decode_rtevent(msg)
elif msg[RT_EVENT_MSG_TYPE_KEY] == RT_EVENT_MSG_TYPE_SIMULATION_SYNQ: # Synchronisation msg for simu
# Analyse the incoming simulation-related message
self.decode_simulation_event(msg)
if self.simu_status_run is True:
run_ems_step = True
# Update the interface data
self.gui_data.put({EMS_gui.MSG_TYPE_KEY: EMS_gui.MSG_TYPE_ADD,
EMS_gui.MSG_CONTENT_DATA: self.print_state(),
EMS_gui.MSG_CONTENT_TIME: self.current_time})
# RUN THE EMS CONTROL STEP
if run_ems_step:
ems_commands = self.update()
if ems_commands is not None:
for command in ems_commands:
self.out_stream.put(command)
# in case of simulation, send the READY signal
ready_signal = {EMS_DOWNSTREAM_MSG_TYPE: EMS_DOWNSTREAM_SIMU_READY}
self.out_stream.put(ready_signal)
if EMS_MODE_VE_SIMULATION == EMS_MODE_VE_SIMULATION:
self.current_time += SIMULATION_TIME_STEP
##########################
######### INITIALIZATION #########
##########################
def init_cms(self):
"""
Fill the empty CMS structure with data coming from the BMS
:return: 0 if everything went right ; non-zero value otherwise
"""
# Initialize the building data structure through the BMS API
self.building_data.initFromBMS()
return 0
##############################
######### MESSAGE PROCESSING #########
##############################
def decode_rtevent(self, msg):
# Type of entity: sensor or actuator ?
type_sender = msg[RT_EVENT_SENDER_TYPE]
#print("processing {0}".format(msg))
if type_sender == RT_EVENT_SENDER_TYPE_SENSOR:
sensor_id = msg[RT_EVENT_SENDER_ID]
sensing_type = msg[RT_EVENT_QUANTITY_TYPE]
comfort_value = msg[RT_EVENT_VALUE]
if sensing_type in EMS_LIST_COMFORT_QUANTITIES:
# Update the corresponding room
self.building_data.updateComfortRoom(sensor_id=sensor_id,
type_comfort=sensing_type,
value=comfort_value)
elif sensing_type in EMS_LIST_ENERGY_RELATED_QUANTITIES:
# Update the corresponding energy-related entity
self.building_data.updateEnergyRelatedEntity(sensor_id=sensor_id,
type_energy=sensing_type,
value=comfort_value)
elif type_sender == RT_EVENT_SENDER_TYPE_ACTUATOR:
actuator_id = msg[RT_EVENT_SENDER_ID]
comfort_type = msg[RT_EVENT_QUANTITY_TYPE]
comfort_value = msg[RT_EVENT_VALUE]
pass #todo
def decode_simulation_event(self, msg_simu):
"""
Decode the parameters sent for the simulation
:param msg_simu:
:return:
"""
self.simu_param = msg_simu[RT_EVENT_SIMULATION_PARAM_KEY]
if self.simu_param is not None:
if RT_EVENT_SIMULATION_PARAM_STOP in self.simu_param:
self.simu_status_run = False
print("STOP SIMULATION !")
self.gui_data.put({EMS_gui.MSG_TYPE_KEY: EMS_gui.MSG_TYPE_PLOT})
else:
self.simu_status_run = True
def battery_set_point(self, s_id, new_value):
storage_command = {EMS_DOWNSTREAM_MSG_TYPE: EMS_DOWNSTREAM_ENERGY_ENTITY_COMMAND,
EMS_DOWNSTREAM_ENERGY_ENTITY_COMMAND_TYPE: EMS_ENERGY_power,
EMS_DOWNSTREAM_MSG_ENTITY_TYPE: EMS_CATEGORY_ENTITY_STORAGE,
EMS_DOWNSTREAM_MSG_ENTITY_ID: s_id,
EMS_DOWNSTREAM_MSG_PAYLOAD: {EMS_ENERGY_power: new_value}}
return storage_command
def hvac_set_point(self, l_id, new_value):
hvac_command = {EMS_DOWNSTREAM_MSG_TYPE: EMS_DOWNSTREAM_ENERGY_ENTITY_COMMAND,
EMS_DOWNSTREAM_ENERGY_ENTITY_COMMAND_TYPE: EMS_ENERGY_power,
EMS_DOWNSTREAM_MSG_ENTITY_TYPE: EMS_CATEGORY_ENTITY_LOAD,
EMS_DOWNSTREAM_MSG_ENTITY_ID: l_id,
EMS_DOWNSTREAM_MSG_PAYLOAD: {EMS_ENERGY_power: new_value}}
return hvac_command
##########################
######### CORE FUNCTIONS #########
##########################
@abstractmethod
def update(self):
"""
This abstract method runs the main energy management algorithm.
:return: a set of commands for the flexible (controllable) building entities
"""
return []
def get_environment_data(self, type_data, time_data):
"""
TODO
"""
(t_cur, t_hor, t_step) = time_data
# TODO: Make it dynamic ! for the moment the raw data are encoded in a vector
if type_data == EMS_ENV_DATA_IRR:
data_raw = self.environment_data.environmentIrr
elif type_data == EMS_ENV_DATA_TEMP:
data_raw = self.environment_data.environmentTemp
elif type_data == EMS_ENV_DATA_ELEC_PRICE:
data_raw = self.environment_data.elecPrice
else:
return None
sig_object = PiecewiseConstantSignal(data_raw['t'], data_raw['v'])
return sig_object.get_interval_val(t_cur, t_cur+t_hor, t_step)
def get_elec_price(self, time_data):
"""
TODO
"""
return self.get_environment_data('electricity_price', time_data)
def print_state(self):
"""
Return a structured dictionary describing the actual state of the building
:return:
"""
state = EMS_gui.get_data_format()
# Loads, generation and storage
grid_power = 0.0
_loads = self.building_data.get_entity_list(EMS_CATEGORY_ENTITY_LOAD)
_stor = self.building_data.get_entity_list(EMS_CATEGORY_ENTITY_STORAGE)
_gen = self.building_data.get_entity_list(EMS_CATEGORY_ENTITY_GENERATION)
for (l_id, l_obj) in _loads:
if l_obj.current_power is not None:
#print("{0}: {1}".format(l_obj.name, l_obj.current_power))
grid_power += l_obj.current_power
state[EMS_gui.MSG_EMS_STATE_STRUCT_ENERGY][EMS_CATEGORY_ENTITY_LOAD][l_obj.name] = l_obj.current_power
for (s_id, s_obj) in _stor:
if s_obj.current_power is not None:
grid_power += s_obj.current_power
state[EMS_gui.MSG_EMS_STATE_STRUCT_ENERGY][EMS_CATEGORY_ENTITY_STORAGE][EMS_ENERGY_power][s_obj.name] = s_obj.current_power
if s_obj.current_soc is not None:
state[EMS_gui.MSG_EMS_STATE_STRUCT_ENERGY][EMS_CATEGORY_ENTITY_STORAGE][EMS_ENERGY_soc][s_obj.name] = s_obj.current_soc
for (g_id, g_obj) in _gen:
if g_obj.current_power is not None:
#print("{0}: {1}".format(g_obj.name, g_obj.current_power))
grid_power += g_obj.current_power
state[EMS_gui.MSG_EMS_STATE_STRUCT_ENERGY][EMS_CATEGORY_ENTITY_GENERATION][g_obj.name] = g_obj.current_power
# Room comfort
for _r in self.building_data.room_list:
room_name = _r.name
state[EMS_gui.MSG_EMS_STATE_STRUCT_COMFORT][room_name] = {} # temp, etc
list_of_comfort = BuildingRoomData.TYPE_COMFORT_LIST
for type_comfort in list_of_comfort:
v = _r.get_comfort_value(type_comfort)
if v is not None:
state[EMS_gui.MSG_EMS_STATE_STRUCT_COMFORT][room_name][type_comfort] = v
# Electricity price
time_data = (self.current_time, self.current_time+EMS_TIME_STEP, EMS_TIME_STEP)
price_vector = self.get_elec_price(time_data)
state[EMS_gui.MSG_EMS_STATE_STRUCT_ENV][EMS_ENV_DATA_ELEC_PRICE] = price_vector[0]
state[EMS_gui.MSG_EMS_STATE_STRUCT_ENV][EMS_ENV_DATA_GRID] = grid_power
print(state)
return state

Event Timeline