SOLVED. Intelligent thermostat algorithm needed. Guru needed

Problem
I have a gas fired central heating system with eTRVs on all 6 radiators in the home. The eTRVs send data over RF433. HA and FrontEnd setup all working. However, it is less than ideal.
The issue is in the reporting of data from the eTRVs. The non-modifable firmware sends data every 15 minutes or so. This is a “design feature” aimed at conserving battery power. In this regard it seems to work well - the batteries have been in for 13 months and lost only a small amount of charge. Great! However there is a flaw.
The flaw means that the setpoint for a given eTRV is reached however the eTRV would only send the actual temperature every 15 minutes. This means that by the time the temperature measured by the eTRV is at the setpoint, 15 minutes elapse before the temperature is sent and received into HA. During this time, the boiler remains active and thus continues to heat the radiator. Thus, by the time the temp is received by HA the ambient temp has actually increased to a much higher figure than reported (the setpoint or thereabouts above). The precise figure depends on several factors including but not limited to: Ambient temp, External outside temp, size of radiator, location of rad (lower floor/upper floor), distance from boiler, and so on. Suffice to say that the increase in temperature over the setpoint can be between 1 and 3 Celsius. I need some way of “tuning” each eTRV to account for system behaviour. To be clear, there is no means by which to change the eTRV behaviour and so the focus needs to be on compensating for this within my HA setup. This is where I need your help please.

Current setup
Pi4 running Raspbian (Debian Buster) with a generic RF433 card. All working. In regard to HA, I use the latest core version downloaded from HA site as of 4/1/2021. For simplicity, let us assume please that I have one eTRV. I control this in HA via the native ‘generic thermostat’ component, and use the ‘simple-thermostat’ lovelace card (https://github.com/nervetattoo/simple-thermostat).
As I say, all works fine albeit without said compensation.

Help needed
Is there some sort of algorithm that would work, what is it called (or the theory name), and where might I obtain sample code. I have been referred to hysteresis (and ‘tolerance’ in HA component config) but this isn’t the right resolution. This is because it turns on the heat when the temp drops below the lower-limit (minus a tolerance value) and only turns off when it reaches the upper-limit [setpoint] (plus a tolerance value). So this will actually make my situation worse because the boiler will be commanded “on” for even longer.
I am fine with Python, C/C#/C++, JS, Java so will understand code you may be able to point me to, but I am less conversant with yaml/HA/templating and exchanging data via service calls between HA core and the cards & components - so I will need help on this. But first off, I would appreciate suggestions on suitable algorithmic names/theories and pointers to some code examples ? then will try to work out as best I can posting the config here ( probably not working :slight_smile: )

What I have tried
So far, lots. The closest I got was (in PDL):-

CONSTANT heating_tolerance = -0.5;
CONSTANT cooling-tolerance = +0.5;
LET setpoint = 18.0;
DO WHEN UPDATE OF etrv_room_temp 
# this is the temp value received from the eTRV. 
# note an update might change the temp, but it might not. 
# so this is an UPDATE trigger, not a CHANGE.
# i.e. run this code on every update regardless of value.
   IF etrv_room_temp >= setpoint - heating_tolerance THEN
     { switch off boiler }
   ELSEIF etrv_room_temp <= setpoint + cooling_tolerance THEN
      { switch on boiler }
   END IF;
END DO;

This allowed me to set (and adjust) tolerances that would compensate for temperature rises likely to occur within 15mins of reaching the setpoint, by effectively reducing the setpoint and increasing the lower-limit for turning on the boiler. However, and somewhat obviously, this just entered a deadlock in which the boiler iteratively cycled on and off within milliseconds. No, this doesnt work then , needs to be more intelligent (or rather I do!)

Many thanks.

1 Like

Not the solution you are looking for - so feel free to ignore, but have you thought about deploying 6x independent temperature sensors to those rooms? That would allow more refined (Ie more frequent) measurements rather than a software-based predictive model. I believe there are 433MHz devices out there but you could also use WiFi.

As mentioned, not what you’re looking for but a possible alternative.

Interesting problem. My Honeywell thermostats have a setting called “heating cycle rate” which, as far as I can tell, attempts to estimate how many on/off cycles per hour are needed to maintain the desired temperature. So, theoretically, it “knows” that it should shoot for running the heat, say, six times in the next hour, for five minutes each.

I only offer this as perspective. Instead of using only current temperature vs. some setpoints, figure out how long your heat should run, based on temperature, setpoint, outside temperature, etc.

I find this a nice feature in my Honeywells. They keep a very stable temperature, compared to the old setpoint-based system.

1 Like

Ah, most interesting. Yes, something like that will do. I accept that eTRVs are useful only to a certain limit, not least they are close to the radiator and also require power to operate the valves and so on. Not ideal alone. I’m sensing software or algorithms are not the answer on its own. What model are you thermostats and how do you integrate/operate within HA?
Thanks

I have just three zones, with zone valves at the boiler. So what works for me may not be ideal for your system.

That said, I happen to run Honeywell RTH6580WF smart WiFi thermostats, only because that’s what I had before I started playing with HA. I’m not a big fan of cloud-based solutions, but that’s how these work. There’s a supported HA integration which uses the Honeywell API back to their cloud.

I’ve grown to accept, maybe even like, this arrangement. Yes, it’s cloud-dependent. But if all else fails the thermostats keep working independently and I can manually adjust them. Meanwhile, the HA integration gives me all the control I need day-to-day, and if HA fails, or I need to do something more complex like modify the schedule, I still have the Honeywell app and web site. Reliability is critical for heating systems in my climate.

1 Like

Somewhat similar to @CaptTom, a low level “solution” could be to set a timeout each time you trigger the boiler. And if at the timeout the temp is still not reached, a new boost is triggered. This is how I have set up my exhaust fan in the bathroom. It runs for 15 minutes and then stops, unless it is triggered for another 15 minutes in the meantime,

1 Like

Hi there!

I am not sure does this help at all but I explain my solution to this problem anyway. I also believe there in much more sophisticated solutions and my programming skills are poor. But this is what I do with my cold storage below. Heating here is done by electric heater, which also has a thermostat. That is adjusted for higher target so the actual control is done by couple zigbee temperature sensors (combined).

I use generic thermostat turning on an input_boolean instead of the smart switch:

EDIT: I try to explain better way:

Heating will be turned on for max 6 min (will be adjusted later based on outside temperature). If “hot tolerance” is not reached in 25 min the “cycle” will start again by turning input boolean off.

So far I adjust this 6 minutes manually. Down in this thread is a solution to automatically adjust this heating time based on outside temperature

This is how it works for me in practice ( accuracy is around ± 0.1C with this setting as seen in picture):

Excellent, i will look into those thermostats Ideally a cheap thermostat would suffice with code in my HA that emulates similar function you describe. Many thanks

Ah, that’s an idea. So some kind of duty cycle algorithm I’ll look at this.

Hi. Thanks for the detail. Not sure i understand due to language barrier but your English is better than my Portoguese :grinning: . Can you summarise your algorithm please, rather than describe what switches and sensor you use? maybe i can help code it?

Template the delay to a seconds value from an input number
Have the input number 360 to 480 (6 to 8 minutes)
Every time you overshoot deduct a second
Every time you undershoot add a second
It will NEVER find a perfect balance but the constant ‘hunting’ will mean you are always pretty close

EDIT: I removed automation part. It is not the best example, and the princible is known now.

And generic thermostat:

############################
  - platform: generic_thermostat
    name: Varasto
    heater: input_boolean.varastoheat
    target_sensor: sensor.varasto_temppi
    min_temp: 1
    max_temp: 20
    target_temp: 2
    cold_tolerance: 0
    hot_tolerance: 0.1
    min_cycle_duration:
      seconds: 10
    keep_alive:
      minutes: 3
############################ 

sorry, I still do not understand.

‘template the delay’

what is meant by template? what delay?

‘overshoot’

overshoot what? overshoot=?(go over/above?)

Just not quite on the language with you - sorry - I’m in England, London and not quite following the ‘english’.

Snap

I was under the impression that you’d both understand the terms given both the usage and the goal you are trying to achieve. I agree its harder for you as you will need to set up more ‘generic_thermostats’ and the gubbins but the principle is the same.

  1. Create an input number with the desired minutes range but in seconds (more control) eg input_number.mark_time
  2. Change the for: or delay part to a template value taking the input number eg
For: "00:00:{{ states('input_number.mark_time') }}" 
  1. Set the automation to check the temp against set point at the end of the ‘pause or mark time’
  2. If it’s 1.5 degrees MORE than setpoint decrement input number if it’s 1 degree lower ‘increment’ the input number
  3. If the overall time firing is consistent you will have a constantly battling mark-space ratio

Job done

Then just tweak the numbers to suit the thermal inertia on the ‘heat entities’ (room in your case) beware, that tuning this will take some time both in summer and winter, so don’t make wild changes, as you need it to be self balancing

Ah, I see.
So looking at your config, :-
You turn heating ‘On’ for a max of 25 minutes in a duty cycle, with 6 minute intervals of ‘Off’ between each duty cycle?

Yeah, I’d agree, I’d start on a 10 minute cycle with an input_number range of 0 to 600

Why ‘London’ strike-through? That’s more interesting at the moment. I’m in W5 !? Always been London for the 40yrs I’ve been here.

Yeah, but I’m not :rofl:

Ah, you were quoting me . Mind you, this site says I’m in Blackpool, Cornwall, and even in the US at one point - never been in any of those places.

Back to the algorithm you provide, I understand 100% - thank you - so will code that up now. I might tweak it slightly to use a timer:

timer:
    mark_countdown:
      duration: "00:00:{{ states('input_number.mark_time') }}"
      #-- see my comment in this post below
..
..
automation:
 - alias: Timer expired
      trigger:
        - platform: event 
          event_type: timer.finished
          event_data:
            entity_id: timer.mark_countdown
      action:
        ..
        ..

But doesn’t “00:00:{{ }}” resolve to a number of seconds upto 59? I can work out this anyway using a slider for 0 to 600 seconds or something.

EDIT: better way

- alias: Timer ON
      trigger:
        - platform: state
          entity_id: input_boolean.water_demand #-- thermostat heater output
          to: 'on'
      action:
        # turn on water
        - service: input_boolean.turn_on            
          entity_id: input_boolean.water #-- boiler                                        
        # start timer for NNN seconds/minutes
        - service: timer.start
          data:
            entity_id: timer.water_countdown
            duration: {{ states('input_number.mark_duration') }} #-- ned to cast this to datetime or use a datetime entity
            #-- from hereon we can trigger on this timer completed then check setpoint vs actual and adjust marker time
..
..

I’ll work on this , test , and post the solution back here.

Thanks for your reply!

Based on my own experience (I use this in few places) I do not need seconds here, minute works for me good enough. As you see from my picture, right now the temperature accuracy is ± 0.1 C with this setting. Of course I understand someone might need more accuracy for their needs.

More important for me would be automatically set that “delay” based on outside temperature. Like (just an example):

< - 20 C -> 15 min
< - 15 C -> 12 min
< - 10 C -> 10 min
< - 5 C -> 8 min
< 0 C -> 6 min
more than 0 -> 4 min