Smarthome Functionen
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

videv.py 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. """
  5. Virtual Device(s)
  6. Targets:
  7. * MQTT-Interface to control joined devices as one virtual device.
  8. * Primary signal routing
  9. * No functionality should be implemented here
  10. """
  11. # TODO: Extend virtual devices
  12. # * Digital-Audio-Sources (Spotify, MPD, Currently playing) oder direkt von my_apps?!
  13. # *
  14. from base import mqtt_base
  15. import devices
  16. import inspect
  17. import json
  18. import logging
  19. BASETOPIC = "videv"
  20. try:
  21. from config import APP_NAME as ROOT_LOGGER_NAME
  22. except ImportError:
  23. ROOT_LOGGER_NAME = 'root'
  24. class base(mqtt_base):
  25. EXEC_RX_FUNC_ALWAYS = []
  26. def __init__(self, mqtt_client, topic, *args, default_values=None):
  27. super().__init__(mqtt_client, topic, default_values=default_values)
  28. self.__device_list__ = {}
  29. for videv_key, device in [reduced[:2] for reduced in args]:
  30. self.__device_list__[videv_key] = device
  31. # send initial state
  32. for key in self.keys():
  33. self.__tx__(key, self[key])
  34. # add receive topics
  35. mqtt_client.add_callback(self.topic + "/#", self.__rx__)
  36. def __tx__(self, key, data):
  37. if type(data) not in (str, ):
  38. data = json.dumps(data)
  39. if key in self.keys():
  40. self.mqtt_client.send(self.topic + '/' + key, data)
  41. else:
  42. self.logger.warning("Ignoring send request for key %s (not available for this class)", key)
  43. def __rx__(self, client, userdata, message):
  44. key = message.topic.split('/')[-1]
  45. if key in self.keys():
  46. try:
  47. data = json.loads(message.payload)
  48. except json.decoder.JSONDecodeError:
  49. data = message.payload
  50. if data != self[key] or key in self.EXEC_RX_FUNC_ALWAYS:
  51. self.__rx_functionality__(key, data)
  52. self.set(key, data)
  53. else:
  54. self.logger.info("Ignoring rx message with topic %s", message.topic)
  55. def __rx_functionality__(self, key, data):
  56. raise NotImplemented("Method __rx_functionality__ needs to be implemented in child class")
  57. def __device_data__(self, device, key, data):
  58. raise NotImplemented("Method __device_data__ needs to be implemented in child class")
  59. class base_routing(base):
  60. def __init__(self, mqtt_client, topic, *args, default_values=None):
  61. super().__init__(mqtt_client, topic, *args, default_values=default_values)
  62. #
  63. self.__device_key__ = {}
  64. index = 0
  65. for videv_key, device, device_key in args:
  66. if self.__device_list__[videv_key] != device:
  67. raise ReferenceError("Parent class generated a deviating device list")
  68. self.__device_key__[videv_key] = device_key
  69. index += 1
  70. # add callbacks
  71. for key in self.__device_list__:
  72. if self.__device_list__[key].__class__.__name__ == "group":
  73. self.__device_list__[key][0].add_callback(self.__device_key__[key], None, self.__device_data__, True)
  74. else:
  75. self.__device_list__[key].add_callback(self.__device_key__[key], None, self.__device_data__, True)
  76. def __rx_functionality__(self, key, data):
  77. try:
  78. self.__device_list__[key].set(self.__device_key__[key], data)
  79. except KeyError:
  80. self.logger.warning("RX passthrough not possible for key %s", key)
  81. def __device_data__(self, device, key, data):
  82. l1 = []
  83. for k, v in self.__device_list__.items():
  84. if v.__class__.__name__ == "group":
  85. if device in v:
  86. l1.append(k)
  87. else:
  88. if v == device:
  89. l1.append(k)
  90. l2 = [k for k, v in self.__device_key__.items() if v == key]
  91. try:
  92. videv_key = [k for k in l1 if k in l2][0]
  93. except IndexError:
  94. self.logger.warning("videv_key not available for %s::%s", device.__class__.__name__, device.topic)
  95. else:
  96. self.set(videv_key, data)
  97. self.__tx__(videv_key, data)
  98. class videv_switching(base_routing):
  99. KEY_STATE = 'state'
  100. #
  101. DEFAULT_VALUES = {
  102. KEY_STATE: False,
  103. }
  104. def __init__(self, mqtt_client, topic, sw_device, sw_key):
  105. super().__init__(mqtt_client, topic, (self.KEY_STATE, sw_device, sw_key))
  106. class videv_switching_timer(base_routing):
  107. KEY_STATE = 'state'
  108. KEY_TIMER = 'timer'
  109. #
  110. DEFAULT_VALUES = {
  111. KEY_STATE: False,
  112. KEY_TIMER: 0
  113. }
  114. def __init__(self, mqtt_client, topic, sw_device, sw_key, tm_device, tm_key):
  115. super().__init__(mqtt_client, topic, (self.KEY_STATE, sw_device, sw_key), (self.KEY_TIMER, tm_device, tm_key))
  116. class videv_switching_motion(base_routing):
  117. KEY_STATE = 'state'
  118. KEY_TIMER = 'timer'
  119. KEY_MOTION_SENSOR = 'motion_%d'
  120. #
  121. DEFAULT_VALUES = {
  122. KEY_STATE: False,
  123. KEY_TIMER: 0
  124. }
  125. def __init__(self, mqtt_client, topic, sw_device, sw_key, motion_function):
  126. dv = {self.KEY_STATE: False, self.KEY_TIMER: 0}
  127. for i in range(0, len(motion_function.args)):
  128. dv[motion_function.KEY_MOTION_SENSOR % i] = False
  129. super().__init__(
  130. mqtt_client, topic,
  131. (self.KEY_STATE, sw_device, sw_key),
  132. (self.KEY_TIMER, motion_function, motion_function.KEY_TIMER),
  133. *[[self.KEY_MOTION_SENSOR % i, motion_function, motion_function.KEY_MOTION_SENSOR % i] for i in range(0, len(motion_function.args))],
  134. default_values=dv
  135. )
  136. class videv_switch_brightness(base_routing):
  137. KEY_STATE = 'state'
  138. KEY_BRIGHTNESS = 'brightness'
  139. #
  140. DEFAULT_VALUES = {
  141. KEY_STATE: False,
  142. KEY_BRIGHTNESS: 0
  143. }
  144. def __init__(self, mqtt_client, topic, sw_device, sw_key, br_device, br_key):
  145. #
  146. super().__init__(mqtt_client, topic, (self.KEY_STATE, sw_device, sw_key), (self.KEY_BRIGHTNESS, br_device, br_key))
  147. class videv_switch_brightness_color_temp(base_routing):
  148. KEY_STATE = 'state'
  149. KEY_BRIGHTNESS = 'brightness'
  150. KEY_COLOR_TEMP = 'color_temp'
  151. #
  152. DEFAULT_VALUES = {
  153. KEY_STATE: False,
  154. KEY_BRIGHTNESS: 0,
  155. KEY_COLOR_TEMP: 0,
  156. }
  157. def __init__(self, mqtt_client, topic, sw_device, sw_key, br_device, br_key, ct_device, ct_key):
  158. #
  159. super().__init__(
  160. mqtt_client, topic,
  161. (self.KEY_STATE, sw_device, sw_key),
  162. (self.KEY_BRIGHTNESS, br_device, br_key),
  163. (self.KEY_COLOR_TEMP, ct_device, ct_key)
  164. )
  165. class videv_heating(base_routing):
  166. KEY_TEMPERATURE = 'temperature'
  167. KEY_USER_TEMPERATURE_SETPOINT = 'user_temperature_setpoint'
  168. KEY_VALVE_TEMPERATURE_SETPOINT = 'valve_temperature_setpoint'
  169. KEY_AWAY_MODE = 'away_mode'
  170. KEY_SUMMER_MODE = 'summer_mode'
  171. KEY_START_BOOST = 'start_boost'
  172. KEY_SET_DEFAULT_TEMPERATURE = 'set_default_temperature'
  173. KEY_BOOST_TIMER = 'boost_timer'
  174. #
  175. EXEC_RX_FUNC_ALWAYS = [KEY_START_BOOST, KEY_SET_DEFAULT_TEMPERATURE, KEY_USER_TEMPERATURE_SETPOINT]
  176. def __init__(self, mqtt_client, topic, heating_function):
  177. #
  178. super().__init__(
  179. mqtt_client, topic,
  180. (self.KEY_TEMPERATURE, heating_function, heating_function.KEY_TEMPERATURE_CURRENT),
  181. (self.KEY_USER_TEMPERATURE_SETPOINT, heating_function, heating_function.KEY_USER_TEMPERATURE_SETPOINT),
  182. (self.KEY_VALVE_TEMPERATURE_SETPOINT, heating_function, heating_function.KEY_TEMPERATURE_SETPOINT),
  183. (self.KEY_AWAY_MODE, heating_function, heating_function.KEY_AWAY_MODE),
  184. (self.KEY_SUMMER_MODE, heating_function, heating_function.KEY_SUMMER_MODE),
  185. (self.KEY_START_BOOST, heating_function, heating_function.KEY_START_BOOST),
  186. (self.KEY_SET_DEFAULT_TEMPERATURE, heating_function, heating_function.KEY_SET_DEFAULT_TEMPERATURE),
  187. (self.KEY_BOOST_TIMER, heating_function, heating_function.KEY_BOOST_TIMER),
  188. default_values={
  189. self.KEY_TEMPERATURE: heating_function[heating_function.KEY_TEMPERATURE_CURRENT],
  190. self.KEY_VALVE_TEMPERATURE_SETPOINT: heating_function[heating_function.KEY_TEMPERATURE_SETPOINT],
  191. self.KEY_USER_TEMPERATURE_SETPOINT: heating_function[heating_function.KEY_USER_TEMPERATURE_SETPOINT],
  192. self.KEY_AWAY_MODE: heating_function[heating_function.KEY_AWAY_MODE],
  193. self.KEY_SUMMER_MODE: heating_function[heating_function.KEY_SUMMER_MODE],
  194. self.KEY_BOOST_TIMER: heating_function[heating_function.KEY_BOOST_TIMER],
  195. self.KEY_START_BOOST: True,
  196. self.KEY_SET_DEFAULT_TEMPERATURE: True,
  197. }
  198. )
  199. class videv_multistate(base):
  200. def __init__(self, mqtt_client, topic, key, device, num_states, default_values=None):
  201. dv = dict.fromkeys(["state_%d" % i for i in range(0, num_states)])
  202. for key in dv:
  203. dv[key] = False
  204. super().__init__(mqtt_client, topic, (key, device), default_values=dv)
  205. #
  206. device.add_callback(key, None, self.__index_rx__, True)
  207. def __index_rx__(self, device, key, data):
  208. for index, key in enumerate(self):
  209. self.set(key, index == data)
  210. self.__tx__(key, self[key])