ГлавнаяАкадемияCOURSE-16: Основы Интернета Вещей и практическое применение → Обработка данных в реальном времени на контроллере

Обработка данных в реальном времени на контроллере

Урок 1 · COURSE-16: Основы Интернета Вещей и практическое применение · theory

COURSE-16-M03-L02 — Обработка данных в реальном времени на контроллере

Введение в обработку на лету (Real-Time Processing)

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

На платформе HI эта задача решается непосредственно на контроллере. Это называется обработкой на краю (Edge Computing). Контроллер не просто собирает данные для отправки в облако, а самостоятельно выполняет логику и принимает решения.

💡 Ключевая концепция: Вся логика в Node-RED построена на событийно-ориентированной модели. Потоки (flows) не работают постоянно, а "спят", ожидая входящего сообщения (события). Как только сообщение поступает от датчика, таймера или другого источника, поток активируется, выполняет логику и снова переходит в режим ожидания. Это обеспечивает высокую эффективность и низкое потребление ресурсов контроллера.

Архитектура обработки данных на контроллере HI

Забудьте о сложных облачных платформах типа Apache Kafka или AWS IoT для базовых задач. 99% сценариев автоматизации на объекте реализуются в рамках трехуровневой архитектуры непосредственно на контроллере HI.

  • Уровень 1: Сбор данных (Источники событий)
  • Это "органы чувств" вашей системы. Данные поступают в Node-RED от физических интерфейсов и протоколов контроллера:

    * Универсальные входы: Сигналы от кнопок, выключателей ("сухой контакт"), герконов.

    * Шина 1-Wire: Показания с датчиков температуры DS18B20.

    * Шина RS-485: Данные с промышленных датчиков, счетчиков, модулей ввода-вывода по протоколу Modbus RTU.

    * Сеть TCP/IP: Сообщения по протоколу MQTT, команды по HTTP, данные от устройств по Modbus TCP.

    * Внутренние события: Срабатывание таймеров, системные события.

  • Уровень 2: Обработка и логика (Ядро на Node-RED)
  • Это "мозг" системы. Здесь входящие сообщения преобразуются, анализируются и на их основе принимаются решения. Для этого используются стандартные узлы Node-RED:

    * `Switch`: Маршрутизация сообщений в зависимости от их содержимого (например, если `msg.payload.value > 25`, отправить на ветку "Включить кондиционер").

    * `Function`: Написание сложной логики на JavaScript. Здесь реализуются вычисления, валидация и формирование сообщений по контракту.

    * `Change`: Простое изменение, установка или удаление свойств сообщения без написания кода.

    * `Trigger`: Формирование последовательности действий (например, "после получения команды включить свет, подождать 10 минут и выключить").

  • Уровень 3: Действие и обратная связь (Исполнители)
  • Это "руки" вашей системы. После принятия решения контроллер выполняет действие:

    * Релейные выходы: Включение/выключение освещения, розеток, управление клапанами и приводами.

    * Шина DALI: Управление яркостью и цветом светильников.

    * Сеть TCP/IP: Отправка статуса в MQTT, запись данных в локальную базу данных MySQL для истории, отправка уведомлений.

    * Визуальный статус: Обновление статуса узла в редакторе Node-RED для быстрой диагностики (`node.status`).

    Практический пример: Реализация климат-контроля на Node-RED

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

    Задача: Поддерживать температуру между 22°C (уставка `setpoint_min`) и 24°C (`setpoint_max`). Если температура падает ниже 22°C, включить обогреватель (реле 1). Если поднимается выше 24°C, выключить обогреватель. Необходимые компоненты:

    Шаг 1: Схема потока (Flow Diagram)

    Это пример использования паттерна "Конечный автомат" (Finite State Machine - FSM), где система может находиться в двух состояниях: `IDLE` (ожидание) и `HEATING` (нагрев).

    // FLOW-CLIMATE-001: Simple Thermostat Logic
    
    

    // Уровень 1: Сбор данных

    [1-Wire In: Temp Sensor] --(msg)--> [Function: Thermostat FSM] --+-- (msg to relay ON) --> [Relay Out: Heater]

    |

    +-- (msg to relay OFF)--> [Relay Out: Heater]

    |

    +-- (no change) --> [null]

    // Уровень 2: Обработка ошибок

    [Catch: All Nodes] --> [Function: Format Error] --> [Log to MySQL]

    Шаг 2: Контракт сообщения

    Чтобы логика была предсказуемой, определим стандартный формат сообщения от датчика.

    // Сообщение, которое мы ожидаем от узла 1-Wire
    

    // msg.payload должен содержать числовое значение температуры

    // Например: 23.5

    Шаг 3: Логика в узле `Function` ("Thermostat FSM")

    Это сердце нашей системы. Мы будем использовать контекст потока (`flow context`) для хранения текущего состояния обогревателя.

    // Получаем текущую температуру из входящего сообщения
    

    const currentTemp = msg.payload;

    // Задаем уставки. В реальном проекте их лучше хранить в контексте

    // или получать по MQTT, чтобы можно было менять без перезагрузки потока.

    const setpoint_min = 22.0;

    const setpoint_max = 24.0;

    // Получаем текущее состояние обогревателя из контекста потока.

    // Если состояния нет (первый запуск), считаем, что он выключен.

    let heaterState = flow.get("heaterState") || "OFF";

    // --- Логика Конечного Автомата (FSM) ---

    // Если сейчас идет нагрев (состояние HEATING)

    if (heaterState === "HEATING") {

    // и температура достигла верхней границы,

    if (currentTemp >= setpoint_max) {

    // то выключаем обогреватель.

    heaterState = "OFF";

    flow.set("heaterState", heaterState); // Сохраняем новое состояние

    node.status({fill:"blue", shape:"dot", text:`Idle at ${currentTemp}°C`});

    // Возвращаем сообщение для узла реле

    return { payload: false }; // false для выключения

    }

    }

    // Если сейчас обогреватель выключен (состояние IDLE)

    else { // heaterState === "OFF"

    // и температура упала ниже нижней границы,

    if (currentTemp < setpoint_min) {

    // то включаем обогреватель.

    heaterState = "HEATING";

    flow.set("heaterState", heaterState); // Сохраняем новое состояние

    node.status({fill:"red", shape:"dot", text:`Heating at ${currentTemp}°C`});

    // Возвращаем сообщение для узла реле

    return { payload: true }; // true для включения

    }

    }

    // Если никаких действий не требуется, обновляем статус и останавливаем поток.

    node.status({fill:"green", shape:"dot", text:`OK: ${currentTemp}°C. State: ${heaterState}`});

    return null; // Ничего не отправляем дальше

    ⚠️ Важно: Использование гистерезиса (разницы между `setpoint_min` и `setpoint_max`) обязательно! Если использовать одну уставку (например, 23°C), реле будет постоянно щелкать (дребезг) при колебаниях температуры около этого значения, что приведет к его быстрому износу.

    Лабораторная работа №1 (COURSE-16-M03-LAB03)

    Название: "Реакция на событие: автоматическое освещение по кнопке" Цель: Создать поток, который включает и выключает реле освещения при нажатии на настенный выключатель (кнопку без фиксации). Скелет потока:

    `[Input: Dry Contact]` -> `[Function: Toggle Logic]` -> `[Output: Relay]`

    Задание:
  • Подключите настенный выключатель к универсальному входу контроллера (например, UI5 и GND). Используйте стандарт `WIRING-LIGHT-015` для подключения.
  • В Node-RED используйте узел `rpi-gpio in` для считывания состояния входа.
  • Напишите логику в узле `Function`, которая будет инвертировать состояние реле при каждом нажатии. Используйте `flow.context` для хранения текущего состояния (ON/OFF).
  • Используйте узел `rpi-gpio out` для управления реле (например, RL3).
  • Добавьте узел `Status` для отображения текущего состояния света ("Свет Вкл", "Свет Выкл").
  • Добавьте узел `Catch` для обработки ошибок, если `rpi-gpio in` или `rpi-gpio out` не смогут инициализироваться.
  • Чек-лист выполнения: Рубрика оценивания:

    Лабораторная работа №2 (COURSE-16-M03-LAB04)

    Название: "Конечный автомат: базовый климат-контроль" Цель: Реализовать на практике логику термостата, описанную в уроке. Скелет потока:

    `[Inject: Timer]` -> `[Input: 1-Wire Sensor]` -> `[Function: Thermostat FSM]` -> `[Output: Relay]`

    Задание:
  • Создайте поток, который раз в 10 секунд опрашивает датчик температуры DS18B20.
  • Используйте код из примера в уроке для узла `Function`. Задайте уставки `setpoint_min = 21.0` и `setpoint_max = 23.0`.
  • Направьте выход из `Function` на узел управления реле, к которому подключен обогреватель.
  • Добавьте узел `Catch` на вкладку и соедините его с узлом `Debug` для отлова возможных ошибок (например, если датчик не отвечает).
  • Усложнение (опционально): Добавьте возможность изменять уставки `setpoint_min` и `setpoint_max` "на лету" через входящие MQTT-сообщения. Используйте паттерн "Контракт сообщения" для MQTT-сообщений с уставками.
  • Чек-лист выполнения: Рубрика оценивания:

    Тест модуля (COURSE-16-M03-QUIZ)

  • Что такое "обработка на краю" (Edge Computing)?
  • a) Обработка данных в облаке Amazon.

    b) Обработка данных непосредственно на IoT-контроллере.

    c) Хранение данных в локальной базе MySQL.

    d) Шифрование данных перед отправкой.

  • Какая модель лежит в основе работы потоков Node-RED?
  • a) Пакетная.

    b) Запрос-ответ.

    c) Событийно-ориентированная.

    d) Многопоточная.

  • Для чего используется узел `Switch` в Node-RED?
  • a) Для написания сложной логики на JavaScript.

    b) Для маршрутизации сообщений в зависимости от их содержимого.

    c) Для включения и выключения реле.

    d) Для хранения переменных.

  • Зачем в логике термостата использовать две уставки (гистерезис)?
  • a) Для повышения точности измерения.

    b) Для предотвращения частого переключения реле (дребезга).

    c) Для экономии электроэнергии.

    d) Это требование протокола Modbus.

  • Где следует хранить состояние сложного устройства (например, термостата) в Node-RED?
  • a) В глобальном контексте (`global.context`).

    b) В контексте потока (`flow.context`).

    c) Внутри `msg.payload`.

    d) В текстовом файле.

  • Какой паттерн проектирования лучше всего подходит для управления устройством с несколькими состояниями (например, "Вкл", "Выкл", "Ожидание", "Авария")?
  • a) Контракт сообщения.

    b) Конечный автомат (FSM).

    c) Обработка ошибок.

    d) Визуальный статус.

  • Что делает команда `return null;` в конце узла `Function`?
  • a) Вызывает ошибку.

    b) Отправляет пустое сообщение.

    c) Останавливает дальнейшее движение сообщения по потоку.

    d) Перезагружает контроллер.

  • Какую информацию должен содержать `msg.payload` согласно "Контракту сообщения" Академии HI?
  • a) Только числовое значение.

    b) JSON-объект со структурой `{ "value": ..., "source": ..., "ts": ... }`.

    c) Строку "ON" или "OFF".

    d) XML-структуру.

  • Для чего предназначен узел `Catch`?
  • a) Для запуска потока по расписанию.

    b) Для перехвата и обработки ошибок, возникающих в других узлах на вкладке.

    c) Для проверки JSON-схемы.

    d) Для отправки HTTP-запросов.

  • Какое действие выполняет узел `rpi-gpio out` при получении `msg.payload` со значением `false`?
  • a) Включает реле.

    b) Выключает реле.

    c) Ничего не делает.

    d) Отправляет сигнал тревоги.

    (Правильные ответы: 1-b, 2-c, 3-b, 4-b, 5-b, 6-b, 7-c, 8-b, 9-b, 10-b)

    Мини-runbook "Если не работает"

    📋 Проблема: Реле не реагирует на команды из Node-RED.

  • Проверка физики: Убедитесь, что нагрузка (лампа, обогреватель) правильно подключена к клеммам реле (C и NO/NC) и к сети 230В. Проверьте, что на сам контроллер подано питание. Используйте `WIRING-LIGHT-015` как эталон.
  • Проверка в Node-RED: Подключите узлы `Inject` со значениями `true` и `false` напрямую к узлу `rpi-gpio out`. Срабатывает ли реле при ручной активации? Если да, проблема в логике. Если нет — в настройках узла (неверный номер GPIO).
  • Проверка логики: Подключите узел `Debug` к выходу вашего узла `Function`. Приходят ли в него сообщения `true`/`false` в нужный момент? Если нет, ошибка в коде `Function`.
  • 📋 Проблема: Узел `1-Wire In` или `Modbus-Read` выдает ошибку или не возвращает данные.

  • Проверка подключения: Проверьте схему подключения датчика (`WIRING-SENS-004`). Для 1-Wire: не перепутаны ли Data и GND? Для Modbus: не перепутаны ли A и B? Есть ли на шине терминатор 120 Ом?
  • Проверка адреса: Убедитесь, что в настройках узла указан правильный ID датчика (для 1-Wire) или Slave ID и адрес регистра (для Modbus). Обратите внимание на "ошибку на единицу" (off-by-one) для Modbus-адресов.
  • Изоляция проблемы: Попробуйте считать данные с помощью сторонней утилиты (например, `ow-shell` для 1-Wire) прямо из консоли Linux на контроллере. Если данные читаются, проблема в Node-RED. Если нет — в физическом подключении или в самом датчике.
  • 📋 Проблема: Логика термостата работает некорректно (реле щелкает слишком часто).

  • Проверка гистерезиса: Убедитесь, что в коде узла `Function` есть разница между `setpoint_min` и `setpoint_max`. Она должна быть не менее 1-2 градусов.
  • Проверка состояния: Используйте `node.status` или `Debug` для вывода текущего состояния (`heaterState`). Возможно, оно неверно сохраняется или считывается из `flow.context`. Убедитесь, что вы используете `flow.set()` и `flow.get()`.
  • Проверка частоты опроса: Убедитесь, что датчик опрашивается не слишком часто. Для термостата достаточно 10-30 секунд. Чрезмерно частый опрос может приводить к "дребезгу" при пограничных значениях.