ГлавнаяАкадемияДатчики и входы: нормализация сигналов → Опрос датчиков в Node-RED: поиск устройств и чтение значений

Опрос датчиков в Node-RED: поиск устройств и чтение значений

Урок 4 · Датчики и входы: нормализация сигналов · 30 мин · theory

Введение: 1-Wire в экосистеме Node-RED на контроллерах HI

Протокол 1-Wire представляет собой уникальное решение для подключения множества устройств, в первую очередь датчиков, по общей трех- или даже двухпроводной шине. Как мы рассматривали в предыдущих уроках, каждое устройство на шине имеет уникальный 64-битный адрес, что позволяет контроллеру обращаться к ним индивидуально. Особенность интеграции 1-Wire в контроллеры HI на базе Linux заключается в том, что операционная система предоставляет доступ к этим устройствам через специальную файловую систему.

Это означает, что для программного обеспечения, такого как Node-RED, каждый датчик на шине выглядит как обычная папка, а его данные — как текстовый файл внутри этой папки. Такой подход значительно упрощает взаимодействие: вместо сложных протокольных обменов на низком уровне мы можем использовать стандартные системные команды для чтения информации.

> 🔗 Связанный материал: Убедитесь, что вы изучили материал урока COURSE-04-M06-L04 "Конфигурация 1-Wire интерфейса в системе". Данный урок предполагает, что шина уже настроена на уровне операционной системы и готова к использованию.

