ГлавнаяАкадемияСценарии умного дома: режимы, состояния, приоритеты → SCN-CLIMATE-011: Интеграция с прогнозом погоды для управления отоплением/поливом

SCN-CLIMATE-011: Интеграция с прогнозом погоды для управления отоплением/поливом

Урок 5 · Сценарии умного дома: режимы, состояния, приоритеты · 30 мин · theory

Введение в проактивное управление климатом

В предыдущих уроках мы рассматривали преимущественно реактивные сценарии управления климатом. Система реагирует на уже произошедшие события: температура в комнате опустилась ниже уставки — включается отопление; концентрация CO2 превысила норму — запускается вентиляция. Такой подход эффективен для систем с малой инерционностью, но он не всегда оптимален с точки зрения комфорта и энергосбережения.

Проактивное (упреждающее) управление — это парадигма, в которой система автоматизации принимает решения на основе прогнозируемых, а не текущих данных. Вместо того чтобы ждать, пока в доме станет холодно из-за резкого похолодания на улице, система может начать прогрев заранее, опираясь на прогноз погоды.

Ключевые преимущества проактивного подхода:

  • Повышение комфорта: Система сглаживает резкие изменения микроклимата. Например, для систем с высокой инерционностью, таких как водяные теплые полы, время от включения до достижения комфортной температуры может составлять несколько часов. Проактивный подход позволяет начать прогрев заранее, чтобы к моменту похолодания пол уже был теплым.
  • Энергосбережение:
  • * Отопление: Зная, что днем ожидается солнечная погода и потепление, система может снизить интенсивность утреннего прогрева, позволяя "догреть" помещение естественным теплом от солнца.

    * Полив: Автоматическая отмена полива газона, если в ближайшие часы прогнозируется дождь, напрямую экономит воду и электроэнергию на работу насоса.

  • Оптимизация работы оборудования: Плавное, упреждающее управление снижает количество циклов включения/выключения дорогостоящего оборудования (котлов, чиллеров, насосов), что продлевает его срок службы.
  • Источники данных и ключевые параметры

    Для реализации проактивных сценариев необходим надежный источник данных о будущем состоянии окружающей среды. Таким источником являются API (Application Programming Interface) погодных сервисов.

    > 📋 Ключевые понятия:

    > * API (Application Programming Interface): Программный интерфейс, который позволяет одному приложению (в нашем случае, Node-RED на контроллере HI) получать данные из другого приложения (погодного сервиса) в стандартизированном формате.

    > * JSON (JavaScript Object Notation): Текстовый формат обмена данными, который легко читается как человеком, так и машиной. Большинство современных API используют JSON для передачи данных.

    Наиболее популярные сервисы, предоставляющие погодные API:

    В рамках этого урока мы будем использовать OpenWeatherMap как один из наиболее доступных и хорошо документированных сервисов.

    При работе с погодными API нас интересуют следующие ключевые параметры:

    | Параметр | Описание | Пример применения |

    | ------------------- | ------------------------------------------------------------------------------------------------------ | ---------------------------------------------------- |

    | Текущая температура | `main.temp`: Фактическая температура воздуха на данный момент. | Расчет дельты для упреждающего прогрева. |

    | Прогноз температуры | `daily.temp.day`, `hourly.temp`: Прогноз температуры на ближайшие часы или дни. | Запуск отопления до наступления похолодания. |

    | Прогноз осадков | `daily.pop` (вероятность), `daily.rain` (объем): Прогноз вероятности и интенсивности осадков. | Отмена автоматического полива. |

    | Влажность воздуха | `main.humidity`: Текущая относительная влажность. | Корректировка работы систем вентиляции и увлажнения. |

    | Скорость ветра | `wind.speed`: Может влиять на теплопотери здания. | Повышение уставки отопления в ветреную погоду. |

    | Облачность | `clouds.all`: Процент покрытия неба облаками. | Учет пассивного солнечного обогрева. |

    Основная идея состоит в том, чтобы периодически запрашивать эти данные, анализировать их и корректировать работу стандартных реактивных сценариев (например, термостата, рассмотренного в `SCN-CLIMATE-001`).

    ---

    Настройка API и получение данных в Node-RED

    Первый практический шаг — настроить получение данных из погодного сервиса. Мы будем использовать узел `http request` для отправки запросов к API OpenWeatherMap и узел `function` для обработки ответа.

    Шаг 1: Регистрация и получение API-ключа

  • Перейдите на сайт OpenWeatherMap и создайте учетную запись.
  • После входа в аккаунт перейдите в раздел "API keys".
  • Скопируйте ваш API-ключ по умолчанию (Default). Этот ключ понадобится нам для аутентификации запросов.
  • > ⚠️ Внимание: Никогда не храните API-ключ в открытом виде внутри узлов Node-RED. Это небезопасно. API-ключ является вашим персональным идентификатором, и его компрометация может привести к блокировке доступа или исчерпанию лимитов. Для безопасного хранения используйте переменные окружения контроллера или файл `credentials`, как это было рассмотрено в курсе по Production Readiness. В примерах ниже мы будем использовать placeholder `YOUR_API_KEY` для наглядности.

    Шаг 2: Создание потока для запроса погоды

    Создадим поток, который будет один раз в час запрашивать прогноз погоды.

    Flow Diagram (ASCII):
    [Inject: раз в час] --> [http request: получить погоду] --> [function: обработать и сохранить] --> [debug]
    

    |

    +----(ошибка)----> [catch] ----> [log/notify]

  • Узел `Inject`:
  • * Payload: `timestamp`

    * Repeat: `interval`, `every 1 hour`

    * Name: `Запрос погоды (1 раз в час)`

  • Узел `http request`:
  • * Method: `GET`

    * URL: Для получения прогноза мы будем использовать "One Call API 3.0". URL имеет следующий формат:

            https://api.openweathermap.org/data/3.0/onecall?lat={lat}&lon={lon}&exclude={part}&appid={API key}&units=metric&lang=ru

    - `{lat}` и `{lon}`: Широта и долгота вашего объекта. Их можно получить, например, в Яндекс.Картах.

    - `{API key}`: Ваш API-ключ.

    - `units=metric`: Получать данные в метрической системе (°C, м/с).

    - `lang=ru`: Получать текстовые описания (например, "небольшой дождь") на русском языке.

    Пример готового URL (для Москвы):

    `https://api.openweathermap.org/data/3.0/onecall?lat=55.7522&lon=37.6156&exclude=minutely,alerts&appid=YOUR_API_KEY&units=metric&lang=ru`

    * Return: `a parsed JSON object`

    * Name: `GET OpenWeatherMap API`

  • Узел `function`:
  • Этот узел будет извлекать нужные нам данные из огромного JSON-ответа и сохранять их в глобальный контекст для использования другими сценариями.

    * Name: `Сохранить прогноз в global`

    * Код:

        // Пример структуры входящего msg.payload от API

    // {

    // "lat": 55.7522,

    // "lon": 37.6156,

    // "current": { "temp": 15.5, "humidity": 60, ... },

    // "hourly": [ { "dt": 1678886400, "temp": 16.1, "pop": 0.1 }, ... ],

    // "daily": [ { "dt": 1678886400, "temp": { "day": 18.2 }, "pop": 0.5, ... }, ... ]

    // }

    // Валидация ответа

    if (!msg.payload || !msg.payload.current || !msg.payload.daily) {

    node.error("Получен некорректный ответ от API погоды", msg);

    node.status({ fill: "red", shape: "dot", text: "Invalid API response" });

    return null;

    }

    const forecast = {

    // Текущие данные

    current: {

    temp: msg.payload.current.temp,

    humidity: msg.payload.current.humidity,

    wind_speed: msg.payload.current.wind_speed

    },

    // Прогноз на сегодня (первый элемент массива daily)

    today: {

    temp_day: msg.payload.daily[0].temp.day,

    temp_night: msg.payload.daily[0].temp.night,

    pop: msg.payload.daily[0].pop, // Вероятность осадков от 0 до 1

    summary: msg.payload.daily[0].summary

    },

    // Прогноз на завтра (второй элемент массива daily)

    tomorrow: {

    temp_day: msg.payload.daily[1].temp.day,

    temp_night: msg.payload.daily[1].temp.night,

    pop: msg.payload.daily[1].pop

    },

    // Данные обновлены

    last_update: Date.now()

    };

    // Сохраняем обработанные данные в глобальный контекст

    global.set('weather_forecast', forecast);

    node.status({ fill: "green", shape: "dot", text: "OK: " + forecast.current.temp + "°C" });

    // Можно передать данные дальше для отладки

    msg.payload = forecast;

    return msg;

    Теперь, после выполнения этого потока, любой другой сценарий в Node-RED может получить доступ к актуальному прогнозу с помощью `global.get('weather_forecast')`.

    ---

    Логика упреждающего управления отоплением

    Рассмотрим применение полученных данных для системы отопления с высокой инерционностью, например, для водяного теплого пола. Классический термостат включит котел, когда пол и воздух уже остыли. Нам же нужно начать прогрев за 2-4 часа до прогнозируемого пика холода.

    Задача: Заблаговременно повысить целевую температуру термостата, если прогноз погоды обещает резкое похолодание.

    Анализ прогноза и расчет дельты

    Логика будет срабатывать параллельно с основным сценарием термостата. Она не будет напрямую управлять котлом, а будет изменять уставку (`setpoint`) для термостата.

  • Получаем данные: Сценарий регулярно (например, раз в 30 минут) обращается к`global.get('weather_forecast')`.
  • Сравниваем температуры: Нас интересует разница между текущей уличной температурой и прогнозируемой ночной температурой.
  • - `current_temp` = `weather_forecast.current.temp`

    - `forecast_night_temp` = `weather_forecast.today.temp_night`

  • Принимаем решение: Если ночная температура прогнозируется значительно ниже текущей (например, на 10°C и более), и при этом текущее время — вечер (например, с 18:00 до 22:00), то это сигнал к действию.
  • Пример реализации в Node-RED

    Этот поток должен выполняться по расписанию и корректировать уставку в основном потоке управления климатом.

    Flow Diagram (ASCII):
    [Inject: раз в 30 мин] --> [function: Проверить прогноз отопления] --> [switch: Нужен прогрев?] --(Да)--> [function: Сформировать команду] --> [mqtt out: new_setpoint]
    
    Код для узла `function: Проверить прогноз отопления`:
    // --- Параметры сценария ---
    

    // Порог разницы температур для активации (°C)

    const TEMP_DELTA_THRESHOLD = 10;

    // Порог текущей уличной температуры, ниже которого включается логика (°C)

    const CURRENT_TEMP_THRESHOLD = 5;

    // Часы, в которые анализируется прогноз (вечер)

    const START_HOUR = 18;

    const END_HOUR = 22;

    // Получаем данные из глобального контекста

    const forecast = global.get('weather_forecast');

    const currentHour = new Date().getHours();

    // Проверка валидности данных (рассмотрено в SCN-CLIMATE-008)

    if (!forecast || (Date.now() - forecast.last_update > 2 60 60 * 1000)) {

    // Данные устарели (нет обновлений > 2 часов)

    node.status({ fill: "yellow", shape: "ring", text: "Stale forecast data" });

    // Переходим к логике отката (fallback) - ничего не делаем

    return null;

    }

    const currentTemp = forecast.current.temp;

    const nightTemp = forecast.today.temp_night;

    const tempDelta = currentTemp - nightTemp;

    // Проверяем условия для упреждающего прогрева

    const needsPreheating =

    (currentHour >= START_HOUR && currentHour < END_HOUR) && // Время для анализа

    (currentTemp > CURRENT_TEMP_THRESHOLD) && // На улице еще не слишком холодно

    (tempDelta >= TEMP_DELTA_THRESHOLD); // Но ожидается резкое похолодание

    msg.payload = {

    needs_preheating: needsPreheating,

    details: {

    current_temp: currentTemp,

    night_temp: nightTemp,

    delta: tempDelta

    }

    };

    if (needsPreheating) {

    node.status({ fill: "blue", shape: "dot", text: `Pré-chauffage activé: ΔT=${tempDelta}°C` });

    } else {

    node.status({ fill: "grey", shape: "dot", text: `Pré-chauffage non requis` });

    }

    return msg;

    Далее узел `switch` проверяет `msg.payload.needs_preheating`. Если `true`, то следующий узел `function` формирует команду на повышение уставки.

    Код узла `function: Сформировать команду`:
    // Текущая уставка для теплого пола, хранится в контексте
    

    let currentSetpoint = flow.get('floor_setpoint') || 24.0;

    // На сколько градусов повысить уставку для упреждающего прогрева

    const PREHEAT_BOOST = 2.0;

    // Формируем сообщение по контракту для нашего сценария термостата

    msg.topic = 'commands/heating/floor/setpoint/set';

    msg.payload = {

    value: currentSetpoint + PREHEAT_BOOST,

    source: 'SCN-CLIMATE-011-Preheat',

    ts: Date.now(),

    meta: {

    reason: 'Proactive heating due to forecast'

    }

    };

    return msg;

    Это сообщение отправляется в MQTT и перехватывается основным сценарием термостата, который плавно поднимает температуру в помещении еще до наступления холодов.

    ---

    Практика: Сценарий 'Умный полив'

    Один из самых очевидных и эффективных сценариев, использующих прогноз погоды, — это автоматизация полива. Главная цель — не тратить воду, если природа сделает это за нас.

    Основное правило: Отменить запланированный сеанс полива, если в ближайшие 12 часов прогнозируется дождь со значительной вероятностью.

    Логика сценария

  • Запуск по расписанию: Полив запускается в определенное время, обычно рано утром или поздно вечером. Для этого используется узел `inject` или более продвинутый планировщик (`node-red-contrib-cron-plus`).
  • Проверка глобального режима: Перед запуском сценарий проверяет, не находится ли дом в режиме "Отпуск" или "Нет дома". Если да, полив отменяется.
  • Проверка прогноза: Сценарий обращается к `global.get('weather_forecast')` и анализирует поле `pop` (вероятность осадков) на сегодня.
  • Принятие решения: Если `pop > 0.5` (вероятность дождя > 50%), поток полива блокируется.
  • Исполнение: Если прогноз благоприятный (дождя не будет), поток продолжается и отправляет команду на включение реле клапана полива.
  • > 💡 Подсказка: Используйте узел `node-red-contrib-within-time` для дополнительной проверки, что полив не будет случайно запущен в дневную жару (например, с 11:00 до 17:00). Это помогает избежать быстрого испарения влаги и ожогов растений.

    Пример реализации в Node-RED

    Flow Diagram (ASCII):
    // Запуск полива по расписанию
    

    [Cron-plus: каждый день в 05:00] --> [switch: Проверить режим дома] --(Дома)--> [function: Проверить прогноз осадков] --> [gate: Блокировать если дождь] --> [function: Открыть клапан на 20 мин] --> [Relay Out: Клапан]

    |

    +---- (управляется `msg.topic`)

    [function: Закрыть клапан] --------------------------+

    Код узла `function: Проверить прогноз осадков`:
    // --- Параметры сценария ---
    

    // Порог вероятности осадков для отмены полива (0.0 - 1.0)

    const PRECIPITATION_PROBABILITY_THRESHOLD = 0.5;

    const forecast = global.get('weather_forecast');

    // Валидация данных прогноза

    if (!forecast || !forecast.today) {

    node.warn("Данные прогноза недоступны. Полив будет выполнен по стандартному расписанию.");

    // В случае ошибки API, мы не блокируем полив. Это fallback-логика.

    // Просто не отправляем команду на блокировку.

    return msg;

    }

    const rainProbability = forecast.today.pop;

    const willRain = rainProbability >= PRECIPITATION_PROBABILITY_THRESHOLD;

    if (willRain) {

    node.status({ fill: "blue", shape: "ring", text: "Полив отменен: прогноз дождя (" + (rainProbability * 100) + "%)" });

    // Отправляем команду на закрытие "ворот" (gate)

    // Узел simple-gate блокирует прохождение сообщений, если получает topic 'close'

    msg.topic = 'close';

    } else {

    node.status({ fill: "green", shape: "dot", text: "Прогноз ясный, полив разрешен." });

    // Отправляем команду на открытие "ворот"

    msg.topic = 'open';

    }

    // Это сообщение пойдет на управляющий вход узла `simple-gate`

    return msg;

    Контракт управляющего сообщения для реле:
    // Сообщение для включения клапана полива, подключенного к реле №10
    

    {

    "payload": true,

    "topic": "commands/relay/10/set"

    }

    Этот сценарий можно усложнить, корректируя длительность полива (`duration`) в зависимости от прогнозируемой дневной температуры и количества дней без осадков.

    ---

    Интеграция с глобальными режимами

    Проактивные сценарии не должны работать в вакууме. Их необходимо интегрировать с общим состоянием системы, которое определяется глобальными режимами ("Дома", "Нет дома", "Сон", "Отпуск").

    > 🔗 Связанный материал: Логика работы с режимами, их установка и использование в сценариях подробно рассмотрены в уроке `SCN-ENERGY-001: Отключение розеток в режиме 'Away' или 'Night'`.

    Правильная иерархия приоритетов выглядит так:

    Глобальный режим > Проактивный сценарий > Реактивный сценарий

    Это означает, что решение, принятое на уровне глобального режима, всегда имеет наивысший приоритет.

    Примеры интеграции:

  • Полив в режиме "Отпуск":
  • * Проблема: Вы уехали в отпуск, а система продолжает поливать газон каждый день, даже если идут дожди, расходуя воду.

    * Решение: В самом начале потока 'Умный полив', сразу после `inject` или `cron`, ставится узел `switch`, который проверяет значение `global.get('Home.Mode')`. Если режим равен "Отпуск" (`Vacation`), поток прерывается.

    Пример узла `switch`:

    * Property: `global.Home.Mode` (тип `global`)

    * Правило 1: `!=` (string) `Vacation` -> выход 1 (продолжить)

    * Правило 2: `иначе` -> выход 2 (остановить)

  • Упреждающий прогрев в режиме "Нет дома":
  • * Проблема: Система обнаруживает прогноз похолодания и начинает заранее греть теплые полы, в то время как в доме никого нет. Это прямая трата энергоресурсов.

    * Решение: Аналогично поливу, поток упреждающего прогрева должен быть заблокирован, если `global.get('Home.Mode')` равен "Нет дома" (`Away`). В этом режиме отопление должно работать в экономном режиме поддержки минимальной температуры (+16°C), и упреждающий прогрев до комфортных +24°C не имеет смысла.

    Такая простая проверка в начале каждого сложного сценария гарантирует, что автоматика будет работать адекватно и предсказуемо, экономя ресурсы, когда это необходимо.

    ---

    Отказоустойчивость и итоговые рекомендации

    Сценарии, зависящие от внешних облачных сервисов, вносят в систему новую точку отказа. Что произойдет, если API погоды станет недоступен из-за проблем с интернетом на объекте или сбоя на стороне самого сервиса? Система не должна "зависать" или переходить в непредсказуемое состояние.

    Реализация логики отката (Fallback Logic)

    Отказоустойчивость — это способность системы продолжать выполнять свои базовые функции даже при отказе одного из компонентов.
  • Для упреждающего отопления: Если данные прогноза недоступны или устарели, сценарий упреждающего прогрева просто не должен выполняться. Система должна автоматически вернуться к работе по обычному реактивному термостату, который опирается на локальные датчики температуры. Это самая простая и надежная fallback-логика.
  • Для умного полива: Если прогноз недоступен, более безопасным решением будет выполнить полив по стандартному расписанию. Пропуск полива в засушливую погоду может нанести вред растениям, в то время как один "лишний" полив перед дождем не так критичен.
  • Механизмы отслеживания ошибок

  • Использование узла `catch`: Узел `http request` имеет два выхода. Второй выход активируется в случае ошибки запроса (например, таймаут, DNS error, код ответа 4xx/5xx).
  • * Подключите к этому выходу последовательность узлов, которая отправит уведомление администратору (через Telegram, MQTT и т.д.) и запишет ошибку в системный журнал.

    * Дополнительно, на каждой вкладке размещайте узел `catch`, настроенный на `all nodes`, чтобы ловить любые необработанные ошибки, в том числе от API.

  • Проверка на устаревшие данные (Stale Data): Как показано в примере выше, при сохранении данных прогноза мы добавляем метку времени `last_update`. Перед использованием этих данных всегда следует проверять, как давно они были обновлены. Если прошло больше 2-3 часов, считать их недействительными и переходить к fallback-логике.
  • Валидация данных (Data Validity)

    Даже если API ответил успешно, нет гарантии, что данные корректны. Теоретически, из-за сбоя сервис может вернуть температуру `-300°C` или вероятность осадков `99`.

    > ℹ️ Информация: Перед использованием любых данных, полученных из внешнего, неконтролируемого источника, производите проверку на правдоподобность (sanity check).

    Например, в узле-обработчике ответа API добавьте простые проверки:

    let temp = msg.payload.current.temp;
    

    if (temp < -60 || temp > 60) {

    node.error(`Аномальное значение температуры от API: ${temp}°C`);

    return null; // Не сохранять и не использовать эти данные

    }

    Итог

    В этом уроке мы рассмотрели, как перейти от реактивного к проактивному управлению климатом, используя данные из внешних API прогноза погоды. Мы реализовали два практических сценария: упреждающий прогрев для систем с высокой инерцией и умный полив, экономящий воду. Ключевым аспектом при внедрении таких сценариев является обеспечение их отказоустойчивости и правильная интеграция с глобальными режимами работы умного дома.

    Что дальше?

    В следующем уроке мы перейдем к более сложным интеграциям и рассмотрим сценарий `SCN-CLIMATE-015: Адаптивное управление кондиционированием`, в котором система будет учитывать не только температуру, но и положение солнца, время дня и наличие людей в помещении для создания идеального микроклимата с минимальными затратами энергии.