Use last value instead of unknown

I have a weather station that sometimes loses its connection due to distance from the router.
All the values it posses turn to “unknown” for a few seconds, even a minute and it’s very annoying to see it on the UI.
Is there anything I can do to let it display the last known value (without cloning all the sensors using templates or something like that?)

Without knowing how it is integrated, no.

I’m not sure how you could really do this without templates. If it loses connection there’s not much you can do about it because the integration (presumably) is populating those sensors and you have no control, so a template weather device and/or a series of sensors is likely the only way to control it.

Thought that might be the case, how would one look, let’s say something like sensor.outside_temp?
I suppose you can do an if/else in the template but how do you set the last known value before it goes to unknown?

Use this.state to get the last known value.

In the following example (a fragment of a Template Sensor), if the value of sensor.outside_temp is not unknown or unavailable then that value is reported. Otherwise the Template Sensor uses its existing value (this.state).

  state: >
    {% set x = states('sensor.outside_temp') %}
    {{ x if has_value(x) else this.state | default(0, true) }}

The default is there for this reason:
When you first create the Template Sensor, it won’t have an existing value for this.state. So if at that moment sensor.outside_temp has the bad luck of being unknown or unavailable then default will be used to report 0.

NOTE

Perhaps a better way to do this is to create a Trigger-based Template Sensor with a State Trigger that listens for changes to sensor.outside_temp but ignores any state-change to unknown or unavailable (using the not_to option). A Trigger-based Template Sensor retains its value after a restart.

template:
  - trigger:
      - platform: state
        entity_id: sensor.outside_temp
        not_to:
          - unknown
          - unavailable
    sensor:
      - name: Outside Temperature
        state: '{{ trigger.to_state.state }}'
        device_class: temperature
        unit_of_measurement: '°C'

EDIT

Corrected typo.

8 Likes

This isn’t quite correct. A sensor could legitimately go unknown or unavailable. What we need is for HA not to declare a sensor unavailable or unknown across a reboot or restart for deep-sleeping ESP Home sensors that only report periodically. We need a user-settable time period without a report before a sensor state is set as unknown or unavailable. Of course, this could be set up with messy complicated maintenance intense helpers and global state variables but it should be built-in because HA restarts are SOP. I’m sure HA already has the last report time for every sensor. I have lots of integrated devices that maintain last-state across reboots. It’s the ESP Home API sensors that forget.

The logic would be something like save and report the last known state until changes or there is no update for xx seconds where xx can be 1 to 9999999

Can you identify the part of what I wrote that was incorrect? I don’t recall saying that unknown or unavailable are not legitimate states.

The way I read it, your trigger would ignore changes to unknown or unavailable. Without a set time period for a sensor to become unknown or unavailable, the concept is incomplete

What I posted wasn’t passing judgment on the legitimacy of unknown or unavailable, it was merely a means to fulfill sd_dracula’s requirement to report the ‘last known (numeric) value’ in lieu of those two states.

The weather station’s sensors can still report unknown or unavailable (thereby indicating a problem with the physical device and/or integration) but the suggested Template Sensor will, as per the OP’s choice, mask the occurrence by reporting the previous state value.

1 Like

So how would you create a template that does keep the last state for a set period of time but wouldn’t persist if the device was offline for whatever reason?

I don’t know of any way other than to store the value into a helper.

You can do all of this with trigger-based template sensors. Explain exactly what you want to happen.

For example, you can trigger off a sensor going offline:

  - trigger:
      - platform: state
        entity_id: sensor.outside_temp
        to:
          - unknown
          - unavailable

or off the state not changing for a given time:

  - trigger:
      - platform: state
        entity_id: sensor.outside_temp
        for: "00:10:00"

You can set ids for these triggers and use them in the state-setting template. Test the last change of a sensor like this (last state change in seconds):

{{ (now() - states['sensor.ID']['last_changed']).total_seconds() }}

How you combine those depends on how your sensor behaves and what you want to achieve.

If anyone needs more specific support:

I solved it this way (according to your inspiration): updating the value to a numerical value every time the input sensor is updated. If the value has not changed for half an hour, the value is set to 0. I also created a frequent changing attribute here (time since last measurement) to feed the influxdb - in this case every 30 minutes - for a consistent display of the diagram (fill-below-to function in Grafana)

    - trigger:
        - platform: state
          entity_id: sensor.symo_12_5_3_m_power_ac
          not_to:
            - unknown
            - unavailable
          id: online
        - platform: state
          entity_id: sensor.stromleistung_pv
          for: 00:30:00
          id: offline
      sensor:
        - name: Stromleistung PV
          unique_id: "stromleistung_pv"
          state_class: "measurement"
          unit_of_measurement: "W"
          device_class: "power"
          state: >
            {% if trigger.id == "online" %}
                {{trigger.to_state.state}}
            {% elif trigger.id == "offline" %}
                {{0}}
            {% endif %}
          attributes: #für regelmäßige Werte in der Nacht
            Letzter Messwert (h): >
                {{ ((now().timestamp() - as_timestamp(states.sensor.stromleistung_pv.last_changed))/3600)|round(0) }}
            Status: >
                {{trigger.id}}

Maybe an expert among you can tell me whether the sensor can be made simpler in some way, it seems relatively “inflated” to me now.

I started my first attempts with a normal template sensor and the lambda function, but it failed because as soon as the input sensor was set to “unavailable” or was no longer updated and accordingly the template sensor was no longer updated, although when a template sensor was created via the graphical interface it was specified that the sensor would be updated “at the beginning of every minute” as soon as a time function (timestamp) is applied - so the timestamp of the sensor no longer produced any output:

     state: >
            {% set current_timestamp = now().timestamp() %}
            {% set fronius_state = states.sensor.symo_12_5_3_m_power_ac.state %}
            {% set fronius_timestamp = as_timestamp(states.sensor.symo_12_5_3_m_power_ac.last_changed) %}
          
            {% if fronius_state != 'unavailable' %}
                {{fronius_state}}
            {% elif current_timestamp - fronius_timestamp > 1800 %}
                {{0}}
            {% endif %}