This is a multi-year exploration project… how to get Evohome to work reliably with Home Assistant.
The problems
0. Since the Evohome radiator smart valves are on top of the radiator… they were a design flaw from scracth. The thermostat integrated measures the temp of the radiator… not the room
- I’ve never been able to set generic thermostat to directly control evohome
- I got this working with an on/off helper switch (which is here for no real use - not even sure if this input boolean is needed) + automation in Nodered
- But this would still faill from time to time, from radiator to radiator.
- So I brute forced a script to babysit evohome
My hardware
- Evo home installation to my gas heater
- Evo Home radiator smart valves (house heats with water)
- Hassio
- Xiaomi temp sensors
Generic Thermostat
In climate.yaml (which means I have the line “climate: !include climate.yaml” in configuration.yaml) I added
- platform: generic_thermostat
name: kitchen
heater: input_boolean.boolean_temp_kitchen
target_sensor: sensor.kitchen_temp
This creates the entity “climate.kitchen”
Automation to Evohome
- I used Nodered for this. the principle is:
- climate.kitchen (create above) is going to have 2 status. Either “Heating” or “Idle”
- I’ll make Evohome a slave to this principle. EIther “heat” at 25℃ or “be cold” at 15℃ It’s the xiaomi sensor, via the generic thermostat that will tell evohome to stop or heat.
- It’s the generic thermostat with the xiaomi sensor that will do the real thermostat job to the exact temp I want.
NodeRed code (you’ll need to adjust home assistant server and your entity names)
[{"id":"fb6d962d5ab9d587","type":"server-state-changed","z":"9e28b3f9.5cc09","name":"Kitchen","server":"a0eea9da.0fe1d8","version":3,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"climate.kitchen","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":false,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":130,"y":3340,"wires":[["3d39c1971f22153a"]]},{"id":"3d39c1971f22153a","type":"debounce-leading-trailing","z":"9e28b3f9.5cc09","time":1000,"debouncetype":"trailing","name":"Debounce","x":340,"y":3340,"wires":[["5116c8df1a8a29df"]]},{"id":"5116c8df1a8a29df","type":"switch","z":"9e28b3f9.5cc09","name":"Heat or Idle","property":"data.new_state.attributes.hvac_action","propertyType":"msg","rules":[{"t":"eq","v":"idle","vt":"str"},{"t":"eq","v":"heating","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":650,"y":3340,"wires":[["9cffb13bfd78e6a4"],["81d76ef2bce6a8ce"]]},{"id":"9cffb13bfd78e6a4","type":"api-call-service","z":"9e28b3f9.5cc09","name":"keuken @ 15","server":"a0eea9da.0fe1d8","version":3,"debugenabled":false,"service_domain":"climate","service":"set_temperature","entityId":"climate.keuken","data":"{\"temperature\":\"15\"}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":870,"y":3320,"wires":[[]]},{"id":"81d76ef2bce6a8ce","type":"api-call-service","z":"9e28b3f9.5cc09","name":"keuken @ 25","server":"a0eea9da.0fe1d8","version":3,"debugenabled":false,"service_domain":"climate","service":"set_temperature","entityId":"climate.keuken","data":"{\"temperature\":\"25\"}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":870,"y":3360,"wires":[[]]},{"id":"5a8313f9a7ce86d0","type":"comment","z":"9e28b3f9.5cc09","name":"Generic Thermostat","info":"","x":130,"y":3300,"wires":[]},{"id":"51665979b86cd64d","type":"comment","z":"9e28b3f9.5cc09","name":"Bug Fix - Home Assistant sends ","info":"","x":390,"y":3220,"wires":[]},{"id":"1eb94b10aa868523","type":"comment","z":"9e28b3f9.5cc09","name":"multiple messages immediately ","info":"","x":390,"y":3260,"wires":[]},{"id":"9467740d3543b520","type":"comment","z":"9e28b3f9.5cc09","name":"when you change the temperature. ","info":"","x":400,"y":3300,"wires":[]},{"id":"e7fc0b72c54ce2f5","type":"comment","z":"9e28b3f9.5cc09","name":"Switch","info":"","x":630,"y":3300,"wires":[]},{"id":"1f79c20599735d01","type":"comment","z":"9e28b3f9.5cc09","name":"Set Evohome to either 15℃ or 25 ℃","info":"","x":880,"y":3280,"wires":[]},{"id":"a0eea9da.0fe1d8","type":"server","name":"GOOD Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30"}]
This is sufficient but… Evohome FAILS randomly to act on the requests.
So…
Over-engineered babysitter for Evohome
It creates a loop to check if evohome has indeed changed to the genenic thermostat request. It will attempt 3x2 times (6 in total) and will send a whatsapp (you need to set that up) at the end.
[{"id":"8f6b6bc73fcb2299","type":"server-state-changed","z":"9e28b3f9.5cc09","name":"Kitchen","server":"a0eea9da.0fe1d8","version":3,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"climate.kitchen","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":false,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":110,"y":2440,"wires":[["d766ef177a51bb36"]]},{"id":"d766ef177a51bb36","type":"debounce-leading-trailing","z":"9e28b3f9.5cc09","time":1000,"debouncetype":"trailing","name":"Debounce","x":260,"y":2440,"wires":[["e9fca3df72957131"]]},{"id":"e9fca3df72957131","type":"switch","z":"9e28b3f9.5cc09","name":"Heat or Idle","property":"data.new_state.attributes.hvac_action","propertyType":"msg","rules":[{"t":"eq","v":"idle","vt":"str"},{"t":"eq","v":"heating","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":430,"y":2440,"wires":[["3846e41ef77b94df"],["0b744837bed1fd43"]]},{"id":"6847c2fc91c6cd91","type":"ha-wait-until","z":"9e28b3f9.5cc09","name":"25sec","server":"a0eea9da.0fe1d8","version":0,"outputs":2,"entityId":"climate.keuken","entityIdFilterType":"exact","property":"attributes.temperature","comparator":"lt","value":"20","valueType":"num","timeout":"25","timeoutType":"num","timeoutUnits":"seconds","entityLocation":"data","entityLocationType":"none","checkCurrentState":true,"blockInputOverrides":true,"x":970,"y":2380,"wires":[[],["3c63f6a1c11314e9"]]},{"id":"3c63f6a1c11314e9","type":"api-call-service","z":"9e28b3f9.5cc09","name":"keuken @ 14","server":"a0eea9da.0fe1d8","version":3,"debugenabled":false,"service_domain":"climate","service":"set_temperature","entityId":"climate.keuken","data":"{\"temperature\":\"14\"}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1150,"y":2380,"wires":[["bb50fe8517b95250"]]},{"id":"3846e41ef77b94df","type":"change","z":"9e28b3f9.5cc09","name":"check again state","rules":[{"t":"set","p":"payload","pt":"msg","to":"homeassistant.gOODHomeAssistant.states[\"climate.kitchen\"].attributes.hvac_action","tot":"global","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":2380,"wires":[["ace1115548347794"]]},{"id":"bb50fe8517b95250","type":"change","z":"9e28b3f9.5cc09","name":"check again state","rules":[{"t":"set","p":"payload","pt":"msg","to":"homeassistant.gOODHomeAssistant.states[\"climate.kitchen\"].attributes.hvac_action","tot":"global","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":2420,"wires":[["e78b7bd5f0172c97"]]},{"id":"cf8079f8122c7f3c","type":"ha-wait-until","z":"9e28b3f9.5cc09","name":"25sec","server":"a0eea9da.0fe1d8","version":0,"outputs":2,"entityId":"climate.keuken","entityIdFilterType":"exact","property":"attributes.temperature","comparator":"lt","value":"20","valueType":"num","timeout":"25","timeoutType":"num","timeoutUnits":"seconds","entityLocation":"data","entityLocationType":"none","checkCurrentState":true,"blockInputOverrides":true,"x":970,"y":2420,"wires":[[],["51e1f83d3aeca86d"]]},{"id":"51e1f83d3aeca86d","type":"api-call-service","z":"9e28b3f9.5cc09","name":"keuken @ 13","server":"a0eea9da.0fe1d8","version":3,"debugenabled":false,"service_domain":"climate","service":"set_temperature","entityId":"climate.keuken","data":"{\"temperature\":\"13\"}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1150,"y":2420,"wires":[["fb045078bf183b15"]]},{"id":"fb045078bf183b15","type":"repeat","z":"9e28b3f9.5cc09","name":"repeat","repetitions":"3","elseOutput":true,"outputs":2,"x":1290,"y":2420,"wires":[["3846e41ef77b94df"],["f871884ddf9f9c56"]]},{"id":"ace1115548347794","type":"switch","z":"9e28b3f9.5cc09","name":"Heat or Idle","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"idle","vt":"str"},{"t":"eq","v":"heating","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":830,"y":2380,"wires":[["6847c2fc91c6cd91"],[]]},{"id":"e78b7bd5f0172c97","type":"switch","z":"9e28b3f9.5cc09","name":"Heat or Idle","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"idle","vt":"str"},{"t":"eq","v":"heating","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":830,"y":2420,"wires":[["cf8079f8122c7f3c"],[]]},{"id":"f871884ddf9f9c56","type":"api-call-service","z":"9e28b3f9.5cc09","name":"Whatsapp","server":"a0eea9da.0fe1d8","version":3,"debugenabled":false,"service_domain":"notify","service":"whatsapp","entityId":"","data":"{\"message\":\"Kitchen Evohome is not Working\"}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1440,"y":2440,"wires":[[]]},{"id":"02d44d663c3ead0f","type":"ha-wait-until","z":"9e28b3f9.5cc09","name":"25sec","server":"a0eea9da.0fe1d8","version":0,"outputs":2,"entityId":"climate.keuken","entityIdFilterType":"exact","property":"attributes.temperature","comparator":"lte","value":"20","valueType":"num","timeout":"25","timeoutType":"num","timeoutUnits":"seconds","entityLocation":"data","entityLocationType":"none","checkCurrentState":true,"blockInputOverrides":true,"x":970,"y":2460,"wires":[[],["2dec6d13e17c91e2"]]},{"id":"2dec6d13e17c91e2","type":"api-call-service","z":"9e28b3f9.5cc09","name":"keuken @ 14","server":"a0eea9da.0fe1d8","version":3,"debugenabled":false,"service_domain":"climate","service":"set_temperature","entityId":"climate.keuken","data":"{\"temperature\":\"24\"}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1150,"y":2460,"wires":[["02da08fc3a85d1c4"]]},{"id":"0b744837bed1fd43","type":"change","z":"9e28b3f9.5cc09","name":"check again state","rules":[{"t":"set","p":"payload","pt":"msg","to":"homeassistant.gOODHomeAssistant.states[\"climate.kitchen\"].attributes.hvac_action","tot":"global","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":2460,"wires":[["4d04f408b64a3294"]]},{"id":"02da08fc3a85d1c4","type":"change","z":"9e28b3f9.5cc09","name":"check again state","rules":[{"t":"set","p":"payload","pt":"msg","to":"homeassistant.gOODHomeAssistant.states[\"climate.kitchen\"].attributes.hvac_action","tot":"global","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":2500,"wires":[["3bd7405eec8b0e08"]]},{"id":"a4bc1cddb066a8e8","type":"ha-wait-until","z":"9e28b3f9.5cc09","name":"25sec","server":"a0eea9da.0fe1d8","version":0,"outputs":2,"entityId":"climate.keuken","entityIdFilterType":"exact","property":"attributes.temperature","comparator":"gt","value":"20","valueType":"num","timeout":"25","timeoutType":"num","timeoutUnits":"seconds","entityLocation":"data","entityLocationType":"none","checkCurrentState":true,"blockInputOverrides":true,"x":970,"y":2500,"wires":[[],["ad8a1e8ff7c0f8d8"]]},{"id":"ad8a1e8ff7c0f8d8","type":"api-call-service","z":"9e28b3f9.5cc09","name":"keuken @ 13","server":"a0eea9da.0fe1d8","version":3,"debugenabled":false,"service_domain":"climate","service":"set_temperature","entityId":"climate.keuken","data":"{\"temperature\":\"25\"}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1150,"y":2500,"wires":[["57516b1fafaa92ec"]]},{"id":"57516b1fafaa92ec","type":"repeat","z":"9e28b3f9.5cc09","name":"repeat","repetitions":"3","elseOutput":true,"outputs":2,"x":1290,"y":2500,"wires":[["0b744837bed1fd43"],["f871884ddf9f9c56"]]},{"id":"4d04f408b64a3294","type":"switch","z":"9e28b3f9.5cc09","name":"Heat or Idle","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"idle","vt":"str"},{"t":"eq","v":"heating","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":830,"y":2460,"wires":[[],["02d44d663c3ead0f"]]},{"id":"3bd7405eec8b0e08","type":"switch","z":"9e28b3f9.5cc09","name":"Heat or Idle","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"idle","vt":"str"},{"t":"eq","v":"heating","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":830,"y":2500,"wires":[[],["a4bc1cddb066a8e8"]]},{"id":"a0eea9da.0fe1d8","type":"server","name":"GOOD Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30"}]
For the geeks
I found this fascinating. Home Assistant in NodeRed assign automatically to global parameters… everything. So I call a change node out of nowehere (this would work with an inject timestamp) to assign the status of my generic thermostat to the payload.
The value
homeassistant.gOODHomeAssistant.states["climate.kitchen"].attributes.hvac_action
Uses my server name for home assistant “Good Home Assistant”
Those global values can be found here: