Having issues using DataUpdateCoordinator

I’m trying to setup a platform that uses one API call to update multiple sensors. I have been directed toward using the DataUpdateCoordinator object to handle polling of the API then scheduling sensors to update based on the data it gets. It looks like a pretty slick thing to use, but I’m running into some issues.

The API library I’m using isn’t “async friendly” so I’m trying to write this platform without using async functions, but it appears that DataUpdateCoordinator needs an async function for it’s update_method parameter (I might be wrong though, the documentation I have doesn’t talk about that very much). That’s all I have been able to figure out. I’m fairly new to python (but not programming, I’m very versed in Java) and the whole concept of async programming, so please forgive my gaps of knowledge.

This is how I’m creating my coordinator.

async def async_poll_api(hass):
        #poll API here, grab the things I need from it, and set it to data
        return data

coordinator = DataUpdateCoordinator(
        hass,
        _LOGGER,
        name="sensor",
        update_method=async_update_data,
        update_interval=timedelta(seconds=30), 
    )

and I’m getting this error message

Traceback (most recent call last):
  File "/workspaces/core/homeassistant/setup.py", line 213, in _async_setup_component
    result = await task
  File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/workspaces/core/homeassistant/components/my_custom/__init__.py", line 141, in setup
    coordinator = DataUpdateCoordinator(
  File "/workspaces/core/homeassistant/helpers/update_coordinator.py", line 57, in __init__
    request_refresh_debouncer = Debouncer(
  File "/workspaces/core/homeassistant/helpers/debounce.py", line 34, in __init__
    self._execute_lock = asyncio.Lock()
  File "/usr/local/lib/python3.8/asyncio/locks.py", line 164, in __init__
    self._loop = events.get_event_loop()
  File "/usr/local/lib/python3.8/asyncio/events.py", line 639, in get_event_loop
    raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'SyncWorker_3'.

I hate to ask for help in situations like these, but I’ve stared at it for a long time now and have gained no progress. Any point in the right direction would be much apricated! Thank you!

That won’t quite work as it’s doing a network call that isn’t suspending execution. Check out the “Sync From Async” heading in this article for a brief explanation.

To answer your question since the library is synchronous you can use the async_add_executor_job method of the hass instance to run a synchronous function in an asynchronous fashion. Here’s an example.

In your case it might look something like:

async def async_poll_api(hass):
        #poll API here, grab the things I need from it, and set it to data
        data = await hass.async_add_executor_job(some_api_instance.fetch, "some arg")
        return data

coordinator = DataUpdateCoordinator(
        hass,
        _LOGGER,
        name="sensor",
        update_method=async_poll_api,
        update_interval=timedelta(seconds=30), 
    )

Note that the update_method argument doesn’t take any parameters, so if you need access to the hass instance you may want to sub-class DataUpdateCoordinator and override the _async_fetch_data method. Then you can access the instance of hass that is set as an attribute on the class.

1 Like

Thank you for the quick and well written answer. You went above and beyond with your explanation. Thank you!