Summary
Client should become an async context manager so that the MQTT connection lifecycle is explicitly managed:
async with await Client.login(email, password) as client:
device = client.device(0)
await device.set_property("ac", "on")
# connection cleaned up on exit
Motivation
Currently, Device.set_property() falls back to a short-lived MQTT connection when no subscription is active (open, publish, close). This is fine for the primary use case (Home Assistant always calls subscribe() first, so _active_mqtt is always set), but means a library consumer who calls set_property() multiple times without subscribing incurs a full connect/disconnect per call.
A proper async context manager would lazily create a persistent _active_mqtt on entry and tear it down on exit — eliminating the short-lived connection fallback entirely.
Constraint
The current CLI pattern is incompatible with this:
# CLI today: synchronous load, then asyncio.run() per command
client = Client.from_saved()
asyncio.run(client.set_property(...))
An async context manager that spans multiple asyncio.run() calls is not possible (each call creates and destroys the event loop). Adopting this pattern would require refactoring the CLI to run a single event loop per invocation, or keeping a separate sync-friendly path.
Depends on
Priority
Low — the short-lived fallback is acceptable for all current consumers. Revisit when the CLI is refactored or when a consumer with high set_property() throughput appears.
Summary
Clientshould become an async context manager so that the MQTT connection lifecycle is explicitly managed:Motivation
Currently,
Device.set_property()falls back to a short-lived MQTT connection when no subscription is active (open, publish, close). This is fine for the primary use case (Home Assistant always callssubscribe()first, so_active_mqttis always set), but means a library consumer who callsset_property()multiple times without subscribing incurs a full connect/disconnect per call.A proper async context manager would lazily create a persistent
_active_mqtton entry and tear it down on exit — eliminating the short-lived connection fallback entirely.Constraint
The current CLI pattern is incompatible with this:
An async context manager that spans multiple
asyncio.run()calls is not possible (each call creates and destroys the event loop). Adopting this pattern would require refactoring the CLI to run a single event loop per invocation, or keeping a separate sync-friendly path.Depends on
_active_mqttslot introduced there is the foundation for thisPriority
Low — the short-lived fallback is acceptable for all current consumers. Revisit when the CLI is refactored or when a consumer with high
set_property()throughput appears.