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
class DogWaterAssistant(Assistants.assistant.Assistant):
 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: Бот для отправки уведомлений.

DogWaterAssistant( name: str, smart_plug: Controllers.smart_plug.SmartPlugController, openweather: DataSources.openweather.OpenWeatherDataSource, temp_threshold, bot: Messengers.bot.Bot = None)
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: Бот для отправки уведомлений.

smart_plug
openweather
temp_threshold
bot
@observe(name=f'Получение состояния {__qualname__}')
def get_state(self):
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 при ошибке.

@observe(name=f'Цикл контроля для {__qualname__}')
def run(self):
 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 при ошибке.