heating functionality addad (sleep_madi)

This commit is contained in:
Dirk Alders 2022-12-21 14:26:35 +01:00
parent 4761f0a29e
commit 1c245a4118
8 changed files with 175 additions and 10 deletions

3
.gitmodules vendored
View File

@ -4,3 +4,6 @@
[submodule "report"]
path = report
url = https://git.mount-mockery.de/pylib/report.git
[submodule "task"]
path = task
url = https://git.mount-mockery.de/pylib/task.git

View File

@ -60,7 +60,6 @@ class base(dict):
TX_TYPE = -1
TX_FILTER_DATA_KEYS = []
#
RX_LOG_INFO_ALWAYS_KEYS = []
RX_KEYS = []
RX_IGNORE_TOPICS = []
RX_IGNORE_KEYS = []
@ -96,8 +95,10 @@ class base(dict):
self[key] = data
# Filter, if needed
self.unpack_filter(key)
logger.log(logging.INFO if key in self.RX_LOG_INFO_ALWAYS_KEYS or prev_value != self.get(key) else logging.DEBUG,
"Received data for (%s) %s - %s", self.topic, key, str(self.get(key)))
if prev_value != self.get(key):
logger.info("Received new data for (%s) %s - %s", self.topic, key, str(self.get(key)))
else:
logger.debug("Received data for (%s) %s - %s", self.topic, key, str(self.get(key)))
self.callback_caller(key, self[key])
elif key not in self.RX_IGNORE_KEYS:
logger.warning('Got a message from \"%s\" with unparsed content "%s"', self.topic, key)
@ -143,6 +144,7 @@ class base(dict):
logger.error(
"Unknown tx type. Set TX_TYPE of class to a known value")
else:
logger.info("Sending data for (%s) %s - %s", self.topic, key, str(data))
if self.TX_TYPE == self.TX_DICT:
self.mqtt_client.send('/'.join([self.topic, self.TX_TOPIC]), json.dumps({key: data}))
else:
@ -452,7 +454,6 @@ class tradfri_button(base):
KEY_BATTERY = "battery"
KEY_ACTION = "action"
#
RX_LOG_INFO_ALWAYS_KEYS = [KEY_ACTION]
RX_KEYS = [KEY_LINKQUALITY, KEY_BATTERY, KEY_ACTION]
RX_IGNORE_TOPICS = []
RX_IGNORE_KEYS = ['update']
@ -485,13 +486,14 @@ class nodered_gui(base):
KEY_STATE = "state"
KEY_BRIGHTNESS = "brightness"
KEY_COLOR_TEMP = "color_temp"
KEY_HEATING_BOOST = "heating_boost"
KEY_HEATING_SETPOINT = "heating_setpoint"
#
TX_TOPIC = 'set'
TX_TYPE = base.TX_VALUE
TX_FILTER_DATA_KEYS = []
#
RX_LOG_INFO_ALWAYS_KEYS = []
RX_KEYS = [KEY_STATE, KEY_BRIGHTNESS, KEY_COLOR_TEMP]
RX_KEYS = [KEY_STATE, KEY_BRIGHTNESS, KEY_COLOR_TEMP, KEY_HEATING_BOOST, KEY_HEATING_SETPOINT]
RX_IGNORE_TOPICS = [KEY_FEEDBACK + '/' + TX_TOPIC, KEY_ENABLE + '/' + TX_TOPIC]
RX_FILTER_DATA_KEYS = []
@ -516,6 +518,16 @@ class nodered_gui(base):
"""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)
#
# TX
#
@ -525,3 +537,61 @@ class nodered_gui(base):
def enable(self, data):
"""data: [True, False]"""
self.pack(self.KEY_ENABLE, data)
class brennenstuhl_heatingvalve(base):
KEY_LINKQUALITY = "linkquality"
KEY_BATTERY = "battery"
KEY_HEATING_SETPOINT = "current_heating_setpoint"
KEY_TEMPERATURE = "local_temperature"
#
KEY_AWAY_MODE = "away_mode"
KEY_CHILD_LOCK = "child_lock"
KEY_PRESET = "preset"
KEY_SYSTEM_MODE = "system_mode"
KEY_VALVE_DETECTION = "valve_detection"
KEY_WINDOW_DETECTION = "window_detection"
#
TX_TOPIC = 'set'
TX_VALUE = 0
TX_DICT = 1
TX_TYPE = base.TX_DICT
TX_FILTER_DATA_KEYS = []
#
RX_KEYS = [KEY_LINKQUALITY, KEY_BATTERY, KEY_HEATING_SETPOINT, KEY_TEMPERATURE]
RX_IGNORE_TOPICS = [TX_TOPIC]
RX_IGNORE_KEYS = [KEY_AWAY_MODE, KEY_CHILD_LOCK, KEY_PRESET,
KEY_SYSTEM_MODE, KEY_VALVE_DETECTION, KEY_WINDOW_DETECTION]
RX_FILTER_DATA_KEYS = []
def __init__(self, mqtt_client, topic):
super().__init__(mqtt_client, topic)
self.mqtt_client.send(self.topic + '/' + self.TX_TOPIC, json.dumps(
{self.KEY_WINDOW_DETECTION: "ON", self.KEY_CHILD_LOCK: "UNLOCK", self.KEY_VALVE_DETECTION: "ON", self.KEY_SYSTEM_MODE: "heat"}))
def warning_call_condition(self):
return self.get(self.KEY_BATTERY) <= BATTERY_WARN_LEVEL
def warning_text(self):
return "Low battery level detected for %s. Battery level was %.0f%%." % (self.topic, self.get(self.KEY_BATTERY))
#
# RX
#
@property
def linkqulity(self):
return self.get(self.KEY_LINKQUALITY)
@property
def heating_setpoint(self):
return self.get(self.KEY_HEATING_SETPOINT)
@property
def temperature(self):
return self.get(self.KEY_TEMPERATURE)
#
# TX
#
def set_heating_setpoint(self, setpoint):
self.pack(self.KEY_HEATING_SETPOINT, setpoint)

View File

@ -6,8 +6,8 @@ from function.ground_floor_west import ground_floor_west_floor, ground_floor_wes
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_madi, first_floor_east_living
import inspect
from function import modules
# TODO: implement heating function sleep_madi
# TODO: implement circulation pump
# TODO: implement switch off functionality (except of switch off button transportation)
# TODO: implement garland (incl. day events like sunset, sunrise, ...)
@ -40,6 +40,7 @@ class all_functions(object):
# additional functionality
#
self.init_input_device_sleep_madi_functionality()
self.init_heating_functionality()
def init_input_device_sleep_madi_functionality(self):
#
@ -57,6 +58,10 @@ class all_functions(object):
self.ffe_button_tradfri_sleep.add_callback(devices.tradfri_button.KEY_ACTION, None,
self.ffe_sleep_madi.fade_light)
def init_heating_functionality(self):
self.ffe_heating_sleep_madi = modules.heating_function_brennenstuhl(
self.mqtt_client, "zigbee_og_e/radiator/sleep_madi", 20, "gui/ffe_bo_sleep_madi", "gui/ffe_ts_sleep_madi", "gui/ffe_bl_sleep_madi")
def devicelist(self):
if self.__devices__ is None:
self.__devices__ = []

86
function/modules.py Normal file
View File

@ -0,0 +1,86 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
import devices
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 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)
#
self.topic = topic_valve
self.default_temperature = default_temperature
#
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(mqtt_client, topic_setpoint)
self.gui_value_temp_setp.add_callback(
devices.nodered_gui.KEY_HEATING_SETPOINT, None, self.heating_setpoint_actions)
self.gui_button_boost = devices.nodered_gui(mqtt_client, topic_boost)
self.gui_button_boost.add_callback(None, None, self.boost_actions)
self.gui_led_boost = devices.nodered_gui(mqtt_client, topic_led)
#
self.return_to_default_timer = None
self.return_to_default_setpoint = None
self.gui_led_boost.set_feedback(False)
#
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 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)

View File

@ -2,7 +2,6 @@
# -*- coding: utf-8 -*-
#
import config
import devices
import logging

2
mqtt

@ -1 +1 @@
Subproject commit 1921bc619a9c4af682a7707d6fe58069478c59cd
Subproject commit 79ac04ffdb61ea61334b2bb90bee565472957657

View File

@ -10,7 +10,8 @@ logger = logging.getLogger(config.APP_NAME)
if __name__ == "__main__":
if config.DEBUG:
report.stdoutLoggingConfigure(([config.APP_NAME, logging.DEBUG], ), report.LONG_FMT)
report.appLoggingConfigure(None, None, ((config.APP_NAME, logging.DEBUG), ),
fmt=report.SHORT_FMT, host='localhost', port=19996)
else:
report.stdoutLoggingConfigure(((config.APP_NAME, logging.INFO),
(config.APP_NAME+'.devices', logging.WARNING)), report.SHORT_FMT)

1
task Submodule

@ -0,0 +1 @@
Subproject commit af35e83d1f07fd4cb9070bdb77cf1f3bdda3a463