Trigger sensor update, despite no sensor change? trigger mqtt update

I’ve solved this as follows:

Automation:

alias: refresh energy usage
description: ''
trigger:
  - platform: time_pattern
    minutes: /29
condition:
  - condition: state
    entity_id: sensor.gas_consumption_5m
    state: '0.0'
    for:
      hours: 0
      minutes: 5
      seconds: 0
      milliseconds: 0
action:
  - data:
      entity_id: sensor.gas_consumption_5m
    service: python_script.force_update_state_gasverbruik
mode: single

python_script.force_update_state_gasverbruik:

sensor = data.get('entity_id')
hass.states.set(sensor,0.0,{'source': 'sensor.gas_consumption','unit_of_measurement': 'm3/uur','friendly_name': 'gas_consumption_5m','icon': 'mdi:chart-line'},force_update=True)

The second line of this python script can be made dynamic as well if you want to (by using ‘entity_id’)

edit: please note that this solution will only work for sensors that go back to zero (which is the case for water and gas consumption, but most likely not for temperature and humidity sensors)

Hi, what about the following python script? This might work, it is not throwing any errors for me at least.

entity_id = data.get('entity_id')
current_state = hass.states.get('entity_id')
current_source = state_attr(entity_id,'source')
current_unit_of_measurement = state_attr(entity_id,'unit_of_measurement')
current_friendly_name = state_attr(entity_id,'friendly_name')
current_icon = state_attr(entity_id,'icon')

hass.states.set(entity_id, current_state, {'source': current_source,'unit_of_measurement': current_unit_of_measurement, 'friendly_name': current_friendly_name, 'icon': current_icon},force_update=True)

Sorry, this hopefully works:

entity_id = data.get('entity_id')
current_entity = hass.states.get(entity_id)
current_state = current_entity.state
current_source = current_entity.attributes.get('source')
current_unit_of_measurement = current_entity.attributes.get('unit_of_measurement')
current_friendly_name = current_entity.attributes.get('friendly_name')
current_icon = current_entity.attributes.get('icon')
hass.states.set(entity_id, current_state, {'source': current_source,'unit_of_measurement': current_unit_of_measurement, 'friendly_name': current_friendly_name, 'icon': current_icon},force_update=True)

Hi Pim,

Thanks for the response quick and in-depth response, but this is way above my paygrade, I don’t even know where to add this in the configuration. Seems like pretty advanced stuff to me at least (I have no coding knowledge at all :slight_smile: ) But my issue is not related to this topic and I think I should create my own one for this specific question right?

I have not done any automations yet, just added some devices, etc for now.

Any documentation I might read up on to wrap my head around stuff like this?

It’s not advanced. It’s an automation and a python script. Don’t put things on a pedistle because they “Look hard”. Read up on how to implement a python script (You don’t have to code it, he already did that). Then create the automation. You have 4 examples now that do what you want.

All solutions are somewhat suboptimal: they all have drawbacks:

  • This solution will throw an error (it worked in older versions of home assistant)
#pass entity_id as argument from call
sensor = data.get('entity_id')

#read old state
oldstate = hass.states.get(sensor)

#write old state to entity and force update to record database
hass.states.set(sensor, oldstate.state , oldstate.attributes, force_update=True)
  • homeassistant.update_entity will not work for most sensors (because it won’t force a new value in the database if the value is the same)
  • The Trigger-based Template Sensor with a Time Pattern Trigger is causing additional usage of resources and duplicate data in your database (the real sensor data + the copy of that data in the template sensor). More-over, changing the configuration in configuration.yaml requires a restart.
  • The solution of triggering a python script is tailor-made for each specific sensor
entity_id = data.get('entity_id')
current_state = hass.states.get('entity_id')
current_source = state_attr(entity_id,'source')
current_unit_of_measurement = state_attr(entity_id,'unit_of_measurement')
current_friendly_name = state_attr(entity_id,'friendly_name')
current_icon = state_attr(entity_id,'icon')

hass.states.set(entity_id, current_state, {'source': current_source,'unit_of_measurement': current_unit_of_measurement, 'friendly_name': current_friendly_name, 'icon': current_icon},force_update=True)

The nicest way would be if we could generalize the last solution (with the python script). Is there a way to copy-paste the attribute dictionary {attribute name: attribute value} into the hass.states.set function? My solution with the hardcoding is imo not the best way to approach this.

Yeah, you can get the state before hand and replace the items with your input.

I didn’t realize your code had all sorts of errors in it. Don’t confuse python with template methods. This does exactly what you’re looking to do, however you’d want to change the entity_id attribute that’s passed to the script to something other than entity_id. I suggest source. You’ll also notice that this is almost identical to what @a94marbo had in his original post. His post should still work without errors.

force_update_state.py

entity_id = data.get('source')
current_state = hass.states.get(entity_id)
hass.states.set(entity_id, current_state.state, current_state.attributes, force_update=True)

automation

- alias: 'Uppdate sensor'
  trigger:
    platform: time_pattern
    seconds: '/1'
  action:  
    - service: python_script.force_update_state
      data:
        source: sensor.xyz

That works. I changed the naming a little bit, so that end-users can still use the familiar name “entity_id” in the action section of the automations/scripts:

source = data.get('entity_id')
current_state = hass.states.get(source)
hass.states.set(source, current_state.state, current_state.attributes, force_update=True)

I’m not sure why this stopped working before (i don’t have the original script anymore, so i can’t replicate it anymore). Does not matter anymore, the above solution is working fine.

One question i do have. You mentioned “I didn’t realize your code had all sorts of errors in it. Don’t confuse python with template methods”.
The below code is working fine, but it lacks the dynamic features of the attribute polulation. What sort of errors do you mean (i guess i’m missing something)?

entity_id = data.get('entity_id')
current_state = hass.states.get('entity_id')
current_source = state_attr(entity_id,'source')
current_unit_of_measurement = state_attr(entity_id,'unit_of_measurement')
current_friendly_name = state_attr(entity_id,'friendly_name')
current_icon = state_attr(entity_id,'icon')

hass.states.set(entity_id, current_state, {'source': current_source,'unit_of_measurement': current_unit_of_measurement, 'friendly_name': current_friendly_name, 'icon': current_icon},force_update=True)

that’s not a real method. No idea how it’s working for you.

that’s an object.

hass.states.set requires a string in that field.

So I have no clue how that is working for you because every line is wrong.

And that completely misses the point of changing entity_id to source. entity_id is data item that home assistant frequently uses. If you keep that as entity_id in the service call, home assistant could replace it with an entity_id that is not the target entity you want. Hence why you should change the incoming field to source, which is what I did.

I want to clarify, the service call I’m referring to is this:

           ^
           |
 using entity_id here could cause home assistant to overwrite your value if incorrectly used.

For example, if a user did this:

    - service: python_script.force_update_state
      target:
        entity_id: python_script.force_update_state
      data:
        source: sensor.xyz

Yeah, it looks wrong, but it will cause problems. It’s best not to use that if you can.

1 Like

Awesome, thank you for taking the time for clarifying this!
Your explanation about why not to use entity_id might actually have been the cause of my issues before.

Hi, I suddenly realize what caused my issues before: recursion errors.

I just received the following error: “Error executing script: maximum recursion depth exceeded in comparison”.

This makes sense, because i ramped up the refresh rate a bit (from once every 50 minutes to once every 1 minute). The error logically disappears at the moment that a real measurement is registered by the sensor.

Is there a way to bypass this error? I would rather not like to increase the queue-depth in Python (it’s not very elegant). One method i was thinking about:

Functionally written out:

Every minute trigger a python script doing the following: 
* if timedifference "now" VS "last non-zero sensor-value"  is > 60 minutes: update the sensor with the hardcoded value 0
* if timedifference "now" VS "last non-zero sensor-value"  is < 60 minutes: update the sensor with the current state value

The sensors involved are measuring gas usage (m3/hour) and electricity power drawn at wall sockets, hence the 0-value proposal (the only way it can be 0 and unchanged for a prolonged period of time, if is there no usage at all).

Could something like this work out? I could use some help to write this out in Python. Any help is much appreciated.

This might solve my issue: Maximum recursion depth exceeded when executing python script. · Issue #26606 · home-assistant/core · GitHub
I’ll check it later today and report back.

Edit:

So far, this solution seems to be working, but with a side-effect:

entity_id = data.get('source')
current_state = hass.states.get(entity_id)
current_attributes = current_state.attributes.copy()

now = datetime.datetime.now()
nowstr = "%04d-%02d-%02dT%02d:%02d:%02d+00:00" % (now.year, now.month, now.day, now.hour, now.minute, now.second)

current_attributes['last_forced_update'] = nowstr

hass.states.set(entity_id, current_state.state , current_attributes, force_update=True)

When looking at the database, i can see that Home Assistant is correcting the attribute list (the last_forced_update attribute is removed 2 seconds after running the python script).

Clearly, this is not the best solution to the problem. Does anyone has a better idea?

avoid what you’re doing because it’s unnecessary…

Kindly explain yourself?

forcing updates on a sensor that doesn’t have or need an update is… pointless. You’re just filling your database and there’s no net gain from it at all. It doesn’t change anything on the graphs other than a point to hover on, and even then, then information is wrong because you planted it there.

You are right about that.

However, Grafana does not has an option yet to default to the value zero in a graph line when no datapoints are available in the selected time range. Instead, it is showing a message “no data in selected time range” . This is a shortcoming of Grafana. Therefore, i’m applying these updates as a workaround.

edit: there is a way in Grafana to force 0-values, but it comes with two drawbacks:
adding the following in the “group by”: $__timeGroup(“time”,‘1m’, 0). The drawbacks are: it’s bucketing the visual (i want to see the real values, not an adaptation), and it costs additional processing power.

Of course, in the ideal world, Grafana would adopt this functionality. But in reality, Grafana is not feature-complete (as compared to some other BI solutions) and a lot of important features are long-standing on the backlog of Grafana. Which all makes sense and is perfectly fine, given the fact that it is open-source. But that won’t solve my issue for now.

Given this background, i hope to made clear why i am looking for a work-around by adding 0-values in the sensor data. I fully agree that it should not be needed, and it causes database polution. But reality is, that my graphs won’t always populate if no sensor data is coming in for the choosen time period.

I’m looking for some help to get a work-around in place.

I have a modbus sensor where I’m trying to force the database to store data even if the data hasn’t changed. I’m using a modification of Petro’s script but it didn’t seem to work.

automations.yaml:

- alias: "Uppdate sensor"
  trigger:
    platform: time_pattern
    seconds: "/15"
  action:
    - service: python_script.force_update_state
      data:
        source: sensor.AirTemperature

In ~/config/python-scripts/force_update_state.py:

entity_id = data.get('source')
current_state = hass.states.get(entity_id)
hass.states.set(entity_id, current_state.state, current_state.attributes, force_update=True)

In the Logbook I see Update sensor triggered by time pattern, which tells me it should be working.
When I watch the data I still only see updates happening when the value changes instead of forcing data to get stored.

Is it just not possible to do this with a modbus sensor, even with a Python force_update?

entity_id’s do not have capital letters.

Updated automations.yaml:

- alias: "Update sensor"
  trigger:
    platform: time_pattern
    seconds: "/15"
  action:
    - service: python_script.force_update_state
      data:
        source: sensor.airtemperature

Still no change. I see the updates in the Home Assistant Logbook but I don’t see any data hitting InfluxDB. Maybe it’s a limitation on the InfluxDB side.

This script forces the change in the state machine, nothing lower (influx)