SOLVED. Intelligent thermostat algorithm needed. Guru needed

Is not this

and this

contradictory ?
Setpoints are on thermostats. You advocate using 4 setpoints close to TRV values and a 5th a bit lower; so this requires 5 setpoints = 5 thermostats. But you also advocate using a single thermostat and feeding the desired sensor into it (currently I’m feeding the midpoint between the avg and max sensor values).

confused.com :face_with_thermometer:

EDIT: No matter. I have played around with my HA setup:-

before

  1. I was running 5 generic_thermostats each using the associated eTRV for target_sensor. Each room thus has its own setpoint on the generic_thermostat
  2. Use 5 lovelace thermostat cards.
  3. The boiler was moded on a switch group component where the group entities were the generic_thermostat.heater outputs.
    The boiler was on and off for weeks, months, and room temps all over the place. Rooms too cold or too hot. Wasted money for months. Grrrr.

now

  1. Manual TRVs (non smart) fitted to all rads. Each is set to yield a comfortable room heat experience.
  2. I only now use one generic_thermostat component. Its target_sensor is the “midpoint temp” which is the value between the maximum reading from the room sensors and the calculated average of all room sensors. Its heater output drives the boiler on/off.
  3. Setpoint on the generic_thermostat is 19C.
  4. Using a single thermostat lovelace card connected to the generic_thermostat

Now I do not understand the theory behind what I have done, but it seems to be working well now, stable house temps, and sensible boiler duty cycles.


Key observation here, is that the blue line (midpoint temp) is tracking closely , the target temp (horizontal pink line) Note: I just turned it up moments ago to test something else , hence the sharp rise on the rightmost side. You can see how I started to tweak all this around 07:30ish upto now, 18:30.

All good.

Thanks to @Mutt

I think I was just completely doing all the wrong I could possibly do, and trying to fork and knife my old setup, into your explanation and model , then trying to defend my completely inappropriate approach. Not a good strategy :sweat_smile:

And here is the final dashboard for my home heating:

However
@Mutt There is just ONE minor issue I could do with your help on, having now educated me ( :slight_smile: ) :-

  • The sensors provide updates at 30 mins out of phase (i.e. not all the same time).
  • When I set the target temp, by the time the boiler switches off, the actual house temp is about 0.3 to 0.9C higher than the target temp.
  • As the room cools it does so to an uncomfortable temperature because it is taking 30 mins for the sensors to report the true temp, which is colder than it actually is. Failing to handle this cooling effect will delay the boiler and the room gets too cold.
  • Thus I require some sort of smoothing algorithm that “learns” over time to adjust the boiler duty cycle duration. Too long a duty cycle and the temps rise due to heat build up through the house, too short a cycle and the house temp will not be reached. Waiting too long to kick in and the rooms are too cold.

Am I explaining well? Anyway , any suggestions please? be gentle please, just the algorithm will suffice - my head hurts tonight :grinning: :grinning:

I think you tried to explain the solution here, but I do not understand sorry:

Still with us @Mutt ?

Well, I have completely redesigned my home setup.
Ditched the crap eTRVs.
I now use Xiaomi Humidity+Temperature sensors, smaller than a matchbox, Tx every 10 minutes., and a year battery power through a CR type “big” watch battery.
Now getting real time temp readings, no delays, no overrrun, no underrun. no boiler kettling.
All because of crap eTRV devices - which by the way all report temps differently when next to each other and all report the wrong temp anyway.
Sigh.

All sorted.

(I still use a smoothing algorithm to keep “the house” warm, using the midpoint between avg and max of all sensors, then comparing that to around 18C which is nice n cosy now).

1 Like

I know this is a late response, but maybe others can use it and it may even have been said in the thread earlier, but I guess its better one too many times than one too few.

In order for your heating to work you actually need 3 values, current temperature, target temperature and valve control.
You only have 2 values in your set up, current temperature and then target temperature that was directly linked to the valve control.
In order to get the 3 values you need to use HA to split up the linked values.
You do that by having HA control and store the target temperature and the use the target temperature on the valve as a valve control by giving it target values that fits the valve setting you actually wants.
You may lose the ability to adjust the temperature directly on the thermostat, since its not actually the real target temperature that is on the there, but the target temperature that give the right valve setting.

To remedy this loss of control you can buy cheap wall thermostats that can be linked to HA, which then can be used to control the valve thermostats. The benefit of this is that these wall thermostats usually comes with a thermometer too and these measure the room temperature better than the one on the radiator, which is highly influenced on the current valve setting.

There are then 3 node-red flows.

Could you maybe share those Node-RED flows? I would also like to try using your method.

Sure thing. Here you go. Hope it makes sense. There are comments. It’s too big to screen shot

