run

Главный цикл приложения e-house.

Инициализирует все компоненты (ассистенты, контроллеры, источники данных, мессенджеры) и запускает их в бесконечном цикле. Периодически проверяет изменения в конфигурационном файле и перезагружает компоненты при необходимости.

  1#!/usr/bin/env python3
  2"""
  3Главный цикл приложения e-house.
  4
  5Инициализирует все компоненты (ассистенты, контроллеры, источники данных,
  6мессенджеры) и запускает их в бесконечном цикле. Периодически проверяет
  7изменения в конфигурационном файле и перезагружает компоненты при
  8необходимости.
  9"""
 10
 11import copy
 12import os
 13import sys
 14import time
 15
 16from e_lib.assistants import LangfuseCleanerAssistant, ScheduledAssistant
 17from e_lib.config import Config
 18from e_lib.time_utils import format_time
 19from langfuse import observe
 20from loguru import logger
 21
 22from Assistants.climate import ClimateAssistant
 23from Assistants.dehumidifier import DehumidifierAssistant
 24from Assistants.dog_heater import DogHeaterAssistant
 25from Assistants.voltage import VoltageAssistant
 26from Controllers.climate import ClimateController
 27from Controllers.dehumidifier import DehumidifierController
 28from Messengers.telegram import TelegramBot, TelegramTimeouts
 29
 30config = Config("configs/config.yml")
 31
 32from Assistants import DogWaterAssistant
 33from Controllers.smart_plug import SmartPlugController
 34from DataSources.openweather import OpenWeatherDataSource
 35
 36
 37APP_VERSION = os.getenv("PRODUCTS_VERSION", "dev")
 38
 39
 40def stop_all(assistants):
 41    """Останавливает всех ассистентов.
 42
 43    Вызывает метод stop() у каждого ассистента в обратном порядке.
 44
 45    Args:
 46        assistants: Список ассистентов для остановки.
 47    """
 48    for assistant in reversed(assistants):
 49        if hasattr(assistant, "stop") and callable(assistant.stop):
 50            assistant.stop()
 51
 52
 53def start_all(assistants):
 54    """Запускает всех ассистентов.
 55
 56    Вызывает метод start() у каждого ассистента.
 57
 58    Args:
 59        assistants: Список ассистентов для запуска.
 60    """
 61    for assistant in assistants:
 62        if hasattr(assistant, "start") and callable(assistant.start):
 63            assistant.start()
 64
 65
 66def init_logger():
 67    """Инициализация логгера"""
 68
 69    logger.remove()  # удаляем стандартный обработчик
 70    # Добавляем обработчик с поддержкой UTF-8
 71    logger.add(
 72        sys.stderr,
 73        level=config.data["General"]["Logger"]["Level"],
 74        #    format="{time:YYYY-MM-DD HH:mm:ss} - {level} - {name} - {message}",
 75        colorize=True,
 76    )
 77
 78    logger.debug("Логгер инициализирован")
 79
 80
 81@observe(name="Инициализация компонентов")
 82def init_components():
 83    """Инициализация компонентов"""
 84    init_logger()
 85
 86    assistants = []
 87    bot = None
 88
 89    if config.data["Messengers"]["Telegram"]["ENABLED"]:
 90        telegram_bot = TelegramBot(
 91            config.data["Messengers"]["Telegram"]["NAME"],
 92            os.getenv("TELEGRAM_TOKEN"),
 93            config.data["Messengers"]["Telegram"]["CHAT_ID"],
 94            TelegramTimeouts(
 95                config.data["Messengers"]["Telegram"]["TIMEOUTS"]["REQUEST"],
 96                config.data["Messengers"]["Telegram"]["TIMEOUTS"]["POLLING"],
 97            ),
 98        )
 99        assistants.append(telegram_bot)
100        bot = telegram_bot
101        logger.info(
102            f'Мессенджер "{config.data["Messengers"]["Telegram"]["NAME"]}" включен'
103        )
104
105    # Initialize devices and data sources
106    smart_plug = SmartPlugController(
107        config.data["Devices"]["SmartPlug"]["DEVICE_ID"],
108        os.getenv("YANDEX_TOKEN"),
109        round_digits=(
110            config.data.get("Devices", {})
111            .get("SmartPlug", {})
112            .get("VOLTAGE_ROUNDING", 0),
113            config.data.get("Devices", {})
114            .get("SmartPlug", {})
115            .get("AMPERAGE_ROUNDING", 0),
116            config.data.get("Devices", {})
117            .get("SmartPlug", {})
118            .get("CONSUMPTION_ROUNDING", 0),
119        ),
120        state_retry_count=config.data.get("Devices", {})
121        .get("SmartPlug", {})
122        .get("STATE_RETRY_COUNT", 3),
123        state_retry_delay=config.data.get("Devices", {})
124        .get("SmartPlug", {})
125        .get("STATE_RETRY_DELAY", 2),
126    )
127    openweather = OpenWeatherDataSource(
128        os.getenv("OPENWEATHER_API_KEY"), config.data["OpenWeather"]["CITY"]
129    )
130
131    temp_controller = ClimateController(
132        config.data["Devices"]["ClimateSensor"]["DEVICE_ID"],
133        os.getenv("YANDEX_TOKEN"),
134        round_digits=(
135            config.data.get("Devices", {}).get("ClimateSensor", {}).get("ROUNDING", 0),
136        ),
137        state_retry_count=config.data.get("Devices", {})
138        .get("ClimateSensor", {})
139        .get("STATE_RETRY_COUNT", 3),
140        state_retry_delay=config.data.get("Devices", {})
141        .get("ClimateSensor", {})
142        .get("STATE_RETRY_DELAY", 2),
143    )
144
145    dog_climate = ClimateController(
146        config.data["Devices"]["DogClimateSensor"]["DEVICE_ID"],
147        os.getenv("YANDEX_TOKEN"),
148        round_digits=(
149            config.data.get("Devices", {})
150            .get("DogClimateSensor", {})
151            .get("ROUNDING", 0),
152        ),
153        state_retry_count=config.data.get("Devices", {})
154        .get("DogClimateSensor", {})
155        .get("STATE_RETRY_COUNT", 3),
156        state_retry_delay=config.data.get("Devices", {})
157        .get("DogClimateSensor", {})
158        .get("STATE_RETRY_DELAY", 2),
159    )
160
161    dehumidifier = DehumidifierController(
162        config.data["Devices"]["Dehumidifier"]["DEVICE_ID"],
163        os.getenv("YANDEX_TOKEN"),
164        state_retry_count=config.data.get("Devices", {})
165        .get("Dehumidifier", {})
166        .get("STATE_RETRY_COUNT", 3),
167        state_retry_delay=config.data.get("Devices", {})
168        .get("Dehumidifier", {})
169        .get("STATE_RETRY_DELAY", 2),
170    )
171
172    # Initialize assistants based on config
173    if config.data["Assistants"]["DogWater"]["ENABLED"]:
174        dog_water = DogWaterAssistant(
175            config.data["Assistants"]["DogWater"]["NAME"],
176            smart_plug,
177            openweather,
178            config.data["Assistants"]["DogWater"]["TEMP_THRESHOLD"],
179            bot,
180        )
181        dog_water_scheduler = ScheduledAssistant(
182            dog_water,
183            config.data["Assistants"]["DogWater"]["CHECK_INTERVAL"],
184            logger=logger,
185        )
186        assistants.append(dog_water_scheduler)
187        logger.info(
188            f'Ассистент "{config.data["Assistants"]["DogWater"]["NAME"]}" включен'
189        )
190
191    if config.data["Assistants"]["Voltage"]["ENABLED"]:
192        voltage = VoltageAssistant(
193            config.data["Assistants"]["Voltage"]["NAME"],
194            smart_plug,
195            config.data.get("Assistants", {})
196            .get("Voltage", {})
197            .get("VOLTAGE_THRESHOLD_LOW", 200),
198            config.data.get("Assistants", {})
199            .get("Voltage", {})
200            .get("VOLTAGE_THRESHOLD_HIGH", 250),
201            config.data.get("Assistants", {})
202            .get("Voltage", {})
203            .get("VOLTAGE_ROUNDING", 0),
204            bot,
205        )
206        voltage_scheduler = ScheduledAssistant(
207            voltage,
208            config.data["Assistants"]["Voltage"]["CHECK_INTERVAL"],
209            logger=logger,
210        )
211        assistants.append(voltage_scheduler)
212        logger.info(
213            f'Ассистент "{config.data["Assistants"]["Voltage"]["NAME"]}" включен'
214        )
215
216    if config.data["Assistants"]["Temperature"]["ENABLED"]:
217        temperature = ClimateAssistant(
218            config.data["Assistants"]["Temperature"]["NAME"],
219            temp_controller,
220            config.data.get("Assistants", {})
221            .get("Temperature", {})
222            .get("TEMP_THRESHOLD_LOW", 23),
223            config.data.get("Assistants", {})
224            .get("Temperature", {})
225            .get("TEMP_THRESHOLD_HIGH", 25),
226            config.data.get("Assistants", {})
227            .get("Temperature", {})
228            .get("HUMIDITY_THRESHOLD_LOW", 25),
229            config.data.get("Assistants", {})
230            .get("Temperature", {})
231            .get("HUMIDITY_THRESHOLD_HIGH", 50),
232            config.data.get("Assistants", {}).get("Temperature", {}).get("ROUNDING", 0),
233            bot,
234        )
235        temp_scheduler = ScheduledAssistant(
236            temperature,
237            config.data["Assistants"]["Temperature"]["CHECK_INTERVAL"],
238            logger=logger,
239        )
240        assistants.append(temp_scheduler)
241        logger.info(
242            f'Ассистент "{config.data["Assistants"]["Temperature"]["NAME"]}" включен'
243        )
244
245    if config.data["Assistants"]["LangfuseCleaner"]["ENABLED"]:
246        lf_cleaner = LangfuseCleanerAssistant(
247            project_slug="e-house",
248            period=config.data.get("Assistants", {})
249            .get("LangfuseCleaner", {})
250            .get("CLEAN_PERIOD", 1),
251            logger=logger,
252        )
253        lf_cleaner_scheduler = ScheduledAssistant(
254            lf_cleaner,
255            config.data.get("Assistants", {})
256            .get("LangfuseCleaner", {})
257            .get("SCHEDULE_INTERVAL", 60),
258        )
259        assistants.append(lf_cleaner_scheduler)
260        logger.info(
261            f'Ассистент "{config.data["Assistants"]["LangfuseCleaner"]["NAME"]}" включен'
262        )
263
264    if config.data["Assistants"]["DogHeater"]["ENABLED"]:
265        dog_heater = DogHeaterAssistant(
266            config.data["Assistants"]["DogHeater"]["NAME"],
267            smart_plug,
268            dog_climate,
269            config.data["Assistants"]["DogHeater"]["TEMP_THRESHOLD"],
270            bot,
271        )
272        dog_heater_scheduler = ScheduledAssistant(
273            dog_heater,
274            config.data["Assistants"]["DogHeater"]["CHECK_INTERVAL"],
275            logger=logger,
276        )
277        assistants.append(dog_heater_scheduler)
278        logger.info(
279            f'Ассистент "{config.data["Assistants"]["DogHeater"]["NAME"]}" включен'
280        )
281
282    if config.data["Assistants"]["Dehumidifier"]["ENABLED"]:
283        dehumidifier_assistant = DehumidifierAssistant(
284            config.data["Assistants"]["Dehumidifier"]["NAME"],
285            dehumidifier,
286            config.data["Assistants"]["Dehumidifier"]["HUMIDITY_THRESHOLD_HIGH"],
287            config.data["Assistants"]["Dehumidifier"].get("HUMIDITY_THRESHOLD_LOW", 50),
288            bot,
289        )
290        dehumidifier_scheduler = ScheduledAssistant(
291            dehumidifier_assistant,
292            config.data["Assistants"]["Dehumidifier"]["CHECK_INTERVAL"],
293            logger=logger,
294        )
295        assistants.append(dehumidifier_scheduler)
296        logger.info(
297            f'Ассистент "{config.data["Assistants"]["Dehumidifier"]["NAME"]}" включен'
298        )
299
300    return assistants
301
302
303def main():
304    """Основная функция приложения.
305
306    Инициализирует компоненты, запускает их и входит в бесконечный цикл.
307    В цикле проверяет изменения конфигурации и при необходимости
308    перезагружает ассистентов. Обрабатывает KeyboardInterrupt и
309    неожиданные ошибки.
310    """
311
312    products_log = None
313    try:
314        from e_lib.product_log import ProductsLog
315
316        products_log = ProductsLog("e-house", APP_VERSION, logger=logger)
317        products_log.post_started()
318    except Exception as e:
319        logger.warning(f"ProductsLog: {e}")
320
321    assistants = []
322    try:
323        logger.info(
324            "Интервал перезагрузки config.yml: "
325            + format_time(config.data["General"]["RELOAD_TIMEOUT"])
326        )
327        assistants = init_components()
328        start_all(assistants)
329
330        # tracer.end_span(span)
331        # tracer.flush()
332
333        while True:
334            old_config = copy.deepcopy(config.data)
335            config.load()
336            if config.data != old_config:
337                try:
338                    stop_all(assistants)
339                    new_assistants = init_components()
340                    start_all(new_assistants)
341                except (OSError, RuntimeError, ValueError, KeyError, TypeError) as err:
342                    logger.error(
343                        f"Не удалось перезапустить ассистентов: {err}", exc_info=True
344                    )
345                    start_all(assistants)
346                    time.sleep(config.data["General"]["RELOAD_TIMEOUT"])
347                    continue
348                assistants = new_assistants
349                logger.debug("config.yml изменен, перезагружен")
350            time.sleep(config.data["General"]["RELOAD_TIMEOUT"])
351
352    except KeyboardInterrupt:
353        stop_all(assistants)
354        logger.info("Работа скрипта остановлена пользователем")
355        try:
356            if products_log:
357                products_log.post_shutdown()
358        except Exception as e:
359            logger.warning(f"ProductsLog: {e}")
360    except (OSError, RuntimeError, ValueError, KeyError, TypeError) as e:
361        logger.error(f"Неожиданная ошибка: {e}")
362
363
364if __name__ == "__main__":
365    main()
config = <e_lib.config.Config object>
APP_VERSION = 'dev'
def stop_all(assistants):
41def stop_all(assistants):
42    """Останавливает всех ассистентов.
43
44    Вызывает метод stop() у каждого ассистента в обратном порядке.
45
46    Args:
47        assistants: Список ассистентов для остановки.
48    """
49    for assistant in reversed(assistants):
50        if hasattr(assistant, "stop") and callable(assistant.stop):
51            assistant.stop()

Останавливает всех ассистентов.

Вызывает метод stop() у каждого ассистента в обратном порядке.

Args: assistants: Список ассистентов для остановки.

def start_all(assistants):
54def start_all(assistants):
55    """Запускает всех ассистентов.
56
57    Вызывает метод start() у каждого ассистента.
58
59    Args:
60        assistants: Список ассистентов для запуска.
61    """
62    for assistant in assistants:
63        if hasattr(assistant, "start") and callable(assistant.start):
64            assistant.start()

Запускает всех ассистентов.

Вызывает метод start() у каждого ассистента.

Args: assistants: Список ассистентов для запуска.

def init_logger():
67def init_logger():
68    """Инициализация логгера"""
69
70    logger.remove()  # удаляем стандартный обработчик
71    # Добавляем обработчик с поддержкой UTF-8
72    logger.add(
73        sys.stderr,
74        level=config.data["General"]["Logger"]["Level"],
75        #    format="{time:YYYY-MM-DD HH:mm:ss} - {level} - {name} - {message}",
76        colorize=True,
77    )
78
79    logger.debug("Логгер инициализирован")

Инициализация логгера

@observe(name='Инициализация компонентов')
def init_components():
 82@observe(name="Инициализация компонентов")
 83def init_components():
 84    """Инициализация компонентов"""
 85    init_logger()
 86
 87    assistants = []
 88    bot = None
 89
 90    if config.data["Messengers"]["Telegram"]["ENABLED"]:
 91        telegram_bot = TelegramBot(
 92            config.data["Messengers"]["Telegram"]["NAME"],
 93            os.getenv("TELEGRAM_TOKEN"),
 94            config.data["Messengers"]["Telegram"]["CHAT_ID"],
 95            TelegramTimeouts(
 96                config.data["Messengers"]["Telegram"]["TIMEOUTS"]["REQUEST"],
 97                config.data["Messengers"]["Telegram"]["TIMEOUTS"]["POLLING"],
 98            ),
 99        )
100        assistants.append(telegram_bot)
101        bot = telegram_bot
102        logger.info(
103            f'Мессенджер "{config.data["Messengers"]["Telegram"]["NAME"]}" включен'
104        )
105
106    # Initialize devices and data sources
107    smart_plug = SmartPlugController(
108        config.data["Devices"]["SmartPlug"]["DEVICE_ID"],
109        os.getenv("YANDEX_TOKEN"),
110        round_digits=(
111            config.data.get("Devices", {})
112            .get("SmartPlug", {})
113            .get("VOLTAGE_ROUNDING", 0),
114            config.data.get("Devices", {})
115            .get("SmartPlug", {})
116            .get("AMPERAGE_ROUNDING", 0),
117            config.data.get("Devices", {})
118            .get("SmartPlug", {})
119            .get("CONSUMPTION_ROUNDING", 0),
120        ),
121        state_retry_count=config.data.get("Devices", {})
122        .get("SmartPlug", {})
123        .get("STATE_RETRY_COUNT", 3),
124        state_retry_delay=config.data.get("Devices", {})
125        .get("SmartPlug", {})
126        .get("STATE_RETRY_DELAY", 2),
127    )
128    openweather = OpenWeatherDataSource(
129        os.getenv("OPENWEATHER_API_KEY"), config.data["OpenWeather"]["CITY"]
130    )
131
132    temp_controller = ClimateController(
133        config.data["Devices"]["ClimateSensor"]["DEVICE_ID"],
134        os.getenv("YANDEX_TOKEN"),
135        round_digits=(
136            config.data.get("Devices", {}).get("ClimateSensor", {}).get("ROUNDING", 0),
137        ),
138        state_retry_count=config.data.get("Devices", {})
139        .get("ClimateSensor", {})
140        .get("STATE_RETRY_COUNT", 3),
141        state_retry_delay=config.data.get("Devices", {})
142        .get("ClimateSensor", {})
143        .get("STATE_RETRY_DELAY", 2),
144    )
145
146    dog_climate = ClimateController(
147        config.data["Devices"]["DogClimateSensor"]["DEVICE_ID"],
148        os.getenv("YANDEX_TOKEN"),
149        round_digits=(
150            config.data.get("Devices", {})
151            .get("DogClimateSensor", {})
152            .get("ROUNDING", 0),
153        ),
154        state_retry_count=config.data.get("Devices", {})
155        .get("DogClimateSensor", {})
156        .get("STATE_RETRY_COUNT", 3),
157        state_retry_delay=config.data.get("Devices", {})
158        .get("DogClimateSensor", {})
159        .get("STATE_RETRY_DELAY", 2),
160    )
161
162    dehumidifier = DehumidifierController(
163        config.data["Devices"]["Dehumidifier"]["DEVICE_ID"],
164        os.getenv("YANDEX_TOKEN"),
165        state_retry_count=config.data.get("Devices", {})
166        .get("Dehumidifier", {})
167        .get("STATE_RETRY_COUNT", 3),
168        state_retry_delay=config.data.get("Devices", {})
169        .get("Dehumidifier", {})
170        .get("STATE_RETRY_DELAY", 2),
171    )
172
173    # Initialize assistants based on config
174    if config.data["Assistants"]["DogWater"]["ENABLED"]:
175        dog_water = DogWaterAssistant(
176            config.data["Assistants"]["DogWater"]["NAME"],
177            smart_plug,
178            openweather,
179            config.data["Assistants"]["DogWater"]["TEMP_THRESHOLD"],
180            bot,
181        )
182        dog_water_scheduler = ScheduledAssistant(
183            dog_water,
184            config.data["Assistants"]["DogWater"]["CHECK_INTERVAL"],
185            logger=logger,
186        )
187        assistants.append(dog_water_scheduler)
188        logger.info(
189            f'Ассистент "{config.data["Assistants"]["DogWater"]["NAME"]}" включен'
190        )
191
192    if config.data["Assistants"]["Voltage"]["ENABLED"]:
193        voltage = VoltageAssistant(
194            config.data["Assistants"]["Voltage"]["NAME"],
195            smart_plug,
196            config.data.get("Assistants", {})
197            .get("Voltage", {})
198            .get("VOLTAGE_THRESHOLD_LOW", 200),
199            config.data.get("Assistants", {})
200            .get("Voltage", {})
201            .get("VOLTAGE_THRESHOLD_HIGH", 250),
202            config.data.get("Assistants", {})
203            .get("Voltage", {})
204            .get("VOLTAGE_ROUNDING", 0),
205            bot,
206        )
207        voltage_scheduler = ScheduledAssistant(
208            voltage,
209            config.data["Assistants"]["Voltage"]["CHECK_INTERVAL"],
210            logger=logger,
211        )
212        assistants.append(voltage_scheduler)
213        logger.info(
214            f'Ассистент "{config.data["Assistants"]["Voltage"]["NAME"]}" включен'
215        )
216
217    if config.data["Assistants"]["Temperature"]["ENABLED"]:
218        temperature = ClimateAssistant(
219            config.data["Assistants"]["Temperature"]["NAME"],
220            temp_controller,
221            config.data.get("Assistants", {})
222            .get("Temperature", {})
223            .get("TEMP_THRESHOLD_LOW", 23),
224            config.data.get("Assistants", {})
225            .get("Temperature", {})
226            .get("TEMP_THRESHOLD_HIGH", 25),
227            config.data.get("Assistants", {})
228            .get("Temperature", {})
229            .get("HUMIDITY_THRESHOLD_LOW", 25),
230            config.data.get("Assistants", {})
231            .get("Temperature", {})
232            .get("HUMIDITY_THRESHOLD_HIGH", 50),
233            config.data.get("Assistants", {}).get("Temperature", {}).get("ROUNDING", 0),
234            bot,
235        )
236        temp_scheduler = ScheduledAssistant(
237            temperature,
238            config.data["Assistants"]["Temperature"]["CHECK_INTERVAL"],
239            logger=logger,
240        )
241        assistants.append(temp_scheduler)
242        logger.info(
243            f'Ассистент "{config.data["Assistants"]["Temperature"]["NAME"]}" включен'
244        )
245
246    if config.data["Assistants"]["LangfuseCleaner"]["ENABLED"]:
247        lf_cleaner = LangfuseCleanerAssistant(
248            project_slug="e-house",
249            period=config.data.get("Assistants", {})
250            .get("LangfuseCleaner", {})
251            .get("CLEAN_PERIOD", 1),
252            logger=logger,
253        )
254        lf_cleaner_scheduler = ScheduledAssistant(
255            lf_cleaner,
256            config.data.get("Assistants", {})
257            .get("LangfuseCleaner", {})
258            .get("SCHEDULE_INTERVAL", 60),
259        )
260        assistants.append(lf_cleaner_scheduler)
261        logger.info(
262            f'Ассистент "{config.data["Assistants"]["LangfuseCleaner"]["NAME"]}" включен'
263        )
264
265    if config.data["Assistants"]["DogHeater"]["ENABLED"]:
266        dog_heater = DogHeaterAssistant(
267            config.data["Assistants"]["DogHeater"]["NAME"],
268            smart_plug,
269            dog_climate,
270            config.data["Assistants"]["DogHeater"]["TEMP_THRESHOLD"],
271            bot,
272        )
273        dog_heater_scheduler = ScheduledAssistant(
274            dog_heater,
275            config.data["Assistants"]["DogHeater"]["CHECK_INTERVAL"],
276            logger=logger,
277        )
278        assistants.append(dog_heater_scheduler)
279        logger.info(
280            f'Ассистент "{config.data["Assistants"]["DogHeater"]["NAME"]}" включен'
281        )
282
283    if config.data["Assistants"]["Dehumidifier"]["ENABLED"]:
284        dehumidifier_assistant = DehumidifierAssistant(
285            config.data["Assistants"]["Dehumidifier"]["NAME"],
286            dehumidifier,
287            config.data["Assistants"]["Dehumidifier"]["HUMIDITY_THRESHOLD_HIGH"],
288            config.data["Assistants"]["Dehumidifier"].get("HUMIDITY_THRESHOLD_LOW", 50),
289            bot,
290        )
291        dehumidifier_scheduler = ScheduledAssistant(
292            dehumidifier_assistant,
293            config.data["Assistants"]["Dehumidifier"]["CHECK_INTERVAL"],
294            logger=logger,
295        )
296        assistants.append(dehumidifier_scheduler)
297        logger.info(
298            f'Ассистент "{config.data["Assistants"]["Dehumidifier"]["NAME"]}" включен'
299        )
300
301    return assistants

Инициализация компонентов

def main():
304def main():
305    """Основная функция приложения.
306
307    Инициализирует компоненты, запускает их и входит в бесконечный цикл.
308    В цикле проверяет изменения конфигурации и при необходимости
309    перезагружает ассистентов. Обрабатывает KeyboardInterrupt и
310    неожиданные ошибки.
311    """
312
313    products_log = None
314    try:
315        from e_lib.product_log import ProductsLog
316
317        products_log = ProductsLog("e-house", APP_VERSION, logger=logger)
318        products_log.post_started()
319    except Exception as e:
320        logger.warning(f"ProductsLog: {e}")
321
322    assistants = []
323    try:
324        logger.info(
325            "Интервал перезагрузки config.yml: "
326            + format_time(config.data["General"]["RELOAD_TIMEOUT"])
327        )
328        assistants = init_components()
329        start_all(assistants)
330
331        # tracer.end_span(span)
332        # tracer.flush()
333
334        while True:
335            old_config = copy.deepcopy(config.data)
336            config.load()
337            if config.data != old_config:
338                try:
339                    stop_all(assistants)
340                    new_assistants = init_components()
341                    start_all(new_assistants)
342                except (OSError, RuntimeError, ValueError, KeyError, TypeError) as err:
343                    logger.error(
344                        f"Не удалось перезапустить ассистентов: {err}", exc_info=True
345                    )
346                    start_all(assistants)
347                    time.sleep(config.data["General"]["RELOAD_TIMEOUT"])
348                    continue
349                assistants = new_assistants
350                logger.debug("config.yml изменен, перезагружен")
351            time.sleep(config.data["General"]["RELOAD_TIMEOUT"])
352
353    except KeyboardInterrupt:
354        stop_all(assistants)
355        logger.info("Работа скрипта остановлена пользователем")
356        try:
357            if products_log:
358                products_log.post_shutdown()
359        except Exception as e:
360            logger.warning(f"ProductsLog: {e}")
361    except (OSError, RuntimeError, ValueError, KeyError, TypeError) as e:
362        logger.error(f"Неожиданная ошибка: {e}")

Основная функция приложения.

Инициализирует компоненты, запускает их и входит в бесконечный цикл. В цикле проверяет изменения конфигурации и при необходимости перезагружает ассистентов. Обрабатывает KeyboardInterrupt и неожиданные ошибки.