94 lines
3.6 KiB
Python
94 lines
3.6 KiB
Python
from util import pos, clamp
|
|
import parameters
|
|
from time import time, sleep
|
|
import zmq
|
|
import syslab
|
|
from syslab.comm.LogUtils import setup_event_logger
|
|
logging = setup_event_logger()
|
|
|
|
|
|
### Parameters
|
|
# If soc is below this limit, divert all power to the battery.
|
|
base_soc_lower_limit = 0.2
|
|
# If soc is above this limit, divert all power to the mobile load.
|
|
base_soc_upper_limit = 0.8
|
|
# This much renewable production shifts our soc_lower_limit down by 0.1 and soc_upper_limit up by 0.1.
|
|
# I.e. if there is a lot of renewable production, the range over which we split between battery and
|
|
# load widens.
|
|
base_renewable_shift = 10.0
|
|
|
|
|
|
# # Variables
|
|
# Controller variables
|
|
x_battery = 0.5 # Default splitting factor
|
|
x_load = 0.5 # Default splitting factor
|
|
# Info on battery state
|
|
battery_soc = 0.5 # Default SOC (= state of charge)
|
|
|
|
soc_lower_limit = 0.2
|
|
soc_upper_limit = 0.8
|
|
|
|
# # Communication
|
|
# Handle the sockets we need
|
|
# Make a context that we use to set up sockets
|
|
context = zmq.Context()
|
|
|
|
# Set up a socket we can use to broadcast splitting factors on
|
|
splitting_out_socket = context.socket(zmq.PUB)
|
|
splitting_out_socket.bind(f"tcp://*:{parameters.SUPERVISOR_PORT}")
|
|
|
|
# Set up a socket to subscribe to the battery's soc
|
|
soc_in_socket = context.socket(zmq.SUB)
|
|
soc_in_socket.connect(f"tcp://{parameters.BATTERY_SOC_IP}:{parameters.BATTERY_SOC_PORT}")
|
|
|
|
# Ensure we only see message on the battery's soc
|
|
soc_in_socket.subscribe(parameters.TOPIC_BATTERY_SOC)
|
|
|
|
### Unit connections
|
|
# TODO step 1.3: Set up connection to the units
|
|
|
|
try:
|
|
while True:
|
|
try:
|
|
# Try to connect the the battery.
|
|
# If we have a connection to the battery, get its current soc.
|
|
# If none have come in, continue with previous soc.
|
|
# We put this in a while-loop to ensure we empty the queue each time,
|
|
# so we always have the latest value.
|
|
while True:
|
|
# Receive the latest splitting factor
|
|
incoming_str = soc_in_socket.recv_string(flags=zmq.NOBLOCK)
|
|
# The incoming string will look like "batt_split;0.781",
|
|
# so we split it up and take the last bit forward.
|
|
battery_soc = float(incoming_str.split(" ")[-1])
|
|
logging.info(f"New battery soc: {battery_soc}")
|
|
except zmq.Again as e:
|
|
# No (more) new messages, move along
|
|
pass
|
|
|
|
# Poll the grid connection to get the current production of renewables.
|
|
wind_p = 4.0 # TODO Task 1.3: Change into syslab connection. Remember that the measurements need to be collected directly from the units since vswitchboard is not working
|
|
solar_p = 7.0
|
|
logging.info(f"Current renewable production: {wind_p + solar_p} kW.")
|
|
|
|
soc_lower_limit = base_soc_lower_limit - (wind_p + solar_p) / base_renewable_shift / 10.0
|
|
soc_upper_limit = base_soc_upper_limit + (wind_p + solar_p) / base_renewable_shift / 10.0
|
|
|
|
# Calculate a new splitting factor for the battery.
|
|
x_battery = clamp(0, (soc_upper_limit - battery_soc)/(soc_upper_limit - soc_lower_limit), 1)
|
|
|
|
# If anything is not taken by the battery, put it in the load.
|
|
x_load = 1 - x_battery
|
|
|
|
# Publish the new splitting factors.
|
|
splitting_out_socket.send_string(f"{parameters.TOPIC_BATTERY_SPLITTING} {x_battery:.06f}")
|
|
splitting_out_socket.send_string(f"{parameters.TOPIC_LOAD_SPLITTING} {x_load:.06f}")
|
|
logging.info(f"Battery split: {x_battery:.03f}; Load split: {x_load:.03f}")
|
|
|
|
# Loop once more in a second
|
|
sleep(1)
|
|
finally:
|
|
# Clean up by closing our sockets.
|
|
soc_in_socket.close()
|
|
splitting_out_socket.close()
|