How to update entity without RuntimeError("Cannot be called from within the event loop")

Here is the background:
I am extending a custom component from HACS. It includes 2 sensors which pull in data from 2 cloud sources; both have details about the expected precipitation but are ‘unparsed’ and used for a frontend card.

The extension i’ve made combines both sources. From my combined data, i want to expose 4 new sensors.

In my ‘combination’ logic sensor, i’ve subscribed to state changes;

async_track_state_change(hass, [ "sensor.neerslag_buienalarm_regen_data", "sensor.neerslag_buienradar_regen_data" ], self.parse_rain_source_data)

This means that whenever either of the sources update, my method self.parse_rain_source_data executes.

In the meantime, i have also registered my new sensors, one is called “sensor.is_it_raining” which I want to update from my callback method;

    @callback
    def parse_rain_source_data(self, entity_id, old_state, new_state):

However, whenever i try to call from within that callback

self.hass.states.set("sensor.is_it_raining", "yes")

Hass bails with an error:

  File "/config/custom_components/neerslag/sensor.py", line 421, in update_sensor_state_and_attributes
    self.hass.states.set(entity_id, new_state, inputAttributesObject, True)
  File "/usr/src/homeassistant/homeassistant/core.py", line 1286, in set
    run_callback_threadsafe(
  File "/usr/src/homeassistant/homeassistant/util/async_.py", line 51, in run_callback_threadsafe
    raise RuntimeError("Cannot be called from within the event loop")
RuntimeError: Cannot be called from within the event loop

And i have no clue how to solve this :slight_smile: Any pointers so that i can update the sensor states in this callback?

Anybody from the devs maybe?

IMO you’re approaching this from an odd angle. If you’re extending an existing integration, you should just extend it properly by adding the 4 additional sensors using the metadata instead of the other states.

Otherwise, if you’re planning on creating a completely new integration that uses existing sensors, then you should look at one of the utility integrations. Many of them contain the information you’re looking for.

For example:

    async def async_added_to_hass(self):
        """Handle added to Hass."""
        self.async_on_remove(
            async_track_state_change_event(
                self.hass,
                [ "sensor.neerslag_buienalarm_regen_data", "sensor.neerslag_buienradar_regen_data" ],
                self.parse_rain_source_data,
            )
        )

    @callback
    def parse_rain_source_data(self, event):
        """Handle sensor state changes."""
        if (new_state := event.data.get("new_state")) is None:
            return

        #do everything else here

        # end with with a "yo write the state"
        self.async_write_ha_state()