The numeric state trigger should coerce strings to numbers

This falls somewhere between a configuration question and feature request.

I have a number of automations that monitor numeric states and trigger upon exceeding some threshold—exactly the sorts of tasks the numeric state trigger is intended to perform. However, in practice, it rarely works for me and I typically use a template trigger to accomplish the same thing.

As others have pointed out, the problem is many numeric states are returned as strings, which you can verify in the dev template pane:

# This fails
{{ states.sensor.ram_used.state > 0 }}
# This works
{{ states.sensor.ram_used.state | float > 0 }}

According to the numeric state trigger’s docs:

On state change of a specified entity, attempts to parse the state as a number

suggesting that some attempt is made to coerce strings to numbers but I haven’t seen any evidence of this and the following strategy doesn’t work:

# approach 1
- alias: 'CPU used - numeric state only'
  trigger:
    platform: numeric_state
    entity_id: sensor.cpu_used
    below: 100
  action:
    - service: notify.slack
      data:
        message: Docker numeric state CPU used.

which is a shame, because it’s the most straight forward approach and feels like the right tool for the right job.

I thought I could workaround this issue by using value_template to perform the coercion:

# approach 2
- alias: 'CPU used - numeric state with value template'
  trigger:
    platform: numeric_state
    entity_id: sensor.cpu_used
    value_template: "{{ state.state | float }}"
    below: 100
  action:
    - service: notify.slack
      data:
        message: Docker numeric state with value template CPU used.

but this too fails and I’m not sure why but would appreciate feedback if I’m missing something.

Ultimately, I end up using the follow approach almost everywhere:

# approach 3
- alias: 'CPU used - template'
  trigger:
    platform: template
    value_template: "{{ states.sensor.cpu_used.state | float < 100 }}"
  action:
    - service: notify.slack
      data:
        message: Docker template CPU used.

which is fine, it works, but seems inelegant. I’ve also seen claims that there is a higher than usual performance cost associated with template triggers.

I’m posting this here in case anyone else has run into this issue and could benefit from my testing.

I help someone with this problem pretty much every day.

Thanks, @treno—glad I’m not the only one. Do you end up using/recommending template triggers as a workaround?

typically.

The list goes on…

That’s a good list. The reason I added this here was in hopes that it might inspire someone with the necessary python skills to implement auto string conversion. :crossed_fingers:

Do I get it correctly, that the problem actually isn’t really the numeric trigger, but instead the components that incorrectly output their states as strings instead of numbers? If so, then coercing would make sense, but would actually just be a workaround for a problem within the components. If someone decides to handle this issue I would add a warning log message so components that behave that way will be noticed, or alternatively add an option to force coercing if needed.

There are several contributing factors that lead to this problem.
Yes, one is that components output their states as strings. You can make a case as to whether this is “incorrect” or not.
In some cases, it clearly is. For example, the new counter component outputs its state as a string. This is clearly incorrect.

Another contributing factor is there is no clear way to identify the type of the output. The “states” developer tool lists the state for a counter as 0 not “0” or ‘0’. This is misleading, and leads to this problem.

Even the template tool doesn’t identify an output type. I have a counter called counter.count1. The template {{states.counter.count1.state}} outputs 0 not ‘0’ or “0” but if I evaluate the template {{states.counter.count1.state > 0}} I get no result. This indicates the comparison is invalid.

Also, though there is the numeric state trigger. or at least the documentation of the numeric state trigger. As identified above, the docs say “attempts to parse the state as a number”. Perhaps it does, I haven’t looked at the source code. But clearly it fails to parse a “0” to a 0 and since that fails, I don’t know what kind of parsing would be successful.

What you describe sounds like a bug. The code does coerce to float, right here.

However, I cannot reproduce the bug. I tried your “approach 1” and it works for me.

An important difference is when the expression is already true during startup: the template will trigger but numeric_state will not. The numeric_state only triggers when the threshold is actually crossed. This is arguably also a bug.

I looked at a few of the links and the posters seem to expect the automation to execute if the trigger expression is true, which is different from the trigger expression turning true.

2 Likes

Did some more testing. This looks like the answer!

I use time instead of numeric trigger to get around this. (i used brightness as a numeric timer which works)

automation lock_timer_pos:
  trigger:
    platform: time
    seconds: '/1'
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: switch.lockstatus
        state: 'off'
      - condition: numeric_state
        entity_id: light.lock_timer
        value_template: '{{ state.attributes.brightness }}'
        above: 2
        below: 100
  action:

Woah, @amelchio. I think you nailed it. And exposed some flawed assumptions in my testing along the way.

I also think you’re right that the numeric_state state should trigger if it evaluates to true during startup.

Anyway, that answers my question. I really appreciate everyone’s input in helping me solve this mystery!

I now filed PR #10125 to raise awareness of the issue with the core developers.

Let’s see what they think … :slight_smile:

1 Like

I think, we should also clarify in the docs that numeric_state requires a number. I will create PR soon.

@arsaboo I believe the conclusion is that no such clarification is needed, that part works as expected and already documented.

Some clarification on the behavior during startup is obviously needed but at this time I am not sure what it should be.

I’m confused. Was template changed in 0.57 to match numeric_trigger or vice versa? My observation is the former, as my numeric triggers are not firing on startup but are on state changes.

What do I use if I want a notification on startup if a sensor value is above or below a set threshold?

The numeric_state trigger was changed. It will not fire on startup though, but on the first updated value.

The change is that it will fire on the first update even if the startup value was above threshold.

If you show your automation I can probably explain what happens.

A work in progress still, but this is the idea:

  - alias: Detect upcoming freezing weather
    trigger:
      - platform: numeric_state
        entity_id: sensor.dark_sky_daily_low_temperature
        below: 2.0
      - platform: numeric_state
        entity_id: sensor.dark_sky_daily_low_temperature_1
        below: 2.0
      - platform: numeric_state
        entity_id: sensor.dark_sky_daily_low_temperature_2
        below: 2.0
      - platform: numeric_state
        entity_id: sensor.dark_sky_daily_low_temperature_3
        below: 2.0
      - platform: numeric_state
        entity_id: sensor.dark_sky_daily_low_temperature_4
        below: 2.0
      - platform: numeric_state
        entity_id: sensor.dark_sky_daily_low_temperature_5
        below: 2.0
      - platform: numeric_state
        entity_id: sensor.dark_sky_daily_low_temperature_6
        below: 2.0
      - platform: numeric_state
        entity_id: sensor.dark_sky_daily_low_temperature_7
        below: 2.0
    action:
      - service: notify.notify
        data:
          message: "Freezing weather in forecast!"
          title: "Weather warning"
      - service: automation.turn_off
        entity_id: automation.detect_freezing_weather
      - delay:
          hours: 24
      - service: automation.turn_on
        entity_id: automation.detect_freezing_weather

my Dark Sky sensors update every 10 minutes, so you’re telling me if any of my sensor states are < 2 then I should get a notification at most 10 minutes after my automation is enabled, regardless of their state at the time automation was enabled?

I am afraid it will only fire if the value changes, for example from 1.8 at startup to 1.9.

If you really want to be notified during startup then you will have to work with the homeassistant_start event.

What if I want it to fire not just at home assistant startup but after startup as soon as the automation is enabled (if the sensor value is below 2)

I may be missing something, and no offence to those who worked on this pull request, but this seems like a reasonably big limitation, especially if you consider sensors that have values that don’t change very frequently but you need to know ANY time the value is above or below a threshold, and promptly.