Showing preview only (5,571K chars total). Download the full file or copy to clipboard to get everything.
Repository: anerdins/nibepi
Branch: master
Commit: 1aa36b02986d
Files: 83
Total size: 5.3 MB
Directory structure:
gitextract_y3rmklbz/
├── .gitignore
├── LICENSE
├── README.en.md
├── README.md
├── backend.js
├── default.json
├── docker/
│ ├── .dockerignore
│ ├── Dockerfile
│ ├── README.md
│ ├── docker-compose.yml
│ └── nibepi/
│ ├── .gitignore
│ ├── LICENSE
│ ├── README.md
│ ├── backend.js
│ ├── default.json
│ ├── index.js
│ ├── lib/
│ │ ├── models.json
│ │ ├── saveGraph.js
│ │ ├── startCore.js
│ │ └── stopCore.js
│ ├── log.js
│ ├── modbus-client.js
│ ├── models/
│ │ ├── F1145.json
│ │ ├── F1155.json
│ │ ├── F1245.json
│ │ ├── F1255.json
│ │ ├── F1345.json
│ │ ├── F1355.json
│ │ ├── F370.json
│ │ ├── F470.json
│ │ ├── F730.json
│ │ ├── F750.json
│ │ ├── RMU40_S1.json
│ │ ├── RMU40_S2.json
│ │ ├── RMU40_S3.json
│ │ ├── RMU40_S4.json
│ │ ├── S1255.json
│ │ ├── VVM225.json
│ │ ├── VVM310.json
│ │ ├── VVM320.json
│ │ ├── VVM325.json
│ │ └── VVM500.json
│ ├── nibegw-client.js
│ ├── package.json
│ └── server.js
├── example-nibeF.js
├── example-nibeS.js
├── example.js
├── index.js
├── lib/
│ ├── models.json
│ ├── saveGraph.js
│ ├── startCore.js
│ └── stopCore.js
├── log.js
├── modbus-client.js
├── modbus-server.js
├── modbus-tcp.js
├── models/
│ ├── F1145.json
│ ├── F1155.json
│ ├── F1245.json
│ ├── F1255.json
│ ├── F1345.json
│ ├── F1355.json
│ ├── F370.json
│ ├── F470.json
│ ├── F730.json
│ ├── F750.json
│ ├── RMU40_S1.json
│ ├── RMU40_S2.json
│ ├── RMU40_S3.json
│ ├── RMU40_S4.json
│ ├── S1255.json
│ ├── SMO20.json
│ ├── SMO40.json
│ ├── VVM225.json
│ ├── VVM310.json
│ ├── VVM320.json
│ ├── VVM325.json
│ └── VVM500.json
├── nibegw-client.js
├── package.json
├── server.js
└── test.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
config.json
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2020 anerdins
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.en.md
================================================
# nibepi
Follow this project on Facebook! https://www.facebook.com/groups/nibepi/<br>
<b>Finally a imagefile running Raspberry Pi Bullseye</b><br>
http://anerdins.se/NibePi/nibepi_1.1.1.rar<br><br>

NibePi is an IoT product for your Nibe heatpump
With a Raspberry Pi Zero+RS485 HAT you can communicate with your heatpump by serial protocol. NibePi can fit inside the shell of the heatpump and be powered directly from the terminals.
NibePi supports a lot of Nibe heatpumps, including: Nibe F370,F470,F730,F750,F1145,F1245,F1155,F1255,VVM225,310,320,325,500.SMO20-40<br>
The foundation in this product is built on Node.JS and Node-RED. If the project dosent suit your needs completly it's easy to make your own project with this as a base.
One of the main features in this project is that NibePi is a dependable solution, the filesystem runs in a read-only mode and that makes it almost total secure against corrupt SD-cards. Since no data is written to the SD-card regulary it will not be worn out.<br>
Note that data is written to the SD-card when you change a setting in the user interface. <br>
If you appreciate my work, you can sponsor me with a coffee
https://www.buymeacoffee.com/0oKFXbQ
Hardware used in the project.
Rpi Zero W:<br>
https://thepihut.com/products/raspberry-pi-zero-w<br>
https://www.kiwi-electronics.nl/raspberry-pi-zero-w<br>
https://www.electrokit.com/produkt/raspberry-pi-zero-wh/<br>
RS485 HAT:<br>
https://thepihut.com/products/rs485-pizero?variant=26469099976<br>
https://www.kiwi-electronics.nl/rs-485-pi<br>
https://www.abelectronics.co.uk/p/77/rs485-pi<br>
https://www.m.nu/utbyggnadskort/wide-input-shim-kit<br>
12V HAT:<br>
https://thepihut.com/products/wide-input-shim<br>
https://www.kiwi-electronics.nl/wide-input-shim<br>
https://www.electrokit.com/produkt/wide-input-shim-3-16v/<br>
SD-card:<br>
https://www.clasohlson.com/se/MicroSDHC-SDXC-minneskort-Klass-10,-Kingston/38-5562<br>
Solder terminals or wires on A and B at the RS485 card, then stack all the cards together on a header and solder them as tight as possible against eachother for the minimal build height.<br>
Download the complete image and burn to the 16GB SD-card.<br>
http://anerdins.se/NibePi/nibepi_1.1.1.rar (1.1)<br>
(Right click the link and select "Save link as")<br>
On the boot partition at the SD-card (also available in Windows) there is a file called wpa_supplicant.conf, update with your own wifi credentials and save.
```
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=SE
network={
ssid="YOUR_WIFI"
psk="YOUR_PASSWORD"
key_mgmt=WPA-PSK
}
```
Install NibePi
```
Step 1: Remove the upper hatch, no screws, just take it off.
Step 2: Remove the two large torx T30 screws at the bottom of the heatpump which is holding the big front hatch.
Step 3: Pull the hatch out approx 10-20 cm and lift the whole front off and put it to the side.
Step 4: Remove the snap-in lid, picture below..
```

```
Step 5: Connect your NibePi according to the picture below
```
```
Please note that the connections can differ from one heatpump to another, check the manual for more info to find the right connections (12v,A,B,GND)
https://www.nibe.fi/nibedocuments/15050/031725-6.pdf
```

