Подключение внутрипольного конвектора

Здравствуйте, появилась задача-подключить конвектор. По умолчанию он управляется термостатом через RS485. В помещении будет стоять датчик WB-MSW v.4 ( подключенный , соответственно, к Wirenboard 7). Подскажите можно ли подключить конвектор напрямую к контроллеру?

Добрый день.
Попытался найти карту регистров, для интеграции по Modbus, которую можно сделать согласно статье.
Но видимо нет в открытом доступе, нужно запрашивать у производителя.

Если честно, немного не понятная инструкция, как вы видите интеграцию не по Modbus?

Протокол обмена VT601 с модулем FCM версия 2022_1.pdf (312,9 КБ)

сейчас интеграцию никак не вижу, но хочу через 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

1 лайк

Спасибо за ответ!

Сделали правило для отправки широковещательных пакетов в незанятый порт.
Скорость 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 + '"');
}