CJNE / ha-myenergi

Home Assistant integration for MyEnergi devices
MIT License
150 stars 33 forks source link

Detected blocking call to load_verify_locations with args (<ssl.SSLContext object at 0x70ff42e77dd0>,) #577

Closed ProximusAl closed 1 month ago

ProximusAl commented 2 months ago

New version of HomeAssistant docker now throws this…

Detected blocking call to load_verify_locations with args (<ssl.SSLContext object at 0x70ff42e77dd0>,) inside the event loop by custom integration 'myenergi' at custom_components/myenergi/init.py, line 107: await self.client.refresh() (offender: /usr/local/lib/python3.12/site-packages/httpx/_config.py, line 147: context.load_verify_locations(cafile=cafile)), please create a bug report at https://github.com/cjne/ha-myenergi/issues For developers, please see https://developers.home-assistant.io/docs/asyncio_blocking_operations/#load_verify_locations Traceback (most recent call last): File "", line 198, in _run_module_as_main File "", line 88, in _run_code File "/usr/src/homeassistant/homeassistant/main.py", line 223, in sys.exit(main()) File "/usr/src/homeassistant/homeassistant/main.py", line 209, in main exit_code = runner.run(runtime_conf) File "/usr/src/homeassistant/homeassistant/runner.py", line 189, in run return loop.run_until_complete(setup_and_run_hass(runtime_config)) File "/usr/local/lib/python3.12/asyncio/base_events.py", line 674, in run_until_complete self.run_forever() File "/usr/local/lib/python3.12/asyncio/base_events.py", line 641, in run_forever self._run_once() File "/usr/local/lib/python3.12/asyncio/base_events.py", line 1990, in _run_once handle._run() File "/usr/local/lib/python3.12/asyncio/events.py", line 88, in _run self._context.run(self._callback, *self._args) File "/usr/src/homeassistant/homeassistant/config_entries.py", line 752, in async_setup_locked await self.async_setup(hass, integration=integration) File "/usr/src/homeassistant/homeassistant/config_entries.py", line 604, in async_setup result = await component.async_setup_entry(hass, self) File "/config/custom_components/myenergi/init.py", line 60, in async_setup_entry await coordinator.async_config_entry_first_refresh() File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 281, in async_config_entry_first_refresh await self._async_refresh( File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 354, in _async_refresh self.data = await self._async_update_data() File "/config/custom_components/myenergi/init.py", line 107, in _async_update_data await self.client.refresh()

MalcolmSpencer commented 2 months ago

I got the same

running on Pi4 Core 2024.9.1 Supervisor 2024.08.0 Operating System 13.1 Frontend 20240906.0 MyEnergi V0.0.28

Logger: homeassistant.util.loop Source: util/loop.py:136 First occurred: 09:12:41 (1 occurrences) Last logged: 09:12:41

Detected blocking call to load_verify_locations with args (<ssl.SSLContext object at 0x7f60de29d0>,) inside the event loop by custom integration 'myenergi' at custom_components/myenergi/init.py, line 55: await conn.discoverLocations() (offender: /usr/local/lib/python3.12/site-packages/httpx/_config.py, line 147: context.load_verify_locations(cafile=cafile)), please create a bug report at https://github.com/cjne/ha-myenergi/issues For developers, please see https://developers.home-assistant.io/docs/asyncio_blocking_operations/#load_verify_locations Traceback (most recent call last): File "", line 198, in _run_module_as_main File "", line 88, in _run_code File "/usr/src/homeassistant/homeassistant/main.py", line 223, in sys.exit(main()) File "/usr/src/homeassistant/homeassistant/main.py", line 209, in main exit_code = runner.run(runtime_conf) File "/usr/src/homeassistant/homeassistant/runner.py", line 189, in run return loop.run_until_complete(setup_and_run_hass(runtime_config)) File "/usr/local/lib/python3.12/asyncio/base_events.py", line 674, in run_until_complete self.run_forever() File "/usr/local/lib/python3.12/asyncio/base_events.py", line 641, in run_forever self._run_once() File "/usr/local/lib/python3.12/asyncio/base_events.py", line 1990, in _run_once handle._run() File "/usr/local/lib/python3.12/asyncio/events.py", line 88, in _run self._context.run(self._callback, *self._args) File "/usr/src/homeassistant/homeassistant/config_entries.py", line 752, in async_setup_locked await self.async_setup(hass, integration=integration) File "/usr/src/homeassistant/homeassistant/config_entries.py", line 604, in async_setup result = await component.async_setup_entry(hass, self) File "/config/custom_components/myenergi/init.py", line 55, in async_setup_entry await conn.discoverLocations()

trizmark commented 2 months ago

I haven't upgraded yet to see this error, but the fix looks simple enough. I'll try to bump my dev HA to the latest version and create a PR.

markruys commented 2 months ago

I haven't upgraded yet to see this error, but the fix looks simple enough. I'll try to bump my dev HA to the latest version and create a PR.

Glad the fix looks simple enough, for me the best way to fix it is unclear yet :) I would say the issue is in pymyenergi. In Blocking operations with asyncio a few helpers are suggested, like homeassistant.helpers.httpx_client.get_async_client().

YanisKyr commented 1 month ago

Got the same today - if you need more logs or diagnostics let me know.

trizmark commented 1 month ago

I started looking at the issue, but the fix might not be that simple. In order to move the currently blocking operation out of the event loop, the suggestion from the HA devs is to use a httpx_client helper from the homeassistant library. Which ideally we want to avoid as the blocking call happens in pymyenergi, which shouldn't depend on homeassistant.

I'll keep looking for other ways to solve this.

trizmark commented 1 month ago

So I thought I could simply change the code to:

await hass.async_add_executor_job(conn.discoverLocations)

however, this results in the following error:

2024-10-09 17:18:22.138 WARNING (MainThread) [py.warnings] /usr/local/lib/python3.12/asyncio/base_events.py:1975: RuntimeWarning: coroutine 'Connection.discoverLocations' was never awaited
  handle = self._ready.popleft()

Strange as the same approach (async_add_executor_job) works fine in other parts of code.

CJNE commented 1 month ago

Thanks for trying to figure this out! Home Assistant seems to prefer to use the same httpx client session for all http calls, this is more efficient and can help performance.

So i've made some changes, first i added a way for us to pass the httpx.AsyncClient we can get from HA to the pymyenergi Connection instance, and changed the http calls to re-user the client instead opening/closing the connection for each invokation.

Then i modified the integration setup to get httpx.AsyncClient from the HA helper function and pass it to the pymyenergi Connection constructor.

It all seems to work fine, the warning is gone :)

markruys commented 1 month ago

Nice work @CJNE!

CJNE commented 1 month ago

Nice work @CJNE!

Thank you!