Getting Evohome to Reliably Work (Home assistant & Nodered)

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

  1. I’ve never been able to set generic thermostat to directly control evohome
  2. 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
  3. But this would still faill from time to time, from radiator to radiator.
  4. 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:

1 Like

I also found the thermostat based temperature measurements on my EvoHome somewhat lacking in regards to accuracy so I went to look for a better solution. With a bit of digging in the EvoHome forum I found that one can use the DT92E Wireless Room Thermostats instead of the the TRV sensors. That way I can position the thermostat wherever I want in the room and get decent reliable temperature information fed into the EvoHome regulating the temperature. I’ve got 7 TRVs on my EvoHome and each one has it’s own DT92E, they come up quite regularly on eBay as second hand (£15-25) as they are seemingly used with one of the relays as a basic way to control a boiler. I’ve been running this setup for several years and it works very well, even allows to change temperature from each DT92E until it gets taken over by the next trigger point in the EvoHome which has proven popular with guests who I don’t want to mess with the EvoHome.

3 Likes