Control loop for adaptive consumption electric roomheater?

Hi all,
I am building an adaptive electric room heater that uses excess PV energy.
It uses ceramic heating elements to consume 0-1300W in 100W increments.
The heater is controlled by an ESP8622.
The data source is a Shelly 3EM Pro measuring over all electricity consumption of my home.
My current plan is to have a helper in HA limited to natural numbers 0-13 representing the heater settings which are then read by the ESP running ESPhome. This helper has the Shelly sensor as source.
So far, I have managed to turn the Shelly data into instructions for the heater:
{{((float(states.sensor.shelly_pro_eem_total_active_power.state) /100) | round(0,"ceil", default)) * (-1)}} and named the result “number.stromuberschuss” or “X”.

This takes the source value from Shelly, transforms it into a number, divides by 100 for the 100w increments of the heater, rounding up to natural numbers and multiplying by -1 to get the heater to switch up by 1 when the Shelly gets below -100w etc.
So the result is basically an instruction of turning the heater up or down by X steps based on the excess energy available.

What I’m basically missing now is a counter that adds or subtracts X every time X updates and is limited between 0 and 13.
Ideally this would be inside the same template helper and the only solution I can think of is using a recursive loop of the type
X=int “heater instruction”
Y=int “heater current stetting”
for (x.update):
Y=Y+X
with appears to be quite difficult in yaml.

An alternative would be to use an automation triggered by an attribute change of number.stromuberschuss to make sure that the heater setting is only changed when X updates.

However my attempt

action:
  service: input_number.set_value
  data_template:
    entity_id: input_number.heizung
    value: '{{ (float(states.number.stromuberschuss.state)) + (float(state.input_number.heizung)) }}'
metadata: {}
data: {}
target:
  entity_id: input_number.heizung

found here returns an error "“s.action.split is not a function or its return value is not iterable”

edit: error solved by TheFes. Correct code:

action: input_number.set_value
data:
  value: >-
    {{ (float(states('number.stromuberschuss'))) +
    (float(states('input_number.heizung'))) |float(0)}}
target:
  entity_id: input_number.heizung

Unfortunately, this only partially solves the original issue since the automation only triggers when the value changes, not when it is updated but remains identical.

Any suggestion on how i can
count up and down from 0-13 by the step size of “number.stromuberschuss” any time “number.stromuberschuss” updates? Thank you :slight_smile: .

As well as tsome other mistakes…

https://www.home-assistant.io/docs/configuration/templating/#states

value: "{{ states('number.stromuberschuss')|float + states('input_number.heizung')|float }}"

If there is any chance your number entity can be unavailable or unknown you should supply a default value, e.g. for zero use |float(0)

Thanks tom.

Amended to

action:
  service: input_number.set_value
  data_template:
    entity_id: input_number.heizung
    value: >-
      {{ (float(states('number.stromuberschuss'))) +
      (float(states('input_number.heizung'))) |float(0)}}
metadata: {}
data: {}
target:
  entity_id: input_number.heizung

However, the error persists.
I now also get “Message malformed: value should be a string for dictionary value @ data[‘actions’][0][‘action’]”

value: "{{ states('number.stromuberschuss')|float(0) + states('input_number.heizung')|float(0) }}"

You are putting an action with really old syntax (service instead of action and data_template instead of data) as the action. So you are nesting the action itself under the action key.

You should do this:

action: input_number.set_value
data:
  value: >-
    {{ (float(states('number.stromuberschuss'))) +
    (float(states('input_number.heizung'))) |float(0)}}
target:
  entity_id: input_number.heizung
1 Like

Thanks again, copy pasted. The editor in the automation will change it to

value: >-
      {{ states('number.stromuberschuss')|float(0) +
      states('input_number.heizung')|float(0) }}

uppon saving. The two error messages persist.

Thanks TheFes. This eliminated both error messages. and the automation behaves like expected. unfortunately, after some testing, it appears that it will only trigger when the value changes, not when the value updates but remains identical.
Is there any way to trigger an automation if a value updates instead of the value changing?
(example: PV is constant at 800w, as is the heater, Shelly reads 0w consumption. A first light is switched on and consumes 100w, shelly shows 100w consumption the automation triggers and and turns the heater down from 800w to 700w. Before the next tick, a second light is switched on for a total consumption of 200w. Thus Shelly remains at 100w, the automation does thus not trigger and the heater remains at 700w instead of switching down to 600w.

Based on that I think you’re approaching this wrong. But you only shared this one action, so please share your complete automation, and describe your goal.

:slight_smile: Thanks for taking an interest. I have tried in the original post above, but i can do my best to reiterate:
Over all Goal: Control an electric heaters energy consumption based on excess energy values recorded for the entire home.
Goal in home assistant: Control an input_number.ID to alternate between 0 and 13 (0w-1300w) depending on the amount total energy consumption of the home recorded by a shelly sensor.

My current approach:

  1. Creating a number template Helper in HA to transform the shelly data into instructions for the heater. Code:
{{(((float(states.sensor.shelly_pro_eem_total_active_power.state) ) /100) | round(0,"ceil", default)) * (-1)}}

This transforms for example -237.566w from shelly into +2 (+200w) for the heater.
2. Create an input value entity in Ha limited to 0-13 (0-1300w) expected energy consumption in the UI. This value is read by the ESP controlling the heater to set the required heater consumption.
3. Connect the two in a way to achieve above goal with an automation. Code:

trigger: state
entity_id:
  - number.stromuberschuss
action: input_number.set_value
data:
  value: >-
    {{ (float(states('number.stromuberschuss'))) +
    (float(states('input_number.heizung'))) |float(0)}}
target:
  entity_id: input_number.heizung

This solution will work in most cases, except for a change in the heater energy consumption being negated by a change in the remaining home power consumption/production to 100w precision, and thus the ‘number.stromuberschuss’ staying constant and thus the automation not triggering, when it should.
I might be able to get around this by additionally triggering the automation at constant time intervals, but this is a bit fiddels and the time intervals depend on the original sensor update intervals and how fast the heater switches.

The heater uses ventilated PTC heater elements which do not exactly consume their rated power which is why i would rather not rely on the heater consuming exactly what it is set to, which is why i want to avoid making that assumption part of the control loop.

If you see any easier / better way to do this feel free to share it.:slight_smile: