#!/usr/bin/env python # -*- coding: utf-8 -*- # from devices.base import base import json import task import time class brennenstuhl_heatingvalve(base): """ Communication (MQTT) brennenstuhl_heatingvalve { | "away_mode": ["ON", "OFF"] | "battery": [0...100] % | "child_lock": ["LOCK", "UNLOCK"] | "current_heating_setpoint": [5...30] °C | "linkquality": [0...255] lqi | "local_temperature": [numeric] °C | "preset": ["manual", ...] | "system_mode": ["heat", ...] | "valve_detection": ["ON", "OFF"] | "window_detection": ["ON", "OFF"] | } +- set { "away_mode": ["ON", "OFF", "TOGGLE"] "child_lock": ["LOCK", "UNLOCK"] "current_heating_setpoint": [5...30] °C "preset": ["manual", ...] "system_mode": ["heat", ...] "valve_detection": ["ON", "OFF", "TOGGLE"] "window_detection": ["ON", "OFF", "TOGGLE"] } """ 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" # RETRY_CYCLE_TIME = 2.5 MAX_TX_RETRIES = 20 RETRY_TIMEOUT = RETRY_CYCLE_TIME * MAX_TX_RETRIES # TX_TYPE = base.TX_DICT # RX_KEYS = [KEY_LINKQUALITY, KEY_BATTERY, KEY_HEATING_SETPOINT, KEY_TEMPERATURE] RX_IGNORE_KEYS = [KEY_AWAY_MODE, KEY_CHILD_LOCK, KEY_PRESET, KEY_SYSTEM_MODE, KEY_VALVE_DETECTION, KEY_WINDOW_DETECTION] # CFG_DATA = { KEY_WINDOW_DETECTION: "ON", KEY_VALVE_DETECTION: "ON", KEY_SYSTEM_MODE: "heat", KEY_PRESET: "manual" } def __init__(self, mqtt_client, topic): super().__init__(mqtt_client, topic) self.add_callback(self.KEY_HEATING_SETPOINT, None, self.__valave_temp_rx__) self.__tx_temperature__ = None self.__rx_temperature__ = None self.__tx_timestamp__ = 0 # self.task = task.periodic(self.RETRY_CYCLE_TIME, self.__task__) self.task.run() def __state_logging__(self, inst, key, data): if key in [self.KEY_HEATING_SETPOINT, self.KEY_CHILD_LOCK, self.KEY_WINDOW_DETECTION, self.KEY_VALVE_DETECTION]: self.logger.info("State change of '%s' to '%s'", key, repr(data)) def send_command(self, key, data): if key == self.KEY_HEATING_SETPOINT: self.__tx_temperature__ = data self.__tx_timestamp__ = time.time() base.send_command(self, key, data) def __valave_temp_rx__(self, inst, key, data): if key == self.KEY_HEATING_SETPOINT: self.__rx_temperature__ = data def __task__(self, rt): if self.__tx_temperature__ is not None and self.__tx_timestamp__ is not None: # Already send a setpoint if self.__tx_temperature__ != self.__rx_temperature__: # Setpoint and valve feedback are unequal if time.time() - self.__tx_timestamp__ < self.RETRY_TIMEOUT: # Timeout condition allows resend of setpoint self.logger.warning("Setpoint not yet acknoledged by device. Sending setpoint again") self.set_heating_setpoint(self.__tx_temperature__) return else: self.__tx_timestamp__ = None # Disable resend logic, if setpoint and valve setpoint are equal # # 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.send_command(self.KEY_HEATING_SETPOINT, setpoint) def set_heating_setpoint_mcb(self, device, key, data): self.set_heating_setpoint(data)