Влияние IoT на окружающую среду: от теории к практике на платформе HI
COURSE-16-M05-L07 — Влияние IoT на окружающую среду: от теории к практике на платформе HI
Введение
Интернет вещей (IoT) является мощным инструментом, способным оказывать как положительное, так и отрицательное воздействие на окружающую среду. С одной стороны, IoT-системы позволяют осуществлять точный мониторинг, рационально использовать ресурсы и снижать выбросы парниковых газов. С другой — массовое внедрение электроники порождает вызовы, связанные с энергопотреблением и утилизацией электронных отходов.
Задача инженера по автоматизации — проектировать системы, которые максимизируют экологические преимущества и минимизируют негативные последствия. В данном уроке мы перейдем от теории к практике и рассмотрим, как с помощью контроллера HI и стандартных протоколов реализовать экологически ориентированные сценарии автоматизации.
Положительное воздействие: Практическая реализация на платформе HI
Рассмотрим два типовых сценария, демонстрирующих, как инженер может внести вклад в защиту окружающей среды, используя стандартные возможности контроллера HI.
1. Мониторинг качества воздуха и управление вентиляцией
Задача: Автоматически поддерживать здоровый микроклимат в офисном помещении, управляя приточной вентиляцией на основе концентрации CO₂. Это позволяет не только улучшить самочувствие сотрудников, но и экономить электроэнергию, избегая избыточной работы вентиляционной установки. Оборудование:- Контроллер HI (основной модуль).
- Датчик качества воздуха с интерфейсом RS-485 (Modbus RTU), например, датчик CO₂/температуры/влажности.
- Приточная вентиляционная установка, управляемая через релейный выход контроллера.
📋 Чек-лист подключения:
//============ WIRING-ENV-AIR-001: Office Air Quality Control ==============
// Используется кабель "витая пара" UTP Cat5e с экраном
[CTRL:HI-Core] (SENS:CO2-01: Modbus ID 15)
(RS485-1)
Клемма Шина Цвет Клемма
+24V --------- (Красный) ---- V+
A ---A------ (Зеленый) ---- A
B ---B------ (Белый) ----- B
GND ---GND---- (Черный) ----- GND
|
(Экран) -------- GND (только со стороны контроллера)
// Управление вентилятором (230V AC)
[CTRL:HI-Core]
~L~ (из щита) --- C (RL-10)
NO (RL-10) --- ~L~ -------- L (Вентилятор)
~N~ (из щита) ------------------------------ N (Вентилятор)
Логика в Node-RED: FLOW-ENV-AIR-001
Поток реализует опрос датчика, анализ данных и управление реле.
// Flow: Опрос датчика CO2 и управление вентиляцией
//
// [Inject: 1 min] -> [Modbus-Read] -> [Function: Validate & Format] -> [Switch: Check CO2] --+
// |
// [Catch] -> [Function: Log Error] -> [mqtt out: errors] |
// |
// +--------------------------------< (CO2 > 1000 ppm) >-- [Change: ON] --> [rpi gpio out: RL-10]
// |
// +--------------------------------< (CO2 < 800 ppm) >--- [Change: OFF] --> [rpi gpio out: RL-10]
Реализация в Node-RED:
* Конфигурация Modbus-Client: Убедитесь, что настроен Modbus RTU клиент на соответствующий COM-порт контроллера HI (`/dev/ttyS1` или `/dev/ttyUSB0`) с правильными параметрами скорости, четности и стоп-битов (например, 9600, 8N1).
* Конфигурация Modbus-Read:
* `Server`: Выбрать настроенный Modbus RTU клиент.
* `Unit-ID`: `15` (или тот, что установлен на датчике).
* `FC`: `FC 3: Read Holding Registers`.
* `Address`: `100` (или соответствующий адрес CO₂ по карте регистров датчика).
* `Quantity`: `1`.
* `Polling interval`: `60` seconds.
// Узел: "Validate & Format CO2"
// Вход: msg.payload от Modbus-узла, например { data: [1150], buffer: }
// Выход: msg с payload в стандартном контракте
// Контракт сообщения: { "value": 1150, "unit": "ppm", "source": "modbus-sensor-office-1", "ts": 1678886400000 }
if (!msg.payload || !Array.isArray(msg.payload.data) || msg.payload.data.length === 0) {
node.status({fill:"red", shape:"dot", text:"No data"});
node.error("Некорректный формат данных от Modbus-датчика", msg);
return null; // Прервать поток
}
const co2_level = msg.payload.data[0];
// 1. Валидация данных
if (isNaN(co2_level) || co2_level < 400 || co2_level > 5000) { // Типичные диапазоны CO2
node.status({fill:"red", shape:"dot", text:"Invalid CO2: " + co2_level});
node.error("Некорректное значение CO2: " + co2_level, msg);
return null; // Прервать поток
}
// 2. Формирование по контракту сообщения
msg.payload = {
value: co2_level,
unit: "ppm",
source: "modbus-sensor-office-1",
ts: Date.now()
};
msg.topic = "telemetry/office/air_quality/co2"; // Для маршрутизации
// 3. Визуальный статус
node.status({fill:"green", shape:"dot", text: co2_level + " ppm"});
return msg;
* `Property`: `msg.payload.value`
* `Rule 1`: `is greater than` `1000` (выход 1)
* `Rule 2`: `is less than` `800` (выход 2)
* Узел `Change` (для включения вентиляции):
* `Set`: `msg.payload`
* `to the value`: `true` (boolean)
* `Set`: `msg.topic`
* `to the value`: `commands/fan/office/set`
* Узел `Change` (для выключения вентиляции):
* `Set`: `msg.payload`
* `to the value`: `false` (boolean)
* `Set`: `msg.topic`
* `to the value`: `commands/fan/office/set`
* Узел `rpi gpio out` (для управления реле):
* `Pin`: `RL-10` (или соответствующий номер реле).
* `Type`: `Digital output`.
* `Initial state`: `Low`.
* `msg.payload` должен быть `true`/`false`.
* Узел `Catch`: Настроен на перехват ошибок от всех узлов на вкладке.
* Узел `Function: Log Error`:
// Форматирование ошибки для логирования по контракту
// Контракт сообщения об ошибке: { "error_message": "...", "node_id": "...", "node_name": "...", "original_msg": {...}, "timestamp": ... }
msg.payload = {
error_message: msg.error.message,
node_id: msg.error.node.id,
node_name: msg.error.node.name,
original_msg: msg.error, // Сохраняем оригинальное сообщение об ошибке для полной диагностики
timestamp: Date.now()
};
msg.topic = "hi/system/logs/error";
return msg;
* Узел `mqtt out`: Публикует отформатированное сообщение об ошибке в топик `hi/system/logs/error`.
2. Рациональное управление водными ресурсами
Задача: Создать систему автоматического полива газона, которая учитывает не только влажность почвы, но и прогноз погоды, чтобы избежать бесполезного расхода воды перед дождем. Оборудование:- Контроллер HI.
- Аналоговый датчик влажности почвы (выход 0-10V или "сухой контакт").
- Электромагнитный клапан на 24V DC для управления подачей воды.
- Блок питания 24V DC.
//============ WIRING-WATER-003: Smart Irrigation System ==============
// Датчик влажности почвы (аналоговый 0-10V)
[CTRL:HI-Core] (SENS:SOIL-01)
+24V (от PSU) ---- (Красный) ----------------- V+
GND (от PSU) ----- (Черный) ----------------- GND
(UI-05) --- (Оранжевый) ---- OUT (0-10V)
(GND) ----- (Черный) ------- GND (общий с сигналом)
// Электромагнитный клапан (24V DC)
[PSU:24VDC] [CTRL:HI-Core]
+24V --(+)------- C (RL-12)
NO (RL-12) ---------------- + (Клапан)
GND --(-)----------------------------------- - (Клапан)
Логика в Node-RED: FLOW-WATER-IRRIG-002 (Паттерн "Конечный автомат")
Этот поток использует `flow context` для хранения состояния системы (`IDLE`, `WATERING`, `WAITING_DUE_TO_RAIN`).
// Flow: Умный полив газона с учетом прогноза погоды
//
// [Inject: 1 hour] -> [Function: Prepare Data] --+--> [HTTP Request: Weather API] --+
// | |
// +--> [rpi gpio in: UI-05] --------+--> [Join: Weather & Soil] --> [Function: FSM Irrigation Logic] --> [rpi gpio out: RL-12]
// |
// +--> [Debug]
//
// [Catch] -> [Function: Log Error] -> [mqtt out: errors]
* Узел `Inject` раз в час запускает проверку.
* Узел `Function: Prepare Data`:
// Подготавливает msg для запроса погоды и чтения датчика
// Контракт сообщения: { "url": "...", "payload": {} }
msg.url = "http://api.openweathermap.org/data/2.5/weather?lat=55.75&lon=37.61&appid=YOUR_API_KEY&units=metric"; // Замените на реальные координаты и ключ API
msg.payload = {}; // Инициализируем payload
return msg;
* Узел `HTTP Request`: Отправляет запрос к бесплатному погодному API (например, OpenWeatherMap) для получения прогноза на ближайшие 3 часа.
* `Method`: `GET`
* `URL`: `msg.url`
* `Return`: `a parsed JSON object`
* `Name`: "Get Weather Forecast"
* Выход `msg.payload` будет содержать JSON-объект с данными о погоде.
* Узел `rpi gpio in` (для датчика влажности):
* `Pin`: `UI-05` (универсальный вход).
* `Type`: `Analog input (0-10V)`.
* `Name`: "Датчик влажности почвы".
* Выход `msg.payload` будет содержать значение от 0 до 1023 (для 10-битного АЦП) или 0-4095 (для 12-битного). Необходимо будет масштабировать в проценты.
* Узел `Join: Weather & Soil`: Объединяет сообщения от погодного API и датчика влажности.
* `Mode`: `manual`
* `Property`: `msg.topic`
* `Output`: `a single message`
* `Join`: `msg.payload`
* `Timeout`: `5` seconds (если одно из сообщений не пришло).
* `Name`: "Join Weather & Soil"
* Важно: Для корректной работы, `msg.topic` от `HTTP Request` и `rpi gpio in` должны быть разными, чтобы `Join` мог их различить. Например, `msg.topic = "weather"` и `msg.topic = "soil"`.
// Узел: "FSM: Irrigation Logic"
// Хранит состояние в flow.irrigation_state
// Вход: msg.payload = { weather: {...}, soil_raw: 512 } (после Join)
// Контракт исходящего сообщения: { "value": true/false, "source": "irrigation_fsm", "ts": ... }
const DRY_THRESHOLD_PERCENT = 30; // % влажности, ниже которого нужно поливать
const RAIN_FORECAST_THRESHOLD_MM = 0.5; // мм осадков, при которых отменяем полив
const ANALOG_MAX_VALUE = 1023; // Максимальное значение АЦП для UI-05 (зависит от контроллера)
let state = flow.get("irrigation_state") || "IDLE";
let soil_raw_value = msg.payload.soil_raw; // Предполагаем, что Join объединил как { "soil_raw": ..., "weather": ... }
let weather_data = msg.payload.weather;
// Масштабирование аналогового значения в проценты влажности (пример)
// Предполагаем, что 0V = 0% влажности, 10V = 100% влажности
let soil_moisture_percent = (soil_raw_value / ANALOG_MAX_VALUE) * 100;
// Проверка прогноза дождя
let is_rain_forecasted = false;
if (weather_data && weather_data.rain && weather_data.rain['1h'] > RAIN_FORECAST_THRESHOLD_MM) {
is_rain_forecasted = true;
}
let output_command = "OFF"; // По умолчанию выключено
switch (state) {
case "IDLE":
if (soil_moisture_percent < DRY_THRESHOLD_PERCENT && !is_rain_forecasted) {
state = "WATERING";
output_command = "ON";
node.warn("Почва сухая, дождя нет. Начинаем полив.");
} else if (is_rain_forecasted) {
state = "WAITING_DUE_TO_RAIN";
node.warn("Прогнозируется дождь. Откладываем полив.");
}
break;
case "WATERING":
// Логика остановки полива:
// 1. Если влажность достигла нужного уровня (например, 70%)
// 2. Или если полив длится слишком долго (например, 30 минут - нужен таймер, реализуется отдельным узлом)
// 3. Или если вдруг пошел дождь
if (soil_moisture_percent >= (DRY_THRESHOLD_PERCENT + 10) || is_rain_forecasted) { // Гистерезис
state = "IDLE";
output_command = "OFF";
node.warn("Полив завершен или отменен из-за дождя.");
} else {
output_command = "ON"; // Продолжаем полив
}
break;
case "WAITING_DUE_TO_RAIN":
if (!is_rain_forecasted) {
state = "IDLE"; // Дождя больше не ожидается, возвращаемся к проверке
node.warn("Дождь не прогнозируется. Возвращаемся в IDLE.");
}
break;
}
flow.set("irrigation_state", state); // Сохраняем текущее состояние
node.status({text: `State: ${state}, Soil: ${soil_moisture_percent.toFixed(1)}%, Rain: ${is_rain_forecasted ? 'Yes' : 'No'}`});
// Формируем сообщение для управления клапаном по контракту
msg.payload = {
value: (output_command === "ON"), // true/false
source: "irrigation_fsm",
ts: Date.now()
};
msg.topic = "commands/irrigation/valve/set";
return msg;
* Важно: Для корректной работы FSM, узел `Function` должен получать оба значения (влажность и прогноз погоды) в одном `msg`. Используйте узел `Join` для объединения сообщений от датчика и HTTP-запроса.
* Узел `rpi gpio out` (для управления клапаном):
* `Pin`: `RL-12` (или соответствующий номер реле).
* `Type`: `Digital output`.
* `Initial state`: `Low`.
* `msg.payload` должен быть `true`/`false`.
Экологические вызовы и методы их минимизации на платформе HI
Инженерное проектирование должно учитывать и минимизировать негативное влияние IoT.
Увеличение количества электронных отходов (E-waste)
⚠️ Проблема: Короткий жизненный цикл многих IoT-устройств приводит к их быстрому устареванию и выбросу.
💡 Решение на платформе HI:
- Долговечность и модульность: Контроллер HI спроектирован для длительной эксплуатации (5-10 лет) в промышленных условиях. Вместо замены всего устройства при изменении требований, инженер обновляет программную логику в Node-RED.
- Использование стандартных протоколов: Благодаря поддержке Modbus, CAN, DALI, вы не привязаны к одному производителю датчиков. Если датчик вышел из строя или устарел, его можно заменить на любой другой совместимый, не меняя центральный контроллер и логику.
- Программное обновление: Функционал контроллера расширяется через обновления ПО (Debian, Node.js, Node-RED), а не заменой "железа".
Повышенное энергопотребление
⚠️ Проблема: Миллиарды подключенных устройств потребляют электроэнергию, увеличивая углеродный след.
💡 Решение на платформе HI:
- Низкое энергопотребление контроллера: Сам контроллер построен на энергоэффективной ARM-архитектуре, его собственное потребление минимально (порядка 5-10 Вт).
- Оптимизация опроса: Не опрашивайте устройства без необходимости. Для инертных процессов (температура в комнате, влажность почвы) достаточно интервала в 1-5 минут. Слишком частый опрос по Modbus или другим шинам бесполезно тратит энергию и загружает сеть.
- Сценарии энергосбережения: Используйте Node-RED для создания логики, которая активно экономит энергию. Пример: сценарий "Никого нет дома" отключает не только свет, но и питание всех второстепенных потребителей (медиацентры, зарядные устройства) через реле контроллера.
- Использование энергоэффективных протоколов: При работе с беспроводными датчиками (опции LoRaWAN, Zigbee) настраивайте их на работу в "спящем" режиме с редкой отправкой данных для максимальной экономии заряда батарей.
Заключение
Ответственный подход к проектированию IoT-систем позволяет превратить их в эффективный инструмент для создания устойчивой и экологичной среды. Инженер, использующий платформу HI, обладает всеми необходимыми средствами для реализации "зеленых" сценариев: от гибкой логики в Node-RED для экономии ресурсов до поддержки стандартных протоколов, обеспечивающих долговечность и ремонтопригодность системы.
---
Лабораторные работы
COURSE-16-M05-LAB13: Создание системы мониторинга CO₂ и журналирование данных
Задача: Настроить поток Node-RED, который считывает данные с (симулированного) Modbus-датчика CO₂, валидирует их, отображает статус и записывает каждое измерение в базу данных MySQL на контроллере. Скелет потока: `[Inject]` -> `[Modbus Getter]` -> `[Function: Validate]` -> `[MySQL Out]`. Дополнительно подключить `[Catch]` для логирования ошибок. Flow Diagram (ASCII):[Inject: 1 min] --> [Modbus-Getter: Simulate CO2] --> [Function: Validate & Format] --> [MySQL Out: telemetry_log]
|
+--> [Debug]
|
+--> [Catch: All Nodes] --> [Function: Format Error] --> [MySQL Out: error_log]
Описание узлов:
* Используйте узел `modbus-flex-getter` или `modbus-read` с настроенным Modbus-клиентом.
* Для симуляции можно использовать узел `Function` перед `Validate & Format`, который генерирует случайное число в диапазоне CO₂.
// Function: Simulate Modbus CO2
// Контракт исходящего сообщения: { "payload": { "data": [1234] } }
msg.payload = { data: [Math.floor(Math.random() * (1500 - 400 + 1)) + 400] }; // CO2 от 400 до 1500 ppm
return msg;
// Узел: "Validate & Format CO2 for DB"
// Вход: msg.payload от Modbus-узла, например { data: [1150], buffer: }
// Контракт исходящего сообщения: { "payload": { "value": 1150, "unit": "ppm", "source": "modbus-sensor-office-1", "timestamp": "..." }, "topic": "INSERT INTO ..." }
if (!msg.payload || !Array.isArray(msg.payload.data) || msg.payload.data.length === 0) {
node.status({fill:"red", shape:"dot", text:"No data"});
node.error("Некорректный формат данных от Modbus-датчика", msg);
return null;
}
const co2_level = msg.payload.data[0];
if (isNaN(co2_level) || co2_level < 400 || co2_level > 5000) {
node.status({fill:"red", shape:"dot", text:"Invalid CO2: " + co2_level});
node.error("Некорректное значение CO2: " + co2_level, msg);
return null;
}
// Формирование по контракту сообщения для MySQL
msg.payload = {
value: co2_level,
unit: "ppm",
source: "modbus-sensor-office-1",
timestamp: new Date().toISOString() // ISO формат для MySQL DATETIME
};
msg.topic = "INSERT INTO telemetry_log (value, unit, source, timestamp) VALUES (?, ?, ?, ?)"; // SQL-запрос
node.status({fill:"green", shape:"dot", text: co2_level + " ppm"});
return msg;
* Настройте подключение к локальной базе данных MySQL на контроллере HI.
* `Name`: `telemetry_log`
* `Query`: `msg.topic`
* `Parameters`: `msg.payload.value, msg.payload.unit, msg.payload.source, msg.payload.timestamp`
* Предварительно создайте таблицу:
CREATE TABLE IF NOT EXISTS telemetry_log (
id INT AUTO_INCREMENT PRIMARY KEY,
value FLOAT,
unit VARCHAR(10),
source VARCHAR(50),
timestamp DATETIME
);
// Форматирование ошибки для записи в MySQL по контракту
// Контракт исходящего сообщения: { "payload": { "error_message": "...", "node_id": "...", "node_name": "...", "original_msg_payload": "...", "timestamp": "..." }, "topic": "INSERT INTO ..." }
msg.payload = {
error_message: msg.error.message,
node_id: msg.error.node.id,
node_name: msg.error.node.name,
original_msg_payload: JSON.stringify(msg.error.message), // Сохраняем оригинальное сообщение
timestamp: new Date().toISOString()
};
msg.topic = "INSERT INTO error_log (error_message, node_id, node_name, original_msg_payload, timestamp) VALUES (?, ?, ?, ?, ?)";
return msg;
* Настройте подключение к локальной базе данных MySQL.
* `Name`: `error_log`
* `Query`: `msg.topic`
* `Parameters`: `msg.payload.error_message, msg.payload.node_id, msg.payload.node_name, msg.payload.original_msg_payload, msg.payload.timestamp`
* Предварительно создайте таблицу:
CREATE TABLE IF NOT EXISTS error_log (
id INT AUTO_INCREMENT PRIMARY KEY,
error_message TEXT,
node_id VARCHAR(50),
node_name VARCHAR(100),
original_msg_payload TEXT,
timestamp DATETIME
);
Критерии оценки:
COURSE-16-M05-LAB14: Разработка сценария умного отключения розеток
Задача: Создать субпоток (subflow) для управления группой розеток. Субпоток должен принимать на вход команду `ON`/`OFF`. Дополнительно, реализовать логику: если в течение 2 часов не было зафиксировано движение ни от одного из трех (симулированных) датчиков движения, все розетки автоматически отключаются для экономии энергии. Flow Diagram (ASCII):// Main Flow:
[MQTT In: motion/sensor1] --+
[MQTT In: motion/sensor2] ---+--> [Join: 3 inputs] --> [Trigger: 2 hours, reset on msg] --> [Change: Set OFF] --> [Link Out: To Subflow Control]
[MQTT In: motion/sensor3] --+
[Inject: Manual ON] --> [Change: Set ON] --> [Link Out: To Subflow Control]
[Inject: Manual OFF] -> [Change: Set OFF] -> [Link Out: To Subflow Control]
// Subflow: "Manage Power Sockets" (FLOW-AUTO-POWER-001)
[Link In: From Subflow Control] --> [Function: Validate Command] --> [rpi gpio out: RL-01]
[rpi gpio out: RL-02]
[rpi gpio out: RL-03]
|
+--> [Status]
Описание узлов:
* `Topic`: `telemetry/motion/sensor1`, `telemetry/motion/sensor2`, `telemetry/motion/sensor3`.
* `Payload`: `true` (движение обнаружено).
* Эти узлы симулируют датчики движения.
* `Mode`: `manual`
* `Count`: `3` (или `wait for a specified time` с коротким таймаутом).
* `Output`: `a single message`
* `Join`: `msg.payload`
* Цель: объединить сообщения от датчиков движения, чтобы любое из них сбрасывало таймер.
* `Send nothing, then send`: `msg.payload` `false` (для отключения розеток).
* `After`: `2` `hours`.
* `Extend delay if new message arrives`: `checked`.
* Этот узел будет ждать 2 часа, прежде чем отправить `false`. Любое входящее сообщение от датчиков движения сбросит таймер.
* `Set`: `msg.payload`
* `to the value`: `false` (boolean)
* `Set`: `msg.topic`
* `to the value`: `commands/sockets/all/set`
* `Payload`: `true` или `false`.
* `Topic`: `commands/sockets/all/set`.
// Узел: "Validate Command for Sockets"
// Вход: msg.payload = true/false, msg.topic = commands/sockets/all/set
// Контракт исходящего сообщения: { "payload": true/false, "topic": "commands/sockets/all/set", "source": "socket_control" }
if (typeof msg.payload !== 'boolean' || msg.topic !== 'commands/sockets/all/set') {
node.status({fill:"red", shape:"dot", text:"Invalid command"});
node.error("Получена некорректная команда для управления розетками", msg);
return null;
}
// Устанавливаем статус для субпотока
node.status({fill: msg.payload ? "green" : "red", shape:"dot", text: msg.payload ? "ON" : "OFF"});
// Формируем исходящее сообщение по контракту
msg.payload = {
value: msg.payload,
source: "socket_control",
ts: Date.now()
};
// msg.topic остается commands/sockets/all/set
return msg;
* `Pin`: `RL-01`, `RL-02`, `RL-03` (или другие реле, к которым подключены розетки).
* `Type`: `Digital output`.
* `Initial state`: `Low`.
* `msg.payload.value` должен быть `true`/`false`.
* Подключите все три узла к выходу `Function: Validate Command`.
Тест для самопроверки
COURSE-16-M05-QUIZ
a) Для экономии памяти контроллера.
b) Для предотвращения частых переключений оборудования.
c) Для более точного измерения.
d) Для соответствия протоколу Modbus.
a) К клемме GND на обоих концах шины.
b) К клемме PE (заземление) на обоих концах.
c) К клемме GND только со стороны контроллера.
d) Не подключать вообще.
a) Контракт сообщения.
b) Конечный автомат (FSM).
c) Визуальный статус.
d) Централизованный обработчик ошибок.
a) Использовать самые дешевые датчики и менять их каждый год.
b) Использовать проприетарные протоколы от одного производителя.
c) Выбирать оборудование с длительным сроком службы и поддержкой стандартных протоколов (Modbus, CAN).
d) Программировать всю логику на низком уровне (C++).
a) Проигнорировать и передать дальше.
b) Заменить на последнее известное корректное значение.
c) Прервать поток (вернуть `null`) и сгенерировать ошибку через `node.error()`.
d) Перезагрузить контроллер.
a) Для измерения уровня воды.
b) Для подачи питания 24V DC на электромагнитный клапан.
c) Для чтения данных с датчика влажности.
d) Для подключения к шине RS-485.
a) `Status`
b) `Link In`
c) `Catch`
d) `Switch`
a) 10 раз в секунду.
b) 1 раз в секунду.
c) 1 раз в 30-60 секунд.
d) 1 раз в час.
a) `value`
b) `source`
c) `ts` (timestamp)
d) `unit` (единица измерения)
a) Система не сможет включить клапан.
b) Система может потратить воду впустую, включив полив перед дождем.
c) Датчик влажности выйдет из строя.
d) Контроллер перегреется.
(Ответы: 1-b, 2-c, 3-b, 4-c, 5-c, 6-b, 7-c, 8-c, 9-d, 10-b)Мини-Runbook: "Если не работает"
Проблема: Датчик CO₂ (Modbus) не отдает данные или показывает ошибку "timeout".
* Питание: Убедитесь, что на датчик подается питание 24V DC. Проверьте индикаторы на его корпусе.
* Шина RS-485: Проверьте правильность подключения проводов A, B, GND согласно схеме `WIRING-ENV-AIR-001`. Попробуйте поменять A и B местами — это частая ошибка.
* Терминатор: Убедитесь, что терминальный резистор 120 Ом включен только на крайних устройствах шины.
* Статус узла: Посмотрите на статус узла `Modbus-Read`. Он показывает "active", "connecting" или "error"?
* Конфигурация клиента: Откройте настройки Modbus-клиента. Убедитесь, что выбран правильный COM-порт (`/dev/ttyS1`, `/dev/ttyUSB0` и т.д.), скорость, четность и стоп-биты соответствуют настройкам датчика.
* Настройки узла: Проверьте, что в узле `Modbus-Read` указан правильный `Unit-ID` (Slave ID) датчика (например, `15`). Проверьте адрес регистра (например, `100`) и функцию чтения (например, `FC 3: Read Holding Registers`).
* Подключите узел `Debug` к выходу узла `Catch`. Какие сообщения об ошибках он показывает? `CRC Error` указывает на проблемы с качеством линии, `Timeout` — на неверный адрес или отсутствие ответа.
* Используйте внешний Modbus-сканер (например, Modbus Poll на ПК с USB-RS485 адаптером) для проверки связи с датчиком напрямую, минуя Node-RED. Это поможет локализовать проблему: в проводке/датчике или в конфигурации Node-RED.
Проблема: Вентилятор/клапан не включается, хотя логика в Node-RED отрабатывает.
* Подключите узел `Debug` к выходу узла `rpi gpio out`, который должен управлять реле. Убедитесь, что он отправляет правильную команду (`true`/`false` для `msg.payload.value`).
* Проверьте, что узел `rpi gpio out` настроен на правильный номер реле (например, `RL-10` для вентилятора, `RL-12` для клапана).
* Индикация на контроллере: Посмотрите на светодиодный индикатор соответствующего реле на корпусе контроллера HI. Загорается ли он в момент отправки команды?
* Если индикатор горит: Проблема во внешней цепи.
* Проверьте подключение проводов к клеммам реле (C и NO) согласно схемам `WIRING-ENV-AIR-001` или `WIRING-WATER-003`.
* Проверьте целостность цепи до самого вентилятора/клапана.
* Убедитесь в наличии питания 230V AC (для вентилятора) или 24V DC (для клапана) на соответствующих клеммах.
* Проверьте работоспособность самого вентилятора/клапана, подав на него питание напрямую (если это безопасно).
* Если индикатор не горит: Проблема в логике или конфигурации Node-RED.
* Убедитесь, что узел `rpi gpio out` настроен на правильный номер выхода (`RL-10`, `RL-12` и т.д.).
* Проверьте, что `msg.payload.value` приходит в виде булевого значения (`true`/`false`), а не строки или числа.