В этой экосистеме Node-RED выступает в роли прикладного уровня (L7). Его задача — оркестрировать процесс:

  • Периодически выполнять системные команды для чтения "файлов" датчиков.
  • Получать текстовые данные ("сырые" значения).
  • Разбирать (парсить) этот текст, проверяя его целостность.
  • Преобразовывать сырые значения в понятный человеку формат (например, в градусы Цельсия).
  • Передавать обработанные данные дальше — в системы логирования, на дашборды, в MQTT-топики или для управления исполнительными устройствами.
  • Для решения этих задач в данном уроке мы будем использовать базовый, но очень мощный набор узлов Node-RED:

    Цель этого урока — научить вас строить надежный и воспроизводимый поток для считывания данных с популярных датчиков температуры DS18B20, используя стандартные возможности контроллера HI и Node-RED.

    ---

    Секция 1: Поиск устройств на шине (Device Discovery)

    Прежде чем считывать данные с конкретного датчика, необходимо узнать его уникальный идентификатор (ID). Операционная система Linux автоматически выполняет обнаружение устройств (discovery) при их подключении к шине 1-Wire и создает для каждого из них отдельную директорию.

    Все обнаруженные устройства доступны в системной директории `/sys/bus/w1/devices/`. Содержимое этой директории представляет собой список всех "ведомых" (slave) устройств, подключенных к шине.

    Чтобы получить этот список в Node-RED, мы можем использовать узел Exec для выполнения стандартной команды Linux `ls`.

    Практикум: Обнаружение 1-Wire устройств

  • Создайте новый поток в Node-RED.
  • Добавьте узел Inject. Настройте его для отправки сообщения один раз при запуске. Это будет наша "кнопка" для запуска поиска.
  • Добавьте узел Exec. В поле "Команда" введите следующую команду:
  •     ls /sys/bus/w1/devices

    Убедитесь, что опция "Добавить к сообщению" установлена в `payload`.

  • Добавьте узел Debug и соедините его с первым выходом (stdout) узла Exec.
  • Разверните (Deploy) поток и нажмите на кнопку узла Inject.
  • В окне отладки вы увидите `msg.payload`, содержащий строку, подобную этой:

    28-01193a79f17d
    

    28-01193a8479e9

    w1_bus_master1

    Это и есть список устройств на вашей шине.

    > 💡 Подсказка: Чтобы сопоставить физический датчик с его ID в системе, можно поочередно нагревать датчики (например, пальцем) и отслеживать, значение с какого ID меняется в реальном времени. Этот метод мы применим в следующих секциях.

    Анализ результата

    На данном этапе крайне важно задокументировать, какой физический датчик какому ID соответствует. Например, в проектной документации или прямо в комментариях в Node-RED:

    | ID устройства | Физическое расположение |

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

    | `28-01193a79f17d` | Температура в гостиной |

    | `28-01193a8479e9` | Температура на улице |

    Этот простой шаг сэкономит массу времени при дальнейшей настройке и обслуживании системы. Ошибочная идентификация датчиков — одна из самых частых проблем на этапе пусконаладки.

    ---

    Секция 2: Структура файла данных датчика и чтение 'сырых' значений

    После того как мы обнаружили ID нужного нам датчика, мы можем прочитать с него данные. Как упоминалось ранее, система представляет данные от датчика в виде специального файла с именем w1_slave. Этот файл находится внутри директории, соответствующей ID датчика.

    Полный путь к файлу с данными для датчика с ID `28-01193a79f17d` будет выглядеть так:

    `/sys/bus/w1/devices/28-01193a79f17d/w1_slave`

    Чтобы прочитать содержимое этого файла, используется стандартная команда Linux `cat`.

    Формат файла `w1_slave`

    Содержимое этого файла — это обычный текст, состоящий из двух строк. Давайте рассмотрим пример вывода команды `cat` для файла `w1_slave`:

    cat /sys/bus/w1/devices/28-01193a79f17d/w1_slave
    

    Результат в `msg.payload` будет выглядеть так (в виде одной строки с символом переноса `\n`):

    79 01 4b 46 7f ff 0c 10 31 : crc=31 YES
    

    79 01 4b 46 7f ff 0c 10 31 t=23562

    Разберем эти строки:

  • Первая строка: `79 01 4b 46 7f ff 0c 10 31 : crc=31 YES`
  • * `79 01 ... 10 31`: Это сырые данные, считанные из памяти датчика. Для нас они не представляют прямого интереса.

    * `crc=31`: Это контрольная сумма (CRC), вычисленная на основе сырых данных.

    * `YES`: Это — самый важный флаг. Он означает, что контрольная сумма, вычисленная контроллером, совпала с контрольной суммой, переданной датчиком. Чтение успешно.

  • Вторая строка: `79 01 4b 46 7f ff 0c 10 31 t=23562`
  • * Данные здесь дублируются.

    * `t=23562`: Это и есть "сырое" значение температуры. Это целочисленное значение, которое необходимо разделить на 1000, чтобы получить температуру в градусах Цельсия. В данном случае `23562 / 1000 = 23.562 °C`.

    > ⚠️ Внимание: Всегда проверяйте результат CRC. Если первая строка содержит `NO`, данные во второй строке некорректны и не должны использоваться. Это может указывать на проблемы с линией связи (помехи, плохой контакт, превышение длины) или питанием датчика, как было рассмотрено в уроке `COURSE-04-M06-L03`. Игнорирование проверки CRC — прямой путь к ненадёжной работе системы.

    Если чтение не удалось (например, из-за помех), вывод может выглядеть так:

    79 01 4b 46 7f ff 0c 10 31 : crc=31 NO
    

    79 01 4b 46 7f ff 0c 10 31 t=23562

    Несмотря на наличие значения `t=...`, его использование недопустимо, так как целостность данных не подтверждена.

    ---

    Секция 3: Практикум: Создание потока для чтения и парсинга данных DS18B20

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

    Пошаговое создание потока

  • Узел `Inject`. Добавьте его на холст. В настройках установите `Repeat` в режим `interval` и задайте интервал, например, `10` секунд. Это обеспечит периодический опрос датчика.
  • Узел `Exec`. Добавьте его и соедините с узлом `Inject`. В поле "Команда" впишите команду `cat` с полным путём к вашему датчику. Замените `28-xxxxxxxxxxxx` на ID, который вы определили в Секции 1.
  •     cat /sys/bus/w1/devices/28-xxxxxxxxxxxx/w1_slave

    Для второго и третьего выхода (`stderr` и `code`) узла `Exec` добавьте узлы `Debug`, чтобы видеть возможные ошибки выполнения команды (например, если ID датчика введён неверно).

  • Узел `Function`. Это сердце нашего процесса. Соедините первый выход узла `Exec` со входом узла `Function`. Дайте ему имя, например, "Парсинг DS18B20". Вставьте следующий JavaScript код:
  •     // Получаем сырые данные из payload в виде строки

    const rawData = msg.payload;

    // 1. Проверяем, что данные не пустые

    if (!rawData) {

    node.error("Пустой payload от узла Exec", msg);

    node.status({fill:"red", shape:"dot", text:"Пустой payload"});

    return null; // Останавливаем поток

    }

    // 2. Проверяем целостность данных (CRC)

    if (rawData.indexOf('YES') === -1) {

    node.warn("Ошибка CRC или некорректные данные", msg);

    node.status({fill:"red", shape:"dot", text:"Ошибка CRC"});

    return null; // Останавливаем поток, если CRC не пройдена

    }

    // 3. Ищем позицию 't='

    const tempPosition = rawData.indexOf('t=');

    if (tempPosition === -1) {

    node.error("Не удалось найти 't=' в строке данных", msg);

    node.status({fill:"red", shape:"dot", text:"Формат нарушен"});

    return null; // Останавливаем поток

    }

    // 4. Извлекаем и преобразуем значение

    try {

    // Берем подстроку после 't='

    const tempString = rawData.substring(tempPosition + 2);

    // Преобразуем в число и делим на 1000

    const temperature = parseInt(tempString, 10) / 1000.0;

    // Валидация значения (DS18B20 работает от -55 до +125)

    if (temperature < -55 || temperature > 125) {

    node.warn("Температура вне допустимого диапазона: " + temperature, msg);

    node.status({fill:"yellow", shape:"ring", text:"Недостоверное значение"});

    return null;

    }

    // 5. Формируем новое сообщение по стандарту "Контракт сообщения"

    msg.payload = {

    "value": temperature,

    "unit": "°C",

    "source": "28-xxxxxxxxxxxx", // Замените на ID вашего датчика

    "ts": Date.now()

    };

    // Устанавливаем визуальный статус для быстрой диагностики

    node.status({fill:"green", shape:"dot", text: temperature.toFixed(2) + " °C"});

    return msg;

    } catch (e) {

    node.error("Ошибка при парсинге температуры", { original_msg: msg, error: e });

    node.status({fill:"red", shape:"dot", text:"Ошибка парсинга"});

    return null;

    }

    > 💡 Подсказка: Для проектов с множеством датчиков вы можете сделать этот поток более динамичным. Передавайте ID датчика в `msg.topic` и используйте его для формирования команды в узле Exec с помощью синтаксиса `{{{topic}}}`. Это позволит создать один переиспользуемый субпоток (subflow) для всех датчиков.

  • Узел `Debug`. Подключите`Debug` к выходу узла `Function`. Теперь, каждые 10 секунд, вы будете видеть в окне отладки структурированный JSON-объект, готовый к дальнейшему использованию.
  • Пример успешного `msg.payload` на выходе:

        {

    "value": 23.562,

    "unit": "°C",

    "source": "28-01193a79f17d",

    "ts": 1678886400000

    }

    Такой формат легко обрабатывать, логировать в базу данных MySQL или отправлять по MQTT.

    ---

    Секция 4: Резюме и лучшие практики

    В этом уроке мы прошли полный цикл работы с датчиком температуры DS18B20 на контроллере HI: от обнаружения его на шине до создания автоматического потока опроса и обработки данных в Node-RED.

    Ключевые этапы, которые мы освоили:
  • Обнаружение: Использование команды `ls /sys/bus/w1/devices` через узел `Exec` для получения списка уникальных ID всех устройств на шине.
  • Чтение: Применение команды `cat` для чтения содержимого файла `w1_slave`, в котором находятся сырые данные и флаг проверки целостности.
  • Парсинг и Валидация: Написание логики на JavaScript в узле `Function` для проверки CRC, извлечения числового значения температуры и его преобразования в градусы Цельсия.
  • Использование: Форматирование данных в стандартный, структурированный JSON-объект (согласно паттерну "Контракт сообщения"), удобный для дальнейшей интеграции.
  • Рекомендации и лучшие практики

    > ℹ️ Информация: Использование узла `Exec` — это базовый, но достаточно ресурсоемкий метод. Он отлично подходит для небольшого количества датчиков и для изучения принципов работы. В курсах продвинутого уровня (`automation` и `integration`) мы рассмотрим альтернативные, более производительные способы работы с 1-Wire, например, через специализированные узлы Node-RED (если они доступны) или через промежуточные скрипты, публикующие данные напрямую в MQTT.

    Что дальше

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