import asyncio from time import sleep import abc from ws.server.ws_server_multi_user import WsServerMultiUser from components.sensor.tempSensorSim import TempSensorSim, ATemperatureSensor from components.plant.pot import Pot, APlant from components.actor.heater import Heater, AHeater from components.pid import kalman, temp_controller from ws.message import MsgIo, MessageDispatcher from utils.value import Value, ChangedFloat, ChangedInteger DT_CTRL = 0.1 DT_PARAMS = 1.0 class ATask: def __init__(self, interval): self.interval = interval @abc.abstractmethod def on_process(self): pass class TempSensorTask(ATask): def __init__(self, sensor: ATemperatureSensor, interval, msg_handler: MsgIo): ATask.__init__(self, interval) self.msg_handler = msg_handler msg_handler.set_recv_handler(self.recv) self.sensor = sensor def on_temp_changed(self, value): asyncio.create_task(self.send({'Temp': value})) async def recv(self, data): print(data) async def send(self, data): await self.msg_handler.send(data) async def on_process(self): print("{}: Started with interval {} s".format(self.msg_handler.get_key(), self.interval)) temp = ChangedFloat(self.on_temp_changed, prec=1) self.sensor.set_on_changed("temp", temp.set) while True: self.sensor.process() await asyncio.sleep(self.interval) class HeaterTask(ATask): def __init__(self, heater: AHeater, interval, msg_handler: MsgIo): ATask.__init__(self, interval) self.heater = heater self.interval = interval self.msg_handler = msg_handler msg_handler.set_recv_handler(self.recv) self.power_soll = 0 self.pulse_counter = 0 def actor(self, y): self.power_soll = max(0, 250 + self.heater.get_power_max() * y) def on_changed_active(self, is_activated): asyncio.create_task(self.send({'Activate': int(is_activated)})) def on_changed_power(self, power): asyncio.create_task(self.send({'Power': power})) async def recv(self, data): print(data) for pair in data.items(): if 'Power' in pair[0]: self.power_soll = pair[1] if 'Activate' in pair[0]: self.heater.activate(bool(pair[1])) async def send(self, data): await self.msg_handler.send(data) async def on_process(self): print("{}: Started with interval {} s".format(self.msg_handler.get_key(), self.interval)) await self.send({'Capabilities': {'Power': {'Min': 0, 'Max': self.heater.get_power_max()}}}) self.heater.set_on_changed('is_active', ChangedInteger(self.on_changed_active).set) self.heater.set_on_changed('power_eff', ChangedInteger(self.on_changed_power).set) self.heater.activate(False) pulse_period_s = 1 pulse_period_count = pulse_period_s/self.interval while True: if self.power_soll < self.heater.get_power_min(): self.heater.setPower(self.heater.get_power_min()) self.heater.activate(False) else: self.heater.setPower(self.power_soll) self.heater.activate(True) on_count = pulse_period_count if self.heater.get_power_min() > 0: on_count = pulse_period_count*min(1, self.power_soll/self.heater.get_power_min()) self.pulse_counter += 1 if self.pulse_counter >= pulse_period_count: self.pulse_counter = 0 if self.pulse_counter < on_count: self.heater.activate(True) else: self.heater.activate(False) self.heater.process() await asyncio.sleep(self.interval) class PotTask(ATask): def __init__(self, pot: APlant, interval, msg_handler: MsgIo): ATask.__init__(self, interval) self.msg_handler = msg_handler msg_handler.set_recv_handler(self.recv) self.plant = pot def on_changed_power(self, value): asyncio.create_task(self.send({'Power': value})) def on_changed_temp(self, value): asyncio.create_task(self.send({'Temp': value})) async def recv(self, data): print(data) for key in data: print(key) async def send(self, data): await self.msg_handler.send(data) async def on_process(self): print("{}: Started with interval {} s".format(self.msg_handler.get_key(), self.interval)) self.plant.set_on_changed('power_actual', ChangedInteger(self.on_changed_power).set) self.plant.set_on_changed('temp', ChangedFloat(self.on_changed_temp, prec=1).set) while True: self.plant.process() await asyncio.sleep(self.interval) class TcTask(ATask): def __init__(self, tc: temp_controller.TempController, interval, msg_handler: MsgIo): ATask.__init__(self, interval) self.tc = tc self.msg_handler = msg_handler msg_handler.set_recv_handler(self.recv) def on_state_changed(self, value): print ("State change to {}".format(value)) asyncio.create_task(self.send({'State': str(value)})) def on_temp_soll_changed(self, value): print ("Temp soll change to {}".format(value)) asyncio.create_task(self.send({'Soll': {'Temp': value}})) def on_rate_soll_curr_changed(self, value): print ("Rate soll change to {}".format(value)) asyncio.create_task(self.send({'Soll': {'Rate': {'Current': value}}})) def on_rate_soll_set_changed(self, value): print ("Rate soll change to {}".format(value)) asyncio.create_task(self.send({'Soll': {'Rate': {'Set': value}}})) def on_temp_ist_changed(self, value): print ("Temp ist change to {}".format(value)) asyncio.create_task(self.send({'Ist': {'Temp': value}})) def on_rate_ist_changed(self, value): print ("Rate ist change to {}".format(value)) asyncio.create_task(self.send({'Ist': {'Rate': value}})) async def recv(self, msg): print(msg) for key in msg.keys(): if 'Soll' in key: submsg = msg['Soll'] for subkey in submsg.keys(): if 'Temp' in subkey: self.tc.set_theta_soll(submsg['Temp']) if 'Rate' in subkey: self.tc.set_heatrate_soll(submsg['Rate']) async def send(self, data): await self.msg_handler.send(data) async def on_process(self): print("{}: Started with interval {} s".format(self.msg_handler.get_key(), self.interval)) self.tc.set_on_changed('state', self.on_state_changed) self.tc.set_on_changed('theta_ist', ChangedFloat(self.on_temp_ist_changed, prec=1).set) self.tc.set_on_changed('heatrate_ist', ChangedFloat(self.on_rate_ist_changed, prec=1).set) self.tc.set_on_changed('theta_soll_set', ChangedFloat(self.on_temp_soll_changed, prec=1).set) self.tc.set_on_changed('heatrate_soll', ChangedFloat(self.on_rate_soll_curr_changed, prec=1).set) self.tc.set_on_changed('heatrate_soll_set', ChangedFloat(self.on_rate_soll_set_changed, prec=1).set) self.tc.set_theta_soll(20.0) self.tc.set_heatrate_soll(1.0) while True: self.tc.process() await asyncio.sleep(self.interval) class TaskManager: def __init__(self): self.tasks = [] def add(self, task: ATask): self.tasks.append(task) def start(self): funcs = [] for task in self.tasks: funcs.append(task.on_process()) return asyncio.gather(*funcs) async def asleep(time): await asyncio.sleep(time) if __name__ == '__main__': if 0: taskmgr = PeriodicUpdaterThreaded() taskmgr.start("localhost", 8765) bg_thread = Thread(target=taskmgr.loop.run_forever) bg_thread.setDaemon(True) bg_thread.start() else: dispatcher = MessageDispatcher() server = WsServerMultiUser(listener=dispatcher) taskmgr = TaskManager() # Sensor sensor = TempSensorSim() taskmgr.add(TempSensorTask(sensor, DT_CTRL, dispatcher.msgio_get("Sensor"))) # Plant pot_params = { "dt" : DT_PARAMS, "theta" : 20, "C" : 4190, "M" : 20, "L" : 0.05, "Td" : 12, "kn" : 0.2 } pot = Pot(pot_params, 20) pot.set_on_changed("temp", ChangedFloat(sensor.set_fake_temp, prec=3).set) taskmgr.add(PotTask(pot, DT_CTRL, dispatcher.msgio_get("Pot"))) # Heater heater = Heater() heater.set_on_changed("power_eff", ChangedFloat(pot.setPower, prec=0).set) heater_task = HeaterTask(heater, DT_CTRL, dispatcher.msgio_get("Heater")) taskmgr.add(heater_task) # Temperature Controller tc_params = { "Hold": { "dt": DT_PARAMS, "kp": 0.5, "ki": 0.0, "kd": 0.0, "kt": 0.0 }, "Heat": { "dt": DT_PARAMS, "kp": 0.1, "ki": 0.01, "kd": 0.0, "kt": 1.0 } } # Kalman Filter kalman_params = { "dt" : DT_PARAMS, "var_P" : 1, "var_Q" : 0.0001, "var_R" : 1 } tc = temp_controller.TempController(tc_params, kalman_params) tc.set_on_changed("y", heater_task.actor) tc_task = TcTask(tc, DT_CTRL, dispatcher.msgio_get("TempCtrl")) taskmgr.add(tc_task) sensor.set_on_changed("temp", ChangedFloat(tc.set_theta_ist, prec=2).set) # Message dispatcher h_dispatcher = taskmgr.start() h_server = server.listen("localhost", 8765) asyncio.gather(h_dispatcher, h_server) server.run_forever() while True: print("Hallo") sleep(1) {"+":"Pot"} {"+":"Heater"} {"Heater": {"Power": 2000, "Activate": 1}}