Assistants.dog_water
Ассистент контроля миски с водой для собаки.
Включает подогрев миски (через розетку) при понижении температуры окружающего воздуха ниже заданного порога.
1""" 2Ассистент контроля миски с водой для собаки. 3 4Включает подогрев миски (через розетку) при понижении температуры 5окружающего воздуха ниже заданного порога. 6""" 7 8import time 9from langfuse.decorators import observe 10from loguru import logger 11 12from Assistants import Assistant 13from DataSources import OpenWeatherDataSource 14from Controllers import SmartPlugController 15from Messengers.bot import Bot 16 17 18class DogWaterAssistant(Assistant): 19 """Контролирует подогрев воды в миске для собаки. 20 21 Получает текущую температуру воздуха через OpenWeather и 22 включает/выключает розетку с подогревом миски в зависимости 23 от порога температуры. 24 25 Attributes: 26 smart_plug: Контроллер розетки для подогрева. 27 openweather: Источник данных о погоде. 28 temp_threshold: Порог температуры для включения подогрева. 29 bot: Бот для отправки уведомлений. 30 """ 31 32 def __init__( 33 self, 34 name: str, 35 smart_plug: SmartPlugController, 36 openweather: OpenWeatherDataSource, 37 temp_threshold, 38 bot: Bot = None, 39 ): 40 """Инициализирует ассистента контроля миски с водой. 41 42 Args: 43 name: Имя ассистента. 44 smart_plug: Контроллер розетки для подогрева. 45 openweather: Источник данных о погоде. 46 temp_threshold: Порог температуры для включения подогрева. 47 bot: Бот для отправки уведомлений. 48 """ 49 super().__init__(name) 50 51 self.smart_plug = smart_plug 52 self.openweather = openweather 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 Получает текущую температуру через OpenWeather, сравнивает 103 с порогом и при необходимости включает или выключает розетку. 104 105 Returns: 106 bool: True если цикл выполнен успешно, False при ошибке. 107 """ 108 logger.debug(f'Запуск цикла контроля температуры для "{self.name}"...') 109 110 # Получаем текущую температуру 111 temperature = self.openweather.get_current_temperature() 112 113 if temperature is None: 114 logger.error(f'Не удалось получить температуру, пропускаем цикл "{self.name}"') 115 return False 116 117 # Определяем нужное действие 118 should_turn_on = temperature <= self.temp_threshold 119 120 state = self.smart_plug.get_state() 121 if state is None: 122 logger.error(f'Не удалось получить состояние розетки, пропускаем цикл "{self.name}"') 123 return False 124 if state["power"] != should_turn_on: 125 success = self.smart_plug.control_plug(should_turn_on) 126 if not success: 127 logger.error(f'Цикл "{self.name}" завершен с ошибкой управления розеткой') 128 return success 129 state = self.get_state() 130 logger.info( 131 f"Температура {temperature}°C (порог: {self.temp_threshold}°C). " 132 + str(self.smart_plug) 133 ) 134 if self.bot: 135 self.bot.send_message( 136 text=f"Температура {temperature}°C (порог: {self.temp_threshold}°C). " 137 + str(self.smart_plug) 138 ) 139 140 logger.debug( 141 f'Цикл "{self.name}" завершен: температура {temperature}°C (порог: {self.temp_threshold}°C). ' 142 + str(self.smart_plug) 143 ) 144 145 return True
19class DogWaterAssistant(Assistant): 20 """Контролирует подогрев воды в миске для собаки. 21 22 Получает текущую температуру воздуха через OpenWeather и 23 включает/выключает розетку с подогревом миски в зависимости 24 от порога температуры. 25 26 Attributes: 27 smart_plug: Контроллер розетки для подогрева. 28 openweather: Источник данных о погоде. 29 temp_threshold: Порог температуры для включения подогрева. 30 bot: Бот для отправки уведомлений. 31 """ 32 33 def __init__( 34 self, 35 name: str, 36 smart_plug: SmartPlugController, 37 openweather: OpenWeatherDataSource, 38 temp_threshold, 39 bot: Bot = None, 40 ): 41 """Инициализирует ассистента контроля миски с водой. 42 43 Args: 44 name: Имя ассистента. 45 smart_plug: Контроллер розетки для подогрева. 46 openweather: Источник данных о погоде. 47 temp_threshold: Порог температуры для включения подогрева. 48 bot: Бот для отправки уведомлений. 49 """ 50 super().__init__(name) 51 52 self.smart_plug = smart_plug 53 self.openweather = openweather 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 Получает текущую температуру через OpenWeather, сравнивает 104 с порогом и при необходимости включает или выключает розетку. 105 106 Returns: 107 bool: True если цикл выполнен успешно, False при ошибке. 108 """ 109 logger.debug(f'Запуск цикла контроля температуры для "{self.name}"...') 110 111 # Получаем текущую температуру 112 temperature = self.openweather.get_current_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
Контролирует подогрев воды в миске для собаки.
Получает текущую температуру воздуха через OpenWeather и включает/выключает розетку с подогревом миски в зависимости от порога температуры.
Attributes: smart_plug: Контроллер розетки для подогрева. openweather: Источник данных о погоде. temp_threshold: Порог температуры для включения подогрева. bot: Бот для отправки уведомлений.
33 def __init__( 34 self, 35 name: str, 36 smart_plug: SmartPlugController, 37 openweather: OpenWeatherDataSource, 38 temp_threshold, 39 bot: Bot = None, 40 ): 41 """Инициализирует ассистента контроля миски с водой. 42 43 Args: 44 name: Имя ассистента. 45 smart_plug: Контроллер розетки для подогрева. 46 openweather: Источник данных о погоде. 47 temp_threshold: Порог температуры для включения подогрева. 48 bot: Бот для отправки уведомлений. 49 """ 50 super().__init__(name) 51 52 self.smart_plug = smart_plug 53 self.openweather = openweather 54 self.temp_threshold = temp_threshold 55 self.bot = bot
Инициализирует ассистента контроля миски с водой.
Args: name: Имя ассистента. smart_plug: Контроллер розетки для подогрева. openweather: Источник данных о погоде. 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 Получает текущую температуру через OpenWeather, сравнивает 104 с порогом и при необходимости включает или выключает розетку. 105 106 Returns: 107 bool: True если цикл выполнен успешно, False при ошибке. 108 """ 109 logger.debug(f'Запуск цикла контроля температуры для "{self.name}"...') 110 111 # Получаем текущую температуру 112 temperature = self.openweather.get_current_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
Выполняет один цикл контроля подогрева миски.
Получает текущую температуру через OpenWeather, сравнивает с порогом и при необходимости включает или выключает розетку.
Returns: bool: True если цикл выполнен успешно, False при ошибке.