diff --git a/.gitmodules b/.gitmodules index 4b92446..3331480 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "geo"] path = geo url = https://git.mount-mockery.de/pylib/geo.git +[submodule "devdi"] + path = devdi + url = https://git.mount-mockery.de/smarthome/smart_devdi.git diff --git a/.vscode/settings.json b/.vscode/settings.json index 211360c..ee25f90 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,12 +1,11 @@ { "python.defaultInterpreterPath": "./venv/bin/python", "autopep8.args": ["--max-line-length=150"], - "python.formatting.provider": "none", "[python]": { - "editor.defaultFormatter": "ms-python.python", + "python.formatting.provider": "none", + "editor.defaultFormatter": "ms-python.autopep8", "editor.formatOnSave": true }, - "editor.formatOnSave": true, "editor.fontSize": 14, "emmet.includeLanguages": { "django-html": "html" }, "python.testing.pytestArgs": ["-v", "--cov", "--cov-report=xml", "__test__"], diff --git a/devdi b/devdi new file mode 160000 index 0000000..773d0a6 --- /dev/null +++ b/devdi @@ -0,0 +1 @@ +Subproject commit 773d0a6679810b365bbd4537156c513b0f496c5a diff --git a/devices/__init__.py b/devices/__init__.py index 9fc6a63..e0bd89c 100644 --- a/devices/__init__.py +++ b/devices/__init__.py @@ -26,50 +26,23 @@ devices (DEVICES) """ -from base import mqtt_base -from base import videv_base -import json -import logging -import math -import task -import time - try: from config import APP_NAME as ROOT_LOGGER_NAME except ImportError: ROOT_LOGGER_NAME = 'root' -BATTERY_WARN_LEVEL = 10 - - -class warning(dict): - TYPE_BATTERY_LOW = 1 - TYPE_OVERTEMPERATURE = 2 - # - KEY_ID = 'id' - KEY_TYPE = 'type' - KEY_TEXT = 'text' - KEY_TM = 'tm' - - def __init__(self, identification, type, text, args): - super().__init__({ - self.KEY_ID: identification, - self.KEY_TYPE: type, - self.KEY_TEXT: text % args, - self.KEY_TM: time.localtime(), - }) - - def __str__(self): - return time.asctime(self.get(self.KEY_TM)) + ": " + self[self.KEY_TEXT] + " - " + self[self.KEY_ID] - - -def is_json(data): - try: - json.loads(data) - except json.decoder.JSONDecodeError: - return False - else: - return True +from devices.shelly import shelly as shelly_sw1 +from devices.tradfri import tradfri_light as tradfri_sw +from devices.tradfri import tradfri_light as tradfri_sw_br +from devices.tradfri import tradfri_light as tradfri_sw_br_ct +from devices.tradfri import tradfri_button as tradfri_button +from devices.tradfri import tradfri_light as livarno_sw_br_ct +from devices.brennenstuhl import brennenstuhl_heatingvalve +from devices.silvercrest import silvercrest_powerplug +from devices.silvercrest import silvercrest_motion_sensor +from devices.mydevices import powerplug as my_powerplug +from devices.mydevices import audio_status +from devices.mydevices import remote class group(object): @@ -79,15 +52,23 @@ class group(object): self._iter_counter = 0 # self.methods = [] - for method in [m for m in args[0].__class__.__dict__.keys()]: - if not method.startswith('_') and callable(getattr(args[0], method)): # add all public callable attributes to the list - self.methods.append(method) + self.variables = [] + for name in [m for m in args[0].__class__.__dict__.keys()]: + if not name.startswith('_') and callable(getattr(args[0], name)): # add all public callable attributes to the list + self.methods.append(name) + if not name.startswith('_') and not callable(getattr(args[0], name)): # add all public callable attributes to the list + self.variables.append(name) # for member in self: methods = [m for m in member.__class__.__dict__.keys() if not m.startswith( '_') if not m.startswith('_') and callable(getattr(args[0], m))] if self.methods != methods: - raise ValueError("All given instances needs to have same attributes:", self.methods, methods) + raise ValueError("All given instances needs to have same methods:", self.methods, methods) + # + variables = [v for v in member.__class__.__dict__.keys() if not v.startswith( + '_') if not v.startswith('_') and not callable(getattr(args[0], v))] + if self.variables != variables: + raise ValueError("All given instances needs to have same variables:", self.variables, variables) def __iter__(self): return self @@ -113,900 +94,30 @@ class group(object): try: rv = super().__getattribute__(name) except AttributeError: - return group_execution + if callable(getattr(self[0], name)): + return group_execution + else: + return getattr(self[0], name) else: return rv -class base(mqtt_base): - TX_TOPIC = "set" - TX_VALUE = 0 - TX_DICT = 1 - TX_TYPE = -1 - TX_FILTER_DATA_KEYS = [] +class warning(dict): + TYPE_BATTERY_LOW = 1 + TYPE_OVERTEMPERATURE = 2 # - RX_KEYS = [] - RX_IGNORE_TOPICS = [] - RX_IGNORE_KEYS = [] - RX_FILTER_DATA_KEYS = [] - # - KEY_WARNING = '__WARNING__' - - def __init__(self, mqtt_client, topic): - super().__init__(mqtt_client, topic, default_values=dict.fromkeys(self.RX_KEYS + [self.KEY_WARNING])) - # data storage - # initialisations - mqtt_client.add_callback(topic=self.topic, callback=self.receive_callback) - mqtt_client.add_callback(topic=self.topic+"/#", callback=self.receive_callback) - - def set(self, key, data, block_callback=[]): - if key in self.RX_IGNORE_KEYS: - pass # ignore these keys - elif key in self.RX_KEYS or key == self.KEY_WARNING: - return super().set(key, data, block_callback) - else: - self.logger.warning("Unexpected key %s", key) - - def receive_callback(self, client, userdata, message): - if message.topic != self.topic + '/' + videv_base.KEY_INFO: - content_key = message.topic[len(self.topic) + 1:] - if content_key not in self.RX_IGNORE_TOPICS and (not message.topic.endswith(self.TX_TOPIC) or len(self.TX_TOPIC) == 0): - self.logger.debug("Unpacking content_key \"%s\" from message.", content_key) - if is_json(message.payload): - data = json.loads(message.payload) - if type(data) is dict: - for key in data: - self.set(key, self.__device_to_instance_filter__(key, data[key])) - else: - self.set(content_key, self.__device_to_instance_filter__(content_key, data)) - # String - else: - self.set(content_key, self.__device_to_instance_filter__(content_key, message.payload.decode('utf-8'))) - else: - self.logger.debug("Ignoring topic %s", content_key) - - def __device_to_instance_filter__(self, key, data): - if key in self.RX_FILTER_DATA_KEYS: - if data in [1, 'on', 'ON']: - return True - elif data in [0, 'off', 'OFF']: - return False - return data - - def __instance_to_device_filter__(self, key, data): - if key in self.TX_FILTER_DATA_KEYS: - if data is True: - return "on" - elif data is False: - return "off" - return data - - def send_command(self, key, data): - data = self.__instance_to_device_filter__(key, data) - if self.TX_TOPIC is not None: - if self.TX_TYPE < 0: - self.logger.error("Unknown tx type. Set TX_TYPE of class to a known value") - else: - self.logger.debug("Sending data for %s - %s", 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: - if type(data) not in [str, bytes]: - data = json.dumps(data) - self.mqtt_client.send('/'.join([self.topic, key, self.TX_TOPIC] if len(self.TX_TOPIC) > 0 else [self.topic, key]), data) - else: - self.logger.error("Unknown tx toptic. Set TX_TOPIC of class to a known value") - - -class shelly(base): - """ Communication (MQTT) - - shelly - +- relay - | +- 0 ["on" / "off"] <- status - | | +- command ["on"/ "off"] <- command - | | +- energy [numeric] <- status - | +- 1 ["on" / "off"] <- status - | +- command ["on"/ "off"] <- command - | +- energy [numeric] <- status - +- input - | +- 0 [0 / 1] <- status - | +- 1 [0 / 1] <- status - +- input_event - | +- 0 <- status - | +- 1 <- status - +- logpush - | +- 0 [0 / 1] <- status - | +- 1 [0 / 1] <- status - +- temperature [numeric] °C <- status - +- temperature_f [numeric] F <- status - +- overtemperature [0 / 1] <- status - +- id <- status - +- model <- status - +- mac <- status - +- ip <- status - +- new_fw <- status - +- fw_ver <- status - """ - KEY_OUTPUT_0 = "relay/0" - KEY_OUTPUT_1 = "relay/1" - KEY_INPUT_0 = "input/0" - KEY_INPUT_1 = "input/1" - KEY_LONGPUSH_0 = "longpush/0" - KEY_LONGPUSH_1 = "longpush/1" - KEY_TEMPERATURE = "temperature" - KEY_OVERTEMPERATURE = "overtemperature" - KEY_ID = "id" - KEY_MODEL = "model" - KEY_MAC = "mac" - KEY_IP = "ip" - KEY_NEW_FIRMWARE = "new_fw" - KEY_FIRMWARE_VERSION = "fw_ver" - # - TX_TOPIC = "command" - TX_TYPE = base.TX_VALUE - TX_FILTER_DATA_KEYS = [KEY_OUTPUT_0, KEY_OUTPUT_1] - # - RX_KEYS = [KEY_OUTPUT_0, KEY_OUTPUT_1, KEY_INPUT_0, KEY_INPUT_1, KEY_LONGPUSH_0, KEY_LONGPUSH_1, KEY_OVERTEMPERATURE, KEY_TEMPERATURE, - KEY_ID, KEY_MODEL, KEY_MAC, KEY_IP, KEY_NEW_FIRMWARE, KEY_FIRMWARE_VERSION] - RX_IGNORE_TOPICS = [KEY_OUTPUT_0 + '/' + "energy", KEY_OUTPUT_1 + '/' + "energy", 'input_event/0', 'input_event/1'] - RX_IGNORE_KEYS = ['temperature_f'] - RX_FILTER_DATA_KEYS = [KEY_INPUT_0, KEY_INPUT_1, KEY_LONGPUSH_0, KEY_LONGPUSH_1, KEY_OUTPUT_0, KEY_OUTPUT_1, KEY_OVERTEMPERATURE] - - def __init__(self, mqtt_client, topic): - super().__init__(mqtt_client, topic) - # - self.output_key_delayed = None - self.delayed_flash_task = task.delayed(0.3, self.flash_task) - self.delayed_off_task = task.delayed(0.3, self.off_task) - # - self.add_callback(self.KEY_OVERTEMPERATURE, True, self.__warning__, True) - # - self.all_off_requested = False - - def flash_task(self, *args): - if self.flash_active: - self.send_command(self.output_key_delayed, not self.get(self.output_key_delayed)) - self.output_key_delayed = None - if self.all_off_requested: - self.delayed_off_task.run() - - def off_task(self, *args): - self.all_off() - - @property - def flash_active(self): - return self.output_key_delayed is not None - - # - # WARNING CALL - # - def __warning__(self, client, key, data): - w = warning(self.topic, warning.TYPE_OVERTEMPERATURE, "Temperature to high (%.1f°C)", self.get(self.KEY_TEMPERATURE) or math.nan) - self.logger.warning(w) - self.set(self.KEY_WARNING, w) - - # - # RX - # - @property - def output_0(self): - """rv: [True, False]""" - return self.get(self.KEY_OUTPUT_0) - - @property - def output_1(self): - """rv: [True, False]""" - return self.get(self.KEY_OUTPUT_1) - - @property - def input_0(self): - """rv: [True, False]""" - return self.get(self.KEY_INPUT_0) - - @property - def input_1(self): - """rv: [True, False]""" - return self.get(self.KEY_INPUT_1) - - @property - def longpush_0(self): - """rv: [True, False]""" - return self.get(self.KEY_LONGPUSH_0) - - @property - def longpush_1(self): - """rv: [True, False]""" - return self.get(self.KEY_LONGPUSH_1) - - @property - def temperature(self): - """rv: numeric value""" - return self.get(self.KEY_TEMPERATURE) - - # - # TX - # - def set_output_0(self, state): - """state: [True, False]""" - self.send_command(self.KEY_OUTPUT_0, state) - - def set_output_0_mcb(self, device, key, data): - self.logger.log(logging.INFO if data != self.output_0 else logging.DEBUG, "Changing output 0 to %s", str(data)) - self.set_output_0(data) - - def toggle_output_0_mcb(self, device, key, data): - self.logger.info("Toggeling output 0") - self.set_output_0(not self.output_0) - - def set_output_1(self, state): - """state: [True, False]""" - self.send_command(self.KEY_OUTPUT_1, state) - - def set_output_1_mcb(self, device, key, data): - self.logger.log(logging.INFO if data != self.output_1 else logging.DEBUG, "Changing output 1 to %s", str(data)) - self.set_output_1(data) - - def toggle_output_1_mcb(self, device, key, data): - self.logger.info("Toggeling output 1") - self.set_output_1(not self.output_1) - - def flash_0_mcb(self, device, key, data): - self.output_key_delayed = self.KEY_OUTPUT_0 - self.toggle_output_0_mcb(device, key, data) - self.delayed_flash_task.run() - - def flash_1_mcb(self, device, key, data): - self.output_key_delayed = self.KEY_OUTPUT_1 - self.toggle_output_1_mcb(device, key, data) - self.delayed_flash_task.run() - - def all_off(self): - if self.flash_active: - self.all_off_requested = True - else: - if self.output_0: - self.set_output_0(False) - if self.output_1: - self.set_output_1(False) - - -class silvercrest_powerplug(base): - """ Communication (MQTT) - - silvercrest_powerplug { - | "state": ["ON" / "OFF"] - | "linkquality": [0...255] lqi - | } - +- get { - | "state": "" - | } - +- set { - "state": ["ON" / "OFF"] - } - """ - KEY_LINKQUALITY = "linkquality" - KEY_OUTPUT_0 = "state" - # - TX_TYPE = base.TX_DICT - TX_FILTER_DATA_KEYS = [KEY_OUTPUT_0] - # - RX_KEYS = [KEY_LINKQUALITY, KEY_OUTPUT_0] - RX_FILTER_DATA_KEYS = [KEY_OUTPUT_0] - - def __init__(self, mqtt_client, topic): - super().__init__(mqtt_client, topic) - - # - # RX - # - @property - def output_0(self): - """rv: [True, False]""" - return self.get(self.KEY_OUTPUT_0) - - @property - def linkquality(self): - """rv: numeric value""" - return self.get(self.KEY_LINKQUALITY) - - # - # TX - # - def set_output_0(self, state): - """state: [True, False]""" - self.send_command(self.KEY_OUTPUT_0, state) - - def set_output_0_mcb(self, device, key, data): - self.logger.log(logging.INFO if data != self.output_0 else logging.DEBUG, "Changing output 0 to %s", str(data)) - self.set_output_0(data) - - def toggle_output_0_mcb(self, device, key, data): - self.logger.info("Toggeling output 0") - self.set_output_0(not self.output_0) - - def all_off(self): - if self.output_0: - self.set_output_0(False) - - -class silvercrest_motion_sensor(base): - """ Communication (MQTT) - - silvercrest_motion_sensor { - battery: [0...100] % - battery_low: [True, False] - linkquality: [0...255] lqi - occupancy: [True, False] - tamper: [True, False] - voltage: [0...] mV - } - """ - KEY_BATTERY = "battery" - KEY_BATTERY_LOW = "battery_low" - KEY_LINKQUALITY = "linkquality" - KEY_OCCUPANCY = "occupancy" - KEY_UNMOUNTED = "tamper" - KEY_VOLTAGE = "voltage" - # - TX_TYPE = base.TX_DICT - # - RX_KEYS = [KEY_BATTERY, KEY_BATTERY_LOW, KEY_LINKQUALITY, KEY_OCCUPANCY, KEY_UNMOUNTED, KEY_VOLTAGE] - - def __init__(self, mqtt_client, topic): - super().__init__(mqtt_client, topic) - # - self.add_callback(self.KEY_BATTERY_LOW, True, self.__warning__, True) - - # - # WARNING CALL - # - def __warning__(self, client, key, data): - w = warning(self.topic, warning.TYPE_BATTERY_LOW, "Battery low (%.1f%%)", self.get(self.KEY_BATTERY) or math.nan) - self.logger.warning(w) - self.set(self.KEY_WARNING, w) - - # - # RX - # - @property - def linkquality(self): - """rv: numeric value""" - return self.get(self.KEY_LINKQUALITY) - - @property - def battery(self): - """rv: numeric value""" - return self.get(self.KEY_BATTERY) - - -class my_powerplug(base): - """ Communication (MQTT) - - my_powerplug - +- output - +- 1 [True, False] <- status - | +- set [True, False, "toggle"] <- command - +- 2 [True, False] <- status - | +- set [True, False, "toggle"] <- command - +- 3 [True, False] <- status - | +- set [True, False, "toggle"] <- command - +- 4 [True, False] <- status - | +- set [True, False, "toggle"] <- command - +- all - +- set [True, False, "toggle"] <- command - """ - KEY_OUTPUT_0 = "output/1" - KEY_OUTPUT_1 = "output/2" - KEY_OUTPUT_2 = "output/3" - KEY_OUTPUT_3 = "output/4" - KEY_OUTPUT_ALL = "output/all" - KEY_OUTPUT_LIST = [KEY_OUTPUT_0, KEY_OUTPUT_1, KEY_OUTPUT_2, KEY_OUTPUT_3] - # - TX_TYPE = base.TX_VALUE - # - RX_KEYS = [KEY_OUTPUT_0, KEY_OUTPUT_1, KEY_OUTPUT_2, KEY_OUTPUT_3] - - def __init__(self, mqtt_client, topic): - super().__init__(mqtt_client, topic) - - # - # RX - # - @property - def output_0(self): - """rv: [True, False]""" - return self.get(self.KEY_OUTPUT_0) - - @property - def output_1(self): - """rv: [True, False]""" - return self.get(self.KEY_OUTPUT_1) - - @property - def output_2(self): - """rv: [True, False]""" - return self.get(self.KEY_OUTPUT_2) - - @property - def output_3(self): - """rv: [True, False]""" - return self.get(self.KEY_OUTPUT_3) - - # - # TX - # - def set_output(self, key, state): - if key in self.KEY_OUTPUT_LIST: - self.send_command(key, state) - else: - logging.error("Unknown key to set the output!") - - def set_output_0(self, state): - """state: [True, False]""" - self.send_command(self.KEY_OUTPUT_0, state) - - def set_output_0_mcb(self, device, key, data): - self.logger.log(logging.INFO if data != self.output_0 else logging.DEBUG, "Changing output 0 to %s", str(data)) - self.set_output_0(data) - - def toggle_output_0_mcb(self, device, key, data): - self.logger.info("Toggeling output 0") - self.set_output_0(not self.output_0) - - def set_output_1(self, state): - """state: [True, False]""" - self.send_command(self.KEY_OUTPUT_1, state) - - def set_output_1_mcb(self, device, key, data): - self.logger.log(logging.INFO if data != self.output_1 else logging.DEBUG, "Changing output 1 to %s", str(data)) - self.set_output_1(data) - - def toggle_output_1_mcb(self, device, key, data): - self.logger.info("Toggeling output 1") - self.set_output_1(not self.output_1) - - def set_output_2(self, state): - """state: [True, False]""" - self.send_command(self.KEY_OUTPUT_2, state) - - def set_output_2_mcb(self, device, key, data): - self.logger.log(logging.INFO if data != self.output_2 else logging.DEBUG, "Changing output 2 to %s", str(data)) - self.set_output_2(data) - - def toggle_output_2_mcb(self, device, key, data): - self.logger.info("Toggeling output 2") - self.set_output_2(not self.output_2) - - def set_output_3(self, state): - """state: [True, False]""" - self.send_command(self.KEY_OUTPUT_3, state) - - def set_output_3_mcb(self, device, key, data): - self.logger.log(logging.INFO if data != self.output_3 else logging.DEBUG, "Changing output 3 to %s", str(data)) - self.set_output_3(data) - - def toggle_output_3_mcb(self, device, key, data): - self.logger.info("Toggeling output 3") - self.set_output_3(not self.output_3) - - def set_output_all(self, state): - """state: [True, False, 'toggle']""" - self.send_command(self.KEY_OUTPUT_ALL, state) - - def set_output_all_mcb(self, device, key, data): - self.logger.info("Changing all outputs to %s", str(data)) - self.set_output_all(data) - - def all_off(self): - self.set_output_all(False) - - -class tradfri_light(base): - """ Communication (MQTT) - - tradfri_light { - | "state": ["ON" / "OFF" / "TOGGLE"] - | "linkquality": [0...255] lqi - | "brightness": [0...254] - | "color_mode": ["color_temp"] - | "color_temp": ["coolest", "cool", "neutral", "warm", "warmest", 250...454] - | "color_temp_startup": ["coolest", "cool", "neutral", "warm", "warmest", "previous", 250...454] - | "update": [] - | } - +- get { - | "state": "" - | } - +- set { - "state": ["ON" / "OFF"] - "brightness": [0...256] - "color_temp": [250...454] - "transition": [0...] seconds - "brightness_move": [-X...0...X] X/s - "brightness_step": [-X...0...X] - "color_temp_move": [-X...0...X] X/s - "color_temp_step": [-X...0...X] - } - """ - KEY_LINKQUALITY = "linkquality" - KEY_OUTPUT_0 = "state" - KEY_BRIGHTNESS = "brightness" - KEY_COLOR_TEMP = "color_temp" - KEY_BRIGHTNESS_FADE = "brightness_move" - # - TX_TYPE = base.TX_DICT - TX_FILTER_DATA_KEYS = [KEY_OUTPUT_0, KEY_BRIGHTNESS, KEY_COLOR_TEMP, KEY_BRIGHTNESS_FADE] - # - RX_KEYS = [KEY_LINKQUALITY, KEY_OUTPUT_0, KEY_BRIGHTNESS, KEY_COLOR_TEMP] - RX_IGNORE_KEYS = ['update', 'color_mode', 'color_temp_startup'] - RX_FILTER_DATA_KEYS = [KEY_OUTPUT_0, KEY_BRIGHTNESS, KEY_COLOR_TEMP] - - def __init__(self, mqtt_client, topic): - super().__init__(mqtt_client, topic) - - def __device_to_instance_filter__(self, key, data): - if key == self.KEY_BRIGHTNESS: - return int(round((data - 1) * 100 / 253, 0)) - elif key == self.KEY_COLOR_TEMP: - return int(round((data - 250) * 10 / 204, 0)) - return super().__device_to_instance_filter__(key, data) - - def __instance_to_device_filter__(self, key, data): - if key == self.KEY_BRIGHTNESS: - return int(round(data * 253 / 100 + 1, 0)) - elif key == self.KEY_COLOR_TEMP: - return int(round(data * 204 / 10 + 250, 0)) - return super().__instance_to_device_filter__(key, data) - - # - # RX - # - @property - def output_0(self): - """rv: [True, False]""" - return self.get(self.KEY_OUTPUT_0, False) - - @property - def linkquality(self): - """rv: numeric value""" - return self.get(self.KEY_LINKQUALITY, 0) - - @property - def brightness(self): - """rv: numeric value [0%, ..., 100%]""" - return self.get(self.KEY_BRIGHTNESS, 0) - - @property - def color_temp(self): - """rv: numeric value [0, ..., 10]""" - return self.get(self.KEY_COLOR_TEMP, 0) - - # - # TX - # - def request_data(self, device=None, key=None, data=None): - self.mqtt_client.send(self.topic + "/get", '{"%s": ""}' % self.KEY_OUTPUT_0) - - def set_output_0(self, state): - """state: [True, False]""" - self.send_command(self.KEY_OUTPUT_0, state) - - def set_output_0_mcb(self, device, key, data): - self.logger.log(logging.INFO if data != self.output_0 else logging.DEBUG, "Changing output 0 to %s", str(data)) - self.set_output_0(data) - - def toggle_output_0_mcb(self, device, key, data): - self.logger.info("Toggeling output 0") - self.set_output_0(not self.output_0) - - def set_brightness(self, brightness): - """brightness: [0, ..., 100]""" - self.send_command(self.KEY_BRIGHTNESS, brightness) - - def set_brightness_mcb(self, device, key, data): - self.logger.log(logging.INFO if data != self.brightness else logging.DEBUG, "Changing brightness to %s", str(data)) - self.set_brightness(data) - - def default_inc(self, speed=40): - self.send_command(self.KEY_BRIGHTNESS_FADE, speed) - - def default_dec(self, speed=-40): - self.default_inc(speed) - - def default_stop(self): - self.default_inc(0) - - def set_color_temp(self, color_temp): - """color_temp: [0, ..., 10]""" - self.send_command(self.KEY_COLOR_TEMP, color_temp) - - def set_color_temp_mcb(self, device, key, data): - self.logger.log(logging.INFO if data != self.color_temp else logging.DEBUG, "Changing color temperature to %s", str(data)) - self.set_color_temp(data) - - def all_off(self): - if self.output_0: - self.set_output_0(False) - - -class tradfri_button(base): - """ Communication (MQTT) - - tradfri_button { - "action": [ - "arrow_left_click", - "arrow_left_hold", - "arrow_left_release", - "arrow_right_click", - "arrow_right_hold", - "arrow_right_release", - "brightness_down_click", - "brightness_down_hold", - "brightness_down_release", - "brightness_up_click", - "brightness_up_hold", - "brightness_up_release", - "toggle" - ] - "action_duration": [0...] s - "battery": [0...100] % - "linkquality": [0...255] lqi - "update": [] - } - """ - ACTION_TOGGLE = "toggle" - ACTION_BRIGHTNESS_UP = "brightness_up_click" - ACTION_BRIGHTNESS_DOWN = "brightness_down_click" - ACTION_RIGHT = "arrow_right_click" - ACTION_LEFT = "arrow_left_click" - ACTION_BRIGHTNESS_UP_LONG = "brightness_up_hold" - ACTION_BRIGHTNESS_UP_RELEASE = "brightness_up_release" - ACTION_BRIGHTNESS_DOWN_LONG = "brightness_down_hold" - ACTION_BRIGHTNESS_DOWN_RELEASE = "brightness_down_release" - ACTION_RIGHT_LONG = "arrow_right_hold" - ACTION_RIGHT_RELEASE = "arrow_right_release" - ACTION_LEFT_LONG = "arrow_left_hold" - ACTION_LEFT_RELEASE = "arrow_left_release" - # - KEY_LINKQUALITY = "linkquality" - KEY_BATTERY = "battery" - KEY_ACTION = "action" - KEY_ACTION_DURATION = "action_duration" - # - RX_KEYS = [KEY_LINKQUALITY, KEY_BATTERY, KEY_ACTION] - RX_IGNORE_KEYS = ['update', KEY_ACTION_DURATION] - - def __init__(self, mqtt_client, topic): - super().__init__(mqtt_client, topic) - # - self.add_callback(self.KEY_BATTERY, None, self.__warning__, True) - self.__battery_warning__ = False - - # - # WARNING CALL - # - def __warning__(self, client, key, data): - if data <= BATTERY_WARN_LEVEL: - if not self.__battery_warning__: - w = warning(self.topic, warning.TYPE_BATTERY_LOW, "Battery low (%.1f%%)", data) - self.logger.warning(w) - self.set(self.KEY_WARNING, w) - else: - self.__battery_warning__ = False - - # - # RX - # - @property - def action(self): - """rv: action_txt""" - return self.get(self.KEY_ACTION) - - -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" - # - 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] - - 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", self.KEY_PRESET: "manual"})) - # - self.add_callback(self.KEY_BATTERY, None, self.__warning__, True) - self.__battery_warning__ = False - - # - # WARNING CALL - # - def __warning__(self, client, key, data): - if data <= BATTERY_WARN_LEVEL: - if not self.__battery_warning__: - self.__battery_warning__ = True - w = warning(self.topic, warning.TYPE_BATTERY_LOW, "Battery low (%.1f%%)", data) - self.logger.warning(w) - self.set(self.KEY_WARNING, w) - else: - self.__battery_warning__ = False - - # - # 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.logger.info("Changing heating setpoint to %s", str(data)) - self.set_heating_setpoint(data) - - -class remote(base): - """ Communication (MQTT) - - remote (RAS5) <- command - +- CD [dc] - +- LINE1 [dc] - +- LINE2 [dc] - +- LINE3 [dc] - +- MUTE [dc] - +- POWER [dc] - +- VOLDOWN [dc] - +- VOLUP [dc] - +- PHONO [dc] - +- DOCK [dc] - - remote (EUR642100) <- command - +- OPEN_CLOSE [dc] - +- VOLDOWN [dc] - +- VOLUP [dc] - +- ONE [dc] - +- TWO [dc] - +- THREE [dc] - +- FOUR [dc] - +- FIVE [dc] - +- SIX [dc] - +- SEVEN [dc] - +- EIGHT [dc] - +- NINE [dc] - +- ZERO [dc] - +- TEN [dc] - +- TEN_PLUS [dc] - +- PROGRAM [dc] - +- CLEAR [dc] - +- RECALL [dc] - +- TIME_MODE [dc] - +- A_B_REPEAT [dc] - +- REPEAT [dc] - +- RANDOM [dc] - +- AUTO_CUE [dc] - +- TAPE_LENGTH [dc] - +- SIDE_A_B [dc] - +- TIME_FADE [dc] - +- PEAK_SEARCH [dc] - +- SEARCH_BACK [dc] - +- SEARCH_FOR [dc] - +- TRACK_NEXT [dc] - +- TRACK_PREV [dc] - +- STOP [dc] - +- PAUSE [dc] - +- PLAY [dc] - """ - KEY_CD = "CD" - KEY_LINE1 = "LINE1" - KEY_LINE3 = "LINE3" - KEY_MUTE = "MUTE" - KEY_POWER = "POWER" - KEY_VOLDOWN = "VOLDOWN" - KEY_VOLUP = "VOLUP" - # - TX_TOPIC = '' - TX_TYPE = base.TX_VALUE - # - RX_IGNORE_TOPICS = [KEY_CD, KEY_LINE1, KEY_LINE3, KEY_MUTE, KEY_POWER, KEY_VOLUP, KEY_VOLDOWN] - - def set_cd(self, device=None, key=None, data=None): - self.send_command(self.KEY_CD, None) - - def set_line1(self, device=None, key=None, data=None): - self.send_command(self.KEY_LINE1, None) - - def set_line3(self, device=None, key=None, data=None): - self.send_command(self.KEY_LINE3, None) - - def set_mute(self, device=None, key=None, data=None): - self.send_command(self.KEY_MUTE, None) - - def set_power(self, device=None, key=None, data=None): - self.send_command(self.KEY_POWER, None) - - def set_volume_up(self, data=False): - """data: [True, False]""" - self.send_command(self.KEY_VOLUP, data) - - def set_volume_down(self, data=False): - """data: [True, False]""" - self.send_command(self.KEY_VOLDOWN, data) - - def default_inc(self, device=None, key=None, data=None): - self.set_volume_up(True) - - def default_dec(self, device=None, key=None, data=None): - self.set_volume_down(True) - - def default_stop(self, device=None, key=None, data=None): - self.set_volume_up(False) - - -class audio_status(base): - """ Communication (MQTT) - - audio_status - +- state [True, False] <- status - +- title [text] <- status - """ - KEY_STATE = "state" - KEY_TITLE = "title" - # - TX_TYPE = base.TX_VALUE - # - RX_KEYS = [KEY_STATE, KEY_TITLE] - - def set_state(self, num, data): - """data: [True, False]""" - self.send_command(self.KEY_STATE + "/" + str(num), data) - - def set_state_mcb(self, device, key, data): - self.logger.info("Changing state to %s", str(data)) - self.set_state(data) + KEY_ID = 'id' + KEY_TYPE = 'type' + KEY_TEXT = 'text' + KEY_TM = 'tm' + + def __init__(self, identification, type, text, args): + super().__init__({ + self.KEY_ID: identification, + self.KEY_TYPE: type, + self.KEY_TEXT: text % args, + self.KEY_TM: time.localtime(), + }) + + def __str__(self): + return time.asctime(self.get(self.KEY_TM)) + ": " + self[self.KEY_TEXT] + " - " + self[self.KEY_ID] diff --git a/devices/base.py b/devices/base.py new file mode 100644 index 0000000..6107e0a --- /dev/null +++ b/devices/base.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +from base import mqtt_base +from base import videv_base +import json + +BATTERY_WARN_LEVEL = 10 + + +def is_json(data): + try: + json.loads(data) + except json.decoder.JSONDecodeError: + return False + else: + return True + + +class base(mqtt_base): + TX_TOPIC = "set" + TX_VALUE = 0 + TX_DICT = 1 + TX_TYPE = -1 + TX_FILTER_DATA_KEYS = [] + # + RX_KEYS = [] + RX_IGNORE_TOPICS = [] + RX_IGNORE_KEYS = [] + RX_FILTER_DATA_KEYS = [] + # + KEY_WARNING = '__WARNING__' + + def __init__(self, mqtt_client, topic): + super().__init__(mqtt_client, topic, default_values=dict.fromkeys(self.RX_KEYS + [self.KEY_WARNING])) + # data storage + # initialisations + mqtt_client.add_callback(topic=self.topic, callback=self.receive_callback) + mqtt_client.add_callback(topic=self.topic+"/#", callback=self.receive_callback) + + def set(self, key, data, block_callback=[]): + if key in self.RX_IGNORE_KEYS: + pass # ignore these keys + elif key in self.RX_KEYS or key == self.KEY_WARNING: + return super().set(key, data, block_callback) + else: + self.logger.warning("Unexpected key %s", key) + + def receive_callback(self, client, userdata, message): + if message.topic != self.topic + '/' + videv_base.KEY_INFO: + content_key = message.topic[len(self.topic) + 1:] + if content_key not in self.RX_IGNORE_TOPICS and (not message.topic.endswith(self.TX_TOPIC) or len(self.TX_TOPIC) == 0): + self.logger.debug("Unpacking content_key \"%s\" from message.", content_key) + if is_json(message.payload): + data = json.loads(message.payload) + if type(data) is dict: + for key in data: + self.set(key, self.__device_to_instance_filter__(key, data[key])) + else: + self.set(content_key, self.__device_to_instance_filter__(content_key, data)) + # String + else: + self.set(content_key, self.__device_to_instance_filter__(content_key, message.payload.decode('utf-8'))) + else: + self.logger.debug("Ignoring topic %s", content_key) + + def __device_to_instance_filter__(self, key, data): + if key in self.RX_FILTER_DATA_KEYS: + if data in [1, 'on', 'ON']: + return True + elif data in [0, 'off', 'OFF']: + return False + return data + + def __instance_to_device_filter__(self, key, data): + if key in self.TX_FILTER_DATA_KEYS: + if data is True: + return "on" + elif data is False: + return "off" + return data + + def send_command(self, key, data): + data = self.__instance_to_device_filter__(key, data) + if self.TX_TOPIC is not None: + if self.TX_TYPE < 0: + self.logger.error("Unknown tx type. Set TX_TYPE of class to a known value") + else: + self.logger.debug("Sending data for %s - %s", key, str(data)) + if self.TX_TYPE == self.TX_DICT: + try: + self.mqtt_client.send('/'.join([self.topic, self.TX_TOPIC]), json.dumps({key: data})) + except TypeError: + print(self.topic) + print(key.__dict__) + print(key) + print(data) + raise TypeError + else: + if type(data) not in [str, bytes]: + data = json.dumps(data) + self.mqtt_client.send('/'.join([self.topic, key, self.TX_TOPIC] if len(self.TX_TOPIC) > 0 else [self.topic, key]), data) + else: + self.logger.error("Unknown tx toptic. Set TX_TOPIC of class to a known value") diff --git a/devices/brennenstuhl.py b/devices/brennenstuhl.py new file mode 100644 index 0000000..48ebb70 --- /dev/null +++ b/devices/brennenstuhl.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +from devices.base import base +from devices.base import BATTERY_WARN_LEVEL +import json + + +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" + # + 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] + + 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", self.KEY_PRESET: "manual"})) + # + self.add_callback(self.KEY_BATTERY, None, self.__warning__, True) + self.__battery_warning__ = False + + # + # WARNING CALL + # + def __warning__(self, client, key, data): + if data <= BATTERY_WARN_LEVEL: + if not self.__battery_warning__: + self.__battery_warning__ = True + w = warning(self.topic, warning.TYPE_BATTERY_LOW, "Battery low (%.1f%%)", data) + self.logger.warning(w) + self.set(self.KEY_WARNING, w) + else: + self.__battery_warning__ = False + + # + # 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.logger.info("Changing heating setpoint to %s", str(data)) + self.set_heating_setpoint(data) diff --git a/devices/mydevices.py b/devices/mydevices.py new file mode 100644 index 0000000..e05794d --- /dev/null +++ b/devices/mydevices.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +from devices.base import base +import logging + + +class powerplug(base): + """ Communication (MQTT) + + my_powerplug + +- output + +- 1 [True, False] <- status + | +- set [True, False, "toggle"] <- command + +- 2 [True, False] <- status + | +- set [True, False, "toggle"] <- command + +- 3 [True, False] <- status + | +- set [True, False, "toggle"] <- command + +- 4 [True, False] <- status + | +- set [True, False, "toggle"] <- command + +- all + +- set [True, False, "toggle"] <- command + """ + KEY_OUTPUT_0 = "output/1" + KEY_OUTPUT_1 = "output/2" + KEY_OUTPUT_2 = "output/3" + KEY_OUTPUT_3 = "output/4" + KEY_OUTPUT_ALL = "output/all" + KEY_OUTPUT_LIST = [KEY_OUTPUT_0, KEY_OUTPUT_1, KEY_OUTPUT_2, KEY_OUTPUT_3] + # + TX_TYPE = base.TX_VALUE + # + RX_KEYS = [KEY_OUTPUT_0, KEY_OUTPUT_1, KEY_OUTPUT_2, KEY_OUTPUT_3] + + def __init__(self, mqtt_client, topic): + super().__init__(mqtt_client, topic) + + # + # RX + # + @property + def output_0(self): + """rv: [True, False]""" + return self.get(self.KEY_OUTPUT_0) + + @property + def output_1(self): + """rv: [True, False]""" + return self.get(self.KEY_OUTPUT_1) + + @property + def output_2(self): + """rv: [True, False]""" + return self.get(self.KEY_OUTPUT_2) + + @property + def output_3(self): + """rv: [True, False]""" + return self.get(self.KEY_OUTPUT_3) + + # + # TX + # + def set_output(self, key, state): + if key in self.KEY_OUTPUT_LIST: + self.send_command(key, state) + else: + logging.error("Unknown key to set the output!") + + def set_output_0(self, state): + """state: [True, False]""" + self.send_command(self.KEY_OUTPUT_0, state) + + def set_output_0_mcb(self, device, key, data): + self.logger.log(logging.INFO if data != self.output_0 else logging.DEBUG, "Changing output 0 to %s", str(data)) + self.set_output_0(data) + + def toggle_output_0_mcb(self, device, key, data): + self.logger.info("Toggeling output 0") + self.set_output_0(not self.output_0) + + def set_output_1(self, state): + """state: [True, False]""" + self.send_command(self.KEY_OUTPUT_1, state) + + def set_output_1_mcb(self, device, key, data): + self.logger.log(logging.INFO if data != self.output_1 else logging.DEBUG, "Changing output 1 to %s", str(data)) + self.set_output_1(data) + + def toggle_output_1_mcb(self, device, key, data): + self.logger.info("Toggeling output 1") + self.set_output_1(not self.output_1) + + def set_output_2(self, state): + """state: [True, False]""" + self.send_command(self.KEY_OUTPUT_2, state) + + def set_output_2_mcb(self, device, key, data): + self.logger.log(logging.INFO if data != self.output_2 else logging.DEBUG, "Changing output 2 to %s", str(data)) + self.set_output_2(data) + + def toggle_output_2_mcb(self, device, key, data): + self.logger.info("Toggeling output 2") + self.set_output_2(not self.output_2) + + def set_output_3(self, state): + """state: [True, False]""" + self.send_command(self.KEY_OUTPUT_3, state) + + def set_output_3_mcb(self, device, key, data): + self.logger.log(logging.INFO if data != self.output_3 else logging.DEBUG, "Changing output 3 to %s", str(data)) + self.set_output_3(data) + + def toggle_output_3_mcb(self, device, key, data): + self.logger.info("Toggeling output 3") + self.set_output_3(not self.output_3) + + def set_output_all(self, state): + """state: [True, False, 'toggle']""" + self.send_command(self.KEY_OUTPUT_ALL, state) + + def set_output_all_mcb(self, device, key, data): + self.logger.info("Changing all outputs to %s", str(data)) + self.set_output_all(data) + + def all_off(self): + self.set_output_all(False) + + +class remote(base): + """ Communication (MQTT) + + remote (RAS5) <- command + +- CD [dc] + +- LINE1 [dc] + +- LINE2 [dc] + +- LINE3 [dc] + +- MUTE [dc] + +- POWER [dc] + +- VOLDOWN [dc] + +- VOLUP [dc] + +- PHONO [dc] + +- DOCK [dc] + + remote (EUR642100) <- command + +- OPEN_CLOSE [dc] + +- VOLDOWN [dc] + +- VOLUP [dc] + +- ONE [dc] + +- TWO [dc] + +- THREE [dc] + +- FOUR [dc] + +- FIVE [dc] + +- SIX [dc] + +- SEVEN [dc] + +- EIGHT [dc] + +- NINE [dc] + +- ZERO [dc] + +- TEN [dc] + +- TEN_PLUS [dc] + +- PROGRAM [dc] + +- CLEAR [dc] + +- RECALL [dc] + +- TIME_MODE [dc] + +- A_B_REPEAT [dc] + +- REPEAT [dc] + +- RANDOM [dc] + +- AUTO_CUE [dc] + +- TAPE_LENGTH [dc] + +- SIDE_A_B [dc] + +- TIME_FADE [dc] + +- PEAK_SEARCH [dc] + +- SEARCH_BACK [dc] + +- SEARCH_FOR [dc] + +- TRACK_NEXT [dc] + +- TRACK_PREV [dc] + +- STOP [dc] + +- PAUSE [dc] + +- PLAY [dc] + """ + KEY_CD = "CD" + KEY_LINE1 = "LINE1" + KEY_LINE3 = "LINE3" + KEY_MUTE = "MUTE" + KEY_POWER = "POWER" + KEY_VOLDOWN = "VOLDOWN" + KEY_VOLUP = "VOLUP" + # + TX_TOPIC = '' + TX_TYPE = base.TX_VALUE + # + RX_IGNORE_TOPICS = [KEY_CD, KEY_LINE1, KEY_LINE3, KEY_MUTE, KEY_POWER, KEY_VOLUP, KEY_VOLDOWN] + + def set_cd(self, device=None, key=None, data=None): + self.send_command(self.KEY_CD, None) + + def set_line1(self, device=None, key=None, data=None): + self.send_command(self.KEY_LINE1, None) + + def set_line3(self, device=None, key=None, data=None): + self.send_command(self.KEY_LINE3, None) + + def set_mute(self, device=None, key=None, data=None): + self.send_command(self.KEY_MUTE, None) + + def set_power(self, device=None, key=None, data=None): + self.send_command(self.KEY_POWER, None) + + def set_volume_up(self, data=False): + """data: [True, False]""" + self.send_command(self.KEY_VOLUP, data) + + def set_volume_down(self, data=False): + """data: [True, False]""" + self.send_command(self.KEY_VOLDOWN, data) + + def default_inc(self, device=None, key=None, data=None): + self.set_volume_up(True) + + def default_dec(self, device=None, key=None, data=None): + self.set_volume_down(True) + + def default_stop(self, device=None, key=None, data=None): + self.set_volume_up(False) + + +class audio_status(base): + """ Communication (MQTT) + + audio_status + +- state [True, False] <- status + +- title [text] <- status + """ + KEY_STATE = "state" + KEY_TITLE = "title" + # + TX_TYPE = base.TX_VALUE + # + RX_KEYS = [KEY_STATE, KEY_TITLE] + + def set_state(self, num, data): + """data: [True, False]""" + self.send_command(self.KEY_STATE + "/" + str(num), data) + + def set_state_mcb(self, device, key, data): + self.logger.info("Changing state to %s", str(data)) + self.set_state(data) diff --git a/devices/shelly.py b/devices/shelly.py new file mode 100644 index 0000000..8870ad3 --- /dev/null +++ b/devices/shelly.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +from devices.base import base +import logging +import task + + +class shelly(base): + """ Communication (MQTT) + + shelly + +- relay + | +- 0 ["on" / "off"] <- status + | | +- command ["on"/ "off"] <- command + | | +- energy [numeric] <- status + | +- 1 ["on" / "off"] <- status + | +- command ["on"/ "off"] <- command + | +- energy [numeric] <- status + +- input + | +- 0 [0 / 1] <- status + | +- 1 [0 / 1] <- status + +- input_event + | +- 0 <- status + | +- 1 <- status + +- logpush + | +- 0 [0 / 1] <- status + | +- 1 [0 / 1] <- status + +- temperature [numeric] °C <- status + +- temperature_f [numeric] F <- status + +- overtemperature [0 / 1] <- status + +- id <- status + +- model <- status + +- mac <- status + +- ip <- status + +- new_fw <- status + +- fw_ver <- status + """ + KEY_OUTPUT_0 = "relay/0" + KEY_OUTPUT_1 = "relay/1" + KEY_INPUT_0 = "input/0" + KEY_INPUT_1 = "input/1" + KEY_LONGPUSH_0 = "longpush/0" + KEY_LONGPUSH_1 = "longpush/1" + KEY_TEMPERATURE = "temperature" + KEY_OVERTEMPERATURE = "overtemperature" + KEY_ID = "id" + KEY_MODEL = "model" + KEY_MAC = "mac" + KEY_IP = "ip" + KEY_NEW_FIRMWARE = "new_fw" + KEY_FIRMWARE_VERSION = "fw_ver" + # + TX_TOPIC = "command" + TX_TYPE = base.TX_VALUE + TX_FILTER_DATA_KEYS = [KEY_OUTPUT_0, KEY_OUTPUT_1] + # + RX_KEYS = [KEY_OUTPUT_0, KEY_OUTPUT_1, KEY_INPUT_0, KEY_INPUT_1, KEY_LONGPUSH_0, KEY_LONGPUSH_1, KEY_OVERTEMPERATURE, KEY_TEMPERATURE, + KEY_ID, KEY_MODEL, KEY_MAC, KEY_IP, KEY_NEW_FIRMWARE, KEY_FIRMWARE_VERSION] + RX_IGNORE_TOPICS = [KEY_OUTPUT_0 + '/' + "energy", KEY_OUTPUT_1 + '/' + "energy", 'input_event/0', 'input_event/1'] + RX_IGNORE_KEYS = ['temperature_f'] + RX_FILTER_DATA_KEYS = [KEY_INPUT_0, KEY_INPUT_1, KEY_LONGPUSH_0, KEY_LONGPUSH_1, KEY_OUTPUT_0, KEY_OUTPUT_1, KEY_OVERTEMPERATURE] + + def __init__(self, mqtt_client, topic): + super().__init__(mqtt_client, topic) + # + self.output_key_delayed = None + self.delayed_flash_task = task.delayed(0.3, self.flash_task) + self.delayed_off_task = task.delayed(0.3, self.off_task) + # + self.add_callback(self.KEY_OVERTEMPERATURE, True, self.__warning__, True) + # + self.all_off_requested = False + + def flash_task(self, *args): + if self.flash_active: + self.send_command(self.output_key_delayed, not self.get(self.output_key_delayed)) + self.output_key_delayed = None + if self.all_off_requested: + self.delayed_off_task.run() + + def off_task(self, *args): + self.all_off() + + @property + def flash_active(self): + return self.output_key_delayed is not None + + # + # WARNING CALL + # + def __warning__(self, client, key, data): + w = warning(self.topic, warning.TYPE_OVERTEMPERATURE, "Temperature to high (%.1f°C)", self.get(self.KEY_TEMPERATURE) or math.nan) + self.logger.warning(w) + self.set(self.KEY_WARNING, w) + + # + # RX + # + @property + def output_0(self): + """rv: [True, False]""" + return self.get(self.KEY_OUTPUT_0) + + @property + def output_1(self): + """rv: [True, False]""" + return self.get(self.KEY_OUTPUT_1) + + @property + def input_0(self): + """rv: [True, False]""" + return self.get(self.KEY_INPUT_0) + + @property + def input_1(self): + """rv: [True, False]""" + return self.get(self.KEY_INPUT_1) + + @property + def longpush_0(self): + """rv: [True, False]""" + return self.get(self.KEY_LONGPUSH_0) + + @property + def longpush_1(self): + """rv: [True, False]""" + return self.get(self.KEY_LONGPUSH_1) + + @property + def temperature(self): + """rv: numeric value""" + return self.get(self.KEY_TEMPERATURE) + + # + # TX + # + def set_output_0(self, state): + """state: [True, False]""" + self.send_command(self.KEY_OUTPUT_0, state) + + def set_output_0_mcb(self, device, key, data): + self.logger.log(logging.INFO if data != self.output_0 else logging.DEBUG, "Changing output 0 to %s", str(data)) + self.set_output_0(data) + + def toggle_output_0_mcb(self, device, key, data): + self.logger.info("Toggeling output 0") + self.set_output_0(not self.output_0) + + def set_output_1(self, state): + """state: [True, False]""" + self.send_command(self.KEY_OUTPUT_1, state) + + def set_output_1_mcb(self, device, key, data): + self.logger.log(logging.INFO if data != self.output_1 else logging.DEBUG, "Changing output 1 to %s", str(data)) + self.set_output_1(data) + + def toggle_output_1_mcb(self, device, key, data): + self.logger.info("Toggeling output 1") + self.set_output_1(not self.output_1) + + def flash_0_mcb(self, device, key, data): + self.output_key_delayed = self.KEY_OUTPUT_0 + self.toggle_output_0_mcb(device, key, data) + self.delayed_flash_task.run() + + def flash_1_mcb(self, device, key, data): + self.output_key_delayed = self.KEY_OUTPUT_1 + self.toggle_output_1_mcb(device, key, data) + self.delayed_flash_task.run() + + def all_off(self): + if self.flash_active: + self.all_off_requested = True + else: + if self.output_0: + self.set_output_0(False) + if self.output_1: + self.set_output_1(False) diff --git a/devices/silvercrest.py b/devices/silvercrest.py new file mode 100644 index 0000000..db931f5 --- /dev/null +++ b/devices/silvercrest.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +from devices.base import base +import logging + + +class silvercrest_powerplug(base): + """ Communication (MQTT) + + silvercrest_powerplug { + | "state": ["ON" / "OFF"] + | "linkquality": [0...255] lqi + | } + +- get { + | "state": "" + | } + +- set { + "state": ["ON" / "OFF"] + } + """ + KEY_LINKQUALITY = "linkquality" + KEY_OUTPUT_0 = "state" + # + TX_TYPE = base.TX_DICT + TX_FILTER_DATA_KEYS = [KEY_OUTPUT_0] + # + RX_KEYS = [KEY_LINKQUALITY, KEY_OUTPUT_0] + RX_FILTER_DATA_KEYS = [KEY_OUTPUT_0] + + def __init__(self, mqtt_client, topic): + super().__init__(mqtt_client, topic) + + # + # RX + # + @property + def output_0(self): + """rv: [True, False]""" + return self.get(self.KEY_OUTPUT_0) + + @property + def linkquality(self): + """rv: numeric value""" + return self.get(self.KEY_LINKQUALITY) + + # + # TX + # + def set_output_0(self, state): + """state: [True, False]""" + self.send_command(self.KEY_OUTPUT_0, state) + + def set_output_0_mcb(self, device, key, data): + self.logger.log(logging.INFO if data != self.output_0 else logging.DEBUG, "Changing output 0 to %s", str(data)) + self.set_output_0(data) + + def toggle_output_0_mcb(self, device, key, data): + self.logger.info("Toggeling output 0") + self.set_output_0(not self.output_0) + + def all_off(self): + if self.output_0: + self.set_output_0(False) + + +class silvercrest_motion_sensor(base): + """ Communication (MQTT) + + silvercrest_motion_sensor { + battery: [0...100] % + battery_low: [True, False] + linkquality: [0...255] lqi + occupancy: [True, False] + tamper: [True, False] + voltage: [0...] mV + } + """ + KEY_BATTERY = "battery" + KEY_BATTERY_LOW = "battery_low" + KEY_LINKQUALITY = "linkquality" + KEY_OCCUPANCY = "occupancy" + KEY_UNMOUNTED = "tamper" + KEY_VOLTAGE = "voltage" + # + TX_TYPE = base.TX_DICT + # + RX_KEYS = [KEY_BATTERY, KEY_BATTERY_LOW, KEY_LINKQUALITY, KEY_OCCUPANCY, KEY_UNMOUNTED, KEY_VOLTAGE] + + def __init__(self, mqtt_client, topic): + super().__init__(mqtt_client, topic) + # + self.add_callback(self.KEY_BATTERY_LOW, True, self.__warning__, True) + + # + # WARNING CALL + # + def __warning__(self, client, key, data): + w = warning(self.topic, warning.TYPE_BATTERY_LOW, "Battery low (%.1f%%)", self.get(self.KEY_BATTERY) or math.nan) + self.logger.warning(w) + self.set(self.KEY_WARNING, w) + + # + # RX + # + @property + def linkquality(self): + """rv: numeric value""" + return self.get(self.KEY_LINKQUALITY) + + @property + def battery(self): + """rv: numeric value""" + return self.get(self.KEY_BATTERY) diff --git a/devices/tradfri.py b/devices/tradfri.py new file mode 100644 index 0000000..6b4453b --- /dev/null +++ b/devices/tradfri.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +from devices.base import base +from devices.base import BATTERY_WARN_LEVEL +import logging + + +class tradfri_light(base): + """ Communication (MQTT) + + tradfri_light { + | "state": ["ON" / "OFF" / "TOGGLE"] + | "linkquality": [0...255] lqi + | "brightness": [0...254] + | "color_mode": ["color_temp"] + | "color_temp": ["coolest", "cool", "neutral", "warm", "warmest", 250...454] + | "color_temp_startup": ["coolest", "cool", "neutral", "warm", "warmest", "previous", 250...454] + | "update": [] + | } + +- get { + | "state": "" + | } + +- set { + "state": ["ON" / "OFF"] + "brightness": [0...256] + "color_temp": [250...454] + "transition": [0...] seconds + "brightness_move": [-X...0...X] X/s + "brightness_step": [-X...0...X] + "color_temp_move": [-X...0...X] X/s + "color_temp_step": [-X...0...X] + } + """ + KEY_LINKQUALITY = "linkquality" + KEY_OUTPUT_0 = "state" + KEY_BRIGHTNESS = "brightness" + KEY_COLOR_TEMP = "color_temp" + KEY_BRIGHTNESS_FADE = "brightness_move" + # + TX_TYPE = base.TX_DICT + TX_FILTER_DATA_KEYS = [KEY_OUTPUT_0, KEY_BRIGHTNESS, KEY_COLOR_TEMP, KEY_BRIGHTNESS_FADE] + # + RX_KEYS = [KEY_LINKQUALITY, KEY_OUTPUT_0, KEY_BRIGHTNESS, KEY_COLOR_TEMP] + RX_IGNORE_KEYS = ['update', 'color_mode', 'color_temp_startup'] + RX_FILTER_DATA_KEYS = [KEY_OUTPUT_0, KEY_BRIGHTNESS, KEY_COLOR_TEMP] + + def __init__(self, mqtt_client, topic): + super().__init__(mqtt_client, topic) + + def __device_to_instance_filter__(self, key, data): + if key == self.KEY_BRIGHTNESS: + return int(round((data - 1) * 100 / 253, 0)) + elif key == self.KEY_COLOR_TEMP: + return int(round((data - 250) * 10 / 204, 0)) + return super().__device_to_instance_filter__(key, data) + + def __instance_to_device_filter__(self, key, data): + if key == self.KEY_BRIGHTNESS: + return int(round(data * 253 / 100 + 1, 0)) + elif key == self.KEY_COLOR_TEMP: + return int(round(data * 204 / 10 + 250, 0)) + return super().__instance_to_device_filter__(key, data) + + # + # RX + # + @property + def output_0(self): + """rv: [True, False]""" + return self.get(self.KEY_OUTPUT_0, False) + + @property + def linkquality(self): + """rv: numeric value""" + return self.get(self.KEY_LINKQUALITY, 0) + + @property + def brightness(self): + """rv: numeric value [0%, ..., 100%]""" + return self.get(self.KEY_BRIGHTNESS, 0) + + @property + def color_temp(self): + """rv: numeric value [0, ..., 10]""" + return self.get(self.KEY_COLOR_TEMP, 0) + + # + # TX + # + def request_data(self, device=None, key=None, data=None): + self.mqtt_client.send(self.topic + "/get", '{"%s": ""}' % self.KEY_OUTPUT_0) + + def set_output_0(self, state): + """state: [True, False]""" + self.send_command(self.KEY_OUTPUT_0, state) + + def set_output_0_mcb(self, device, key, data): + self.logger.log(logging.INFO if data != self.output_0 else logging.DEBUG, "Changing output 0 to %s", str(data)) + self.set_output_0(data) + + def toggle_output_0_mcb(self, device, key, data): + self.logger.info("Toggeling output 0") + self.set_output_0(not self.output_0) + + def set_brightness(self, brightness): + """brightness: [0, ..., 100]""" + self.send_command(self.KEY_BRIGHTNESS, brightness) + + def set_brightness_mcb(self, device, key, data): + self.logger.log(logging.INFO if data != self.brightness else logging.DEBUG, "Changing brightness to %s", str(data)) + self.set_brightness(data) + + def default_inc(self, speed=40): + self.send_command(self.KEY_BRIGHTNESS_FADE, speed) + + def default_dec(self, speed=-40): + self.default_inc(speed) + + def default_stop(self): + self.default_inc(0) + + def set_color_temp(self, color_temp): + """color_temp: [0, ..., 10]""" + self.send_command(self.KEY_COLOR_TEMP, color_temp) + + def set_color_temp_mcb(self, device, key, data): + self.logger.log(logging.INFO if data != self.color_temp else logging.DEBUG, "Changing color temperature to %s", str(data)) + self.set_color_temp(data) + + def all_off(self): + if self.output_0: + self.set_output_0(False) + + +class tradfri_button(base): + """ Communication (MQTT) + + tradfri_button { + "action": [ + "arrow_left_click", + "arrow_left_hold", + "arrow_left_release", + "arrow_right_click", + "arrow_right_hold", + "arrow_right_release", + "brightness_down_click", + "brightness_down_hold", + "brightness_down_release", + "brightness_up_click", + "brightness_up_hold", + "brightness_up_release", + "toggle" + ] + "action_duration": [0...] s + "battery": [0...100] % + "linkquality": [0...255] lqi + "update": [] + } + """ + ACTION_TOGGLE = "toggle" + ACTION_BRIGHTNESS_UP = "brightness_up_click" + ACTION_BRIGHTNESS_DOWN = "brightness_down_click" + ACTION_RIGHT = "arrow_right_click" + ACTION_LEFT = "arrow_left_click" + ACTION_BRIGHTNESS_UP_LONG = "brightness_up_hold" + ACTION_BRIGHTNESS_UP_RELEASE = "brightness_up_release" + ACTION_BRIGHTNESS_DOWN_LONG = "brightness_down_hold" + ACTION_BRIGHTNESS_DOWN_RELEASE = "brightness_down_release" + ACTION_RIGHT_LONG = "arrow_right_hold" + ACTION_RIGHT_RELEASE = "arrow_right_release" + ACTION_LEFT_LONG = "arrow_left_hold" + ACTION_LEFT_RELEASE = "arrow_left_release" + # + KEY_LINKQUALITY = "linkquality" + KEY_BATTERY = "battery" + KEY_ACTION = "action" + KEY_ACTION_DURATION = "action_duration" + # + RX_KEYS = [KEY_LINKQUALITY, KEY_BATTERY, KEY_ACTION] + RX_IGNORE_KEYS = ['update', KEY_ACTION_DURATION] + + def __init__(self, mqtt_client, topic): + super().__init__(mqtt_client, topic) + # + self.add_callback(self.KEY_BATTERY, None, self.__warning__, True) + self.__battery_warning__ = False + + # + # WARNING CALL + # + def __warning__(self, client, key, data): + if data <= BATTERY_WARN_LEVEL: + if not self.__battery_warning__: + w = warning(self.topic, warning.TYPE_BATTERY_LOW, "Battery low (%.1f%%)", data) + self.logger.warning(w) + self.set(self.KEY_WARNING, w) + else: + self.__battery_warning__ = False + + # + # RX + # + @property + def action(self): + """rv: action_txt""" + return self.get(self.KEY_ACTION) diff --git a/function/__init__.py b/function/__init__.py index f0c9cad..5fee2fe 100644 --- a/function/__init__.py +++ b/function/__init__.py @@ -19,19 +19,19 @@ logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__) class all_functions(room_collection): - def __init__(self, mqtt_client): - super().__init__(mqtt_client) + def __init__(self, mqtt_client, pd, vd): + super().__init__(mqtt_client, pd, vd) # # Rooms # # stairway - self.stw = stairway(self.mqtt_client) + self.stw = stairway(self.mqtt_client, pd, vd) # ground floor west - self.gfw = ground_floor_west(self.mqtt_client) + self.gfw = ground_floor_west(self.mqtt_client, pd, vd) # first floor west - self.ffw = first_floor_west(self.mqtt_client) + self.ffw = first_floor_west(self.mqtt_client, pd, vd) # first floor east - self.ffe = first_floor_east(self.mqtt_client) + self.ffe = first_floor_east(self.mqtt_client, pd, vd) # # Interactions # @@ -42,27 +42,30 @@ class all_functions(room_collection): # Warnings videv_warning = videv_warnings(self.mqtt_client, config.TOPIC_WARNINGS) for device in self.all_devices(): - device.add_callback(devices.base.KEY_WARNING, None, videv_warning.warningcollector) + device.add_callback(devices.base.base.KEY_WARNING, None, videv_warning.warningcollector) def init_cross_room_interactions(self): # shelly dirk input 1 self.last_gfw_dirk_input_1 = None - self.gfw.dirk.main_light_shelly.add_callback(devices.shelly.KEY_INPUT_1, None, self.gfw_dirk_input_1) + self.gfw.dirk.main_light_shelly.add_callback(self.gfw.dirk.main_light_shelly.KEY_INPUT_1, None, self.gfw_dirk_input_1) # tradfri button ffe_sleep right click - 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) + self.ffe.sleep.button_tradfri.add_callback(self.ffe.sleep.button_tradfri.KEY_ACTION, + self.ffe.sleep.button_tradfri.ACTION_RIGHT, + self.ffe.floor.main_light_shelly.toggle_output_0_mcb) def init_off_functionality(self): # ALL OFF - Virtual device self.videv_all_off = all_off(self.mqtt_client, config.TOPIC_ALL_OFF_VIDEV, self) # ALL OFF - Long push stairway - self.stw.stairway.main_light_shelly.add_callback(devices.shelly.KEY_LONGPUSH_0, True, self.stw.stairway.main_light_shelly.flash_0_mcb) - self.stw.stairway.main_light_shelly.add_callback(devices.shelly.KEY_LONGPUSH_0, True, self.all_off) + self.stw.stairway.main_light_shelly.add_callback(self.stw.stairway.main_light_shelly.KEY_LONGPUSH_0, + True, self.stw.stairway.main_light_shelly.flash_0_mcb) + self.stw.stairway.main_light_shelly.add_callback(self.stw.stairway.main_light_shelly.KEY_LONGPUSH_0, True, self.all_off) # FFE ALL OFF - Long push ffe_floor - self.ffe.floor.main_light_shelly.add_callback(devices.shelly.KEY_LONGPUSH_0, True, self.ffe.floor.main_light_shelly.flash_0_mcb) - self.ffe.floor.main_light_shelly.add_callback(devices.shelly.KEY_LONGPUSH_0, True, self.ffe.all_off) + self.ffe.floor.main_light_shelly.add_callback(self.ffe.floor.main_light_shelly.KEY_LONGPUSH_0, + True, self.ffe.floor.main_light_shelly.flash_0_mcb) + self.ffe.floor.main_light_shelly.add_callback(self.ffe.floor.main_light_shelly.KEY_LONGPUSH_0, True, self.ffe.all_off) # FFE ALL OFF - Long push input device self.ffe.sleep.button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_RIGHT_LONG, self.ffe.all_off) diff --git a/function/first_floor_east.py b/function/first_floor_east.py index 42da476..3a0534f 100644 --- a/function/first_floor_east.py +++ b/function/first_floor_east.py @@ -3,7 +3,8 @@ # import config -import devices +import devdi.props as props +from devices import group from function.db import get_radiator_data, set_radiator_data from function.helpers import day_event from function.modules import brightness_choose_n_action, timer_on_activation, heating_function @@ -17,26 +18,29 @@ except ImportError: ROOT_LOGGER_NAME = 'root' logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__) +loc = props.LOC_FFE + class first_floor_east(room_collection): - def __init__(self, mqtt_client): - super().__init__(mqtt_client) - self.dining = first_floor_east_dining(mqtt_client) - self.floor = first_floor_east_floor(mqtt_client) - self.kitchen = first_floor_east_kitchen(mqtt_client) - self.livingroom = first_floor_east_living(mqtt_client) - self.sleep = first_floor_east_sleep(mqtt_client) + def __init__(self, mqtt_client, pd, vd): + super().__init__(mqtt_client, pd, vd) + self.dining = first_floor_east_dining(mqtt_client, pd, vd) + self.floor = first_floor_east_floor(mqtt_client, pd, vd) + self.kitchen = first_floor_east_kitchen(mqtt_client, pd, vd) + self.livingroom = first_floor_east_living(mqtt_client, pd, vd) + self.sleep = first_floor_east_sleep(mqtt_client, pd, vd) class first_floor_east_floor(room): - def __init__(self, mqtt_client): + def __init__(self, mqtt_client, pd, vd): + roo = props.ROO_FLO # # Device initialisation # # http://shelly1l-3C6105E4E629 # main light - self.main_light_shelly = devices.shelly(mqtt_client, config.TOPIC_FFE_FLOOR_MAIN_LIGHT_SHELLY) - super().__init__(mqtt_client) + self.main_light_shelly = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL) + super().__init__(mqtt_client, pd, vd) # # Virtual Device Interface @@ -44,36 +48,37 @@ class first_floor_east_floor(room): # main light self.main_light = videv_switching( mqtt_client, config.TOPIC_FFE_FLOOR_MAIN_LIGHT_VIDEV, - self.main_light_shelly, devices.shelly.KEY_OUTPUT_0 + self.main_light_shelly, self.main_light_shelly.KEY_OUTPUT_0 ) class first_floor_east_kitchen(room): - def __init__(self, mqtt_client): + def __init__(self, mqtt_client, pd, vd): + roo = props.ROO_KIT # # Device initialisation # # http://shelly1l-8CAAB5616C01 # main light - self.main_light_shelly = devices.shelly(mqtt_client, config.TOPIC_FFE_KITCHEN_MAIN_LIGHT_SHELLY) + self.main_light_shelly = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL) # http://shelly1-e89f6d85a466/ # circulation pump - self.circulation_pump_shelly = devices.shelly(mqtt_client, config.TOPIC_FFE_KITCHEN_CIRCULATION_PUMP_SHELLY) + self.circulation_pump_shelly = pd.get(props.STG_SHE, loc, roo, props.FUN_CIR) # heating function - self.heating_valve = devices.brennenstuhl_heatingvalve(mqtt_client, config.TOPIC_FFE_KITCHEN_HEATING_VALVE_ZIGBEE) + self.heating_valve = pd.get(props.STG_ZFE, loc, roo, props.FUN_HEA) - super().__init__(mqtt_client) + super().__init__(mqtt_client, pd, vd) # # Functionality initialisation # # circulation pump - self.circulation_pump = timer_on_activation(self.circulation_pump_shelly, devices.shelly.KEY_OUTPUT_0, 10*60) - self.circulation_pump_shelly.add_callback(devices.shelly.KEY_OUTPUT_0, True, self.main_light_shelly.flash_0_mcb, True) + self.circulation_pump = timer_on_activation(self.circulation_pump_shelly, self.circulation_pump_shelly.KEY_OUTPUT_0, 10*60) + self.circulation_pump_shelly.add_callback(self.circulation_pump_shelly.KEY_OUTPUT_0, True, self.main_light_shelly.flash_0_mcb, True) # heating function self.heating_function = heating_function( self.heating_valve, - config.DEFAULT_TEMPERATURE[self.heating_valve.topic], + config.DEFAULT_TEMPERATURE, **get_radiator_data(self.heating_valve.topic) ) self.heating_function.add_callback(None, None, set_radiator_data, True) @@ -84,12 +89,12 @@ class first_floor_east_kitchen(room): # main light self.main_light_videv = videv_switching( mqtt_client, config.TOPIC_FFE_KITCHEN_MAIN_LIGHT_VIDEV, - self.main_light_shelly, devices.shelly.KEY_OUTPUT_0 + self.main_light_shelly, self.main_light_shelly.KEY_OUTPUT_0 ) # circulation pump self.circulation_pump_videv = videv_switching_timer( mqtt_client, config.TOPIC_FFE_KITCHEN_CIRCULATION_PUMP_VIDEV, - self.circulation_pump_shelly, devices.shelly.KEY_OUTPUT_0, + self.circulation_pump_shelly, self.circulation_pump_shelly.KEY_OUTPUT_0, self.circulation_pump, timer_on_activation.KEY_TIMER ) # heating function @@ -100,7 +105,8 @@ class first_floor_east_kitchen(room): class first_floor_east_dining(room): - def __init__(self, mqtt_client): + def __init__(self, mqtt_client, pd, vd): + roo = props.ROO_DIN # # Device initialisation # @@ -108,15 +114,15 @@ class first_floor_east_dining(room): # http://shelly1l-84CCA8ADD055 # main light - self.main_light_shelly = devices.shelly(mqtt_client, config.TOPIC_FFE_DININGROOM_MAIN_LIGHT_SHELLY) + self.main_light_shelly = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL) # floor lamp - self.floorlamp_powerplug = devices.silvercrest_powerplug(mqtt_client, config.TOPIC_FFE_DININGROOM_FLOOR_LAMP_POWERPLUG) + self.floorlamp_powerplug = pd.get(props.STG_ZFE, loc, roo, props.FUN_FLL) # heating function - self.heating_valve = devices.brennenstuhl_heatingvalve(mqtt_client, config.TOPIC_FFE_DININGROOM_HEATING_VALVE_ZIGBEE) + self.heating_valve = pd.get(props.STG_ZFE, loc, roo, props.FUN_HEA) # garland if config.CHRISTMAS: - self.garland_powerplug = devices.silvercrest_powerplug(mqtt_client, config.TOPIC_FFE_DININGROOM_GARLAND_POWERPLUG) - super().__init__(mqtt_client) + self.garland_powerplug = pd.get(props.STG_ZFE, loc, roo, props.FUN_GAR) + super().__init__(mqtt_client, pd, vd) # # Functionality initialisation @@ -124,12 +130,12 @@ class first_floor_east_dining(room): self.day_events.add_callback(None, True, self.__day_events__, True) # main light - self.main_light_shelly.add_callback(devices.shelly.KEY_OUTPUT_0, None, self.floorlamp_powerplug.set_output_0_mcb, True) + self.main_light_shelly.add_callback(self.main_light_shelly.KEY_OUTPUT_0, None, self.floorlamp_powerplug.set_output_0_mcb, True) # heating function self.heating_function = heating_function( self.heating_valve, - config.DEFAULT_TEMPERATURE[self.heating_valve.topic], + config.DEFAULT_TEMPERATURE, **get_radiator_data(self.heating_valve.topic) ) self.heating_function.add_callback(None, None, set_radiator_data, True) @@ -140,12 +146,12 @@ class first_floor_east_dining(room): # main light self.main_light_videv = videv_switching( mqtt_client, config.TOPIC_FFE_DININGROOM_MAIN_LIGHT_VIDEV, - self.main_light_shelly, devices.shelly.KEY_OUTPUT_0 + self.main_light_shelly, self.main_light_shelly.KEY_OUTPUT_0 ) # floor lamp self.floorlamp_videv = videv_switching( mqtt_client, config.TOPIC_FFE_DININGROOM_FLOOR_LAMP_VIDEV, - self.floorlamp_powerplug, devices.silvercrest_powerplug.KEY_OUTPUT_0 + self.floorlamp_powerplug, self.floorlamp_powerplug.KEY_OUTPUT_0 ) # heating function self.heating_function_videv = videv_heating( @@ -156,7 +162,7 @@ class first_floor_east_dining(room): if config.CHRISTMAS: self.garland_videv = videv_switching( mqtt_client, config.TOPIC_FFE_DININGROOM_GARLAND_VIDEV, - self.garland_powerplug, devices.silvercrest_powerplug.KEY_OUTPUT_0 + self.garland_powerplug, self.garland_powerplug.KEY_OUTPUT_0 ) def __day_events__(self, device, key, data): @@ -169,44 +175,45 @@ class first_floor_east_dining(room): class first_floor_east_sleep(room): - def __init__(self, mqtt_client): + def __init__(self, mqtt_client, pd, vd): + roo = props.ROO_SLP # # Device initialisation # # http://shelly1l-E8DB84A254C7 # main light - self.main_light_shelly = devices.shelly(mqtt_client, config.TOPIC_FFE_SLEEP_MAIN_LIGHT_SHELLY) - self.main_light_tradfri = devices.tradfri_light(mqtt_client, config.TOPIC_FFE_SLEEP_MAIN_LIGHT_ZIGBEE) + self.main_light_shelly = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL) + self.main_light_tradfri = pd.get(props.STG_ZFE, loc, roo, props.FUN_MAL) # bed light - self.bed_light_di_tradfri = devices.tradfri_light(mqtt_client, config.TOPIC_FFE_SLEEP_BED_LIGHT_DI_ZIGBEE) - self.bed_light_ma_powerplug = devices.silvercrest_powerplug(mqtt_client, config.TOPIC_FFE_SLEEP_BED_LIGHT_MA_POWERPLUG) + self.bed_light_di_tradfri = pd.get(props.STG_ZFE, loc, roo, props.FUN_BLD) + self.bed_light_ma_powerplug = pd.get(props.STG_ZFE, loc, roo, props.FUN_BLM) # heating function - self.heating_valve = devices.brennenstuhl_heatingvalve(mqtt_client, config.TOPIC_FFE_SLEEP_HEATING_VALVE_ZIGBEE) + self.heating_valve = pd.get(props.STG_ZFE, loc, roo, props.FUN_HEA) # button - self.button_tradfri = devices.tradfri_button(mqtt_client, config.TOPIC_FFE_SLEEP_INPUT_DEVICE) + self.button_tradfri = pd.get(props.STG_ZFE, loc, roo, props.FUN_INP) - super().__init__(mqtt_client) + super().__init__(mqtt_client, pd, vd) # # Functionality initialisation # # button / brightness function self.brightness_functions = brightness_choose_n_action(self.button_tradfri) - 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) + self.brightness_functions.add(self.main_light_tradfri, self.main_light_shelly, self.main_light_shelly.KEY_OUTPUT_0) + self.brightness_functions.add(self.bed_light_di_tradfri, self.bed_light_di_tradfri, self.bed_light_di_tradfri.KEY_OUTPUT_0) # button / main light - self.button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_TOGGLE, + self.button_tradfri.add_callback(self.button_tradfri.KEY_ACTION, self.button_tradfri.ACTION_TOGGLE, self.main_light_shelly.toggle_output_0_mcb) # button / bed light - self.button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_LEFT, + self.button_tradfri.add_callback(self.button_tradfri.KEY_ACTION, self.button_tradfri.ACTION_LEFT, self.bed_light_di_tradfri.toggle_output_0_mcb) - self.button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_LEFT_LONG, + self.button_tradfri.add_callback(self.button_tradfri.KEY_ACTION, self.button_tradfri.ACTION_LEFT_LONG, self.bed_light_ma_powerplug.toggle_output_0_mcb) # heating function self.heating_function = heating_function( self.heating_valve, - config.DEFAULT_TEMPERATURE[self.heating_valve.topic], + config.DEFAULT_TEMPERATURE, **get_radiator_data(self.heating_valve.topic) ) self.heating_function.add_callback(None, None, set_radiator_data, True) @@ -217,19 +224,19 @@ class first_floor_east_sleep(room): # main light self.main_light_videv = videv_switch_brightness_color_temp( mqtt_client, config.TOPIC_FFE_SLEEP_MAIN_LIGHT_VIDEV, - self.main_light_shelly, devices.shelly.KEY_OUTPUT_0, - self.main_light_tradfri, devices.tradfri_light.KEY_BRIGHTNESS, - self.main_light_tradfri, devices.tradfri_light.KEY_COLOR_TEMP + self.main_light_shelly, self.main_light_shelly.KEY_OUTPUT_0, + self.main_light_tradfri, self.main_light_tradfri.KEY_BRIGHTNESS, + self.main_light_tradfri, self.main_light_tradfri.KEY_COLOR_TEMP ) # bed light self.bed_light_di_videv = videv_switch_brightness( mqtt_client, config.TOPIC_FFE_SLEEP_BED_LIGHT_DI_VIDEV, - self.bed_light_di_tradfri, devices.tradfri_light.KEY_OUTPUT_0, - self.bed_light_di_tradfri, devices.tradfri_light.KEY_BRIGHTNESS, + self.bed_light_di_tradfri, self.bed_light_di_tradfri.KEY_OUTPUT_0, + self.bed_light_di_tradfri, self.bed_light_di_tradfri.KEY_BRIGHTNESS, ) self.bed_light_ma_videv = videv_switching( mqtt_client, config.TOPIC_FFE_SLEEP_BED_LIGHT_MA_VIDEV, - self.bed_light_ma_powerplug, devices.silvercrest_powerplug.KEY_OUTPUT_0 + self.bed_light_ma_powerplug, self.bed_light_ma_powerplug.KEY_OUTPUT_0 ) # heating function self.heating_function_videv = videv_heating( @@ -244,35 +251,35 @@ class first_floor_east_sleep(room): class first_floor_east_living(room): - def __init__(self, mqtt_client): + def __init__(self, mqtt_client, pd, vd): + roo = props.ROO_LIV # # Device initialisation # # http://shelly1l-3C6105E3F910 # main light - self.main_light_shelly = devices.shelly(mqtt_client, config.TOPIC_FFE_LIVINGROOM_MAIN_LIGHT_SHELLY) - self.main_light_tradfri = devices.tradfri_light(mqtt_client, config.TOPIC_FFE_LIVINGROOM_MAIN_LIGHT_ZIGBEE) + self.main_light_shelly = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL) + self.main_light_tradfri = pd.get(props.STG_ZFE, loc, roo, props.FUN_MAL) # floor lamp - self.floorlamp_tradfri = devices.group( - *[devices.tradfri_light(mqtt_client, config.TOPIC_FFE_LIVINGROOM_FLOOR_LAMP_ZIGBEE % i) for i in range(1, 7)]) + self.floorlamp_tradfri = pd.get(props.STG_ZFE, loc, roo, props.FUN_FLL) # heating function - self.heating_valve = devices.brennenstuhl_heatingvalve(mqtt_client, config.TOPIC_FFE_LIVINGROOM_HEATING_VALVE_ZIGBEE) + self.heating_valve = pd.get(props.STG_ZFE, loc, roo, props.FUN_HEA) # xmas tree if config.CHRISTMAS: - self.powerplug_xmas_tree = devices.silvercrest_powerplug(mqtt_client, config.TOPIC_FFE_LIVINGROOM_XMAS_TREE_POWERPLUG) - self.powerplug_xmas_star = devices.silvercrest_powerplug(mqtt_client, config.TOPIC_FFE_LIVINGROOM_XMAS_STAR_POWERPLUG) + self.powerplug_xmas_tree = pd.get(props.STG_ZFE, loc, roo, props.FUN_XTR) + self.powerplug_xmas_star = pd.get(props.STG_ZFE, loc, roo, props.FUN_XST) - super().__init__(mqtt_client) + super().__init__(mqtt_client, pd, vd) # # Functionality initialisation # # floor lamp synchronisation with main_light - self.main_light_shelly.add_callback(devices.shelly.KEY_OUTPUT_0, None, self.floorlamp_tradfri.set_output_0_mcb, True) + self.main_light_shelly.add_callback(self.main_light_shelly.KEY_OUTPUT_0, None, self.floorlamp_tradfri.set_output_0_mcb, True) # heating function self.heating_function = heating_function( self.heating_valve, - config.DEFAULT_TEMPERATURE[self.heating_valve.topic], + config.DEFAULT_TEMPERATURE, **get_radiator_data(self.heating_valve.topic) ) self.heating_function.add_callback(None, None, set_radiator_data, True) @@ -283,16 +290,16 @@ class first_floor_east_living(room): # main light self.main_light_videv = videv_switch_brightness_color_temp( mqtt_client, config.TOPIC_FFE_LIVINGROOM_MAIN_LIGHT_VIDEV, - self.main_light_shelly, devices.shelly.KEY_OUTPUT_0, - self.main_light_tradfri, devices.tradfri_light.KEY_BRIGHTNESS, - self.main_light_tradfri, devices.tradfri_light.KEY_COLOR_TEMP + self.main_light_shelly, self.main_light_shelly.KEY_OUTPUT_0, + self.main_light_tradfri, self.main_light_tradfri.KEY_BRIGHTNESS, + self.main_light_tradfri, self.main_light_tradfri.KEY_COLOR_TEMP ) # floor lamp self.floorlamp_videv = videv_switch_brightness_color_temp( mqtt_client, config.TOPIC_FFE_LIVINGROOM_FLOOR_LAMP_VIDEV, - self.floorlamp_tradfri, devices.tradfri_light.KEY_OUTPUT_0, - self.floorlamp_tradfri, devices.tradfri_light.KEY_BRIGHTNESS, - self.floorlamp_tradfri, devices.tradfri_light.KEY_COLOR_TEMP + self.floorlamp_tradfri, self.floorlamp_tradfri.KEY_OUTPUT_0, + self.floorlamp_tradfri, self.floorlamp_tradfri.KEY_BRIGHTNESS, + self.floorlamp_tradfri, self.floorlamp_tradfri.KEY_COLOR_TEMP ) # heating function self.heating_function_videv = videv_heating( @@ -303,5 +310,5 @@ class first_floor_east_living(room): if config.CHRISTMAS: self.xmas_tree_videv = videv_switching( mqtt_client, config.TOPIC_FFE_LIVINGROOM_XMAS_TREE_VIDEV, - self.powerplug_xmas_tree, devices.silvercrest_powerplug.KEY_OUTPUT_0 + self.powerplug_xmas_tree, self.powerplug_xmas_tree.KEY_OUTPUT_0 ) diff --git a/function/first_floor_west.py b/function/first_floor_west.py index 4c4d853..3b0cbc2 100644 --- a/function/first_floor_west.py +++ b/function/first_floor_west.py @@ -3,7 +3,7 @@ # import config -import devices +import devdi.props as props from function.db import get_radiator_data, set_radiator_data from function.modules import heating_function from function.rooms import room, room_collection @@ -17,35 +17,38 @@ except ImportError: ROOT_LOGGER_NAME = 'root' logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__) +loc = props.LOC_FFW + class first_floor_west(room_collection): - def __init__(self, mqtt_client): - super().__init__(mqtt_client) - self.bath = first_floor_west_bath(mqtt_client) - self.julian = first_floor_west_julian(mqtt_client) - self.livingroom = first_floor_west_living(mqtt_client) - self.sleep = first_floor_west_sleep(mqtt_client) + def __init__(self, mqtt_client, pd, vd): + super().__init__(mqtt_client, pd, vd) + self.bath = first_floor_west_bath(mqtt_client, pd, vd) + self.julian = first_floor_west_julian(mqtt_client, pd, vd) + self.livingroom = first_floor_west_living(mqtt_client, pd, vd) + self.sleep = first_floor_west_sleep(mqtt_client, pd, vd) class first_floor_west_julian(room): - def __init__(self, mqtt_client): + def __init__(self, mqtt_client, pd, vd): + roo = props.ROO_JUL # # Device initialisation # # http://shelly1l-3C6105E43452 # main light - self.main_light_shelly = devices.shelly(mqtt_client, config.TOPIC_FFW_JULIAN_MAIN_LIGHT_SHELLY) - self.main_light_tradfri = devices.tradfri_light(mqtt_client, config.TOPIC_FFW_JULIAN_MAIN_LIGHT_ZIGBEE) + self.main_light_shelly = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL) + self.main_light_tradfri = pd.get(props.STG_ZFW, loc, roo, props.FUN_MAL) # heating function - self.heating_valve = devices.brennenstuhl_heatingvalve(mqtt_client, config.TOPIC_FFW_JULIAN_HEATING_VALVE_ZIGBEE) - super().__init__(mqtt_client) + self.heating_valve = pd.get(props.STG_ZFW, loc, roo, props.FUN_HEA) + super().__init__(mqtt_client, pd, vd) # # Functionality initialisation # # heating function self.heating_function = heating_function( self.heating_valve, - config.DEFAULT_TEMPERATURE[self.heating_valve.topic], + config.DEFAULT_TEMPERATURE, **get_radiator_data(self.heating_valve.topic) ) self.heating_function.add_callback(None, None, set_radiator_data, True) @@ -56,9 +59,9 @@ class first_floor_west_julian(room): # main light self.main_light_videv = videv_switch_brightness_color_temp( mqtt_client, config.TOPIC_FFW_JULIAN_MAIN_LIGHT_VIDEV, - self.main_light_shelly, devices.shelly.KEY_OUTPUT_0, - self.main_light_tradfri, devices.tradfri_light.KEY_BRIGHTNESS, - self.main_light_tradfri, devices.tradfri_light.KEY_COLOR_TEMP + self.main_light_shelly, self.main_light_shelly.KEY_OUTPUT_0, + self.main_light_tradfri, self.main_light_tradfri.KEY_BRIGHTNESS, + self.main_light_tradfri, self.main_light_tradfri.KEY_COLOR_TEMP ) # heating function self.heating_function_videv = videv_heating( @@ -68,13 +71,14 @@ class first_floor_west_julian(room): class first_floor_west_bath(room): - def __init__(self, mqtt_client): + def __init__(self, mqtt_client, pd, vd): + roo = props.ROO_BAT # # Device initialisation # # heating function - self.heating_valve = devices.brennenstuhl_heatingvalve(mqtt_client, config.TOPIC_FFW_BATH_HEATING_VALVE_ZIGBEE) - super().__init__(mqtt_client) + self.heating_valve = pd.get(props.STG_ZFW, loc, roo, props.FUN_HEA) + super().__init__(mqtt_client, pd, vd) # # Functionality initialisation @@ -82,7 +86,7 @@ class first_floor_west_bath(room): # heating function self.heating_function = heating_function( self.heating_valve, - config.DEFAULT_TEMPERATURE[self.heating_valve.topic], + config.DEFAULT_TEMPERATURE, **get_radiator_data(self.heating_valve.topic) ) self.heating_function.add_callback(None, None, set_radiator_data, True) @@ -98,17 +102,18 @@ class first_floor_west_bath(room): class first_floor_west_living(room): - def __init__(self, mqtt_client): + def __init__(self, mqtt_client, pd, vd): + roo = props.ROO_LIV # # Device initialisation # # http://shelly1l-84CCA8ACE6A1 # main light - self.main_light_shelly = devices.shelly(mqtt_client, config.TOPIC_FFW_LIVINGROOM_MAIN_LIGHT_SHELLY) - self.main_light_tradfri = devices.tradfri_light(mqtt_client, config.TOPIC_FFW_LIVINGROOM_MAIN_LIGHT_ZIGBEE) + self.main_light_shelly = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL) + self.main_light_tradfri = pd.get(props.STG_ZFW, loc, roo, props.FUN_MAL) # # heating function - # self.heating_valve = devices.brennenstuhl_heatingvalve(mqtt_client, config.TOPIC_FFW_LIVINGROOM_HEATING_VALVE_ZIGBEE) - super().__init__(mqtt_client) + # self.heating_valve = pd.get(props.STG_ZFW, loc, roo, props.FUN_HEA) + super().__init__(mqtt_client, pd, vd) # # Functionality initialisation @@ -127,9 +132,9 @@ class first_floor_west_living(room): # main light self.main_light_videv = videv_switch_brightness_color_temp( mqtt_client, config.TOPIC_FFW_LIVINGROOM_MAIN_LIGHT_VIDEV, - self.main_light_shelly, devices.shelly.KEY_OUTPUT_0, - self.main_light_tradfri, devices.tradfri_light.KEY_BRIGHTNESS, - self.main_light_tradfri, devices.tradfri_light.KEY_COLOR_TEMP + self.main_light_shelly, self.main_light_shelly.KEY_OUTPUT_0, + self.main_light_tradfri, self.main_light_tradfri.KEY_BRIGHTNESS, + self.main_light_tradfri, self.main_light_tradfri.KEY_COLOR_TEMP ) # # heating function # self.heating_function_videv = videv_heating( @@ -139,17 +144,18 @@ class first_floor_west_living(room): class first_floor_west_sleep(room): - def __init__(self, mqtt_client): + def __init__(self, mqtt_client, pd, vd): + roo = props.ROO_SLP # # Device initialisation # # http://shelly1-3494546A51F2 # main light - self.main_light_shelly = devices.shelly(mqtt_client, config.TOPIC_FFW_SLEEP_MAIN_LIGHT_SHELLY) - self.main_light_tradfri = devices.tradfri_light(mqtt_client, config.TOPIC_FFW_SLEEP_MAIN_LIGHT_ZIGBEE) + self.main_light_shelly = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL) + self.main_light_tradfri = pd.get(props.STG_ZFW, loc, roo, props.FUN_MAL) # heating function - self.heating_valve = devices.brennenstuhl_heatingvalve(mqtt_client, config.TOPIC_FFW_SLEEP_HEATING_VALVE_ZIGBEE) - super().__init__(mqtt_client) + self.heating_valve = pd.get(props.STG_ZFW, loc, roo, props.FUN_HEA) + super().__init__(mqtt_client, pd, vd) # # Functionality initialisation @@ -157,7 +163,7 @@ class first_floor_west_sleep(room): # heating function self.heating_function = heating_function( self.heating_valve, - config.DEFAULT_TEMPERATURE[self.heating_valve.topic], + config.DEFAULT_TEMPERATURE, **get_radiator_data(self.heating_valve.topic) ) self.heating_function.add_callback(None, None, set_radiator_data, True) @@ -168,8 +174,8 @@ class first_floor_west_sleep(room): # main light self.main_light_videv = videv_switch_brightness( mqtt_client, config.TOPIC_FFW_SLEEP_MAIN_LIGHT_VIDEV, - self.main_light_shelly, devices.shelly.KEY_OUTPUT_0, - self.main_light_tradfri, devices.tradfri_light.KEY_BRIGHTNESS + self.main_light_shelly, self.main_light_shelly.KEY_OUTPUT_0, + self.main_light_tradfri, self.main_light_tradfri.KEY_BRIGHTNESS ) # heating function self.heating_function_videv = videv_heating( diff --git a/function/ground_floor_west.py b/function/ground_floor_west.py index 76add53..dc1d29a 100644 --- a/function/ground_floor_west.py +++ b/function/ground_floor_west.py @@ -3,7 +3,8 @@ # import config -import devices +from devdi import props +from devices import group from function.db import get_radiator_data, set_radiator_data from function.modules import brightness_choose_n_action, heating_function, switched_light from function.rooms import room, room_collection @@ -17,54 +18,57 @@ except ImportError: ROOT_LOGGER_NAME = 'root' logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__) +loc = props.LOC_GFW + class ground_floor_west(room_collection): - def __init__(self, mqtt_client): - super().__init__(mqtt_client) - self.dirk = ground_floor_west_dirk(mqtt_client) - self.floor = ground_floor_west_floor(mqtt_client) - self.marion = ground_floor_west_marion(mqtt_client) + def __init__(self, mqtt_client, pd, vd): + super().__init__(mqtt_client, pd, vd) + self.dirk = ground_floor_west_dirk(mqtt_client, pd, vd) + self.floor = ground_floor_west_floor(mqtt_client, pd, vd) + self.marion = ground_floor_west_marion(mqtt_client, pd, vd) class ground_floor_west_floor(room): - def __init__(self, mqtt_client): + def __init__(self, mqtt_client, pd, vd): + roo = props.ROO_FLO # # Device initialisation # # http://shelly1l-84CCA8AD1148 - self.main_light_shelly = devices.shelly(mqtt_client, config.TOPIC_GFW_FLOOR_MAIN_LIGHT_SHELLY) - self.main_light_tradfri = devices.group( - devices.tradfri_light(mqtt_client, config.TOPIC_GFW_FLOOR_MAIN_LIGHT_ZIGBEE % 1), - devices.tradfri_light(mqtt_client, config.TOPIC_GFW_FLOOR_MAIN_LIGHT_ZIGBEE % 2) - ) - super().__init__(mqtt_client) + self.main_light_shelly = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL) + self.main_light_tradfri = pd.get(props.STG_ZGW, loc, roo, props.FUN_MAL) + super().__init__(mqtt_client, pd, vd) # # Functionality initialisation # # Request silvercrest data of lead light after power on - switched_light(self.main_light_shelly, devices.shelly.KEY_OUTPUT_0, self.main_light_tradfri) + switched_light(self.main_light_shelly, self.main_light_shelly.KEY_OUTPUT_0, self.main_light_tradfri) # # Virtual Device Interface # self.main_light_videv = videv_switch_brightness_color_temp( mqtt_client, config.TOPIC_GFW_FLOOR_MAIN_LIGHT_VIDEV, - self.main_light_shelly, devices.shelly.KEY_OUTPUT_0, - self.main_light_tradfri, devices.tradfri_light.KEY_BRIGHTNESS, - self.main_light_tradfri, devices.tradfri_light.KEY_COLOR_TEMP + self.main_light_shelly, self.main_light_shelly.KEY_OUTPUT_0, + self.main_light_tradfri, self.main_light_tradfri.KEY_BRIGHTNESS, + self.main_light_tradfri, self.main_light_tradfri.KEY_COLOR_TEMP ) class ground_floor_west_marion(room): - def __init__(self, mqtt_client): + def __init__(self, mqtt_client, pd, vd): + roo = props.ROO_MAR # # Device initialisation # # http://shelly1l-E8DB84A1E067 - self.main_light_shelly = devices.shelly(mqtt_client, config.TOPIC_GFW_MARION_MAIN_LIGHT_SHELLY) - self.heating_valve = devices.brennenstuhl_heatingvalve(mqtt_client, config.TOPIC_GFW_MARION_HEATING_VALVE_ZIGBEE) - super().__init__(mqtt_client) + # main light + self.main_light_shelly = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL) + # heating function + self.heating_valve = pd.get(props.STG_ZGW, loc, roo, props.FUN_HEA) + super().__init__(mqtt_client, pd, vd) # # Functionality initialisation @@ -72,7 +76,7 @@ class ground_floor_west_marion(room): # heating function self.heating_function = heating_function( self.heating_valve, - config.DEFAULT_TEMPERATURE[self.heating_valve.topic], + config.DEFAULT_TEMPERATURE, **get_radiator_data(self.heating_valve.topic) ) self.heating_function.add_callback(None, None, set_radiator_data, True) @@ -82,7 +86,7 @@ class ground_floor_west_marion(room): # self.main_light_videv = videv_switching( mqtt_client, config.TOPIC_GFW_MARION_MAIN_LIGHT_VIDEV, - self.main_light_shelly, devices.shelly.KEY_OUTPUT_0 + self.main_light_shelly, self.main_light_shelly.KEY_OUTPUT_0 ) self.heating_function_videv = videv_heating( mqtt_client, config.TOPIC_GFW_MARION_HEATING_VALVE_VIDEV, @@ -96,69 +100,75 @@ class ground_floor_west_dirk(room): STATE_ACTIVE_DEVICE_AMPLIFIER = 2 STATE_ACTIVE_DEVICE_MAX_VALUE = STATE_ACTIVE_DEVICE_AMPLIFIER # - KEY_POWERPLUG_AMPLIFIER = devices.my_powerplug.KEY_OUTPUT_0 - KEY_POWERPLUG_CD_PLAYER = devices.my_powerplug.KEY_OUTPUT_2 - KEY_POWERPLUG_DESK_LIGHT = devices.my_powerplug.KEY_OUTPUT_1 - KEY_POWERPLUG_PC_DOCK = devices.my_powerplug.KEY_OUTPUT_3 - # AUDIO_SOURCE_PC = 0 AUDIO_SOURCE_CD = 1 AUDIO_SOURCE_RASPI = 2 - def __init__(self, mqtt_client): + def __init__(self, mqtt_client, pd, vd): + roo = props.ROO_DIR # # Device initialisation # # http://shelly1l-3C6105E44F27 - self.main_light_shelly = devices.shelly(mqtt_client, config.TOPIC_GFW_DIRK_MAIN_LIGHT_SHELLY) - self.main_light_tradfri = devices.tradfri_light(mqtt_client, config.TOPIC_GFW_DIRK_MAIN_LIGHT_ZIGBEE) - self.powerplug_common = devices.my_powerplug(mqtt_client, config.TOPIC_GFW_DIRK_POWERPLUG) - self.desk_light_tradfri = devices.tradfri_light(mqtt_client, config.TOPIC_GFW_DIRK_DESK_LIGHT_ZIGBEE) - self.button_tradfri = devices.tradfri_button(mqtt_client, config.TOPIC_GFW_DIRK_INPUT_DEVICE) - self.remote_amplifier = devices.remote(mqtt_client, config.TOPIC_GFW_DIRK_AMPLIFIER_REMOTE) - self.spotify_state = devices.audio_status(mqtt_client, config.TOPIC_GFW_DIRK_SPOTIFY) - self.mpd_state = devices.audio_status(mqtt_client, config.TOPIC_GFW_DIRK_MPD) - self.heating_valve = devices.brennenstuhl_heatingvalve(mqtt_client, config.TOPIC_GFW_DIRK_HEATING_VALVE_ZIGBEE) - super().__init__(mqtt_client) + # main light + self.main_light_shelly = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL) + self.main_light_tradfri = pd.get(props.STG_ZGW, loc, roo, props.FUN_MAL) + # powerplug + self.powerplug_common = pd.get(props.STG_MYA, loc, roo, props.FUN_MPP) + self.KEY_POWERPLUG_AMPLIFIER = self.powerplug_common.KEY_OUTPUT_0 + self.KEY_POWERPLUG_DESK_LIGHT = self.powerplug_common.KEY_OUTPUT_1 + self.KEY_POWERPLUG_CD_PLAYER = self.powerplug_common.KEY_OUTPUT_2 + self.KEY_POWERPLUG_PC_DOCK = self.powerplug_common.KEY_OUTPUT_3 + # desk light + self.desk_light_tradfri = pd.get(props.STG_ZGW, loc, roo, props.FUN_DEL) + # button + self.button_tradfri = pd.get(props.STG_ZGW, loc, roo, props.FUN_INP) + # hifi + self.remote_amplifier = pd.get(props.STG_MYA, loc, roo, props.FUN_RCA) + self.spotify_state = pd.get(props.STG_MYA, loc, roo, props.FUN_ASS) + self.mpd_state = pd.get(props.STG_MYA, loc, roo, props.FUN_ASM) + # heating function + self.heating_valve = pd.get(props.STG_ZGW, loc, roo, props.FUN_HEA) + super().__init__(mqtt_client, pd, vd) # # Functionality initialisation # # Button - Brightness functionality self.brightness_functions = brightness_choose_n_action(self.button_tradfri) - self.brightness_functions.add(self.main_light_tradfri, self.main_light_shelly, devices.shelly.KEY_OUTPUT_0) + self.brightness_functions.add(self.main_light_tradfri, self.main_light_shelly, self.main_light_shelly.KEY_OUTPUT_0) self.brightness_functions.add(self.desk_light_tradfri, self.powerplug_common, self.KEY_POWERPLUG_DESK_LIGHT) self.brightness_functions.add(self.remote_amplifier, self.powerplug_common, self.KEY_POWERPLUG_AMPLIFIER) # Button - Main light - self.button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_TOGGLE, + self.button_tradfri.add_callback(self.button_tradfri.KEY_ACTION, self.button_tradfri.ACTION_TOGGLE, self.main_light_shelly.toggle_output_0_mcb) # Button - Desk light - self.button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_RIGHT, + self.button_tradfri.add_callback(self.button_tradfri.KEY_ACTION, self.button_tradfri.ACTION_RIGHT, self.powerplug_common.toggle_output_1_mcb) # Button - Amplifier - self.button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_LEFT_LONG, + self.button_tradfri.add_callback(self.button_tradfri.KEY_ACTION, self.button_tradfri.ACTION_LEFT_LONG, self.powerplug_common.toggle_output_0_mcb) # Button - CD player - self.button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_RIGHT_LONG, + self.button_tradfri.add_callback(self.button_tradfri.KEY_ACTION, self.button_tradfri.ACTION_RIGHT_LONG, self.powerplug_common.toggle_output_2_mcb) # Button - PC dock - self.button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_LEFT, + self.button_tradfri.add_callback(self.button_tradfri.KEY_ACTION, self.button_tradfri.ACTION_LEFT, self.powerplug_common.toggle_output_3_mcb) # Mediaplayer - Amplifier auto on self.powerplug_common.add_callback(self.KEY_POWERPLUG_CD_PLAYER, None, self.powerplug_common.set_output_0_mcb, True) - self.spotify_state.add_callback(devices.audio_status.KEY_STATE, None, self.powerplug_common.set_output_0_mcb, True) - self.mpd_state.add_callback(devices.audio_status.KEY_STATE, None, self.powerplug_common.set_output_0_mcb, True) + self.spotify_state.add_callback(self.spotify_state.KEY_STATE, None, self.powerplug_common.set_output_0_mcb, True) + self.mpd_state.add_callback(self.mpd_state.KEY_STATE, None, self.powerplug_common.set_output_0_mcb, True) # Mediaplayer - Audio source selection self.powerplug_common.add_callback(self.KEY_POWERPLUG_AMPLIFIER, True, self.audio_source_selector, True) self.powerplug_common.add_callback(self.KEY_POWERPLUG_CD_PLAYER, True, self.audio_source_selector, True) - self.spotify_state.add_callback(devices.audio_status.KEY_STATE, True, self.audio_source_selector, True) - self.mpd_state.add_callback(devices.audio_status.KEY_STATE, True, self.audio_source_selector, True) + self.spotify_state.add_callback(self.spotify_state.KEY_STATE, True, self.audio_source_selector, True) + self.mpd_state.add_callback(self.mpd_state.KEY_STATE, True, self.audio_source_selector, True) self.audio_source = self.AUDIO_SOURCE_PC # heating function self.heating_function = heating_function( self.heating_valve, - config.DEFAULT_TEMPERATURE[self.heating_valve.topic], + config.DEFAULT_TEMPERATURE, **get_radiator_data(self.heating_valve.topic) ) self.heating_function.add_callback(None, None, set_radiator_data, True) @@ -168,15 +178,15 @@ class ground_floor_west_dirk(room): # self.main_light_videv = videv_switch_brightness_color_temp( mqtt_client, config.TOPIC_GFW_DIRK_MAIN_LIGHT_VIDEV, - self.main_light_shelly, devices.shelly.KEY_OUTPUT_0, - self.main_light_tradfri, devices.tradfri_light.KEY_BRIGHTNESS, - self.main_light_tradfri, devices.tradfri_light.KEY_COLOR_TEMP + self.main_light_shelly, self.main_light_shelly.KEY_OUTPUT_0, + self.main_light_tradfri, self.main_light_tradfri.KEY_BRIGHTNESS, + self.main_light_tradfri, self.main_light_tradfri.KEY_COLOR_TEMP ) self.desk_light_videv = videv_switch_brightness_color_temp( mqtt_client, config.TOPIC_GFW_DIRK_DESK_LIGHT_VIDEV, self.powerplug_common, self.KEY_POWERPLUG_DESK_LIGHT, - self.desk_light_tradfri, devices.tradfri_light.KEY_BRIGHTNESS, - self.desk_light_tradfri, devices.tradfri_light.KEY_COLOR_TEMP + self.desk_light_tradfri, self.desk_light_tradfri.KEY_BRIGHTNESS, + self.desk_light_tradfri, self.desk_light_tradfri.KEY_COLOR_TEMP ) self.amplifier_videv = videv_switching( mqtt_client, config.TOPIC_GFW_DIRK_AMPLIFIER_VIDEV, diff --git a/function/modules.py b/function/modules.py index 24ee11a..29d8b8b 100644 --- a/function/modules.py +++ b/function/modules.py @@ -27,7 +27,7 @@ logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__) class switched_light(object): def __init__(self, sw_device, sw_key, li_device): - sw_device.add_callback(devices.shelly.KEY_OUTPUT_0, True, li_device.request_data, True) + sw_device.add_callback(sw_device.KEY_OUTPUT_0, True, li_device.request_data, True) class brightness_choose_n_action(common_base): @@ -275,8 +275,8 @@ class motion_sensor_light(common_base): self.motion_sensors = args self.timer_reload_value = timer_value # - sw_device.add_callback(devices.shelly.KEY_OUTPUT_0, True, self.reload_timer, True) - sw_device.add_callback(devices.shelly.KEY_OUTPUT_0, False, self.reset_timer, True) + sw_device.add_callback(devices.shelly_sw1.KEY_OUTPUT_0, True, self.reload_timer, True) + sw_device.add_callback(devices.shelly_sw1.KEY_OUTPUT_0, False, self.reset_timer, True) for motion_sensor in args: motion_sensor.add_callback(motion_sensor.KEY_OCCUPANCY, None, self.set_motion_detected, True) # diff --git a/function/rooms.py b/function/rooms.py index d0c7836..c4f0e28 100644 --- a/function/rooms.py +++ b/function/rooms.py @@ -13,8 +13,10 @@ logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__) class room(object): - def __init__(self, mqtt_client): + def __init__(self, mqtt_client, pd, vd): self.mqtt_client = mqtt_client + self.pd = pd + self.vd = vd def all_off(self, device=None, key=None, data=None): logger.info("Switching all off \"%s\"", type(self).__name__) @@ -29,8 +31,10 @@ class room(object): class room_collection(object): ALLOWED_CLASSES = ("room", "room_collection") - def __init__(self, mqtt_client): + def __init__(self, mqtt_client, pd, vd): self.mqtt_client = mqtt_client + self.pd = pd + self.vd = vd def all_off(self, device=None, key=None, data=None): logger.info("Switching all off \"%s\"", type(self).__name__) diff --git a/function/stairway.py b/function/stairway.py index 2bd8f81..ab3adc3 100644 --- a/function/stairway.py +++ b/function/stairway.py @@ -3,7 +3,7 @@ # import config -import devices +from devdi import props import logging from function.modules import motion_sensor_light from function.rooms import room, room_collection @@ -15,23 +15,25 @@ except ImportError: ROOT_LOGGER_NAME = 'root' logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__) +loc = props.LOC_STW + class stairway(room_collection): - def __init__(self, mqtt_client): - super().__init__(mqtt_client) - self.stairway = stairway_stairway(mqtt_client) + def __init__(self, mqtt_client, pd, vd): + super().__init__(mqtt_client, pd, vd) + self.stairway = stairway_stairway(mqtt_client, pd, vd) class stairway_stairway(room): - def __init__(self, mqtt_client): + def __init__(self, mqtt_client, pd, vd): # # Device initialisation # # http://shelly1-3494546A9364 - self.main_light_shelly = devices.shelly(mqtt_client, config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_SHELLY) - self.motion_sensor_gf = devices.silvercrest_motion_sensor(mqtt_client, config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_MOTION_SENSOR_GF) - self.motion_sensor_ff = devices.silvercrest_motion_sensor(mqtt_client, config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_MOTION_SENSOR_FF) - super().__init__(mqtt_client) + self.main_light_shelly = pd.get(props.STG_SHE, loc, props.ROO_STF, props.FUN_MAL) + self.motion_sensor_ff = pd.get(props.STG_ZFE, loc, props.ROO_STF, props.FUN_MSE) + self.motion_sensor_gf = pd.get(props.STG_ZGW, loc, props.ROO_STG, props.FUN_MSE) + super().__init__(mqtt_client, pd, vd) # # Functionality initialisation @@ -47,6 +49,6 @@ class stairway_stairway(room): # self.main_light_videv = videv_switching_motion( mqtt_client, config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_VIDEV, - self.main_light_shelly, devices.shelly.KEY_OUTPUT_0, + self.main_light_shelly, self.main_light_shelly.KEY_OUTPUT_0, self.motion_sensor_light ) diff --git a/smart_brain.py b/smart_brain.py index 505d34b..f88d05a 100644 --- a/smart_brain.py +++ b/smart_brain.py @@ -1,4 +1,5 @@ import config +import devdi import function import json import logging @@ -38,17 +39,36 @@ def __info_publisher__(client, userdata, message): if __name__ == "__main__": + # + # Logging + # if config.DEBUG: report.appLoggingConfigure(None, 'stdout', ((config.APP_NAME, logging.DEBUG), ), target_level=logging.WARNING, fmt=report.SHORT_FMT, host='localhost', port=19996) else: report.stdoutLoggingConfigure(((config.APP_NAME, logging.WARNING), ), report.SHORT_FMT) + + # + # MQTT Client # mc = mqtt.mqtt_client(host=config.MQTT_SERVER, port=config.MQTT_PORT, username=config.MQTT_USER, password=config.MQTT_PASSWORD, name=config.APP_NAME) mc.add_callback(INFO_TOPIC, __info_publisher__) - func = function.all_functions(mc) + # + # Smarthome physical Devices + # + pd = devdi.physical_devices(mc) + + # + # Smarthome physical Devices + # + vd = devdi.videv_devices(mc) + + # + # Smart Home Functionality + # + func = function.all_functions(mc, pd, vd) while (True): time.sleep(1) diff --git a/topics.py b/topics.py index a0fdeb3..3f6a92a 100644 --- a/topics.py +++ b/topics.py @@ -5,115 +5,68 @@ TOPIC_WARNINGS = "videv/warnings" TOPIC_ALL_OFF_VIDEV = "videv/off" # ground floor west # floor -TOPIC_GFW_FLOOR_MAIN_LIGHT_SHELLY = "shellies/gfw/floor/main_light" TOPIC_GFW_FLOOR_MAIN_LIGHT_VIDEV = "videv/gfw/floor/main_light" -TOPIC_GFW_FLOOR_MAIN_LIGHT_ZIGBEE = "zigbee/gfw/floor/main_light_%d" # marion -TOPIC_GFW_MARION_MAIN_LIGHT_SHELLY = "shellies/gfw/marion/main_light" TOPIC_GFW_MARION_MAIN_LIGHT_VIDEV = "videv/gfw/marion/main_light" -TOPIC_GFW_MARION_HEATING_VALVE_ZIGBEE = "zigbee/gfw/marion/heating_valve" TOPIC_GFW_MARION_HEATING_VALVE_VIDEV = "videv/gfw/marion/heating_valve" # dirk -TOPIC_GFW_DIRK_MAIN_LIGHT_SHELLY = "shellies/gfw/dirk/main_light" TOPIC_GFW_DIRK_MAIN_LIGHT_VIDEV = "videv/gfw/dirk/main_light" -TOPIC_GFW_DIRK_MAIN_LIGHT_ZIGBEE = "zigbee/gfw/dirk/main_light" -TOPIC_GFW_DIRK_INPUT_DEVICE = "zigbee/gfw/dirk/input_device" -TOPIC_GFW_DIRK_POWERPLUG = "my_apps/gfw/dirk/powerplug" -TOPIC_GFW_DIRK_DESK_LIGHT_ZIGBEE = "zigbee/gfw/dirk/desk_light" TOPIC_GFW_DIRK_DESK_LIGHT_VIDEV = "videv/gfw/dirk/desk_light" TOPIC_GFW_DIRK_AMPLIFIER_VIDEV = "videv/gfw/dirk/amplifier" TOPIC_GFW_DIRK_CD_PLAYER_VIDEV = "videv/gfw/dirk/cd_player" TOPIC_GFW_DIRK_PC_DOCK_VIDEV = "videv/gfw/dirk/pc_dock" -TOPIC_GFW_DIRK_AMPLIFIER_REMOTE = "my_apps/gfw/dirk/remote/RAS5" TOPIC_GFW_DIRK_ACTIVE_BRIGHTNESS_DEVICE_VIDEV = "videv/gfw/dirk/active_brightness_device" -TOPIC_GFW_DIRK_SPOTIFY = "my_apps/gfw/dirk/hifi/spotify" -TOPIC_GFW_DIRK_MPD = "my_apps/gfw/dirk/hifi/mpd" TOPIC_GFW_DIRK_AUDIO_PLAYER_VIDEV = "videv/gfw/dirk/audio_player" -TOPIC_GFW_DIRK_HEATING_VALVE_ZIGBEE = "zigbee/gfw/dirk/heating_valve" TOPIC_GFW_DIRK_HEATING_VALVE_VIDEV = "videv/gfw/dirk/heating_valve" # first floor west # julian -TOPIC_FFW_JULIAN_MAIN_LIGHT_SHELLY = "shellies/ffw/julian/main_light" TOPIC_FFW_JULIAN_MAIN_LIGHT_VIDEV = "videv/ffw/julian/main_light" -TOPIC_FFW_JULIAN_MAIN_LIGHT_ZIGBEE = "zigbee/ffw/julian/main_light" -TOPIC_FFW_JULIAN_HEATING_VALVE_ZIGBEE = "zigbee/ffw/julian/heating_valve" TOPIC_FFW_JULIAN_HEATING_VALVE_VIDEV = "videv/ffw/julian/heating_valve" # bath -TOPIC_FFW_BATH_HEATING_VALVE_ZIGBEE = "zigbee/ffw/bath/heating_valve" TOPIC_FFW_BATH_HEATING_VALVE_VIDEV = "videv/ffw/bath/heating_valve" # livingroom -TOPIC_FFW_LIVINGROOM_MAIN_LIGHT_SHELLY = "shellies/ffw/livingroom/main_light" TOPIC_FFW_LIVINGROOM_MAIN_LIGHT_VIDEV = "videv/ffw/livingroom/main_light" -TOPIC_FFW_LIVINGROOM_MAIN_LIGHT_ZIGBEE = "zigbee/ffw/livingroom/main_light" -# TOPIC_FFW_LIVINGROOM_HEATING_VALVE_ZIGBEE = "zigbee/ffw/livingroom/heating_valve" -# TOPIC_FFW_LIVINGROOM_HEATING_VALVE_VIDEV = "videv/ffw/livingroom/heating_valve" # sleep -TOPIC_FFW_SLEEP_MAIN_LIGHT_SHELLY = "shellies/ffw/sleep/main_light" TOPIC_FFW_SLEEP_MAIN_LIGHT_VIDEV = "videv/ffw/sleep/main_light" -TOPIC_FFW_SLEEP_MAIN_LIGHT_ZIGBEE = "zigbee/ffw/sleep/main_light" -TOPIC_FFW_SLEEP_HEATING_VALVE_ZIGBEE = "zigbee/ffw/sleep/heating_valve" TOPIC_FFW_SLEEP_HEATING_VALVE_VIDEV = "videv/ffw/sleep/heating_valve" # first floor east # floor -TOPIC_FFE_FLOOR_MAIN_LIGHT_SHELLY = "shellies/ffe/floor/main_light" TOPIC_FFE_FLOOR_MAIN_LIGHT_VIDEV = "videv/ffe/floor/main_light" # kitchen -TOPIC_FFE_KITCHEN_MAIN_LIGHT_SHELLY = "shellies/ffe/kitchen/main_light" TOPIC_FFE_KITCHEN_MAIN_LIGHT_VIDEV = "videv/ffe/kitchen/main_light" -TOPIC_FFE_KITCHEN_CIRCULATION_PUMP_SHELLY = "shellies/ffe/kitchen/circulation_pump" TOPIC_FFE_KITCHEN_CIRCULATION_PUMP_VIDEV = "videv/ffe/kitchen/circulation_pump" -TOPIC_FFE_KITCHEN_HEATING_VALVE_ZIGBEE = "zigbee/ffe/kitchen/heating_valve" TOPIC_FFE_KITCHEN_HEATING_VALVE_VIDEV = "videv/ffe/kitchen/heating_valve" # diningroom -TOPIC_FFE_DININGROOM_MAIN_LIGHT_SHELLY = "shellies/ffe/diningroom/main_light" TOPIC_FFE_DININGROOM_MAIN_LIGHT_VIDEV = "videv/ffe/diningroom/main_light" -TOPIC_FFE_DININGROOM_FLOOR_LAMP_POWERPLUG = "zigbee/ffe/diningroom/powerplug_floorlamp" TOPIC_FFE_DININGROOM_FLOOR_LAMP_VIDEV = "videv/ffe/diningroom/floorlamp" -TOPIC_FFE_DININGROOM_GARLAND_POWERPLUG = "zigbee/ffe/diningroom/garland" TOPIC_FFE_DININGROOM_GARLAND_VIDEV = "videv/ffe/diningroom/garland" -TOPIC_FFE_DININGROOM_HEATING_VALVE_ZIGBEE = "zigbee/ffe/diningroom/heating_valve" TOPIC_FFE_DININGROOM_HEATING_VALVE_VIDEV = "videv/ffe/diningroom/heating_valve" # sleep -TOPIC_FFE_SLEEP_MAIN_LIGHT_SHELLY = "shellies/ffe/sleep/main_light" TOPIC_FFE_SLEEP_MAIN_LIGHT_VIDEV = "videv/ffe/sleep/main_light" -TOPIC_FFE_SLEEP_MAIN_LIGHT_ZIGBEE = "zigbee/ffe/sleep/main_light" -TOPIC_FFE_SLEEP_INPUT_DEVICE = "zigbee/ffe/sleep/input_device" -TOPIC_FFE_SLEEP_BED_LIGHT_DI_ZIGBEE = "zigbee/ffe/sleep/bed_light_di" TOPIC_FFE_SLEEP_BED_LIGHT_DI_VIDEV = "videv/ffe/sleep/bed_light_di" -TOPIC_FFE_SLEEP_BED_LIGHT_MA_POWERPLUG = "zigbee/ffe/sleep/bed_light_ma" TOPIC_FFE_SLEEP_BED_LIGHT_MA_VIDEV = "videv/ffe/sleep/bed_light_ma" TOPIC_FFE_SLEEP_ACTIVE_BRIGHTNESS_DEVICE_VIDEV = "videv/ffe/sleep/active_brightness_device" -TOPIC_FFE_SLEEP_HEATING_VALVE_ZIGBEE = "zigbee/ffe/sleep/heating_valve" TOPIC_FFE_SLEEP_HEATING_VALVE_VIDEV = "videv/ffe/sleep/heating_valve" # livingroom -TOPIC_FFE_LIVINGROOM_MAIN_LIGHT_SHELLY = "shellies/ffe/livingroom/main_light" TOPIC_FFE_LIVINGROOM_MAIN_LIGHT_VIDEV = "videv/ffe/livingroom/main_light" -TOPIC_FFE_LIVINGROOM_MAIN_LIGHT_ZIGBEE = "zigbee/ffe/livingroom/main_light" -TOPIC_FFE_LIVINGROOM_FLOOR_LAMP_ZIGBEE = "zigbee/ffe/livingroom/floorlamp_%d" TOPIC_FFE_LIVINGROOM_FLOOR_LAMP_VIDEV = "videv/ffe/livingroom/floorlamp" -TOPIC_FFE_LIVINGROOM_XMAS_TREE_POWERPLUG = "zigbee/ffe/livingroom/powerplug_xmas-tree" TOPIC_FFE_LIVINGROOM_XMAS_TREE_VIDEV = "videv/ffe/livingroom/xmas_tree" -TOPIC_FFE_LIVINGROOM_XMAS_STAR_POWERPLUG = "zigbee/ffe/livingroom/powerplug_xmas-star" -TOPIC_FFE_LIVINGROOM_HEATING_VALVE_ZIGBEE = "zigbee/ffe/livingroom/heating_valve" TOPIC_FFE_LIVINGROOM_HEATING_VALVE_VIDEV = "videv/ffe/livingroom/heating_valve" # first floor east # floor -TOPIC_STW_STAIRWAY_MAIN_LIGHT_SHELLY = "shellies/stw/stairway/main_light" TOPIC_STW_STAIRWAY_MAIN_LIGHT_VIDEV = "videv/stw/stairway/main_light" -TOPIC_STW_STAIRWAY_MAIN_LIGHT_MOTION_SENSOR_FF = "zigbee/ffe/stairway/motion_sensor_ff" -TOPIC_STW_STAIRWAY_MAIN_LIGHT_MOTION_SENSOR_GF = "zigbee/gfw/stairway/motion_sensor_gf"