Fix Home Assistant SNMP blocking-call warnings - #80
Merged
Conversation
PySNMP loads bundled MIB modules from disk the first time an engine encodes a request and decodes the response. Because the engine was created lazily on the event loop, Home Assistant flagged those file reads as blocking calls inside the event loop. Port the warm-up technique used in switch_port_card_pro: - Create the engine in an executor and preload the bundled MIB modules (both the well-known set and every file-backed module PySNMP ships) while still off the event loop. A GET now performs zero file reads on the loop, down from three. - Share one warmed engine across all SNMP clients in the process, so the preload cost is paid once rather than per config entry. - Stop closing the dispatcher in disconnect(): the engine is shared, so unloading one config entry must not tear it down for the others. Each client still drops its own transport and connection state. hass is threaded through to the client from both construction sites so the engine is built with async_add_executor_job; a loop executor is used as a fallback when no hass is available. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YcBZKHHnbLVbwmB95WS2uA
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ports the SNMP engine warm-up technique from
switch_port_card_pro(itsfix-ha-2026-log-errorsbranch) into Protocol Wizard.Problem
PySNMP loads bundled MIB modules from disk the first time an engine encodes a request and decodes the response.
SNMPClient._ensure_enginecreatedSnmpEngine()lazily on the event loop, so Home Assistant flagged those file reads as blocking calls inside the event loop.Measured against pysnmp 7.1.29, counting
open()calls during a single GET:PYSNMP-SOURCE-MIB.py,PYSNMP-MIB.py,SNMPv2-TM.pyChanges
custom_components/protocol_wizard/protocols/snmp/client.py_create_engine()builds the engine and preloads its MIB modules — the well-known set plus every file-backed module PySNMP ships, discovered by_iter_pysnmp_mib_module_names(). Warm-up loads 34 modules vs. 13 bare, in ~0.17s._async_get_shared_engine()runs that in an executor and caches the result, so the engine is never built on the loop.SNMPClient; preloading all bundled MIBs per config entry would repeat expensive work. Each client still owns its ownUdpTransportTarget.disconnect()no longer callsclose_dispatcher(). This follows from sharing —__init__.pycallsdisconnect()on config-entry unload, which would otherwise tear the engine out from under every other SNMP entry. The client still drops its transport and connection state.__init__.py/config_flow.pyhassis threaded through to the client from both construction sites so the engine is built withasync_add_executor_job; a loop executor is used as a fallback when nohassis available.The other two parts of the upstream fix were checked and did not apply here: Protocol Wizard already calls
async_config_entry_first_refresh()beforeasync_forward_entry_setupsin all three setup paths, andentity_base.pyhas no try/except aroundavailable.Tests
New
tests/test_snmp_client_engine.py(9 tests) covers MIB preloading, module discovery from file-backed sources, executor use, the loop-executor fallback, concurrent callers sharing one engine, anddisconnect()leaving the shared engine open for other clients.Full suite: 219 passed.
ruff check .clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01YcBZKHHnbLVbwmB95WS2uA
Generated by Claude Code