Skip to content

Instantly share code, notes, and snippets.

@stas-dovgodko
Last active October 12, 2023 11:26
Show Gist options
  • Save stas-dovgodko/c7b47d576d36f8952346d5c1e8be49a0 to your computer and use it in GitHub Desktop.
Save stas-dovgodko/c7b47d576d36f8952346d5c1e8be49a0 to your computer and use it in GitHub Desktop.
Openhab NVAC proxy layer
// Моя проксі-бібліотека
// 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