Skip to content

IoT MQTT listener silently never connects/subscribes (no logs at all) — forces reliance on polling, causing binary sensors like toilet_occupied to miss short-duration events #280

Description

@Nebur692

Integration version

1.27.0

Region

EU (api.eu-pet.com, confirmed from request logs)

Device type

Litter (Litter-Robot / Purobot-style box, model reporting as T6/D4H in logs)

Checklist

Describe the issue

PetkitIotMqttListener (iot_mqtt.py) is started unconditionally on every config entry setup (await mqtt_listener.async_start() in __init__.py), and is meant to switch the coordinator from REST polling to real-time MQTT push once connected (_on_subscribe sets mqtt_connected = True and relaxes the poll interval to SCAN_INTERVAL_SLOW).

On my installation this channel never appears to work, and — more importantly — it fails completely silently: over a full 7-day window of Home Assistant logs (default log level, nothing overridden for this integration), there is not a single occurrence of any of the following strings that iot_mqtt.py would log on success or failure:

  • "Subscribed to %s" (on_subscribe success)
  • "connect failed (reason_code=%s)"
  • "Broker rejected you subscription"
  • "Disconnected unexpectedly" / "Disconnected"
  • "Failed to fetch Petkit IoT MQTT config"
  • "Config is missing required fields; listener disabled"
  • "Invalid host"
  • "Failed to start connection"

Since get_iot_mqtt_config() apparently returns a fully-populated IotInfo (otherwise the "Config is missing required fields" warning would have fired), the client proceeds to paho_client.connect_async(...) + loop_start(). Because connect_async is non-blocking and the component never calls paho_client.enable_logger(), if the underlying TCP/TLS handshake never completes (as opposed to connecting then later dropping), none of _on_connect, _on_disconnect, or paho's own internal diagnostics are ever surfaced — the listener just sits in CONNECTING state forever with zero visibility, even in debug logs, since paho's own logger is never attached to HA's logging.

This matches what @fullstackPrincess independently observed in #234's description (messages_received stays at 0 on their setup too) — my logs suggest it may not even be completing the connect/subscribe handshake at all, which would be a step further than "connected but no messages".

Real-world impact (reproduced and verified against DB, not just logs)

Because MQTT never connects, mqtt_connected stays False and the coordinator falls back to DEFAULT_SCAN_INTERVAL (60s) REST polling only. Some binary sensors (e.g. binary_sensor.<litter>_toilet_occupied, backed by device.state.pet_in_time) reflect a transient live flag rather than a historical record, and enable_fast_poll only kicks in after the sensor has already been observed as on once — it cannot help catch the first detection.

I confirmed via the recorder DB (Postgres) that a real litter box visit lasting ~71 seconds (2026-07-23 07:29–07:30 local) was correctly captured by history-based sensors (sensor.*_uso_total incremented, sensor.max_last_urination timestamp set, weight/duration recorded) but binary_sensor.*_toilet_occupied never transitioned to on for that visit at all — it simply fell between two 60s polls. As a direct consequence, an automation triggered on that binary sensor's on state (used to notify a phone when the cat uses the litter box) silently did not fire, even though the underlying pypetkitapi retry bug (see Jezza34000/py-petkit-api#94) is already fixed on my setup.

Reproduction steps

  1. Install/reload the Petkit integration with a Litter device.
  2. Enable debug logging is not even necessary — check regular (info-level) HA logs over several hours/days for any iot_mqtt connect/subscribe/fail message.
  3. Observe: none appear, ever, regardless of whether the litter box is used.
  4. Cross-check binary_sensor.*_toilet_occupied history against a history-based sensor (e.g. *_uso_total/last-used sensors) around a real, brief litter box visit — the historical sensors update, the transient binary sensor frequently does not.

Suggested fix direction (not a PR, just what the code points to)

  • Call paho_client.enable_logger(logging.getLogger(f"{DOMAIN}.iot_mqtt.paho")) (or similar) so connection failures are actually visible instead of silently swallowed.
  • Add an explicit connect timeout / watchdog: if _connection_status stays CONNECTING for more than e.g. 30s, log a warning and let the coordinator know MQTT is unavailable rather than waiting indefinitely.
  • Consider whether feat: expose coordinator polling intervals as user-configurable options #234's configurable fast polling interval should be the recommended default mitigation for time-sensitive binary sensors like toilet_occupied until/unless the MQTT channel is confirmed reliable, since right now users have no way to know MQTT isn't working at all.

Debug logs

No debug logging was needed to observe the absence — that's the core of the bug (nothing is logged even without debug). Relevant log excerpt showing normal REST-poll network errors (already fixed, unrelated to this issue) still occurring without any adjacent MQTT log activity:

2026-07-23 17:24:28.405 WARNING (MainThread) [pypetkitapi.client] Network error reaching https://api.eu-pet.com/latest/d4h/device_detail:
2026-07-23 17:30:45.405 WARNING (MainThread) [pypetkitapi.client] Network error reaching https://api.eu-pet.com/latest/d4h/device_detail:

(no iot_mqtt-related lines anywhere before/after, across 7 days)

Diagnostics dump

Not attached — the integration's iot_mqtt.py does expose a diagnostics property (status, messages_received, last_message_at) on the listener object itself, but it isn't wired into the standard HA diagnostics download for the config entry, so I could not easily attach it. Might be worth exposing there too.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions