Подключил такое двухканальное реле к порту RS485-2 WirenBoard 8.4: https://aliexpress.ru/item/1005006546630262.html?sku_id=12000037624457919. Добавил устройство через стандартный шаблон “Устройство с протоколом modbus”. Добавил два канала с адресами coil 0 и 1 соответственно. Оба канала реле работают при включении и отключении. Однако второй канал горит красным в Устройствах. Почему так?
Добрый день!
Для диагностики проблемы прошу прислать архив с диагностической информацией контроллера. Описание процесса создания архива можно найти в документации.
Также рекомендую запросить у производителя документацию по регистрам устройства и выполнить рекомендации из этой статьи.
Добрый день!
Судя по ошибкам:
Jan 11 15:35:08 wirenboard-AON5RX2F wb-mqtt-serial[719947]: WARNING: [modbus] failed to read 1 coil(s) @ 1 of device modbus:200: Serial protocol error: request timed out
Jan 11 15:35:09 wirenboard-AON5RX2F wb-mqtt-serial[719947]: WARNING: [modbus] failed to read 1 coil(s) @ 1 of device modbus:200: Serial protocol error: request timed out
Jan 11 15:35:10 wirenboard-AON5RX2F wb-mqtt-serial[719947]: WARNING: [modbus] failed to read 1 coil(s) @ 1 of device modbus:200: Serial protocol error: request timed out
Контроллер не может считать регистры устройства. Рекомендую:
- Свериться с настройками устройства по документации на реле:
- Проверьте правильность адреса Modbus.
- Убедитесь, что скорость, биты данных, чётность и стоп-биты совпадают.
- Проверить работу через Modbus-client:
- Используйте инструкцию для считывания данных напрямую через Modbus-client.
Предположу что проблема может быть вызвана следующим обстоятельством (ранее как то приходилось работать с реле через modbus client): считывание coil регистров ведется побайтно, для получения значения второго регистра необходимо прочитать регистры (команда 01) начиная с 0 регистра 8 бит (1 байт), полученное значение будет соответстсвовать максимальному возможному кол-ву реле - 8. Как реализовать такую логику чтения в wb?
Добрый день!
Не совсем понимаю цель ваших действий. Пожалуйста, опишите подробнее:
- Что именно вы делаете?
- Какого результата ожидаете?
- Что получаете в итоге?
Поясню подробнее. Я пытаюсь добавить в WB двухканальное реле (ссылку на устройство присылал в первом письме, там же по ссылке на алиэкспресс в описании указаны команды для работы с реле по modbus).
При этом хочу чтобы я мог а) управлять обоими каналами реле из веб-интерфейса б) постоянно получать актуальное состояние реле.
Отдельно отмечу, что проверил работу реле через usb стик и программу CAS Modbus Scanner. То есть параметры соединения (9600, 8, none, 1) и адрес - правильные. Коды команд мне понятны, и ответные сообщения - тоже.
Я попробовал добавить реле в WB двумя способами:
1 вариант. Добавить новое устройство через веб-интерфейс WB: настройки драйверов serial-устройств → порт /dev/ttyRS485-2 (настроен с указанными выше параметрами) → Добавить устройства вручную → Устройство с протоколом modbus → Добавляем два канала с адресами 0 и 1, тип регистра coil. Данные каналы оба работают на включение, однако второй канал подсвечивается в “Устройствах” красным. То есть явно возникает ошибка чтения второго канала. В этом и был первоначальный вопрос.
2 вариант. Долго пытался добавить реле через виртуальное устройство. С помощью разных команд: /usr/bin/printf, mbpoll, modbus_client. Но выходила похожая ошибка: реле включались, т.е. команда на запись работает. Но ответа не приходило. И вот только сегодня вычитал в документации wirenboard, что для корректной работы с modbus_client требуется отключить службу wb-mqtt-serial. Отключаешь - все ок, ответ возвращается как при подаче команды на запись состояния реле, так и при чтении состояния реле. При этом я хочу считывать состояние реле скажем каждые 0,2 сек, чтобы оно корректно отображалось на веб-интерфейсе. Но нельзя ведь так часто отключать и включать службу wb-mqtt-serial.
И еще такую неприятную вещь заметил: как только начинаешь обращаться через командную строку SSH с помощью команды modbus к реле, а затем запускаешь службу wb-mqtt-serial контроллер автоматически создает двухканальное реле с двумя каналами - такое же как и при ручном создании. Несмотря на то, что я его удалил. И это точно не виртуальное устройство. В созданном устройстве с двумя каналами второй канал также продолжает подсвечиваться красным.
Получается что оба способа нерабочие: 1 способ подсвечивает второй канал красным, 2 способ предполагает отключение wb-mqtt-serial на время выполнения запроса.
Добрый день!
Возможно, в решении вашего вопроса поможет данная статья, где подробно описан процесс подключения сторонних устройств к Wiren Board.
Добрый день, удалось решить вопрос?
Пока что не получилось. Попробовал при этом предложенные в статье способы изменения параметров guard_interval_us, response_timeout_ms, max_bit_hole. Не помогло.
Добрый день!
Прошу прислать карту регистров данного реле и общую документацию. Это поможет более детально рассмотреть ваш вопрос и предложить решение.
полной карты регистров на реле не нашел, но команды для управления приведены в описании по ссылке в первом письме, чуть больше информации есть здесь Релейный модуль 2 канала, RS485 Modbus | купить, адреса ключевых койлов, отвечающих за работу двух каналов - 0х0000 и 0х0001, при этом указанные в описании команды исправно работают если их вводить из консоли ssh (важно! при отключенном wb-mqtt-serial), исправно - значит приходят ответы! вообще реле стоит 300-400 руб, проще его купить ) при включенном wb-mqtt-serial поведение реле не меняется: второй канал горит красным, вне зависимости от того как его добавлять: типовой или кастомный шаблон, виртуальное устройство также не подходит т.к. не получается считывать состояние реле, только записывать
Добрый день!
Потребуется некоторое время для ознакомления с документацией. Как только будут результаты, я свяжусь с вами.
Добрый день!
Мы не компетентны помогать со сторонними неподдерживаемыми устройствами. Можем упустить какие-то из их особенностей.
Услуг настройки стороннего оборудования не оказываем.
Шаблон и modbus_client могут корректно работать только со стандартным Modbus - на странице по вашей ссылке указано, что модбас у данного устройства нестандартный.
Не могу понять по описанию, что вы делали с виртуальным устройством и modbus_client? Как это реализоввывали? Можете, пожалуйста, рассказать поподробнее?
Такое может быть от слишком частых запросов. Можно попробовать реже опрашивать канал.
Вместо modbus_client при включенном wb-mqtt-serial можно использовать modbus_client_rpc.
Также для с нестандартными протоколами можно работать через RPC.
Тестировать работу по нестандартному протоколу можно с помощью serial_tool.
Про утилиту modbus_client_rpc когда читал, не увидел. С ней все работает исправно. Спасибо. Единственное что приходится учитывать - команде требуется более 1 сек чтобы считать значение. Поэтому из-за ассинхронности runShellCommand приходится добавлять задержку с setTimeout. В коде ниже есть пара “лишних” функций, но в целом все функции рабочие:
var is_active_Example_Modbus_relay = true;
if (is_active_Example_Modbus_relay) {
defineVirtualDevice("modbus_relay", {
title: {
"en": "Two-Channel Modbus Relay",
"ru": "Двухканальное реле"
},
cells: {
relay1: {
type: "switch",
value: false,
title: {
"en": "Relay 1",
"ru": "Реле 1"
}
},
relay2: {
type: "switch",
value: false,
title: {
"en": "Relay 2",
"ru": "Реле 2"
}
}
}
});
var DEVICE_ADDRESS = 200; // Адрес устройства
var BAUD_RATE = 9600; // Скорость обмена
var PARITY = "none"; // Четность
var DATA_BITS = 8; // Биты данных
var STOP_BITS = 1; // Стоповые биты
var POLL_INTERVAL = 5000; // Интервал опроса в мс (между чтением состояния реле)
var POLL_DELAY = 2000; // Ожидаем результата выполнения запроса
var MODBUS_PORT = "/dev/ttyRS485-2"; // Порт устройства
var RelStatus = []; // по умолчанию пустой массив
var Rel1Pushed = false;
var Rel2Pushed = false;
// CRC вычисление
function calculateCRC(command) {
var crc = 0xFFFF;
for (var i = 0; i < command.length; i++) {
crc ^= command[i];
for (var j = 0; j < 8; j++) {
if (crc & 1) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc >>= 1;
}
}
}
return [(crc & 0xFF), (crc >> 8)];
}
// Настройка порта
function setupPort() {
runShellCommand("stty -F " + MODBUS_PORT + " ospeed " + BAUD_RATE + " ispeed " + BAUD_RATE + " raw clocal -crtscts -parenb -echo cs8");
}
// Добавление CRC в команду и получение команды для запуска runShellCommand
function CommandCRC(command) {
var crc = calculateCRC(command);
var fullCommand = command.concat(crc);
var commandString = "";
for (var i = 0; i < fullCommand.length; i++) {
var hexValue = fullCommand[i].toString(16).toUpperCase();
// Убедимся, что hexValue всегда будет длиной 2 символа
if (hexValue.length === 1) {
hexValue = "0" + hexValue; // добавляем ведущий ноль
}
commandString += "\\\\x" + hexValue;
}
return commandString;
}
// Отправка команды в порт
function sendCommand(command) {
//runShellCommand('/usr/bin/printf "' + CommandCRC(command) + '" > ' + MODBUS_PORT);
var cmd = 'modbus_client_rpc --debug -mrtu -b' + BAUD_RATE + ' -d' + DATA_BITS + ' -s' + STOP_BITS + ' -p' + PARITY + ' ' + MODBUS_PORT + ' -a' + DEVICE_ADDRESS + ' -t' + command[1] + ' -r' + ((command[2] << 8) | command[3]) + ' ' + ((command[4] << 8) | command[5]);
runShellCommand(cmd);
}
// Чтение койла (один регистр 0 или 1)
function getModbusRegisterValue(command) {
var cmd = 'modbus_client_rpc --debug -mrtu -b' + BAUD_RATE + ' -d' + DATA_BITS + ' -s' + STOP_BITS + ' -p' + PARITY + ' ' + MODBUS_PORT + ' -a' + DEVICE_ADDRESS + ' -t' + command[1] + ' -r' + ((command[2] << 8) | command[3]) + ' -c' + ((command[4] << 8) | command[5]);
RelStatus = []; // по умолчанию пустой массив
runShellCommand(cmd, {
captureOutput: true,
exitCallback: function(exitCode, capturedOutput) {
if (exitCode === 0 && capturedOutput.length > 0) {
RelStatus = capturedOutput.split("Data:")[1].trim().split(" ").map(function(byte) {
return parseInt(byte, 16);
});
}
}
});
}
// Чтение состояния реле
function readRelayStatus() {
getModbusRegisterValue([DEVICE_ADDRESS, 0x01, 0x00, 0x00, 0x00, 0x08]);
setTimeout(function() {
if (RelStatus.length>0) {
if (!Rel1Pushed) {
dev["modbus_relay/relay1"] = RelStatus[0] ? true : false;
}
if (!Rel2Pushed) {
dev["modbus_relay/relay2"] = RelStatus[1] ? true : false;
}
}
}, POLL_DELAY);
}
// Обработка изменений состояния реле
defineRule("relay1_control", {
whenChanged: "modbus_relay/relay1",
then: function (newValue) {
Rel1Pushed = true;
sendCommand([DEVICE_ADDRESS, 0x05, 0x00, 0x00, newValue ? 0xFF : 0x00, 0x00]);
setTimeout(function() {
Rel1Pushed = false;
}, POLL_DELAY);
}
});
defineRule("relay2_control", {
whenChanged: "modbus_relay/relay2",
then: function (newValue) {
Rel2Pushed = true;
sendCommand([DEVICE_ADDRESS, 0x05, 0x00, 0x01, newValue ? 0xFF : 0x00, 0x00]);
setTimeout(function() {
Rel2Pushed = false;
}, POLL_DELAY);
}
});
// Периодический опрос состояния реле
setInterval(readRelayStatus, POLL_INTERVAL);
// Инициализация
setTimeout(setupPort, 1000);
}
Рада, что хоть немного удалось помочь