2023-01-20 08:03:06 +01:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#
|
|
|
|
"""
|
|
|
|
Virtual Device(s)
|
|
|
|
|
|
|
|
Targets:
|
2023-02-06 12:42:44 +01:00
|
|
|
* MQTT-Interface to control joined devices as one virtual device
|
|
|
|
* Primary signal routing
|
2023-01-20 08:03:06 +01:00
|
|
|
* No functionality should be implemented here
|
|
|
|
"""
|
|
|
|
|
2023-02-22 07:34:06 +01:00
|
|
|
from base import videv_base
|
2023-01-31 19:17:10 +01:00
|
|
|
from function.rooms import room, room_collection
|
2023-01-29 12:41:35 +01:00
|
|
|
import time
|
2023-01-20 08:03:06 +01:00
|
|
|
|
|
|
|
try:
|
|
|
|
from config import APP_NAME as ROOT_LOGGER_NAME
|
|
|
|
except ImportError:
|
|
|
|
ROOT_LOGGER_NAME = 'root'
|
|
|
|
|
|
|
|
|
2023-02-22 07:34:06 +01:00
|
|
|
class videv_switching(videv_base):
|
2023-01-20 08:03:06 +01:00
|
|
|
KEY_STATE = 'state'
|
|
|
|
|
|
|
|
def __init__(self, mqtt_client, topic, sw_device, sw_key):
|
2023-01-28 14:32:52 +01:00
|
|
|
super().__init__(mqtt_client, topic)
|
|
|
|
self.add_routing(self.KEY_STATE, sw_device, sw_key)
|
2023-01-20 08:03:06 +01:00
|
|
|
|
|
|
|
|
2023-02-22 07:34:06 +01:00
|
|
|
class videv_switching_timer(videv_base):
|
2023-01-25 07:40:33 +01:00
|
|
|
KEY_STATE = 'state'
|
|
|
|
KEY_TIMER = 'timer'
|
|
|
|
|
|
|
|
def __init__(self, mqtt_client, topic, sw_device, sw_key, tm_device, tm_key):
|
2023-01-28 14:32:52 +01:00
|
|
|
super().__init__(mqtt_client, topic)
|
|
|
|
self.add_routing(self.KEY_STATE, sw_device, sw_key)
|
|
|
|
self.add_display(self.KEY_TIMER, tm_device, tm_key)
|
2023-01-25 07:40:33 +01:00
|
|
|
|
|
|
|
|
2023-02-22 07:34:06 +01:00
|
|
|
class videv_switching_motion(videv_base):
|
2023-01-25 07:40:33 +01:00
|
|
|
KEY_STATE = 'state'
|
2023-01-28 14:32:52 +01:00
|
|
|
#
|
2023-01-25 07:40:33 +01:00
|
|
|
KEY_TIMER = 'timer'
|
|
|
|
KEY_MOTION_SENSOR = 'motion_%d'
|
|
|
|
|
|
|
|
def __init__(self, mqtt_client, topic, sw_device, sw_key, motion_function):
|
2023-01-28 14:32:52 +01:00
|
|
|
self.motion_sensors = motion_function.motion_sensors
|
|
|
|
#
|
|
|
|
super().__init__(mqtt_client, topic)
|
|
|
|
self.add_routing(self.KEY_STATE, sw_device, sw_key)
|
|
|
|
self.add_display(self.KEY_TIMER, motion_function, motion_function.KEY_TIMER)
|
|
|
|
# motion sensor state
|
|
|
|
for index, motion_sensor in enumerate(self.motion_sensors):
|
|
|
|
self.add_display(self.KEY_MOTION_SENSOR % index, motion_sensor, motion_sensor.KEY_OCCUPANCY)
|
|
|
|
|
|
|
|
|
2023-02-22 07:34:06 +01:00
|
|
|
class videv_switch_brightness(videv_base):
|
2023-01-20 08:03:06 +01:00
|
|
|
KEY_STATE = 'state'
|
|
|
|
KEY_BRIGHTNESS = 'brightness'
|
|
|
|
|
|
|
|
def __init__(self, mqtt_client, topic, sw_device, sw_key, br_device, br_key):
|
2023-01-28 14:32:52 +01:00
|
|
|
super().__init__(mqtt_client, topic)
|
|
|
|
self.add_routing(self.KEY_STATE, sw_device, sw_key)
|
|
|
|
self.add_routing(self.KEY_BRIGHTNESS, br_device, br_key)
|
2023-01-20 08:03:06 +01:00
|
|
|
|
|
|
|
|
2023-02-22 07:34:06 +01:00
|
|
|
class videv_switch_brightness_color_temp(videv_base):
|
2023-01-20 08:03:06 +01:00
|
|
|
KEY_STATE = 'state'
|
|
|
|
KEY_BRIGHTNESS = 'brightness'
|
|
|
|
KEY_COLOR_TEMP = 'color_temp'
|
|
|
|
|
|
|
|
def __init__(self, mqtt_client, topic, sw_device, sw_key, br_device, br_key, ct_device, ct_key):
|
2023-01-28 14:32:52 +01:00
|
|
|
super().__init__(mqtt_client, topic)
|
|
|
|
self.add_routing(self.KEY_STATE, sw_device, sw_key)
|
|
|
|
self.add_routing(self.KEY_BRIGHTNESS, br_device, br_key)
|
|
|
|
self.add_routing(self.KEY_COLOR_TEMP, ct_device, ct_key)
|
2023-01-25 07:40:33 +01:00
|
|
|
|
|
|
|
|
2023-02-22 07:34:06 +01:00
|
|
|
class videv_heating(videv_base):
|
2023-01-25 07:40:33 +01:00
|
|
|
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'
|
|
|
|
#
|
2023-01-28 14:32:52 +01:00
|
|
|
KEY_TEMPERATURE = 'temperature'
|
2023-01-25 07:40:33 +01:00
|
|
|
|
|
|
|
def __init__(self, mqtt_client, topic, heating_function):
|
2023-01-28 14:32:52 +01:00
|
|
|
super().__init__(mqtt_client, topic)
|
|
|
|
#
|
|
|
|
self.add_routing(self.KEY_USER_TEMPERATURE_SETPOINT, heating_function, heating_function.KEY_USER_TEMPERATURE_SETPOINT)
|
|
|
|
self.add_routing(self.KEY_AWAY_MODE, heating_function, heating_function.KEY_AWAY_MODE)
|
|
|
|
self.add_routing(self.KEY_SUMMER_MODE, heating_function, heating_function.KEY_SUMMER_MODE)
|
2023-01-25 07:40:33 +01:00
|
|
|
#
|
2023-01-28 14:32:52 +01:00
|
|
|
self.add_control(self.KEY_START_BOOST, heating_function, heating_function.KEY_START_BOOST, False)
|
|
|
|
self.add_control(self.KEY_SET_DEFAULT_TEMPERATURE, heating_function, heating_function.KEY_SET_DEFAULT_TEMPERATURE, False)
|
|
|
|
#
|
|
|
|
self.add_display(self.KEY_VALVE_TEMPERATURE_SETPOINT, heating_function, heating_function.KEY_TEMPERATURE_SETPOINT)
|
|
|
|
self.add_display(self.KEY_BOOST_TIMER, heating_function, heating_function.KEY_BOOST_TIMER)
|
2023-01-28 21:25:15 +01:00
|
|
|
self.add_display(self.KEY_TEMPERATURE, heating_function, heating_function.KEY_TEMPERATURE_CURRENT, False)
|
2023-01-25 07:40:33 +01:00
|
|
|
|
|
|
|
|
2023-02-22 07:34:06 +01:00
|
|
|
class videv_multistate(videv_base):
|
2023-01-28 14:32:52 +01:00
|
|
|
KEY_STATE = 'state_%d'
|
|
|
|
|
2023-01-25 12:49:36 +01:00
|
|
|
def __init__(self, mqtt_client, topic, key_for_device, device, num_states, default_values=None):
|
2023-01-28 14:32:52 +01:00
|
|
|
super().__init__(mqtt_client, topic)
|
|
|
|
self.num_states = num_states
|
|
|
|
# send default values
|
|
|
|
for i in range(0, num_states):
|
|
|
|
self.__tx__(self.KEY_STATE % i, False)
|
2023-01-25 07:40:33 +01:00
|
|
|
#
|
2023-01-25 12:49:36 +01:00
|
|
|
device.add_callback(key_for_device, None, self.__index_rx__, True)
|
2023-01-25 07:40:33 +01:00
|
|
|
|
|
|
|
def __index_rx__(self, device, key, data):
|
2023-01-28 14:32:52 +01:00
|
|
|
for i in range(0, self.num_states):
|
|
|
|
self.__tx__(self.KEY_STATE % i, i == data)
|
2023-01-25 13:15:33 +01:00
|
|
|
|
2023-01-25 12:49:36 +01:00
|
|
|
|
2023-02-22 07:34:06 +01:00
|
|
|
class videv_audio_player(videv_base):
|
2023-01-25 12:49:36 +01:00
|
|
|
KEY_ACTIVE_PLAYER = 'player_%d'
|
|
|
|
KEY_TITLE = 'title'
|
|
|
|
NO_TITLE = '---'
|
|
|
|
|
|
|
|
def __init__(self, mqtt_client, topic, *args):
|
2023-01-28 14:32:52 +01:00
|
|
|
super().__init__(mqtt_client, topic)
|
|
|
|
for i, device in enumerate(args):
|
|
|
|
self.add_display(self.KEY_ACTIVE_PLAYER % i, device, device.KEY_STATE)
|
|
|
|
#
|
2023-01-25 12:49:36 +01:00
|
|
|
for audio_device in args:
|
|
|
|
audio_device.add_callback(audio_device.KEY_TITLE, None, self.__title_rx__, True)
|
|
|
|
|
|
|
|
def __title_rx__(self, device, key, data):
|
2023-01-28 14:32:52 +01:00
|
|
|
self.__tx__(self.KEY_TITLE, data or self.NO_TITLE)
|
|
|
|
|
2023-01-31 19:17:10 +01:00
|
|
|
|
2023-02-22 07:34:06 +01:00
|
|
|
class videv_warnings(videv_base):
|
2023-02-10 14:34:49 +01:00
|
|
|
MAX_WARNINGS = 10
|
2023-02-10 15:47:02 +01:00
|
|
|
KEY_WARNING = 'html_short'
|
2023-02-10 14:34:49 +01:00
|
|
|
|
|
|
|
def __init__(self, mqtt_client, topic, default_values=None):
|
|
|
|
super().__init__(mqtt_client, topic, default_values)
|
|
|
|
self.__warnings__ = []
|
|
|
|
|
|
|
|
def warningcollector(self, client, key, data):
|
|
|
|
self.__warnings__.append(data)
|
|
|
|
self.__warnings__ = self.__warnings__[-self.MAX_WARNINGS:]
|
2023-02-10 15:47:02 +01:00
|
|
|
txt = "<br><br>".join([time.asctime(w[w.KEY_TM]) + "<br>" + w[w.KEY_TEXT] + "<br>" + w[w.KEY_ID] for w in self.__warnings__])
|
|
|
|
self.__tx__(self.KEY_WARNING, txt)
|
2023-02-10 14:34:49 +01:00
|
|
|
|
|
|
|
|
2023-02-22 07:34:06 +01:00
|
|
|
class all_off(videv_base):
|
2023-01-31 19:17:10 +01:00
|
|
|
ALLOWED_CLASSES = (room, room_collection, )
|
|
|
|
|
|
|
|
def __init__(self, mqtt_client, topic, room_collection):
|
|
|
|
super().__init__(mqtt_client, topic)
|
|
|
|
self.__room_collection__ = room_collection
|
|
|
|
# init __inst_dict__
|
|
|
|
self.__inst_dict__ = {}
|
|
|
|
self.__add_instances__("all", self.__room_collection__)
|
|
|
|
# register mqtt callbacks for all my keys
|
|
|
|
for key in self.__inst_dict__:
|
|
|
|
mqtt_client.add_callback(topic + "/" + key, self.all_off)
|
|
|
|
|
|
|
|
def __check_inst_capabilities__(self, name, inst):
|
|
|
|
# fits to specified classes
|
|
|
|
if isinstance(inst, self.ALLOWED_CLASSES):
|
|
|
|
try:
|
|
|
|
# all_off method is callable
|
|
|
|
return callable(inst.all_off)
|
|
|
|
except AttributeError:
|
|
|
|
# all_off method does not exist
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
|
|
|
|
def __add_instances__(self, name, inst, level=0):
|
|
|
|
if self.__check_inst_capabilities__(name, inst):
|
|
|
|
# add given instance to my __inst_dict__
|
|
|
|
self.__inst_dict__[name] = inst
|
|
|
|
# iterate over all attribute names of instance
|
|
|
|
for sub_name in dir(inst):
|
|
|
|
# attribute name is not private
|
|
|
|
if not sub_name.startswith("__"):
|
|
|
|
sub = getattr(inst, sub_name)
|
|
|
|
# recurse with this object
|
|
|
|
if level == 0:
|
|
|
|
self.__add_instances__(sub_name, sub, level=level+1)
|
|
|
|
else:
|
|
|
|
self.__add_instances__(name + "/" + sub_name, sub, level=level+1)
|
|
|
|
|
|
|
|
def all_off(self, client, userdata, message):
|
|
|
|
key = message.topic[len(self.topic) + 1:]
|
|
|
|
self.__inst_dict__[key].all_off()
|