Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F86469243
ems_main.py
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Oct 6, 16:32
Size
11 KB
Mime Type
text/x-python
Expires
Tue, Oct 8, 16:32 (2 d)
Engine
blob
Format
Raw Data
Handle
21428500
Attached To
R3852 EMS for Smart-Building
ems_main.py
View Options
__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
"""
pass
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
Log In to Comment