This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Control Nefit boiler
#1
I like to control a Nefit boiler that has an EMS protocol. Its not possible to control it directly so i inserted an EMS-ESP into my system.

Now i can get data from my system with this script
Code:
--[[
Nefit heat pump ems bus
https://bbqkees-electronics.nl/wiki/gateway/restful-api.html
https://docs.emsesp.org/Commands/
ems-esp/boiler                                        {"cmd":"heatingactivated", "data":"on"}        turn on heatingactivated in boiler
ems-esp/boiler/heatingactivated        {"data":"on"}                                                            turn on heatingactivated in boiler (equivalent to command above)
ems-esp/boiler                                        {"cmd":"dhw.disinfecting", "data":"on"}        turn on DHW disinfecting in boiler
--]]

https = require('ssl.https')
json = require('json')
ltn12 = require('ltn12')

iDebug = true
devIp = '192.168.x.xx' -- ems-esp.local
devUrl = 'http://'..devIp..'/api/'

function getData(iFunction)
  if iDebug then log(devUrl..iFunction) end
  res, code = https.request({
      url = devUrl..iFunction,
      method = 'GET'
  })
  if iDebug then
      log(code, res)
  end
  return code, res
end

function setData(iFunction, iData)
  if iDebug then log(devUrl..iFunction) end
  res, code = https.request({
      url = devUrl..iFunction,
      method = 'POST',
      headers = {["content-type"] = "application/json"},
      data = iData
      })
  if iDebug then
      log(code, res)
  end
  return code, res
end

-- get system info
--getData('system')

-- get boiler info - GET outputs current EMS device information in verbose
--getData('boiler/info')

-- get boiler values - GET outputs current EMS device information in short format
--getData('boiler/values')

-- get boiler - GET    same as values above
--getData('boiler')

-- get boiler commands - GET    lists the available command entities to call
--getData('boiler/commands')

-- get boiler entities -     GET    lists all enabled entities
--getData('boiler/entities')

-- get boiler dhw info
--getData('boiler/dhw/info')

-- get boiler entity heatingactive
--getData('boiler/heatingactive')

-- thermostaat streeftemperatuur
--getData('thermostat/seltemp')

-- dhw Laden
--getData('thermostat/dhw/charge')
setData('thermostat/dhw/charge', '{"value": true}') --curl -X POST http:///api/system/dhw/charge -H "Content-Type: application/json" -d '{"value": true}'

I also like to control the data with the setData function (last line). But i received an error 400. Whats wrong with my code?

Documentation can be found here: https://docs.emsesp.org/Commands/
Reply
#2
You are missing Content-Length header for the POST request.
Code:
["Content-Length"] = #iData,

You should use json.encode instead of writing JSON manually to avoid potential errors.
Reply
#3
(26.09.2025, 12:58)admin Wrote: You are missing Content-Length header for the POST request.
Code:
["Content-Length"] = #iData,

You should use json.encode instead of writing JSON manually to avoid potential errors.

Like this (but with same error)?
Code:
setData('thermostat/dhw/charge', {value = true})


function setData(iFunction, iData)
  if iDebug then log(devUrl..iFunction) end
  res, code = https.request({
      url = devUrl..iFunction,
      method = 'POST',
      headers = {["Content-Type"] = "application/json",
                           ["Content-Length"] = #iData
                          },
      data = json.encode(iData)
      })
  if iDebug then
      log(code, res)
  end
  return code, res
end
Reply
#4
Try this:
Code:
setData('thermostat/dhw/charge', {value = true})

function setData(iFunction, iData)
  local data = json.encode(iData)
  if iDebug then log(devUrl..iFunction) end
  res, code = https.request({
    url = devUrl..iFunction,
    method = 'POST',
    headers = {
      ["Content-Type"] = "application/json",
      ["Content-Length"] = #data
    },
    data = data
  })
  if iDebug then log(code, res) end
  return code, res
end
Reply
#5
(26.09.2025, 13:13)admin Wrote: Try this:
Code:
setData('thermostat/dhw/charge', {value = true})

function setData(iFunction, iData)
  local data = json.encode(iData)
  if iDebug then log(devUrl..iFunction) end
  res, code = https.request({
    url = devUrl..iFunction,
    method = 'POST',
    headers = {
      ["Content-Type"] = "application/json",
      ["Content-Length"] = #data
    },
    data = data
  })
  if iDebug then log(code, res) end
  return code, res
end

Other error:
* arg: 1
  * string: closed
* arg: 2
  * nil
Reply
#6
Are you sure that URL endpoint and parameters are correct?
Reply
#7
(26.09.2025, 13:27)admin Wrote: Are you sure that URL endpoint and parameters are correct?

getData for that endpoint works and the result is:
* arg: 1
  * number: 200
* arg: 2
  * string: {"name":"charge","fullname":"dhw Laden","circuit":"dhw","bool":false,"index":0,"value":"uit","type":"boolean","readable":true,"writeable":true,"visible":true}
Reply
#8
Send a request to http://<hostname>/api/<device>/commands to get a list of available commands. Do you have access token enabled in Security->Manage Users?
Reply
#9
(26.09.2025, 13:39)admin Wrote: Send a request to http://<hostname>/api/<device>/commands to get a list of available commands. Do you have access token enabled in Security->Manage Users?

Access token is disabled

In the output i need the command:  ,"dhw[n].charge":"Laden"

Output:
{"info":"lijst van alle waardes","values":"list all values","commands":"lijst van alle commando's","entities":"lijst van alle entiteiten","[hc<n>.]boost":"boost mode","[hc<n>.]boosttime":"boost time","[hc<n>.]comforttemp":"Comforttemperatuur","[hc<n>.]control":"Afstandsbedieding","[hc<n>.]controlmode":"Comtrolemodus","[hc<n>.]cooloffdelay":"cooling off delay","[hc<n>.]coolondelay":"cooling on delay","[hc<n>.]coolstart":"cooling starttemp","[hc<n>.]cooltemp":"Temperatuur koelbedrijf","[hc<n>.]designtemp":"Ontwerptemperatuur","[hc<n>.]dewoffset":"Offset dauwpunt","[hc<n>.]dhwprio":"Prioriteit warm water","[hc<n>.]ecotemp":"Temperatuur eco","[hc<n>.]fastheatup":"Snel opwarmen","[hc<n>.]heatingtype":"Verwarmingstype","[hc<n>.]heatoffdelay":"heat-off delay","[hc<n>.]heatondelay":"heat-on delay","[hc<n>.]hpcooling":"WP koelbedrijf","[hc<n>.]hpminflowtemp":"Minimale aanvoertemperatuur WP","[hc<n>.]hpmode":"Modus warmtepomp","[hc<n>.]hpoperatingmode":"Bedrijfsmodus warmtepomp","[hc<n>.]instantstart":"instant start","[hc<n>.]intoffset":"Offset interne temperatuur","[hc<n>.]manualtemp":"Temperatuur handmatig","[hc<n>.]maxflowtemp":"Maximale aanvoertemperatuur","[hc<n>.]minflowtemp":"Minimale aanvoertemperatuur","[hc<n>.]mode":"Modus","[hc<n>.]nofrostmode":"Vorstbeveiligingsmodus","[hc<n>.]nofrosttemp":"Temperatuur vorstbeveiliging","[hc<n>.]noreducetemp":"Reduceermodus onderbreken onder","[hc<n>.]offsettemp":"Temperatuur offset","[hc<n>.]program":"Programma","[hc<n>.]redthreshold":"reduction threshold","[hc<n>.]reducemode":"Gereduceerde modus","[hc<n>.]reducetemp":"Onderste afschakeltemperatuur","[hc<n>.]remotehum":"room humidity from remote","[hc<n>.]remotetemp":"Ruimtetemperatuur van afstandsbediening","[hc<n>.]roominflfactor":"Factor ruimteinvloed","[hc<n>.]roominfluence":"Ruimteinvloed","[hc<n>.]roomtempdiff":"Verschiltemperatuur kamertemp","[hc<n>.]seltemp":"Streeftemperatuur kamer","[hc<n>.]solarinfl":"solar influence","[hc<n>.]summersetmode":"Instelling zomerbedrijf","[hc<n>.]summertemp":"Zomertemperatuur","[hc<n>.]switchonoptimization":"Inschakeloptimalisering","[hc<n>.]switchprogmode":"switch program mode","[hc<n>.]tempautotemp":"Streeftemperatuur automodus tijdelijk","absent":"absent","building":"Type gebouw","damping":"Demping buitentemperatuur","datetime":"Datum/Tijd","delayboiler":"Vertragingsoptie","dhw[n].charge":"Laden","dhw[n].chargeduration":"Laadtijd","dhw[n].circmode":"Modus circulatiepomp","dhw[n].dailyheating":"Dagelijks opwarmen","dhw[n].dailyheattime":"Tijd dagelijkse opwarming","dhw[n].disinfectday":"Desinfectiedag","dhw[n].disinfecting":"Desinfectie","dhw[n].disinfecttime":"Desinfectietijd","dhw[n].mode":"Modus","dhw[n].settemp":"Streeftemperatuut","dhw[n].settemplow":"Onderste streeftemperatuur","electricfactor":"Energiefactor electrisch","energycostratio":"Energiekostenratio","fossilefactor":"Energiefactor fossiele brandstof","hybridstrategy":"Hybride strategie","intoffset":"Offset interne temperatuur","minexttemp":"Min. buitentemperatuur","pvenabledhw":"Verhoging WW activeren","pvlowercool":"Verlagen koeling met PV activeren","pvraiseheat":"Verwarmen met PV activeren","solar":"solar","switchovertemp":"Schakeltemperatuur buitentemperatuur","tempdiffboiler":"Verschiltemperatuuroptie"}
Reply
#10
Try sending true instead of {value = true}. If this does not help then you should ask this question here: https://github.com/emsesp/EMS-ESP32/discussions
Reply
#11
Fyi: Theben has an Opentherm to KNX gateway and there is an Opentherm to EMS converter. I have this setup and it works very well.
Reply
#12
(26.09.2025, 21:00)maxmp Wrote: Fyi: Theben has an Opentherm to KNX gateway and there is an Opentherm to EMS converter. I have this setup and it works very well.

Which Openterm to EMS converter do you use?

And can you control the DHW charge? (Extra warm water function)
Reply


Forum Jump: