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
21 changes: 21 additions & 0 deletions homeassistant/components/roborock/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.issue_registry import (
IssueSeverity,
async_create_issue,
async_delete_issue,
)
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.util import dt as dt_util, slugify
Expand Down Expand Up @@ -274,6 +279,9 @@ async def _verify_api(self) -> None:
try:
await self.api.async_connect()
await self.api.ping()
async_delete_issue(
self.hass, DOMAIN, f"cloud_api_used_{self.duid_slug}"
)
except RoborockException:
_LOGGER.warning(
"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",
Expand All @@ -284,6 +292,19 @@ async def _verify_api(self) -> None:
self.api = self.cloud_api
self.update_interval = V1_CLOUD_NOT_CLEANING_INTERVAL
self._is_cloud_api = True
async_create_issue(
self.hass,
DOMAIN,
f"cloud_api_used_{self.duid_slug}",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="cloud_api_used",
translation_placeholders={
"device_name": self.roborock_device_info.device.name
},
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",
)

# Right now this should never be called if the cloud api is the primary api,
# but in the future if it is, a new else should be added.

Expand Down
7 changes: 7 additions & 0 deletions homeassistant/components/roborock/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@
"wrong_account": "Wrong account: Please authenticate with the right account."
}
},
"issues": {
"cloud_api_used": {
"title": "Cloud API used",
"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."
}
},

"options": {
"step": {
"drawables": {
Expand Down
27 changes: 20 additions & 7 deletions homeassistant/components/webostv/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ def __init__(self, entry: WebOsTvConfigEntry) -> None:
self._entry = entry
self._client = entry.runtime_data
self._attr_assumed_state = True
self._unavailable_logged = False
self._device_name = entry.title
self._attr_unique_id = entry.unique_id
self._sources = entry.options.get(CONF_SOURCES)
Expand Down Expand Up @@ -348,19 +349,31 @@ def _update_sources(self) -> None:
):
self._source_list["Live TV"] = app

def _set_availability(self, available: bool) -> None:
"""Set availability and log changes only once."""
self._attr_available = available
if not available and not self._unavailable_logged:
_LOGGER.info("LG webOS TV entity %s is unavailable", self.entity_id)
self._unavailable_logged = True
elif available and self._unavailable_logged:
_LOGGER.info("LG webOS TV entity %s is back online", self.entity_id)
self._unavailable_logged = False

@util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
async def async_update(self) -> None:
"""Connect."""
if self._client.is_connected():
return

with suppress(*WEBOSTV_EXCEPTIONS):
try:
await self._client.connect()
except WebOsTvPairError:
self._entry.async_start_reauth(self.hass)
else:
update_client_key(self.hass, self._entry)
try:
await self._client.connect()
except WEBOSTV_EXCEPTIONS:
self._set_availability(bool(self._turn_on))
except WebOsTvPairError:
self._entry.async_start_reauth(self.hass)
else:
self._set_availability(True)
update_client_key(self.hass, self._entry)

@property
def supported_features(self) -> MediaPlayerEntityFeature:
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/webostv/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ rules:
config-entry-unloading: done
docs-configuration-parameters: done
docs-installation-parameters: done
entity-unavailable: todo
entity-unavailable: done
integration-owner: done
log-when-unavailable: todo
log-when-unavailable: done
parallel-updates: done
reauthentication-flow: done
test-coverage: done
Expand Down
36 changes: 16 additions & 20 deletions homeassistant/components/xbox/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@
from yarl import URL

from homeassistant.components.binary_sensor import (
DOMAIN as BINARY_SENSOR_DOMAIN,
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from .coordinator import XboxConfigEntry, XboxUpdateCoordinator
from .entity import XboxBaseEntity
from .entity import XboxBaseEntity, check_deprecated_entity


class XboxBinarySensor(StrEnum):
Expand All @@ -37,6 +38,7 @@ class XboxBinarySensorEntityDescription(BinarySensorEntityDescription):

is_on_fn: Callable[[Person], bool | None]
entity_picture_fn: Callable[[Person], str | None] | None = None
deprecated: bool | None = None


def profile_pic(person: Person) -> str | None:
Expand Down Expand Up @@ -82,13 +84,8 @@ def in_game(person: Person) -> bool:
),
XboxBinarySensorEntityDescription(
key=XboxBinarySensor.IN_PARTY,
translation_key=XboxBinarySensor.IN_PARTY,
is_on_fn=(
lambda x: bool(x.multiplayer_summary.in_party)
if x.multiplayer_summary
else None
),
entity_registry_enabled_default=False,
is_on_fn=lambda _: None,
deprecated=True,
),
XboxBinarySensorEntityDescription(
key=XboxBinarySensor.IN_GAME,
Expand All @@ -97,13 +94,8 @@ def in_game(person: Person) -> bool:
),
XboxBinarySensorEntityDescription(
key=XboxBinarySensor.IN_MULTIPLAYER,
translation_key=XboxBinarySensor.IN_MULTIPLAYER,
is_on_fn=(
lambda x: bool(x.multiplayer_summary.in_multiplayer_session)
if x.multiplayer_summary
else None
),
entity_registry_enabled_default=False,
is_on_fn=lambda _: None,
deprecated=True,
),
XboxBinarySensorEntityDescription(
key=XboxBinarySensor.HAS_GAME_PASS,
Expand All @@ -121,7 +113,9 @@ async def async_setup_entry(
"""Set up Xbox Live friends."""
coordinator = entry.runtime_data

update_friends = partial(async_update_friends, coordinator, {}, async_add_entities)
update_friends = partial(
async_update_friends, hass, coordinator, {}, async_add_entities
)

entry.async_on_unload(coordinator.async_add_listener(update_friends))

Expand Down Expand Up @@ -152,6 +146,7 @@ def entity_picture(self) -> str | None:

@callback
def async_update_friends(
hass: HomeAssistant,
coordinator: XboxUpdateCoordinator,
current: dict[str, list[XboxBinarySensorEntity]],
async_add_entities,
Expand All @@ -163,10 +158,11 @@ def async_update_friends(
# Process new favorites, add them to Home Assistant
new_entities: list[XboxBinarySensorEntity] = []
for xuid in new_ids - current_ids:
current[xuid] = [
XboxBinarySensorEntity(coordinator, xuid, description)
for description in SENSOR_DESCRIPTIONS
]
current[xuid] = []
for description in SENSOR_DESCRIPTIONS:
entity = XboxBinarySensorEntity(coordinator, xuid, description)
if check_deprecated_entity(hass, entity, BINARY_SENSOR_DOMAIN):
current[xuid].append(entity)
new_entities = new_entities + current[xuid]
if new_entities:
async_add_entities(new_entities)
Expand Down
30 changes: 30 additions & 0 deletions homeassistant/components/xbox/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

from xbox.webapi.api.provider.smartglass.models import ConsoleType, SmartglassConsole

from homeassistant.components.automation import automations_with_entity
from homeassistant.components.script import scripts_with_entity
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.update_coordinator import CoordinatorEntity
Expand Down Expand Up @@ -83,3 +87,29 @@ def __init__(
def data(self) -> ConsoleData:
"""Return coordinator data for this console."""
return self.coordinator.data.consoles[self._console.id]


def entity_used_in(hass: HomeAssistant, entity_id: str) -> list[str]:
"""Get list of related automations and scripts."""
used_in = automations_with_entity(hass, entity_id)
used_in += scripts_with_entity(hass, entity_id)
return used_in


def check_deprecated_entity(
hass: HomeAssistant,
entity: XboxBaseEntity,
entity_domain: str,
) -> bool:
"""Check for deprecated entity and remove it."""
if not getattr(entity.entity_description, "deprecated", False):
return True
ent_reg = er.async_get(hass)
if entity_id := ent_reg.async_get_entity_id(
entity_domain,
DOMAIN,
f"{entity.xuid}_{entity.entity_description.key}",
):
ent_reg.async_remove(entity_id)

return False
12 changes: 0 additions & 12 deletions homeassistant/components/xbox/icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,6 @@
"gamer_score": {
"default": "mdi:alpha-g-circle"
},
"account_tier": {
"default": "mdi:microsoft-xbox"
},
"gold_tenure": {
"default": "mdi:microsoft-xbox"
},
"last_online": {
"default": "mdi:account-clock"
},
Expand All @@ -27,15 +21,9 @@
"online": {
"default": "mdi:account"
},
"in_party": {
"default": "mdi:account-group"
},
"in_game": {
"default": "mdi:microsoft-xbox-controller"
},
"in_multiplayer": {
"default": "mdi:account-multiple"
},
"has_game_pass": {
"default": "mdi:microsoft-xbox"
}
Expand Down
28 changes: 16 additions & 12 deletions homeassistant/components/xbox/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from xbox.webapi.api.provider.people.models import Person

from homeassistant.components.sensor import (
DOMAIN as SENSOR_DOMAIN,
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
Expand All @@ -20,7 +21,7 @@
from homeassistant.helpers.typing import StateType

from .coordinator import XboxConfigEntry, XboxUpdateCoordinator
from .entity import XboxBaseEntity
from .entity import XboxBaseEntity, check_deprecated_entity


class XboxSensor(StrEnum):
Expand All @@ -40,6 +41,7 @@ class XboxSensorEntityDescription(SensorEntityDescription):
"""Xbox sensor description."""

value_fn: Callable[[Person], StateType | datetime]
deprecated: bool | None = None


SENSOR_DESCRIPTIONS: tuple[XboxSensorEntityDescription, ...] = (
Expand All @@ -55,15 +57,13 @@ class XboxSensorEntityDescription(SensorEntityDescription):
),
XboxSensorEntityDescription(
key=XboxSensor.ACCOUNT_TIER,
translation_key=XboxSensor.ACCOUNT_TIER,
entity_registry_enabled_default=False,
value_fn=lambda x: x.detail.account_tier if x.detail else None,
value_fn=lambda _: None,
deprecated=True,
),
XboxSensorEntityDescription(
key=XboxSensor.GOLD_TENURE,
translation_key=XboxSensor.GOLD_TENURE,
entity_registry_enabled_default=False,
value_fn=lambda x: x.detail.tenure if x.detail else None,
value_fn=lambda _: None,
deprecated=True,
),
XboxSensorEntityDescription(
key=XboxSensor.LAST_ONLINE,
Expand Down Expand Up @@ -96,7 +96,9 @@ async def async_setup_entry(
"""Set up Xbox Live friends."""
coordinator = config_entry.runtime_data

update_friends = partial(async_update_friends, coordinator, {}, async_add_entities)
update_friends = partial(
async_update_friends, hass, coordinator, {}, async_add_entities
)

config_entry.async_on_unload(coordinator.async_add_listener(update_friends))
update_friends()
Expand All @@ -115,6 +117,7 @@ def native_value(self) -> StateType | datetime:

@callback
def async_update_friends(
hass: HomeAssistant,
coordinator: XboxUpdateCoordinator,
current: dict[str, list[XboxSensorEntity]],
async_add_entities,
Expand All @@ -126,10 +129,11 @@ def async_update_friends(
# Process new favorites, add them to Home Assistant
new_entities: list[XboxSensorEntity] = []
for xuid in new_ids - current_ids:
current[xuid] = [
XboxSensorEntity(coordinator, xuid, description)
for description in SENSOR_DESCRIPTIONS
]
current[xuid] = []
for description in SENSOR_DESCRIPTIONS:
entity = XboxSensorEntity(coordinator, xuid, description)
if check_deprecated_entity(hass, entity, SENSOR_DOMAIN):
current[xuid].append(entity)
new_entities = new_entities + current[xuid]
if new_entities:
async_add_entities(new_entities)
Expand Down
12 changes: 0 additions & 12 deletions homeassistant/components/xbox/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@
"name": "Gamerscore",
"unit_of_measurement": "points"
},
"account_tier": {
"name": "Account tier"
},
"gold_tenure": {
"name": "Gold tenure"
},
"last_online": {
"name": "Last online"
},
Expand All @@ -56,15 +50,9 @@
}
},
"binary_sensor": {
"in_party": {
"name": "In party"
},
"in_game": {
"name": "In game"
},
"in_multiplayer": {
"name": "In multiplayer"
},
"has_game_pass": {
"name": "Subscribed to Xbox Game Pass"
}
Expand Down
Loading
Loading