Trend sensor in ESPHome

In Home assistant you can define binary trend sensors like this:

binary_sensor:
- platform: trend
  sensors:
   house_stove_pipe_temp_falling:
     entity_id: sensor.house_uart_pipe_temp
     sample_duration: 10
     max_samples: 10
     min_gradient: -0.2 #5 degrees / 10s
     device_class: cold
 
   house_stove_pipe_temp_rising:
     entity_id: sensor.house_uart_pipe_temp
     sample_duration: 10
     max_samples: 10
     min_gradient: 0.2 #5 degrees / 10s
     device_class: heat           

They go TRUE when the conditions are met.

Has anyone figured out a way to get the same or similar functionality in ESPHome? My use case can’t depend on home assistant so the logic needs to reside in the ESP.

Use lambdas?

  - platform: template
    id: switch1
    internal: true
    lambda: |-
      if (id(sensor_push_switch_1).state < 95.0) {
        return true;
      } else {
        return false;
      }

That isn’t a trend sensor.

There should be a derivative library for arduino out there somewhere though :slight_smile:

hey @nickrout
true, but the question was asked wrong :wink:

Yes but those conditions are for a derivative or trend.

That’s not a trend. That’s comparing an absolute value.
A trend is comparing the slope of a trend line… and when the slope is detected, the binary sensor goes TRUE.

Derivatives. Integrals. Area under the curve. Uggggg. I should have stayed awake in my advanced calculus classes in college 35 years ago. My dog ate my homework…

What i ment is, you can make a slope calculation using lambda…

Someone who doesn’t have a dog who ate their homework could probably write a lambda! My advanced math skills are looong gone. That’s why math libraries were created!

@nickrout I agree, there must be a library out there somewhere.

Yes but you need something saving the last sensor value to compare it to the current one to establish a slope. Or the last 10 sensor values, or whatever accuracy you want.

Better than my dog who ate a file in the office yesterday!

Yes that is the right track, find a library, implement it via a custom c++ sensor.

Speaking of school, we only did BASIC. Fortran at Uni.

That was the whole reason someone created the trend sensor for home assistant. Because it’s not trivial!

Fortran!! Yup, been there and 8086 assembler. I had to put a reset button on my pc… :weary:

Perhaps this GitHub - twrackers/Calculus-library: Arduino library to provide basic calculus functions, including integral and derivative, for fixed-step sampled data.

PS there is a PID controller in esphome, and PID depends on derivatives, so there is some support for it in esphome.

I see that! I use a PID controller on my ESPHome Solar battery heaters!

That’s an interesting library but it doesn’t have trends. And I’ve never used libraries so I wouldn’t even know where to begin…

Could you setup an internal sensor, and use that to store values?

globals:
  # Dim direction for Switch 1: 0=Up (brighten) 1=down (dim)
  - id: g_direction_1
    type: int
    restore_value: no
    initial_value: "1"
  # Counter for time pressed for switch 1
  - id: g_counter_1
    type: int
    restore_value: no
    initial_value: "0"

# Polling object for long press handling of switch for dim/brighten cycle
interval:
  - interval: 20ms
    then:
      - if:
          condition:
            binary_sensor.is_on: switch1
          then:
            # Ramp rate for dim is product of interval (20ms) * number of intervals
            # Every 20ms Dimmer is increased/decreased by 2/255
            # Lower limit = 10%
            # Upper limit = 100%
            # 100% - 10% = 90% = 230/255. Therefore 230/2 * 20ms = 2.3 seconds for full range
            # At full/min brightness - further 16x20ms = 0.32 Seconds "dwell" by resetting counter to 0
            # Initial pause for 16x20ms = 0.32s to allow "on_click" to be discounted 1st
            # g_direction_1 = 0 (Increasing brightness)
            # g_direction_1 = 1 (decreasing brightness)
            # g_counter_1 = Interval pulse counter

            lambda: |-
              float curr_bright = id(light_main_1).remote_values.get_brightness();
              id(g_counter_1) += 1; 

              // If max bright, change direction
              if (curr_bright >= 0.999 && id(g_direction_1) == 0) {
                id(g_direction_1) = 1;
                id(g_counter_1) = 0;
              }

              // If below min_bright, change direction
              if (curr_bright < 0.1 && id(g_direction_1) == 1) {
                id(g_direction_1) = 0;
                id(g_counter_1) = 0;
              }

              if (id(g_direction_1) == 0 && id(g_counter_1) > 15) {
                // Increase Bright
                auto call = id(light_main_1).turn_on();
                call.set_brightness(curr_bright + (2.0/255.0));
                call.perform();
              }

              else if(id(g_direction_1) == 1 && id(g_counter_1) > 15) {
                // Decrease Bright
                auto call = id(light_main_1).turn_on();
                call.set_brightness(curr_bright - (2.0/255.0));
                call.perform();
              }

(again just an example for inspiration) :slight_smile:

Btw going back all the way to hex coding machine language here :stuck_out_tongue:

A trend is just a differentiator, it is the “slope” of a graph of the sensor value vs time.

Interesting. I’d have to wrap my pea-sized brain around that code.

In my head I see this pseudo code: Store a bunch of samples (10) round robin FIFO style in an array and do math on the samples in the bucket after each new sample arrives. If the math checks out (the slope is up or down or flat) set a binary sensor or better yet, text global to 'heating/idle/cooling"

Translating that to ESPHome code is a different story.

1 Like