Virtual sensor based on value change of an entity

I want to monitor a power measure entity for increase in power and when the increase is within certain values (eg. 300-600W) then to change state to ON. When decreases withing the same values then change state back to off.
So if lets say the entity shows 2100 and next value is 2500, then change the state of the virtual sensor to on.

I want to monitor like that power measure entities on all 3 phases and then I want to have a group where all 3 virtual sensors will be indicating whether the 3 phase appliance is on or off.

What is the easiest or the best way to achieve something like that?

The statistics integration can calculate the “change” of a sensor, there’s an example of it on the page. That might do exactly what you want.

Then, I’d make use of the a template binary sensor to take that info and turn it into an “on/off” entity.

Last, I’d use the group integration to make a binary sensor that turns on when the template binary sensors above turn on. It’s completely possible to do this using another template binary sensor, and the advantage is that you’d have a lot more control. Like you could say “if phase1 change is greater than 100, and phase2 change is greater than 300, and phase3 change is greater than 500, then turn on”. The group integration is just basic, "if all these sensors are on, then turn on.

sensor:
  - platform: statistics
    name: "Device Phase 1 Power Change Over 5 Minutes"
    entity_id: sensor.device_phase1_power
    state_characteristic: change
    max_age:
      minutes: 5
    sampling_size: 50
    precision: 1
    ...
    #<same thing for phase 2 & 3>
    ...

template:
  - binary_sensor:
      - name: "Device Phase 1 Power"
        device_class: "power"
        state: >
          {{ if states('sensor.device_phase_1_power_change_over_5_minutes') | float(0) > 300 }}
      ...
      #<same thing for phase 2 & 3>
      ...

binary_sensor:
  - platform: group
    name: "Device Power"
    device_class: power
    all: true # This changes the behavior, up to you how you want it
    entities:
      - binary_sensor.device_phase_1_power
      - binary_sensor.device_phase_2_power
      - binary_sensor.device_phase_3_power

And just in case the change part of the statistics integration doesn’t do what I think it does, you could still use a mean or moving average to accomplish something similar. In the template binary sensor, just compare the average to the current value. “If the difference between instantaneous power and the average is greater than 300, then turn on”.

1 Like

Here is my code:

sensor:
  - platform: statistics
    name: "Device Phase 1 Power Change Over 15 Seconds"
    entity_id: sensor.solax_measured_power_l1
    state_characteristic: change
    max_age:
      seconds: 30
    sampling_size: 50
    precision: 1
  - platform: statistics
    name: "Device Phase 2 Power Change Over 15 Seconds"
    entity_id: sensor.solax_measured_power_l2
    state_characteristic: change
    max_age:
      seconds: 30
    sampling_size: 50
    precision: 1
  - platform: statistics
    name: "Device Phase 3 Power Change Over 15 Seconds"
    entity_id: sensor.solax_measured_power_l3
    state_characteristic: change
    max_age:
      seconds: 30
    sampling_size: 50
    precision: 1

template:
  - binary_sensor:
      - name: "Device Phase 1 Power"
        device_class: "power"
        state: >
          {% if states('sensor.solax_measured_power_l1') | float(0) < -250 %}
          {% endif %}
      - name: "Device Phase 2 Power"
        device_class: "power"
        state: >
          {% if states('sensor.solax_measured_power_l1') | float(0) < -250 %}
          {% endif %}
      - name: "Device Phase 3 Power"
        device_class: "power"
        state: >
          {% if states('sensor.solax_measured_power_l1') | float(0) < -250 %}
          {% endif %}

binary_sensor:
  - platform: group
    name: "Nautilus Pump status"
    device_class: power
    all: true # This changes the behavior, up to you how you want it
    entities:
      - binary_sensor.device_phase_1_power
      - binary_sensor.device_phase_2_power
      - binary_sensor.device_phase_3_power

The sensor section seem to work fine. Problem is that the sensor gives a negative value and therefore is not detected as power increase but decrease. So instead of 300W it shows -300W.
I tried to change

{% if states('sensor.solax_measured_power_l1') | float(0) < -250 %}

but it does not do anything and I am not very good in yaml syntax

image

Another tricky part might be to keep the status of the appliance ON until we read the same power drop which will be detected as positive, therefore as increase of the power. Weirdly enough when it happens now, the state of appliance still does not change, which definitely should, not sure where the problem is.

But thank you anyway, we are getting there slowly! :slight_smile:

As for the another solution, I am not sure if the average value will work properly compared to the current value. I would rather prefer to store the current value somehow and change it to another variable old and them compare.
I started this simple code, but need to figure out how to do the sleep command plus whether it can actually work this way.

template:
  - sensor:
      - name: "L1 monitor"
        state: >
          {% set first = states('sensor.solax_measured_power_l1') | float %}
          sleep 15
          {% set second = states('sensor.solax_measured_power_l1') | float %}
          
          {{ second-first }}

not sure if it can work this way, need to also figure out the

{% if states('sensor.solax_measured_power_l1') | float(0)  > 250 %}

Two thoughts here. First, I think I made a mistake in how this is written. If you use the {{ }} brackets, you shouldn’t need the if. Second, there’s an absolute value filter as well, so you can catch any positive or negative change above a threshold. Try:

{{ states('sensor.solax_measured_power_l1') | float(0) | abs > 250 }}

That should output True or False, which should correctly turn on the binary sensor.

Gonna split up my replies, second one coming in a few minutes. EDIT: Sorry! I’m falling asleep. I’ll have to finish it in the morning.

I changed the code to {%… because {{… was giving me errors, did not know that you can skip “if” with two brackets, I will change it.

I will also try to measure against absolute value, however the code will also have to establish whether the energy is increasing or decreasing to indicate whether we set the value of the sensor to ON or OFF.
Ultimately I want to watch whether the sensor value is ON and for how long before it is changed to OFF so I can set up some automation.

Those 2 bellow should help as the first one confirms the threshold and the second one should indicate the change to OFF state if true. So if the first one is true and the second one if false, then I want to set the sensor state ON.

{{ states('sensor.solax_measured_power_l1') | float(0) | abs > 250 }}
{{ states('sensor.solax_measured_power_l1') | float(0) > 250 }}

The use case here is when the pressure switch brakes down(which just happened) and the pump is working for more than 10 seconds, turn it off to prevent the pump from overheating and send the alarm, but that part should be pretty easy.