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(); } });