OpenTherm <-> UART
Источник: Alex_Jet » 30 мар 2022, 17:00
Мой пример опроса газового котла через шлюз OpenTherm ↔ UART (ModBus RTU) и, соответственно, через MegaD-2561 как шлюз UART (ModBus RTU) ↔ Ethernet (HTTP) с помощью сценария в intraHouse v4:
/**
* @name Отопление - OT мониторинг газового котла
* @desc Мониторинг котла по Opentherm
* @version 4
*/
const boiler_gaz = Device("ACTOR_HEATING_SYS_01", [
{"name":"data_request", "note":"Запрос данных", "type":"string", "val":""},
{"name":"firmware", "note":"Версия прошивки", "type":"string", "val":""},
{"name":"boiler_status", "note":"Master и Slave статус", "type":"string", "val":""},
{"name":"temp_outside", "note":"Температура внешняя", "type":"string", "val":""},
{"name":"temp_heating", "note":"Температура отопления", "type":"string", "val":""},
{"name":"temp_return", "note":"Температура обратки", "type":"string", "val":""},
{"name":"temp_hot_water", "note":"Температура ГВС", "type":"string", "val":""},
{"name":"pressure", "note":"Давление в системе", "type":"string", "val":""},
{"name":"modulation", "note":"Модуляция горелки", "type":"string", "val":""},
{"name":"error_number", "note":"Ошибка котла", "type":"string", "val":""},
{"name":"Max_Hot_Water", "note":"Максимальная температура ГВС", "type":"string", "val":""},
{"name":"Min_Hot_Water", "note":"Минимальная температура ГВС", "type":"string", "val":""},
{"name":"Max_Heating", "note":"Максимальная температура отопления", "type":"string", "val":""},
{"name":"Min_Heating", "note":"Минимальная температура отопления", "type":"string", "val":""}
]);
const temp_outside = Device("BOILER_GAS_TEMP_OUTSIDE");
const temp_heating = Device("BOILER_GAS_TEMP_HEATING");
const temp_return = Device("BOILER_GAS_TEMP_RETURN");
const temp_hot_water = Device("BOILER_GAS_TEMP_HOT_WATER");
const pressure = Device("BOILER_GAS_PRESSURE_SYSTEM");
const modulation = Device("BOILER_GAS_MODULATION_BURNER");
const error_number = Device("BOILER_GAS_ERROR_NUMBER");
const state_fault = Device("BOILER_GAS_STATE_FAULT");
const state_CH_mode = Device("BOILER_GAS_STATE_CH_MODE");
const state_DHW_mode = Device("BOILER_GAS_STATE_DHW_MODE");
const state_flame = Device("BOILER_GAS_STATE_FLAME");
const boiler_status = Device("ST_HEATING_SYS_04");
script({
unit: "megad4", //Контроллер с UART
uart_tx: "", //Переменная для передачи данных
uart_rx: "uart_rx=1&mode=rs485", //Переменная для получения данных
timeout: 1, //Пауза перед получением данных
time_wd: 6, //Пауза если данные записываются в шлюз
command: 1, //Переменная для формирования передачи
error_rx: 0, //Ошибка приема данных (MegaD возвращает CRC Error)
debug: 0, //Отладка: 0 - выключена, 1-включена
//Биты состояния котла в соответствии с OpenTherm
bit_state_fault: 1, //Бит наличия ошибки
bit_state_CH_mode: 2, //Бит состояния контура отопления 1
bit_state_DHW_mode: 4, //Бит состояния контура ГВС
bit_state_flame: 8, //Бит состояния горелки
bit_state_cooling: 16, //Бит состояния охлаждения
bit_state_CH2_mode: 32, //Бит состояния контура отопления 2
bit_state_diagnostic: 64, //Бит состояния процедуры диагностики
start() {
//Если происходит запись данных в шлюз, то добавляем слушателя
if(global.get("Boiler_Gaz_WriteData")) {
this.startTimer("PauseWhileWritingData", this.time_wd, "setReadData");
//this.addListener("globals.Boiler_Gaz_WriteData", "setReadData");
}
//Иначе устанавливаем признак чтения данных из шлюза
else this.setReadData();
},
setReadData() {
//Установка признака начала чтения данных из шлюза
global.set("Boiler_Gaz_ReadData", 1);
//globals.Boiler_Gaz_ReadData = 1;
//Отладка
if(this.debug) this.log('Отладка #X: Boiler_Gaz_ReadData = ' +global.get("Boiler_Gaz_ReadData"));
//Передача данных в шлюз
this.dataTransfer();
},
dataTransfer() {
let address = "0b";
let code = "04";
let register;
let number = "0001";
switch(this.command) {
case 1: register = "00cc"; //Версия прошивки
break;
case 2: register = "00cd"; //Статус котла
break;
case 3: register = "00ce"; //Ошибка котла
break;
case 4: register = "00cf"; //Температура отопления текущая
break;
case 5: register = "00d0"; //Температура горячей воды текущая
break;
case 6: register = "00d1"; //Уровень модуляции пламени горелки
break;
case 7: register = "00d2"; //Давление (P*10)
break;
case 8: register = "00d3"; //Температура внешняя ((Т+100)*10)
break;
case 9: register = "00d4"; //Верхняя граница температуры ГВС
break;
case 10: register = "00d5"; //Нижняя граница температуры ГВС
break;
case 11: register = "00d6"; //Верхняя граница температуры котловой воды
break;
case 12: register = "00d7"; //Нижняя граница температуры котловой воды
break;
case 13: register = "00d8"; //Температура обратки текущая
break;
}
//Формирование передачи для MegaD
this.uart_tx = "uart_tx=" +address+code+register+number+ "&mode=rs485";
//Отладка
if(this.debug) this.log("Отладка #1: request = " +this.uart_tx);
this.sendRequest();
},
sendRequest() {
//Передаем запрос на MegaD
this.pluginCommand({unit:this.unit, command:'/sec/?'+this.uart_tx});
//Через timeout запрашиваем у контроллера ответ ModBus-устройства
this.startTimer("getAnswer", this.timeout, "getAnswer");
},
getAnswer() {
//Передаем запрос на MegaD, ответ без обработки придет в сценарий (onResponse:'raw')
this.pluginCommand({unit:this.unit, command:{url:'/sec/?'+this.uart_rx, onResponse:'raw'}}, 'getResponse');
},
getResponse(body) {
var data_array;
var data_status;
var error;
var data;
if(body == "CRC Error") {
data_status = "CRC Error";
this.error_rx = this.error_rx + 1;
error = 1;
}
else if(body === undefined) {
data_status = "Not connect";
error = 1;
}
else {
data_status = "OK";
error = 0;
//Формируем массив из ответа
data_array = body.split("|");
data = parseInt(data_array[3]+data_array[4], 16);
}
//Вывод статуса запроса данных
boiler_gaz.setParam("data_request", data_status+ " (CRC Error - " +this.error_rx+ ")");
//Отладка
if(this.debug) this.log('Отладка #2: body = ' +body+ "; data = " +data);
//Если все нормально, то опрашиваем шлюз
if(!error) {
switch(this.command) {
case 1: //Версия прошивки
data = data*0.01;
boiler_gaz.setParam("firmware", data);
break;
case 2: //Статус котла
let bin = this.dec2bin(data);
boiler_gaz.setParam("boiler_status", bin+ " ("+data+")");
this.assign(boiler_status, "value", bin+ " ("+data+")");
let state;
state = this.BitState(this.bit_state_fault, data);
this.assign(state_fault, "value", state);
state = this.BitState(this.bit_state_CH_mode, data);
this.assign(state_CH_mode, "value", state);
state = this.BitState(this.bit_state_DHW_mode, data);
this.assign(state_DHW_mode, "value", state);
state = this.BitState(this.bit_state_flame, data);
this.assign(state_flame, "value", state);
//this.assign(boiler_status, "error", 0);
break;
case 3: //Ошибки котла
if(data === 0) data = "нет";
boiler_gaz.setParam("error_number", data);
//error_number.setValue(data);
this.assign(error_number, "value", data);
//this.assign(error_number, "error", 0);
break;
case 4: //Температура отопления текущая
boiler_gaz.setParam("temp_heating", data);
//temp_heating.setValue(data);
this.assign(temp_heating, "value", data);
//this.assign(temp_heating, "error", 0);
break;
case 5: //Температура горячей воды текущая
boiler_gaz.setParam("temp_hot_water", data);
//temp_hot_water.setValue(data);
this.assign(temp_hot_water, "value", data);
//this.assign(temp_hot_water, "error", 0);
break;
case 6: //Уровень модуляции пламени горелки
boiler_gaz.setParam("modulation", data);
//modulation.setValue(data);
this.assign(modulation, "value", data);
//this.assign(modulation, "error", 0);
break;
case 7: //Давление системы (P*10)
data = data*0.1 - 100;
boiler_gaz.setParam("pressure", data.toFixed(2));
//pressure.setValue(data);
this.assign(pressure, "value", data.toFixed(2));
//this.assign(pressure, "error", 0);
break;
case 8: //Температура внешняя ((Т+100)*10)
data = data*0.1 - 100;
boiler_gaz.setParam("temp_outside", data.toFixed(2));
//temp_outside.setValue(data);
this.assign(temp_outside, "value", data.toFixed(2));
//this.assign(temp_outside, "error", 0);
break;
case 9: //Верхняя граница температуры ГВС
boiler_gaz.setParam("Max_Hot_Water", data);
break;
case 10: //Нижняя граница температуры ГВС
boiler_gaz.setParam("Min_Hot_Water", data);
break;
case 11: //Верхняя граница температуры отопления
boiler_gaz.setParam("Max_Heating", data);
break;
case 12: //Нижняя граница температуры отопления
boiler_gaz.setParam("Min_Heating", data);
break;
case 13: //Температура обратки текущая
boiler_gaz.setParam("temp_return", data);
this.assign(temp_return, "value", data);
break;
}
if(++this.command > 13) {
this.exitScript();
}
else this.dataTransfer();
}
//Если ошибка, то выходим из сценария
else this.exitScript();
},
dec2bin(hex) {
var str = (parseInt(hex, 10).toString(2)).padStart(16, "0");
return str.substr(8);
},
BitState(bit, data) {
let state = data & bit;
if(state) state = 1;
else state = 0;
return state;
},
exitScript() {
this.command = 1;
//Установка признака окончания чтения данных из шлюза
global.set("Boiler_Gaz_ReadData", 0);
//globals.Boiler_Gaz_ReadData = 0;
//Отладка
if(this.debug) this.log('Отладка #X: Boiler_Gaz_ReadData = ' +global.get("Boiler_Gaz_ReadData"));
this.exit();
}
});