Физический сигнал, логическое событие, состояние системы: фундаментальные различия
Введение: от физики к логике
В современной системе автоматизации мы постоянно работаем с данными, которые поступают от сотен датчиков и устройств. Чтобы построить надежную и предсказуемую систему, критически важно понимать путь, который проходят эти данные — от физического мира до логических операций внутри контроллера. Весь этот путь можно разложить на три фундаментальные составляющие: физический сигнал, логическое событие и состояние системы.
> ℹ️ Информация: В рамках этого курса мы будем использовать термины «сигнал», «событие» и «состояние» в строго определенном контексте, который является стандартом для инженеров сертификационной академии. Четкое разделение этих понятий — залог успешного проектирования и безошибочной диагностики.
Представьте себе простую аналогию:
В экосистеме контроллера HI этот поток данных выглядит следующим образом:
- Физический сигнал: Изменение напряжения или сопротивления на универсальном входе (UI) контроллера от подключенного датчика.
- Логическое событие: Программный код в Node-RED анализирует этот сигнал, приводит его к человекочитаемому виду (например, в градусы Цельсия) и формирует стандартизированное сообщение `msg`.
- Состояние системы: Это сообщение обновляет переменную в памяти контроллера (контексте Node-RED), которая хранит актуальное значение, например, `office_temperature = 23.5`.
Понимание этой триады позволяет инженеру-инсталлятору корректно настраивать обработку данных от любого, даже самого сложного датчика, и создавать автоматизацию, которая работает не только «здесь и сейчас», но и будет стабильной, масштабируемой и простой в обслуживании в будущем.
---
Физический сигнал: язык датчиков
Физический сигнал — это самое низкоуровневое представление информации, с которым работает аппаратная часть контроллера. Это измеримая физическая величина, такая как напряжение, сила тока или сопротивление, которая поступает на клеммы устройства. Все физические сигналы, с которыми мы работаем, делятся на два больших класса: аналоговые и дискретные.| Характеристика | Аналоговый сигнал | Дискретный сигнал |
| ------------------------ | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| Природа | Непрерывно изменяющаяся величина в определенном диапазоне. | Имеет только два или несколько фиксированных состояний. |
| Примеры на объекте | Датчик температуры (NTC/PT1000), датчик освещенности (0-10В), датчик давления (4-20мА). | Кнопка, геркон на двери, датчик протечки, выход "сухой контакт" другого устройства. |
| Физическое проявление | Изменение напряжения (e.g., 0-3.3В), изменение сопротивления. | Замкнутая или разомкнутая цепь (сопротивление близко к 0 или бесконечности). |
| Роль контроллера HI | АЦП (Аналого-цифровой преобразователь) измеряет напряжение и преобразует его в число. | Универсальный вход в режиме DI (Digital Input) определяет, замкнута цепь или нет. |
| "Сырые" данные | Число, пропорциональное напряжению. Например, `1532` (из диапазона 0-4095 для 12-битного АЦП). | `0` (разомкнуто) или `1` (замкнуто). |
Аналоговый сигнал на примере датчика температуры NTC
Датчик температуры NTC (Negative Temperature Coefficient) — это, по сути, резистор, сопротивление которого уменьшается при увеличении температуры. Контроллер HI подает на него опорное напряжение через делитель и измеряет результирующее напряжение на входе. Это напряжение напрямую зависит от сопротивления NTC-датчика, а значит, и от температуры.
АЦП контроллера замеряет это напряжение и выдает "сырое" (raw) цифровое значение. Например, для 12-битного АЦП, работающего с напряжением от 0 до 3.3В, мы получим:
- 0В → число `0`
- 1.65В → число `2048`
- 3.3В → число `4095`
В Node-RED, из специализированного узла для чтения аналоговых входов (например, гипотетического `HI-AI`), придет сообщение `msg` с `payload`, содержащим это сырое число: `1532`. Это и есть физический сигнал в его цифровом представлении. Он еще не несет для нас никакого смысла, кроме как "напряжение на входе составляет примерно `1532/4095 * 3.3В`".
Дискретный сигнал на примере геркона
Геркон (герметизированный контакт) на окне — это классический пример источника дискретного сигнала. Когда окно закрыто, магнит рядом с герконом замыкает его контакты. Когда окно открывается, магнит удаляется, и контакты под действием упругости размыкаются.
Универсальный вход контроллера HI, настроенный как дискретный, постоянно проверяет состояние этой цепи.
- Цепь замкнута → Вход "видит" логический `1` (или `true`).
- Цепь разомкнута → Вход "видит" логический `0` (или `false`).
В Node-RED от узла `HI-DI` придет сообщение с `msg.payload`, равным `0` или `1`. Это тоже "сырой" физический сигнал. Он говорит нам о состоянии электрической цепи, но еще не говорит о состоянии окна в понятных для автоматизации терминах.
> 💡 Подсказка: Для стабильного чтения дискретных сигналов всегда используйте внешнюю или внутреннюю "подтяжку" (pull-up/pull-down резисторы), чтобы избежать "плавающего" состояния входа, когда он не подключен ни к `GND`, ни к питанию. Подробнее об этом было рассмотрено в уроке 🔗 COURSE-03-M02-L01.
---
Логическое событие: рождение смысла
Логическое событие — это результат интеллектуальной обработки сырого физического сигнала. Это осмысленное, структурированное сообщение, которое говорит системе не о напряжении на клемме, а о том, что именно произошло в реальном мире. Процесс преобразования сигнала в событие называется нормализацией и является одной из ключевых задач инженера при настройке системы.Этот процесс происходит внутри Node-RED, как правило, в узле `function`.
Техники нормализации и фильтрации
Формирование канонического `msg` объекта
После нормализации и фильтрации результат должен быть упакован в стандартный, предсказуемый формат. Как мы знаем из паттернов Node-RED, это "контракт сообщения".
- `msg.topic` используется для семантической идентификации источника. Он должен отвечать на вопросы "что это?" и "откуда?". Например, `telemetry/living_room/temperature` или `events/front_door/status`.
- `msg.payload` должен содержать структурированные данные в формате JSON.
Давайте посмотрим на примере преобразования сигнала с NTC-датчика в логическое событие.
/*
Узел Function: "Нормализация температуры в гостиной"
Вход: msg.payload = 1532 (сырое значение от АЦП узла HI-AI)
Выход: структурированное сообщение с температурой в °C
*/
// --- 1. Нормализация ---
// Предположим, мы экспериментально или по документации выяснили,
// что для нашего датчика и делителя формула такова:
// Temp_C = (3800 - raw_value) / 30.5
let rawValue = msg.payload;
let temperature = (3800 - rawValue) / 30.5;
// Округляем до одного знака после запятой
temperature = Math.round(temperature * 10) / 10;
// --- 2. Валидация ---
// Отсекаем нереалистичные значения, которые могут возникнуть при обрыве или КЗ датчика.
if (temperature < -40 || temperature > 100) {
// Если значение некорректно, логируем ошибку и останавливаем поток.
// Узел Catch поймает эту ошибку.
node.error(`Некорректное значение температуры после нормализации: ${temperature}°C, raw: ${rawValue}`, msg);
return null; // Остановить обработку этого сообщения
}
// --- 3. Формирование каноничного сообщения (События) ---
// Заполняем topic для маршрутизации
msg.topic = "telemetry/living_room/temperature";
// Заполняем payload согласно контракту
msg.payload = {
"value": temperature,
"unit": "°C",
"source": "ui-05-ntc-livingroom", // Уникальный ID источника
"ts": Date.now(), // Временная метка события
"raw": rawValue // Опционально сохраняем сырое значение для отладки
};
node.status({fill:"green", shape:"dot", text:`${temperature} °C`});
return msg;
Теперь на выходе узла мы имеем не просто число, а полноценное, понятное системе логическое событие, которое можно отправлять в MQTT, сохранять в базу данных или использовать в сценариях автоматизации.
---
Состояние системы: цифровая память объекта
Если событие — это сообщение о том, что что-то изменилось, то состояние — это информация о том, как обстоят дела прямо сейчас. Состояние системы — это "снимок" всех её важных параметров в определенный момент времени, хранящийся в памяти контроллера.
События порождают изменения состояния. Например, событие «Дверь открылась» изменяет состояние `system.doors.front_door` с `'closed'` на `'open'`.
В Node-RED для хранения состояний используется механизм контекста. Контекст — это, по сути, область памяти, где можно хранить переменные. Существует три уровня контекста:
- Node Context: Переменная видна только тому узлу, который ее создал. Используется редко, для очень специфичных задач.
- Flow Context: Переменные видны всем узлам на одной вкладке (flow). Это основной инструмент для хранения локальных состояний. Например, состояние света в одной комнате.
- Global Context: Переменные видны абсолютно всем узлам на всех вкладках. Используется для хранения глобальных состояний, к которым нужен доступ из разных подсистем (например, режим «Я ушел из дома», статус охранной системы).
> ⚠️ Внимание: Избегайте хранения слишком больших или сложных объектов в контексте. Это увеличивает использование оперативной памяти (ОЗУ) контроллера и может замедлить время развертывания потоков (deploy). Храните только необходимую информацию: `{'state': 'ON', 'brightness': 80}`, а не весь объект `msg`.
Преимущества работы с состояниями
Представьте, что вам нужно включить кондиционер, только если все окна в доме закрыты.
- Подход без состояний: Вам пришлось бы подписаться на события от каждого геркона на каждом окне и в сложной логике отслеживать их.
- Подход с состояниями: Каждый геркон при изменении своего статуса (событие `WINDOW_OPENED`/`WINDOW_CLOSED`) обновляет свою переменную в глобальном контексте. Например, `global.set('windows.living_room.state', 'closed')`. Сценарий управления кондиционером перед включением просто проверяет значения всех этих переменных: `global.get('windows.living_room.state')`, `global.get('windows.bedroom.state')` и т.д.
Этот подход делает систему декомпозированной и масштабируемой. Логика управления кондиционером ничего не знает о герконах — она работает с абстрактными состояниями окон. А логика обработки герконов ничего не знает о кондиционере. Систему становится легко отлаживать и расширять.
Пример чтения состояния из контекста в `function` узле:
// Получаем текущий статус входной двери из глобального контекста
const frontDoorStatus = global.get('security.doors.front_door');
// frontDoorStatus может выглядеть так:
// { "status": "closed", "last_change": 1678886400000 }
if (frontDoorStatus && frontDoorStatus.status === 'open') {
// Логика, если дверь открыта
}
Контроллер HI позволяет настроить персистентное хранение контекста. Это означает, что даже после перезагрузки или сбоя питания все сохраненные состояния будут восстановлены, и система вернется к работе в том же виде, в котором была до отключения. Это критически важно для надежности.
---
Сквозной пример: от кнопки до управления светом
Давайте объединим все три концепции на простом, но очень показательном примере: управление светом в комнате с помощью одной кнопки без фиксации. Каждое нажатие должно инвертировать состояние света (был включен — выключится, был выключен — включится).
Наша задача: [HI-DI In] [rbe] [function] [HI-Relay Out]
(сигнал) -- (Кнопка) --.-- (Фильтр) -- (Событие) -- (Логика) -- (Изменение состояния) -- (Команда) --> (Реле света)
| | | |
0/1 1 "PRESSED" msg.payload: true/false
Шаг 1: Чтение физического сигнала
Используем узел `HI-DI In` (или его аналог для дискретных входов), настроенный на пин, к которому подключена кнопка. На выходе этого узла мы будем получать `msg.payload` со значением `1` при нажатии и `0` при отпускании.
Шаг 2: Создание события "Кнопка нажата"
Нам важно отреагировать только на факт нажатия, а не на дребезг или отпускание.
Теперь на выходе узла `switch` мы имеем чистое логическое событие, которое можно обрабатывать.
Шаг 3: Обработка события и управление состоянием
Это сердце нашей логики. Мы используем узел `function` для инвертирования состояния.
/*
Узел Function: "Логика переключения света"
Вход: любое сообщение (событие нажатия кнопки)
Выход: msg.payload = true (включить) или false (выключить)
*/
// --- 1. Чтение текущего состояния ---
// Сначала получаем текущее состояние света из контекста потока.
// Если состояния нет (первый запуск), считаем, что свет выключен (false).
let currentState = flow.get('light_state') || false;
// --- 2. Инвертирование состояния ---
// Меняем состояние на противоположное.
let newState = !currentState;
// --- 3. Сохранение нового состояния ---
// Записываем новое состояние обратно в контекст потока для следующего нажатия.
flow.set('light_state', newState);
// --- 4. Формирование команды для реле ---
// Помещаем новое состояние в msg.payload. Узел HI-Relay Out
// ожидает `true` для включения или `false` для выключения.
msg.payload = newState;
// Обновляем визуальный статус узла для удобства отладки
if (newState) {
node.status({fill:"yellow", shape:"dot", text:"State: ON"});
} else {
node.status({fill:"grey", shape:"dot", text:"State: OFF"});
}
return msg;
Шаг 4: Исполнение команды
На выходе узла `function` мы имеем `msg.payload`, равный `true` или `false`. Это сообщение мы отправляем напрямую в узел `HI-Relay Out`, который настроен на управление нужным реле. Узел получит `true` и замкнет реле, или `false` и разомкнет его.
Таким образом, мы прошли весь путь: от нестабильного сигнала `0/1/0/1/1...` на входе до чистого события "нажатие", которое изменило внутреннее состояние системы и привело к физическому действию.
---
Резюме: Сигнал → Событие → Состояние
В этом уроке мы рассмотрели три кита, на которых держится любая надежная система автоматизации. Четкое разделение этих понятий позволяет создавать логику, которая легко читается, отлаживается и масштабируется.
Давайте закрепим основные определения:
- Сигнал — это "сырая", необработанная физическая величина на входе контроллера (напряжение, сопротивление, замыкание цепи). Это язык оборудования. В Node-RED это, как правило, простое число или `true`/`false` в `msg.payload`.
- Событие — это результат обработки и нормализации сигнала. Это осмысленное, структурированное сообщение о том, что в реальном мире произошло нечто важное (температура превысила порог, дверь открылась, кнопка нажата). Это язык логики. В Node-RED это `msg` с осмысленным `topic` и структурированным `payload`.
- Состояние — это актуальная информация об объекте или системе, хранящаяся в "памяти" контроллера (контексте) и изменяемая событиями. Это цифровая модель реального мира. Она позволяет разным частям системы принимать решения, не дожидаясь новых событий.
Освоив эту модель, вы перестаете мыслить в терминах "замкнуть реле, когда на входе X появится напряжение Y". Вместо этого вы начинаете проектировать на более высоком уровне абстракции: "Изменить состояние `climate.mode` на `heating`, когда произойдет событие `TEMPERATURE_TOO_LOW`". Это и есть профессиональный подход к автоматизации на платформе HI.
> 📋 Ключевые понятия:
>
> - Физический сигнал (аналоговый/дискретный): Необработанная информация от датчика.
> - Логическое событие: Осмысленное сообщение об изменении в системе.
> - Состояние системы: Актуальный "снимок" параметров системы, хранящийся в памяти.
> - Контекст Node-RED (global/flow): Механизм для хранения состояний.
> - Нормализация сигнала: Преобразование сырых данных в реальные физические величины.
> - Фильтрация дребезга (Debounce): Устранение ложных сигналов от механических контактов.
> - АЦП (ADC): Аналого-цифровой преобразователь.
> - Дискретный вход (DI): Вход для определения двух состояний (замкнуто/разомкнуто).
Что дальше?
В следующем уроке мы углубимся в практические аспекты работы с аналоговыми сигналами. Мы рассмотрим различные типы датчиков (NTC, Pt1000, 0-10В, 4-20мА), изучим типовые схемы их подключения к универсальным входам контроллера HI и разберем более сложные примеры нормализации и калибровки в Node-RED.