diff --git a/__simulation__/devices.py b/__simulation__/devices.py index 25a6f69..5c9b261 100644 --- a/__simulation__/devices.py +++ b/__simulation__/devices.py @@ -760,28 +760,44 @@ class gui_radiator_valve(base): # TEMP_RANGE = [10, 30] # - KEY_BOOST_LED = "boost_led" - KEY_TEMPERATURE_SETPOINT = "temperature_setpoint" + KEY_TIMER = "timer" + KEY_TEMPERATURE = "temperature" + KEY_SETPOINT_TEMP = "setpoint_temp" + KEY_SETPOINT_TO_DEFAULT = "setpoint_to_default" + KEY_BOOST = 'boost' # COMMANDS = [ + "get_temperature", "get_temperature_setpoint", "set_temperature_setpoint", - "get_boost_state", "trigger_boost", + "trigger_boost", "trigger_setpoint_to_default" ] def __init__(self, mqtt_client, topic): super().__init__(mqtt_client, topic) - self.add_callback(self.KEY_TEMPERATURE_SETPOINT, self.print_formatted, None) - self.add_callback(self.KEY_BOOST_LED, self.print_formatted, None) + self.add_callback(self.KEY_SETPOINT_TEMP, self.print_formatted, None) + self.add_callback(self.KEY_TIMER, self.print_formatted, None) + # + self.store_data(**{ + self.KEY_TEMPERATURE: 20.7, + self.KEY_SETPOINT_TEMP: 20, + self.KEY_TIMER: 0, + }) def __rx__(self, client, userdata, message): - if message.topic.startswith(self.topic) and message.topic.endswith("/set"): - payload = payload_filter(message.payload) - if type(payload) == bool: - self.store_data(**{self.KEY_BOOST_LED: payload}) + value = payload_filter(message.payload) + if message.topic.startswith(self.topic) and message.topic.endswith('/set'): + targetkey = message.topic.split('/')[-2] + if targetkey in self.data.keys(): + self.store_data(**{targetkey: value}) else: - self.store_data(**{self.KEY_TEMPERATURE_SETPOINT: payload}) - else: - print(message.topic) + print("Unknown key %s in %s::%s" % (targetkey, message.topic, self.__class__.__name__)) + elif message.topic == self.topic + '/get': + self.__tx__(None) + + def send(self, key, data): + if data is not None: + topic = self.topic + '/' + key + self.mqtt_client.send(topic, json.dumps(data)) def command(self, command): try: @@ -790,27 +806,35 @@ class gui_radiator_valve(base): value = None if command in self.COMMANDS: if command == self.COMMANDS[0]: - self.print_formatted(self, self.KEY_TEMPERATURE_SETPOINT, self.data.get(self.KEY_TEMPERATURE_SETPOINT)) + self.print_formatted(self, self.KEY_TEMPERATURE, self.data.get(self.KEY_TEMPERATURE)) elif command == self.COMMANDS[1]: - ################################### TEMPORARY!!! ################################### - self.mqtt_client.send(self.topic + "/feedback/set", command_float_value(value)) - ################################### TEMPORARY!!! ################################### + self.print_formatted(self, self.KEY_SETPOINT_TEMP, self.data.get(self.KEY_SETPOINT_TEMP)) elif command == self.COMMANDS[2]: - self.print_formatted(self, self.KEY_BOOST_LED, self.data.get(self.KEY_BOOST_LED)) + self.send(self.KEY_SETPOINT_TEMP, command_float_value(value)) elif command == self.COMMANDS[3]: - ################################### TEMPORARY!!! ################################### - self.mqtt_client.send(self.topic + "/state", json.dumps(True)) - ################################### TEMPORARY!!! ################################### + self.send(self.KEY_BOOST, True) + elif command == self.COMMANDS[4]: + self.send(self.KEY_SETPOINT_TO_DEFAULT, True) def print_formatted(self, device, key, value): devicename = ' - '.join(self.topic.split('/')[1:]) - if key == self.KEY_BOOST_LED: - led = green_led() if value else grey_led() - print(10 * ' ' + led + 9 * ' ' + COLOR_GUI_ACTIVE + devicename + " (Boost)" + colored.attr("reset")) - elif key == self.KEY_TEMPERATURE_SETPOINT: - perc = 100 * (value - self.TEMP_RANGE[0]) / (self.TEMP_RANGE[1] - self.TEMP_RANGE[0]) + if key in [self.KEY_TEMPERATURE, self.KEY_SETPOINT_TEMP, self.KEY_TIMER]: + if key in [self.KEY_TEMPERATURE, self.KEY_SETPOINT_TEMP]: + perc = 100 * (value - self.TEMP_RANGE[0]) / (self.TEMP_RANGE[1] - self.TEMP_RANGE[0]) + info = " (Temperature)" if key == self.KEY_TEMPERATURE else " (Setpoint)" + else: + try: + perc = 100 * value / 60 + except TypeError: + value = 0 + perc = 0 + info = " (Timer)" perc = 100 if perc > 100 else perc perc = 0 if perc < 0 else perc - sys.stdout.write(COLOR_GUI_ACTIVE + '\u03d1' + percent_bar(perc)) - sys.stdout.write("%4.1f°C" % value + 3 * " ") - print(devicename + colored.attr("reset")) + + sys.stdout.write(COLOR_GUI_ACTIVE) + if key == self.KEY_TIMER: + sys.stdout.write('T' + percent_bar(perc) + "%4.1fmin" % value + 2 * " ") + else: + sys.stdout.write('\u03d1' + percent_bar(perc) + "%4.1f°C" % value + 3 * " ") + print(devicename + info + colored.attr("reset")) diff --git a/__simulation__/rooms.py b/__simulation__/rooms.py index 6ef1de0..cf82663 100644 --- a/__simulation__/rooms.py +++ b/__simulation__/rooms.py @@ -168,10 +168,8 @@ class ffe_sleep(base): self.led_array.add_channel_name(gui_led_array.KEY_LED_0, "Main Light") self.led_array.add_channel_name(gui_led_array.KEY_LED_1, "Bed Light Dirk") # - self.heating_valve = brennenstuhl_radiator_valve(mqtt_client, config.TOPIC_FFE_SLEEP_RADIATOR_VALVE_ZIGBEE) - self.gui_heating_valve = gui_radiator_valve(mqtt_client, "gui/ffe_ts_sleep_madi") - self.gui_heating_valve_boost_led = gui_radiator_valve(mqtt_client, "gui/ffe_bl_sleep_madi") - self.gui_heating_valve_boost_button = gui_radiator_valve(mqtt_client, "gui/ffe_bo_sleep_madi") + self.radiator_valve = brennenstuhl_radiator_valve(mqtt_client, config.TOPIC_FFE_SLEEP_RADIATOR_VALVE_ZIGBEE) + self.gui_radiator_valve = gui_radiator_valve(mqtt_client, config.TOPIC_FFE_SLEEP_RADIATOR_VALVE_GUI) class ffe_livingroom(base): diff --git a/devices/__init__.py b/devices/__init__.py index e3dc5a1..9c4fc5c 100644 --- a/devices/__init__.py +++ b/devices/__init__.py @@ -186,41 +186,6 @@ class base(dict): return self.__previous__.get(key) -class nodered_gui_leds(base): - KEY_LED_0 = "led0" - KEY_LED_1 = "led1" - KEY_LED_2 = "led2" - KEY_LED_3 = "led3" - KEY_LED_4 = "led4" - KEY_LED_5 = "led5" - KEY_LED_6 = "led6" - KEY_LED_7 = "led7" - KEY_LED_8 = "led8" - KEY_LED_9 = "led9" - KEY_LED_LIST = [KEY_LED_0, KEY_LED_1, KEY_LED_2, KEY_LED_3, KEY_LED_4, KEY_LED_5, KEY_LED_6, KEY_LED_7, KEY_LED_8, KEY_LED_9] - # - TX_TYPE = base.TX_VALUE - - def set_led(self, key, data): - """data: [True, False]""" - self.logger.debug("Sending %s with content %s", key, str(data)) - self.pack(key, data) - - -class nodered_gui_timer(base): - KEY_TIMER = "timer" - # - TX_TYPE = base.TX_VALUE - - def set_timer(self, data): - """data: numeric""" - self.pack(self.KEY_TIMER, data) - - def set_timer_mcb(self, device, key, data): - self.logger.debug("Sending %s with content %s", key, str(data)) - self.set_timer(data) - - class shelly(base): KEY_OUTPUT_0 = "relay/0" KEY_OUTPUT_1 = "relay/1" @@ -649,61 +614,39 @@ class tradfri_button(base): return "Low battery level detected for %s. Battery level was %.0f%%." % (self.topic, self.get(self.KEY_BATTERY)) -class nodered_gui_heatvalve(base): - KEY_FEEDBACK = "feedback" - KEY_ENABLE = "enable" - KEY_STATE = "state" - KEY_BRIGHTNESS = "brightness" - KEY_COLOR_TEMP = "color_temp" - KEY_HEATING_BOOST = "heating_boost" - KEY_HEATING_SETPOINT = "heating_setpoint" - KEY_OFF_BUTTON = "off_button" +class nodered_gui_leds(base): + KEY_LED_0 = "led0" + KEY_LED_1 = "led1" + KEY_LED_2 = "led2" + KEY_LED_3 = "led3" + KEY_LED_4 = "led4" + KEY_LED_5 = "led5" + KEY_LED_6 = "led6" + KEY_LED_7 = "led7" + KEY_LED_8 = "led8" + KEY_LED_9 = "led9" + KEY_LED_LIST = [KEY_LED_0, KEY_LED_1, KEY_LED_2, KEY_LED_3, KEY_LED_4, KEY_LED_5, KEY_LED_6, KEY_LED_7, KEY_LED_8, KEY_LED_9] # TX_TYPE = base.TX_VALUE + + def set_led(self, key, data): + """data: [True, False]""" + self.logger.debug("Sending %s with content %s", key, str(data)) + self.pack(key, data) + + +class nodered_gui_timer(base): + KEY_TIMER = "timer" # - RX_KEYS = [KEY_STATE, KEY_BRIGHTNESS, KEY_COLOR_TEMP, KEY_HEATING_BOOST, KEY_HEATING_SETPOINT, KEY_OFF_BUTTON] + TX_TYPE = base.TX_VALUE - def __init__(self, mqtt_client, topic): - super().__init__(mqtt_client, topic) + def set_timer(self, data): + """data: numeric""" + self.pack(self.KEY_TIMER, data) - # - # RX - # - @property - def state(self): - """rv: [True, False]""" - return self.get(self.KEY_STATE) - - @property - def brightness(self): - """rv: [0, ..., 100]""" - return self.get(self.KEY_BRIGHTNESS) - - @property - def color_temp(self): - """rv: [0, ..., 100]""" - return self.get(self.KEY_COLOR_TEMP) - - @property - def heating_boost(self): - """rv: [True, False]""" - return self.get(self.KEY_HEATING_BOOST) - - @property - def heating_(self): - """rv: [5, ..., 30]""" - return self.get(self.KEY_HEATING_SETPOINT) - - @property - def off_button(self): - """rv: [True, False]""" - return self.get(self.KEY_OFF_BUTTON) - - # - # TX - # - def set_feedback(self, data): - self.pack(self.KEY_FEEDBACK, data) + def set_timer_mcb(self, device, key, data): + self.logger.debug("Sending %s with content %s", key, str(data)) + self.set_timer(data) class nodered_gui_button(base): @@ -790,6 +733,34 @@ class nodered_gui_light(nodered_gui_switch, nodered_gui_leds, nodered_gui_timer) self.set_color_temp(data) +class nodered_gui_radiator(nodered_gui_timer): + KEY_TEMPERATURE = "temperature" + KEY_SETPOINT_TEMP = "setpoint_temp" + KEY_SETPOINT_TO_DEFAULT = "setpoint_to_default" + KEY_BOOST = 'boost' + # + RX_KEYS = [KEY_TEMPERATURE, KEY_SETPOINT_TEMP, KEY_SETPOINT_TO_DEFAULT, KEY_BOOST] + + # + # TX + # + def set_temperature(self, data): + """data: [True, False]""" + self.pack(self.KEY_TEMPERATURE, data) + + def set_temperature_mcb(self, device, key, data): + self.logger.debug("Sending %s with content %s", key, str(data)) + self.set_temperature(data) + + def set_setpoint_temperature(self, data): + """data: [True, False]""" + self.pack(self.KEY_SETPOINT_TEMP, data) + + def set_setpoint_temperature_mcb(self, device, key, data): + self.logger.debug("Sending %s with content %s", key, str(data)) + self.set_setpoint_temperature(data) + + class brennenstuhl_heatingvalve(base): KEY_LINKQUALITY = "linkquality" KEY_BATTERY = "battery" diff --git a/function/__init__.py b/function/__init__.py index c46bb1f..e97a042 100644 --- a/function/__init__.py +++ b/function/__init__.py @@ -6,7 +6,6 @@ from function.stairway import stairway from function.ground_floor_west import ground_floor_west_floor, ground_floor_west_marion, ground_floor_west_dirk from function.first_floor_west import first_floor_west_julian, first_floor_west_living from function.first_floor_east import first_floor_east_floor, first_floor_east_kitchen, first_floor_east_dining, first_floor_east_sleep, first_floor_east_living -from function.common import common_heating, common_circulation_pump import inspect import logging @@ -16,9 +15,6 @@ except ImportError: ROOT_LOGGER_NAME = 'root' logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__) -# TODO: implement devices.nodered_gui_heatvalve incl. setpoint, boost, ... + replace led with timer -# TODO: improve heating function (away mode (reduced setpoint), return to default button, default values in config) -# TODO: improve devices.brennenstuhl_heatvalve # TODO: implement garland (incl. day events like sunset, sunrise, ...) # TODO: implement warning message @@ -28,9 +24,6 @@ class all_functions(object): self.mqtt_client = mqtt_client # self.__devices__ = None - # heating and warm water - self.common_ffe_heat_sleep = common_heating(self.mqtt_client) - self.common_circulation_pump = common_circulation_pump(self.mqtt_client) # stairway self.stw_stairway = stairway(self.mqtt_client) # ground floor west @@ -51,8 +44,6 @@ class all_functions(object): # # cross_room_interactions self.init_cross_room_interactions() - # Circulation pump - self.init_circulation_pump() # Off Buttons self.init_off_functionality() @@ -117,9 +108,6 @@ class all_functions(object): self.ffe_sleep.button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_RIGHT, self.ffe_floor.main_light_shelly.toggle_output_0_mcb) - def init_circulation_pump(self): - self.common_circulation_pump.main_light_shelly.add_callback(devices.shelly.KEY_OUTPUT_0, None, self.ffe_kitchen.flash_main_light) - def gfw_dirk_input_1(self, device, key, data): if self.last_gfw_dirk_input_1 is not None: if self.last_gfw_dirk_input_1 != data: diff --git a/function/common.py b/function/common.py deleted file mode 100644 index 674de13..0000000 --- a/function/common.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# - -import config -import devices -from function.rooms import room_shelly -from function.modules import heating_function_brennenstuhl -import logging -import task - -try: - from config import APP_NAME as ROOT_LOGGER_NAME -except ImportError: - ROOT_LOGGER_NAME = 'root' -logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__) - - -class common_circulation_pump(room_shelly): - def __init__(self, mqtt_client): - # http://shelly1-E89F6D85A466 - super().__init__(mqtt_client, config.TOPIC_FFE_KITCHEN_CIRCULATION_PUMP_SHELLY, config.TOPIC_FFE_KITCHEN_CIRCULATION_PUMP_GUI) - # - self.main_light_shelly.add_callback(devices.shelly.KEY_OUTPUT_0, None, self.circ_pump_actions, True) - # - self.gui_main_light.set_timer('-') - # - self.ct = task.periodic(6, self.cyclic_task) - self.pump_timer = None - # - self.ct.run() - - def circ_pump_actions(self, device, key, data): - if data is True: - self.pump_timer = 10 - self.gui_main_light.set_timer(self.pump_timer) - else: - self.pump_timer = None - self.gui_main_light.set_timer('-') - - def cyclic_task(self, rt): - if self.pump_timer is not None: - if self.pump_timer <= 0: - self.pump_timer = None - self.gui_main_light.set_timer('-') - else: - self.gui_main_light.set_timer(self.pump_timer) - self.pump_timer -= self.ct.cycle_time / 60 - - -class common_heating(object): - def __init__(self, mqtt_client): - self.ffe_heating_sleep_madi = heating_function_brennenstuhl( - mqtt_client, "zigbee/ffe/sleep/radiator_valve", 20, "gui/ffe_bo_sleep_madi", "gui/ffe_ts_sleep_madi", "gui/ffe_bl_sleep_madi") - - def all_off(self): - pass # dummy method for compatibility reasons diff --git a/function/first_floor_east.py b/function/first_floor_east.py index 4f5605a..7ade8a2 100644 --- a/function/first_floor_east.py +++ b/function/first_floor_east.py @@ -4,7 +4,7 @@ import config import devices -from function.modules import brightness_choose_n_action +from function.modules import brightness_choose_n_action, circulation_pump, radiator_function import logging from function.rooms import room_shelly, room_shelly_motion_sensor, room_shelly_tradfri_light try: @@ -24,6 +24,13 @@ class first_floor_east_kitchen(room_shelly): def __init__(self, mqtt_client): # http://shelly1l-8CAAB5616C01 super().__init__(mqtt_client, config.TOPIC_FFE_KITCHEN_MAIN_LIGHT_SHELLY, config.TOPIC_FFE_KITCHEN_MAIN_LIGHT_GUI) + # + self.circulation_pump = circulation_pump(mqtt_client) + self.circulation_pump.main_light_shelly.add_callback(devices.shelly.KEY_OUTPUT_0, None, self.flash_main_light) + + def all_off(self, device=None, key=None, data=None): + self.circulation_pump.all_off(device, key, data) + return super().all_off(device, key, data) class first_floor_east_dining(room_shelly): @@ -53,16 +60,18 @@ class first_floor_east_sleep(room_shelly_tradfri_light): def __init__(self, mqtt_client): # http://shelly1l-E8DB84A254C7 super().__init__(mqtt_client, config.TOPIC_FFE_SLEEP_MAIN_LIGHT_SHELLY, config.TOPIC_FFE_SLEEP_MAIN_LIGHT_GUI, config.TOPIC_FFE_SLEEP_MAIN_LIGHT_ZIGBEE) - # + # bed light self.bed_light_di_tradfri = devices.tradfri_light(mqtt_client, config.TOPIC_FFE_SLEEP_BED_LIGHT_DI_ZIGBEE) - # self.gui_bed_light_di = devices.nodered_gui_light(mqtt_client, config.TOPIC_FFE_SLEEP_BED_LIGHT_DI_GUI) # self.button_tradfri = devices.tradfri_button(mqtt_client, config.TOPIC_FFE_SLEEP_INPUT_DEVICE) - # + # button / brightness function self.brightness_functions = brightness_choose_n_action(mqtt_client, self.button_tradfri, config.TOPIC_FFE_SLEEP_DEVICE_CHOOSER_LED) self.brightness_functions.add(self.main_light_tradfri, self.main_light_shelly, devices.shelly.KEY_OUTPUT_0) self.brightness_functions.add(self.bed_light_di_tradfri, self.bed_light_di_tradfri, devices.tradfri_light.KEY_OUTPUT_0) + # radiator valve + self.radiator_function = radiator_function(mqtt_client, config.TOPIC_FFE_SLEEP_RADIATOR_VALVE_ZIGBEE, + config.TOPIC_FFE_SLEEP_RADIATOR_VALVE_GUI, config.DEFAULT_TEMPERATURE_FFE_SLEEP) # # Callback initialisation # diff --git a/function/modules.py b/function/modules.py index c2b3f91..2df2c98 100644 --- a/function/modules.py +++ b/function/modules.py @@ -2,7 +2,9 @@ # -*- coding: utf-8 -*- # +import config import devices +from function.rooms import room_shelly import logging import task @@ -100,73 +102,94 @@ class brightness_choose_n_action(object): target.default_stop() -class heating_function_brennenstuhl(object): - RETURN_TO_DEFAULT_TIME = 45 * 60 - BOOST_TEMP_OFFSET = 5 - - def __init__(self, mqtt_client, topic_valve, default_temperature, topic_boost, topic_setpoint, topic_led): - self.ct = task.periodic(1, self.cyclic_task) +class circulation_pump(room_shelly): + def __init__(self, mqtt_client): + super().__init__(mqtt_client, config.TOPIC_FFE_KITCHEN_CIRCULATION_PUMP_SHELLY, config.TOPIC_FFE_KITCHEN_CIRCULATION_PUMP_GUI) # - self.topic = topic_valve - self.default_temperature = default_temperature + self.main_light_shelly.add_callback(devices.shelly.KEY_OUTPUT_0, None, self.circ_pump_actions, True) # - self.heating_valve = devices.brennenstuhl_heatingvalve(mqtt_client, topic_valve) - self.heating_valve.set_heating_setpoint(self.default_temperature) - self.heating_valve.add_callback( - devices.brennenstuhl_heatingvalve.KEY_HEATING_SETPOINT, None, self.heating_setpoint_actions) - - self.gui_value_temp_setp = devices.nodered_gui_heatvalve(mqtt_client, topic_setpoint) - self.gui_value_temp_setp.add_callback( - devices.nodered_gui_heatvalve.KEY_HEATING_SETPOINT, None, self.heating_setpoint_actions) - - self.gui_button_boost = devices.nodered_gui_heatvalve(mqtt_client, topic_boost) - self.gui_button_boost.add_callback(None, None, self.boost_actions) - - self.gui_led_boost = devices.nodered_gui_heatvalve(mqtt_client, topic_led) - + self.gui_main_light.set_timer('-') # - self.return_to_default_timer = None - self.return_to_default_setpoint = None - self.gui_led_boost.set_feedback(False) + self.ct = task.periodic(6, self.cyclic_task) + self.pump_timer = None # self.ct.run() - def heating_setpoint_actions(self, device, key, data): - if device.topic == self.heating_valve.topic: - # valve setpoint action - self.gui_value_temp_setp.set_feedback(data) - if data > self.default_temperature: - if data != self.return_to_default_setpoint: - logger.info('Got heating setpoint (%.1f°C) \"%s\" with deviation to the default value (%.1f°C). Starting timer for returning to default.', - data, self.topic, self.default_temperature) - self.return_to_default_timer = self.RETURN_TO_DEFAULT_TIME - self.return_to_default_setpoint = data - self.gui_led_boost.set_feedback(True) - else: - if self.return_to_default_timer is not None: - logger.info('Deleting timer \"%s\" for returning to default.', self.topic) - self.return_to_default_timer = None - self.return_to_default_setpoint = None - self.gui_led_boost.set_feedback(False) - elif device.topic == self.gui_value_temp_setp.topic: - # user setpoint action - logger.info('Setpoint change \"%s\" to %.1f°C', self.topic, data) - self.default_temperature = data - self.heating_valve.set_heating_setpoint(self.default_temperature) - self.return_to_default_timer = None - self.return_to_default_setpoint = None - self.gui_led_boost.set_feedback(False) - - def boost_actions(self, davice, key, data): - logger.info('Starting boost mode \"%s\" with setpoint %.1f°C.', self.topic, self.default_temperature + self.BOOST_TEMP_OFFSET) - self.heating_valve.set_heating_setpoint(self.default_temperature + self.BOOST_TEMP_OFFSET) + def circ_pump_actions(self, device, key, data): + if data is True: + self.pump_timer = 10 + self.gui_main_light.set_timer(self.pump_timer) + else: + self.pump_timer = None + self.gui_main_light.set_timer('-') def cyclic_task(self, rt): - if self.return_to_default_timer is not None: - self.return_to_default_timer -= self.ct.cycle_time - if self.return_to_default_timer <= 0: - logger.info('Return to default timer expired \"%s\".', self.topic) - self.heating_valve.set_heating_setpoint(self.default_temperature) - self.return_to_default_timer = None - self.return_to_default_setpoint = None - self.gui_led_boost.set_feedback(False) + if self.pump_timer is not None: + if self.pump_timer <= 0: + self.pump_timer = None + self.gui_main_light.set_timer('-') + else: + self.gui_main_light.set_timer(self.pump_timer) + self.pump_timer -= self.ct.cycle_time / 60 + + +# TODO: +# - improve devices.brennenstuhl_heatingvalve (at least switch on for boost) and use boost in heating_function.boost_mcb +# - implement modules.heating_function +# * Central switch incl. central parameter storage for state (summer mode, away_mode - each switch activation disables the other switch) +class radiator_function(object): + def __init__(self, mqtt_client, topic_valve, topic_gui, default_temperature): + self.default_temperature = default_temperature + self.regular_temp_setpoint = self.default_temperature + # + self.ct = task.periodic(1, self.cyclic_task) + # + self.heating_valve = devices.brennenstuhl_heatingvalve(mqtt_client, topic_valve) + self.gui_heating = devices.nodered_gui_radiator(mqtt_client, topic_gui) + # + self.heating_valve.set_heating_setpoint(self.default_temperature) + self.heating_valve.add_callback(devices.brennenstuhl_heatingvalve.KEY_TEMPERATURE, None, self.gui_heating.set_temperature_mcb) + self.heating_valve.add_callback(devices.brennenstuhl_heatingvalve.KEY_HEATING_SETPOINT, None, self.gui_heating.set_setpoint_temperature_mcb) + self.heating_valve.add_callback(devices.brennenstuhl_heatingvalve.KEY_HEATING_SETPOINT, None, self.store_regular_setpoint) + # + self.gui_heating.add_callback(devices.nodered_gui_radiator.KEY_SETPOINT_TEMP, None, self.heating_valve.set_heating_setpoint_mcb) + self.gui_heating.add_callback(devices.nodered_gui_radiator.KEY_BOOST, None, self.boost_mcb) + self.gui_heating.add_callback(devices.nodered_gui_radiator.KEY_SETPOINT_TO_DEFAULT, None, self.setpoint_to_default_mcb) + self.gui_heating.add_callback(devices.nodered_gui_radiator.KEY_SETPOINT_TEMP, None, self.cancel_boost) + self.gui_heating.add_callback(devices.nodered_gui_radiator.KEY_SETPOINT_TO_DEFAULT, None, self.cancel_boost) + # + self.boost_timer = None + # + self.ct.run() + + def cyclic_task(self, rt): + if self.boost_timer is not None: + self.gui_heating.set_timer(round(self.boost_timer / 60, 1)) + # + self.boost_timer -= self.ct.cycle_time + if self.boost_timer <= 0: + self.cancel_boost() + self.heating_valve.set_heating_setpoint(self.regular_temp_setpoint) + + def cancel_boost(self, device=None, key=None, data=None): + if self.boost_timer is not None: + self.heating_valve.logger.info('Timer expired. returning to regular temperature setpoint %.1f°C.', self.regular_temp_setpoint) + self.boost_timer = None + self.gui_heating.set_timer('-') + + def store_regular_setpoint(self, device, key, data): + if self.boost_timer is None: + self.regular_temp_setpoint = data + + def boost_mcb(self, device, key, data): + if self.boost_timer is None: + self.heating_valve.logger.info('Starting boost mode with setpoint %.1f°C.', self.regular_temp_setpoint + 5) + self.boost_timer = 15*60 + self.heating_valve.set_heating_setpoint(self.regular_temp_setpoint + 5) # TODO: Change setpoint to "on" if possible + else: + self.boost_timer += 15 * 60 + if self.boost_timer > 60 * 60: + self.boost_timer = 60 * 60 + + def setpoint_to_default_mcb(self, device, key, data): + self.heating_valve.set_heating_setpoint(self.default_temperature) diff --git a/function/rooms.py b/function/rooms.py index f6dcf32..b1126c8 100644 --- a/function/rooms.py +++ b/function/rooms.py @@ -106,14 +106,13 @@ class room_shelly_motion_sensor(room_shelly): logger.info("No motion and time ran out - Switching off main light %s", self.main_light_shelly.topic) self.main_light_shelly.set_output_0(False) self.main_light_timer = None + self.gui_main_light.set_timer('-') else: self.gui_main_light.set_timer(self.main_light_timer) if (self.motion_detected_1 or self.motion_detected_2) and self.main_light_timer <= self.timer_value / 10: self.main_light_timer = self.timer_value / 10 else: self.main_light_timer -= cyclic_task.cycle_time - else: - self.gui_main_light.set_timer('-') class room_shelly_tradfri_light(room_shelly):