EV charging scheduling solution with solar power and a home battery

You’ll need some basic understanding of a logic in order to automate things. With node red you can visualise a lot of things, which makes it more easy.
As an alternative you can use a custom integration using HACS, for example: GitHub - jonasbkarlsson/ev_smart_charging: Electric vehicle smart charging for Home Assistant.

I do not control the battery directly. The inverter controls the battery. I use the battery level (SOC%) to trigger an automation, for example. If the battery soc% is >40% it is ok to charge, stop if it is below 20%.
It is the charger and/or car which determins if it is actally charging.
To carify: I have a number of conditions which could trigger a flag (= a toggle entity helper) which tells if it ok to start charging or not. These conditions could be: home battery level, electricity price, solar power, …
But it’s the charger and the car which decides if the charging actually starts based on their individual settings

Your EV charging solutions is very interesting and exactly what I’m looking for.
My situation is very similar, GoodWe inverter with BYD battery, and EV which I want to charge according the Belpex hour tariffs and solar production.
I just started HA one week ago, so everything is still “chinees voor mij”, but I’m really jealous about your screenshots from your user interface because that’s exactly what I have in mind.

This is what I use to get everything running:

  • HACS
  • DSMR Slimme meter
  • ENTSO-e Transparency platform
  • GoodWe Inverter
  • Node-Red companion
  • Node-Red Add on
  • Nord Pool
  • Wallbox
  • nordpool_diff (= the core of the automation)

I’ve had a few tweeks the past year and this is how it looks like at the moment:

My main strategy:

  • During winter I run in Automatic mode, mainly switching off the 6 hour interval during the weekend.
  • From April to October just turn on “charge from battery only”
  • During high summer I often turn on “only charge when the battery is full”

The main automation sequence in node-red looks like this:

code:

