Kostal Enector Wallbox mode maintained from home assistant

Dear community,
I use the Kostal Plenticore Integration within Home Assistant and it works just perfect.
My installation does not only contain a Kostal Plenticore 8.5 Plus inverter, I do also have the Kostal Smart Energy Meter and the Kostal Enector Wallbox.

There is one piece of functionality I’m missing. The Wallbox has certain modes for loading the car battery:

  • Lock mode (e.g. to pause loading)
  • Power Mode (load with max speed, even if it from grid)
  • Solar Pure Mode (loads only the excess solar energy to the battery and does not “purhase” energy from the grid)
  • Solar Plus Mode (loads as soon as there is a certain amount of solar energy reached, and tops it up with grid power)
    (This is a quick and dirty description, there might me more details to it :slight_smile: )

The issue that I am facing now: The Kostal Smart Energy Meter is not as smart as it should be. This means they handle battery power equally as solar power in this calculation. This means if I connect the car in the evening to the wallbox, it instantly sucks emtpy my battery system in solar pure mode (as it is treated as “solar power”).

I would like to have more control about loading and e.g. set the wallbox mode to “Lock” every evening after sunset, to leave the battery system for house energy usage. Home assistant could help me to set this lock automatically and to release it the next morning as soon as there is enough excess power.
(The car is hybrid and only in use every 2-3 days and therefore it does not have to be loaded instantly it is connected.)

To set and release the lock manually each day is a big pain in the a**.

So is there any idea on how to access this enector mode via home assistant?
I already integrated the wallbox via modbus according to some tutorials - but this are all read only values and do not even cover reading the loading mode.

So I think the only way might to be via the Inverter / KSEM integration to extend it (as the mode itself can be selected on the KSEM web interface):

Thanks a lot,

Thomas

Hey Thomas,

I faced the same challenge :wink:

My final solution is now realized via the REST API that also the local webserver APP from the KOSTAL Smart Energy Meter is using.

Using a http request (with a bearer authentication) allows to do everything, that you can interactively do with the webapp.
To integrate those requests in HA you can use several ways. I choose a Node-Red solution.

  1. bearer certificat needs to be called @ http://192.168.178.161/api/web-login/token (IP of the KSME), “content type”: “application/x-www-form-urlencoded”, with payload: {“grant_type”:“password”,“client_id”:“emos”,“client_secret”:56951025,“username”:“admin”,“password”:“YOUR PASSWORD”}
    The result of these request will be the bearer token. Add to this token the “Bearer “ as a string.
  2. PUT request @ http://192.168.178.161/api/e-mobility/config/chargemode with basic bearer authentication token from 1st step, with payload: { “mode”: “pv”, “mincharginpowerquota”: 0, “minpvpowerquota”: 100 } (possible modes: Lock, grid, pv, hybrid for the four modes)
  3. GET request, with same payload, to read the current state.

I reverse engineered it by using the developer tool of chrome when using the Kostal webInterface. In the network chapter one can see the traffic between KSEM and browser. Any action is logged. Looking on each action you can identify the messages that are forced by your interaction. One can see the endpoint URL and the corresponding payload…

If you have further questions, just ask!
It was an eye opener for me, because you have now all degree of freedom. No need for the modbus interface, no need for the hardware switch (I started with)!

BR,
Lars

image

This it how it looks like!
Works like charm!

1 Like

Hello Lars,

Your solution looks very good. I’m looking for exactly the same thing to control my wallbox.
However, I am a newcomer to Node Red. Can you create a detailed documentation for rebuilding your solution or share your Nodes as JSON?
Unfortunately, I’m failing because of the HTTP requests. I always get the following message:

payload: object
error: “invalid_request”
error_description: “The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.”
statusCode: 200

Can you help me?

Thank you very much,
Philipp

Can you please share the code? That would be great

