Skip to content

Commit 3c46b40

Browse files
Lash-LzweckjCopilotallenporter
authored
Raise an issue when the Roborock local api is unavailable. (home-assistant#154576)
Co-authored-by: Josef Zweck <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: Allen Porter <[email protected]>
1 parent 4c9810a commit 3c46b40

File tree

3 files changed

+67
-0
lines changed

3 files changed

+67
-0
lines changed

homeassistant/components/roborock/coordinator.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838
from homeassistant.exceptions import HomeAssistantError
3939
from homeassistant.helpers import device_registry as dr
4040
from homeassistant.helpers.device_registry import DeviceInfo
41+
from homeassistant.helpers.issue_registry import (
42+
IssueSeverity,
43+
async_create_issue,
44+
async_delete_issue,
45+
)
4146
from homeassistant.helpers.typing import StateType
4247
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
4348
from homeassistant.util import dt as dt_util, slugify
@@ -274,6 +279,9 @@ async def _verify_api(self) -> None:
274279
try:
275280
await self.api.async_connect()
276281
await self.api.ping()
282+
async_delete_issue(
283+
self.hass, DOMAIN, f"cloud_api_used_{self.duid_slug}"
284+
)
277285
except RoborockException:
278286
_LOGGER.warning(
279287
"Using the cloud API for device %s. This is not recommended as it can lead to rate limiting. We recommend making your vacuum accessible by your Home Assistant instance",
@@ -284,6 +292,19 @@ async def _verify_api(self) -> None:
284292
self.api = self.cloud_api
285293
self.update_interval = V1_CLOUD_NOT_CLEANING_INTERVAL
286294
self._is_cloud_api = True
295+
async_create_issue(
296+
self.hass,
297+
DOMAIN,
298+
f"cloud_api_used_{self.duid_slug}",
299+
is_fixable=False,
300+
severity=IssueSeverity.WARNING,
301+
translation_key="cloud_api_used",
302+
translation_placeholders={
303+
"device_name": self.roborock_device_info.device.name
304+
},
305+
learn_more_url="https://www.home-assistant.io/integrations/roborock/#the-integration-tells-me-it-cannot-reach-my-vacuum-and-is-using-the-cloud-api-and-that-this-is-not-supported-or-i-am-having-any-networking-issues",
306+
)
307+
287308
# Right now this should never be called if the cloud api is the primary api,
288309
# but in the future if it is, a new else should be added.
289310

homeassistant/components/roborock/strings.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@
3939
"wrong_account": "Wrong account: Please authenticate with the right account."
4040
}
4141
},
42+
"issues": {
43+
"cloud_api_used": {
44+
"title": "Cloud API used",
45+
"description": "The Roborock integration is unable to connect directly to {device_name} and falling back to the cloud API. This is not recommended as it can lead to rate limiting. Please make your vacuum accessible on the local network by your Home Assistant instance."
46+
}
47+
},
48+
4249
"options": {
4350
"step": {
4451
"drawables": {

tests/components/roborock/test_coordinator.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from homeassistant.components.roborock.coordinator import RoborockDataUpdateCoordinator
2323
from homeassistant.const import ATTR_ENTITY_ID, Platform
2424
from homeassistant.core import HomeAssistant
25+
from homeassistant.helpers import issue_registry as ir
2526
from homeassistant.util import dt as dt_util
2627

2728
from .mock_data import PROP
@@ -171,6 +172,44 @@ async def test_no_maps(
171172
assert load_map.call_count == 0
172173

173174

175+
async def test_cloud_api_repair(
176+
hass: HomeAssistant,
177+
mock_roborock_entry: MockConfigEntry,
178+
bypass_api_fixture_v1_only,
179+
) -> None:
180+
"""Test that a repair is created when we use the cloud api."""
181+
# Force the system to use the cloud api.
182+
with patch(
183+
"homeassistant.components.roborock.coordinator.RoborockLocalClientV1.ping",
184+
side_effect=RoborockException(),
185+
):
186+
await hass.config_entries.async_setup(mock_roborock_entry.entry_id)
187+
await hass.async_block_till_done()
188+
189+
issue_registry = ir.async_get(hass)
190+
assert len(issue_registry.issues) == 2
191+
# Check that both expected device names are present, regardless of order
192+
assert all(
193+
issue.translation_key == "cloud_api_used"
194+
for issue in issue_registry.issues.values()
195+
)
196+
names = {
197+
issue.translation_placeholders["device_name"]
198+
for issue in issue_registry.issues.values()
199+
}
200+
assert names == {"Roborock S7 MaxV", "Roborock S7 2"}
201+
await hass.config_entries.async_unload(mock_roborock_entry.entry_id)
202+
# Now change to using the local api
203+
with patch(
204+
"homeassistant.components.roborock.coordinator.RoborockLocalClientV1.ping"
205+
):
206+
# Set it back up
207+
await hass.config_entries.async_setup(mock_roborock_entry.entry_id)
208+
await hass.async_block_till_done()
209+
210+
assert len(issue_registry.issues) == 0
211+
212+
174213
async def test_two_maps_in_cleaning(
175214
hass: HomeAssistant,
176215
mock_roborock_entry: MockConfigEntry,

0 commit comments

Comments
 (0)