Connecting my heatpump 'iDM Terra ML Complete HGL' to OpenHAB 2 using MODBUS via node-red

For some time now I have been using OpenHAB at home for the central control of my house. In OpenHAB, for example, I manage shading, control some lamps, measure and visualize the energy consumption of certain consumers such as refrigerators or washing machines.

The biggest consumer in the house I have not connected yet, my heating. This is a Terra ML Complete HGL heat pump from iDM.

A little research on theire website has shown that the key figures of the machine can be read out via TCP (i. e. Ethernet) via the MODBUS protocol.

Since I didn’t find more detailed information on the internet about how to read the data, I would like to document this on this page.

Necessary tools/software

OpenHAB

First you have to create items in OpenHAB in which the values of the heat pump will be stored in the future:

Group gHeizung (gHaus)

Number Heizung_Temp_Aussen "Aussentemperatur (Heizung) [%.1f °C]" <heating> (gHeizung)
Number Heizung_Temp_WaermepumpeVorlauf "Wärmepumpe Vorlauf [%.1f °C]" <heating> (gHeizung)
Number Heizung_Temp_WaermepumpeRuecklauf "Wärmepumpe Rücklauf [%.1f °C]" <heating> (gHeizung)
Number Heizung_Temp_Hygienik "Hygienik [%.1f °C]" <heating> (gHeizung)
Number Heizung_Temp_Warmwasser "Warmwasser [%.1f °C]" <heating> (gHeizung)
Number Heizung_Temp_HeizkreisAVorlauf "Heizkreis A Vorlauf [%.1f °C]" <heating> (gHeizung)

I tried to read out the machine directly via the MODBUS binding of OpenHAB, but unfortunately I failed. Therefore I use the detour via node-red.

node-red

In node-red I created the following flow:

node-red Flow
node-red Flow

“Modbus Read” reads the data in hex format from the heat pump, this module is configured as follows:

modbus read
modbus read

The server (in my case “IDM Heizung”) must also be configured:

server settings
server settings

In the second step I pass the data to the function “decode Buffer”. This function converts the 4* 8bit hex values into a 32bit float value. The source code of the function is as follows:

let val1 = msg.payload.buffer.readFloatBE(0,4) // 1000 Aussentemperatur
let val2 = msg.payload.buffer.readFloatBE(4,4) // 1002 Wärmepumpe Vorlauf
//let val3 = msg.payload.buffer.readFloatBE(8,4) // 1004 HGL Vorlauftmeperatur
//let val4 = msg.payload.buffer.readFloatBE(12,4) // 1006 Wärmequellenaustritt
let val5 = msg.payload.buffer.readFloatBE(16,4) // 1008 Wärmepumpe Rücklauf
//let val6 = msg.payload.buffer.readFloatBE(20,4) // 1010 Kältespeicher
let val7 = msg.payload.buffer.readFloatBE(24,4) // 1012 Trinkwasserwärme
let val8 = msg.payload.buffer.readFloatBE(28,4) // 1014 Frischwasserzapf
let val9 = msg.payload.buffer.readFloatBE(32,4) // 1016 Heizkreis A Vorlauftemp
//let val10 = msg.payload.buffer.readFloatBE(36,4)
//let val11 = msg.payload.buffer.readFloatBE(40,4)
//let val12 = msg.payload.buffer.readFloatBE(44,4)
//let val13 = msg.payload.buffer.readFloatBE(48,4)
//let val14 = msg.payload.buffer.readFloatBE(52,4)
//let val15 = msg.payload.buffer.readFloatBE(56,4)
//let val16 = msg.payload.buffer.readFloatBE(60,4) // 1030 Heizkreis A Raumgerät
//let val17 = msg.payload.buffer.readFloatBE(64,4)
//let val18 = msg.payload.buffer.readFloatBE(68,4)
//let val19 = msg.payload.buffer.readFloatBE(72,4)
//let val20 = msg.payload.buffer.readFloatBE(76,4)
//let val21 = msg.payload.buffer.readFloatBE(80,4)
//let val22 = msg.payload.buffer.readFloatBE(84,4)
let val23 = msg.payload.buffer.readFloatBE(88,4) // 1044 Heissgastemp
//let val24 = msg.payload.buffer.readFloatBE(92,4) // Feuchtesensor
let val25 = msg.payload.buffer.readFloatBE(96,4) // Luftansaugtemp
let val26 = msg.payload.buffer.readFloatBE(100,4) // Luftwärmetauschtertemp
//let val27 = msg.payload.buffer.readFloatBE(104,4) // Solar Kollektortemp
//let val28 = msg.payload.buffer.readFloatBE(108,4) // Solar Ladetemp
//let val29 = msg.payload.buffer.readFloatBE(112,4) // Solar Kollektorrücklauftemp
//let val30 = msg.payload.buffer.readFloatBE(116,4) // Solar Wärmequellen Referenztemp
let val31 = msg.payload.buffer.readFloatBE(120,4) // Gemittelte Aussentemp

