Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions roborock/devices/rpc/v1_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,14 @@ def is_local_connected(self) -> bool:

@property
def is_mqtt_connected(self) -> bool:
"""Return whether MQTT connection is available."""
return self._mqtt_channel.is_connected
"""Return whether MQTT connection is available for the device.

This requires the MQTT session to be connected to the broker and
the subscription to the device's topic to have successfully
been established (to handle cases where the device is offline
or deleted).
"""
return self._mqtt_channel.is_connected and self._mqtt_unsub is not None
Comment thread
allenporter marked this conversation as resolved.

@property
def rpc_channel(self) -> V1RpcChannel:
Expand Down
50 changes: 50 additions & 0 deletions tests/devices/rpc/test_v1_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,56 @@ async def test_v1_channel_mqtt_disconnected(
assert not mock_mqtt_channel.subscribers


async def test_v1_channel_mqtt_subscription_fails_local_succeeds(
v1_channel: V1Channel,
mock_mqtt_channel: FakeChannel,
device_cache: DeviceCache,
) -> None:
"""Test MQTT subscription failure while local connection succeeds."""
# Pre-populate cache so we don't query network info via MQTT
device_cache_data = await device_cache.get()
device_cache_data.network_info = TEST_NETWORKING_INFO
await device_cache.set(device_cache_data)

# Simulate MQTT subscription failing
mock_mqtt_channel.subscribe.side_effect = RoborockException("MQTT subscription failed")

# Subscribe should succeed via local fallback
callback = Mock()
unsub = await v1_channel.subscribe(callback)

# Verify MQTT is not reported as connected, but local is
assert not v1_channel.is_mqtt_connected
assert v1_channel.is_local_connected
assert v1_channel.is_connected

unsub()


async def test_v1_channel_all_connection_attempts_fail(
v1_channel: V1Channel,
mock_mqtt_channel: FakeChannel,
mock_local_channel: FakeChannel,
device_cache: DeviceCache,
) -> None:
"""Test when both local connect and MQTT subscribe fail."""
# Pre-populate cache so we don't query network info via MQTT
device_cache_data = await device_cache.get()
device_cache_data.network_info = TEST_NETWORKING_INFO
await device_cache.set(device_cache_data)

mock_local_channel.connect.side_effect = RoborockException("local down")
mock_mqtt_channel.subscribe.side_effect = RoborockException("MQTT subscription failed")

with pytest.raises(RoborockException):
await v1_channel.subscribe(Mock())

# After a failed subscription, properties should reflect no active connection
assert not v1_channel.is_mqtt_connected
assert not v1_channel.is_local_connected
assert not v1_channel.is_connected


async def test_v1_channel_subscribe_local_success(
v1_channel: V1Channel,
mock_mqtt_channel: Mock,
Expand Down
Loading