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

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

smart_plug
climate
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        Получает температуру из датчика в будке, сравнивает с порогом
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 при ошибке.