[{"id":"e1990edd.19d3f8","type":"tab","label":"Climate","disabled":false,"info":""},{"id":"ba3b1dc9.70d1d","type":"server-state-changed","z":"e1990edd.19d3f8","name":"Increase temp","server":"3f1b73d1.299cbc","version":3,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_boolean.living_room_temperature_up","entityidfiltertype":"exact","outputinitially":true,"state_type":"str","haltifstate":"on","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"for":"100","forType":"num","forUnits":"milliseconds","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"x":110,"y":160,"wires":[["30d2da05.d31976","74ffef80.494e4","2e2cad33.fe8b8a"],[]]},{"id":"30d2da05.d31976","type":"delay","z":"e1990edd.19d3f8","name":"Wait 100ms","pauseType":"delay","timeout":"100","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":350,"y":140,"wires":[["2b983094.26baa"]]},{"id":"2b983094.26baa","type":"api-call-service","z":"e1990edd.19d3f8","name":"Turn off button","server":"3f1b73d1.299cbc","version":3,"debugenabled":false,"service_domain":"input_boolean","service":"turn_off","entityId":"input_boolean.living_room_temperature_up, input_boolean.living_room_temperature_down","data":"","dataType":"json","mergecontext":"","mustacheAltTags":false,"output_location":"payload","output_location_type":"msg","x":540,"y":140,"wires":[[]]},{"id":"8f2ab4c5.d14bc8","type":"api-call-service","z":"e1990edd.19d3f8","name":"Set new targets","server":"3f1b73d1.299cbc","version":3,"debugenabled":false,"service_domain":"climate","service":"set_temperature","entityId":"climate.livingroom_thermostat","data":"","dataType":"json","mergecontext":"","mustacheAltTags":false,"x":580,"y":300,"wires":[[]]},{"id":"9e722cbd.8266a","type":"api-current-state","z":"e1990edd.19d3f8","name":"Get current target","server":"3f1b73d1.299cbc","version":2,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"climate.livingroom_thermostat","state_type":"str","blockInputOverrides":false,"x":570,"y":220,"wires":[["344a613f.68ecae"]]},{"id":"57e8ccf8.35ebbc","type":"server-state-changed","z":"e1990edd.19d3f8","name":"Decrease temp","server":"3f1b73d1.299cbc","version":3,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_boolean.living_room_temperature_down","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"on","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"for":"100","forType":"num","forUnits":"milliseconds","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"x":100,"y":220,"wires":[["30d2da05.d31976","ce219d1.894ac6","2e2cad33.fe8b8a"],[]]},{"id":"344a613f.68ecae","type":"function","z":"e1990edd.19d3f8","name":"Calc new target","func":"var temp_change = flow.get('temp_change') || 0\nvar current_temp = msg.data.attributes.temperature\n\nvar new_temp = current_temp + temp_change\nmsg.payload = {\n    data: {\n        temperature: new_temp\n    },\n    current_temp: current_temp,\n    temp_change: temp_change\n}\n\nflow.set('temp_change', 0)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":400,"y":300,"wires":[["8f2ab4c5.d14bc8"]]},{"id":"74ffef80.494e4","type":"function","z":"e1990edd.19d3f8","name":"Increment  counter","func":"var temp_change = flow.get('temp_change') || 0\n\nflow.set('temp_change', temp_change + 1)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":310,"y":100,"wires":[[]]},{"id":"eb5852cb.afb968","type":"function","z":"e1990edd.19d3f8","name":"initialisation","func":"\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":90,"y":100,"wires":[[]]},{"id":"ce219d1.894ac6","type":"function","z":"e1990edd.19d3f8","name":"Decrement counter","func":"var temp_change = flow.get('temp_change') || 0\n\nflow.set('temp_change', temp_change - 1)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":310,"y":260,"wires":[[]]},{"id":"2e2cad33.fe8b8a","type":"trigger","z":"e1990edd.19d3f8","name":"5 second timer","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"5","extend":true,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":360,"y":220,"wires":[["9e722cbd.8266a"]]},{"id":"f2301f3e.4a805","type":"comment","z":"e1990edd.19d3f8","name":"Adjust the thermostat target temperatures","info":"Increment or decrement the target temperatures of the Living room thermostat.\n\nEach the up or down buttons are pressed, a counter is incremented/decremented. Once 5 seconds has elapsed from the time of the last button-press, the current target will be retrieved and the new target calculated. The new target is then sent to the thermostat.","x":180,"y":60,"wires":[]},{"id":"f254f430.d4d838","type":"inject","z":"e1990edd.19d3f8","name":"trigger at 00:01","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"01 00 * * *","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":400,"wires":[["cb5911db.6c3bf","18617dd5.0f436a"]]},{"id":"cb5911db.6c3bf","type":"api-call-service","z":"e1990edd.19d3f8","name":"Turn off manual overide","server":"3f1b73d1.299cbc","version":3,"debugenabled":false,"service_domain":"input_boolean","service":"turn_off","entityId":"input_boolean.central_heating_manual","data":"","dataType":"json","mergecontext":"","mustacheAltTags":false,"x":350,"y":400,"wires":[[]]},{"id":"792aca1f.f54f0c","type":"comment","z":"e1990edd.19d3f8","name":"Reset the central_heating_manual switch","info":"There is a manual overide switch to prevent Schedy switching to nighttime mode. This switch needs to be reset at midnight.","x":180,"y":360,"wires":[]},{"id":"d7754504.1ad5d8","type":"comment","z":"e1990edd.19d3f8","name":"Control CH Boiler","info":"Use the state of the \"we need heat\" virtual switch to control the Sheely switch that causes the boiler to fire.","x":100,"y":568,"wires":[]},{"id":"83331097.6a4d98","type":"api-call-service","z":"e1990edd.19d3f8","name":"Boiler Off","server":"3f1b73d1.299cbc","version":3,"debugenabled":false,"service_domain":"switch","service":"turn_off","entityId":"switch.central_heating_boiler_ch","data":"","dataType":"json","mergecontext":"","mustacheAltTags":false,"x":540,"y":648,"wires":[[]]},{"id":"8ae45f67.0b0278","type":"api-call-service","z":"e1990edd.19d3f8","name":"Boiler On","server":"3f1b73d1.299cbc","version":3,"debugenabled":false,"service_domain":"switch","service":"turn_on","entityId":"switch.central_heating_boiler_ch","data":"","dataType":"json","mergecontext":"","mustacheAltTags":false,"x":540,"y":568,"wires":[[]]},{"id":"16d9f61.9f28c8a","type":"api-call-service","z":"e1990edd.19d3f8","name":"Set Dining Rad","server":"3f1b73d1.299cbc","version":3,"debugenabled":false,"service_domain":"climate","service":"set_temperature","entityId":"climate.diningroom_radiator_thermostat","data":"","dataType":"json","mergecontext":"","mustacheAltTags":false,"x":600,"y":900,"wires":[[]]},{"id":"f62a45ba.70aa08","type":"trigger-state","z":"e1990edd.19d3f8","name":"Livingroom Thermostat","server":"3f1b73d1.299cbc","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"climate.livingroom_thermostat","entityidfiltertype":"exact","debugenabled":false,"constraints":[],"outputs":2,"customoutputs":[],"outputinitially":false,"state_type":"str","x":130,"y":800,"wires":[["8d475e87.2e9fe8","f0087f7a.b18908"],[]]},{"id":"8d475e87.2e9fe8","type":"function","z":"e1990edd.19d3f8","name":"","func":"var newTemp;\n\nnewTemp = msg.data.event.new_state.attributes.temperature + 0.5;\n\nmsg.payload = {\n    domain: 'climate',\n    service: 'set_temperature',\n    data: {\n        temperature: newTemp\n    }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":400,"y":800,"wires":[["9bd29009.94aca","ce82251c.a54b38"]]},{"id":"9bd29009.94aca","type":"debug","z":"e1990edd.19d3f8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":710,"y":800,"wires":[]},{"id":"ce82251c.a54b38","type":"api-call-service","z":"e1990edd.19d3f8","name":"Set Living Rad","server":"3f1b73d1.299cbc","version":3,"debugenabled":false,"service_domain":"climate","service":"set_temperature","entityId":"climate.livingroom_radiator_thermostat","data":"","dataType":"json","mergecontext":"","mustacheAltTags":false,"x":600,"y":840,"wires":[[]]},{"id":"f712e71d.311498","type":"trigger-state","z":"e1990edd.19d3f8","name":"Bedroom 1 Thermostat","server":"3f1b73d1.299cbc","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"climate.bedroom_1_thermostat","entityidfiltertype":"exact","debugenabled":false,"constraints":[],"outputs":2,"customoutputs":[],"outputinitially":false,"state_type":"str","x":130,"y":960,"wires":[["c0e41ebe.a00d78"],[]]},{"id":"c0e41ebe.a00d78","type":"function","z":"e1990edd.19d3f8","name":"","func":"var newTemp;\n\nnewTemp = msg.data.event.new_state.attributes.temperature + 0.5\nmsg.payload = {\n    domain: 'climate',\n    service: 'set_temperature',\n    data: {\n        temperature: newTemp\n    }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":380,"y":960,"wires":[["3dc170e1.308168","1e46bad6.134e7d"]]},{"id":"3dc170e1.308168","type":"debug","z":"e1990edd.19d3f8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":590,"y":960,"wires":[]},{"id":"1e46bad6.134e7d","type":"api-call-service","z":"e1990edd.19d3f8","name":"Set Bedroom 1 Rad","server":"3f1b73d1.299cbc","version":3,"debugenabled":false,"service_domain":"climate","service":"set_temperature","entityId":"climate.bedroom_1_radiator_thermostat","data":"","dataType":"json","mergecontext":"","mustacheAltTags":false,"x":620,"y":1000,"wires":[[]]},{"id":"c1ceb612.36728","type":"trigger-state","z":"e1990edd.19d3f8","name":"Bedroom 2 Thermostat","server":"3f1b73d1.299cbc","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"climate.bedroom_2_thermostat","entityidfiltertype":"exact","debugenabled":false,"constraints":[],"outputs":2,"customoutputs":[],"outputinitially":false,"state_type":"str","x":130,"y":1060,"wires":[["588c8f80.166088"],[]]},{"id":"588c8f80.166088","type":"function","z":"e1990edd.19d3f8","name":"","func":"var newTemp;\n\nnewTemp = msg.data.event.new_state.attributes.temperature + 2.5;\n\nmsg.payload = {\n    domain: 'climate',\n    service: 'set_temperature',\n    data: {\n        temperature: newTemp\n    }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":380,"y":1060,"wires":[["9004e06d.b7e97","74370f6c.66f92"]]},{"id":"9004e06d.b7e97","type":"debug","z":"e1990edd.19d3f8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":590,"y":1060,"wires":[]},{"id":"74370f6c.66f92","type":"api-call-service","z":"e1990edd.19d3f8","name":"Set Bedroom 2 Rad","server":"3f1b73d1.299cbc","version":3,"debugenabled":false,"service_domain":"climate","service":"set_temperature","entityId":"climate.bedroom_2_radiator_thermostat","data":"","dataType":"json","mergecontext":"","mustacheAltTags":false,"x":620,"y":1100,"wires":[[]]},{"id":"6804d077.05d9c8","type":"poll-state","z":"e1990edd.19d3f8","name":"Poll \"We need heat\"","server":"3f1b73d1.299cbc","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"updateinterval":"1","updateIntervalUnits":"minutes","outputinitially":false,"outputonchanged":false,"entity_id":"binary_sensor.we_need_heat","state_type":"str","halt_if":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"x":110,"y":600,"wires":[["32ef889e.3865d"]]},{"id":"32ef889e.3865d","type":"switch","z":"e1990edd.19d3f8","name":"On/Off","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"on","vt":"str"},{"t":"cont","v":"off","vt":"str"}],"checkall":"false","repair":false,"outputs":2,"x":330,"y":608,"wires":[["8ae45f67.0b0278"],["83331097.6a4d98"]]},{"id":"f0087f7a.b18908","type":"function","z":"e1990edd.19d3f8","name":"","func":"var newTemp;\n\nnewTemp = msg.data.event.new_state.attributes.temperature + 1.0;\n\nmsg.payload = {\n    domain: 'climate',\n    service: 'set_temperature',\n    data: {\n        temperature: newTemp\n    }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":400,"y":860,"wires":[["16d9f61.9f28c8a"]]},{"id":"18617dd5.0f436a","type":"api-call-service","z":"e1990edd.19d3f8","name":"Reset simulate_bedtime","server":"3f1b73d1.299cbc","version":3,"debugenabled":false,"service_domain":"input_boolean","service":"turn_off","entityId":"input_boolean.simulate_bedtime","data":"","dataType":"jsonata","mergecontext":"","mustacheAltTags":false,"x":360,"y":500,"wires":[[]]},{"id":"ecd70450ccacd0ab","type":"comment","z":"e1990edd.19d3f8","name":"Adjust the room TRVs","info":"","x":130,"y":760,"wires":[]},{"id":"615c6742e66aee2b","type":"comment","z":"e1990edd.19d3f8","name":"Overview","info":"# Entities\n- Each room has at least one radiator with a Danfoss TRV. Unfortunately, you cannot read the actual room temperature from the TRV, so\n- Each room also has a temperature sensor\n- Each room has a generic thermostat in HA which controls the state of:\n- an input_boolean if the room needs heat\n- Some rooms have up/down buttons in HA to increment/decrement the target temp\n\n# Control loops\n- Schedy is running in an Appdaemon addon to provide top level control of room set-points.\n- A couple of rooms have a Node-Red flow that is triggered by the up/down buttons and adjust the room's 'thermostat'\n- Each room then has a node-red flow to ensure the room's TRV mirrors the thermostat's set-point (with the option of adding an offset based on how closely the TRV's set-point matches that of the thermostat)\n- An automation monitors the state of each room's \"I need heat\" input_boolean to decide if the House needs heat. (this allows the flexibility to add additional \"rooms\" or other reasons to switch the heating on)\n- The last node-red flow then uses the state of the \"we need heat\" inut_boolean to control the boiler","x":80,"y":20,"wires":[]},{"id":"3f1b73d1.299cbc","type":"server","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]
1 Like