Smarthome Functionen
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

modules.py 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. """
  5. Functional Modules
  6. Targets:
  7. * Device like structure to be compatible with videv
  8. - KEY_* as part of the class for all parameters which needs to be accessed from videv
  9. - Method *.set(key, data) to pass data from videv to Module
  10. - Method .add_calback(key, data, callback, on_change_only=False) to register videv actualisation on changes
  11. """
  12. import config
  13. import devices
  14. from function.db import get_gui_radiator_data, set_gui_radiator_data
  15. from function.rooms import room_shelly
  16. import logging
  17. import task
  18. try:
  19. from config import APP_NAME as ROOT_LOGGER_NAME
  20. except ImportError:
  21. ROOT_LOGGER_NAME = 'root'
  22. logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__)
  23. class base(object):
  24. def set(key, data):
  25. pass
  26. def add_calback(self, key, data, callback, on_change_only=False):
  27. pass
  28. class brightness_choose_n_action(object):
  29. def __init__(self, mqtt_client, button_tradfri, topic_led):
  30. self.gui_led_active_device = devices.nodered_gui_leds(mqtt_client, topic_led)
  31. # brightness change
  32. button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION,
  33. devices.tradfri_button.ACTION_BRIGHTNESS_DOWN_LONG, self.brightness_action)
  34. button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_BRIGHTNESS_UP_LONG, self.brightness_action)
  35. button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION,
  36. devices.tradfri_button.ACTION_BRIGHTNESS_DOWN_RELEASE, self.brightness_action)
  37. button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION,
  38. devices.tradfri_button.ACTION_BRIGHTNESS_UP_RELEASE, self.brightness_action)
  39. # device change
  40. button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_BRIGHTNESS_UP, self.choose_next_device)
  41. button_tradfri.add_callback(devices.tradfri_button.KEY_ACTION, devices.tradfri_button.ACTION_BRIGHTNESS_DOWN, self.choose_prev_device)
  42. #
  43. self.brightness_device_list = []
  44. self.callback_device_list = []
  45. self.device_states = []
  46. self.active_device_state = None
  47. self.update_active_device_led()
  48. def add(self, brightness_device, callback_device, callback_key):
  49. """
  50. brightness_device: A device for brightness function needs to have the following methods:
  51. * .default_inc()
  52. * .default_dec()
  53. * .default_stop()
  54. callback_device: A device for installing callback which are executed, when the device is switched on or off. It needs the following method:
  55. * .add_callback(key, data or None, callback, on_changes_only)
  56. """
  57. if len(self.brightness_device_list) >= len(devices.nodered_gui_leds.KEY_LED_LIST):
  58. raise ValueError("Number of devices is limited by number of leds in devices.nodered_gui_leds.")
  59. self.brightness_device_list.append(brightness_device)
  60. self.callback_device_list.append((callback_device, callback_key))
  61. self.device_states.append(False)
  62. callback_device.add_callback(callback_key, True, self.device_state_action, True)
  63. callback_device.add_callback(callback_key, False, self.device_state_action, True)
  64. def device_state_action(self, device, key, data):
  65. self.device_states[self.callback_device_list.index((device, key))] = data
  66. if data is True:
  67. self.active_device_state = self.callback_device_list.index((device, key))
  68. self.update_active_device_led()
  69. else:
  70. self.choose_next_device()
  71. def update_active_device_led(self):
  72. for i in range(0, len(self.brightness_device_list)):
  73. self.gui_led_active_device.set_led(devices.nodered_gui_leds.KEY_LED_LIST[i], self.active_device_state == i)
  74. def choose_prev_device(self, device=None, key=None, data=None):
  75. if self.active_device_state is not None:
  76. start_value = self.active_device_state
  77. for i in range(0, len(self.brightness_device_list)):
  78. target_state = (start_value - i - 1) % (len(self.brightness_device_list))
  79. if self.device_states[target_state]:
  80. self.active_device_state = target_state
  81. self.update_active_device_led()
  82. return
  83. self.active_device_state = None
  84. self.update_active_device_led()
  85. def choose_next_device(self, device=None, key=None, data=None):
  86. if self.active_device_state is not None:
  87. start_value = self.active_device_state
  88. for i in range(0, len(self.brightness_device_list)):
  89. target_state = (start_value + i + 1) % (len(self.brightness_device_list))
  90. if self.device_states[target_state]:
  91. self.active_device_state = target_state
  92. self.update_active_device_led()
  93. return
  94. self.active_device_state = None
  95. self.update_active_device_led()
  96. def brightness_action(self, device, key, data):
  97. if self.active_device_state is not None:
  98. target = self.brightness_device_list[self.active_device_state]
  99. if data == devices.tradfri_button.ACTION_BRIGHTNESS_UP_LONG:
  100. logger.info("Increasing \"%s\" - %s", type(self).__name__, target.topic)
  101. target.default_inc()
  102. elif data == devices.tradfri_button.ACTION_BRIGHTNESS_DOWN_LONG:
  103. logger.info("Decreasing \"%s\" - %s", type(self).__name__, target.topic)
  104. target.default_dec()
  105. elif data in [devices.tradfri_button.ACTION_BRIGHTNESS_UP_RELEASE, devices.tradfri_button.ACTION_BRIGHTNESS_DOWN_RELEASE]:
  106. target.default_stop()
  107. class circulation_pump(room_shelly):
  108. def __init__(self, mqtt_client):
  109. super().__init__(mqtt_client, config.TOPIC_FFE_KITCHEN_CIRCULATION_PUMP_SHELLY, config.TOPIC_FFE_KITCHEN_CIRCULATION_PUMP_GUI)
  110. #
  111. self.main_light_shelly.add_callback(devices.shelly.KEY_OUTPUT_0, None, self.circ_pump_actions, True)
  112. #
  113. self.gui_main_light.set_timer('-')
  114. #
  115. self.ct = task.periodic(6, self.cyclic_task)
  116. self.pump_timer = None
  117. #
  118. self.ct.run()
  119. def circ_pump_actions(self, device, key, data):
  120. if data is True:
  121. self.pump_timer = 10
  122. self.gui_main_light.set_timer(self.pump_timer)
  123. else:
  124. self.pump_timer = None
  125. self.gui_main_light.set_timer('-')
  126. def cyclic_task(self, rt):
  127. if self.pump_timer is not None:
  128. if self.pump_timer <= 0:
  129. self.pump_timer = None
  130. self.gui_main_light.set_timer('-')
  131. else:
  132. self.gui_main_light.set_timer(self.pump_timer)
  133. self.pump_timer -= self.ct.cycle_time / 60
  134. class radiator_function(object):
  135. BOOST_TEMPERATURE = 30
  136. AWAY_REDUCTION = 5
  137. SUMMER_TEMPERATURE = 5
  138. def __init__(self, mqtt_client, topic_valve, topic_gui, default_temperature):
  139. self.default_temperature = default_temperature
  140. self.boost_timer = None
  141. # device initialisation
  142. self.heating_valve = devices.brennenstuhl_heatingvalve(mqtt_client, topic_valve)
  143. self.gui_heating = devices.nodered_gui_radiator(mqtt_client, topic_gui)
  144. # db-stored data initialisation
  145. db_data = get_gui_radiator_data(topic_gui)
  146. self.__away_mode__ = db_data[0] or False
  147. self.__summer_mode__ = db_data[1] or False
  148. self.__user_temperature_setpoint__ = db_data[2] or default_temperature
  149. if self.__away_mode__:
  150. self.away_mode(None, None, True)
  151. elif self.__summer_mode__:
  152. self.summer_mode(None, None, True)
  153. else:
  154. self.set_heating_setpoint(None, None, self.__user_temperature_setpoint__)
  155. # callback initialisation
  156. self.heating_valve.add_callback(devices.brennenstuhl_heatingvalve.KEY_TEMPERATURE, None, self.gui_heating.set_temperature_mcb)
  157. self.heating_valve.add_callback(devices.brennenstuhl_heatingvalve.KEY_HEATING_SETPOINT, None, self.get_radiator_setpoint)
  158. #
  159. self.gui_heating.add_callback(devices.nodered_gui_radiator.KEY_SETPOINT_TEMP, None, self.set_heating_setpoint)
  160. self.gui_heating.add_callback(devices.nodered_gui_radiator.KEY_BOOST, None, self.boost)
  161. self.gui_heating.add_callback(devices.nodered_gui_radiator.KEY_SETPOINT_TO_DEFAULT, None, self.setpoint_to_default)
  162. self.gui_heating.add_callback(devices.nodered_gui_radiator.KEY_AWAY, None, self.away_mode)
  163. self.gui_heating.add_callback(devices.nodered_gui_radiator.KEY_SUMMER, None, self.summer_mode)
  164. # cyclic task initialisation
  165. self.ct = task.periodic(1, self.cyclic_task)
  166. self.ct.run()
  167. def cyclic_task(self, rt):
  168. if self.boost_timer is not None:
  169. self.gui_heating.set_timer(round(self.boost_timer / 60, 1))
  170. #
  171. self.boost_timer -= self.ct.cycle_time
  172. if self.boost_timer <= 0:
  173. self.cancel_boost()
  174. self.heating_valve.set_heating_setpoint(self.__user_temperature_setpoint__)
  175. self.heating_valve.logger.info('Timer expired. returning to regular temperature setpoint %.1f°C.', self.__user_temperature_setpoint__)
  176. def cancel_boost(self, device=None, key=None, data=None):
  177. if self.boost_timer is not None:
  178. self.boost_timer = None
  179. self.gui_heating.set_timer('-')
  180. def update_states(self, away_mode=None, summer_mode=None, user_temperature_setpoint=None):
  181. if away_mode is not None:
  182. self.__away_mode__ = away_mode
  183. if summer_mode is not None:
  184. self.__summer_mode__ = summer_mode
  185. if user_temperature_setpoint is not None:
  186. self.__user_temperature_setpoint__ = user_temperature_setpoint
  187. set_gui_radiator_data(self.gui_heating.topic, self.__away_mode__, self.__summer_mode__, self.__user_temperature_setpoint__)
  188. #
  189. self.gui_heating.set_away(self.__away_mode__)
  190. self.gui_heating.set_summer(self.__summer_mode__)
  191. self.gui_heating.set_enable(not self.__away_mode__ and not self.__summer_mode__)
  192. def away_mode(self, device, key, value):
  193. if value is True:
  194. self.cancel_boost()
  195. self.update_states(away_mode=value, summer_mode=False)
  196. self.heating_valve.set_heating_setpoint(self.__user_temperature_setpoint__ - self.AWAY_REDUCTION)
  197. else:
  198. self.update_states(away_mode=value)
  199. self.heating_valve.set_heating_setpoint(self.__user_temperature_setpoint__)
  200. def summer_mode(self, device, key, value):
  201. if value is True:
  202. self.cancel_boost()
  203. self.update_states(away_mode=False, summer_mode=value)
  204. self.heating_valve.set_heating_setpoint(self.SUMMER_TEMPERATURE)
  205. else:
  206. self.update_states(summer_mode=value)
  207. self.heating_valve.set_heating_setpoint(self.__user_temperature_setpoint__)
  208. def boost(self, device, key, data):
  209. if self.boost_timer is None:
  210. self.heating_valve.logger.info('Starting boost mode with setpoint %.1f°C.', self.BOOST_TEMPERATURE)
  211. self.boost_timer = 15*60
  212. self.heating_valve.set_heating_setpoint(self.BOOST_TEMPERATURE)
  213. else:
  214. self.boost_timer += 15 * 60
  215. if self.boost_timer > 60 * 60:
  216. self.boost_timer = 60 * 60
  217. self.update_states(away_mode=False, summer_mode=False)
  218. def setpoint_to_default(self, device, key, data):
  219. self.set_heating_setpoint(device, key, self.default_temperature)
  220. def set_heating_setpoint(self, device, key, data):
  221. self.cancel_boost()
  222. self.update_states(away_mode=False, summer_mode=False, user_temperature_setpoint=data)
  223. self.heating_valve.set_heating_setpoint(data)
  224. def get_radiator_setpoint(self, device, key, data):
  225. if self.boost_timer is None and not self.__away_mode__ and not self.__summer_mode__:
  226. self.update_states(user_temperature_setpoint=data)
  227. else:
  228. self.update_states()
  229. self.gui_heating.set_setpoint_temperature(data)