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