Last active
October 12, 2023 11:26
-
-
Save stas-dovgodko/c7b47d576d36f8952346d5c1e8be49a0 to your computer and use it in GitHub Desktop.
Openhab NVAC proxy layer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Моя проксі-бібліотека | |
// https://www.npmjs.com/package/openhab-proxy-pattern | |
let proxy = require('openhab-proxy-pattern'); | |
// modbus адаптер на датчики віддає температуру в цілому вигляді як десяті долі, наприклад 225 | |
// в логічні елементи вже потрапляє як нормальне значення | |
const modbus_ds_map = function(value) { | |
if (typeof value == 'string') { | |
let t = parseInt(value) * 0.1; | |
return `${t} °C`; | |
} else return undefined; | |
}; | |
proxy.bind('VentilationHeatPipe_OutputTemperature', 'MODBUS_DS1820_T1').update(modbus_ds_map, 5); | |
proxy.bind('Ventilation_OutputTemperature', 'MODBUS_DS1820_T2').update(modbus_ds_map, 5); | |
// modbus адаптер на 0..10в оперує сотими долями вольта, значення в диапазоні 0-100 | |
// треба то привести до звичаного дімера 0-100% | |
// оскільки адаптер r|w і може теоретично бути змінений не тільки з опенхабу то зв'язок в обидва боки | |
proxy. Bind('VentilationHeater_OutputState', 'N4DAC02_1_VOLTAGE').update(function(value) { | |
if (typeof value == 'string') { | |
// convert 0-1000 to 0-100 | |
return Math.round(parseFloat(value)/10.00); | |
} else return undefined; | |
}).forward(function(value) { | |
if (typeof value == 'string') { | |
// convert 0-100 to 0-1000 | |
return Math.round(parseFloat(value) * 10); | |
} else return undefined; | |
}); | |
// регістри температури ПВУ, відповідно до документації, зміщені на 40градусів в плюс | |
// відповідно це треба скорегувати для логічних елементів | |
const tmap = function(value) { | |
if (typeof value == 'string') { | |
const v = parseFloat(value); | |
let t = v - 40.0; | |
return isNaN(t) ? undefined : `${t} °C`; | |
} else return undefined; | |
}; | |
proxy.bind('VentilationUnit_OutputTemperature', 'NEOCLIMA_T_OUTPUT').update(tmap); | |
proxy.bind('VentilationUnit_InputTemperature', 'NEOCLIMA_T_INPUT').update(tmap); | |
proxy.bind('VentilationUnit_ExhaustTemperature', 'NEOCLIMA_T_EXHAUST').update(tmap); | |
proxy.bind('VentilationUnit_ExchangeTemperature', 'NEOCLIMA_T_EXCHANGE').update(tmap); | |
// рідна уставка температури ПВУ Neoclima: | |
// 1) оперує тільки цілими температурами, а в мене флоати, тож треба міняти лише при зміні більше градуса | |
// 2) при встановленні температури не в дозволеному диапазоні впадає в ступор | |
proxy. Bind('Ventilation_OutputSetpointTemperature', 'NEOCLIMA_SETPOINT_OUTPUT').update(function(value) { | |
if (typeof value == 'string') { | |
const v = parseFloat(value); | |
const current = parseFloat(items.getItem('Ventilation_OutputSetpointTemperature').state); | |
// неокліма не вміє міняти градацію меньше 1 градуса | |
if (Math.abs(v - current) >= 1) return `${v} °C`; | |
} | |
}).forward(function(value) { | |
if (typeof value == 'string') { | |
const v = Math.ceil(parseFloat(value)); | |
if (!isNaN(v)) { | |
if (v > 25) return 25; | |
else if (v < 10) return 10; | |
else return v; | |
} else { | |
return undefined; | |
} | |
} else return undefined; | |
}, 5); | |
// байпас ПВУ керується окремо та ще має власний діпазон | |
// оскільки в рекуператора байпас не 100% то треба зробити невелику корекцію (відкривати за трохи меньшох т-ри) | |
proxy.bind('Ventilation_OutputSetpointTemperature', 'NEOCLIMA_BYPASS_OPENING').forward(function(value) { | |
if (typeof value == 'string') { | |
let v = Math.ceil(parseFloat(value)); | |
v = v - 2; | |
items.getItem('NEOCLIMA_BYPASS_RANGE').sendCommand(10); // тут не зрозуміло що ставити, я тавою дефолтні по документації 10 градусів диапазону | |
if (!isNaN(v)) { | |
if (v > 30) return 30; | |
else if (v < 5) return 5; | |
else return v; | |
} else { | |
return undefined; | |
} | |
} else return 19; // це дефолтне/заводське значення, на всяк випадок | |
}); | |
// треба перетворити 5 фіксованих режимів роботи вентиляції в швидкості двох вентиляторів | |
// моя бібліотека не вміє проксувати декілька в один тому стандартна бібліотека | |
// обидва вентилятори ПВУ мають 3 режими швидкості + зупинку (документація до регістрів) | |
// тож паплю режим в швидкості. Тут ще треба зворотню логіку додати, щоб підхватувати родне керувння з пульта але трохи ліньки | |
rules.JSRule({ | |
name: "Forward ventilation mode", | |
triggers: [triggers.ItemCommandTrigger('VentilationUnit_OutputMode')], | |
execute: (event) => { | |
let mode = event.receivedCommand; | |
if (mode == 'BOOST') { | |
items.getItem('NEOCLIMA_S_SUPPLY').sendCommand(5); | |
items.getItem('NEOCLIMA_S_EXHAUST').sendCommand(5); | |
} else if (mode == 'MAIN') { | |
items.getItem('NEOCLIMA_S_SUPPLY').sendCommand(5); | |
items.getItem('NEOCLIMA_S_EXHAUST').sendCommand(3); | |
} else if (mode == 'INTAKE') { | |
items.getItem('NEOCLIMA_S_SUPPLY').sendCommand(5); | |
items.getItem('NEOCLIMA_S_EXHAUST').sendCommand(2); | |
} else if (mode == 'IDLE') { | |
items.getItem('NEOCLIMA_S_SUPPLY').sendCommand(2); | |
items.getItem('NEOCLIMA_S_EXHAUST').sendCommand(2); | |
} else if (mode == 'OFF') { | |
items.getItem('NEOCLIMA_S_SUPPLY').sendCommand(0); | |
items.getItem('NEOCLIMA_S_EXHAUST').sendCommand(0); | |
} | |
} | |
}); | |
// трохи безпекової магії | |
// якщо ПВУ каже що в нього вимкнутий приток (чи з опенхабу чи з пульта) то безумовно вимикаємо догрівач, | |
// бо гарантовано спрацює захист від перегріву, а нащо нам то | |
rules.JSRule({ | |
name: "Forward ventilation mode", | |
triggers: [triggers.ItemStateChangeTrigger('NEOCLIMA_S_SUPPLY')], | |
execute: (event) => { | |
let state = parseInt(items.getItem('NEOCLIMA_S_SUPPLY').state); | |
if (state > 0) { | |
items.getItem('NEOCLIMA_SW_HEATER').sendCommand('ON'); | |
} else { | |
items.getItem('NEOCLIMA_SW_HEATER').sendCommand('OFF'); | |
} | |
} | |
}); | |
// керуємо реле байпасу ГТО | |
proxy.bind('Ventilation_IntakeDumperSwitch', 'SHELLY_25_2_RELAY2').forward(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment