heating functionality addad (sleep_madi)
This commit is contained in:
parent
4761f0a29e
commit
1c245a4118
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
86
function/modules.py
Normal 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)
|
@ -2,7 +2,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
import config
|
||||
import devices
|
||||
import logging
|
||||
|
||||
|
2
mqtt
2
mqtt
@ -1 +1 @@
|
||||
Subproject commit 1921bc619a9c4af682a7707d6fe58069478c59cd
|
||||
Subproject commit 79ac04ffdb61ea61334b2bb90bee565472957657
|
@ -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
1
task
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit af35e83d1f07fd4cb9070bdb77cf1f3bdda3a463
|
Loading…
x
Reference in New Issue
Block a user