Подключение датчиков типа 'сухой контакт'
id: COURSE-01-M03-L01
title: Подключение датчиков типа 'сухой контакт'
level: foundation
tags: [hardware, input, dry-contact, sensor, wiring, mqtt, node-red]
prerequisites: [COURSE-01-M03-L00]
version: 1.0
status: published
# Урок: Подключение датчиков типа 'сухой контакт'
В этом уроке мы детально разберем один из самых распространенных и надежных типов датчиков в системах автоматизации — датчики с выходом типа "сухой контакт". Вы научитесь правильно их подключать к контроллеру, считывать их состояние и создавать базовую логику для реагирования на события.
COURSE-01-M03-L01-S01: Введение в 'сухие контакты'
> 💡 Подсказка: Термин 'сухой контакт' является отраслевым стандартом де-факто для обозначения беспотенциальных контактов реле или выходов датчиков. Его также называют "потенциально-свободный контакт".
В основе своей, "сухой контакт" — это просто переключатель, который не имеет собственного источника питания. Он либо замыкает, либо размыкает электрическую цепь, которую предоставляет внешнее устройство — в нашем случае, контроллер.
📋 Ключевые понятия:
- Сухой контакт (Dry Contact): Физический интерфейс (например, два винтовых зажима на датчике), который не подает собственное напряжение. Его задача — только замыкать или размыкать внешнюю низковольтную цепь.
- Мокрый контакт (Wet Contact): Противоположность "сухому". Этот тип выхода сам генерирует напряжение при срабатывании (например, подает +12В или +24В на выходной контакт). Подключение такого выхода к входу, предназначенному для "сухого контакта", приведет к повреждению контроллера.
Нормально открытые (NO) и нормально закрытые (NC) контакты
Понимание этой разницы критически важно для построения надежных систем, особенно систем безопасности.
* Состояние покоя: Контакт разомкнут. Электрическая цепь разорвана.
* Состояние сработки (тревоги): Контакт замыкается. Цепь замыкается.
* Пример: Классическая кнопка звонка. Пока вы не нажали кнопку, цепь разомкнута. При нажатии — цепь замыкается, и звонок звонит.
* Состояние покоя: Контакт замкнут. Электрическая цепь замкнута.
* Состояние сработки (тревоги): Контакт размыкается. Цепь разрывается.
* Пример: Датчики охранной сигнализации (герконы на дверях, датчики разбития стекла). В состоянии покоя они образуют замкнутый шлейф. Если злоумышленник откроет дверь или перережет провод, цепь разорвется, что немедленно вызовет тревогу. Эта схема является "fail-safe" (отказобезопасной), так как обрыв линии связи эквивалентен сигналу тревоги.
Типовые устройства с выходом "сухой контакт"
- Герконы (магнитоконтактные датчики): Устанавливаются на двери и окна для определения их открытия/закрытия. Чаще всего используют NC-логику.
- Датчики движения (PIR-сенсоры): Многие модели охранных датчиков движения имеют релейный выход типа "сухой контакт" (часто NC) для интеграции в общую систему сигнализации.
- Кнопки и выключатели: Любая не-умная кнопка без собственной подсветки или логики является классическим примером "сухого контакта".
- Датчики протечки воды: Два электрода, которые замыкаются между собой при попадании на них воды. Это NO-датчик.
- Поплавковые датчики: Используются для контроля уровня жидкости в емкостях (например, в септике или резервуаре с водой). Могут быть как NO, так и NC.
COURSE-01-M03-L01-S02: Схемы подключения к контроллеру
> ⚠️ Внимание: Критически важно убедиться, что выход датчика действительно является 'сухим контактом'. Подача внешнего напряжения на дискретный вход 'DI' может повредить контроллер. Всегда сверяйтесь с документацией производителя датчика. Перед подключением можно "прозвонить" выходные контакты датчика мультиметром в режиме измерения сопротивления, чтобы убедиться в отсутствии напряжения.
Для подключения датчиков типа "сухой контакт" наш контроллер использует специальные дискретные входы (Digital Inputs).
Подключение к входам 'DI'
На клеммниках контроллера вы найдете группу входов, маркированных как `DIx` (например, `DI1_IN`, `DI2_IN`...) и землю `GND`. Схема подключения предельно проста:
+-----------------------+ +--------------------+
| | | |
| Контроллер | | Датчик ('сухой |
| | | контакт') |
| [DI1] o--------------------o [OUT 1] |
| | | |
| [GND] o--------------------o [OUT 2] |
| | | |
+-----------------------+ +--------------------+
Принцип работы:
Внутри контроллера каждый вход `DI` через резистор "подтянут" к внутреннему источнику питания (+3.3В или +5В). Это называется внутренний подтягивающий резистор (pull-up resistor).
- Когда контакт датчика разомкнут (NO в покое, NC в тревоге): На вход `DI` через этот резистор поступает напряжение. Контроллер считывает это как логическую '1' (высокий уровень).
- Когда контакт датчика замкнут (NO в тревоге, NC в покое): Вход `DI` напрямую соединяется с `GND` (землей, 0В). Ток начинает течь на землю, и напряжение на входе падает до нуля. Контроллер считывает это как логический '0' (низкий уровень).
Конфигурация универсальных входов ('A' и 'D')
Как мы рассматривали в уроке `[COURSE-01-M03-L00] Обзор 22 универсальных входов`, многие входы контроллера являются универсальными. Чтобы использовать их для подключения "сухого контакта", необходимо настроить их в правильный режим.
Порядок действий:После этого универсальный вход `A1` будет работать идентично специализированному входу `DI`, включая наличие внутреннего подтягивающего резистора. Схема подключения к нему будет такой же: один провод на клемму входа, второй — на `GND`.
COURSE-01-M03-L01-S03: Чтение состояний через MQTT
После физического подключения и настройки входа, контроллер начинает публиковать его состояние в локальный MQTT-брокер. Это позволяет любому сервису, включая Node-RED, отслеживать состояние датчика в реальном времени.
Структура MQTT-топиков
Драйвер `wb-mqtt-gpio`, отвечающий за работу с дискретными входами, использует стандартизированную структуру топиков:
`/devices/wb-gpio/controls/DIx_IN`
Где `DIx_IN` — это идентификатор конкретного входа (например, `DI1_IN`, `DI2_IN`, `A3`, `D5` и т.д.).
Сообщения (payload) в этом топике:- `'1'` — Контакт разомкнут. Для NO-датчика это состояние покоя, для NC-датчика — состояние тревоги.
- `'0'` — Контакт замкнут на землю. Для NO-датчика это состояние тревоги, для NC-датчика — состояние покоя.
Существует также "виртуальный" топик `/on`, который публикует `1` при сработке и `0` при возврате в норму, но для максимальной ясности и контроля мы рекомендуем работать с основным топиком и обрабатывать логику самостоятельно.
Работа в Node-RED
Для получения данных от датчика в Node-RED используется узел `mqtt in`.
* Сервер (Server): Выберите `localhost:1883` (или как настроен ваш MQTT-брокер).
* Тема (Topic): Укажите полный путь к топику вашего датчика, например: `/devices/wb-gpio/controls/DI3_IN`.
* QoS: `0` — для большинства задач мониторинга этого достаточно.
* Вывод (Output): `разобранный объект JSON` (a parsed JSON object) или `строка` (a string). Для простых значений '0'/'1' удобнее работать со строкой.
Теперь откройте панель отладки (Debug) справа. Попробуйте физически активировать ваш датчик (например, поднесите магнит к геркону или нажмите на кнопку). Вы должны увидеть входящие сообщения в панели отладки.
Пример сообщения в окне отладки:
{
"topic": "/devices/wb-gpio/controls/DI3_IN",
"payload": "0",
"qos": 0,
"retain": true,
"_msgid": "a1b2c3d4.e5f6g7"
}
Это сообщение показывает, что на входе `DI3` произошло замыкание на землю. Если вы отпустите кнопку, придет новое сообщение с `payload: "1"`. Этот простой тест является обязательным шагом при пусконаладке — он подтверждает, что и физическое подключение, и программная часть (драйвер, MQTT) работают корректно.
COURSE-01-M03-L01-S04: Пример: логика для датчика протечки
Рассмотрим практический сценарий: датчик протечки (NO-типа) подключен к входу `DI1`. При обнаружении воды он замыкает контакты, и мы должны немедленно отправить уведомление в Telegram.
> 💡 Подсказка: Используйте узел `rbe` (report by exception) сразу после узла `mqtt in`, чтобы поток обрабатывал только реальные изменения состояния датчика, игнорируя дублирующиеся сообщения, которые MQTT-брокер может присылать по разным причинам. Режим работы `rbe` — `block unless value changes`.
Построение потока в Node-RED
Базовая схема потока выглядит так:
[mqtt in]--->[rbe]--->[switch]--->[trigger]--->[function]--->[telegram sender]
|
+---->[debug]
Шаг 1: `mqtt in` (Датчик протечки Кухня)
- Topic: `/devices/wb-gpio/controls/DI1_IN`
- Как мы выяснили, сработка NO-датчика (протечка) — это замыкание, т.е. `payload: '0'`.
- Mode: `block unless value changes`. Этот узел пропустит сообщение дальше только в том случае, если его `msg.payload` отличается от предыдущего.
- Нам нужно реагировать только на событие протечки, а не на высыхание датчика.
- Property: `msg.payload`
- Rule: `==` (is equal to) `0` (как строка или число, в зависимости от настроек `mqtt in`). Это создаст один выход, который будет активен только при получении '0'.
- Если датчик будет "дребезжать" или вода будет попадать на него прерывисто, мы рискуем получить десятки уведомлений в секунду. Узел `trigger` решает эту проблему.
- Send: `the original message` (или можно сформировать простое сообщение, например, строку `ALARM`).
- then wait for: `5 minutes`.
- and then send: `nothing`.
- Handling: `extend delay if new message arrives`.
- Логика: При первом сообщении о протечке он немедленно пропустит его дальше. Затем запустится таймер на 5 минут. Любые новые сообщения, приходящие в течение этого времени, будут просто сбрасывать таймер, но не пройдут дальше. Это гарантирует, что мы получим одно уведомление в 5 минут, пока проблема не устранена.
- Создаем "контракт сообщения" для нашего сервиса уведомлений (в данном случае, для узла `node-red-contrib-telegrambot`).
// Получаем текущее время для лога
const timestamp = new Date().toLocaleString("ru-RU");
// Формируем объект payload, который понимает узел Telegram
msg.payload = {
// В реальном проекте chatId должен храниться в глобальных переменных
// или извлекаться из настроек
chatId: "-1234567890",
type: "message",
content: `🚨 ТРЕВОГА: ОБНАРУЖЕНА ПРОТЕЧКА! 🚨
Объект: Кухня
Датчик: Датчик протечки под раковиной (DI1)
Время: ${timestamp}
Необходимо срочно перекрыть воду и проверить место установки датчика.`
};
// Записываем событие в системный журнал для аудита
node.log({
event: "WATER_LEAK_ALARM",
source: "DI1",
timestamp: Date.now()
});
return msg;
Шаг 6: `telegram sender` (Отправка)
- Это конечный узел из пакета `node-red-contrib-telegrambot`, который принимает на вход `msg.payload` из предыдущего узла и отправляет сообщение.
[
{
"id": "c1f7a8b3.1e0858",
"type": "tab",
"label": "Урок: Датчик протечки",
"disabled": false,
"info": ""
},
{
"id": "a2b3c4d5.e6f7g8",
"type": "mqtt in",
"z": "c1f7a8b3.1e0858",
"name": "MQTT: Датчик протечки (DI1)",
"topic": "/devices/wb-gpio/controls/DI1_IN",
"qos": "0",
"datatype": "utf8",
"broker": "YOUR_MQTT_BROKER_ID",
"x": 190,
"y": 100,
"wires": [
[
"b3c4d5e6.f7g8h9"
]
]
},
{
"id": "b3c4d5e6.f7g8h9",
"type": "rbe",
"z": "c1f7a8b3.1e0858",
"name": "Фильтр дублей",
"func": "rbe",
"gap": "",
"start": "",
"inout": "out",
"property": "payload",
"x": 400,
"y": 100,
"wires": [
[
"c4d5e6f7.g8h9i0"
]
]
},
{
"id": "c4d5e6f7.g8h9i0",
"type": "switch",
"z": "c1f7a8b3.1e0858",
"name": "Сработка? (payload == '0')",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "0",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 620,
"y": 100,
"wires": [
[
"d5e6f7g8.h9i0j1"
]
]
},
{
"id": "d5e6f7g8.h9i0j1",
"type": "trigger",
"z": "c1f7a8b3.1e0858",
"name": "Защита от флуда (1/5 мин)",
"op1": "",
"op2": "",
"op1type": "pay",
"op2type": "nul",
"duration": "5",
"extend": true,
"units": "min",
"reset": "",
"bytopic": "all",
"topic": "topic",
"outputs": 1,
"x": 860,
"y": 100,
"wires": [
[
"e6f7g8h9.i0j1k2"
]
]
},
{
"id": "e6f7g8h9.i0j1k2",
"type": "function",
"z": "c1f7a8b3.1e0858",
"name": "Формирование уведомления",
"func": "const timestamp = new Date().toLocaleString(\"ru-RU\");\n\nmsg.payload = {\n chatId: \"ВАШ_CHAT_ID\", \n type: \"message\",\n content: `🚨 ТРЕВОГА: ОБНАРУЖЕНА ПРОТЕЧКА! 🚨\\n\\nОбъект: Кухня\\nДатчик: Датчик протечки под раковиной (DI1)\\nВремя: ${timestamp}`\n};\n\nnode.log({\n event: \"WATER_LEAK_ALARM\",\n source: \"DI1\",\n timestamp: Date.now()\n});\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 1110,
"y": 100,
"wires": [
[]
]
}
]
COURSE-01-M03-L01-S05: Итоги и лучшие практики
> 🔗 Связанный материал: Для подключения аналоговых датчиков (температуры, влажности, освещенности) смотрите следующий модуль.
"Сухой контакт" — это фундаментальный и чрезвычайно надежный способ интеграции простых цифровых датчиков в любую систему автоматизации. Он прост в диагностике и не требует сложной настройки.
Ключевые шаги для успешного внедрения:Дребезг контактов (Debouncing)
Механические контакты (в кнопках, реле) при замыкании и размыкании могут создавать серию очень коротких импульсов вместо одного чистого переключения. Это явление называется "дребезг контактов". Если логика на него не рассчитана, одно нажатие кнопки может быть воспринято как десять.
Методы борьбы:- Аппаратный: Многие качественные датчики имеют встроенную схему подавления дребезга.
- Программный: В Node-RED для этого можно использовать узел `delay` в режиме `Rate Limit` (ограничение частоты) или `trigger`, как мы сделали в примере выше.
Документирование потоков
Ваш проект будет жить долго, и обслуживать его будете не только вы.
- Именуйте узлы осмысленно: `mqtt in: Датчик движения (Коридор)` лучше, чем просто `mqtt in`.
- Используйте комментарии: Узел `comment` отлично подходит для описания логики сложных участков потока.
- Группируйте узлы: Выделите узлы, относящиеся к одной функции, и создайте группу (Ctrl+G), задав ей цвет и название.
---
Что дальше?
В следующем уроке мы перейдем от входов к выходам и научимся управлять нагрузками.
➡️ Следующий урок: COURSE-01-M03-L02: Управление релейными выходами и подключение нагрузок