Smarthome Functionen
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

videv.py 9.3KB

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. from base import mqtt_base
  12. import devices
  13. import json
  14. try:
  15. from config import APP_NAME as ROOT_LOGGER_NAME
  16. except ImportError:
  17. ROOT_LOGGER_NAME = 'root'
  18. class base(mqtt_base):
  19. KEY_INFO = '__info__'
  20. def __init__(self, mqtt_client, topic, default_values=None):
  21. super().__init__(mqtt_client, topic, default_values=default_values)
  22. self.__display_dict__ = {}
  23. self.__control_dict__ = {}
  24. self.__capabilities__ = None
  25. def add_display(self, my_key, ext_device, ext_key, on_change_only=True):
  26. """
  27. listen to data changes of ext_device and update videv information
  28. """
  29. if ext_device.__class__.__name__ == "group":
  30. # store information to identify callback from ext_device
  31. self.__display_dict__[(id(ext_device[0]), ext_key)] = my_key
  32. # register a callback to listen for data from external device
  33. ext_device[0].add_callback(ext_key, None, self.__rx_ext_device_data__, on_change_only)
  34. else:
  35. # store information to identify callback from ext_device
  36. self.__display_dict__[(id(ext_device), ext_key)] = my_key
  37. # register a callback to listen for data from external device
  38. ext_device.add_callback(ext_key, None, self.__rx_ext_device_data__, on_change_only)
  39. # send default data to videv interface
  40. def __rx_ext_device_data__(self, ext_device, ext_key, data):
  41. self.__tx__(self.__display_dict__[(id(ext_device), ext_key)], data)
  42. def __tx__(self, key, data):
  43. if type(data) not in (str, ):
  44. data = json.dumps(data)
  45. self.mqtt_client.send(self.topic + '/' + key, data)
  46. self.__tx_capabilities__()
  47. def __tx_capabilities__(self):
  48. self.mqtt_client.send(self.topic + '/' + self.KEY_INFO, json.dumps(self.capabilities))
  49. def add_control(self, my_key, ext_device, ext_key, on_change_only=True):
  50. """
  51. listen to videv information and pass data to ext_device
  52. """
  53. self[my_key] = None
  54. # store information to identify callback from videv
  55. self.__control_dict__[my_key] = (ext_device, ext_key, on_change_only)
  56. # add callback for videv changes
  57. self.mqtt_client.add_callback(self.topic + '/' + my_key, self.__rx_videv_data__)
  58. def __rx_videv_data__(self, client, userdata, message):
  59. my_key = message.topic.split('/')[-1]
  60. ext_device, ext_key, on_change_only = self.__control_dict__[my_key]
  61. if my_key in self.keys():
  62. try:
  63. data = json.loads(message.payload)
  64. except json.decoder.JSONDecodeError:
  65. data = message.payload
  66. if data != self[my_key] or not on_change_only:
  67. ext_device.set(ext_key, data)
  68. self.set(my_key, data)
  69. else:
  70. self.logger.info("Ignoring rx message with topic %s", message.topic)
  71. def add_routing(self, my_key, ext_device, ext_key, on_change_only_disp=True, on_change_only_videv=True):
  72. """
  73. listen to data changes of ext_device and update videv information
  74. and
  75. listen to videv information and pass data to ext_device
  76. """
  77. # add display
  78. self.add_display(my_key, ext_device, ext_key, on_change_only_disp)
  79. self.add_control(my_key, ext_device, ext_key, on_change_only_videv)
  80. @property
  81. def capabilities(self):
  82. if self.__capabilities__ is None:
  83. self.__capabilities__ = {}
  84. self.__capabilities__['__type__'] = self.__class__.__name__
  85. for key in self.__control_dict__:
  86. if not key in self.__capabilities__:
  87. self.__capabilities__[key] = {}
  88. self.__capabilities__[key]['control'] = True
  89. for key in self.__display_dict__.values():
  90. if not key in self.__capabilities__:
  91. self.__capabilities__[key] = {}
  92. self.__capabilities__[key]['display'] = True
  93. return self.__capabilities__
  94. class videv_switching(base):
  95. KEY_STATE = 'state'
  96. def __init__(self, mqtt_client, topic, sw_device, sw_key):
  97. super().__init__(mqtt_client, topic)
  98. self.add_routing(self.KEY_STATE, sw_device, sw_key)
  99. #
  100. self.__tx_capabilities__()
  101. class videv_switching_timer(base):
  102. KEY_STATE = 'state'
  103. KEY_TIMER = 'timer'
  104. def __init__(self, mqtt_client, topic, sw_device, sw_key, tm_device, tm_key):
  105. super().__init__(mqtt_client, topic)
  106. self.add_routing(self.KEY_STATE, sw_device, sw_key)
  107. self.add_display(self.KEY_TIMER, tm_device, tm_key)
  108. #
  109. self.__tx_capabilities__()
  110. class videv_switching_motion(base):
  111. KEY_STATE = 'state'
  112. #
  113. KEY_TIMER = 'timer'
  114. KEY_MOTION_SENSOR = 'motion_%d'
  115. def __init__(self, mqtt_client, topic, sw_device, sw_key, motion_function):
  116. self.motion_sensors = motion_function.motion_sensors
  117. #
  118. super().__init__(mqtt_client, topic)
  119. self.add_routing(self.KEY_STATE, sw_device, sw_key)
  120. self.add_display(self.KEY_TIMER, motion_function, motion_function.KEY_TIMER)
  121. # motion sensor state
  122. for index, motion_sensor in enumerate(self.motion_sensors):
  123. self.add_display(self.KEY_MOTION_SENSOR % index, motion_sensor, motion_sensor.KEY_OCCUPANCY)
  124. #
  125. self.__tx_capabilities__()
  126. class videv_switch_brightness(base):
  127. KEY_STATE = 'state'
  128. KEY_BRIGHTNESS = 'brightness'
  129. def __init__(self, mqtt_client, topic, sw_device, sw_key, br_device, br_key):
  130. super().__init__(mqtt_client, topic)
  131. self.add_routing(self.KEY_STATE, sw_device, sw_key)
  132. self.add_routing(self.KEY_BRIGHTNESS, br_device, br_key)
  133. #
  134. self.__tx_capabilities__()
  135. class videv_switch_brightness_color_temp(base):
  136. KEY_STATE = 'state'
  137. KEY_BRIGHTNESS = 'brightness'
  138. KEY_COLOR_TEMP = 'color_temp'
  139. def __init__(self, mqtt_client, topic, sw_device, sw_key, br_device, br_key, ct_device, ct_key):
  140. super().__init__(mqtt_client, topic)
  141. self.add_routing(self.KEY_STATE, sw_device, sw_key)
  142. self.add_routing(self.KEY_BRIGHTNESS, br_device, br_key)
  143. self.add_routing(self.KEY_COLOR_TEMP, ct_device, ct_key)
  144. #
  145. self.__tx_capabilities__()
  146. class videv_heating(base):
  147. KEY_USER_TEMPERATURE_SETPOINT = 'user_temperature_setpoint'
  148. KEY_VALVE_TEMPERATURE_SETPOINT = 'valve_temperature_setpoint'
  149. KEY_AWAY_MODE = 'away_mode'
  150. KEY_SUMMER_MODE = 'summer_mode'
  151. KEY_START_BOOST = 'start_boost'
  152. KEY_SET_DEFAULT_TEMPERATURE = 'set_default_temperature'
  153. KEY_BOOST_TIMER = 'boost_timer'
  154. #
  155. KEY_TEMPERATURE = 'temperature'
  156. def __init__(self, mqtt_client, topic, heating_function):
  157. super().__init__(mqtt_client, topic)
  158. #
  159. self.add_routing(self.KEY_USER_TEMPERATURE_SETPOINT, heating_function, heating_function.KEY_USER_TEMPERATURE_SETPOINT)
  160. self.add_routing(self.KEY_AWAY_MODE, heating_function, heating_function.KEY_AWAY_MODE)
  161. self.add_routing(self.KEY_SUMMER_MODE, heating_function, heating_function.KEY_SUMMER_MODE)
  162. #
  163. self.add_control(self.KEY_START_BOOST, heating_function, heating_function.KEY_START_BOOST, False)
  164. self.add_control(self.KEY_SET_DEFAULT_TEMPERATURE, heating_function, heating_function.KEY_SET_DEFAULT_TEMPERATURE, False)
  165. #
  166. self.add_display(self.KEY_VALVE_TEMPERATURE_SETPOINT, heating_function, heating_function.KEY_TEMPERATURE_SETPOINT)
  167. self.add_display(self.KEY_BOOST_TIMER, heating_function, heating_function.KEY_BOOST_TIMER)
  168. self.add_display(self.KEY_TEMPERATURE, heating_function, heating_function.KEY_TEMPERATURE_CURRENT)
  169. #
  170. self.__tx_capabilities__()
  171. class videv_multistate(base):
  172. KEY_STATE = 'state_%d'
  173. def __init__(self, mqtt_client, topic, key_for_device, device, num_states, default_values=None):
  174. super().__init__(mqtt_client, topic)
  175. self.num_states = num_states
  176. # send default values
  177. for i in range(0, num_states):
  178. self.__tx__(self.KEY_STATE % i, False)
  179. #
  180. device.add_callback(key_for_device, None, self.__index_rx__, True)
  181. #
  182. self.__tx_capabilities__()
  183. def __index_rx__(self, device, key, data):
  184. for i in range(0, self.num_states):
  185. self.__tx__(self.KEY_STATE % i, i == data)
  186. #
  187. self.__tx_capabilities__()
  188. class videv_audio_player(base):
  189. KEY_ACTIVE_PLAYER = 'player_%d'
  190. KEY_TITLE = 'title'
  191. NO_TITLE = '---'
  192. def __init__(self, mqtt_client, topic, *args):
  193. super().__init__(mqtt_client, topic)
  194. for i, device in enumerate(args):
  195. self.add_display(self.KEY_ACTIVE_PLAYER % i, device, device.KEY_STATE)
  196. #
  197. for audio_device in args:
  198. audio_device.add_callback(audio_device.KEY_TITLE, None, self.__title_rx__, True)
  199. #
  200. self.__tx_capabilities__()
  201. def __title_rx__(self, device, key, data):
  202. self.__tx__(self.KEY_TITLE, data or self.NO_TITLE)
  203. @property
  204. def capabilities(self):
  205. super().capabilities
  206. self.__capabilities__[self.KEY_TITLE] = {'display': True}
  207. return self.__capabilities__