Здравствуйте, появилась задача-подключить конвектор. По умолчанию он управляется термостатом через RS485. В помещении будет стоять датчик WB-MSW v.4 ( подключенный , соответственно, к Wirenboard 7). Подскажите можно ли подключить конвектор напрямую к контроллеру?
Добрый день.
Попытался найти карту регистров, для интеграции по Modbus, которую можно сделать согласно статье.
Но видимо нет в открытом доступе, нужно запрашивать у производителя.
Если честно, немного не понятная инструкция, как вы видите интеграцию не по Modbus?
сейчас интеграцию никак не вижу, но хочу через modbus. Смущает такой момент -
сам конвектор не имеет адреса на шине, а управляется широковещательной командой.Отсюда вопрос-как это отобразить в шаблоне?
Судя по протоколу обмена — там не modbus.
Можно воспользоваться прямой записью в порт с помощью RPC — GitHub - wirenboard/wb-mqtt-serial: Wiren Board MQTT serial protocol driver
В качестве примера — Примеры правил — Wiren Board
// Подключаем библиотеку для работы с Modbus
const modbus = require(‘modbus’);
// Адрес устройства на шине RS485
const DEVICE_ADDRESS = 0xFF; // Широковещательный адрес (или конкретный адрес устройства)
// Функция для создания пакета данных
function createPacket(regOffset, value) {
const preamble = 0x55;
const len = 0x04; // Длина тела пакета
const comm = 0x01; // Команда записи
const payload = [DEVICE_ADDRESS, len, comm, regOffset, value];
const cs = payload.reduce((acc, byte) => acc ^ byte, 0); // Контрольная сумма
return Buffer.from([preamble, …payload, cs]);
}
// Функция для отправки данных на устройство
function sendData(regOffset, value) {
const packet = createPacket(regOffset, value);
modbus.write(DEVICE_ADDRESS, packet, (err) => {
if (err) {
console.error(“Ошибка отправки данных:”, err);
} else {
console.log(“Данные успешно отправлены:”, packet);
}
});
}
// Функция для чтения данных с устройства
function readData(regOffset, callback) {
modbus.read(DEVICE_ADDRESS, regOffset, 1, (err, data) => {
if (err) {
console.error(“Ошибка чтения данных:”, err);
} else {
console.log(“Данные успешно получены:”, data);
callback(data);
}
});
}
// Пример использования
defineVirtualDevice(“fan_controller”, {
title: “Fan Controller”,
cells: {
fan_speed: {
type: “range”,
value: 0,
max: 255,
readonly: false
},
valve_state: {
type: “range”,
value: 0,
max: 255,
readonly: false
}
}
});
// Обработка изменения скорости вентилятора
defineRule(“fan_speed_change”, {
whenChanged: “fan_controller/fan_speed”,
then: function (newValue) {
sendData(0x00, newValue); // Отправляем значение ШИМ для вентилятора
}
});
// Обработка изменения состояния клапана
defineRule(“valve_state_change”, {
whenChanged: “fan_controller/valve_state”,
then: function (newValue) {
sendData(0x01, newValue); // Отправляем состояние клапана
}
});
// Периодическое чтение данных с устройства
setInterval(() => {
readData(0x00, (data) => {
dev[“fan_controller/fan_speed”] = data[0]; // Обновляем значение скорости вентилятора
});
readData(0x01, (data) => {
dev[“fan_controller/valve_state”] = data[0]; // Обновляем состояние клапана
});
}, 5000); // Опрос каждые 5 секунд
В продолжение темы- такая конструкция может работать?
То есть этот код я закидываю в wb-rules, и получаю виртуальное устройство?
Меня тут кто-нибудь читает? Алё!
Вы задаете вопросы в закрытой (решенной) теме - техподдержка (обычно они отвечают в рабочие дни в рабочее время) такие темы может не заметить.
Создание виртуальных устройств происходит вот так Примеры правил — Wiren Board
Для работы с протоколом modbus нет необходимости в дополнительных манипуляциях (коде) - этот протокол поддерживается драйверами контроллера “из коробки”.
Если у вас на шине RS-485 устройство с “нестандартным modbus`ом” или иным протоколом и вам необходимо посылать команды и принимать ответы (не modbus), то это можно делать вот так Примеры правил — Wiren Board
Также для своих (отсутствующих “в комплекте” шаблонов) устройств, вы можете написать свой шаблон - Как писать шаблоны для сторонних Modbus-устройств — Wiren Board
Спасибо за ответ!
Сделали правило для отправки широковещательных пакетов в незанятый порт.
Скорость 0-100 приобразовывается в 0-255 согласно формуле в мануале.
В вирт. устройстве отображается отправленная команда для справки.
// создание виртуального устройства с управляющими контроллами
defineVirtualDevice('vt601', {
title: {
en: 'VT601 exchange with FCM module',
ru: 'Обмен VT601 c модулем FCM'
},
cells: {
valve: {title: {en: 'Valve', ru: 'Клапан'}, type: 'switch', value: false, order: 1},
speed: {title: {en: 'Speed', ru: 'Скорость'}, type: 'range', value: 0, max: 100, order: 2},
command: {title: {en: 'Command', ru: 'Команда'}, type: 'text', value: '', readonly: true, order: 3}
}
});
// привязываем изменение контроллов на отправку команды
defineRule('vt601_change', {
whenChanged: ['vt601/valve', 'vt601/speed'],
then: function (value, device, control) {
switch (control) {
// команда для изменения состояния клапана: 0 - выкл, 1..255 вкл
case 'valve':
value = value ? 1 : 0;
command = [0x03, 0x01, 0x01, value];
break;
// команда для изменения скорости вентилятора
case 'speed':
value = value ? Math.round((value / 5) * 11 + 35) : 0;
command = [0x03, 0x01, 0x00, value];
break;
}
sendCommand(command, '/dev/ttyMOD1');
}
});
// функция для отправки команды в устройство
function sendCommand(command, port) {
// преамбула с широковещательным адресом
var packet = [0x55, 0xFF], crc = 0;
// проверка пакета на недопустыми байты под замену
for (var i = 0; i < command.length; i++) {
if (command[i] === 0x55) packet.push(0xAA, 0xFF);
else if (command[i] === 0xAA) packet.push(0xAA, 0x00);
else packet.push(command[i]);
}
// расчитываем контрольную сумму (XOR), пропуск 1 байта с преамбулой
for (var i = 1; i < packet.length; i++) {
crc ^= packet[i];
}
// добавляем контрольную сумму в конец
packet.push(crc);
// преобразуем в HEX-строку
var result = packet.map(function(byte) {
return '\\x' + ('0' + byte.toString(16)).slice(-2);
}).join('');
// отображаем команду на вирт. устройстве и отправляем в заданный порт
dev.vt601.command = result.replace(/\\x/g, ' ').toUpperCase().trim();
runShellCommand('/usr/bin/printf "' + result + '" > "' + port + '"');
}