2022-12-21 14:26:35 +01:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#
|
|
|
|
|
2023-01-09 16:42:18 +01:00
|
|
|
import config
|
2022-12-21 14:26:35 +01:00
|
|
|
import devices
|
2023-01-09 16:42:18 +01:00
|
|
|
from function.rooms import room_shelly
|
2022-12-21 14:26:35 +01:00
|
|
|
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__)
|
|
|
|
|
|
|
|
|
2022-12-27 11:29:39 +01:00
|
|
|
class brightness_choose_n_action(object):
|
|
|
|
def __init__(self, mqtt_client, button_tradfri, topic_led):
|
|
|
|
self.gui_led_active_device = devices.nodered_gui_leds(mqtt_client, topic_led)
|
|
|
|
# brightness change
|
|
|
|
button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION,
|
|
|
|
devices.tradfri_button.ACTION_BRIGHTNESS_DOWN_LONG, self.brightness_action)
|
|
|
|
button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_BRIGHTNESS_UP_LONG, self.brightness_action)
|
|
|
|
button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION,
|
|
|
|
devices.tradfri_button.ACTION_BRIGHTNESS_DOWN_RELEASE, self.brightness_action)
|
|
|
|
button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION,
|
|
|
|
devices.tradfri_button.ACTION_BRIGHTNESS_UP_RELEASE, self.brightness_action)
|
|
|
|
# device change
|
|
|
|
button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_BRIGHTNESS_UP, self.choose_next_device)
|
|
|
|
button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_BRIGHTNESS_DOWN, self.choose_prev_device)
|
|
|
|
#
|
2022-12-28 14:52:24 +01:00
|
|
|
self.brightness_device_list = []
|
2022-12-27 11:29:39 +01:00
|
|
|
self.callback_device_list = []
|
|
|
|
self.device_states = []
|
|
|
|
self.active_device_state = None
|
|
|
|
self.update_active_device_led()
|
|
|
|
|
2022-12-28 14:52:24 +01:00
|
|
|
def add(self, brightness_device, callback_device, callback_key):
|
2022-12-27 11:29:39 +01:00
|
|
|
"""
|
2022-12-28 14:52:24 +01:00
|
|
|
brightness_device: A device for brightness function needs to have the following methods:
|
2022-12-27 11:29:39 +01:00
|
|
|
* .default_inc()
|
|
|
|
* .default_dec()
|
|
|
|
* .default_stop()
|
2022-12-28 14:52:24 +01:00
|
|
|
callback_device: A device for installing callback which are executed, when the device is switched on or off. It needs the following method:
|
|
|
|
* .add_callback(key, data or None, callback, on_changes_only)
|
2022-12-27 11:29:39 +01:00
|
|
|
"""
|
2023-01-08 20:35:36 +01:00
|
|
|
if len(self.brightness_device_list) >= len(devices.nodered_gui_leds.KEY_LED_LIST):
|
2022-12-27 11:29:39 +01:00
|
|
|
raise ValueError("Number of devices is limited by number of leds in devices.nodered_gui_leds.")
|
2022-12-28 14:52:24 +01:00
|
|
|
self.brightness_device_list.append(brightness_device)
|
|
|
|
self.callback_device_list.append((callback_device, callback_key))
|
2022-12-27 11:29:39 +01:00
|
|
|
self.device_states.append(False)
|
2022-12-28 14:52:24 +01:00
|
|
|
callback_device.add_callback(callback_key, True, self.device_state_action, True)
|
|
|
|
callback_device.add_callback(callback_key, False, self.device_state_action, True)
|
2022-12-27 11:29:39 +01:00
|
|
|
|
|
|
|
def device_state_action(self, device, key, data):
|
2022-12-28 14:52:24 +01:00
|
|
|
self.device_states[self.callback_device_list.index((device, key))] = data
|
2022-12-27 11:29:39 +01:00
|
|
|
if data is True:
|
2022-12-28 14:52:24 +01:00
|
|
|
self.active_device_state = self.callback_device_list.index((device, key))
|
2022-12-27 11:29:39 +01:00
|
|
|
self.update_active_device_led()
|
|
|
|
else:
|
|
|
|
self.choose_next_device()
|
|
|
|
|
|
|
|
def update_active_device_led(self):
|
2022-12-28 14:52:24 +01:00
|
|
|
for i in range(0, len(self.brightness_device_list)):
|
2023-01-08 20:35:36 +01:00
|
|
|
self.gui_led_active_device.set_led(devices.nodered_gui_leds.KEY_LED_LIST[i], self.active_device_state == i)
|
2022-12-27 11:29:39 +01:00
|
|
|
|
|
|
|
def choose_prev_device(self, device=None, key=None, data=None):
|
|
|
|
if self.active_device_state is not None:
|
|
|
|
start_value = self.active_device_state
|
2022-12-28 14:52:24 +01:00
|
|
|
for i in range(0, len(self.brightness_device_list)):
|
|
|
|
target_state = (start_value - i - 1) % (len(self.brightness_device_list))
|
2022-12-27 11:29:39 +01:00
|
|
|
if self.device_states[target_state]:
|
|
|
|
self.active_device_state = target_state
|
|
|
|
self.update_active_device_led()
|
|
|
|
return
|
|
|
|
self.active_device_state = None
|
|
|
|
self.update_active_device_led()
|
|
|
|
|
|
|
|
def choose_next_device(self, device=None, key=None, data=None):
|
|
|
|
if self.active_device_state is not None:
|
|
|
|
start_value = self.active_device_state
|
2022-12-28 14:52:24 +01:00
|
|
|
for i in range(0, len(self.brightness_device_list)):
|
|
|
|
target_state = (start_value + i + 1) % (len(self.brightness_device_list))
|
2022-12-27 11:29:39 +01:00
|
|
|
if self.device_states[target_state]:
|
|
|
|
self.active_device_state = target_state
|
|
|
|
self.update_active_device_led()
|
|
|
|
return
|
|
|
|
self.active_device_state = None
|
|
|
|
self.update_active_device_led()
|
|
|
|
|
|
|
|
def brightness_action(self, device, key, data):
|
|
|
|
if self.active_device_state is not None:
|
2022-12-28 14:52:24 +01:00
|
|
|
target = self.brightness_device_list[self.active_device_state]
|
2022-12-27 11:29:39 +01:00
|
|
|
if data == devices.tradfri_button.ACTION_BRIGHTNESS_UP_LONG:
|
|
|
|
logger.info("Increasing \"%s\" - %s", type(self).__name__, target.topic)
|
|
|
|
target.default_inc()
|
|
|
|
elif data == devices.tradfri_button.ACTION_BRIGHTNESS_DOWN_LONG:
|
|
|
|
logger.info("Decreasing \"%s\" - %s", type(self).__name__, target.topic)
|
|
|
|
target.default_dec()
|
|
|
|
elif data in [devices.tradfri_button.ACTION_BRIGHTNESS_UP_RELEASE, devices.tradfri_button.ACTION_BRIGHTNESS_DOWN_RELEASE]:
|
|
|
|
target.default_stop()
|
|
|
|
|
|
|
|
|
2023-01-09 16:42:18 +01:00
|
|
|
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)
|
2022-12-21 14:26:35 +01:00
|
|
|
#
|
2023-01-09 16:42:18 +01:00
|
|
|
self.main_light_shelly.add_callback(devices.shelly.KEY_OUTPUT_0, None, self.circ_pump_actions, True)
|
2022-12-21 14:26:35 +01:00
|
|
|
#
|
2023-01-09 16:42:18 +01:00
|
|
|
self.gui_main_light.set_timer('-')
|
|
|
|
#
|
|
|
|
self.ct = task.periodic(6, self.cyclic_task)
|
|
|
|
self.pump_timer = None
|
|
|
|
#
|
|
|
|
self.ct.run()
|
2022-12-21 14:26:35 +01:00
|
|
|
|
2023-01-09 16:42:18 +01:00
|
|
|
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('-')
|
2022-12-21 14:26:35 +01:00
|
|
|
|
2023-01-09 16:42:18 +01:00
|
|
|
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
|
2022-12-21 14:26:35 +01:00
|
|
|
|
|
|
|
|
2023-01-09 16:42:18 +01:00
|
|
|
class radiator_function(object):
|
2023-01-10 23:17:47 +01:00
|
|
|
BOOST_TEMPERATURE = 30
|
|
|
|
AWAY_REDUCTION = 5
|
|
|
|
SUMMER_TEMPERATURE = 5
|
|
|
|
|
2023-01-09 16:42:18 +01:00
|
|
|
def __init__(self, mqtt_client, topic_valve, topic_gui, default_temperature):
|
|
|
|
self.default_temperature = default_temperature
|
|
|
|
self.regular_temp_setpoint = self.default_temperature
|
2023-01-10 23:17:47 +01:00
|
|
|
self.__away_mode__ = False
|
|
|
|
self.__summer_mode__ = False
|
2022-12-21 14:26:35 +01:00
|
|
|
#
|
2023-01-09 16:42:18 +01:00
|
|
|
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)
|
2023-01-10 23:17:47 +01:00
|
|
|
self.heating_valve.add_callback(devices.brennenstuhl_heatingvalve.KEY_HEATING_SETPOINT, None, self.get_radiator_setpoint)
|
2023-01-09 16:42:18 +01:00
|
|
|
#
|
2023-01-10 23:17:47 +01:00
|
|
|
self.gui_heating.add_callback(devices.nodered_gui_radiator.KEY_SETPOINT_TEMP, None, self.set_heating_setpoint)
|
|
|
|
self.gui_heating.add_callback(devices.nodered_gui_radiator.KEY_BOOST, None, self.boost)
|
|
|
|
self.gui_heating.add_callback(devices.nodered_gui_radiator.KEY_SETPOINT_TO_DEFAULT, None, self.setpoint_to_default)
|
|
|
|
self.gui_heating.add_callback(devices.nodered_gui_radiator.KEY_AWAY, None, self.away_mode)
|
|
|
|
self.gui_heating.add_callback(devices.nodered_gui_radiator.KEY_SUMMER, None, self.summer_mode)
|
2023-01-09 16:42:18 +01:00
|
|
|
#
|
|
|
|
self.boost_timer = None
|
2022-12-21 14:26:35 +01:00
|
|
|
#
|
|
|
|
self.ct.run()
|
|
|
|
|
|
|
|
def cyclic_task(self, rt):
|
2023-01-09 16:42:18 +01:00
|
|
|
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('-')
|
|
|
|
|
2023-01-10 23:17:47 +01:00
|
|
|
def away_mode(self, device, key, value):
|
|
|
|
self.__away_mode__ = value
|
|
|
|
self.gui_heating.set_away(value)
|
|
|
|
if value is True:
|
|
|
|
self.__summer_mode__ = False
|
|
|
|
self.gui_heating.set_summer(False)
|
|
|
|
self.cancel_boost()
|
|
|
|
self.heating_valve.set_heating_setpoint(self.default_temperature - self.AWAY_REDUCTION)
|
|
|
|
else:
|
|
|
|
self.heating_valve.set_heating_setpoint(self.default_temperature)
|
|
|
|
|
|
|
|
def summer_mode(self, device, key, value):
|
|
|
|
self.__summer_mode__ = value
|
|
|
|
self.gui_heating.set_summer(value)
|
|
|
|
if value is True:
|
|
|
|
self.__away_mode__ = False
|
|
|
|
self.gui_heating.set_away(False)
|
|
|
|
self.cancel_boost()
|
|
|
|
self.heating_valve.set_heating_setpoint(self.SUMMER_TEMPERATURE)
|
|
|
|
else:
|
|
|
|
self.heating_valve.set_heating_setpoint(self.default_temperature)
|
2023-01-09 16:42:18 +01:00
|
|
|
|
2023-01-10 23:17:47 +01:00
|
|
|
def boost(self, device, key, data):
|
|
|
|
self.cancel_boost()
|
2023-01-09 16:42:18 +01:00
|
|
|
if self.boost_timer is None:
|
2023-01-10 23:17:47 +01:00
|
|
|
self.heating_valve.logger.info('Starting boost mode with setpoint %.1f°C.', self.BOOST_TEMPERATURE)
|
2023-01-09 16:42:18 +01:00
|
|
|
self.boost_timer = 15*60
|
2023-01-10 23:17:47 +01:00
|
|
|
self.heating_valve.set_heating_setpoint(self.BOOST_TEMPERATURE)
|
2023-01-09 16:42:18 +01:00
|
|
|
else:
|
|
|
|
self.boost_timer += 15 * 60
|
|
|
|
if self.boost_timer > 60 * 60:
|
|
|
|
self.boost_timer = 60 * 60
|
|
|
|
|
2023-01-10 23:17:47 +01:00
|
|
|
def setpoint_to_default(self, device, key, data):
|
2023-01-09 16:42:18 +01:00
|
|
|
self.heating_valve.set_heating_setpoint(self.default_temperature)
|
2023-01-10 23:17:47 +01:00
|
|
|
|
|
|
|
def set_heating_setpoint(self, device, key, data):
|
|
|
|
self.cancel_boost()
|
|
|
|
self.heating_valve.set_heating_setpoint(data)
|
|
|
|
|
|
|
|
def get_radiator_setpoint(self, device, key, data):
|
|
|
|
self.gui_heating.set_setpoint_temperature(data)
|
|
|
|
if self.__away_mode__:
|
|
|
|
self.away_mode(device, self.gui_heating.KEY_AWAY, True)
|
|
|
|
if self.__summer_mode__:
|
|
|
|
self.summer_mode(device, self.gui_heating.KEY_SUMMER, True)
|
|
|
|
if self.boost_timer is None and not self.__away_mode__ and not self.__summer_mode__:
|
|
|
|
self.regular_temp_setpoint = data
|