[{"id":"3e69cdaf73117960","type":"tab","label":"Charge on logic","disabled":false,"info":"","env":[]},{"id":"640730e15ac8308f","type":"api-current-state","z":"3e69cdaf73117960","name":"","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.charge_at_night_schedule","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":310,"y":420,"wires":[["d5e983d821b83bad"],["37fe8108339c41c4","8adb93a631a3cbe8","31ce5a6452e8a6a6"]]},{"id":"d5e983d821b83bad","type":"time-range-switch","z":"3e69cdaf73117960","name":"19:00-07:00","lat":"51.16054","lon":"4.6485","startTime":"19:01","endTime":"07:01","startOffset":0,"endOffset":0,"x":690,"y":420,"wires":[["37fe8108339c41c4","8adb93a631a3cbe8","31ce5a6452e8a6a6"],["84266b72acf4a5db"]]},{"id":"31ce5a6452e8a6a6","type":"api-current-state","z":"3e69cdaf73117960","name":"","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.only_charge_with_full_battery","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":300,"y":740,"wires":[["9b24b931347d780c"],[]]},{"id":"9b24b931347d780c","type":"api-current-state","z":"3e69cdaf73117960","name":"Battery >=96%","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"96","halt_if_type":"num","halt_if_compare":"gte","entity_id":"sensor.average_battery_state_of_charge","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"on","valueType":"str"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":680,"y":720,"wires":[["c53bebd0c6bc9449"],[]]},{"id":"2be8becef398085f","type":"api-call-service","z":"3e69cdaf73117960","name":"Charge on","server":"f610b696.ce7818","version":5,"debugenabled":false,"domain":"input_boolean","service":"turn_on","areaId":[],"deviceId":[],"entityId":["input_boolean.charge"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1190,"y":780,"wires":[["c0b5d5d30dfbbd83"]]},{"id":"615e4fcebe049208","type":"api-current-state","z":"3e69cdaf73117960","name":"","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.charge_when_connected","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":320,"y":180,"wires":[["a34d2937afd18c16"],["1fe065c1dc9850df"]]},{"id":"a34d2937afd18c16","type":"api-current-state","z":"3e69cdaf73117960","name":"Wallbox Unavailable?","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"Unavailable","halt_if_type":"str","halt_if_compare":"is","entity_id":"switch.wallbox_portal_pause_resume","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"on","valueType":"str"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":680,"y":180,"wires":[[],["40fb6d6ab472f564"]]},{"id":"40fb6d6ab472f564","type":"api-call-service","z":"3e69cdaf73117960","name":"Charge on","server":"f610b696.ce7818","version":5,"debugenabled":false,"domain":"input_boolean","service":"turn_on","areaId":[],"deviceId":[],"entityId":["input_boolean.charge"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":910,"y":180,"wires":[["c0b5d5d30dfbbd83"]]},{"id":"37fe8108339c41c4","type":"api-current-state","z":"3e69cdaf73117960","name":"","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.charge_long_interval","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":290,"y":580,"wires":[["316fff4bc9f3f0ba"],[]]},{"id":"316fff4bc9f3f0ba","type":"api-current-state","z":"3e69cdaf73117960","name":"Interval 20 > 0.5?","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"0.5","halt_if_type":"num","halt_if_compare":"gt","entity_id":"sensor.nordpool_diff_interval_20","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"on","valueType":"str"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":650,"y":560,"wires":[["00e38cfb26f19e37"],[]]},{"id":"00e38cfb26f19e37","type":"api-call-service","z":"3e69cdaf73117960","name":"Charge on","server":"f610b696.ce7818","version":5,"debugenabled":false,"domain":"input_boolean","service":"turn_on","areaId":[],"deviceId":[],"entityId":["input_boolean.charge"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":950,"y":560,"wires":[["c0b5d5d30dfbbd83"]]},{"id":"025eba556e0f115c","type":"inject","z":"3e69cdaf73117960","name":"Inject 30s","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"30","crontab":"","once":true,"onceDelay":"1","topic":"","payload":"","payloadType":"date","x":130,"y":80,"wires":[["afe72b3375754982"]]},{"id":"afe72b3375754982","type":"delay","z":"3e69cdaf73117960","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":300,"y":80,"wires":[["b354759ee335037d"]]},{"id":"8adb93a631a3cbe8","type":"api-current-state","z":"3e69cdaf73117960","name":"","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.charge_short_interval","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":290,"y":660,"wires":[["9daaeb0eb34917f7"],[]]},{"id":"9daaeb0eb34917f7","type":"api-current-state","z":"3e69cdaf73117960","name":"Interval 6 > 0?","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"0","halt_if_type":"num","halt_if_compare":"gt","entity_id":"sensor.nordpool_diff_interval_6","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"on","valueType":"str"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":640,"y":640,"wires":[["8f0d81d271476fc4"],[]]},{"id":"8f0d81d271476fc4","type":"api-call-service","z":"3e69cdaf73117960","name":"Charge on","server":"f610b696.ce7818","version":5,"debugenabled":false,"domain":"input_boolean","service":"turn_on","areaId":[],"deviceId":[],"entityId":["input_boolean.charge"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":950,"y":640,"wires":[["c0b5d5d30dfbbd83"]]},{"id":"a65f19fbcded465a","type":"delay","z":"3e69cdaf73117960","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1020,"y":80,"wires":[["9bf4f1e8a804fa95"]]},{"id":"c0b5d5d30dfbbd83","type":"change","z":"3e69cdaf73117960","name":"","rules":[{"t":"set","p":"reset","pt":"msg","to":"","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1340,"y":320,"wires":[["a65f19fbcded465a"]]},{"id":"84266b72acf4a5db","type":"api-call-service","z":"3e69cdaf73117960","name":"Charge off","server":"f610b696.ce7818","version":5,"debugenabled":false,"domain":"input_boolean","service":"turn_off","areaId":[],"deviceId":[],"entityId":["input_boolean.charge"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":930,"y":460,"wires":[[]]},{"id":"b354759ee335037d","type":"api-current-state","z":"3e69cdaf73117960","name":"Wallbox Ready? (= not connected)","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"Ready","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.wallbox_portal_status_description","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":540,"y":80,"wires":[["a25411b7fce0f702"],["a65f19fbcded465a","615e4fcebe049208"]]},{"id":"a25411b7fce0f702","type":"api-call-service","z":"3e69cdaf73117960","name":"Charge off","server":"f610b696.ce7818","version":5,"debugenabled":false,"domain":"input_boolean","service":"turn_off","areaId":[],"deviceId":[],"entityId":["input_boolean.charge"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":930,"y":20,"wires":[[]]},{"id":"c53bebd0c6bc9449","type":"api-current-state","z":"3e69cdaf73117960","name":"Charge is off?","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"off","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.charge","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":760,"y":780,"wires":[["645bf126dd182a76"],["2be8becef398085f"]]},{"id":"645bf126dd182a76","type":"api-current-state","z":"3e69cdaf73117960","name":"Battery >=99%","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"99","halt_if_type":"num","halt_if_compare":"gte","entity_id":"sensor.average_battery_state_of_charge","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"on","valueType":"str"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":940,"y":700,"wires":[["516ae73dca691dde"],[]]},{"id":"516ae73dca691dde","type":"api-call-service","z":"3e69cdaf73117960","name":"Charge on","server":"f610b696.ce7818","version":5,"debugenabled":false,"domain":"input_boolean","service":"turn_on","areaId":[],"deviceId":[],"entityId":["input_boolean.charge"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1150,"y":700,"wires":[["c0b5d5d30dfbbd83"]]},{"id":"9bf4f1e8a804fa95","type":"api-call-service","z":"3e69cdaf73117960","name":"Charge off","server":"f610b696.ce7818","version":5,"debugenabled":false,"domain":"input_boolean","service":"turn_off","areaId":[],"deviceId":[],"entityId":["input_boolean.charge"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1230,"y":80,"wires":[[]]},{"id":"1fe065c1dc9850df","type":"api-current-state","z":"3e69cdaf73117960","name":"","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.charge_from_battery","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":290,"y":280,"wires":[["61aeb2c7bb69300f"],["640730e15ac8308f"]]},{"id":"61aeb2c7bb69300f","type":"api-current-state","z":"3e69cdaf73117960","name":"Battery start >=?%","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"$number(\t   $entities(\"input_number.start_charging_at_battery_percentage\").state\t)\t","halt_if_type":"jsonata","halt_if_compare":"gte","entity_id":"sensor.average_battery_state_of_charge","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"on","valueType":"str"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":670,"y":280,"wires":[["a18dcc3d8fabacb8"],["cb5eeb9eb1d8bfc5"]]},{"id":"ccf68e320061dd43","type":"api-current-state","z":"3e69cdaf73117960","name":"Battery stop >=?%","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"$number(\t   $entities(\"input_number.stop_charging_at_battery_percentage\").state\t)\t","halt_if_type":"jsonata","halt_if_compare":"gte","entity_id":"sensor.average_battery_state_of_charge","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"on","valueType":"str"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":910,"y":360,"wires":[["e4a638116f709566"],["640730e15ac8308f"]]},{"id":"e4a638116f709566","type":"api-call-service","z":"3e69cdaf73117960","name":"Charge on","server":"f610b696.ce7818","version":5,"debugenabled":false,"domain":"input_boolean","service":"turn_on","areaId":[],"deviceId":[],"entityId":["input_boolean.charge"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1090,"y":320,"wires":[["c0b5d5d30dfbbd83"]]},{"id":"a18dcc3d8fabacb8","type":"api-call-service","z":"3e69cdaf73117960","name":"Charge on","server":"f610b696.ce7818","version":5,"debugenabled":false,"domain":"input_boolean","service":"turn_on","areaId":[],"deviceId":[],"entityId":["input_boolean.charge"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":930,"y":260,"wires":[["c0b5d5d30dfbbd83"]]},{"id":"cb5eeb9eb1d8bfc5","type":"api-current-state","z":"3e69cdaf73117960","name":"Charge is off?","server":"f610b696.ce7818","version":3,"outputs":2,"halt_if":"off","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.charge","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":660,"y":340,"wires":[["640730e15ac8308f"],["ccf68e320061dd43"]]},{"id":"f610b696.ce7818","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"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}]

The main idea is:

  • If the charger is connected to the car turn the charger off with a delay of 5s
  • start the evaluation (seen on the left side) and turn the charger on when one of the conditions is true
  • interrupt turning off the charger if one of the conditions is true (shown on the right)

I might post it on github one day when I find the time to move this from node red to automations and create a testing environment for experimenting.