Assistants.dog_heater
Ассистент контроля обогрева будки для собаки.
Включает обогрев будки (через розетку) при понижении температуры внутри будки ниже заданного порога.
1""" 2Ассистент контроля обогрева будки для собаки. 3 4Включает обогрев будки (через розетку) при понижении температуры 5внутри будки ниже заданного порога. 6""" 7 8import time 9from langfuse.decorators import observe 10from loguru import logger 11 12from Assistants import Assistant 13from Controllers.climate import ClimateController 14from DataSources import OpenWeatherDataSource 15from Controllers import SmartPlugController 16from Messengers.bot import Bot 17 18 19class DogHeaterAssistant(Assistant): 20 """Контролирует обогрев будки для собаки. 21 22 Получает температуру из датчика климата в будке и 23 включает/выключает обогреватель через розетку. 24 25 Attributes: 26 smart_plug: Контроллер розетки для обогревателя. 27 climate: Контроллер датчика температуры в будке. 28 temp_threshold: Порог температуры для включения обогрева. 29 bot: Бот для отправки уведомлений. 30 """ 31 32 def __init__( 33 self, 34 name: str, 35 smart_plug: SmartPlugController, 36 climate: ClimateController, 37 temp_threshold, 38 bot: Bot = None, 39 ): 40 """Инициализирует ассистента обогрева будки. 41 42 Args: 43 name: Имя ассистента. 44 smart_plug: Контроллер розетки для обогревателя. 45 climate: Контроллер датчика температуры в будке. 46 temp_threshold: Порог температуры для включения обогрева. 47 bot: Бот для отправки уведомлений. 48 """ 49 super().__init__(name) 50 51 self.smart_plug = smart_plug 52 self.climate = climate 53 self.temp_threshold = temp_threshold 54 self.bot = bot 55 56 @observe(name=f"Получение состояния {__qualname__}") 57 def get_state(self): 58 """Получает состояние розетки обогревателя с повторными попытками. 59 60 Проверяет консистентность состояния: включена — есть ток, 61 выключена — тока нет. 62 63 Returns: 64 dict: Состояние розетки или None при ошибке. 65 """ 66 retry_count = self.smart_plug.state_retry_count 67 retry_delay = self.smart_plug.state_retry_delay 68 69 for attempt in range(retry_count): 70 state = self.smart_plug.get_state() 71 if ( 72 state is not None 73 and state["power"] 74 and state.get("amperage") is not None 75 and state.get("amperage") > 0 76 ): 77 return state 78 if ( 79 state is not None 80 and not state["power"] 81 and state.get("amperage") is not None 82 and state.get("amperage") == 0 83 ): 84 return state 85 logger.debug(f"Попытка {attempt + 1} не удалась, повтор через {retry_delay} секунд...") 86 time.sleep(retry_delay) 87 if state is not None and state["power"]: 88 logger.warning( 89 "Розетка включена, но потребление тока отсутствует или недоступно после нескольких попыток." 90 ) 91 if state is not None and not state["power"]: 92 logger.warning( 93 "Розетка выключена, но потребление тока присутствует или недоступно после нескольких попыток." 94 ) 95 96 return state 97 98 @observe(name=f"Цикл контроля для {__qualname__}") 99 def run(self): 100 """Выполняет один цикл контроля обогрева будки. 101 102 Получает температуру из датчика в будке, сравнивает с порогом 103 и при необходимости включает или выключает обогреватель. 104 105 Returns: 106 bool: True если цикл выполнен успешно, False при ошибке. 107 """ 108 logger.debug(f'Запуск цикла контроля температуры для "{self.name}"...') 109 110 # Получаем текущую температуру 111 state = self.climate.get_state() 112 temperature = state["temperature"] 113 114 if temperature is None: 115 logger.error(f'Не удалось получить температуру, пропускаем цикл "{self.name}"') 116 return False 117 118 # Определяем нужное действие 119 should_turn_on = temperature <= self.temp_threshold 120 121 state = self.smart_plug.get_state() 122 if state is None: 123 logger.error(f'Не удалось получить состояние розетки, пропускаем цикл "{self.name}"') 124 return False 125 if state["power"] != should_turn_on: 126 success = self.smart_plug.control_plug(should_turn_on) 127 if not success: 128 logger.error(f'Цикл "{self.name}" завершен с ошибкой управления розеткой') 129 return success 130 state = self.get_state() 131 logger.info( 132 f"Температура {temperature}°C (порог: {self.temp_threshold}°C). " 133 + str(self.smart_plug) 134 ) 135 if self.bot: 136 self.bot.send_message( 137 text=f"Температура {temperature}°C (порог: {self.temp_threshold}°C). " 138 + str(self.smart_plug) 139 ) 140 141 logger.debug( 142 f'Цикл "{self.name}" завершен: температура {temperature}°C (порог: {self.temp_threshold}°C). ' 143 + str(self.smart_plug) 144 ) 145 146 return True
20class DogHeaterAssistant(Assistant): 21 """Контролирует обогрев будки для собаки. 22 23 Получает температуру из датчика климата в будке и 24 включает/выключает обогреватель через розетку. 25 26 Attributes: 27 smart_plug: Контроллер розетки для обогревателя. 28 climate: Контроллер датчика температуры в будке. 29 temp_threshold: Порог температуры для включения обогрева. 30 bot: Бот для отправки уведомлений. 31 """ 32 33 def __init__( 34 self, 35 name: str, 36 smart_plug: SmartPlugController, 37 climate: ClimateController, 38 temp_threshold, 39 bot: Bot = None, 40 ): 41 """Инициализирует ассистента обогрева будки. 42 43 Args: 44 name: Имя ассистента. 45 smart_plug: Контроллер розетки для обогревателя. 46 climate: Контроллер датчика температуры в будке. 47 temp_threshold: Порог температуры для включения обогрева. 48 bot: Бот для отправки уведомлений. 49 """ 50 super().__init__(name) 51 52 self.smart_plug = smart_plug 53 self.climate = climate 54 self.temp_threshold = temp_threshold 55 self.bot = bot 56 57 @observe(name=f"Получение состояния {__qualname__}") 58 def get_state(self): 59 """Получает состояние розетки обогревателя с повторными попытками. 60 61 Проверяет консистентность состояния: включена — есть ток, 62 выключена — тока нет. 63 64 Returns: 65 dict: Состояние розетки или None при ошибке. 66 """ 67 retry_count = self.smart_plug.state_retry_count 68 retry_delay = self.smart_plug.state_retry_delay 69 70 for attempt in range(retry_count): 71 state = self.smart_plug.get_state() 72 if ( 73 state is not None 74 and state["power"] 75 and state.get("amperage") is not None 76 and state.get("amperage") > 0 77 ): 78 return state 79 if ( 80 state is not None 81 and not state["power"] 82 and state.get("amperage") is not None 83 and state.get("amperage") == 0 84 ): 85 return state 86 logger.debug(f"Попытка {attempt + 1} не удалась, повтор через {retry_delay} секунд...") 87 time.sleep(retry_delay) 88 if state is not None and state["power"]: 89 logger.warning( 90 "Розетка включена, но потребление тока отсутствует или недоступно после нескольких попыток." 91 ) 92 if state is not None and not state["power"]: 93 logger.warning( 94 "Розетка выключена, но потребление тока присутствует или недоступно после нескольких попыток." 95 ) 96 97 return state 98 99 @observe(name=f"Цикл контроля для {__qualname__}") 100 def run(self): 101 """Выполняет один цикл контроля обогрева будки. 102 103 Получает температуру из датчика в будке, сравнивает с порогом 104 и при необходимости включает или выключает обогреватель. 105 106 Returns: 107 bool: True если цикл выполнен успешно, False при ошибке. 108 """ 109 logger.debug(f'Запуск цикла контроля температуры для "{self.name}"...') 110 111 # Получаем текущую температуру 112 state = self.climate.get_state() 113 temperature = state["temperature"] 114 115 if temperature is None: 116 logger.error(f'Не удалось получить температуру, пропускаем цикл "{self.name}"') 117 return False 118 119 # Определяем нужное действие 120 should_turn_on = temperature <= self.temp_threshold 121 122 state = self.smart_plug.get_state() 123 if state is None: 124 logger.error(f'Не удалось получить состояние розетки, пропускаем цикл "{self.name}"') 125 return False 126 if state["power"] != should_turn_on: 127 success = self.smart_plug.control_plug(should_turn_on) 128 if not success: 129 logger.error(f'Цикл "{self.name}" завершен с ошибкой управления розеткой') 130 return success 131 state = self.get_state() 132 logger.info( 133 f"Температура {temperature}°C (порог: {self.temp_threshold}°C). " 134 + str(self.smart_plug) 135 ) 136 if self.bot: 137 self.bot.send_message( 138 text=f"Температура {temperature}°C (порог: {self.temp_threshold}°C). " 139 + str(self.smart_plug) 140 ) 141 142 logger.debug( 143 f'Цикл "{self.name}" завершен: температура {temperature}°C (порог: {self.temp_threshold}°C). ' 144 + str(self.smart_plug) 145 ) 146 147 return True
Контролирует обогрев будки для собаки.
Получает температуру из датчика климата в будке и включает/выключает обогреватель через розетку.
Attributes: smart_plug: Контроллер розетки для обогревателя. climate: Контроллер датчика температуры в будке. temp_threshold: Порог температуры для включения обогрева. bot: Бот для отправки уведомлений.
33 def __init__( 34 self, 35 name: str, 36 smart_plug: SmartPlugController, 37 climate: ClimateController, 38 temp_threshold, 39 bot: Bot = None, 40 ): 41 """Инициализирует ассистента обогрева будки. 42 43 Args: 44 name: Имя ассистента. 45 smart_plug: Контроллер розетки для обогревателя. 46 climate: Контроллер датчика температуры в будке. 47 temp_threshold: Порог температуры для включения обогрева. 48 bot: Бот для отправки уведомлений. 49 """ 50 super().__init__(name) 51 52 self.smart_plug = smart_plug 53 self.climate = climate 54 self.temp_threshold = temp_threshold 55 self.bot = bot
Инициализирует ассистента обогрева будки.
Args: name: Имя ассистента. smart_plug: Контроллер розетки для обогревателя. climate: Контроллер датчика температуры в будке. temp_threshold: Порог температуры для включения обогрева. bot: Бот для отправки уведомлений.
57 @observe(name=f"Получение состояния {__qualname__}") 58 def get_state(self): 59 """Получает состояние розетки обогревателя с повторными попытками. 60 61 Проверяет консистентность состояния: включена — есть ток, 62 выключена — тока нет. 63 64 Returns: 65 dict: Состояние розетки или None при ошибке. 66 """ 67 retry_count = self.smart_plug.state_retry_count 68 retry_delay = self.smart_plug.state_retry_delay 69 70 for attempt in range(retry_count): 71 state = self.smart_plug.get_state() 72 if ( 73 state is not None 74 and state["power"] 75 and state.get("amperage") is not None 76 and state.get("amperage") > 0 77 ): 78 return state 79 if ( 80 state is not None 81 and not state["power"] 82 and state.get("amperage") is not None 83 and state.get("amperage") == 0 84 ): 85 return state 86 logger.debug(f"Попытка {attempt + 1} не удалась, повтор через {retry_delay} секунд...") 87 time.sleep(retry_delay) 88 if state is not None and state["power"]: 89 logger.warning( 90 "Розетка включена, но потребление тока отсутствует или недоступно после нескольких попыток." 91 ) 92 if state is not None and not state["power"]: 93 logger.warning( 94 "Розетка выключена, но потребление тока присутствует или недоступно после нескольких попыток." 95 ) 96 97 return state
Получает состояние розетки обогревателя с повторными попытками.
Проверяет консистентность состояния: включена — есть ток, выключена — тока нет.
Returns: dict: Состояние розетки или None при ошибке.
99 @observe(name=f"Цикл контроля для {__qualname__}") 100 def run(self): 101 """Выполняет один цикл контроля обогрева будки. 102 103 Получает температуру из датчика в будке, сравнивает с порогом 104 и при необходимости включает или выключает обогреватель. 105 106 Returns: 107 bool: True если цикл выполнен успешно, False при ошибке. 108 """ 109 logger.debug(f'Запуск цикла контроля температуры для "{self.name}"...') 110 111 # Получаем текущую температуру 112 state = self.climate.get_state() 113 temperature = state["temperature"] 114 115 if temperature is None: 116 logger.error(f'Не удалось получить температуру, пропускаем цикл "{self.name}"') 117 return False 118 119 # Определяем нужное действие 120 should_turn_on = temperature <= self.temp_threshold 121 122 state = self.smart_plug.get_state() 123 if state is None: 124 logger.error(f'Не удалось получить состояние розетки, пропускаем цикл "{self.name}"') 125 return False 126 if state["power"] != should_turn_on: 127 success = self.smart_plug.control_plug(should_turn_on) 128 if not success: 129 logger.error(f'Цикл "{self.name}" завершен с ошибкой управления розеткой') 130 return success 131 state = self.get_state() 132 logger.info( 133 f"Температура {temperature}°C (порог: {self.temp_threshold}°C). " 134 + str(self.smart_plug) 135 ) 136 if self.bot: 137 self.bot.send_message( 138 text=f"Температура {temperature}°C (порог: {self.temp_threshold}°C). " 139 + str(self.smart_plug) 140 ) 141 142 logger.debug( 143 f'Цикл "{self.name}" завершен: температура {temperature}°C (порог: {self.temp_threshold}°C). ' 144 + str(self.smart_plug) 145 ) 146 147 return True
Выполняет один цикл контроля обогрева будки.
Получает температуру из датчика в будке, сравнивает с порогом и при необходимости включает или выключает обогреватель.
Returns: bool: True если цикл выполнен успешно, False при ошибке.