Lambda Heat Pump in OpenHab

Hello!
Since about a week my heatpump Lambda E08L is running.
I am planning to

  • read the values of the heatpump
  • send the access power provided by my PV to the E08L.
    In the short run I will try to use Modbus, in the long run this could lead to a binding.

My first steps:

Helpful was reading of this thread in the openWB-forum:
https://forum.openwb.de/viewtopic.php?t=5380

I guess I will need collaboration of users with experience with modbus and later on with github to publish a binding.

2 Likes

Just a short update:
Using the modbus binding I can now read values of my E08L and write the value of register 102 in the E-Manager section. This was the trickier part resulting in:

Modbus:poller:

UID: modbus:poller:Lambda_Bridge:LA_EMgr
label: Lambda Poll E-Manager
thingTypeUID: modbus:poller
configuration:
  start: 100
  length: 5
  refresh: 10000
  maxTries: 3
  cacheMillis: 50
  type: holding
bridgeUID: modbus:tcp:Lambda_Bridge

Modbus:data:

UID: modbus:data:LA_E-Manager:LA_EMgr_Actual_Power
label: Lambda E-Mgr Actual Power
thingTypeUID: modbus:data
configuration:
  readValueType: int16
  readTransform: JS(nullen.js)
  writeTransform: default
  writeType: holding
  readStart: "102"
  updateUnchangedValuesEveryMillis: 1000
  writeValueType: int16
  writeMultipleEvenWithSingleRegisterOrCoil: true
  writeMaxTries: 3
  writeStart: "102"
  bridgeUID: modbus:poller:Lambda_Bridge:LA_EMgr
3 Likes

I am not shure if I should try to work on an “official” extension as mentioned in:https://www.openhab.org/addons/bindings/modbus/
(E3DC, Helios, …)
because I am not shure how much work this is. Perhaps if someone volunteers to help me in the process?

Thanks a lot for sharing, Christian. Very helpful. Concerning your solution, I have some questions and for clarity, I share here my implementation via thing/item files:

thing file

Bridge modbus:tcp:lambda [ host="192.168.x.x", port=502, id=1 ] { 
    Bridge poller LA_general [ start=0, length=5, refresh=10000, type="holding" ] {
        Thing data temp [ readStart="002", readValueType="int16"] 
    }
    Bridge poller LA_EMgr [ start=100, length=5, refresh=10000, type="holding" ] {
        Thing data LA_EMgr_Actual_Power [ readStart="102", readValueType="uint16", writeStart="102", writeValueType="int16", writeType="holding"] 
        Thing data LA_EMgr_Consumption [ readStart="103", readValueType="uint16"] 
    }
    Bridge poller HeatPump [ start=1000, length=15, refresh=10000, type="holding" ] {
        Thing data COP [ readStart="1013", readValueType="int16", readTransform="JS(divide10.js)"] 
    }
    Bridge poller Buffer [ start=3000, length=4, refresh=10000, type="holding" ] {
        Thing data HiTemp [ readStart="3002", readValueType="int16", readTransform="JS(divide10.js)"] 
    }
}

item file

Number HeatPump_Temperature "Außentemperatur [%.1f °C]" (gUG) { channel="modbus:data:lambda:LA_general:temp:number" }
Number HeatPump_Actual_Power "Actual power [%.1f W]" (gUG) { channel="modbus:data:lambda:LA_EMgr:LA_EMgr_Actual_Power:number" }
Number HeatPump_Consumption "Verbrauch [%.1f W]" (gUG) { channel="modbus:data:lambda:LA_EMgr:LA_EMgr_Consumption:number" }
Number HeatPump_COP "COP [%.1f]" (gUG) { channel="modbus:data:lambda:HeatPump:COP:number" }
Number HeatPump_Buffer "Pufferspeicher [%.1f °C]" (gUG) { channel="modbus:data:lambda:Buffer:HiTemp:number" }
  • Maybe stupid question, but what is the purpose of JS(nullen.js)?
  • I get for the Actual power (#102) “32768,0” as a value. Do you just overwrite it with your current surplus PV power?

Thanks,
Jan

@Nullen.js: Somewhere (in the OpenWB-Thread ???) I found the suggestion that one should not send negative values to the heat pump. So I found a script to set the value to 0 when a negative value is set. I am not shure if that is really necessary.

@Actual Power: In my system it shows the last value I wrote to register 102 via sendcommand.
(But watching the graph I just notice that there are negative values around sunset and sunrise - I have to look into this :wink: )

I am using register 103 (Lambda E-Mgr Power Consumption) to find out the actual power usage of the heat pump.

1 Like

I got one step closer: the Lambda service can configure for you negative or positive values as excess power (see screen shot). Therefor I assume you have either the positive value setting or the nullen.js script will interfere in your communication with heat pump.

My current rule is the following - for anybody who whats to reproduce:

rule "Adjust LA_EMgr_Actual_Power based on Solar and Power conditions"
when
    Item Solar_Spot changed
then
    // Check if Solar_Spot > 500 --> wenn mehr als 500 W produziert werden
    if (Solar_Spot.state > 500) {
        // Check if Power_Supply_delta = 0 and Power_Feedin_delta > 800
        if (Power_Supply_delta.state == 0 && Power_Feedin_delta.state > 800) { //wenn seit 5 min kein Strombezug und Einspeisung >800 W
            // Calculate the negative value of Power_Feedin_delta
            val negativeFeedinDelta = -((Power_Feedin_delta.state as Number).intValue)
            // Send the negative value to LA_EMgr_Actual_Power
            HeatPump_Actual_Power.sendCommand(negativeFeedinDelta)
        }
    }
end

In your screenshot a red message “Alarm: E-Manager ungültiger Wert” appears, so something is still wrong.

When Lambda configured my Modbus-Access they configuered it to
E-Meter Messpunkt: E-Eintrag. So in my case sending positive values is appropiate:

@nullen.js: In my posted configuration above I put it in the read-part, that was wrong. You have to put it into the write-part. That seems to work: When openhab sends a negative value, the heat pump shows 0 kW.

Das Skript:

(function(inputData) {
    if(inputData < 0) return "0";
   return parseFloat(inputData) ;

Ich musste dazu als Add-on Javascript in Openhab (Installed automation Javascript scripting) ergänzen, das Skript sitzt in /etc/openhab/transform

When Item Solar_Spot changed

At what time intervals does Solar_Spot_Changed occur? The value of Heat_Pump_Actual_Power has to be written quite often - I did it with a cron job every 30 s.

Pretty often, more then every 30 sec. I see in the console log that the heat pump refuses to take the value (error 1: illegal function), so most likely it isn’t set up right in the configuration. I have reached out to the lambda support now…

I am working on a binding to add to the modbus binding. I compiled a first draft (with only 3 Channels) using the stiebelelctron-Binding.
I copied the jar to /usr/share/openhab/addons. It shows up:

321 │ Resolved │  80 │ 4.3.0.202408091312    │ openHAB Add-ons :: Bundles :: Lambda Bundle

After about two days of looking at my code I got a working bundle showing up in the Main UI and in the API.

:raised_hands: It is running now. I got my issue solved with a hint from the Lambda support (write multiple instead of single register). For reference for all, who are seeking to get a Lambda heat pump into thier openhab with text configuration files:

.thing Config

Bridge modbus:tcp:lambda [ host="192.168.xxx.xxx", port=502, id=1 ] { 
    Bridge poller LA_general [ start=0, length=5, refresh=10000, type="holding" ] {
        Thing data temp [ readStart="2", readValueType="int16",readTransform="JS(divide10.js)"] 
        Thing data temp_av [ readStart="3", readValueType="int16",readTransform="JS(divide10.js)"] 
    }
    Bridge poller LA_EMgr [ start=100, length=5, refresh=10000, type="holding" ] {
        Thing data LA_EMgr_Actual_Power [ readStart="102", readValueType="uint16", writeStart="102", writeValueType="int16", writeType="holding",writeMultipleEvenWithSingleRegisterOrCoil="true",writeTransform="default"] 
        Thing data LA_EMgr_Consumption [ readStart="103", readValueType="int16"] 
    }
    Bridge poller HeatPump [ start=1000, length=15, refresh=10000, type="holding" ] {
        Thing data COP [ readStart="1013", readValueType="int16",readTransform="JS(divide10.js)"] 
    }
    Bridge poller Buffer [ start=3000, length=4, refresh=10000, type="holding" ] {
        Thing data HiTemp [ readStart="3002", readValueType="int16",readTransform="JS(divide10.js)"] 
    }
}
  

.items file

Number HeatPump_Temperature "Außentemperatur [%.1f °C]" <temperature> (gUG) { channel="modbus:data:lambda:LA_general:temp:number" }
Number HeatPump_Temperature_Av "Außentemperatur letzte Stunde [%.1f °C]" <temperature> (gUG) { channel="modbus:data:lambda:LA_general:temp_av:number" }
Number HeatPump_Actual_Power "Actual power [%.0f W]" (gUG) { channel="modbus:data:lambda:LA_EMgr:LA_EMgr_Actual_Power:number" }
Number HeatPump_Consumption "Wärmepumpe Verbrauch [%.1f W]" (gUG) { channel="modbus:data:lambda:LA_EMgr:LA_EMgr_Consumption:number" }
Number HeatPump_COP "Wärmepumpe COP [%.1f]" (gUG) { channel="modbus:data:lambda:HeatPump:COP:number" }
Number HeatPump_Buffer "Pufferspeicher [%.1f °C]" <temperature> (gUG) { channel="modbus:data:lambda:Buffer:HiTemp:number" }

.rules

rule "Adjust LA_EMgr_Actual_Power based on Solar and Power conditions"
when
    Item Solar_Spot changed or
    System started
then
    // Check if Solar_Spot > 500 --> wenn mehr als 500 W produziert werden
    if (Solar_Spot.state > 500) {
        // Check if Power_Feedin_delta > 500
        if (Power_Feedin_delta.state > 500) { //wenn seit 5 min kein Strombezug und Einspeisung >800 W
            // Calculate the negative value of Power_Feedin_delta
            val negativeFeedinDelta = -((Power_Feedin_delta.state as Number).intValue)
            // Send the negative value to LA_EMgr_Actual_Power
            HeatPump_Actual_Power.sendCommand(negativeFeedinDelta)
        }
        else{
            HeatPump_Actual_Power.sendCommand(0)
        }
         
    } 
    else{
            HeatPump_Actual_Power.sendCommand(0)
    }
    
end

divide10.js

(function(inputData) {
    // on read: the polled number as string
    // on write: openHAB command as string
    var DIVIDE_BY = 10;
    return parseFloat(inputData) / DIVIDE_BY;
    })(input)

Thanks. So register 102 / LA_EMgr_Actual_Power is key to force (pre-)heating ?
Is there any comprehensive documentation available to explain what changes to this affect?
Do you also know of a register to make it stop heating such as on your provider’s signal (“EVU Sperre”) ? Or register to simulate the four Smart grid ready states ?

This is what the Lambda FAQ says using SG ready versus Modbus TCP. I’ve seen some using a Rhasberry Pi Zero to implement the first, but think the Modbus TCP option is the better option.

Es gibt mehrere im wesentlichen 2 Möglichkeiten wie eine intelligente Nutzung des überschüssigen Photovoltaikstroms erfolgen kann.

  1. Möglichkeit: Digitales Freigabesignal

Eine simple und einfache Möglichkeit ist die Bereitstellung eines potentialfreien Kontaktes (z.B. vom Wechselrichter oder einem Energiemanagementsystem). Unsere Steuerung verfügt standardmäßig über einen entsprechenden 24V Eingang der das Signal verarbeiten kann. Sprich sobald ein Überschuss (z.B. 2kW) vom Wechselrichter erfasst wird wird dies über einen digitalen Kontakt der Wärmepumpe mitgeteilt. Es werden weiter die Solltemperaturen für die Speicher und Heizkreise (einstellbar) erhöht und die Wärmepumpe mit einer fixen elektrischen Leistung (z.B. 2kW) betrieben.

  1. Möglichkeit: Überschusserfassung via Smartmeter

Via Smartmeter (optionales Zubehör) kann entweder die PV Leistung oder der Überschussleistung am Hausanschluss erfasst werden. Wird ein bestimmter Schwellwert (z.B. 2kW) überschritten, so wechselt die Wärmepumpe in den PV Modus. Dabei werden wiederum die Solltemperaturen in den Speichern und den Heizkreisen erhöht. Im Unterschied zur Möglichkeit 1 versucht die Wärmepumpe aber zusätzlich die vorgegebene Leistung so gut wie möglich via Varriation der Verdichterdrehzahl „abzuregeln“. Dadurch wird erreicht, dass am Einspeißepunkt möglichst wenig Energie eingespeißt aber auch bezogen werden muss.

  1. Möglichkeit: Leistungsvorgabe via Modbus TCP

Die Leistungsvorgabe unserer Wärmepumpe kann über Modbus TCP beschrieben werden. Die Funktion ist dann die selbe wie im Punkt 2. Der Überschuss wird meist über ein Energiemanagement erfasst und kann unserer Wärempumpesteuerung via Modbus TCP gesendet werden. Wichtig: Das Energiemanagementsystem fungiert als Modbus Master, die Wärmepumpensteuerung als Modbus Slave. Spich das Energiemanagementsystem muss die Werte aktiv senden.

And here is the documentation to the Modbus Protocol by Lambda. I don’t see any registers you can write to stop the heat pump

Thanks.
Does sending “0” to HeatPump_Actual_Power stop heating?

0 means it operates normal. Any access energy is used to produce more heat in advance, e.g. your buffer temperature will rise from 45°C to 50°C - so that the heat pump works less in the night or less often…

Ah, what a pity.
You can get much more savings out of a heat pump by halting it during specific times rather than forcing it to (over-)heat at cheap times, that’s why I’m so keen on that.
The modbus spec says for subindex 1, number 02 (does that mean register 102 ?) that it “depends on settings in module” if the register value is interpreted as input power or excess power. Maybe that’s a way.
Do you know which settings these are and if those can be read or written via modbus, too ?

There seem to be three different modes the Lambda support configures it. In my case they put it in
E-Meter Messpunkt: E-Eintrag
Other possibilities are: neg. E-Ăśberschuss, pos E-Ăśberschuss
These configuration options are discussed in the OpenWB-Forum.
If you have the password for user service you can change these values without asking Lambda support.
I am not sure if you can accomplish your goal using these settings.

How about another approach?
You can try to change the values of the maximum temperatures of boiler and buffer (registers 50) and the operating mode of the heating circuit (set register 06 to 0 (off) or 5 (frost)) or work with the temperatures (registers 04 and 05) of the heating circuit.