EMS-ESP gateway configuration for Nefit/Buderus/Junkers/Bosch boilers

Hi there,

My first post as newbie to the OpenHab community.
I am running Openhab2 on an RPI3 for a year now, building light, blinds, alarms, doors and recently heating projects.

Since this community has helped me so much in understanding and building my own Openhab home automation, I want to share with you my cool project on controlling a Nefit/Buderus/Junkers/Bosch boiler using an EMS-ESP gateway device and mqtt.

I started the project to save energy by limiting my floor heating pump activity only during active heating (instead of 24x7). An EMS-ESP gateway device allowed me to also read useful boiler metrics and remotely control my thermostat using the EMS bus standards.

I enabled the following functions using Openhab UI and automation rules:

  1. Read and show boiler metrics (warm water, heating, shower)
  2. Read/Set thermostat (sync current room temp, set room temp, set manual/auto mode)
  3. Scheduled activation of floor heating pump (daily intervals and triggered when central heating switches on/off)

Openhab UI:

I have set-up the project using the following configuration:

  1. Nefit Trendline boiler with Moduline-300 thermostat (can be any combination supporting EMS bus protocols)
  2. EMS-ESP gateway device (build yourself with ESP8266 or buy from bbqkees-electronics.nl with proddy firmware)
  3. PowerPlug switch (Mine is a KaKu/Trust; could be any Wifi/433Mhz/Zwave powerplug)
  4. Local openhab2 mqtt broker (moquette)
  5. Things file (mqtt topics)
  6. Items file
  7. Sitemap file
  8. Rules file (control floorpump and thermostat mode)

You can use MQTT-explorer (client) to test and explore other useful mqtt topics.
Below the configuration files. Plz check other posts for enabling Openahb2 local mqtt broker.

