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

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

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

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