Hey!
Off course I can share the code.
Quick and dirty :wink: Hope it helps! If not raise your hands!

  1. Copy/Past the JSON into node red:
  • burger symbol in Node-Red (upper right corner)
  • import: past the copied JSON below
  • place the nodes in a new flow window
[{"id":"94936bfddddb4650","type":"http request","z":"c7120bbd05d84382","name":"http request GET","method":"GET","ret":"obj","paytoqs":"ignore","url":"http://192.168.178.161/api/e-mobility/config/chargemode","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"other","keyValue":"Authorization","valueType":"msg","valueValue":"bearer"}],"x":970,"y":260,"wires":[["20bbc142a981ef08"]]},{"id":"20bbc142a981ef08","type":"debug","z":"c7120bbd05d84382","name":"state reached","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1180,"y":260,"wires":[]},{"id":"99844a53c8d56d88","type":"http request","z":"c7120bbd05d84382","name":"http request PUT","method":"PUT","ret":"obj","paytoqs":"ignore","url":"http://192.168.178.161/api/e-mobility/config/chargemode","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"other","keyValue":"Authorization","valueType":"msg","valueValue":"bearer"}],"x":710,"y":260,"wires":[["94936bfddddb4650","49969fe6a9c3805c"]]},{"id":"735ba62bbdcdb6eb","type":"inject","z":"c7120bbd05d84382","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"00 12 * * *","once":true,"onceDelay":0.1,"topic":"","payload":"{\"grant_type\":\"password\",\"client_id\":\"emos\",\"client_secret\":56951025,\"username\":\"admin\",\"password\":\"PASSWORD\"}","payloadType":"json","x":190,"y":440,"wires":[["846f1f51841513bb"]]},{"id":"af10bfd8baaabfa5","type":"function","z":"c7120bbd05d84382","name":"global bearer String","func":"var msg1 = { bearer:\"\"}\nvar auth = \"Bearer\"\nvar bearer_kostal = msg.payload.access_token\n\n\nmsg1.bearer = auth.concat(\" \", bearer_kostal);\nglobal.set(\"Kostal_bearer\", msg1.bearer);\nreturn msg1;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":650,"y":440,"wires":[["64e91ffcb634fab7"]]},{"id":"e5cb3b11d88b2d8f","type":"function","z":"c7120bbd05d84382","name":"mode parser","func":"var msg1 = { payload: { \"mode\": 0, \"bearer\":0 } }\nvar SelectedMode = msg.payload\nvar mode\nif (SelectedMode === \"Lock Mode\") {\n    mode = '{ \"mode\": \"lock\", \"mincharginpowerquota\": 0, \"minpvpowerquota\": 100 }';\n}\nelse if (SelectedMode === \"Power Mode\") {\n    mode ='{ \"mode\": \"grid\", \"mincharginpowerquota\": 0, \"minpvpowerquota\": 100 }';\n}\nelse if (SelectedMode === \"Solar Pure Mode\") {\n    mode = '{ \"mode\": \"pv\", \"mincharginpowerquota\": 0, \"minpvpowerquota\": 100 }';\n\n}\nelse if (SelectedMode === \"Solar Plus Mode\") {\n    mode = '{ \"mode\": \"hybrid\", \"mincharginpowerquota\": 0, \"minpvpowerquota\": 100 }';\n\n}\n\nmsg1.payload = mode;\nmsg1.bearer = global.get(\"Kostal_bearer\") ;\nreturn msg1;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":260,"wires":[["99844a53c8d56d88"]]},{"id":"129b483a188d30d9","type":"trigger-state","z":"c7120bbd05d84382","name":"Wallbox PhaseUsage","server":"ba0f7c7d.deae9","version":4,"inputs":0,"outputs":3,"exposeAsEntityConfig":"","entityId":"input_select.wallbox_phaseusage","entityIdType":"exact","debugEnabled":false,"constraints":[],"customOutputs":[{"messageType":"default","messageValue":"","messageValueType":"json","comparatorPropertyType":"always","comparatorPropertyValue":"","comparatorType":"is","comparatorValue":"","comparatorValueDataType":"str"}],"outputInitially":false,"stateType":"str","enableInput":false,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"x":200,"y":360,"wires":[["07116615698274ec"],[],[]]},{"id":"07116615698274ec","type":"function","z":"c7120bbd05d84382","name":"mode parser","func":"var msg1 = { payload: { \"mode\": 0, \"bearer\":0 } }\nvar SelectedMode = msg.payload\nvar mode\nif (SelectedMode === \"3 phasig\") {\n    mode = '{\"phase_usage\":0}';\n}\nelse if (SelectedMode === \"1 phasig\") {\n     mode = '{\"phase_usage\":1}';\n}\n\nmsg1.payload = mode;\nmsg1.bearer = global.get(\"Kostal_bearer\") ;\nreturn msg1;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":360,"wires":[["552dd6fe4113b4eb"]]},{"id":"ced1ae3f51a47cfc","type":"debug","z":"c7120bbd05d84382","name":"state reached","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1180,"y":360,"wires":[]},{"id":"552dd6fe4113b4eb","type":"http request","z":"c7120bbd05d84382","name":"http request PUT","method":"PUT","ret":"obj","paytoqs":"ignore","url":"http://192.168.178.161/api/e-mobility/phaseusage","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"other","keyValue":"Authorization","valueType":"msg","valueValue":"bearer"}],"x":710,"y":360,"wires":[["c13dd19967cd7b74"]]},{"id":"c13dd19967cd7b74","type":"http request","z":"c7120bbd05d84382","name":"http request GET","method":"GET","ret":"obj","paytoqs":"ignore","url":"http://192.168.178.161/api/e-mobility/phaseusage","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"bearer","senderr":false,"headers":[{"keyType":"other","keyValue":"Authorization","valueType":"msg","valueValue":"bearer"}],"x":970,"y":360,"wires":[["ced1ae3f51a47cfc"]]},{"id":"49969fe6a9c3805c","type":"debug","z":"c7120bbd05d84382","name":"state reached","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1096.7652587890625,"y":148.5565185546875,"wires":[]},{"id":"18eac1025038a0e4","type":"http request","z":"c7120bbd05d84382","name":"http request GET","method":"GET","ret":"obj","paytoqs":"ignore","url":"http://192.168.178.161/api/kostal-energyflow/configuration/batteryusage","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"other","keyValue":"Authorization","valueType":"msg","valueValue":"bearer"}],"x":970,"y":560,"wires":[["a495f79658f60b16"]]},{"id":"a495f79658f60b16","type":"debug","z":"c7120bbd05d84382","name":"state reached","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1180,"y":560,"wires":[]},{"id":"a4d6e0cae28be6cf","type":"http request","z":"c7120bbd05d84382","name":"http request PUT","method":"PUT","ret":"obj","paytoqs":"ignore","url":"http://192.168.178.161/api/kostal-energyflow/configuration/batteryusage","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"other","keyValue":"Authorization","valueType":"msg","valueValue":"bearer"}],"x":710,"y":560,"wires":[["18eac1025038a0e4","93e605fef2ef9f16"]]},{"id":"9212201553e219f7","type":"trigger-state","z":"c7120bbd05d84382","name":"Wallbox BatteryChargeMode","server":"ba0f7c7d.deae9","version":4,"inputs":0,"outputs":3,"exposeAsEntityConfig":"","entityId":"input_select.wallbox_batterychargemode","entityIdType":"exact","debugEnabled":false,"constraints":[],"customOutputs":[{"messageType":"default","messageValue":"","messageValueType":"json","comparatorPropertyType":"always","comparatorPropertyValue":"","comparatorType":"is","comparatorValue":"","comparatorValueDataType":"str"}],"outputInitially":false,"stateType":"str","enableInput":false,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"x":220,"y":560,"wires":[["c85146218b4d714b"],[],[]]},{"id":"c85146218b4d714b","type":"function","z":"c7120bbd05d84382","name":"mode parser","func":"var msg1 = { payload: { \"mode\": 0, \"bearer\":0 } }\nvar SelectedMode = msg.payload\nvar mode\nif (SelectedMode === \"Hausbatterie nutzen\") {\n    mode = \"true\";\n}\nelse if (SelectedMode === \"Hausbatterie nicht nutzen\") {\n    mode = \"false\";\n}\n\n\nmsg1.payload = mode;\nmsg1.bearer = global.get(\"Kostal_bearer\") ;\nreturn msg1;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":560,"wires":[["a4d6e0cae28be6cf","9cfd60b22e4fa216"]]},{"id":"9cfd60b22e4fa216","type":"debug","z":"c7120bbd05d84382","name":"state reached","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":660,"y":660,"wires":[]},{"id":"93e605fef2ef9f16","type":"debug","z":"c7120bbd05d84382","name":"state reached","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1000,"y":640,"wires":[]},{"id":"64e91ffcb634fab7","type":"debug","z":"c7120bbd05d84382","name":"state reached","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":858.9674072265625,"y":438.016357421875,"wires":[]},{"id":"4c3b2a1059f43b65","type":"debug","z":"c7120bbd05d84382","name":"state reached","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":660,"y":500,"wires":[]},{"id":"846f1f51841513bb","type":"http request","z":"c7120bbd05d84382","name":"","method":"POST","ret":"obj","paytoqs":"ignore","url":"http://192.168.178.161/api/web-login/token","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"other","keyValue":"content-type","valueType":"other","valueValue":"application/x-www-form-urlencoded"}],"x":450,"y":440,"wires":[["af10bfd8baaabfa5","4c3b2a1059f43b65"]]},{"id":"67bc08a33b571706","type":"trigger-state","z":"c7120bbd05d84382","name":"Wallbox ActiveChargeMode","server":"ba0f7c7d.deae9","version":4,"inputs":0,"outputs":3,"exposeAsEntityConfig":"","entityId":"input_select.wallbox_activechargemode","entityIdType":"exact","debugEnabled":false,"constraints":[],"customOutputs":[{"messageType":"default","messageValue":"","messageValueType":"json","comparatorPropertyType":"always","comparatorPropertyValue":"","comparatorType":"is","comparatorValue":"","comparatorValueDataType":"str"}],"outputInitially":false,"stateType":"str","enableInput":false,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"x":220,"y":260,"wires":[["e5cb3b11d88b2d8f"],[],[]]},{"id":"ba0f7c7d.deae9","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]
  1. Implement the helpers within HomeAssistant:
  • Settings/Helper → Create Helper → i
  • name, configure the 3 helpers like shown in the pictures
  • Input_select, type dropdown
  • EXACTLY the same :wink:

  1. Configure Node-RED flow:
    3.1 inject Node - Password to web app
  • Open the inject Node and add your personal password in the payload. (Password of the (local) KSEM Websit)

{“grant_type”:“password”,“client_id”:“emos”,“client_secret”:56951025,“username”:“admin”,“password”:“PLACE YOUR PASSWORD HERE”}

3.2 Update IP adress to KMSE

  1. Deploy and test

Thank you for sharing your solution. Works like charm!
The password I used is the login Password of the (local) KSEM Website, not for the password of the Kostal app.

1 Like

Thank you its working fine.

Do you know how to implement also the Start / Pause button?

Sometimes the Wallbox is in pause and i cant start without pushing the button in webinterface.

Thanks in advance

1 Like

Ah, yes good remark! Changed it in the text! Lars

Could you share a Screenshot of the corresponding Web Site?

Here you can see the “pause” symbole which you can push

Hey,

could you also share the corresponding Screen off the local Website? If you find the Pause function I can help!

I don’t use the webApp at all.

Lars

When a car connected you fond it on the first page