Smarthome Functionen
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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