Please forgive my formatting; this is my first post.
Have fun (surely I did :wink: !


Bridge mqtt:systemBroker:embedded-mqtt-broker "Embedded MQTT broker" [ host="", secure=false ]
   Thing mqtt:topic:ems-esp "Nefit Proline"  @ "boven" {
   Type string : status "Nefit EMS Status" [ stateTopic="ems-esp/status", on="online", off="offline" ]
   Type switch : tapwater_active "Tapwater active" [ stateTopic="ems-esp/tapwater_active", on="1", off="0" ]
	Type switch : heating_active "Heating active" [ stateTopic="ems-esp/heating_active", on="1", off="0" ]
	//Channels for thermostat topics
	Type number : hc1_seltemp "Mod300 HC1 selected temp" [stateTopic="ems-esp/thermostat_data", transformationPattern="JSONPATH:$.hc1.seltemp" ]
	Type number : hc1_currtemp "Mod300 HC1 current temp" [stateTopic="ems-esp/thermostat_data", transformationPattern="JSONPATH:$.hc1.currtemp" ]
	Type string : hc1_mode "Mod300 HC1 mode" [stateTopic="ems-esp/thermostat_data", transformationPattern="JSONPATH:$.hc1.mode" ]
	Type number : thermostat_cmd_temp "Thermostat setpoint temp" [commandTopic="ems-esp/thermostat_cmd_temp" ]
   Type switch : thermostat_cmd_mode "Thermostat mode" [commandTopic="ems-esp/thermostat_cmd_mode", on="auto", off="manual" ]
	//Channels for boiler parameters (read state)
	Type switch : burnGas "Gas burner status" [ stateTopic="ems-esp/boiler_data", transformationPattern="JSONPATH:$.burnGas", on="on", off="off" ]
	Type switch : wWHeat "wWHeatValve status" [ stateTopic="ems-esp/boiler_data", transformationPattern="JSONPATH:$.wWHeat", on="on", off="off"  ]
	Type switch : heatPmp "HeatPump status" [ stateTopic="ems-esp/boiler_data", transformationPattern="JSONPATH:$.heatPmp", on="on", off="off"  ]
   Type number : wWcurFlow "Warm Water Flow volume (l/min)" [stateTopic="ems-esp/boiler_data", transformationPattern="JSONPATH:$.wWCurFlow" ]
   Type number : curFlowTemp "Warm Water Flow temp" [stateTopic="ems-esp/boiler_data", transformationPattern="JSONPATH:$.curFlowTemp" ]
   Type number : sysPress "Verwarming druk" [stateTopic="ems-esp/boiler_data", transformationPattern="JSONPATH:$.sysPress" ]
    //Channels for shower (timer)
   Type string : shower_duration "Shower Duration" [stateTopic="ems-esp/shower_data", transformationPattern="JSONPATH:$.duration" ]
   //Channels for mqtt generic command topics
	Type switch : shower_coldshot "Coldshot" [commandTopic="ems-esp/generic_cmd", on="shower_coldshot", off="" ]


//Nefit Moduline 300 Thermostat items: temp set by thermostat (hc1 group) or EMS bus mqtt (command_temp)
Number Kamer_temp_setpoint  "Thermostaat set temp [%.1f °C]"   <moduline300>     (GrpV1,GrpHeating)         { channel="mqtt:topic:ems-esp:hc1_seltemp", channel="mqtt:topic:ems-esp:thermostat_cmd_temp" }
Number Kamer_temp           "Kamer temperatuur [%.1f °C]"	<temperature>     (GrpV1,GrpHeating)         { channel="mqtt:topic:ems-esp:hc1_currtemp"}
Switch Thermostat_mode_switch "Thermostaat mode switch"	 <moduline300>     (GrpV1,GrpHeating)         { channel="mqtt:topic:ems-esp:thermostat_cmd_mode"}
String Thermostat_mode      "Thermostaat mode [%s]"	<moduline300>     (GrpV1,GrpHeating)         { channel="mqtt:topic:ems-esp:hc1_mode"}
//Nefit boiler items
Switch Tapwater_active   "Warm tapwater [%s]"	<hotwater>         (GrpV1,GrpHeating)         { channel="mqtt:topic:ems-esp:tapwater_active"}
Switch HeatPump          "Boilerpomp [%s]"	<humidity>      (GrpV1,GrpHeating)         { channel="mqtt:topic:ems-esp:heatPmp"}
Switch BurnGas           "Gasbrander [%s]"	<fire>          (GrpV1,GrpHeating)         { channel="mqtt:topic:ems-esp:burnGas"}
Switch WWheat_valve      "WW / CV klep [%s]"	<softener>      (GrpV1,GrpHeating)         { channel="mqtt:topic:ems-esp:wWHeat"}
Number WWflow_volume     "Warm water flow volume [%.1f l/m]"  <hotwater>         (GrpV1,GrpHeating)         { channel="mqtt:topic:ems-esp:wWcurFlow"}
Number WWflow_temp       "Warm water flow temp [%.1f °C]"  <hotwater>         (GrpV1,GrpHeating)         { channel="mqtt:topic:ems-esp:curFlowTemp"}
Number Heating_pressure   "CV druk [%.1f bar]"		<humidity>      (GrpV1,GrpHeating)         { channel="mqtt:topic:ems-esp:sysPress"}
//Control items
String Douche_timer   "Douche timer [%s]"			<time>            (GrpV1,GrpHeating)         { channel="mqtt:topic:ems-esp:shower_duration"}
Switch Coldshot       "Coldshot"				<hotwater>        (GrpV1,GrpHeating)         { channel="mqtt:topic:ems-esp:shower_coldshot", expire="2s, state=OFF"}
Switch Vloerpomp      "Vloerverwarming pomp [%s]"	          	<pump>	          (GrpV1,GrpHeating)	        { lightwaverf="room=6,device=1,type=SWITCH" }


Group item=GrpHeating icon="heating" {
  Frame label="Thermostaat"
    //Note: Thermostat_mode_switch auto synced by Heating rule
    Setpoint item=Kamer_temp_setpoint minValue=15 maxValue=25 step=0.5
    Switch item=Thermostat_mode_switch label="Thermostaat mode[]" mappings=[ON="Auto", OFF="Manual"]
    Text item=Kamer_temp
    //Text item=Thermostat_set_temp
  Frame label="Boiler status"
    Switch item=Tapwater_active
    Switch item=HeatPump
    Switch item=WWheat_valve label="Warm water / CV klep[]"  mappings=[ON="WW", OFF="CV"]
    Switch item=BurnGas
  Frame label="Verwarming status"
    Switch item=Vloerpomp
    Text item=Heating_pressure
    Text item=WWflow_volume
    Text item=WWflow_temp
  Frame label="Douche status"
    Text item=Douche_timer
    Switch item=Coldshot


// ----------------------------------------------------------------------------------------------------
// Initialize values
// ----------------------------------------------------------------------------------------------------
var String RuleName = "Trigger_Heating"
var FloorPumpTimer = null
var PumpRunTime = 3 //minutes

// ----------------------------------------------------------------------------------------------------
// Daily start/stop Floorheating pump to prevent pump locking up
// ----------------------------------------------------------------------------------------------------
rule "Heating: Daily Run FloorHeatingPump"
// Enable FloorHeatingPump for 3 minutes daily at 23:55
//    Time cron "0 55 23 ? * * *"
    Time cron "0 0 0/12 1/1 * ? *" // every 12 hours
		logInfo (RuleName, "FloorHeatingPump scheduled switched ON at {}. WW valve status = {}.", LocalDateTime.now , WWheat_valve.state)
		if (FloorPumpTimer === null) {
			FloorPumpTimer = createTimer(now.plusMinutes(PumpRunTime)) [|
					if (WWheat_valve.state == ON) {
						//Valve set to Warm Water (not CV): safe to turn off Pump
						sendCommand(Vloerpomp, "OFF")
						logInfo (RuleName, "FloorHeatingPump scheduled switched OFF after {} minutes. WW valve status = {}.", PumpRunTime, WWheat_valve.state)
					} else {
						//Valve set to CV, so CV pump is active: do not turn off FloorHeatingPump
						logInfo (RuleName, "FloorHeatingPump scheduled switched OFF ignored. WW valve status = {}.", WWheat_valve.state)
					FloorPumpTimer = null

// ----------------------------------------------------------------------------------------------------
// Trigger rule to automatically switch Floor Heatpump
// ----------------------------------------------------------------------------------------------------

rule "Heating: FloorHeatingPump trigger ON/OFF by Boiler Gas and Heatpump activity"
  		Item HeatPump changed
		// Check if HeatPump is on while WW valve is set to CV (OFF). If so, activate Floor Heatpump
		if ( HeatPump.state == ON) {
				if ( WWheat_valve.state == OFF) {
					//Heatpump changed to ON while valve set to CV
					logInfo (RuleName, "Floorpump state changed to {}", Vloerpomp.state)
				} else {
					//Heatpump changed to ON while valve set to WW
		} else {
			//Heatpump changed to OFF
			if ( WWheat_valve.state == OFF) {
				//BurnGas changed to OFF while valve set to CV
				logInfo (RuleName, "Floorpump state changed to {}", Vloerpomp.state)

// ----------------------------------------------------------------------------------------------------
// Trigger rule to sync Thermostat mode switch on UI when Thermostat_mode changed on Thermostat device
// ----------------------------------------------------------------------------------------------------

rule "Heating: Thermostat device sync manual-auto mode with sitemap UI"
		Item Thermostat_mode changed
		if (Thermostat_mode.state == "auto")   { Thermostat_mode_switch.postUpdate("ON")  }
		if (Thermostat_mode.state == "manual") { Thermostat_mode_switch.postUpdate("OFF")	}

Hi Erwin

Thankyou very much for sharing your project, it has been very helpful for getting my ems-esp gateway up and running.

Only a part of your item files is accessible because the right vertical slider is missing. If possible Is this something you can look into?

My setup is a bit different, because I have a BOSCH HT3 and FW100 thermostat, but I am using your item, things, sitemap file as inspiration (And learning a lot, besides mqtt😊).



Hi Per,

Good to see my configs are helpful to you.
The items file has no more lines to show; these were all that were relevant to me to build the sitemap.

Additional mqtt topics (burn power, pump modulation etc.) are on github:

You can link these in things file to additional channels in the same way using stateTopic and commandTopic references.
I am still working on the shower coldshot; currently doesn’t seem to work with my Nefit boiler.


Thank you, for your quick reply and input!

Continuing the discussion from EMS-ESP gateway configuration for Nefit/Buderus/Junkers/Bosch boilers:

Hi all,

Short update on the project.

Given these cold winter days I wanted to tweak my Nefit condensing boiler for maximum efficiency and minimum energy usage. For this I extended Openhab with energy metering data and persisted room temperatures, gas and heating water temperatures.
Goal is to reduce peaks in heating water temperatures (lower return water temperature implies more energy reuse) while still reaching target room temperature in acceptable time.

Project Add-ons:
1 - Enabled Openhab2 DSMR smart meter binding
2 - Connected a P1-USB cable from Smart Meter serial port to RPI (make sure to check protocol and connector compatibility)
3 - Added items for smart metering: gas and electricity usage
4 - Added 3 persistence groups for temperature, warm water, gas items
5 - Enabled rr4jd persistence for mentioned groups

Below charts show correlation between gas usage, heating water temperatures and room temperatures.

Hi Erwin,

You had done great job. I have similar setup, and evreything went good to up until I wanted to set a thermostat temperature. It doesnt work.

First of all I need to understand this variable:


I just cant find it on wiki page of the ems esp. I dont get any error from openhab when I use it but temperature after few seconds is going back to what was set on thermostat earlier.

Hi Przemek,

Nice to see it is working for you as well.
I think there is a timing issue when you change the thermostat temperature.

I’ve created a single Number item Kamer_temp_setpoint with links to two MQTT channels: hc1_seltemp and thermostat_cmd_temp

This is because both your OH setpoint and your Nefit thermostat device must be able to set a new temp (command) and get updated from a change (state) by EMS bus/MQTT.

  • With the first channel (state) the boiler tells via EMS bus/MQTT regularly to OH which is the current set temp. It is updated either by OH via MQTT command/EMS gateway (thermostat_cmd_temp) or by your thermostat device via EMS bus.
  • The second channel (command) tells your boiler via MQTT/EMS gateway to change to the new temp that you set via OH setpoint.

After OH has sent the MQTT command to set new temp, it takes some seconds until hc1_seltemp is updated. The OH item Kamer_temp_setpoint may shortly after be reset to the former temp sent by the hc1_seltemp MQTT state message.

I think you can fix your issue like this:

  1. Only link the command channel (thermostat_cmd_temp) to the item.

To allow OH sitemap to also update temp. when you change it using yur thermostat device:
2. Create a new number item for hc1_seltemp
3. Create a rule that updates the Number item thermostat_cmd_temp only when the state of item hc1_seltemp changes.

Hope this helps.