123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- #
- """
- Virtual Device(s)
-
- Targets:
- * MQTT-Interface to control joined devices as one virtual device.
- * Primary signal routing
- * No functionality should be implemented here
- """
-
- # TODO: Extend virtual devices
- # * Digital-Audio-Sources (Spotify, MPD, Currently playing) oder direkt von my_apps?!
- # *
-
- from base import mqtt_base
- import devices
- import inspect
- import json
- import logging
-
- BASETOPIC = "videv"
-
-
- try:
- from config import APP_NAME as ROOT_LOGGER_NAME
- except ImportError:
- ROOT_LOGGER_NAME = 'root'
-
-
- class base(mqtt_base):
- EXEC_RX_FUNC_ALWAYS = []
-
- def __init__(self, mqtt_client, topic, *args, default_values=None):
- super().__init__(mqtt_client, topic, default_values=default_values)
- self.__device_list__ = {}
- for videv_key, device in [reduced[:2] for reduced in args]:
- self.__device_list__[videv_key] = device
- # send initial state
- for key in self.keys():
- self.__tx__(key, self[key])
- # add receive topics
- mqtt_client.add_callback(self.topic + "/#", self.__rx__)
-
- def __tx__(self, key, data):
- if type(data) not in (str, ):
- data = json.dumps(data)
- if key in self.keys():
- self.mqtt_client.send(self.topic + '/' + key, data)
- else:
- self.logger.warning("Ignoring send request for key %s (not available for this class)", key)
-
- def __rx__(self, client, userdata, message):
- key = message.topic.split('/')[-1]
- if key in self.keys():
- try:
- data = json.loads(message.payload)
- except json.decoder.JSONDecodeError:
- data = message.payload
- if data != self[key] or key in self.EXEC_RX_FUNC_ALWAYS:
- self.__rx_functionality__(key, data)
- self.set(key, data)
- else:
- self.logger.info("Ignoring rx message with topic %s", message.topic)
-
- def __rx_functionality__(self, key, data):
- raise NotImplemented("Method __rx_functionality__ needs to be implemented in child class")
-
- def __device_data__(self, device, key, data):
- raise NotImplemented("Method __device_data__ needs to be implemented in child class")
-
-
- class base_routing(base):
- def __init__(self, mqtt_client, topic, *args, default_values=None):
- super().__init__(mqtt_client, topic, *args, default_values=default_values)
- #
- self.__device_key__ = {}
- index = 0
- for videv_key, device, device_key in args:
- if self.__device_list__[videv_key] != device:
- raise ReferenceError("Parent class generated a deviating device list")
- self.__device_key__[videv_key] = device_key
- index += 1
- # add callbacks
- for key in self.__device_list__:
- if self.__device_list__[key].__class__.__name__ == "group":
- self.__device_list__[key][0].add_callback(self.__device_key__[key], None, self.__device_data__, True)
- else:
- self.__device_list__[key].add_callback(self.__device_key__[key], None, self.__device_data__, True)
-
- def __rx_functionality__(self, key, data):
- try:
- self.__device_list__[key].set(self.__device_key__[key], data)
- except KeyError:
- self.logger.warning("RX passthrough not possible for key %s", key)
-
- def __device_data__(self, device, key, data):
- l1 = []
- for k, v in self.__device_list__.items():
- if v.__class__.__name__ == "group":
- if device in v:
- l1.append(k)
- else:
- if v == device:
- l1.append(k)
- l2 = [k for k, v in self.__device_key__.items() if v == key]
- try:
- videv_key = [k for k in l1 if k in l2][0]
- except IndexError:
- self.logger.warning("videv_key not available for %s::%s", device.__class__.__name__, device.topic)
- else:
- self.set(videv_key, data)
- self.__tx__(videv_key, data)
-
-
- class videv_switching(base_routing):
- KEY_STATE = 'state'
- #
- DEFAULT_VALUES = {
- KEY_STATE: False,
- }
-
- def __init__(self, mqtt_client, topic, sw_device, sw_key):
- super().__init__(mqtt_client, topic, (self.KEY_STATE, sw_device, sw_key))
-
-
- class videv_switching_timer(base_routing):
- KEY_STATE = 'state'
- KEY_TIMER = 'timer'
- #
- DEFAULT_VALUES = {
- KEY_STATE: False,
- KEY_TIMER: 0
- }
-
- def __init__(self, mqtt_client, topic, sw_device, sw_key, tm_device, tm_key):
- super().__init__(mqtt_client, topic, (self.KEY_STATE, sw_device, sw_key), (self.KEY_TIMER, tm_device, tm_key))
-
-
- class videv_switching_motion(base_routing):
- KEY_STATE = 'state'
- KEY_TIMER = 'timer'
- KEY_MOTION_SENSOR = 'motion_%d'
- #
- DEFAULT_VALUES = {
- KEY_STATE: False,
- KEY_TIMER: 0
- }
-
- def __init__(self, mqtt_client, topic, sw_device, sw_key, motion_function):
- dv = {self.KEY_STATE: False, self.KEY_TIMER: 0}
- for i in range(0, len(motion_function.args)):
- dv[motion_function.KEY_MOTION_SENSOR % i] = False
- super().__init__(
- mqtt_client, topic,
- (self.KEY_STATE, sw_device, sw_key),
- (self.KEY_TIMER, motion_function, motion_function.KEY_TIMER),
- *[[self.KEY_MOTION_SENSOR % i, motion_function, motion_function.KEY_MOTION_SENSOR % i] for i in range(0, len(motion_function.args))],
- default_values=dv
- )
-
-
- class videv_switch_brightness(base_routing):
- KEY_STATE = 'state'
- KEY_BRIGHTNESS = 'brightness'
- #
- DEFAULT_VALUES = {
- KEY_STATE: False,
- KEY_BRIGHTNESS: 0
- }
-
- def __init__(self, mqtt_client, topic, sw_device, sw_key, br_device, br_key):
- #
- super().__init__(mqtt_client, topic, (self.KEY_STATE, sw_device, sw_key), (self.KEY_BRIGHTNESS, br_device, br_key))
-
-
- class videv_switch_brightness_color_temp(base_routing):
- KEY_STATE = 'state'
- KEY_BRIGHTNESS = 'brightness'
- KEY_COLOR_TEMP = 'color_temp'
- #
- DEFAULT_VALUES = {
- KEY_STATE: False,
- KEY_BRIGHTNESS: 0,
- KEY_COLOR_TEMP: 0,
- }
-
- def __init__(self, mqtt_client, topic, sw_device, sw_key, br_device, br_key, ct_device, ct_key):
- #
- super().__init__(
- mqtt_client, topic,
- (self.KEY_STATE, sw_device, sw_key),
- (self.KEY_BRIGHTNESS, br_device, br_key),
- (self.KEY_COLOR_TEMP, ct_device, ct_key)
- )
-
-
- class videv_heating(base_routing):
- KEY_TEMPERATURE = 'temperature'
- KEY_USER_TEMPERATURE_SETPOINT = 'user_temperature_setpoint'
- KEY_VALVE_TEMPERATURE_SETPOINT = 'valve_temperature_setpoint'
- KEY_AWAY_MODE = 'away_mode'
- KEY_SUMMER_MODE = 'summer_mode'
- KEY_START_BOOST = 'start_boost'
- KEY_SET_DEFAULT_TEMPERATURE = 'set_default_temperature'
- KEY_BOOST_TIMER = 'boost_timer'
- #
- EXEC_RX_FUNC_ALWAYS = [KEY_START_BOOST, KEY_SET_DEFAULT_TEMPERATURE, KEY_USER_TEMPERATURE_SETPOINT]
-
- def __init__(self, mqtt_client, topic, heating_function):
- #
- super().__init__(
- mqtt_client, topic,
- (self.KEY_TEMPERATURE, heating_function, heating_function.KEY_TEMPERATURE_CURRENT),
- (self.KEY_USER_TEMPERATURE_SETPOINT, heating_function, heating_function.KEY_USER_TEMPERATURE_SETPOINT),
- (self.KEY_VALVE_TEMPERATURE_SETPOINT, heating_function, heating_function.KEY_TEMPERATURE_SETPOINT),
- (self.KEY_AWAY_MODE, heating_function, heating_function.KEY_AWAY_MODE),
- (self.KEY_SUMMER_MODE, heating_function, heating_function.KEY_SUMMER_MODE),
- (self.KEY_START_BOOST, heating_function, heating_function.KEY_START_BOOST),
- (self.KEY_SET_DEFAULT_TEMPERATURE, heating_function, heating_function.KEY_SET_DEFAULT_TEMPERATURE),
- (self.KEY_BOOST_TIMER, heating_function, heating_function.KEY_BOOST_TIMER),
- default_values={
- self.KEY_TEMPERATURE: heating_function[heating_function.KEY_TEMPERATURE_CURRENT],
- self.KEY_VALVE_TEMPERATURE_SETPOINT: heating_function[heating_function.KEY_TEMPERATURE_SETPOINT],
- self.KEY_USER_TEMPERATURE_SETPOINT: heating_function[heating_function.KEY_USER_TEMPERATURE_SETPOINT],
- self.KEY_AWAY_MODE: heating_function[heating_function.KEY_AWAY_MODE],
- self.KEY_SUMMER_MODE: heating_function[heating_function.KEY_SUMMER_MODE],
- self.KEY_BOOST_TIMER: heating_function[heating_function.KEY_BOOST_TIMER],
- self.KEY_START_BOOST: True,
- self.KEY_SET_DEFAULT_TEMPERATURE: True,
- }
- )
-
-
- class videv_multistate(base):
- def __init__(self, mqtt_client, topic, key_for_topic, device, num_states, default_values=None):
- dv = dict.fromkeys(["state_%d" % i for i in range(0, num_states)])
- for key in dv:
- dv[key] = False
- super().__init__(mqtt_client, topic, (key_for_topic, device), default_values=dv)
- #
- device.add_callback(key_for_topic, None, self.__index_rx__, True)
-
- def __index_rx__(self, device, key, data):
- for index, key in enumerate(self):
- self.set(key, index == data)
- self.__tx__(key, self[key])
|