let val32 = msg.payload.buffer.readFloatBE(124,4) // Wärmequellen Eintrittstemp
let val33 = msg.payload.buffer.readFloatBE(128,4) // IDM Systemkühlung Ladefühler
let val34 = msg.payload.buffer.readFloatBE(132,4) // IDM Systemkühlung Rückkühlfühler
let val35 = msg.payload.buffer.readFloatBE(136,4) // Wärmemenge Wärmepumpenvorlauf
let val36 = msg.payload.buffer.readFloatBE(140,4) // Wärmemenge HGL Vorlauf
let val37 = msg.payload.buffer.readFloatBE(144,4) // Wärmemenge Momentanleistung
let val38 = msg.payload.buffer.readFloatBE(148,4) // Wärmemenge Solar
let val39 = msg.payload.buffer.readFloatBE(152,4) // Wärmemenge gesamt
let val40 = msg.payload.buffer.readFloatBE(156,4) // Wärmemenge Heizen gesamt
let val41 = msg.payload.buffer.readFloatBE(160,4) // Wärmemenge HGL gesamt
let val42 = msg.payload.buffer.readFloatBE(164,4) // Wärmemengen Kühlen gesamt
let val43 = msg.payload.buffer.readFloatBE(168,4) // Wämemenge Solar gesamt
let val44 = msg.payload.buffer.readFloatBE(172,4) // Summe Durchflussmengenzähler Grundwasser
let val45 = msg.payload.buffer.readFloatBE(176,4) // Betriebsstunden Wärmequellenpumpe

return [
    {
        payload: {
            aussenTemp: Number((val1).toFixed(1)),
            waermepumpeVorlaufTemp: Number((val2).toFixed(1)),
            waermepumpeRuecklaufTemp: Number((val5).toFixed(1)),
            hygienikTemp: Number((val7).toFixed(1)),
            frischwasserZapfTemp: Number((val8).toFixed(1)),
            heizkreisAVorlaufTemp: Number((val9).toFixed(1)),
            heissgasTemp: Number((val23).toFixed(1)),
            luftAnsaugTemp: Number((val25).toFixed(1)),
            luftWaermeTauscherTemp: Number((val26).toFixed(1)),
            gemittelteAussenTemp: Number((val31).toFixed(1)),
            val32: val32,
            val33: val33,
            val34: val34,
            val35: val35,
            val36: val36,
            val37: val37,
            val38: val38,
            val39: val39,
            val40: val40,
            val41: val41,
            val42: val42,
            val43: val43,
            val44: val44,
            val45: val45
        }
    }    
];

Via the “change” module (set msg. payload) I distribute the information to the individual OpenHAB outputs:

change module
change module

For example, such an OpenHAB Outpust is configured as follows:

OpenHAB output
OpenHAB output

Now every 30 seconds the data of the heat pump are written to the items previously created in OpenHAB.

InfluxDB & Grafana

This data can then be persisted in an Influx database and visualized via Grafana. This tutorial shows how to do this:

https://community.openhab.org/t/influxdb-grafana-persistence-and-graphing/13761

For me, for example, the result looks like this:

Grafana visualization
Grafana visualization

I hope you enjoyed the guide.