```
Step 6: Start the heatpump with the SD-card plugged into NibePi.
```
```
Activate Modbus in the heatpump.
Step 1: Hold the "Back" button for approx 7 seconds, one new service menu will popup, enter it.
Step 2: Go to, System settings 5.2, in some models you have to click another menu to see the list for the possible accessories.
Step 3: Scroll down and look for "Modbus", check it.
Step 4: The heatpump might raise an red alarm if NibePi has not started yet. Or the light will remain green and then the heatpump has a connection to NibePi.
```
Node-RED is now available at NibePi's hostname. http://nibepi:1880<br>
The webinterface for NibePi (based on Node-red) is available at http://nibepi:1880/ui<br>
If the above example doesn't work, please try with NibePis IP address instead of the hostname.
Not it's all done!
If you appreciate my work, you can sponsor me with a coffee
https://www.buymeacoffee.com/0oKFXbQ
================================================
FILE: README.md
================================================
# nibepi
<i>README in other languages: [English](https://github.com/anerdins/nibepi/blob/master/README.en.md)</i><br><br>

NibePi är en IoT produkt för din Nibe värmepump.
Med en Raspberry Pi Zero+RS485 HAT så kommunicerar NibePi med pumpen via Modbus. NibePi får plats innanför skalet på Värmepumpen och matas direkt från kretskortet i pumpen. NibePi stödjer Nibe F370,F470,F730,F750,F1145,F1245,F1155,F1255,VVM225,310,320,325,500.SMO40<br>
Grunden i automatisering och styrning av pumpen är baserad på NodeJS och Node-RED. Det finns även möjligheter att kunna redigera fritt.<br>
En viktig aspekt i hela projektet är att det måste vara en driftsäker lösning. Sönderskrivna SD-kort bör inte kunna hända på en NibePi eftersom att systemet körs i read-only. Detta gör den väldigt driftsäker.<br>
Fler funktioner kommer att byggas till och optimeras löpande. Det går även att uppdatera NibePi direkt via webinterfacet för att få tillgång till de senaste funktionerna.<br>
I webinterfacet finns information samt möjligheter för att starta om hårdvara eller mjukvara.
<b>Hårdvara som behövs</b>
Rpi Zero W:<br>
https://thepihut.com/products/raspberry-pi-zero-w<br>
https://www.kiwi-electronics.nl/raspberry-pi-zero-w<br>
https://www.electrokit.com/produkt/raspberry-pi-zero-wh/<br>
RS485 HAT:<br>
https://thepihut.com/products/rs485-pizero?variant=26469099976<br>
https://www.kiwi-electronics.nl/rs-485-pi<br>
https://www.abelectronics.co.uk/p/77/rs485-pi<br>
https://www.m.nu/utbyggnadskort/wide-input-shim-kit<br>
12V HAT:<br>
https://thepihut.com/products/wide-input-shim<br>
https://www.kiwi-electronics.nl/wide-input-shim<br>
https://www.electrokit.com/produkt/wide-input-shim-3-16v/<br>
SD-kort:<br>
https://www.clasohlson.com/se/MicroSDHC-SDXC-minneskort-Klass-10,-Kingston/38-5562<br>
Löd på anslutningskontakter på A och B på RS485 kortet. Stacka sedan ihop alla kort, antingen med headers eller löd dom rätt på varandra för minsta möjliga bygghöjd.<br>
Ladda ner en fullständig image fil att skriva till ett 16GB SD kort.<br>
Kolla in den officiella sidan
https://energy.anerdins-iot.se<br>
På boot partionen (som även är tillgänglig i windows) ligger det en fil som heter wpa_supplicant.conf Där skriver du in dina wifi uppgifter.
```
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=SE
network={
ssid="WIFINAMN"
psk="WIFILÖSEN"
key_mgmt=WPA-PSK
}
```
Ändra filen enligt ovan och spara.<br>
```
Installera NibePi
Steg 1: Ta bort den övre luckan där luftfiltret sitter (Gäller endast vid frånluftspumpar).
Steg 2: Skruva bort de två stora torx T30 skruvarna längst ner i botten på fronten.
Steg 3: Luta ut fronten i nederkant 10-20 cm och lyft fronten uppåt (Den hänger på en skena i ovankant.
Steg 4: Ställ undan fronten.
Steg 5: Ta bort det lilla snäpplocket enl. bild nedan
```

```
Steg 6: Anslut NibePi enl. bild nedan.
Inkopplingen kan skilja sig från olika värmepumpar https://www.nibe.fi/nibedocuments/15050/031725-6.pdf
```

```
Steg 7: Stoppa in SD-kortet. Starta värmepumpen med fronten av så länge.
```
```
Aktivera Modbus i Värmepumpen.
Steg 1: Håll in bakåt knappen i ca 7 sekunder, en service meny kommer upp, gå in i den.
Steg 2: Gå in i meny 5.2 Systeminställningar ( I vissa pumpar är det ytterligare ett menyval )
Steg 3: Nästan längst ner i den menyn bockar man för "Modbus".
Steg 4: Pumpen kan nu börja lysa rött om NibePi inte har startat ordentligt än, vilket kan ta några minuter.
```
Node-RED är nu tillgängligt på NibePi's adress. http://nibepi:1880<br>
Webinterfacet är tillgängligt på http://nibepi:1880/ui<br>
Om det ovanstående länkar inte fungerar så använd IP adressen istället. T.ex http://192.168.0.100:1880
Om du söker nytt elavtal får du gärna använda min affiliate länk och bli kund hos Tibber. <a href="https://invite.tibber.com/587354e8">https://invite.tibber.com/587354e8</a><br>
Om du uppskattar mitt arbete så kan du bjuda mig på lite kaffe på nedanstående länk.
https://www.buymeacoffee.com/0oKFXbQ
================================================
FILE: backend.js
================================================
/*MIT License
Copyright (c) 2019 Fredrik Anerdin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
const version = "1.1.0";
/*var exec = require('child_process').exec;
exec(`sudo chrt -a -f -p 99 ${process.pid}`, function(error, stdout, stderr) {
if(error) {
} else {
console.log('High priority backend is started')
}
});*/
const serialport = require('serialport');
const nack = [0x15];
const ack = [0x06];
var myPort;
const sendQueue = [[192,107,6,115,176,1,0,0,0,111],[192,107,6,212,190,0,0,0,0,199]];
const getQueue = [];
const rmuQueue = [];
var regQueue = [];
var regCount = 0;
var msgOut = Buffer.alloc(0);
var rmu_buffer = Buffer.alloc(0);
var red = false;
var fs_start = false;
var rmu_start = false;
let other_start = false;
var startReset = true;
let checkACK = {};
process.on('message', (m) => {
if(m.start===true) {
if(m.port!==undefined) {
portName = m.port;
myPort = new serialport(portName, 9600);
myPort.on('open', showPortOpen);
myPort.on('data', analyzeData);
myPort.on('close', showPortClose);
myPort.on('error', showError);
} else {
if(process.connected===true) {
process.send({type:"log",data:'Error starting backend, no serial port specified',level:"error",kind:"Serialport"});
}
}
} else if(m.type=="reqData") {
if(m.data!==undefined) {
let found = false;
for (i = 0; i < getQueue.length; i = i + 1) {
let address = (getQueue[i][4]*256)+getQueue[i][3];
if((m.data[4]*256)+m.data[3]==address) {
found = true;
}
}
if(found===false) getQueue.unshift(m.data)
}
;
} else if(m.type=="setData") {
sendQueue.push(m.data);
} else if(m.type=="rmuSet") {
rmuQueue.push(m.data);
} else if(m.type=="regRegister") {
regQueue = m.data;
} else if(m.type=="red") {
red = m.data;
}
});
process.on('disconnect', (m) => {
if(red===false) {
console.log('Shutting down the core.')
process.exit(99);
}
});
function showPortOpen() {
//console.log(`Core started on serial port ${portName}`);
}
function showPortClose() {
console.log('Port closed. Data rate: ' + myPort.baudRate);
}
function showError(error) {
if(process.connected===true) {
process.send({type:"fault",data:{from:"core",message:"The core could not be started, check the serialport"}});
}
myPort.removeAllListeners();
if(process.connected===true) {
process.disconnect();
console.log('Error in the core, shuting it down.')
process.exit(99);
}
}
function analyzeData(data) {
if(process.connected===true) {
process.send({type:"log",data:Array.from(data),level:"core",kind:"RAW"});
}
// Sometimes and ACK [0x06] is the first byte, and the second byte is the start. We shift it.
if(data[0]===0x06 && data[1]===0x5C) {
//console.log('ACK')
data = data.slice(1)
} else if(data[0]===0x06 && data[1]===undefined) {
//console.log('ACK')
}
//Check for start message, 0x5C if it's Nibe F series.
if(fs_start===false) {
if(data[0]===0x5C) {
fs_start = true;
}
}
if(fs_start===true) {
msgOut = Buffer.concat([msgOut,data]);
if(msgOut.length>=3) {
if(startReset===true) {
startReset = false;
sendQueue.push([192,107,6,115,176,1,0,0,0,111]);
}
// Only decode objects we know
if(msgOut[2]!==0x19 && msgOut[2]!==0x1A && msgOut[2]!==0x1B && msgOut[2]!==0x1C&& msgOut[2]!==0x20) {
msgOut = Buffer.alloc(0)
fs_start = false;
}
if(msgOut.length>=5) {
let msgLength = msgOut[4]+6;
// Check if we have the full length of the message.
if(msgOut.length>=msgLength) {
// We have full length
if(msgOut[2]==0x19 || msgOut[2]==0x1A || msgOut[2]==0x1B || msgOut[2]==0x1C) {
if(checkACK[msgOut[2]]===undefined) {
if(msgOut.length>=6) {
if(msgOut[msgOut[4]+6]===0x06 || msgOut[msgOut[4]+6]===0xC0) {
checkACK[msgOut[2]] = true;
msgOut = Buffer.alloc(0)
fs_start = false;
} else {
checkACK[msgOut[2]] = false;
msgOut = Buffer.alloc(0)
fs_start = false;
}
} else {
msgLength++;
}
return;
}
}
msgOut = msgOut.slice(0, msgLength);
checkMessage(msgOut).then(data => {
makeResponse(data).then(result => {
if(startReset===false) {
result = Array.from(result);
let doubleFound = false;
for (i = 5; i < result.length - 1; i = i + 1) {
if(result[i]===92 && result[i+1]===92) {
result.splice(i, 1);
result[4] = result[4]-1;
doubleFound = true;
}
}
if(doubleFound===true) {
var calcChecksum = 0;
for(i = 2; i < (result[4] + 5); i++) {
calcChecksum ^= result[i];
}
result[result.length-1] = calcChecksum;
}
if(process.connected===true) {
process.send({type:"data",data:result,rmu:checkACK[result[2]]});
process.send({type:"log",data:result,level:"debug",kind:"OK"});
}
}
}, err => {
})
}, err => {
err = Array.from(err);
console.log(`CHKSUM ERROR: ${err}`)
if(process.connected===true) {
process.send({type:"log",data:err,level:"error",kind:"CHKSUM"});
}
myPort.write(nack);
})
} else {
// Message is not ready yet.
}
}
}
}
}
const checkMessage = (data) => {
const promise = new Promise((resolve,reject) => {
let error = data;
msgOut = Buffer.alloc(0);
fs_start = false;
msgChecksum = data[data[4]+5];
var calcChecksum = 0;
for(i = 2; i < (data[4] + 5); i++) {
calcChecksum ^= data[i];
}
if((msgChecksum==calcChecksum) || (msgChecksum==0xC5 && calcChecksum==0x5C)) {
resolve(data);
} else {
reject(error)
}
});
return promise;
}
const makeResponse = (data) => {
const promise = new Promise((resolve,reject) => {
// Read from heatpump
if(data[2]==0x19 || data[2]==0x1A || data[2]==0x1B || data[2]==0x1C) { // < System
if(data[3]==0x60) { // Send data message
if(checkACK[data[2]]===false) {
if(rmuQueue.length!==0) {
var lastMsg = rmuQueue.pop();
if(lastMsg!==undefined) {
if(Number(lastMsg.ackback[2])==Number(data[2])) {
let address = lastMsg.address;
if(process.connected===true) {
process.send({type:"ack",data:{register:address,ack:true}});
process.send({type:"log",data:`Register: ${address}, Buffer: ${JSON.stringify(lastMsg)}`,level:"core",kind:"RMU SENT"});
}
if(lastMsg.data[3]===6) {
if(process.connected===true) {
process.send({type:"data",data:lastMsg.ackback,rmu:checkACK[lastMsg.ackback[2]]});
process.send({type:"log",data:lastMsg,level:"debug",kind:"RMU ACKBACK"});
}
}
myPort.write(lastMsg.data);
} else {
rmuQueue.push(lastMsg);
myPort.write(ack);
resolve(data);
}
} else {
myPort.write(ack);
resolve(data);
}
} else {
myPort.write(ack);
resolve(data);
}
} else {
resolve(data);
}
} else if(data[3]==0x62) {
// Message updates
if(checkACK[data[2]]===false) {
if(process.connected===true) {
let logOut = Array.from(data);
process.send({type:"log",data:logOut,level:"debug",kind:"RMU DATA"});
}
myPort.write(ack);
resolve(data);
} else {
resolve(data);
}
resolve(data);
} else if(data[3]==0x63) {
if(checkACK[data[2]]===false) {
myPort.write([192,96,2,99,0,193]);
resolve(data);
} else {
resolve(data);
}
} else if(data[3]==0xEE) {
if(checkACK[data[2]]===false) {
if(process.connected===true) {
process.send({type:"log",data:"Sending RMU Version v259",level:"debug",kind:"RMU ACK"});
}
myPort.write([192,238,3,238,3,1,193]);
resolve(data);
} else {
resolve(data);
}
} else {
if(checkACK[data[2]]===false) {
myPort.write(ack);
resolve(data);
} else {
resolve(data);
}
}
} else if(data[3]==105 && data[4]==0x00) {
if(getQueue!==undefined && getQueue.length!==0) {
var lastMsg = getQueue.pop();
if(lastMsg!==undefined) {
myPort.write(lastMsg);
resolve(data);
} else if(getQueue.length!==0) {
lastMsg = getQueue.pop();
if(lastMsg!==undefined) {
myPort.write(lastMsg);
resolve(data);
} else {
myPort.write(ack);
resolve(data);
}
} else {
myPort.write(ack);
resolve(data);
}
} else {
if(regQueue.length!==0) {
if(regCount>=regQueue.length) regCount = 0;
myPort.write(regQueue[regCount]);
regCount++;
resolve(data);
} else {
myPort.write(ack);
resolve(data);
}
}
// Write to heatpump
} else if(data[3]==107 && data[4]==0x00) {
if(sendQueue.length!==0) {
var lastMsg = sendQueue.pop();
if(lastMsg!==undefined) {
let address = (lastMsg[4] * 256 + lastMsg[3]);
if(process.connected===true) {
process.send({type:"ack",data:{register:address,ack:true}});
process.send({type:"log",data:`Register: ${address}, Buffer: ${JSON.stringify(lastMsg)}`,level:"debug",kind:"SENT"});
}
myPort.write(lastMsg);
resolve(data);
} else {
myPort.write(ack);
resolve(data);
}
} else {
myPort.write(ack);
resolve(data);
}
} else {
if(data[3]==109) {
} else if(data[3]==238) {
} else if(data[3]==106 || data[3]==104) {
} else {
}
myPort.write(ack);
resolve(data);
}
});
return promise;
}
================================================
FILE: default.json
================================================
{
"version":"1.1",
"registers":[],
"connection": {
"enable":"serial",
"series":"fSeries"
},
"serial":{
"port":"/dev/ttyAMA0"
},
"home": {
"adjust_s1":0,
"adjust_s2":0
},
"mqtt": {
"enable":false,
"host":"127.0.0.1",
"port":"1883",
"user":"",
"pass":"",
"topic":"nibe/modbus/"
},
"system": {
"readonly": true
},
"hotwater": {
"enable_autoluxury": false,
"diff": 20,
"time": 10,
"enable_hw_priority": false
},
"log": {
"enable": false,
"info": false,
"core": false,
"debug": false,
"error": true
},
"indoor": {
"dm_reset_enable":false,
"dm_reset_enable_stop":false,
"dm_reset_stop_diff":0.7,
"dm_reset_slow_diff":0.3
},
"fan": {
"co2_limit":800,
"low_cpr_freq":40
},
"plejd": {
"host":"127.0.0.1",
"port":"1883"
}
}
================================================
FILE: docker/.dockerignore
================================================
node_modules
npm-debug.log
nibepi/modbus-server.js
nibepi/modbus-tcp.js
nibepi/test.js
nibepi/example.js
nibepi/example-nibeS.js
nibepi/example-nibeF.js
nibepi/.git
nibepi/.gitignore
config
docker-compose.yml
config.json
================================================
FILE: docker/Dockerfile
================================================
FROM node:latest
# Copy source to container
RUN mkdir -p /usr/app/src
RUN mkdir -p /etc/nibepi
RUN chown -R node:node /usr/app
RUN chown -R node:node /etc/nibepi
COPY nibepi/package*.json /usr/app/src
WORKDIR /usr/app
USER node
RUN cd src && npm install -only=production
USER root
RUN apt-get remove --purge -y \
bzr \
git \
mercurial \
openssh-client \
subversion \
autoconf \
automake \
bzip2 \
dpkg-dev \
file \
g++ \
imagemagick \
libbz2-dev \
libc6-dev \
libcurl4-openssl-dev \
libdb-dev \
libevent-dev \
libffi-dev \
libgdbm-dev \
libglib2.0-dev \
libgmp-dev \
libjpeg-dev \
libkrb5-dev \
liblzma-dev \
libmagickcore-dev \
libmagickwand-dev \
libncurses5-dev \
libncursesw5-dev \
libpng-dev \
libpq-dev \
libreadline-dev \
libsqlite3-dev \
libssl-dev \
libtool \
libwebp-dev \
libxml2-dev \
libxslt-dev \
libyaml-dev \
make \
patch \
unzip \
xz-utils \
zlib1g-dev && \
rm -rf /var/lib/apt/lists/*
USER node
COPY nibepi /usr/app/src
CMD [ "node", "./src/server.js" ]
================================================
FILE: docker/README.md
================================================
This is the Docker section of NibePi, the files for building the image manually will be found here, check out the docker hub page https://hub.docker.com/r/anerdins/nibepi-base
================================================
FILE: docker/docker-compose.yml
================================================
version: '3'
services:
nibepi:
container_name: "nibepi"
build: .
# image: anerdins/nibepi-base
volumes:
- /home/pi/nibepi/config:/etc/nibepi
- "/etc/localtime:/etc/localtime:ro"
- "/etc/timezone:/etc/timezone:ro"
network_mode: "host"
user: "1000"
================================================
FILE: docker/nibepi/.gitignore
================================================
config.json
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
================================================
FILE: docker/nibepi/LICENSE
================================================
MIT License
Copyright (c) 2020 anerdins
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: docker/nibepi/README.md
================================================
# nibepi
Backend for Nibe F series heatpump
================================================
FILE: docker/nibepi/backend.js
================================================
/*MIT License
Copyright (c) 2019 Fredrik Anerdin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
const version = "1.1.0";
/*var exec = require('child_process').exec;
exec(`sudo chrt -a -f -p 99 ${process.pid}`, function(error, stdout, stderr) {
if(error) {
} else {
console.log('High priority backend is started')
}
});*/
const serialport = require('serialport');
const nack = [0x15];
const ack = [0x06];
var myPort;
const sendQueue = [[192,107,6,115,176,1,0,0,0,111],[192,107,6,212,190,0,0,0,0,199]];
const getQueue = [];
const rmuQueue = [];
var regQueue = [];
var regCount = 0;
var msgOut = Buffer.alloc(0);
var rmu_buffer = Buffer.alloc(0);
var red = false;
var fs_start = false;
var rmu_start = false;
let other_start = false;
var startReset = true;
let checkACK = {};
process.on('message', (m) => {
if(m.start===true) {
if(m.port!==undefined) {
portName = m.port;
myPort = new serialport(portName, 9600);
myPort.on('open', showPortOpen);
myPort.on('data', analyzeData);
myPort.on('close', showPortClose);
myPort.on('error', showError);
} else {
if(process.connected===true) {
process.send({type:"log",data:'Error starting backend, no serial port specified',level:"error",kind:"Serialport"});
}
}
} else if(m.type=="reqData") {
getQueue.unshift(m.data);
} else if(m.type=="setData") {
sendQueue.push(m.data);
} else if(m.type=="rmuSet") {
rmuQueue.push(m.data);
} else if(m.type=="regRegister") {
regQueue = m.data;
} else if(m.type=="red") {
red = m.data;
}
});
process.on('disconnect', (m) => {
if(red===false) {
console.log('Shutting down the core.')
process.exit(99);
}
});
function showPortOpen() {
//console.log(`Core started on serial port ${portName}`);
}
function showPortClose() {
console.log('Port closed. Data rate: ' + myPort.baudRate);
}
function showError(error) {
if(process.connected===true) {
process.send({type:"fault",data:{from:"core",message:"The core could not be started, check the serialport"}});
}
myPort.removeAllListeners();
if(process.connected===true) {
process.disconnect();
console.log('Error in the core, shuting it down.')
process.exit(99);
}
}
function analyzeData(data) {
if(process.connected===true) {
process.send({type:"log",data:Array.from(data),level:"core",kind:"RAW"});
}
// Sometimes and ACK [0x06] is the first byte, and the second byte is the start. We shift it.
if(data[0]===0x06 && data[1]===0x5C) {
//console.log('ACK')
data = data.slice(1)
} else if(data[0]===0x06 && data[1]===undefined) {
//console.log('ACK')
}
//Check for start message, 0x5C if it's Nibe F series.
if(fs_start===false) {
if(data[0]===0x5C) {
fs_start = true;
}
}
if(fs_start===true) {
msgOut = Buffer.concat([msgOut,data]);
if(msgOut.length>=3) {
if(startReset===true) {
startReset = false;
sendQueue.push([192,107,6,115,176,1,0,0,0,111]);
}
// Only decode objects we know
if(msgOut[2]!==0x19 && msgOut[2]!==0x1A && msgOut[2]!==0x1B && msgOut[2]!==0x1C&& msgOut[2]!==0x20) {
msgOut = Buffer.alloc(0)
fs_start = false;
}
if(msgOut.length>=5) {
let msgLength = msgOut[4]+6;
// Check if we have the full length of the message.
if(msgOut.length>=msgLength) {
// We have full length
if(msgOut[2]==0x19 || msgOut[2]==0x1A || msgOut[2]==0x1B || msgOut[2]==0x1C) {
if(checkACK[msgOut[2]]===undefined) {
if(msgOut.length>=6) {
if(msgOut[msgOut[4]+6]===0x06 || msgOut[msgOut[4]+6]===0xC0) {
checkACK[msgOut[2]] = true;
msgOut = Buffer.alloc(0)
fs_start = false;
} else {
checkACK[msgOut[2]] = false;
msgOut = Buffer.alloc(0)
fs_start = false;
}
} else {
msgLength++;
}
return;
}
}
msgOut = msgOut.slice(0, msgLength);
checkMessage(msgOut).then(data => {
makeResponse(data).then(result => {
if(startReset===false) {
result = Array.from(result);
let doubleFound = false;
for (i = 5; i < result.length - 1; i = i + 1) {
if(result[i]===92 && result[i+1]===92) {
result.splice(i, 1);
result[4] = result[4]-1;
doubleFound = true;
}
}
if(doubleFound===true) {
var calcChecksum = 0;
for(i = 2; i < (result[4] + 5); i++) {
calcChecksum ^= result[i];
}
result[result.length-1] = calcChecksum;
}
if(process.connected===true) {
process.send({type:"data",data:result,rmu:checkACK[result[2]]});
process.send({type:"log",data:result,level:"debug",kind:"OK"});
}
}
}, err => {
})
}, err => {
err = Array.from(err);
console.log(`CHKSUM ERROR: ${err}`)
if(process.connected===true) {
process.send({type:"log",data:err,level:"error",kind:"CHKSUM"});
}
myPort.write(nack);
})
} else {
// Message is not ready yet.
}
}
}
}
}
const checkMessage = (data) => {
const promise = new Promise((resolve,reject) => {
let error = data;
msgOut = Buffer.alloc(0);
fs_start = false;
msgChecksum = data[data[4]+5];
var calcChecksum = 0;
for(i = 2; i < (data[4] + 5); i++) {
calcChecksum ^= data[i];
}
if((msgChecksum==calcChecksum) || (msgChecksum==0xC5 && calcChecksum==0x5C)) {
resolve(data);
} else {
reject(error)
}
});
return promise;
}
const makeResponse = (data) => {
const promise = new Promise((resolve,reject) => {
// Read from heatpump
if(data[2]==0x19 || data[2]==0x1A || data[2]==0x1B || data[2]==0x1C) { // < System
if(data[3]==0x60) { // Send data message
if(checkACK[data[2]]===false) {
if(rmuQueue.length!==0) {
var lastMsg = rmuQueue.pop();
if(lastMsg!==undefined) {
if(Number(lastMsg.ackback[2])==Number(data[2])) {
let address = lastMsg.address;
if(process.connected===true) {
process.send({type:"ack",data:{register:address,ack:true}});
process.send({type:"log",data:`Register: ${address}, Buffer: ${JSON.stringify(lastMsg)}`,level:"core",kind:"RMU SENT"});
}
if(lastMsg.data[3]===6) {
if(process.connected===true) {
process.send({type:"data",data:lastMsg.ackback,rmu:checkACK[lastMsg.ackback[2]]});
process.send({type:"log",data:lastMsg,level:"debug",kind:"RMU ACKBACK"});
}
}
myPort.write(lastMsg.data);
} else {
rmuQueue.push(lastMsg);
myPort.write(ack);
resolve(data);
}
} else {
myPort.write(ack);
resolve(data);
}
} else {
myPort.write(ack);
resolve(data);
}
} else {
resolve(data);
}
} else if(data[3]==0x62) {
// Message updates
if(checkACK[data[2]]===false) {
if(process.connected===true) {
let logOut = Array.from(data);
process.send({type:"log",data:logOut,level:"debug",kind:"RMU DATA"});
}
myPort.write(ack);
resolve(data);
} else {
resolve(data);
}
resolve(data);
} else if(data[3]==0x63) {
if(checkACK[data[2]]===false) {
myPort.write([192,96,2,99,0,193]);
resolve(data);
} else {
resolve(data);
}
} else if(data[3]==0xEE) {
if(checkACK[data[2]]===false) {
if(process.connected===true) {
process.send({type:"log",data:"Sending RMU Version v259",level:"debug",kind:"RMU ACK"});
}
myPort.write([192,238,3,238,3,1,193]);
resolve(data);
} else {
resolve(data);
}
} else {
if(checkACK[data[2]]===false) {
myPort.write(ack);
resolve(data);
} else {
resolve(data);
}
}
} else if(data[3]==105 && data[4]==0x00) {
if(getQueue!==undefined && getQueue.length!==0) {
var lastMsg = getQueue.pop();
if(lastMsg!==undefined) {
myPort.write(lastMsg);
resolve(data);
} else if(getQueue.length!==0) {
lastMsg = getQueue.pop();
if(lastMsg!==undefined) {
myPort.write(lastMsg);
resolve(data);
} else {
myPort.write(ack);
resolve(data);
}
} else {
myPort.write(ack);
resolve(data);
}
} else {
if(regQueue.length!==0) {
if(regCount>=regQueue.length) regCount = 0;
myPort.write(regQueue[regCount]);
regCount++;
resolve(data);
} else {
myPort.write(ack);
resolve(data);
}
}
// Write to heatpump
} else if(data[3]==107 && data[4]==0x00) {
if(sendQueue.length!==0) {
var lastMsg = sendQueue.pop();
if(lastMsg!==undefined) {
let address = (lastMsg[4] * 256 + lastMsg[3]);
if(process.connected===true) {
process.send({type:"ack",data:{register:address,ack:true}});
process.send({type:"log",data:`Register: ${address}, Buffer: ${JSON.stringify(lastMsg)}`,level:"debug",kind:"SENT"});
}
myPort.write(lastMsg);
resolve(data);
} else {
myPort.write(ack);
resolve(data);
}
} else {
myPort.write(ack);
resolve(data);
}
} else {
if(data[3]==109) {
} else if(data[3]==238) {
} else if(data[3]==106 || data[3]==104) {
} else {
}
myPort.write(ack);
resolve(data);
}
});
return promise;
}
================================================
FILE: docker/nibepi/default.json
================================================
{
"version":"1.1",
"registers":[],
"connection": {
"enable":"serial",
"series":"fSeries"
},
"serial":{
"port":"/dev/ttyAMA0"
},
"home": {
"adjust_s1":0,
"adjust_s2":0
},
"mqtt": {
"enable":false,
"host":"127.0.0.1",
"port":"1883",
"user":"",
"pass":"",
"topic":"nibe/modbus/"
},
"system": {
"readonly": true
},
"hotwater": {
"enable_autoluxury": false,
"diff": 20,
"time": 10,
"enable_hw_priority": false
},
"log": {
"enable": false,
"info": false,
"core": false,
"debug": false,
"error": true
},
"indoor": {
"dm_reset_enable":false,
"dm_reset_enable_stop":false,
"dm_reset_stop_diff":0.7,
"dm_reset_slow_diff":0.3
},
"fan": {
"co2_limit":800,
"low_cpr_freq":40
}
}
================================================
FILE: docker/nibepi/index.js
================================================
/*MIT License
Copyright (c) 2019 Fredrik Anerdin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
//const path = __dirname;
const Core = require(__dirname+'/lib/startCore')
const startCore = Core.startCoreF;
const startCoreS = Core.startCoreS;
const startNibeGW = Core.startNibeGW;
const stopCore = require(__dirname+'/lib/stopCore');
var log = require('./log');
var child = require('child_process');
var docker = false;
let exec = child.exec;
let spawn = child.spawn;
let model = "";
let rmu = {};
let firmware = "";
let register = [];
let mqtt_client;
let mqtt_subcribers = [];
let mqttData = {};
let mqttDiscoverySensors = [];
let red = false;
let config;
const regQueue = [];
var pumpModel = require(__dirname+'/lib/models.json')
const EventEmitter = require('events').EventEmitter
const nibeEmit = new EventEmitter();
const fs = require('fs');
const path = "/etc/nibepi"
if (!fs.existsSync(path)) {
exec(`sudo mount -o remount,rw / && sudo mkdir ${path} && sudo chown ${process.env.USER}:${process.env.USER} ${path}`, function(error, stdout, stderr) {
if(error) {
exec(`mkdir ${path} && chown ${process.env.USER}:${process.env.USER} ${path}`, function(error, stdout, stderr) {
if(error) {console.log('Error creating config directory')} else { console.log('Created config directory')}
});
} else {
console.log(`Configuration directory created ${path}`);
}
});
}
function requireF(modulePath){ // force require
try {
return require(modulePath);
}
catch (e) {
console.log('Config file not found, loading default.');
let conf = require(__dirname+'/default.json')
fs.writeFile(path+'/config.json', JSON.stringify(conf,null,2), function(err) {
if(err) console.log(err)
});
return conf;
}
}
function requireGraph(){ // force require
const promise = new Promise((resolve,reject) => {
try {
resolve(require(path+'/graph.json'));
}
catch (e) {
reject('No graphs to load.')
}
});
return promise;
}
config = requireF(path+'/config.json');
var timer;
const saveGraph = (data) => {
const promise = new Promise((resolve,reject) => {
if(config.system===undefined || config.system.save_graph!==true) reject();
if(data===undefined) reject(new Error('Cant save empty graph'));
if(config.system===undefined) config.system = {};
if(config.log===undefined) config.log = {};
if(config.system.readonly===true) {
exec('sudo mount -o remount,rw /', function(error, stdout, stderr) {
if(error) {
reject(new Error('Error saving graph, could not set RW mode'));
} else {
fs.writeFile(path+'/graph.json', JSON.stringify(data,null,2), function(err) {
if(err) reject(new Error('Error saving graph to disc, write error'));
log(config.log.enable,"Graphs saved",config.log['info'],"Graph");
nibeEmit.emit('fault',{from:"Grafer",message:'Graferna är sparade till SD-kort'});
resolve('Graferna sparade till SD-kort')
exec('sudo mount -o remount,ro /', function(error, stdout, stderr) {
if(error) {
nibeEmit.emit('fault',{from:"Grafer",message:'Kunde inte sätta läsbart läge på filsystemet.'});
reject(new Error('Error setting read-only mode after saving graph'));
} else {
console.log('Read only mode set.')
resolve('Graferna är sparade till SD-kort och läsbart läge aktivt')
}
})
});
}
});
} else {
exec('sudo mount -o remount,rw /', function(error, stdout, stderr) {
if(error) {
log(config.log.enable,"Could not open the system for write mode",config.log['error'],"Config");
reject(new Error('Error saving graph, could not set RW mode'));
} else {
fs.writeFile(path+'/graph.json', JSON.stringify(data,null,2), function(err) {
if(err) reject(new Error('Error saving graph to disc, write error'));
nibeEmit.emit('fault',{from:"Grafer",message:'Graferna är sparade till SD-kort'});
resolve('Graferna sparade till SD-kort')
});
}
});
}
});
return promise;
}
let startingMQTT = false;
const updateConfig = (data) => {
config = data;
handleMQTT(config.mqtt.enable,config.mqtt.host,config.mqtt.port,config.mqtt.user,config.mqtt.pass, (err,result) => {
if(err) {
return console.log(err);
} else {
}
})
nibeEmit.emit('config',config);
let run = false;
if(timer!==undefined && timer._idleTimeout>0) {
clearTimeout(timer);
run = true;
} else {
run = true;
}
if(run===true) {
timer = setTimeout(() => {
if(JSON.stringify(data).length>2) {
if(config.system===undefined) config.system = {};
if(config.log===undefined) config.log = {};
if(config.system.readonly===true && docker===false) {
exec('sudo mount -o remount,rw /', function(error, stdout, stderr) {
if(error) {
log(config.log.enable,"Could not open the system for write mode",config.log['error'],"Config");
return(false);
} else {
fs.writeFile(path+'/config.json', JSON.stringify(data,null,2), function(err) {
if(err) return (false);
log(config.log.enable,"Config file saved",config.log['info'],"Config");
nibeEmit.emit('fault',{from:"Inställningar",message:'Inställningarna är sparade till SD-kort'});
exec('sudo mount -o remount,ro /', function(error, stdout, stderr) {
if(error) {
nibeEmit.emit('fault',{from:"Inställningar",message:'Kunde inte sätta läsbart läge på filsystemet.'});
log(config.log.enable,"Could not set read-only mode.",config.log['error'],"Config");
return(false);
} else {
console.log('Read only mode set.')
return (true)
}
})
});
}
});
} else {
if(docker===false) {
exec('sudo mount -o remount,rw /', function(error, stdout, stderr) {
if(error) {
log(config.log.enable,error,config.log['error'],"Config");
return(false);
} else {
fs.writeFile(path+'/config.json', JSON.stringify(data,null,2), function(err) {
if(err) {
log(config.log.enable,err,config.log['error'],"Config");
return (false);
}
nibeEmit.emit('fault',{from:"Inställningar",message:'Inställningarna är sparade till SD-kort'});
log(config.log.enable,"Config file saved",config.log['info'],"Config");
return (true)
});
}
});
} else if(docker===true) {
fs.writeFile(path+'/config.json', JSON.stringify(data,null,2), function(err) {
if(err) {
log(config.log.enable,err,config.log['error'],"Config");
return (false);
}
nibeEmit.emit('fault',{from:"Inställningar",message:'Inställningarna är sparade till SD-kort'});
log(config.log.enable,"Config file saved",config.log['info'],"Config");
return (true)
});
}
}
}
}, 5000);
}
}
let core;
const resetCore = () => {
model = "";
register = [];
firmware = "";
}
const initiateCore = (host,port,cb) => {
if(config.log===undefined) config.log = {};
if(docker===false) {
if(config.system.readonly===true) {
exec('sudo mount -o remount,ro /', function(error, stdout, stderr) {
if(error) {
log(config.log.enable,"Could not set read-only mode at startup.",config.log['error'],"Startup");
return(false);
} else {
console.log('Read only mode set.')
return (true)
}
})
} else {
exec('sudo mount -o remount,rw /', function(error, stdout, stderr) {
if(error) {
log(config.log.enable,"Could not set write mode at startup.",config.log['error'],"Startup");
return(false);
} else {
return (true)
}
})
}
}
if(config.connection!==undefined && config.connection.series!==undefined) {
if(config.connection.series=="fSeries") {
if(config.connection.enable=="serial") {
startCore(port).then(result => {
core = result;
core.on('message', (m) => {
if(m.type=="data") {
let n = m.data;
announcment(m, (err,ready) => {
if(err) console.log(err);
if(ready===true) {
config.serial.port = port;
cb(null,result);
} else {
}
});
decodeRMU(n);
decodeMessage(n);
} else if(m.type=="fault") {
nibeEmit.emit('fault',m.data);
} else if(m.type=="ack") {
nibeEmit.emit("ACK_"+m.data.register,m.data.ack);
} else if(m.type=="log") {
if(config.log===undefined) {
config.log = {};
updateConfig(config);
}
log(config.log.enable,m.data,config.log[m.level],m.kind);
}
});
});
} else if(config.connection.enable=="nibegw") {
startNibeGW(port).then(result => {
core = result;
core.on('message', (m) => {
if(m.type=="data") {
let n = m.data;
announcment(m, (err,ready) => {
if(err) console.log(err);
if(ready===true) {
config.serial.port = port;
cb(null,result);
} else {
}
});
decodeMessage(n);
} else if(m.type=="fault") {
nibeEmit.emit('fault',m.data);
} else if(m.type=="ack") {
nibeEmit.emit("ACK_"+m.data.register,m.data.ack);
} else if(m.type=="log") {
if(config.log===undefined) {
config.log = {};
updateConfig(config);
}
log(config.log.enable,m.data,config.log[m.level],m.kind);
}
});
});
}
} else if(config.connection.series=="sSeries") {
startCoreS(host,port).then(result => {
core = result;
core.on('message', (m) => {
if(m.type=="started") {
let data = m.data;
if(config.tcp!==undefined && config.tcp.pump!==undefined) {
let reg = require(pumpModel[config.tcp.pump]);
if(reg!==undefined) {
for (i = 0; i < reg.length; i = i + 1) {
let found = false;
for (j = 0; j < register.length; j = j + 1) {
if(register[j].register===reg[i].register) {
found = true;
}
}
if(found===false) {
register.push(reg[i])
}
}
if(regQueue.length===0) {
for (var i = 0; i < config.registers.length; i++) {
addRegular(config.registers[i]);
}
}
}
}
if(data===true) {
cb(null,result);
}
// Process message
} else if(m.type=="data") {
let data = m.data;
decodeS(data);
} else if(m.type=="ack") {
nibeEmit.emit("ACK_"+m.data.register,m.data.ack);
} else if(m.type=="fault") {
nibeEmit.emit('fault',m.data);
} else if(m.type=="log") {
if(config.log===undefined) {
config.log = {};
updateConfig(config);
}
log(config.log.enable,m.data,config.log[m.level],m.kind);
}
});
});
}
}
}
const announcment = (msg,cb) => {
const checkPump = (data,callback) => {
let modelLength = data[4]+5;
model = (Buffer.from(data).slice(8,modelLength).toString()).split(" ");
firmware = (data[6]*256)+data[7];
if(model[0]=="VVM") {
model[0] = model[0]+model[1];
}
model = model[0].split("-");
model = model[0];
config.system.pump = model;
config.system.firmware = firmware;
callback(null);
}
if(model=="" && config.system.pump!==undefined && config.system.pump!=="" && config.system.firmware!==undefined && config.system.firmware!=="") {
model = config.system.pump;
firmware = config.system.firmware;
let reg = require(pumpModel[model]);
for (i = 0; i < reg.length; i = i + 1) {
let found = false;
for (j = 0; j < register.length; j = j + 1) {
if(register[j].register===reg[i].register) {
found = true;
}
}
if(found===false) {
register.push(reg[i])
}
}
cb(null,true)
console.log(`Nibe ${model} connected`);
console.log(`Firmware ${firmware}`);
console.log(`Register is set. Length: ${register.length}`)
} else if(msg.data[3]==109) {
let index = register.findIndex(i => i.register == 45001);
if(index!==-1) {
reqData(45001).then(atad => {
let data = Object.assign({}, atad);
if(data!==undefined && data.raw_data===251) {
console.log('Resetting alarm.')
setData(45171,1);
}
},err => {
});
}
//console.log(`Announcement message`);
if(model=="") {
checkPump(msg.data, function(err) {
if(err) throw err;
let reg = require(pumpModel[model]);
for (i = 0; i < reg.length; i = i + 1) {
let found = false;
for (j = 0; j < register.length; j = j + 1) {
if(register[j].register===reg[i].register) {
found = true;
}
}
if(found===false) {
register.push(reg[i])
}
}
cb(null,true)
console.log(`Nibe ${model} connected`);
console.log(`Firmware ${firmware}`);
console.log(`Register is set. Length: ${register.length}`)
});
}
} else if(msg.data[3]==98) {
//log('info',msg.data)
if(rmu['s'+((-24)+msg.data[2])]===undefined || rmu['s'+((-24)+msg.data[2])]===false) {
rmu['s'+((-24)+msg.data[2])] = true;
let reg = require(pumpModel['RMU40_S'+((-24)+msg.data[2])]);
for (i = 0; i < reg.length; i = i + 1) {
if(msg.rmu===true) { reg[i].mode = "R"; }
let found = false;
for (j = 0; j < register.length; j = j + 1) {
if(register[j].register===reg[i].register) {
found = true;
}
}
if(found===false) {
register.push(reg[i])
}
}
if(msg.rmu===true) {
console.log('RMU40 System '+((-24)+msg.data[2])+' connected (read-only mode)');
} else {
console.log('RMU40 System '+((-24)+msg.data[2])+' connected');
// EMIT HERE
nibeEmit.emit('rmu_ready','s'+((-24)+msg.data[2]));
}
console.log(`Register is set. Length: ${register.length}`)
cb(null,false)
}
} else {
cb(null,false)
}
}
let getTimer = {};
async function reqData (address) {
async function getDataFseries(address) {
const promise = new Promise((resolve,reject) => {
let index = register.findIndex(index => index.register == address);
if(index!==-1 || (address!==undefined && config.system.testmode===true && address!=="00000")) {
getTimer[address] = setTimeout((address,index) => {
getTimer[address] = setTimeout((address) => {
nibeEmit.removeAllListeners(address);
reject(new Error('No respond from register ('+address+')'));
}, 30000, address);
if(register[index]!==undefined || config.system.testmode===true) {
if(register[index]!==undefined) register[index].logset = false;
var data = [];
data[0] = 0xc0;
data[1] = 0x69;
data[2] = 0x02;
data[3] = (address & 0xFF);
data[4] = ((address >> 8) & 0xFF);
data[5] = Calc_CRC(data);
nibeEmit.removeAllListeners(address);
nibeEmit.once(address,(data) => {
clearTimeout(getTimer[data.register]);
resolve(data);
})
core.send({type:"reqData",data:data});
} else {
reject(new Error('Register ('+address+') returned no data.'));
}
}, 7000, address,index);
if((register[index]===undefined && config.system.testmode===true) || register[index].logset===undefined || register[index].logset===false) {
var data = [];
data[0] = 0xc0;
data[1] = 0x69;
data[2] = 0x02;
data[3] = (address & 0xFF);
data[4] = ((address >> 8) & 0xFF);
data[5] = Calc_CRC(data);
nibeEmit.once(address,(data) => {
clearTimeout(getTimer[data.register]);
resolve(data);
})
core.send({type:"reqData",data:data});
} else {
nibeEmit.once(address,(data) => {
clearTimeout(getTimer[data.register]);
resolve(data);
})
}
} else {
reject(new Error('Register ('+address+') not in database'));
}
});
return promise;
}
async function getDataSseries(address) {
const promise = new Promise((resolve,reject) => {
let index = register.findIndex(index => index.register == address);
if(index!==-1 || (address!==undefined && config.system.testmode===true && address!=="00000")) {
getTimer[address] = setTimeout((address) => {
nibeEmit.removeAllListeners(address);
reject(new Error('No respond from register ('+address+')'));
}, 30000, address);
nibeEmit.once(address,(data) => {
resolve(data);
clearTimeout(getTimer[data.register]);
});
core.send({type:"reqData",data:address});
} else {
reject(new Error('Register ('+address+') not in database'));
}
});
return promise;
}
const promise = new Promise((resolve,reject) => {
if(core!==undefined && core.connected!==undefined && core.connected===true) {
if(config.connection===undefined || config.connection.series===undefined) return reject(new Error('Configuration is invalid'));
if(config.connection.series=="fSeries") {
if(model.length!==0) {
getDataFseries(address).then(result => {
resolve(result)
},(error => {
reject(error)
}));
} else {
reject(new Error('Heatpump is not ready yet.'))
}
} else if(config.connection.series=="sSeries") {
getDataSseries(address).then(result => {
resolve(result)
},(error => {
reject(error)
})).catch(err => {
reject(error)
});
}
} else {
reject(new Error('Core is not started.'))
}
});
return promise;
}
const setData = (address,value,cb=()=>{}) => {
var output = setDataValue({register:address,value:value})
if(output===-1) {
let err = ('Register dont exist')
return cb(err);
} else if(output===-2) {
let err = ('Register not writeable');
return cb(err);
}
if(core!==undefined && core.connected!==undefined && core.connected===true) {
if(output!==undefined) {
nibeEmit.once("ACK_"+address,(result) => {
cb(null,result);
})
if(address.toString().charAt(0)=="1") {
core.send({type:"rmuSet",data:output});
} else {
core.send({type:"setData",data:output});
reqData(address);
}
}
} else {
setTimeout((data,address) => {
if(core!==undefined && core.connected!==undefined && core.connected===true) {
if(data!==undefined) {
nibeEmit.once("ACK_"+address,(result) => {
cb(null,result);
})
if(address.toString().charAt(0)=="1") {
core.send({type:"rmuSet",data:data});
} else {
core.send({type:"setData",data:data});
reqData(address);
}
}
}
}, 5000, output,address);
}
}
function getData(address) {
var item = register.find(item => item.register == address);
if(item!==undefined || config.system.testmode===true) {
if(config.connection.enable!==undefined && (config.connection.enable=="serial" || config.connection.enable=="nibegw")) {
var data = [];
data[0] = 0xc0;
data[1] = 0x69;
data[2] = 0x02;
data[3] = (address & 0xFF);
data[4] = ((address >> 8) & 0xFF);
data[5] = Calc_CRC(data);
return(data);
} else if(config.connection.enable!==undefined && config.connection.enable=="tcp") {
return(address);
}
} else {
console.log('Register('+address+') not in database');
return;
}
}
function setDataValue(incoming) {
var item = register.find(item => item.register == incoming.register);
if(item!==undefined) {
var data = [];
var rmu = {data:[],address:incoming.register,ackback:[]};
if(item.mode=="R/W") {
var min = Number(item.min);
var max = Number(item.max);
var corruptData;
incoming.value = incoming.value*item.factor;
if(min!==undefined && max!==undefined) {
if(min!==0 || max!==0) {
if(incoming.value>max) {
incoming.value = max
corruptData = true;
nibeEmit.emit('fault',{from:"Skicka värde",message:'Data ('+incoming.value/item.factor+') utanför giltigt värde som får skickas.'});
log(config.log.enable,'Data ('+incoming.value/item.factor+') out of range, to register '+incoming.register,config.log['error'],"Data");
} else if(incoming.value<min) {
incoming.value = min;
corruptData = true;
nibeEmit.emit('fault',{from:"Skicka värde",message:'Data ('+incoming.value/item.factor+') utanför giltigt värde som får skickas.'});
log(config.log.enable,'Data ('+incoming.value/item.factor+') out of range, to register '+incoming.register,config.log['error'],"Data");
}
}
}
if(config.connection.enable!==undefined && (config.connection.enable=="serial" || config.connection.enable=="nibegw")) {
if(item.register.charAt(0)=="1") {
let len = 0x03;
if(item.size=="s8" || item.size=="u8") {
len = 0x02;
}
rmu.data[0] = 0xc0;
rmu.data[1] = 0x60;
rmu.data[2] = len;
rmu.data[3] = Number(item.register.charAt(3));
if(item.size=="s8" || item.size=="u8") {
rmu.data[4] = (incoming.value & 0xFF);
rmu.data[5] = Calc_CRC(rmu.data);
} else {
let value = incoming.value;
if(value>=32768) { value = value-7 } else { value = value+7 }
rmu.data[4] = (value & 0xFF);
rmu.data[5] = ((value >> 8) & 0xFF);
rmu.data[6] = Calc_CRC(rmu.data);
}
rmu.ackback[0] = 92;
rmu.ackback[1] = 0;
rmu.ackback[2] = (Number(item.register.charAt(2))+25);
rmu.ackback[3] = 96;
rmu.ackback[4] = 6;
rmu.ackback[5] = (incoming.register & 0xFF);
rmu.ackback[6] = ((incoming.register >> 8) & 0xFF);
rmu.ackback[7] = (incoming.value & 0xFF);
rmu.ackback[8] = ((incoming.value >> 8) & 0xFF);
rmu.ackback[9] = ((incoming.value >> 16) & 0xFF);
rmu.ackback[10] = ((incoming.value >> 24) & 0xFF);
rmu.ackback[11] = Calc_CRC(rmu.ackback);
} else {
data[0] = 0xc0;
data[1] = 0x6b;
data[2] = 0x06;
data[3] = (incoming.register & 0xFF);
data[4] = ((incoming.register >> 8) & 0xFF);
data[5] = (incoming.value & 0xFF);
data[6] = ((incoming.value >> 8) & 0xFF);
data[7] = ((incoming.value >> 16) & 0xFF);
data[8] = ((incoming.value >> 24) & 0xFF);
data[9] = Calc_CRC(data);
}
if(corruptData===undefined) {
log(config.log.enable,`Sending data: ${incoming.register}, ${incoming.value}, ${JSON.stringify(data)}`,config.log['info'],"Data");
if(data.length===0) {
return rmu;
} else {
return data;
}
}
} else if(config.connection.enable!==undefined && config.connection.enable=="tcp") {
if(corruptData===undefined) {
item.data = incoming.value;
log(config.log.enable,`Sending data: ${incoming.register}, ${incoming.value}`,config.log['info'],"Data");
return item;
}
}
} else {
nibeEmit.emit('fault',{from:"Skicka värde",message:'Register('+incoming.register+') går ej att skriva till.'});
log(config.log.enable,'Register('+incoming.register+') not allowed write access',config.log['error'],"Data");
return -2;
}
} else {
nibeEmit.emit('fault',{from:"Skicka värde",message:'Register('+incoming.register+') finns ej i databasen.'});
log(config.log.enable,'Register('+incoming.register+') not in database',config.log['error'],"Data");
return -1;
}
}
function Calc_CRC(data) {
var calc_checksum = 0;
for (var i = 0; i < (data[2] + 5); i++)
calc_checksum ^= data[i];
return calc_checksum;
}
const addRegister = (address,logset=false) => {
if(register.length!==0) {
let index = register.findIndex(index => index.register == address);
if(index===-1 && config.system.testmode!==true) {
return;
};
if(config.registers===undefined) {
config.registers = [];
updateConfig(config)
}
if(register[index]!==undefined) register[index].logset = logset;
let confIndex = config.registers.findIndex(confIndex => confIndex == address);
if(confIndex===-1) {
log(config.log.enable,`Adding register ${address}`,config.log['info'],"Register");
config.registers.push(address);
if(logset===false) {
addRegular(address);
}
updateConfig(config)
}
}
}
function removeRegister(address) {
if(register!==[] && register.length>1) {
let index = register.findIndex(index => index.register == address);
if(index===-1 && config.system.testmode!==true) {
return;
};
if(config.registers===undefined) {
config.registers = [];
updateConfig(config)
}
let confIndex = config.registers.findIndex(confIndex => confIndex == address);
if(confIndex!==-1) {
config.registers.splice(confIndex,1);
removeMQTTdiscovery(register[index]);
updateConfig(config)
removeRegular(address);
}
}
}
const addRegular = (address) => {
if(core!==undefined && core.connected!==undefined && core.connected===true) {
log(config.log.enable,`Adding regular register (${address})`,config.log['debug'],"Register");
let regIndex = register.findIndex(regIndex => regIndex.register == address);
if(register[regIndex]===undefined && config.system.testmode!==true) {
log(config.log.enable,`Regular register (${address}) not in database`,config.log['debug'],"Register");
return;
};
if((config.system.testmode!==true && register[regIndex]===-1) || (register[regIndex]!==undefined && register[regIndex].logset!==undefined && register[regIndex].logset===true)) {
log(config.log.enable,`Regular register (${address}) not in database or logset register`,config.log['debug'],"Register");
return;
}
let index = regQueue.findIndex(index => index == getData(address));
if(index===-1) {
if(address.toString().charAt(0)=="1") {
log(config.log.enable,`RMU register not added to regular list, Register: ${address}`,config.log['debug'],"Register");
} else {
// Req data change
reqData(address);
regQueue.push(getData(address));
log(config.log.enable,`Regular register added (${getData(address)})`,config.log['info'],"Register");
core.send({type:"regRegister",data:regQueue});
}
//
}
} else {
setTimeout((data) => {
addRegular(data)
}, 10000, address);
}
}
const removeRegular = (address) => {
var stringed = getData(address).toString();
if(core!==undefined && core.connected!==undefined && core.connected===true) {
for (i = 0; i < regQueue.length; i = i + 1) {
let value = regQueue[i].toString();
if(stringed===value) {
regQueue.splice(i,1)
log(config.log.enable,`Regular register removed (${address})`,config.log['info'],"Register");
core.send({type:"regRegister",data:regQueue});
}
}
} else {
setTimeout((data) => {
removeRegular(data);
}, 10000, address);
}
}
const decodeRMU = (buf) => {
if((buf[2]==0x19 || buf[2]==0x1A || buf[2]==0x1B || buf[2]==0x1C) && buf[3]===98) {
let data = [];
let bitData = buf[21];
let r = {};
if(bitData>=128) { bitData = bitData-128; } else { }
if(bitData>=64) { bitData = bitData-64; }
if(bitData>=32) { bitData = bitData-32; r[47393] = 1;} else { r[47393] = 0; } // Inside S2 activated
if(bitData>=16) { bitData = bitData-16; r[47394] = 1;} else { r[47394] = 0; } // Inside S1 activated
if(bitData>=8) { bitData = bitData-8; }
if(bitData>=4) { bitData = bitData-4; }
if(bitData>=2) { bitData = bitData-2; }
if(bitData>=1) { bitData = bitData-1; }
if(r[47394]===1) { r[47398] = buf[9]+50 } else { r[47011] = buf[9] };
if(r[47393]===1) { r[47397] = buf[10]+50 } else { r[47010] = buf[10] };
r[40004] = (buf[6] & 0xFF) << 8 | (buf[5] & 0xFF);
if(r[40004]>=32768) { r[40004] = r[40004]+5 } else { r[40004] = r[40004]-5 }
r[40013] = ((buf[8] & 0xFF) << 8 | (buf[7] & 0xFF))-5;
r[40058] = ((buf[14] & 0xFF) << 8 | (buf[13] & 0xFF))-5;
data[0] = 92;
data[1] = 0;
data[2] = buf[2];
data[3] = buf[3];
data[4] = data.length;
data[5] = (40004 & 0xFF);
data[6] = ((40004 >> 8) & 0xFF);
data[7] = (r[40004] & 0xFF);
data[8] = ((r[40004] >> 8) & 0xFF);
data[9] = (40013 & 0xFF);
data[10] = ((40013 >> 8) & 0xFF);
data[11] = (r[40013] & 0xFF);
data[12] = ((r[40013] >> 8) & 0xFF);
data[13] = (40058-buf[2] & 0xFF);
data[14] = ((40058-buf[2] >> 8) & 0xFF);
data[15] = (r[40058] & 0xFF);
data[16] = ((r[40058] >> 8) & 0xFF);
if(r[47394]===1) { data[17] = (47398 & 0xFF); } else { data[17] = (47011 & 0xFF); }
if(r[47394]===1) { data[18] = ((47398 >> 8) & 0xFF); } else { data[18] = ((47011 >> 8) & 0xFF); }
if(r[47394]===1) { data[19] = r[47398]; } else { data[19] = r[47011]; }
data[20] = 0;
if(r[47393]===1) { data[21] = (47397 & 0xFF); } else { data[21] = (47010 & 0xFF); }
if(r[47393]===1) { data[22] = ((47397 >> 8) & 0xFF); } else { data[22] = ((47010 >> 8) & 0xFF); }
if(r[47393]===1) { data[23] = r[47397]; } else { data[23] = r[47010]; }
data[24] = 0;
data[25] = (47394 & 0xFF);
data[26] = ((47394 >> 8) & 0xFF);
data[27] = r[47394];
data[28] = 0;
data[29] = (47393 & 0xFF);
data[30] = ((47393 >> 8) & 0xFF);
data[31] = r[47393];
data[32] = 0;
data[33] = (10001 & 0xFF);
data[34] = ((10001 >> 8) & 0xFF);
data[35] = buf[24];
data[36] = 0;
let fan_address = Number(`10${buf[2]-25}10`);
data[37] = (fan_address & 0xFF);
data[38] = ((fan_address >> 8) & 0xFF);
data[39] = buf[18];
data[40] = 0;
let hw_address = Number(`10${buf[2]-25}20`);
data[41] = (hw_address & 0xFF);
data[42] = ((hw_address >> 8) & 0xFF);
data[43] = buf[15];
data[44] = 0;
data[45] = (10011 & 0xFF);
data[46] = ((10011 >> 8) & 0xFF);
if(buf[18]===0) { data[47] = 0; } else { data[47] = buf[26]; }
data[48] = 0;
data[49] = (10012 & 0xFF);
data[50] = ((10012 >> 8) & 0xFF);
if(buf[18]===0) { data[51] = 0; } else { data[51] = buf[27]; }
data[52] = 0;
data[53] = (10021 & 0xFF);
data[54] = ((10021 >> 8) & 0xFF);
data[55] = buf[16];
data[56] = 0;
data[57] = (10022 & 0xFF);
data[58] = ((10022 >> 8) & 0xFF);
data[59] = buf[17];
data[60] = 0;
data[4] = data.length;
decodeMessage(data);
/*
if(i===26) address = 10011;
if(i===27) address = 10012;*/
}
}
async function decodeS(data) {
if(register.length===0) return;
let address = data.register;
data = data.data;
let timeNow = Date.now();
var index = register.findIndex(index => index.register == address);
if (index!==-1) {
if (register[index].size == "s32") {
if (data >= 2147483647) {
data = (data - 4294967294);
}
}
else if (register[index].size == "s16") {
if (data >= 32768) {
data = data - 65536;
}
}
else if (register[index].size == "s8") {
if (data > 128 && data < 32768) {
data = data - 256;
} else if (data >= 32768) {
data = data - 65536;
}
}
else if (register[index].size == "u32") {
data = data>>>0;
}
data = data / register[index].factor;
let corruptData = false;
let min = Number(register[index].min);
let max = Number(register[index].max);
if (min !== undefined && max !== undefined) {
if (min !== 0 || max !== 0) {
if ((data > max / register[index].factor) || (data < min / register[index].factor)) {
nibeEmit.emit('fault',{from:"Datahantering",message:'Korrupt värde från register '+address+", Värde: "+data+register[index].unit});
log(config.log.enable,register[index].register+", "+register[index].titel+": "+register[index].data+" "+register[index].unit,config.log['error'],"CORRUPT");
corruptData = true;
}
}
}
if(corruptData===false) {
register[index].data = data;
register[index].raw_data = data;
register[index].timestamp = timeNow;
nibeEmit.emit('data',register[index]);
nibeEmit.emit(address,register[index]);
addMQTTdiscovery(register[index]);
publishMQTT(config.mqtt.topic+address+"/json",JSON.stringify(register[index]))
publishMQTT(config.mqtt.topic+address+"/raw",register[index].raw_data)
publishMQTT(config.mqtt.topic+address,register[index].data)
log(config.log.enable,JSON.stringify(register[index]),config.log['debug'],"Data");
log(config.log.enable,register[index].register+", "+register[index].titel+": "+register[index].data+" "+register[index].unit,config.log['info'],"Data");
}
} else if((config.system.testmode===true && address!=="00000")) {
let output = {
register:address,
data:data,
raw_data:data,
factor:1,
unit:"",
size:"",
titel:"Unknown register "+address,
info:"",
mode:"R",
min:0,
max:0,
timestamp:timeNow
}
log(config.log.enable,JSON.stringify(output),config.log['debug'],"Data");
nibeEmit.emit('data',output);
nibeEmit.emit(address,output);
}
}
const decodeMessage = (buf) => {
if(register.length===0) return;
if(buf[3]!==104 && buf[3]!==106 && buf[3]!==98 && buf[3]!==96) return;
var data;
let timeNow = Date.now();
for (i = 5; i < buf.length-3; i = i + 1) {
var address = (buf[i + 1] * 256 + buf[i]);
var index = register.findIndex(index => index.register == address);
if (index!==-1) {
if (buf[3]===104 || buf[3]===98 || buf[3]===96) {
addRegister(address,true)
} else {
if(register[index].logset===true) {
removeRegular(address);
}
}
//log('info',`Register: ${register[index].register} found at index ${index}, ${JSON.stringify(register[index])}`)
if (register[index].size == "s32") {
if (buf[3]===104) {
data = buf[i + 2] | buf[i + 3]<<8 | buf[i + 6] <<16 | buf[i + 7] <<24;
if (data >= 2147483647) {
data = (data - 4294967294);
}
i = i + 7;
}
else {
data = buf[i + 4] | buf[i + 5] <<8 | buf[i + 2] <<16 | buf[i + 3] <<24;
//data = buf[i + 2] | buf[i + 3] <<8 | buf[i + 4] <<16 | buf[i + 5] <<24;
if (data >= 2147483647) {
data = (data - 4294967294);
}
i = i + 5;
}
}
else if (register[index].size == "s16") {
data = (buf[i + 3] & 0xFF) << 8 | (buf[i + 2] & 0xFF);
i = i + 3;
if (data >= 32768) {
data = data - 65536;
}
}
else if (register[index].size == "s8") {
data = (buf[i + 3] & 0xFF) << 8 | (buf[i + 2] & 0xFF);
i = i + 3;
if (data > 128 && data < 32768) {
data = data - 256;
} else if (data >= 32768) {
data = data - 65536;
}
}
else if (register[index].size == "u32") {
if (buf[3]===104) {
data = buf[i + 2] | buf[i + 3]<<8 | buf[i + 6] <<16 | buf[i + 7] <<24;
data = data>>>0;
i = i + 7;
}
else {
data = (buf[i + 4] & 0xFF) | (buf[i + 5] & 0xFF) << 8 | (buf[i + 2] & 0xFF) << 16 | (buf[i + 3] & 0xFF) << 24;
//data = (buf[i + 2] & 0xFF) | (buf[i + 3] & 0xFF) << 8 | (buf[i + 4] & 0xFF) << 16 | (buf[i + 5] & 0xFF) << 24;
//data = (buf[i + 2] & 0xFF) << 16 | (buf[i + 3] & 0xFF) << 24 | (buf[i + 4] & 0xFF) | (buf[i + 5] & 0xFF) << 8; Old way
data = data>>>0;
i = i + 5;
}
}
else if (register[index].size == "u16") {
data = (buf[i + 3] & 0xFF) << 8 | (buf[i + 2] & 0xFF);
i = i + 3;
}
else if (register[index].size == "u8") {
data = (buf[i + 3] & 0xFF) << 8 | (buf[i + 2] & 0xFF);
i = i + 3;
}
else {
i = i + 3;
}
data = data / register[index].factor;
var map = register[index].map;
var valueMap;
if (map !== undefined) {
for (y = 0; y < map.length; y = y + 1) {
var mapValue = Object.values(map[y]);
if (Number(Object.keys(map[y])) == data) {
valueMap = mapValue[0];
}
}
}
let corruptData = false;
let min = Number(register[index].min);
let max = Number(register[index].max);
if (min !== undefined && max !== undefined) {
if (min !== 0 || max !== 0) {
if ((data > max / register[index].factor) || (data < min / register[index].factor)) {
nibeEmit.emit('fault',{from:"Datahantering",message:'Korrupt värde från register '+address+", Värde: "+data+register[index].unit});
log(config.log.enable,register[index].register+", "+register[index].titel+": "+register[index].data+" "+register[index].unit,config.log['error'],"CORRUPT");
corruptData = true;
}
}
}
if(corruptData===false) {
if(valueMap!==undefined) {
register[index].data = valueMap;
valueMap = undefined;
} else {
register[index].data = data;
}
register[index].raw_data = data;
register[index].timestamp = timeNow;
nibeEmit.emit('data',register[index]);
nibeEmit.emit(address,register[index]);
addMQTTdiscovery(register[index]);
publishMQTT(config.mqtt.topic+address+"/json",JSON.stringify(register[index]))
publishMQTT(config.mqtt.topic+address+"/raw",register[index].raw_data)
publishMQTT(config.mqtt.topic+address,register[index].data)
log(config.log.enable,JSON.stringify(register[index]),config.log['debug'],"Data");
log(config.log.enable,register[index].register+", "+register[index].titel+": "+register[index].data+" "+register[index].unit,config.log['info'],"Data");
}
address = undefined;
} else {
i = i + 3;
}
}
if(regQueue.length===0 && buf[3]===104) {
for (var i = 0; i < config.registers.length; i++) {
addRegular(config.registers[i]);
}
}
}
const getConfig = () => {
//nibeEmit.emit('config',config);
return config;
}
const getRegister = () => {
return register;
}
function startMQTT(host,port,user,pass) {
return new Promise(function(resolve, reject) {
const mqtt = require('mqtt');
if(user=="") user = undefined;
if(pass=="") pass = undefined;
var mqtt_host = host;
var mqtt_port = port;
var mqtt_subscribe_topic = 'nibe';
var mqtt_publish_topic = 'nibe';
var mqtt_username = user;
var mqtt_password = pass;
var mqtt_client_id = 'nibe_' + Math.random().toString(16).substr(2, 8);
// MQTT CLIENT OPTIONS
var mqtt_Options = {
port: mqtt_port,
keepalive: 60,
clientId: mqtt_client_id,
protocolId: 'MQTT',
//protocolVersion: 4,
clean: true,
reconnectPeriod: 5000,
connectTimeout: 30 * 1000,
rejectUnauthorized: false,
username: mqtt_username, //the username required by your broker, if any
password: mqtt_password, //the password required by your broker, if any
will: { topic: mqtt_publish_topic, payload: mqtt_client_id + ' disconnected', qos: 1, retain: false }
};
mqtt_client = mqtt.connect('mqtt://' + mqtt_host, mqtt_Options);
mqtt_client.on('connect', function () {
nibeEmit.emit('fault',{from:"MQTT",message:'MQTT Brokern är ansluten'});
console.log("MQTT Broker is connected.")
resolve(mqtt_client);
});
mqtt_client.on('close',function(){
nibeEmit.emit('fault',{from:"MQTT",message:'MQTT Brokern är frånkopplad'});
console.log("MQTT Broker is disconnected.")
reject(mqtt_client);
})
mqtt_client.on('error',function(){
nibeEmit.emit('fault',{from:"MQTT",message:'Kunde inte ansluta till MQTT Brokern'});
console.log("Could not connect to MQTT broker")
reject(mqtt_client);
})
})
}
//
async function addMQTTdiscovery(data) {
if(config.mqtt===undefined) {
config.mqtt = {};
updateConfig(config);
}
if(config.mqtt.discovery===true) {
let i = mqttDiscoverySensors.findIndex(i => i == data.register);
let j = config.registers.findIndex(j => j == data.register);
if(i===-1 && j!==-1) {
let result = await formatMQTTdiscovery(data)
let topic = 'homeassistant/'+result.component+'/'+data.register+'/config'
let message = JSON.stringify({"name": "Nibe "+data.titel,"device_class":result.type,"unit_of_measurement":result.unit,"state_topic":result.topic});
if(result.component!==undefined) {
publishMQTTpromise(topic,message,true).then(result => {
log(config.log.enable,`Adding MQTT Discovery object, register ${data.register}`,config.log['info'],"MQTT");
mqttDiscoverySensors.push(data.register);
},(error => {
}));
}
} else {
}
} else {
removeMQTTdiscovery(data);
}
}
async function removeMQTTdiscovery(data) {
let i = mqttDiscoverySensors.findIndex(i => i == data.register);
if(i!==-1) {
let result = await formatMQTTdiscovery(data)
let topic = 'homeassistant/'+result.component+'/'+data.register+'/config'
let message = "";
publishMQTTpromise(topic,message,true).then(result => {
let i = mqttDiscoverySensors.findIndex(i => i == data.register);
if(i!==-1) mqttDiscoverySensors.splice(i,1);
log(config.log.enable,`Removed MQTT Discovery object, register ${data.register}`,config.log['info'],"MQTT");
},(error => {
}));
}
}
function formatMQTTdiscovery(data) {
const promise = new Promise((resolve,reject) => {
let result = {}
result.unit = data.unit;
result.component = "sensor";
result.topic = config.mqtt.topic+data.register;
if(result.unit=="°C") {
result.type = "temperature";
} else if(result.unit=="A") {
result.type = "power";
} else if(result.unit=="kW") {
result.type = "power";
} else if(result.unit=="Hz" || result.unit=="%") {
result.type = undefined;
} else if(result.unit=="") {
result.type = undefined;
result.unit = undefined;
} else {
}
resolve(result)
});
return promise;
}
const handleMQTT = (on,host,port,user,pass,cb) => {
if(on===undefined || on=="" || on=="false" || on===false) {
if(mqtt_client!==undefined && mqtt_client.connected===true) {
mqtt_client.end();
console.log('Terminated MQTT session, shutdown');
return cb(null,false)
} else {
return cb(null,false)
}
};
if(host===undefined || host=="") return cb(err = new Error('No MQTT host defined'));
if(port===undefined || port=="") return cb(err = new Error('No MQTT port defined'));
if(mqtt_client===undefined || mqtt_client.connected!==true) {
if(startingMQTT===false) {
startingMQTT = true;
startMQTT(host,port,user,pass).then(result => {
startingMQTT = false
//mqtt_client = result;
config.mqtt.host = host;
config.mqtt.port = port;
config.mqtt.enable = true;
result.subscribe(config.mqtt.topic+'#');
updateSensors();
if(mqtt_client!==undefined && mqtt_client.connected===true) {
mqtt_client.on('message', function (topic, message) {
let subTopic = config.mqtt.topic;
let subscribed = false;
for (const arr of mqtt_subcribers) {
if(topic===arr) {
let save = topic.replace(/\//g,"_");
let messageString = message.toString().replace(/\,/g,".");
if(mqttData[save]===undefined) mqttData[save] = {};
mqttData[save].data = Number(messageString);
mqttData[save].raw_data = Number(messageString);
mqttData[save].register = save;
mqttData[save].timestamp = Date.now();
nibeEmit.emit('mqttData',mqttData[save]);
subscribed = true;
}
}
if(subscribed===false && topic.includes(subTopic)) {
topic = topic.replace(config.mqtt.topic,'')
topic = topic.split('/');
if(topic.includes('set')) {
setData(topic[0],message,(err,result) => {
if(err) return console.log(err);
});
} else if(topic.includes('get')) {
reqData(topic[0]);
} else if(topic.includes('add')) {
addRegister(topic[0])
} else if(topic.includes('remove')) {
removeRegister(topic[0])
}
}
//console.log('Incoming MQTT message:', topic, message.toString());
});
}
cb(null,true);
},(reject => {
if(mqtt_client!==undefined) {
mqtt_client.end();
}
console.log('Terminated MQTT session');
return cb(null,false)
}));
}
} else {
return cb(null,true)
}
}
const publishMQTT = (topic,message,retain=false) => {
if(mqtt_client!==undefined) {
if(mqtt_client.connected===true && mqtt_client.disconnecting!==true) {
mqtt_client.publish(topic, message.toString(),{retain:retain});
}
}
}
const publishMQTTpromise = (topic,message,retain=false) => {
const promise = new Promise((resolve,reject) => {
if(mqtt_client!==undefined) {
if(mqtt_client.connected===true && mqtt_client.disconnecting!==true) {
mqtt_client.publish(topic, message.toString(),{retain:retain});
resolve(true);
} else {
reject(false);
}
} else {
reject(false);
}
});
return promise;
}
const redOn = (enable=true) => {
core.send({type:"red",data:enable});
}
const updateSensors = () => {
if(config.home===undefined) config.home = {};
if(config.home.inside_sensors===undefined) config.home.inside_sensors = [];
updateConfig(config);
for (const arr of config.home.inside_sensors) {
if(arr.source=="mqtt") {
let found = false;
for (i = 0; i < mqtt_subcribers.length; i = i + 1) {
if(mqtt_subcribers[i]===arr.register) found = true;
}
if(found===false) {
mqtt_subcribers.push(arr.register);
}
}
}
if(mqtt_client!==undefined && mqtt_client.connected===true) {
for (const arr of mqtt_subcribers) {
mqtt_client.subscribe(arr);
nibeEmit.emit('updateSensor',true);
}
}
}
const addSensor = (config) => {
updateConfig(config);
updateSensors();
}
const removeSensor = (data) => {
if(config.home.inside_sensors!==undefined) {
let i = config.home.inside_sensors.findIndex(i => i.register == data.register);
if(i!==-1) {
config.home.inside_sensors.splice(i,1);
i = mqtt_subcribers.findIndex(i => i == data);
mqtt_subcribers.splice(i,1);
let mqttRemove = data.register.replace(/\//g,"_");
delete mqttData[mqttRemove];
updateConfig(config);
mqtt_client.unsubscribe(data.register);
nibeEmit.emit('updateSensor',true);
}
}
}
const getMQTTData = (data) => {
const promise = new Promise((resolve,reject) => {
if(data!==undefined) data = data.replace(/\//g,"_");
if(mqttData[data]!==undefined) {
resolve(mqttData[data]);
} else {
reject({})
}
});
return promise;
}
const writeLog = (data,plugin,level) => {
let from = "System";
if(plugin=="fan") from = "Automatiskt luftflöde";
if(plugin=="hw") from = "Varmvattenreglering";
if(plugin=="weather") from = "Prognosreglering";
if(plugin=="diagnostic") from = "Diagnostik";
if(level=="info" || level=="error") {
nibeEmit.emit('fault',{from:from,message:data});
}
if(config.log[plugin]!==undefined) {
log(config.log.enable,data,config.log[plugin],from);
}
return;
}
const setDocker = (cmd) => {
docker = cmd;
}
module.exports = {
reqData:reqData,
setData:setData,
addRegister:addRegister,
removeRegister:removeRegister,
initiateCore:initiateCore,
stopCore:stopCore,
resetCore:resetCore,
data:nibeEmit,
getConfig:getConfig,
setConfig:updateConfig,
getRegister:getRegister,
handleMQTT:handleMQTT,
redOn:redOn,
addSensor: addSensor,
removeSensor: removeSensor,
getMQTTData:getMQTTData,
log:writeLog,
saveGraph:saveGraph,
requireGraph:requireGraph,
setDocker:setDocker
}
================================================
FILE: docker/nibepi/lib/models.json
================================================
{
"F370":"./models/F370.json",
"F470":"./models/F470.json",
"F730":"./models/F730.json",
"F750":"./models/F750.json",
"F1145":"./models/F1145.json",
"F1155":"./models/F1155.json",
"F1245":"./models/F1245.json",
"F1255":"./models/F1255.json",
"F1345":"./models/F1345.json",
"F1355":"./models/F1355.json",
"VVM225":"./models/VVM225.json",
"VVM310":"./models/VVM310.json",
"VVM320":"./models/VVM320.json",
"VVM325":"./models/VVM325.json",
"VVM500":"./models/VVM500.json",
"RMU40_S1":"./models/RMU40_S1.json",
"RMU40_S2":"./models/RMU40_S2.json",
"RMU40_S3":"./models/RMU40_S3.json",
"RMU40_S4":"./models/RMU40_S4.json",
"S1255":"./models/S1255.json"
}
================================================
FILE: docker/nibepi/lib/saveGraph.js
================================================
let path = process.env.path;
let exec = require('child_process').exec;
let config = JSON.parse(process.env.config);
process.on('message', (m) => {
console.log('Hello')
let data = m;
for (var property in data) {
if (data.hasOwnProperty(property)) {
for (var object in data[property]) {
if (data[property].hasOwnProperty(object)) {
if(data[property][object]!==undefined && data[property][object].length>5000) {
let len = data[property][object].length-5000;
data[property][object].splice(0,len)
}
}
}
}
}
if(JSON.stringify(data).length>2) {
if(config.system===undefined) config.system = {};
if(config.log===undefined) config.log = {};
if(config.system.readonly===true) {
exec('sudo mount -o remount,rw /', function(error, stdout, stderr) {
if(error) {
//log(config.log.enable,"Could not open the system for write mode",config.log['error'],"Config");
return(false);
} else {
fs.writeFile(path+'/graph.json', JSON.stringify(data,null,2), function(err) {
if(err) return (false);
//log(config.log.enable,"Graphs saved",config.log['info'],"Graph");
//nibeEmit.emit('fault',{from:"Grafer",message:'Graferna är sparade till SD-kort'});
exec('sudo mount -o remount,ro /', function(error, stdout, stderr) {
if(error) {
//nibeEmit.emit('fault',{from:"Grafer",message:'Kunde inte sätta läsbart läge på filsystemet.'});
//log(config.log.enable,"Could not set read-only mode.",config.log['error'],"Graph");
return(false);
} else {
console.log('Read only mode set.')
return (true)
}
})
});
}
});
} else {
exec('sudo mount -o remount,rw /', function(error, stdout, stderr) {
if(error) {
//log(config.log.enable,"Could not open the system for write mode",config.log['error'],"Config");
return(false);
} else {
fs.writeFile(path+'/graph.json', JSON.stringify(data,null,2), function(err) {
if(err) return (false);
//nibeEmit.emit('fault',{from:"Grafer",message:'Graferna är sparade till SD-kort'});
//log(config.log.enable,"Config file saved",config.log['info'],"Config");
return (true)
});
}
});
}
}
process.exit(99);
});
================================================
FILE: docker/nibepi/lib/startCore.js
================================================
const startCoreF = (port) => {
const promise = new Promise((resolve,reject) => {
setTimeout((port) => {
let output = {};
const path = require('path');
let reqPath = path.join(__dirname, '../');
const { fork } = require('child_process');
output.core = fork(reqPath+'/backend.js', {
detached: true
});
output.core.send({start:true,port:port });
resolve(output.core);
}, 2000, port);
});
return promise;
}
const startCoreS = (host,port) => {
const promise = new Promise((resolve,reject) => {
setTimeout((host,port) => {
let output = {};
const path = require('path');
let reqPath = path.join(__dirname, '../');
const { fork } = require('child_process');
output.core = fork(reqPath+'/modbus-client.js', {
detached: true
});
output.core.send({start:true,host:host,port:port });
resolve(output.core);
}, 2000, host,port);
});
return promise;
}
const startNibeGW = (port) => {
const promise = new Promise((resolve,reject) => {
setTimeout((port) => {
let output = {};
const path = require('path');
let reqPath = path.join(__dirname, '../');
const { fork } = require('child_process');
output.core = fork(reqPath+'/nibegw-client.js', {
detached: true
});
output.core.send({start:true,port:port });
resolve(output.core);
}, 2000, port);
});
return promise;
}
module.exports = {
startCoreF:startCoreF,
startCoreS:startCoreS,
startNibeGW:startNibeGW
}
================================================
FILE: docker/nibepi/lib/stopCore.js
================================================
const stopCore = (core) => {
const promise = new Promise((resolve,reject) => {
if(core!==undefined) {
if(core.connected===true) {
core.disconnect();
} else {
}
core.kill('SIGINT');
resolve(core.connected);
} else {
resolve(false);
}
});
return promise;
}
module.exports = stopCore;
================================================
FILE: docker/nibepi/log.js
================================================
var fs = require('fs');
let writer = fs.createWriteStream('/tmp/nibepi.log');
const log = (enable,data,enabled,kind) => {
if(enable!==undefined && enable===true && enabled!==undefined && enabled===true) {
var tzoffset = (new Date()).getTimezoneOffset() * 60000;
var time = (new Date(Date.now() - tzoffset)).toISOString().slice(0, -1).replace('T',' ');
writer.write(`${time} ${kind}: [${data}]\n`);
}
}
module.exports = log;
================================================
FILE: docker/nibepi/modbus-client.js
================================================
// create an empty modbus client
var ModbusRTU = require("modbus-serial");
var client = new ModbusRTU();
const getQueue = [];
var regQueue = [30001];
var red = false;
var getTimer = {};
var setTimer = {};
async function writeData(item) {
let address = item.register;
const promise = new Promise((resolve,reject) => {
let register = Number(address)-40000;
let size = 0xFFFF;
if(item.size=="u8" || item.size=="s8") size = 0xFF;
if(item.size=="u32" || item.size=="s32") size = 0xFFFFFFFF;
process.send({type:"log",data:JSON.stringify(item,null,2),level:"core",kind:"WRITE"});
setTimer[address] = setTimeout((address) => {
process.send({type:"log",data:"5 sec timeout from register: "+address,level:"core",kind:"ERROR"});
reject(new Error('No respond when writing to register ('+address+')'));
}, 5000, address);
client.writeRegisters(register, [item.data,size])
.then(data => {
clearTimeout(setTimer[address]);
console.log(data);
resolve(data)
});
}).catch((err => {
clearTimeout(getTimer[address]);
reject(err)
}));
return promise;
}
async function requestData(address) {
const promise = new Promise((resolve,reject) => {
process.send({type:"log",data:"Requesting data from register: "+address,level:"core",kind:"REQ"});
if(address.toString().charAt(0)=="3") {
let register = Number(address)-30000;
// Get input register
if(client!==undefined) {
getTimer[address] = setTimeout((address) => {
process.send({type:"log",data:"5 sec timeout from register: "+address,level:"core",kind:"ERROR"});
reject(new Error('No respond from register ('+address+')'));
}, 5000, address);
client.readInputRegisters(register, 1, function(err, data) {
clearTimeout(getTimer[address]);
if(err) {
reject(new Error("Could not read data from register"))
} else if(data!==undefined) {
if(process.connected===true) {
process.send({type:"log",data:"Got data from register: "+address+", "+JSON.stringify(data),level:"core",kind:"SUCCESS"});
process.send({type:"data",data:{register:address,data:data.data}});
resolve(data.data)
//process.send({type:"log",data:data.data,level:"debug",kind:"OK"});
} else {
reject(new Error("Core has been disconnected"))
}
} else {
reject(new Error("Could not read data from register"))
}
});
} else {
reject(new Error("Heatpump not connected yet"))
}
} else if(address.toString().charAt(0)=="4") {
// Get holding register
let register = Number(address)-40000;
if(client!==undefined) {
getTimer[address] = setTimeout((address) => {
process.send({type:"log",data:"5 sec timeout from register: "+address,level:"core",kind:"ERROR"});
reject(new Error('No respond from register ('+address+')'));
}, 5000, address);
client.readHoldingRegisters(register, 1, function(err, data) {
clearTimeout(getTimer[address]);
if(err) {
reject(new Error("Could not read data from register"))
} else if(data!==undefined) {
if(process.connected===true) {
process.send({type:"log",data:"Got data from register: "+address+", "+JSON.stringify(data),level:"core",kind:"SUCCESS"});
process.send({type:"data",data:{register:address,data:data.data}});
resolve(data.data)
//process.send({type:"log",data:data.data,level:"debug",kind:"OK"});
} else {
reject(new Error("Core has been disconnected"))
}
} else {
reject(new Error("Could not read data from register"))
}
});
} else {
reject(new Error("Heatpump not connected yet"))
}
} else {
reject(new Error("Can't request register which is not in the 30000-49999 range"))
}
});
return promise;
}
process.on('message', (m) => {
if(m.start===true) {
// open connection to a tcp line
client.connectTCP(m.host, { port: m.port });
client.setID(1);
setTimeout(async () => {
process.send({type:"started",data:true});
async function startLoop() {
var len = regQueue.length;
for( var i = 0; i < regQueue.length; i++){
if(getQueue!==undefined && getQueue.length!==0) {
var lastMsg = getQueue.pop();
await requestData(lastMsg).catch((err) => {
process.send({type:"log",data:JSON.stringify(err),level:"core",kind:"ERROR"});
});
i--;
} else {
await requestData(regQueue[i]).catch((err) => {
process.send({type:"log",data:JSON.stringify(err),level:"core",kind:"ERROR"});
});;
}
if(len!==regQueue.length) {
process.send({type:"log",data:'Starting over the regQueue again, register added',level:"core",kind:"LOOP"});
i = regQueue.length;
startLoop();
} else {
if(i===regQueue.length-1) i=-1;
process.send({type:"log",data:JSON.stringify(regQueue,null,2),level:"core",kind:"LOOP"});
}
}
}
startLoop();
}, 2000);
} else if(m.type=="reqData") {
getQueue.unshift(m.data);
} else if(m.type=="regRegister") {
regQueue = m.data;
} else if(m.type=="setData") {
let item = m.data;
writeData(item)
.then(data => {
if(process.connected===true) {
process.send({type:"ack",data:{register:item.register,ack:true}});
}
}).catch(err => {
if(process.connected===true) {
process.send({type:"ack",data:{register:item.register,ack:false}});
}
})
} else if(m.type=="red") {
//red = m.data;
}
});
process.on('disconnect', (m) => {
if(red===false) {
console.log('Shutting down the core.')
process.exit(99);
}
});
================================================
FILE: docker/nibepi/models/F1145.json
================================================
[
{"register":"40004","factor":10,"size":"s16","mode":"R","titel":"BT1 Outdoor Temperature","info":"Current outdoor temperature","unit":"°C","min":"0","max":"0"},
{"register":"40005","factor":10,"size":"s16","mode":"R","titel":"EP23-BT2 Supply temp S4","info":"Supply temperature for system 4","unit":"°C","min":"0","max":"0"},
{"register":"40006","factor":10,"size":"s16","mode":"R","titel":"EP22-BT2 Supply temp S3","info":"Supply temperature for system 3","unit":"°C","min":"0","max":"0"},
{"register":"40007","factor":10,"size":"s16","mode":"R","titel":"EP21-BT2 Supply temp S2","info":"Supply temperature for system 2","unit":"°C","min":"0","max":"0"},
{"register":"40008","factor":10,"size":"s16","mode":"R","titel":"BT2 Supply temp S1","info":"Supply temperature for system 1","unit":"°C","min":"0","max":"0"},
{"register":"40012","factor":10,"size":"s16","mode":"R","titel":"EB100-EP14-BT3 Return temp","info":"Return temperature","unit":"°C","min":"0","max":"0"},
{"register":"40013","factor":10,"size":"s16","mode":"R","titel":"BT7 HW Top","info":"Hot water top temperature, BT7","unit":"°C","min":"0","max":"0"},
{"register":"40014","factor":10,"size":"s16","mode":"R","titel":"BT6 HW Load","info":"Hot water load temperature, BT6","unit":"°C","min":"0","max":"0"},
{"register":"40015","factor":10,"size":"s16","mode":"R","titel":"EB100-EP14-BT10 Brine In Temp","info":"Brine in temperature, BT10","unit":"°C","min":"0","max":"0"},
{"register":"40016","factor":10,"size":"s16","mode":"R","titel":"EB100-EP14-BT11 Brine Out Temp","info":"Brine out temperature, BT11","unit":"°C","min":"0","max":"0"},
{"register":"40017","factor":10,"size":"s16","mode":"R","titel":"EB100-EP14-BT12 Condensor Out","info":"Condensor out temperature, BT12","unit":"°C","min":"0","max":"0"},
{"register":"40018","factor":10,"size":"s16","mode":"R","titel":"EB100-EP14-BT14 Hot Gas Temp","info":"Hot gas temperature, BT14","unit":"°C","min":"0","max":"0"},
{"register":"40019","factor":10,"size":"s16","mode":"R","titel":"EB100-EP14-BT15 Liquid Line","info":"Liquid line temperature, BT15","unit":"°C","min":"0","max":"0"},
{"register":"40022","factor":10,"size":"s16","mode":"R","titel":"EB100-EP14-BT17 Suction","info":"Suction temperature, BT17","unit":"°C","min":"0","max":"0"},
{"register":"40025","factor":10,"size":"s16","mode":"R","titel":"BT20 Exhaust air temp. 1","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40026","factor":10,"size":"s16","mode":"R","titel":"BT21 Vented air temp. 1","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40028","factor":10,"size":"s16","mode":"R","titel":"AZ1-BT26 Temp Collector in FLM 1","info":"Connected to the FLM module","unit":"°C","min":"0","max":"0"},
{"register":"40029","factor":10,"size":"s16","mode":"R","titel":"AZ1-BT27 Temp Collector out FLM 1","info":"Connected to the FLM module","unit":"°C","min":"0","max":"0"},
{"register":"40030","factor":10,"size":"s16","mode":"R","titel":"EP23-BT50 Room Temp S4","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40031","factor":10,"size":"s16","mode":"R","titel":"EP22-BT50 Room Temp S3","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40032","factor":10,"size":"s16","mode":"R","titel":"EP21-BT50 Room Temp S2","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40033","factor":10,"size":"s16","mode":"R","titel":"BT50 Room Temp S1","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40042","factor":10,"size":"s16","mode":"R","titel":"CL11-BT51 Pool 1 Temp","info":"Pool temperature for Pool 1, BT51","unit":"°C","min":"0","max":"0"},
{"register":"40043","factor":10,"size":"s16","mode":"R","titel":"BT53 Solar Panel Temp","info":"Used in Solar and AHPS Docking accessories","unit":"°C","min":"0","max":"0"},
{"register":"40044","factor":10,"size":"s16","mode":"R","titel":"BT54 Solar Load Temp","info":"Used in Solar and AHPS Docking accessories","unit":"°C","min":"0","max":"0"},
{"register":"40045","factor":10,"size":"s16","mode":"R","titel":"EQ1-BT64 Cool Supply Temp","info":"Cool supply temperature, BT64","unit":"°C","min":"0","max":"0"},
{"register":"40046","factor":10,"size":"s16","mode":"R","titel":"EQ1-BT65 Cool Return Temp","info":"Cool return temperature, BT65","unit":"°C","min":"0","max":"0"},
{"register":"40054","factor":1,"size":"s16","mode":"R","titel":"EB100-FD1 Temperature limiter","info":"","unit":"","min":"0","max":"0"},
{"register":"40067","factor":10,"size":"s16","mode":"R","titel":"BT1 Average","info":"EB100-BT1 Outdoor temperature average","unit":"°C","min":"0","max":"0"},
{"register":"40070","factor":10,"size":"s16","mode":"R","titel":"EM1-BT52 Boiler Temperature","info":"Boiler temperature, BT52","unit":"°C","min":"0","max":"0"},
{"register":"40071","factor":10,"size":"s16","mode":"R","titel":"BT25 Ext. Supply","info":"External supply temperature, BT25","unit":"°C","min":"0","max":"0"},
{"register":"40072","factor":10,"size":"s16","mode":"R","titel":"BF1 EP14 Flow","info":"Current flow EP14|Current flow EP15","unit":"l/m","min":"0","max":"0"},
{"register":"40074","factor":1,"size":"s16","mode":"R","titel":"EB100-FR1 Anode Status","info":"","unit":"","min":"0","max":"0"},
{"register":"40075","factor":10,"size":"s16","mode":"R","titel":"BT22 Supply air temp.","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40079","factor":10,"size":"u32","mode":"R","titel":"EB100-BE3 Current","info":"","unit":"A","min":"0","max":"0"},
{"register":"40081","factor":10,"size":"u32","mode":"R","titel":"EB100-BE2 Current","info":"","unit":"A","min":"0","max":"0"},
{"register":"40083","factor":10,"size":"u32","mode":"R","titel":"EB100-BE1 Current","info":"","unit":"A","min":"0","max":"0"},
{"register":"40106","factor":10,"size":"s16","mode":"R","titel":"CL12-BT51 Pool 2 Temp","info":"Pool temperature for Pool 2, BT51","unit":"°C","min":"0","max":"0"},
{"register":"40107","factor":10,"size":"s16","mode":"R","titel":"BT20 Exhaust air temp. 4","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40108","factor":10,"size":"s16","mode":"R","titel":"BT20 Exhaust air temp. 3","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40109","factor":10,"size":"s16","mode":"R","titel":"BT20 Exhaust air temp. 2","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40110","factor":10,"size":"s16","mode":"R","titel":"BT21 Vented air temp. 4","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40111","factor":10,"size":"s16","mode":"R","titel":"BT21 Vented air temp. 3","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40112","factor":10,"size":"s16","mode":"R","titel":"BT21 Vented air temp. 2","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40113","factor":10,"size":"s16","mode":"R","titel":"AZ4-BT26 Temp Collector in FLM 4","info":"Connected to the FLM module","unit":"°C","min":"0","max":"0"},
{"register":"40114","factor":10,"size":"s16","mode":"R","titel":"AZ3-BT26 Temp Collector in FLM 3","info":"Connected to the FLM module","unit":"°C","min":"0","max":"0"},
{"register":"40115","factor":10,"size":"s16","mode":"R","titel":"AZ2-BT26 Temp Collector in FLM 2","info":"Connected to the FLM module","unit":"°C","min":"0","max":"0"},
{"register":"40116","factor":10,"size":"s16","mode":"R","titel":"AZ4-BT27 Temp Collector out FLM 4","info":"Connected to the FLM module","unit":"°C","min":"0","max":"0"},
{"register":"40117","factor":10,"size":"s16","mode":"R","titel":"AZ3-BT27 Temp Collector out FLM 3","info":"Connected to the FLM module","unit":"°C","min":"0","max":"0"},
{"register":"40118","factor":10,"size":"s16","mode":"R","titel":"AZ2-BT27 Temp Collector out FLM 2","info":"Connected to the FLM module","unit":"°C","min":"0","max":"0"},
{"register":"40127","factor":10,"size":"s16","mode":"R","titel":"EP23-BT3 Return temp S4","info":"Return temperature for system 4","unit":"°C","min":"0","max":"0"},
{"register":"40128","factor":10,"size":"s16","mode":"R","titel":"EP22-BT3 Return temp S3","info":"Return temperature for system 3","unit":"°C","min":"0","max":"0"},
{"register":"40129","factor":10,"size":"s16","mode":"R","titel":"EP21-BT3 Return temp S2","info":"Return temperature for system 2","unit":"°C","min":"0","max":"0"},
{"register":"40147","factor":10,"size":"s16","mode":"R","titel":"BT70 HW Comfort Supply Temp.","info":"Hot water comfort supply temperature, BT70","unit":"°C","min":"0","max":"0"},
{"register":"40152","factor":10,"size":"s16","mode":"R","titel":"BT71 Ext. Return Temp","info":"External return temperature, BT71","unit":"°C","min":"0","max":"0"},
{"register":"40155","factor":10,"size":"s16","mode":"R","titel":"EQ1-BT57 Collector Temp.","info":"External collector temperature, BT57, for ACS","unit":"°C","min":"0","max":"0"},
{"register":"40156","factor":10,"size":"s16","mode":"R","titel":"EQ1-BT75 Heatdump Temp.","info":"Heating medium dump temperature, BT75, for ACS","unit":"°C","min":"0","max":"0"},
{"register":"40159","factor":10,"size":"s16","mode":"R","titel":"EP47-BT2 Supply temp S8","info":"Supply temperature for system 8","unit":"°C","min":"0","max":"0"},
{"register":"40160","factor":10,"size":"s16","mode":"R","titel":"EP46-BT2 Supply temp S7","info":"Supply temperature for system 7","unit":"°C","min":"0","max":"0"},
{"register":"40161","factor":10,"size":"s16","mode":"R","titel":"EP45-BT2 Supply temp S6","info":"Supply temperature for system 6","unit":"°C","min":"0","max":"0"},
{"register":"40162","factor":10,"size":"s16","mode":"R","titel":"EP44-BT2 Supply temp S5","info":"Supply temperature for system 5","unit":"°C","min":"0","max":"0"},
{"register":"40163","factor":10,"size":"s16","mode":"R","titel":"EP47-BT3 Return temp S8","info":"Return temperature for system 8","unit":"°C","min":"0","max":"0"},
{"register":"40164","factor":10,"size":"s16","mode":"R","titel":"EP46-BT3 Return temp S7","info":"Return temperature for system 7","unit":"°C","min":"0","max":"0"},
{"register":"40165","factor":10,"size":"s16","mode":"R","titel":"EP45-BT3 Return temp S6","info":"Return temperature for system 6","unit":"°C","min":"0","max":"0"},
{"register":"40166","factor":10,"size":"s16","mode":"R","titel":"EP44-BT3 Return temp S5","info":"Return temperature for system 5","unit":"°C","min":"0","max":"0"},
{"register":"40167","factor":10,"size":"s16","mode":"R","titel":"EP47-BT50 Room Temp S8","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40168","factor":10,"size":"s16","mode":"R","titel":"EP46-BT50 Room Temp S7","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40169","factor":10,"size":"s16","mode":"R","titel":"EP45-BT50 Room Temp S6","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40170","factor":10,"size":"s16","mode":"R","titel":"EP44-BT50 Room Temp S5","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40183","factor":10,"size":"s16","mode":"R","titel":"AZ30-BT23 Outdoor temp. ERS 1","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40185","factor":10,"size":"s16","mode":"R","titel":"BT1 Average, 1h","info":"EB100-BT1 Outdoor temperature average, 1h","unit":"°C","min":"0","max":"0"},
{"register":"40188","factor":10,"size":"s16","mode":"R","titel":"EP47-BT50 Room Temp S8 Average","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40189","factor":10,"size":"s16","mode":"R","titel":"EP46-BT50 Room Temp S7 Average","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40190","factor":10,"size":"s16","mode":"R","titel":"EP45-BT50 Room Temp S6 Average","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40191","factor":10,"size":"s16","mode":"R","titel":"EP44-BT50 Room Temp S5 Average","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40192","factor":10,"size":"s16","mode":"R","titel":"EP23-BT50 Room Temp S4 Average","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40193","factor":10,"size":"s16","mode":"R","titel":"EP22-BT50 Room Temp S3 Average","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40194","factor":10,"size":"s16","mode":"R","titel":"EP21-BT50 Room Temp S2 Average","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40195","factor":10,"size":"s16","mode":"R","titel":"BT50 Room Temp S1 Average","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40212","factor":10,"size":"s16","mode":"R","titel":"BT74 Average","info":"BT74 heating cooling sensor average","unit":"°C","min":"0","max":"0"},
{"register":"40216","factor":10,"size":"s16","mode":"R","titel":"BT25 Ext. supply temp, cooling","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40217","factor":10,"size":"s16","mode":"R","titel":"Calc. Supply S8","info":"Calculated supply temperature for the climate system","unit":"°C","min":"0","max":"0"},
{"register":"40218","factor":10,"size":"s16","mode":"R","titel":"Calc. Supply S7","info":"Calculated supply temperature for the climate system","unit":"°C","min":"0","max":"0"},
{"register":"40219","factor":10,"size":"s16","mode":"R","titel":"Calc. Supply S6","info":"Calculated supply temperature for the climate system","unit":"°C","min":"0","max":"0"},
{"register":"40220","factor":10,"size":"s16","mode":"R","titel":"Calculated Supply S5","info":"Calculated supply temperature for the climate system","unit":"°C","min":"0","max":"0"},
{"register":"40221","factor":10,"size":"s16","mode":"R","titel":"Calc. Cooling Supply S8","info":"Calculated supply temperature in cooling mode for the climate system","unit":"°C","min":"0","max":"0"},
{"register":"40222","factor":10,"size":"s16","mode":"R","titel":"Calc. Cooling Supply S7","info":"Calculated supply temperature in cooling mode for the climate system","unit":"°C","min":"0","max":"0"},
{"register":"40223","factor":10,"size":"s16","mode":"R","titel":"Calc. Cooling Supply S6","info":"Calculated supply temperature in cooling mode for the climate system","unit":"°C","min":"0","max":"0"},
{"register":"40224","factor":10,"size":"s16","mode":"R","titel":"Calc. Cooling Supply S5","info":"Calculated supply temperature in cooling mode for the climate system","unit":"°C","min":"0","max":"0"},
{"register":"40305","factor":1,"size":"u8","mode":"R","titel":"Mixing Valve State S8","info":"State of the mixing valve for the climate system","unit":"","min":"0","max":"0"},
{"register":"40306","factor":1,"size":"u8","mode":"R","titel":"Mixing Valve State S7","info":"State of the mixing valve for the climate system","unit":"","min":"0","max":"0"},
{"register":"40307","factor":1,"size":"u8","mode":"R","titel":"Mixing Valve State S6","info":"State of the mixing valve for the climate system","unit":"","min":"0","max":"0"},
{"register":"40308","factor":1,"size":"u8","mode":"R","titel":"Mixing Valve State S5","info":"State of the mixing valve for the climate system","unit":"","min":"0","max":"0"},
{"register":"40310","factor":1,"size":"u8","mode":"R","titel":"External ERS 1 accessory relays","info":"Indicates the status of the relays on the ERS accessory. The information is binary encoded. b0: K1, b1: K2, b2: K3, b3: K4","unit":"","min":"0","max":"0"},
{"register":"40311","factor":1,"size":"u8","mode":"R","titel":"External ERS 1 accessory GQ2 speed","info":"Indicates the speed of the GQ2 fan speed on the ERS accessory.","unit":"%","min":"0","max":"0"},
{"register":"40312","factor":1,"size":"u8","mode":"R","titel":"External ERS 1 accessory GQ3 speed","info":"Indicates the speed of the GQ3 fan speed on the ERS accessory.","unit":"%","min":"0","max":"0"},
{"register":"40339","factor":1,"size":"u8","mode":"R","titel":"External adjustment activated via input S8","info":"","unit":"","min":"0","max":"0"},
{"register":"40340","factor":1,"size":"u8","mode":"R","titel":"External adjustment activated via input S7","info":"","unit":"","min":"0","max":"0"},
{"register":"40341","factor":1,"size":"u8","mode":"R","titel":"External adjustment activated via input S6","info":"","unit":"","min":"0","max":"0"},
{"register":"40342","factor":1,"size":"u8","mode":"R","titel":"External adjustment activated via input S5","info":"","unit":"","min":"0","max":"0"},
{"register":"40365","factor":1,"size":"u8","mode":"R","titel":"Extra heating system pump S8","info":"","unit":"","min":"0","max":"0"},
{"register":"40366","factor":1,"size":"u8","mode":"R","titel":"Extra heating system pump S7","info":"","unit":"","min":"0","max":"0"},
{"register":"40367","factor":1,"size":"u8","mode":"R","titel":"Extra heating system pump S6","info":"","unit":"","min":"0","max":"0"},
{"register":"40368","factor":1,"size":"u8","mode":"R","titel":"Extra heating system pump S5","info":"","unit":"","min":"0","max":"0"},
{"register":"40369","factor":1,"size":"u8","mode":"R","titel":"Extra cooling HPAC, ACS","info":"","unit":"","min":"0","max":"0"},
{"register":"40625","factor":10,"size":"s16","mode":"R","titel":"BT82 HW Comfort Return Temp","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40626","factor":10,"size":"s16","mode":"R","titel":"BT83 HW Comfort Cylinder Temp","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40647","factor":1,"size":"u32","mode":"R","titel":"EB108-EP15 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40649","factor":1,"size":"u32","mode":"R","titel":"EB108-EP15 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40651","factor":1,"size":"u32","mode":"R","titel":"EB108-EP15 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40653","factor":1,"size":"u32","mode":"R","titel":"EB108-EP14 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40655","factor":1,"size":"u32","mode":"R","titel":"EB108-EP14 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40657","factor":1,"size":"u32","mode":"R","titel":"EB108-EP14 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40659","factor":1,"size":"u32","mode":"R","titel":"EB107-EP15 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40661","factor":1,"size":"u32","mode":"R","titel":"EB107-EP15 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40663","factor":1,"size":"u32","mode":"R","titel":"EB107-EP15 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40665","factor":1,"size":"u32","mode":"R","titel":"EB107-EP14 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40667","factor":1,"size":"u32","mode":"R","titel":"EB107-EP14 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40669","factor":1,"size":"u32","mode":"R","titel":"EB107-EP14 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40671","factor":1,"size":"u32","mode":"R","titel":"EB106-EP15 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40673","factor":1,"size":"u32","mode":"R","titel":"EB106-EP15 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40675","factor":1,"size":"u32","mode":"R","titel":"EB106-EP15 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40677","factor":1,"size":"u32","mode":"R","titel":"EB106-EP14 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40679","factor":1,"size":"u32","mode":"R","titel":"EB106-EP14 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40681","factor":1,"size":"u32","mode":"R","titel":"EB106-EP14 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40683","factor":1,"size":"u32","mode":"R","titel":"EB105-EP15 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40685","factor":1,"size":"u32","mode":"R","titel":"EB105-EP15 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40687","factor":1,"size":"u32","mode":"R","titel":"EB105-EP15 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40689","factor":1,"size":"u32","mode":"R","titel":"EB105-EP14 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40691","factor":1,"size":"u32","mode":"R","titel":"EB105-EP14 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40693","factor":1,"size":"u32","mode":"R","titel":"EB105-EP14 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40695","factor":1,"size":"u32","mode":"R","titel":"EB104-EP15 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40697","factor":1,"size":"u32","mode":"R","titel":"EB104-EP15 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40699","factor":1,"size":"u32","mode":"R","titel":"EB104-EP15 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40701","factor":1,"size":"u32","mode":"R","titel":"EB104-EP14 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40703","factor":1,"size":"u32","mode":"R","titel":"EB104-EP14 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40705","factor":1,"size":"u32","mode":"R","titel":"EB104-EP14 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40707","factor":1,"size":"u32","mode":"R","titel":"EB103-EP15 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40709","factor":1,"size":"u32","mode":"R","titel":"EB103-EP15 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40711","factor":1,"size":"u32","mode":"R","titel":"EB103-EP15 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40713","factor":1,"size":"u32","mode":"R","titel":"EB103-EP14 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40715","factor":1,"size":"u32","mode":"R","titel":"EB103-EP14 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40717","factor":1,"size":"u32","mode":"R","titel":"EB103-EP14 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40719","factor":1,"size":"u32","mode":"R","titel":"EB102-EP15 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40721","factor":1,"size":"u32","mode":"R","titel":"EB102-EP15 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40723","factor":1,"size":"u32","mode":"R","titel":"EB102-EP15 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40725","factor":1,"size":"u32","mode":"R","titel":"EB102-EP14 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40727","factor":1,"size":"u32","mode":"R","titel":"EB102-EP14 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40729","factor":1,"size":"u32","mode":"R","titel":"EB102-EP14 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40731","factor":1,"size":"u32","mode":"R","titel":"EB101-EP15 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40733","factor":1,"size":"u32","mode":"R","titel":"EB101-EP15 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40735","factor":1,"size":"u32","mode":"R","titel":"EB101-EP15 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"0"},
{"register":"40737","factor":1,"size":"u32","mode":"R","titel":"EB101-EP14 Tot. Cooling op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40739","factor":1,"size":"u32","mode":"R","titel":"EB101-EP14 Tot. Pool1 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40741","factor":1,"size":"u32","mode":"R","titel":"EB101-EP14 Tot. Pool2 op.time compr","info":"","unit":"h","min":"0","max":"9999999"},
{"register":"40755","factor":10,"size":"s32","mode":"R","titel":"Tot. ext. HW add op.time","info":"Total external hw-electric additive operation time","unit":"h","min":"0","max":"9999999"},
{"register":"40771","factor":10,"size":"u32","mode":"R","titel":"Heat Meter - Pool2 Cpr EP14","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"40792","factor":1,"size":"u8","mode":"R","titel":"OPT state","info":"Indicates the state of the boiler connected through the OPT accessory.","unit":"","min":"0","max":"0"},
{"register":"40793","factor":1,"size":"u16","mode":"R","titel":"OPT version","info":"Version of the OPT PCBA software","unit":"","min":"0","max":"0"},
{"register":"40801","factor":10,"size":"s16","mode":"R","titel":"OPT rel. modulation level","info":"OPT relative modulation level","unit":"%","min":"0","max":"0"},
{"register":"40802","factor":10,"size":"s16","mode":"R","titel":"OPT boiler temperature","info":"OPT boiler temperature","unit":"°C","min":"0","max":"0"},
{"register":"40806","factor":1,"size":"u16","mode":"R","titel":"OPT boiler op. time","info":"OPT boiler operation time","unit":"h","min":"0","max":"0"},
{"register":"40818","factor":1,"size":"u8","mode":"R","titel":"Available Heat Compressors","info":"Number of compressors available for heating","unit":"","min":"0","max":"0"},
{"register":"40819","factor":1,"size":"u8","mode":"R","titel":"Available Hot Water Compressors","info":"Number of compressors available for to hot water","unit":"","min":"0","max":"0"},
{"register":"40820","factor":1,"size":"u8","mode":"R","titel":"Available Pool 1 Compressors","info":"Number of compressors available for pool 1","unit":"","min":"0","max":"0"},
{"register":"40821","factor":1,"size":"u8","mode":"R","titel":"Available Pool 2 Compressors","info":"Number of compressors available for pool 2","unit":"","min":"0","max":"0"},
{"register":"40822","factor":1,"size":"u8","mode":"R","titel":"Available Cool Compressors","info":"Number of compressors available for cooling","unit":"","min":"0","max":"0"},
{"register":"40823","factor":1,"size":"u8","mode":"R","titel":"Available External Compressors","info":"Number of compressors available for external control","unit":"","min":"0","max":"0"},
{"register":"40834","factor":10,"size":"s16","mode":"R","titel":"BM1 Humidity ","info":"","unit":"%","min":"0","max":"0"},
{"register":"40856","factor":10,"size":"s16","mode":"R","titel":"BM1 BT50 Room temp.","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40857","factor":10,"size":"s16","mode":"R","titel":"BM1 Pressure ","info":"","unit":"kPa","min":"0","max":"0"},
{"register":"40858","factor":10,"size":"s16","mode":"R","titel":"BM1 Dewpoint","info":"","unit":"°C","min":"0","max":"0"},
{"register":"40868","factor":1,"size":"u8","mode":"R","titel":"=+Adjust AUX Port","info":"","unit":"1","min":"0","max":"0"},
{"register":"40870","factor":1,"size":"u8","mode":"R","titel":"=+Adjust OP mode","info":"Tells if plusadjust system calls for heat or cool","unit":"","min":"0","max":"0"},
{"register":"40871","factor":1,"size":"u8","mode":"R","titel":"=+Adjust Comfort mode","info":"Which comfort mode","unit":"","min":"0","max":"0"},
{"register":"40872","factor":1,"size":"s8","mode":"R","titel":"=+Adjust Parallell adjustment","info":"requested adjustment","unit":"","min":"0","max":"0"},
{"register":"40873","factor":10,"size":"s16","mode":"R","titel":"=+Adjust Humidity","info":"Humidity","unit":"%RH","min":"0","max":"0"},
{"register":"40874","factor":10,"size":"s16","mode":"R","titel":"=+Adjust Temp indoor","info":"Average of all room sensors","unit":"°C","min":"0","max":"0"},
{"register":"40875","factor":10,"size":"s16","mode":"R","titel":"=+Adjust Temp outdoor","info":"Outdoor temp","unit":"°C","min":"0","max":"0"},
{"register":"40876","factor":1,"size":"u16","mode":"R","titel":"=+Adjust Version","info":"PCA input version","unit":"","min":"0","max":"0"},
{"register":"40877","factor":1,"size":"u8","mode":"R","titel":"=+Adjust Activated","info":"If plusadjust accessory is activated","unit":"","min":"0","max":"0"},
{"register":"40878","factor":1,"size":"u8","mode":"R","titel":"=+Adjust Need","info":"If plusadjust system calls for heat","unit":"","min":"0","max":"0"},
{"register":"40879","factor":1,"size":"s8","mode":"R/W","titel":"=+Adjust Parallell factor","info":"","unit":"1","min":"1","max":"10"},
{"register":"40880","factor":1,"size":"s8","mode":"R/W","titel":"=+Adjust Max change","info":"Largest allowed change","unit":"","min":"0","max":"0"},
{"register":"40881","factor":1,"size":"u8","mode":"R/W","titel":"=+Adjust Affect system8","info":"System affected by paralell change","unit":"","min":"0","max":"1"},
{"register":"40882","factor":1,"size":"u8","mode":"R/W","titel":"=+Adjust Affect system7","info":"System affected by paralell change","unit":"","min":"0","max":"1"},
{"register":"40883","factor":1,"size":"u8","mode":"R/W","titel":"=+Adjust Affect system6","info":"System affected by paralell change","unit":"","min":"0","max":"1"},
{"register":"40884","factor":1,"size":"u8","mode":"R/W","titel":"=+Adjust Affect system5","info":"System affected by paralell change","unit":"","min":"0","max":"1"},
{"register":"40885","factor":1,"size":"u8","mode":"R/W","titel":"=+Adjust Affect system4","info":"System affected by paralell change","unit":"","min":"0","max":"1"},
{"register":"40886","factor":1,"size":"u8","mode":"R/W","titel":"=+Adjust Affect system3","info":"System affected by paralell change","unit":"","min":"0","max":"1"},
{"register":"40887","factor":1,"size":"u8","mode":"R/W","titel":"=+Adjust Affect system2","info":"System affected by paralell change","unit":"","min":"0","max":"1"},
{"register":"40888","factor":1,"size":"u8","mode":"R/W","titel":"=+Adjust Affect system1","info":"System affected by paralell change","unit":"","min":"0","max":"1"},
{"register":"40889","factor":10,"size":"s16","mode":"R","titel":"BT64 Average","info":"BT64 Cooling supply average","unit":"°C","min":"0","max":"0"},
{"register":"40912","factor":1,"size":"u8","mode":"R","titel":"EQ1 State ACS Thermostat","info":"10=off,40=active wait,50=active","unit":"","min":"0","max":"0"},
{"register":"40913","factor":1,"size":"u8","mode":"R","titel":"EQ1 State ACS Thermostat Heat Dump","info":"10=shunt off,20=shunt open,30=shunt closed","unit":"","min":"0","max":"0"},
{"register":"40940","factor":10,"size":"s32","mode":"R/W","titel":"Degree Minutes (32 bit)","info":"Degree minutes, 32bit value. Full resolution.","unit":"","min":"-30000","max":"30000"},
{"register":"40942","factor":1,"size":"u8","mode":"R","titel":"External ERS 1 accessory block status","info":"Indicates if the ERS accessory is externaly blocked.","unit":"","min":"0","max":"0"},
{"register":"40943","factor":1,"size":"u8","mode":"R","titel":"External ERS 1 accessory EB17","info":"Indicates if the status of ERS accessory EB17. I = closed, 0 = open.","unit":"","min":"0","max":"0"},
{"register":"40995","factor":100,"size":"u32","mode":"R","titel":"External Energy Meter 2 Accumulated Energy","info":"","unit":"kWh","min":"0","max":"2147483647"},
{"register":"40997","factor":100,"size":"u32","mode":"R","titel":"External Energy Meter 1 Accumulated Energy","info":"","unit":"kWh","min":"0","max":"2147483647"},
{"register":"41027","factor":10,"size":"s16","mode":"R","titel":"Humidity average","info":"Humidity average","unit":"%","min":"0","max":"0"},
{"register":"41186","factor":10,"size":"s16","mode":"R","titel":"Set point OPT boiler","info":"Set point OPT boiler","unit":"°C","min":"0","max":"0"},
{"register":"41189","factor":10,"size":"s16","mode":"R","titel":"AA20-BE5 EME10 Current","info":"","unit":"A","min":"0","max":"0"},
{"register":"41190","factor":10,"size":"s16","mode":"R","titel":"AA20-BE5 EME10 Average Current","info":"","unit":"A","min":"0","max":"0"},
{"register":"41191","factor":1,"size":"u8","mode":"R","titel":"PV Panel State","info":"","unit":"","min":"0","max":"0"},
{"register":"41210","factor":10,"size":"s16","mode":"R","titel":"AZ4-BT50 Room temp","info":"AZ4-BT50 Room temp","unit":"°C","min":"0","max":"0"},
{"register":"41211","factor":10,"size":"s16","mode":"R","titel":"AZ3-BT50 Room temp","info":"AZ3-BT50 Room temp","unit":"°C","min":"0","max":"0"},
{"register":"41212","factor":10,"size":"s16","mode":"R","titel":"AZ2-BT50 Room temp","info":"AZ2-BT50 Room temp","unit":"°C","min":"0","max":"0"},
{"register":"41213","factor":10,"size":"s16","mode":"R","titel":"AZ1-BT50 Room temp","info":"AZ1-BT50 Room temp","unit":"°C","min":"0","max":"0"},
{"register":"41256","factor":1,"size":"u8","mode":"R","titel":"Fan speed current","info":"The current fan speed after scheduling and blocks are considered","unit":"%","min":"0","max":"0"},
{"register":"41257","factor":1,"size":"u8","mode":"R","titel":"Fan speed current","info":"The current fan speed after scheduling and blocks are considered","unit":"%","min":"0","max":"0"},
{"register":"41258","factor":1,"size":"u8","mode":"R","titel":"Fan speed current","info":"The current fan speed after scheduling and blocks are considered","unit":"%","min":"0","max":"0"},
{"register":"41265","factor":1,"size":"u8","mode":"R","titel":"Smart Home Mode","info":"Current smart home mode, 0=Default,1=Away from home,2=Vacation","unit":"","min":"0","max":"0"},
{"register":"41266","factor":10,"size":"s8","mode":"R","titel":"Offset to smart home system","info":"Offset to smart home system","unit":"°C","min":"0","max":"0"},
{"register":"41267","factor":1,"size":"u8","mode":"R","titel":"Smart Home ctrl syst 8","info":"Smart Home is controlling the system","unit":"","min":"0","max":"0"},
{"register":"41268","factor":1,"size":"u8","mode":"R","titel":"Smart Home ctrl syst 7","info":"Smart Home is controlling the system","unit":"","min":"0","max":"0"},
{"register":"41269","factor":1,"size":"u8","mode":"R","titel":"Smart Home ctrl syst 6","info":"Smart Home is controlling the system","unit":"","min":"0","max":"0"},
{"register":"41270","factor":1,"size":"u8","mode":"R","titel":"Smart Home ctrl syst 5","info":"Smart Home is controlling the system","unit":"","min":"0","max":"0"},
{"register":"41271","factor":1,"size":"u8","mode":"R","titel":"Smart Home ctrl syst 4","info":"Smart Home is controlling the system","unit":"","min":"0","max":"0"},
{"register":"41272","factor":1,"size":"u8","mode":"R","titel":"Smart Home ctrl syst 3","info":"Smart Home is controlling the system","unit":"","min":"0","max":"0"},
{"register":"41273","factor":1,"size":"u8","mode":"R","titel":"Smart Home ctrl syst 2","info":"Smart Home is controlling the system","unit":"","min":"0","max":"0"},
{"register":"41274","factor":1,"size":"u8","mode":"R","titel":"Smart Home ctrl syst 1","info":"Smart Home is controlling the system","unit":"","min":"0","max":"0"},
{"register":"41287","factor":1,"size":"u8","mode":"R","titel":"OPT boiler has priority hot water","info":"OPT boiler has priority hot water","unit":"","min":"0","max":"0"},
{"register":"41393","factor":1,"size":"s32","mode":"R","titel":"Smart energy source, energy source prio 7, start DM","info":"Energy source prio 7, start DM","unit":"","min":"0","max":"0"},
{"register":"41395","factor":1,"size":"s32","mode":"R","titel":"Smart energy source, energy source prio 6, start DM","info":"Energy source prio 6, start DM","unit":"","min":"0","max":"0"},
{"register":"41397","factor":1,"size":"s32","mode":"R","titel":"Smart energy source, energy source prio 5, start DM","info":"Energy source prio 5, start DM","unit":"","min":"0","max":"0"},
{"register":"41399","factor":1,"size":"s32","mode":"R","titel":"Smart energy source, energy source prio 4, start DM","info":"Energy source prio 4, start DM","unit":"","min":"0","max":"0"},
{"register":"41401","factor":1,"size":"s32","mode":"R","titel":"Smart energy source, energy source prio 3, start DM","info":"Energy source prio 3, start DM","unit":"","min":"0","max":"0"},
{"register":"41403","factor":1,"size":"s32","mode":"R","titel":"Smart energy source, energy source prio 2, start DM","info":"Energy source prio 2, start DM","unit":"","min":"0","max":"0"},
{"register":"41405","factor":1,"size":"s32","mode":"R","titel":"Smart energy source, energy source prio 1, start DM","info":"Energy source prio 1, start DM","unit":"","min":"0","max":"0"},
{"register":"41421","factor":1,"size":"s32","mode":"R","titel":"Smart energy source, degree minute min value","info":"Smart energy source, degree minute min value in Smart energy source system","unit":"","min":"0","max":"0"},
{"register":"41424","factor":1,"size":"u16","mode":"R","titel":"Smart energy source, actual OPT10 addition price","info":"Smart energy source, actual OPT10 addition price.","unit":"","min":"0","max":"0"},
{"register":"41425","factor":1,"size":"u16","mode":"R","titel":"Smart energy source, actual shunt add price","info":"Smart energy source, actual external step addition price.","unit":"","min":"0","max":"0"},
{"register":"41426","factor":1,"size":"u16","mode":"R","titel":"Smart energy source, actual ext. step add price","info":"Smart energy source, actual external step add price.","unit":"","min":"0","max":"0"},
{"register":"41427","factor":1,"size":"u16","mode":"R","titel":"Smart energy source, actual electricity price","info":"Smart energy source, actual electricity price.","unit":"","min":"0","max":"0"},
{"register":"41429","factor":10,"size":"s16","mode":"R","titel":"EP12-BT57 Collector In","info":"","unit":"°C","min":"0","max":"0"},
{"register":"41430","factor":10,"size":"s16","mode":"R","titel":"EP12-BT58 Collector Out","info":"","unit":"°C","min":"0","max":"0"},
{"register":"41742","factor":10,"size":"s16","mode":"R","titel":"EB108-EP15 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41743","factor":10,"size":"s16","mode":"R","titel":"EB108-EP15 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41744","factor":10,"size":"s16","mode":"R","titel":"EB108-EP14 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41745","factor":10,"size":"s16","mode":"R","titel":"EB108-EP14 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41746","factor":10,"size":"s16","mode":"R","titel":"EB107-EP15 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41747","factor":10,"size":"s16","mode":"R","titel":"EB107-EP15 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41748","factor":10,"size":"s16","mode":"R","titel":"EB107-EP14 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41749","factor":10,"size":"s16","mode":"R","titel":"EB107-EP14 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41750","factor":10,"size":"s16","mode":"R","titel":"EB106-EP15 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41751","factor":10,"size":"s16","mode":"R","titel":"EB106-EP15 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41752","factor":10,"size":"s16","mode":"R","titel":"EB106-EP14 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41753","factor":10,"size":"s16","mode":"R","titel":"EB106-EP14 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41754","factor":10,"size":"s16","mode":"R","titel":"EB105-EP15 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41755","factor":10,"size":"s16","mode":"R","titel":"EB105-EP15 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41756","factor":10,"size":"s16","mode":"R","titel":"EB105-EP14 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41757","factor":10,"size":"s16","mode":"R","titel":"EB105-EP14 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41758","factor":10,"size":"s16","mode":"R","titel":"EB104-EP15 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41759","factor":10,"size":"s16","mode":"R","titel":"EB104-EP15 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41760","factor":10,"size":"s16","mode":"R","titel":"EB104-EP14 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41761","factor":10,"size":"s16","mode":"R","titel":"EB104-EP14 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41762","factor":10,"size":"s16","mode":"R","titel":"EB103-EP15 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41763","factor":10,"size":"s16","mode":"R","titel":"EB103-EP15 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41764","factor":10,"size":"s16","mode":"R","titel":"EB103-EP14 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41765","factor":10,"size":"s16","mode":"R","titel":"EB103-EP14 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41766","factor":10,"size":"s16","mode":"R","titel":"EB102-EP15 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41767","factor":10,"size":"s16","mode":"R","titel":"EB102-EP15 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41768","factor":10,"size":"s16","mode":"R","titel":"EB102-EP14 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41769","factor":10,"size":"s16","mode":"R","titel":"EB102-EP14 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41770","factor":10,"size":"s16","mode":"R","titel":"EB101-EP15 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41771","factor":10,"size":"s16","mode":"R","titel":"EB101-EP15 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41772","factor":10,"size":"s16","mode":"R","titel":"EB101-EP14 Alarm condensor in level","info":"Alarm condensor in level","unit":"°C","min":"0","max":"0"},
{"register":"41773","factor":10,"size":"s16","mode":"R","titel":"EB101-EP14 Alarm condensor out level","info":"Alarm condensor out level","unit":"°C","min":"0","max":"0"},
{"register":"41928","factor":100,"size":"u16","mode":"R","titel":"Smart Price Adaption Price","info":"The current electric price","unit":"","min":"0","max":"0"},
{"register":"41929","factor":1,"size":"u8","mode":"R","titel":"Smart Price Adaption Price Level","info":"Whether the current price is unknown (0), low (1), medium (2), high (3)","unit":"","min":"0","max":"0","map":[
{"0":"UNKNOWN"},
{"1":"CHEAP"},
{"2":"NORMAL"},
{"3":"EXPENSIVE"}
]},
{"register":"41930","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Power 10","info":"","unit":"W","min":"0","max":"0"},
{"register":"41931","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Power 9","info":"","unit":"W","min":"0","max":"0"},
{"register":"41932","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Power 8","info":"","unit":"W","min":"0","max":"0"},
{"register":"41933","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Power 7","info":"","unit":"W","min":"0","max":"0"},
{"register":"41934","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Power 6","info":"","unit":"W","min":"0","max":"0"},
{"register":"41935","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Power 5","info":"","unit":"W","min":"0","max":"0"},
{"register":"41936","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Power 4","info":"","unit":"W","min":"0","max":"0"},
{"register":"41937","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Power 3","info":"","unit":"W","min":"0","max":"0"},
{"register":"41938","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Power 2","info":"","unit":"W","min":"0","max":"0"},
{"register":"41939","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Power 1","info":"","unit":"W","min":"0","max":"0"},
{"register":"41940","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error High 10","info":"","unit":"W","min":"0","max":"0"},
{"register":"41941","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error High 9","info":"","unit":"W","min":"0","max":"0"},
{"register":"41942","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error High 8","info":"","unit":"W","min":"0","max":"0"},
{"register":"41943","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error High 7","info":"","unit":"W","min":"0","max":"0"},
{"register":"41944","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error High 6","info":"","unit":"W","min":"0","max":"0"},
{"register":"41945","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error High 5","info":"","unit":"W","min":"0","max":"0"},
{"register":"41946","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error High 4","info":"","unit":"W","min":"0","max":"0"},
{"register":"41947","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error High 3","info":"","unit":"W","min":"0","max":"0"},
{"register":"41948","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error High 2","info":"","unit":"W","min":"0","max":"0"},
{"register":"41949","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error High 1","info":"","unit":"W","min":"0","max":"0"},
{"register":"41950","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error Low 10","info":"","unit":"W","min":"0","max":"0"},
{"register":"41951","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error Low 9","info":"","unit":"W","min":"0","max":"0"},
{"register":"41952","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error Low 8","info":"","unit":"W","min":"0","max":"0"},
{"register":"41953","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error Low 7","info":"","unit":"W","min":"0","max":"0"},
{"register":"41954","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error Low 6","info":"","unit":"W","min":"0","max":"0"},
{"register":"41955","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error Low 5","info":"","unit":"W","min":"0","max":"0"},
{"register":"41956","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error Low 4","info":"","unit":"W","min":"0","max":"0"},
{"register":"41957","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error Low 3","info":"","unit":"W","min":"0","max":"0"},
{"register":"41958","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error Low 2","info":"","unit":"W","min":"0","max":"0"},
{"register":"41959","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 Error Low 1","info":"","unit":"W","min":"0","max":"0"},
{"register":"41960","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Com Percentage 10","info":"","unit":"%","min":"0","max":"0"},
{"register":"41961","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Com Percentage 9","info":"","unit":"%","min":"0","max":"0"},
{"register":"41962","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Com Percentage 8","info":"","unit":"%","min":"0","max":"0"},
{"register":"41963","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Com Percentage 7","info":"","unit":"%","min":"0","max":"0"},
{"register":"41964","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Com Percentage 6","info":"","unit":"%","min":"0","max":"0"},
{"register":"41965","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Com Percentage 5","info":"","unit":"%","min":"0","max":"0"},
{"register":"41966","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Com Percentage 4","info":"","unit":"%","min":"0","max":"0"},
{"register":"41967","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Com Percentage 3","info":"","unit":"%","min":"0","max":"0"},
{"register":"41968","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Com Percentage 2","info":"","unit":"%","min":"0","max":"0"},
{"register":"41969","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Com Percentage 1","info":"","unit":"%","min":"0","max":"0"},
{"register":"41980","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage1 10","info":"","unit":"V","min":"0","max":"0"},
{"register":"41981","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage1 9","info":"","unit":"V","min":"0","max":"0"},
{"register":"41982","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage1 8","info":"","unit":"V","min":"0","max":"0"},
{"register":"41983","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage1 7","info":"","unit":"V","min":"0","max":"0"},
{"register":"41984","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage1 6","info":"","unit":"V","min":"0","max":"0"},
{"register":"41985","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage1 5","info":"","unit":"V","min":"0","max":"0"},
{"register":"41986","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage1 4","info":"","unit":"V","min":"0","max":"0"},
{"register":"41987","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage1 3","info":"","unit":"V","min":"0","max":"0"},
{"register":"41988","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage1 2","info":"","unit":"V","min":"0","max":"0"},
{"register":"41989","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage1 1","info":"","unit":"V","min":"0","max":"0"},
{"register":"41990","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage2 10","info":"","unit":"V","min":"0","max":"0"},
{"register":"41991","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage2 9","info":"","unit":"V","min":"0","max":"0"},
{"register":"41992","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage2 8","info":"","unit":"V","min":"0","max":"0"},
{"register":"41993","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage2 7","info":"","unit":"V","min":"0","max":"0"},
{"register":"41994","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage2 6","info":"","unit":"V","min":"0","max":"0"},
{"register":"41995","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage2 5","info":"","unit":"V","min":"0","max":"0"},
{"register":"41996","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage2 4","info":"","unit":"V","min":"0","max":"0"},
{"register":"41997","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage2 3","info":"","unit":"V","min":"0","max":"0"},
{"register":"41998","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage2 2","info":"","unit":"V","min":"0","max":"0"},
{"register":"41999","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Voltage2 1","info":"","unit":"V","min":"0","max":"0"},
{"register":"42000","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Temperature 10","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42001","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Temperature 9","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42002","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Temperature 8","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42003","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Temperature 7","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42004","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Temperature 6","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42005","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Temperature 5","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42006","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Temperature 4","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42007","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Temperature 3","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42008","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Temperature 2","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42009","factor":10,"size":"u16","mode":"R","titel":"AA23-BE5 Temperature 1","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42010","factor":10,"size":"u32","mode":"R","titel":"AA23-BE5 Energy 10","info":"","unit":"kWh","min":"0","max":"0"},
{"register":"42012","factor":10,"size":"u32","mode":"R","titel":"AA23-BE5 Energy 9","info":"","unit":"kWh","min":"0","max":"0"},
{"register":"42014","factor":10,"size":"u32","mode":"R","titel":"AA23-BE5 Energy 8","info":"","unit":"kWh","min":"0","max":"0"},
{"register":"42016","factor":10,"size":"u32","mode":"R","titel":"AA23-BE5 Energy 7","info":"","unit":"kWh","min":"0","max":"0"},
{"register":"42018","factor":10,"size":"u32","mode":"R","titel":"AA23-BE5 Energy 6","info":"","unit":"kWh","min":"0","max":"0"},
{"register":"42020","factor":10,"size":"u32","mode":"R","titel":"AA23-BE5 Energy 5","info":"","unit":"kWh","min":"0","max":"0"},
{"register":"42022","factor":10,"size":"u32","mode":"R","titel":"AA23-BE5 Energy 4","info":"","unit":"kWh","min":"0","max":"0"},
{"register":"42024","factor":10,"size":"u32","mode":"R","titel":"AA23-BE5 Energy 3","info":"","unit":"kWh","min":"0","max":"0"},
{"register":"42026","factor":10,"size":"u32","mode":"R","titel":"AA23-BE5 Energy 2","info":"","unit":"kWh","min":"0","max":"0"},
{"register":"42028","factor":10,"size":"u32","mode":"R","titel":"AA23-BE5 Energy 1","info":"","unit":"kWh","min":"0","max":"0"},
{"register":"42030","factor":1,"size":"u16","mode":"R","titel":"AA23-BE5 EME20 Version","info":"","unit":"","min":"0","max":"0"},
{"register":"42033","factor":10,"size":"u8","mode":"R","titel":"PV Panel Heat Offset","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42034","factor":10,"size":"u8","mode":"R","titel":"PV Panel Pool Offset","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42035","factor":1,"size":"u32","mode":"R","titel":"AA23-BE5 EME20 Total Power","info":"","unit":"W","min":"0","max":"0"},
{"register":"42037","factor":1,"size":"u32","mode":"R","titel":"AA23-BE5 EME20 Total Average Power","info":"","unit":"W","min":"0","max":"0"},
{"register":"42075","factor":10,"size":"u32","mode":"R","titel":"AA23-BE5 EME20 Total Energy","info":"","unit":"kWh","min":"0","max":"0"},
{"register":"42080","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Alarm 504","info":"","unit":"","min":"0","max":"0"},
{"register":"42081","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Alarm 505","info":"","unit":"","min":"0","max":"0"},
{"register":"42082","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Alarm 506","info":"","unit":"","min":"0","max":"0"},
{"register":"42083","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Alarm 507","info":"","unit":"","min":"0","max":"0"},
{"register":"42084","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Alarm 508","info":"","unit":"","min":"0","max":"0"},
{"register":"42085","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Alarm 509","info":"","unit":"","min":"0","max":"0"},
{"register":"42086","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Alarm 510","info":"","unit":"","min":"0","max":"0"},
{"register":"42087","factor":1,"size":"u8","mode":"R","titel":"AA23-BE5 Alarm 511","info":"","unit":"","min":"0","max":"0"},
{"register":"42097","factor":1,"size":"s8","mode":"R/W","titel":"Ground water pump auto speed","info":"Ground water pump auto speed","unit":"","min":"0","max":"0"},
{"register":"42100","factor":10,"size":"s16","mode":"R","titel":"BT1 Average, 24h","info":"EB100-BT1 Outdoor temperature average, 24h","unit":"°C","min":"0","max":"0"},
{"register":"42101","factor":10,"size":"s16","mode":"R","titel":"Used heating power average, 24h","info":"Used heating power average, 24h","unit":"°C","min":"0","max":"0"},
{"register":"42136","factor":10,"size":"s16","mode":"R","titel":"BT22 Supply air temp.","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42137","factor":10,"size":"s16","mode":"R","titel":"BT22 Supply air temp.","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42138","factor":10,"size":"s16","mode":"R","titel":"BT22 Supply air temp.","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42139","factor":10,"size":"s16","mode":"R","titel":"AZ30-BT23 Outdoor temp. ERS 4","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42140","factor":10,"size":"s16","mode":"R","titel":"AZ30-BT23 Outdoor temp. ERS 3","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42141","factor":10,"size":"s16","mode":"R","titel":"AZ30-BT23 Outdoor temp. ERS 2","info":"","unit":"°C","min":"0","max":"0"},
{"register":"42150","factor":1,"size":"u8","mode":"R","titel":"External ERS 4 accessory relays","info":"Indicates the status of the relays on the ERS accessory. The information is binary encoded. b0: K1, b1: K2, b2: K3, b3: K4","unit":"","min":"0","max":"0"},
{"register":"42151","factor":1,"size":"u8","mode":"R","titel":"External ERS 3 accessory relays","info":"Indicates the status of the relays on the ERS accessory. The information is binary encoded. b0: K1, b1: K2, b2: K3, b3: K4","unit":"","min":"0","max":"0"},
{"register":"42152","factor":1,"size":"u8","mode":"R","titel":"External ERS 2 accessory relays","info":"Indicates the status of the relays on the ERS accessory. The information is binary encoded. b0: K1, b1: K2, b2: K3, b3: K4","unit":"","min":"0","max":"0"},
{"register":"42153","factor":1,"size":"u8","mode":"R","titel":"External ERS 4 accessory GQ2 speed","info":"Indicates the speed of the GQ2 fan speed on the ERS accessory.","unit":"%","min":"0","max":"0"},
{"register":"42154","factor":1,"size":"u8","mode":"R","titel":"External ERS 3 accessory GQ2 speed","info":"Indicates the speed of the GQ2 fan speed on the ERS accessory.","unit":"%","min":"0","max":"0"},
{"register":"42155","factor":1,"size":"u8","mode":"R","titel":"External ERS 2 accessory GQ2 speed","info":"Indicates the speed of the GQ2 fan speed on the ERS accessory.","unit":"%","min":"0","max":"0"},
{"register":"42156","factor":1,"size":"u8","mode":"R","titel":"External ERS 4 accessory GQ3 speed","info":"Indicates the speed of the GQ3 fan speed on the ERS accessory.","unit":"%","min":"0","max":"0"},
{"register":"42157","factor":1,"size":"u8","mode":"R","titel":"External ERS 3 accessory GQ3 speed","info":"Indicates the speed of the GQ3 fan speed on the ERS accessory.","unit":"%","min":"0","max":"0"},
{"register":"42158","factor":1,"size":"u8","mode":"R","titel":"External ERS 2 accessory GQ3 speed","info":"Indicates the speed of the GQ3 fan speed on the ERS accessory.","unit":"%","min":"0","max":"0"},
{"register":"42159","factor":1,"size":"u8","mode":"R","titel":"External ERS 4 accessory block status","info":"Indicates if the ERS accessory is externaly blocked.","unit":"","min":"0","max":"0"},
{"register":"42160","factor":1,"size":"u8","mode":"R","titel":"External ERS 3 accessory block status","info":"Indicates if the ERS accessory is externaly blocked.","unit":"","min":"0","max":"0"},
{"register":"42161","factor":1,"size":"u8","mode":"R","titel":"External ERS 2 accessory block status","info":"Indicates if the ERS accessory is externaly blocked.","unit":"","min":"0","max":"0"},
{"register":"42162","factor":1,"size":"u8","mode":"R","titel":"External ERS 4 accessory EB17","info":"Indicates if the status of ERS accessory EB17. I = closed, 0 = open.","unit":"","min":"0","max":"0"},
{"register":"42163","factor":1,"size":"u8","mode":"R","titel":"External ERS 3 accessory EB17","info":"Indicates if the status of ERS accessory EB17. I = closed, 0 = open.","unit":"","min":"0","max":"0"},
{"register":"42164","factor":1,"size":"u8","mode":"R","titel":"External ERS 2 accessory EB17","info":"Indicates if the status of ERS accessory EB17. I = closed, 0 = open.","unit":"","min":"0","max":"0"},
{"register":"42168","factor":10,"size":"u32","mode":"R","titel":"EB108-EP15 Heat Meter - HW Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42170","factor":10,"size":"u32","mode":"R","titel":"EB108-EP15 Heat Meter - Heat Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42172","factor":10,"size":"u32","mode":"R","titel":"EB108-EP15 Heat Meter - Cooling Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42174","factor":10,"size":"u32","mode":"R","titel":"EB108-EP15 Heat Meter - Pool Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42176","factor":10,"size":"u32","mode":"R","titel":"EB108-EP15 Heat Meter - HW Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42178","factor":10,"size":"u32","mode":"R","titel":"EB108-EP15 Heat Meter - Heat Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42183","factor":10,"size":"u32","mode":"R","titel":"EB108-EP14 Heat Meter - HW Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42185","factor":10,"size":"u32","mode":"R","titel":"EB108-EP14 Heat Meter - Heat Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42187","factor":10,"size":"u32","mode":"R","titel":"EB108-EP14 Heat Meter - Cooling Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42189","factor":10,"size":"u32","mode":"R","titel":"EB108-EP14 Heat Meter - Pool Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42191","factor":10,"size":"u32","mode":"R","titel":"EB108-EP14 Heat Meter - HW Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42193","factor":10,"size":"u32","mode":"R","titel":"EB108-EP14 Heat Meter - Heat Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42198","factor":10,"size":"u32","mode":"R","titel":"EB107-EP15 Heat Meter - HW Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42200","factor":10,"size":"u32","mode":"R","titel":"EB107-EP15 Heat Meter - Heat Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42202","factor":10,"size":"u32","mode":"R","titel":"EB107-EP15 Heat Meter - Cooling Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42204","factor":10,"size":"u32","mode":"R","titel":"EB107-EP15 Heat Meter - Pool Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42206","factor":10,"size":"u32","mode":"R","titel":"EB107-EP15 Heat Meter - HW Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42208","factor":10,"size":"u32","mode":"R","titel":"EB107-EP15 Heat Meter - Heat Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42213","factor":10,"size":"u32","mode":"R","titel":"EB107-EP14 Heat Meter - HW Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42215","factor":10,"size":"u32","mode":"R","titel":"EB107-EP14 Heat Meter - Heat Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42217","factor":10,"size":"u32","mode":"R","titel":"EB107-EP14 Heat Meter - Cooling Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42219","factor":10,"size":"u32","mode":"R","titel":"EB107-EP14 Heat Meter - Pool Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42221","factor":10,"size":"u32","mode":"R","titel":"EB107-EP14 Heat Meter - HW Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42223","factor":10,"size":"u32","mode":"R","titel":"EB107-EP14 Heat Meter - Heat Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42228","factor":10,"size":"u32","mode":"R","titel":"EB106-EP15 Heat Meter - HW Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42230","factor":10,"size":"u32","mode":"R","titel":"EB106-EP15 Heat Meter - Heat Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42232","factor":10,"size":"u32","mode":"R","titel":"EB106-EP15 Heat Meter - Cooling Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42234","factor":10,"size":"u32","mode":"R","titel":"EB106-EP15 Heat Meter - Pool Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42236","factor":10,"size":"u32","mode":"R","titel":"EB106-EP15 Heat Meter - HW Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42238","factor":10,"size":"u32","mode":"R","titel":"EB106-EP15 Heat Meter - Heat Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42243","factor":10,"size":"u32","mode":"R","titel":"EB106-EP14 Heat Meter - HW Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42245","factor":10,"size":"u32","mode":"R","titel":"EB106-EP14 Heat Meter - Heat Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42247","factor":10,"size":"u32","mode":"R","titel":"EB106-EP14 Heat Meter - Cooling Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42249","factor":10,"size":"u32","mode":"R","titel":"EB106-EP14 Heat Meter - Pool Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42251","factor":10,"size":"u32","mode":"R","titel":"EB106-EP14 Heat Meter - HW Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42253","factor":10,"size":"u32","mode":"R","titel":"EB106-EP14 Heat Meter - Heat Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42258","factor":10,"size":"u32","mode":"R","titel":"EB105-EP15 Heat Meter - HW Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42260","factor":10,"size":"u32","mode":"R","titel":"EB105-EP15 Heat Meter - Heat Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42262","factor":10,"size":"u32","mode":"R","titel":"EB105-EP15 Heat Meter - Cooling Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42264","factor":10,"size":"u32","mode":"R","titel":"EB105-EP15 Heat Meter - Pool Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42266","factor":10,"size":"u32","mode":"R","titel":"EB105-EP15 Heat Meter - HW Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42268","factor":10,"size":"u32","mode":"R","titel":"EB105-EP15 Heat Meter - Heat Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42273","factor":10,"size":"u32","mode":"R","titel":"EB105-EP14 Heat Meter - HW Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42275","factor":10,"size":"u32","mode":"R","titel":"EB105-EP14 Heat Meter - Heat Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42277","factor":10,"size":"u32","mode":"R","titel":"EB105-EP14 Heat Meter - Cooling Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42279","factor":10,"size":"u32","mode":"R","titel":"EB105-EP14 Heat Meter - Pool Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42281","factor":10,"size":"u32","mode":"R","titel":"EB105-EP14 Heat Meter - HW Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42283","factor":10,"size":"u32","mode":"R","titel":"EB105-EP14 Heat Meter - Heat Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42288","factor":10,"size":"u32","mode":"R","titel":"EB104-EP15 Heat Meter - HW Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42290","factor":10,"size":"u32","mode":"R","titel":"EB104-EP15 Heat Meter - Heat Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42292","factor":10,"size":"u32","mode":"R","titel":"EB104-EP15 Heat Meter - Cooling Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42294","factor":10,"size":"u32","mode":"R","titel":"EB104-EP15 Heat Meter - Pool Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42296","factor":10,"size":"u32","mode":"R","titel":"EB104-EP15 Heat Meter - HW Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42298","factor":10,"size":"u32","mode":"R","titel":"EB104-EP15 Heat Meter - Heat Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42303","factor":10,"size":"u32","mode":"R","titel":"EB104-EP14 Heat Meter - HW Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42305","factor":10,"size":"u32","mode":"R","titel":"EB104-EP14 Heat Meter - Heat Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42307","factor":10,"size":"u32","mode":"R","titel":"EB104-EP14 Heat Meter - Cooling Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42309","factor":10,"size":"u32","mode":"R","titel":"EB104-EP14 Heat Meter - Pool Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42311","factor":10,"size":"u32","mode":"R","titel":"EB104-EP14 Heat Meter - HW Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42313","factor":10,"size":"u32","mode":"R","titel":"EB104-EP14 Heat Meter - Heat Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42318","factor":10,"size":"u32","mode":"R","titel":"EB103-EP15 Heat Meter - HW Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42320","factor":10,"size":"u32","mode":"R","titel":"EB103-EP15 Heat Meter - Heat Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42322","factor":10,"size":"u32","mode":"R","titel":"EB103-EP15 Heat Meter - Cooling Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42324","factor":10,"size":"u32","mode":"R","titel":"EB103-EP15 Heat Meter - Pool Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42326","factor":10,"size":"u32","mode":"R","titel":"EB103-EP15 Heat Meter - HW Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42328","factor":10,"size":"u32","mode":"R","titel":"EB103-EP15 Heat Meter - Heat Cpr","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","min":"0","max":"0"},
{"register":"42333","factor":10,"size":"u32","mode":"R","titel":"EB103-EP14 Heat Meter - HW Cpr and Add","info":"Accumulated energy production as calculated by the heat meter","unit":"kWh","
gitextract_y3rmklbz/ ├── .gitignore ├── LICENSE ├── README.en.md ├── README.md ├── backend.js ├── default.json ├── docker/ │ ├── .dockerignore │ ├── Dockerfile │ ├── README.md │ ├── docker-compose.yml │ └── nibepi/ │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── backend.js │ ├── default.json │ ├── index.js │ ├── lib/ │ │ ├── models.json │ │ ├── saveGraph.js │ │ ├── startCore.js │ │ └── stopCore.js │ ├── log.js │ ├── modbus-client.js │ ├── models/ │ │ ├── F1145.json │ │ ├── F1155.json │ │ ├── F1245.json │ │ ├── F1255.json │ │ ├── F1345.json │ │ ├── F1355.json │ │ ├── F370.json │ │ ├── F470.json │ │ ├── F730.json │ │ ├── F750.json │ │ ├── RMU40_S1.json │ │ ├── RMU40_S2.json │ │ ├── RMU40_S3.json │ │ ├── RMU40_S4.json │ │ ├── S1255.json │ │ ├── VVM225.json │ │ ├── VVM310.json │ │ ├── VVM320.json │ │ ├── VVM325.json │ │ └── VVM500.json │ ├── nibegw-client.js │ ├── package.json │ └── server.js ├── example-nibeF.js ├── example-nibeS.js ├── example.js ├── index.js ├── lib/ │ ├── models.json │ ├── saveGraph.js │ ├── startCore.js │ └── stopCore.js ├── log.js ├── modbus-client.js ├── modbus-server.js ├── modbus-tcp.js ├── models/ │ ├── F1145.json │ ├── F1155.json │ ├── F1245.json │ ├── F1255.json │ ├── F1345.json │ ├── F1355.json │ ├── F370.json │ ├── F470.json │ ├── F730.json │ ├── F750.json │ ├── RMU40_S1.json │ ├── RMU40_S2.json │ ├── RMU40_S3.json │ ├── RMU40_S4.json │ ├── S1255.json │ ├── SMO20.json │ ├── SMO40.json │ ├── VVM225.json │ ├── VVM310.json │ ├── VVM320.json │ ├── VVM325.json │ └── VVM500.json ├── nibegw-client.js ├── package.json ├── server.js └── test.js
SYMBOL INDEX (45 symbols across 8 files)
FILE: backend.js
function showPortOpen (line 95) | function showPortOpen() {
function showPortClose (line 98) | function showPortClose() {
function showError (line 101) | function showError(error) {
function analyzeData (line 113) | function analyzeData(data) {
FILE: docker/nibepi/backend.js
function showPortOpen (line 85) | function showPortOpen() {
function showPortClose (line 88) | function showPortClose() {
function showError (line 91) | function showError(error) {
function analyzeData (line 103) | function analyzeData(data) {
FILE: docker/nibepi/index.js
function requireF (line 62) | function requireF(modulePath){ // force require
function requireGraph (line 75) | function requireGraph(){ // force require
function reqData (line 481) | async function reqData (address) {
function getData (line 628) | function getData(address) {
function setDataValue (line 649) | function setDataValue(incoming) {
function Calc_CRC (line 744) | function Calc_CRC(data) {
function removeRegister (line 772) | function removeRegister(address) {
function decodeS (line 931) | async function decodeS(data) {
function startMQTT (line 1152) | function startMQTT(host,port,user,pass) {
function addMQTTdiscovery (line 1199) | async function addMQTTdiscovery(data) {
function removeMQTTdiscovery (line 1227) | async function removeMQTTdiscovery(data) {
function formatMQTTdiscovery (line 1242) | function formatMQTTdiscovery(data) {
FILE: docker/nibepi/modbus-client.js
function writeData (line 9) | async function writeData(item) {
function requestData (line 34) | async function requestData(address) {
function startLoop (line 110) | async function startLoop() {
FILE: docker/nibepi/nibegw-client.js
function write (line 51) | function write(data) {
function read (line 59) | function read(data) {
function start (line 67) | function start() {
FILE: index.js
function requireF (line 66) | function requireF(modulePath){ // force require
function requireGraph (line 79) | function requireGraph(){ // force require
function reqData (line 493) | async function reqData (address) {
function getData (line 640) | function getData(address) {
function setDataValue (line 661) | function setDataValue(incoming) {
function Calc_CRC (line 756) | function Calc_CRC(data) {
function removeRegister (line 784) | function removeRegister(address) {
function decodeS (line 937) | async function decodeS(data) {
function startMQTT (line 1162) | function startMQTT(host,port,user,pass) {
function addMQTTdiscovery (line 1209) | async function addMQTTdiscovery(data) {
function removeMQTTdiscovery (line 1237) | async function removeMQTTdiscovery(data) {
function formatMQTTdiscovery (line 1252) | function formatMQTTdiscovery(data) {
function sendID (line 1452) | function sendID(dev,model,firmware) {
FILE: modbus-client.js
function writeData (line 9) | async function writeData(item) {
function requestData (line 34) | async function requestData(address) {
function startLoop (line 110) | async function startLoop() {
FILE: nibegw-client.js
function write (line 51) | function write(data) {
function read (line 59) | function read(data) {
function start (line 67) | function start() {
Condensed preview — 83 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (6,712K chars).
[
{
"path": ".gitignore",
"chars": 1623,
"preview": "config.json\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (ht"
},
{
"path": "LICENSE",
"chars": 1065,
"preview": "MIT License\n\nCopyright (c) 2020 anerdins\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\no"
},
{
"path": "README.en.md",
"chars": 4389,
"preview": "# nibepi\nFollow this project on Facebook! https://www.facebook.com/groups/nibepi/<br>\n<b>Finally a imagefile running Ras"
},
{
"path": "README.md",
"chars": 4231,
"preview": "# nibepi\n<i>README in other languages: [English](https://github.com/anerdins/nibepi/blob/master/README.en.md)</i><br><br"
},
{
"path": "backend.js",
"chars": 14403,
"preview": "/*MIT License\r\n\r\nCopyright (c) 2019 Fredrik Anerdin\r\n\r\nPermission is hereby granted, free of charge, to any person obtai"
},
{
"path": "default.json",
"chars": 1087,
"preview": "{\r\n \"version\":\"1.1\",\r\n \"registers\":[],\r\n \"connection\": {\r\n \"enable\":\"serial\",\r\n \"series\":\"fSeries"
},
{
"path": "docker/.dockerignore",
"chars": 220,
"preview": "node_modules\nnpm-debug.log\nnibepi/modbus-server.js\nnibepi/modbus-tcp.js\nnibepi/test.js\nnibepi/example.js\nnibepi/example-"
},
{
"path": "docker/Dockerfile",
"chars": 975,
"preview": "FROM node:latest\n\n# Copy source to container\nRUN mkdir -p /usr/app/src\nRUN mkdir -p /etc/nibepi\nRUN chown -R node:node /"
},
{
"path": "docker/README.md",
"chars": 176,
"preview": "This is the Docker section of NibePi, the files for building the image manually will be found here, check out the docker"
},
{
"path": "docker/docker-compose.yml",
"chars": 292,
"preview": "version: '3'\nservices:\n nibepi:\n container_name: \"nibepi\"\n build: .\n# image: anerdins/nibepi-base\n volumes:"
},
{
"path": "docker/nibepi/.gitignore",
"chars": 1623,
"preview": "config.json\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (ht"
},
{
"path": "docker/nibepi/LICENSE",
"chars": 1065,
"preview": "MIT License\n\nCopyright (c) 2020 anerdins\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\no"
},
{
"path": "docker/nibepi/README.md",
"chars": 44,
"preview": "# nibepi\nBackend for Nibe F series heatpump\n"
},
{
"path": "docker/nibepi/backend.js",
"chars": 14040,
"preview": "/*MIT License\r\n\r\nCopyright (c) 2019 Fredrik Anerdin\r\n\r\nPermission is hereby granted, free of charge, to any person obtai"
},
{
"path": "docker/nibepi/default.json",
"chars": 1009,
"preview": "{\r\n \"version\":\"1.1\",\r\n \"registers\":[],\r\n \"connection\": {\r\n \"enable\":\"serial\",\r\n \"series\":\"fSeries"
},
{
"path": "docker/nibepi/index.js",
"chars": 61956,
"preview": "/*MIT License\r\n\r\nCopyright (c) 2019 Fredrik Anerdin\r\n\r\nPermission is hereby granted, free of charge, to any person obtai"
},
{
"path": "docker/nibepi/lib/models.json",
"chars": 729,
"preview": "{\n \"F370\":\"./models/F370.json\",\n \"F470\":\"./models/F470.json\",\n \"F730\":\"./models/F730.json\",\n \"F750\":\"./model"
},
{
"path": "docker/nibepi/lib/saveGraph.js",
"chars": 3518,
"preview": "let path = process.env.path;\r\nlet exec = require('child_process').exec;\r\nlet config = JSON.parse(process.env.config);\r\np"
},
{
"path": "docker/nibepi/lib/startCore.js",
"chars": 1757,
"preview": "const startCoreF = (port) => {\r\n const promise = new Promise((resolve,reject) => {\r\n setTimeout((port) => {\r\n "
},
{
"path": "docker/nibepi/lib/stopCore.js",
"chars": 444,
"preview": "const stopCore = (core) => {\r\n const promise = new Promise((resolve,reject) => {\r\n if(core!==undefined) {\r\n "
},
{
"path": "docker/nibepi/log.js",
"chars": 453,
"preview": "var fs = require('fs');\nlet writer = fs.createWriteStream('/tmp/nibepi.log');\nconst log = (enable,data,enabled,kind) => "
},
{
"path": "docker/nibepi/modbus-client.js",
"chars": 7375,
"preview": "// create an empty modbus client\r\nvar ModbusRTU = require(\"modbus-serial\");\r\nvar client = new ModbusRTU();\r\nconst getQue"
},
{
"path": "docker/nibepi/models/F1145.json",
"chars": 256279,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "docker/nibepi/models/F1155.json",
"chars": 169766,
"preview": "[\r\n {\"register\":\"32260\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"NIBE Inverter 216-state\",\"info\":\"\",\"unit\":\"\",\"min\""
},
{
"path": "docker/nibepi/models/F1245.json",
"chars": 256279,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "docker/nibepi/models/F1255.json",
"chars": 169766,
"preview": "[\r\n {\"register\":\"32260\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"NIBE Inverter 216-state\",\"info\":\"\",\"unit\":\"\",\"min\""
},
{
"path": "docker/nibepi/models/F1345.json",
"chars": 266440,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "docker/nibepi/models/F1355.json",
"chars": 273409,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "docker/nibepi/models/F370.json",
"chars": 81827,
"preview": "[\n {\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor "
},
{
"path": "docker/nibepi/models/F470.json",
"chars": 82328,
"preview": "[\r\n {\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor"
},
{
"path": "docker/nibepi/models/F730.json",
"chars": 98763,
"preview": "[\r\n {\"register\":\"32260\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"NIBE Inverter 216-state\",\"info\":\"\",\"unit\":\"\",\"min\""
},
{
"path": "docker/nibepi/models/F750.json",
"chars": 109500,
"preview": "[\n {\"register\":\"32260\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"NIBE Inverter 216-state\",\"info\":\"\",\"unit\":\"\",\"min\":"
},
{
"path": "docker/nibepi/models/RMU40_S1.json",
"chars": 2120,
"preview": "[\r\n {\"register\":\"10001\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"A-larm\",\"info\":\"Indicates the alarm number of the "
},
{
"path": "docker/nibepi/models/RMU40_S2.json",
"chars": 2125,
"preview": "[\r\n {\"register\":\"10001\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"A-larm\",\"info\":\"Indicates the alarm number of the "
},
{
"path": "docker/nibepi/models/RMU40_S3.json",
"chars": 2125,
"preview": "[\r\n {\"register\":\"10001\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"A-larm\",\"info\":\"Indicates the alarm number of the "
},
{
"path": "docker/nibepi/models/RMU40_S4.json",
"chars": 2125,
"preview": "[\r\n {\"register\":\"10001\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"A-larm\",\"info\":\"Indicates the alarm number of the "
},
{
"path": "docker/nibepi/models/S1255.json",
"chars": 4982,
"preview": "[\r\n{\"register\":\"30001\",\"factor\":\"10\",\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1\",\"info\":\"Utomhusgivare\",\"unit\":\"°C\",\"min\":\"0\","
},
{
"path": "docker/nibepi/models/VVM225.json",
"chars": 149895,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "docker/nibepi/models/VVM310.json",
"chars": 147259,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "docker/nibepi/models/VVM320.json",
"chars": 149895,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "docker/nibepi/models/VVM325.json",
"chars": 149895,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "docker/nibepi/models/VVM500.json",
"chars": 147259,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "docker/nibepi/nibegw-client.js",
"chars": 5599,
"preview": "const dgram = require('dgram');\r\nvar server = dgram.createSocket('udp4');\r\n\r\nvar HOST = \"127.0.0.1\";\r\nvar PORT = 9999;\r\n"
},
{
"path": "docker/nibepi/package.json",
"chars": 508,
"preview": "{\n \"author\": {\n \"name\": \"Fredrik Anerdin\"\n },\n \"bundleDependencies\": false,\n \"dependencies\": {\n \"mqtt\": \"^3.0."
},
{
"path": "docker/nibepi/server.js",
"chars": 3065,
"preview": "var nibe = require('./index.js');\r\n\r\nprocess.on('exit', function(code) {\r\n console.log('About to exit with code:', co"
},
{
"path": "example-nibeF.js",
"chars": 698,
"preview": "var nibe = require('./index');\r\nconst serialPort = \"/dev/ttyAMA0\";\r\nconst mqtt_host = \"127.0.0.1\";\r\nconst mqtt_port = \"1"
},
{
"path": "example-nibeS.js",
"chars": 950,
"preview": "var nibe = require('./index.js');\r\nconst host = \"192.168.1.23\";\r\nconst port = 502;\r\n//const host = \"127.0.0.1\";\r\n//const"
},
{
"path": "example.js",
"chars": 699,
"preview": "var nibe = require('./index');\r\nconst serialPort = \"/dev/ttyAMA0\";\r\nconst mqtt_host = \"127.0.0.1\";\r\nconst mqtt_port = \"1"
},
{
"path": "index.js",
"chars": 64124,
"preview": "/*MIT License\r\n\r\nCopyright (c) 2019 Fredrik Anerdin\r\n\r\nPermission is hereby granted, free of charge, to any person obtai"
},
{
"path": "lib/models.json",
"chars": 823,
"preview": "{\r\n \"F370\":\"./models/F370.json\",\r\n \"F470\":\"./models/F470.json\",\r\n \"F730\":\"./models/F730.json\",\r\n \"F750\":\"./m"
},
{
"path": "lib/saveGraph.js",
"chars": 3518,
"preview": "let path = process.env.path;\r\nlet exec = require('child_process').exec;\r\nlet config = JSON.parse(process.env.config);\r\np"
},
{
"path": "lib/startCore.js",
"chars": 1757,
"preview": "const startCoreF = (port) => {\r\n const promise = new Promise((resolve,reject) => {\r\n setTimeout((port) => {\r\n "
},
{
"path": "lib/stopCore.js",
"chars": 444,
"preview": "const stopCore = (core) => {\r\n const promise = new Promise((resolve,reject) => {\r\n if(core!==undefined) {\r\n "
},
{
"path": "log.js",
"chars": 453,
"preview": "var fs = require('fs');\nlet writer = fs.createWriteStream('/tmp/nibepi.log');\nconst log = (enable,data,enabled,kind) => "
},
{
"path": "modbus-client.js",
"chars": 7375,
"preview": "// create an empty modbus client\r\nvar ModbusRTU = require(\"modbus-serial\");\r\nvar client = new ModbusRTU();\r\nconst getQue"
},
{
"path": "modbus-server.js",
"chars": 1766,
"preview": "// create an empty modbus client\r\nvar Modbus = require(\"modbus-serial\");\r\nvar vector = {\r\n getInputRegister: function"
},
{
"path": "modbus-tcp.js",
"chars": 1779,
"preview": "// create an empty modbus client\r\nvar ModbusRTU = require(\"modbus-serial\");\r\nvar vector = {\r\n getInputRegister: funct"
},
{
"path": "models/F1145.json",
"chars": 256279,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "models/F1155.json",
"chars": 169766,
"preview": "[\r\n {\"register\":\"32260\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"NIBE Inverter 216-state\",\"info\":\"\",\"unit\":\"\",\"min\""
},
{
"path": "models/F1245.json",
"chars": 256279,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "models/F1255.json",
"chars": 169766,
"preview": "[\r\n {\"register\":\"32260\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"NIBE Inverter 216-state\",\"info\":\"\",\"unit\":\"\",\"min\""
},
{
"path": "models/F1345.json",
"chars": 266440,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "models/F1355.json",
"chars": 273409,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "models/F370.json",
"chars": 82328,
"preview": "[\r\n {\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor"
},
{
"path": "models/F470.json",
"chars": 82328,
"preview": "[\r\n {\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor"
},
{
"path": "models/F730.json",
"chars": 98763,
"preview": "[\r\n {\"register\":\"32260\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"NIBE Inverter 216-state\",\"info\":\"\",\"unit\":\"\",\"min\""
},
{
"path": "models/F750.json",
"chars": 109500,
"preview": "[\n {\"register\":\"32260\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"NIBE Inverter 216-state\",\"info\":\"\",\"unit\":\"\",\"min\":"
},
{
"path": "models/RMU40_S1.json",
"chars": 2120,
"preview": "[\r\n {\"register\":\"10001\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"A-larm\",\"info\":\"Indicates the alarm number of the "
},
{
"path": "models/RMU40_S2.json",
"chars": 2125,
"preview": "[\r\n {\"register\":\"10001\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"A-larm\",\"info\":\"Indicates the alarm number of the "
},
{
"path": "models/RMU40_S3.json",
"chars": 2125,
"preview": "[\r\n {\"register\":\"10001\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"A-larm\",\"info\":\"Indicates the alarm number of the "
},
{
"path": "models/RMU40_S4.json",
"chars": 2125,
"preview": "[\r\n {\"register\":\"10001\",\"factor\":1,\"size\":\"u8\",\"mode\":\"R\",\"titel\":\"A-larm\",\"info\":\"Indicates the alarm number of the "
},
{
"path": "models/S1255.json",
"chars": 4982,
"preview": "[\r\n{\"register\":\"30001\",\"factor\":\"10\",\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1\",\"info\":\"Utomhusgivare\",\"unit\":\"°C\",\"min\":\"0\","
},
{
"path": "models/SMO20.json",
"chars": 59655,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":\"10\",\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor t"
},
{
"path": "models/SMO40.json",
"chars": 219339,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":\"10\",\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor t"
},
{
"path": "models/VVM225.json",
"chars": 149895,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "models/VVM310.json",
"chars": 147259,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "models/VVM320.json",
"chars": 149895,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "models/VVM325.json",
"chars": 149895,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "models/VVM500.json",
"chars": 147259,
"preview": "[\r\n{\"register\":\"40004\",\"factor\":10,\"size\":\"s16\",\"mode\":\"R\",\"titel\":\"BT1 Outdoor Temperature\",\"info\":\"Current outdoor tem"
},
{
"path": "nibegw-client.js",
"chars": 5599,
"preview": "const dgram = require('dgram');\r\nvar server = dgram.createSocket('udp4');\r\n\r\nvar HOST = \"127.0.0.1\";\r\nvar PORT = 9999;\r\n"
},
{
"path": "package.json",
"chars": 508,
"preview": "{\n \"author\": {\n \"name\": \"Fredrik Anerdin\"\n },\n \"bundleDependencies\": false,\n \"dependencies\": {\n \"mqtt\": \"^3.0."
},
{
"path": "server.js",
"chars": 3065,
"preview": "var nibe = require('./index.js');\r\n\r\nprocess.on('exit', function(code) {\r\n console.log('About to exit with code:', co"
},
{
"path": "test.js",
"chars": 195,
"preview": "var spawn = require('child_process').spawn;\r\nconst child = spawn('node', ['./lib/saveGraph.js'], {\r\n env: { data: \"He"
}
]
About this extraction
This page contains the full source code of the anerdins/nibepi GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 83 files (5.3 MB), approximately 1.4M tokens, and a symbol index with 45 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.