1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-24 21:06:19 +00:00

Add new entities to Xbox integration (#154911)

This commit is contained in:
Manu
2025-10-21 08:51:30 +02:00
committed by GitHub
parent 854882d612
commit 5c070c8f03
8 changed files with 658 additions and 5 deletions

View File

@@ -27,6 +27,7 @@ class XboxBinarySensor(StrEnum):
IN_PARTY = "in_party"
IN_GAME = "in_game"
IN_MULTIPLAYER = "in_multiplayer"
HAS_GAME_PASS = "has_game_pass"
@dataclass(kw_only=True, frozen=True)
@@ -79,6 +80,11 @@ SENSOR_DESCRIPTIONS: tuple[XboxBinarySensorEntityDescription, ...] = (
is_on_fn=lambda x: x.in_multiplayer,
entity_registry_enabled_default=False,
),
XboxBinarySensorEntityDescription(
key=XboxBinarySensor.HAS_GAME_PASS,
translation_key=XboxBinarySensor.HAS_GAME_PASS,
is_on_fn=lambda x: x.has_game_pass,
),
)

View File

@@ -3,7 +3,7 @@
from __future__ import annotations
from dataclasses import dataclass, field
from datetime import timedelta
from datetime import UTC, datetime, timedelta
import logging
from httpx import HTTPStatusError, RequestError, TimeoutException
@@ -58,6 +58,10 @@ class PresenceData:
gamer_score: str
gold_tenure: str | None
account_tier: str
last_seen: datetime | None
following_count: int
follower_count: int
has_game_pass: bool
@dataclass
@@ -246,4 +250,12 @@ def _build_presence_data(person: Person) -> PresenceData:
gamer_score=person.gamer_score,
gold_tenure=person.detail.tenure,
account_tier=person.detail.account_tier,
last_seen=(
person.last_seen_date_time_utc.replace(tzinfo=UTC)
if person.last_seen_date_time_utc
else None
),
follower_count=person.detail.follower_count,
following_count=person.detail.following_count,
has_game_pass=person.detail.has_game_pass,
)

View File

@@ -12,6 +12,15 @@
},
"gold_tenure": {
"default": "mdi:microsoft-xbox"
},
"last_online": {
"default": "mdi:account-clock"
},
"follower": {
"default": "mdi:account-arrow-left"
},
"following": {
"default": "mdi:account-arrow-right"
}
},
"binary_sensor": {
@@ -26,6 +35,9 @@
},
"in_multiplayer": {
"default": "mdi:account-multiple"
},
"has_game_pass": {
"default": "mdi:microsoft-xbox"
}
}
}

View File

@@ -4,10 +4,15 @@ from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime
from enum import StrEnum
from functools import partial
from homeassistant.components.sensor import SensorEntity, SensorEntityDescription
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.typing import StateType
@@ -23,13 +28,16 @@ class XboxSensor(StrEnum):
GAMER_SCORE = "gamer_score"
ACCOUNT_TIER = "account_tier"
GOLD_TENURE = "gold_tenure"
LAST_ONLINE = "last_online"
FOLLOWING = "following"
FOLLOWER = "follower"
@dataclass(kw_only=True, frozen=True)
class XboxSensorEntityDescription(SensorEntityDescription):
"""Xbox sensor description."""
value_fn: Callable[[PresenceData], StateType]
value_fn: Callable[[PresenceData], StateType | datetime]
SENSOR_DESCRIPTIONS: tuple[XboxSensorEntityDescription, ...] = (
@@ -55,6 +63,22 @@ SENSOR_DESCRIPTIONS: tuple[XboxSensorEntityDescription, ...] = (
entity_registry_enabled_default=False,
value_fn=lambda x: x.gold_tenure,
),
XboxSensorEntityDescription(
key=XboxSensor.LAST_ONLINE,
translation_key=XboxSensor.LAST_ONLINE,
value_fn=(lambda x: x.last_seen),
device_class=SensorDeviceClass.TIMESTAMP,
),
XboxSensorEntityDescription(
key=XboxSensor.FOLLOWING,
translation_key=XboxSensor.FOLLOWING,
value_fn=lambda x: x.following_count,
),
XboxSensorEntityDescription(
key=XboxSensor.FOLLOWER,
translation_key=XboxSensor.FOLLOWER,
value_fn=lambda x: x.follower_count,
),
)
@@ -78,7 +102,7 @@ class XboxSensorEntity(XboxBaseEntity, SensorEntity):
entity_description: XboxSensorEntityDescription
@property
def native_value(self) -> StateType:
def native_value(self) -> StateType | datetime:
"""Return the state of the requested attribute."""
return self.entity_description.value_fn(self.data)

View File

@@ -38,6 +38,17 @@
},
"gold_tenure": {
"name": "Gold tenure"
},
"last_online": {
"name": "Last online"
},
"following": {
"name": "Following",
"unit_of_measurement": "people"
},
"follower": {
"name": "Follower",
"unit_of_measurement": "[%key:component::xbox::entity::sensor::following::unit_of_measurement%]"
}
},
"binary_sensor": {
@@ -49,6 +60,9 @@
},
"in_multiplayer": {
"name": "In multiplayer"
},
"has_game_pass": {
"name": "Subscribed to Xbox Game Pass"
}
}
},

View File

@@ -67,7 +67,7 @@
"mute": false,
"followerCount": 105,
"followingCount": 121,
"hasGamePass": false
"hasGamePass": true
},
"communityManagerTitles": null,
"socialManager": null,

View File

@@ -192,6 +192,54 @@
'state': 'off',
})
# ---
# name: test_binary_sensors[binary_sensor.erics273_subscribed_to_xbox_game_pass-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.erics273_subscribed_to_xbox_game_pass',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Subscribed to Xbox Game Pass',
'platform': 'xbox',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': <XboxBinarySensor.HAS_GAME_PASS: 'has_game_pass'>,
'unique_id': '2533274913657542_has_game_pass',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensors[binary_sensor.erics273_subscribed_to_xbox_game_pass-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'erics273 Subscribed to Xbox Game Pass',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.erics273_subscribed_to_xbox_game_pass',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_binary_sensors[binary_sensor.gsr_ae-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@@ -385,6 +433,54 @@
'state': 'off',
})
# ---
# name: test_binary_sensors[binary_sensor.gsr_ae_subscribed_to_xbox_game_pass-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.gsr_ae_subscribed_to_xbox_game_pass',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Subscribed to Xbox Game Pass',
'platform': 'xbox',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': <XboxBinarySensor.HAS_GAME_PASS: 'has_game_pass'>,
'unique_id': '271958441785640_has_game_pass',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensors[binary_sensor.gsr_ae_subscribed_to_xbox_game_pass-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'GSR Ae Subscribed to Xbox Game Pass',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.gsr_ae_subscribed_to_xbox_game_pass',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_binary_sensors[binary_sensor.ikken_hissatsuu-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@@ -578,3 +674,51 @@
'state': 'off',
})
# ---
# name: test_binary_sensors[binary_sensor.ikken_hissatsuu_subscribed_to_xbox_game_pass-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.ikken_hissatsuu_subscribed_to_xbox_game_pass',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Subscribed to Xbox Game Pass',
'platform': 'xbox',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': <XboxBinarySensor.HAS_GAME_PASS: 'has_game_pass'>,
'unique_id': '2533274838782903_has_game_pass',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensors[binary_sensor.ikken_hissatsuu_subscribed_to_xbox_game_pass-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Ikken Hissatsuu Subscribed to Xbox Game Pass',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.ikken_hissatsuu_subscribed_to_xbox_game_pass',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---

View File

@@ -47,6 +47,104 @@
'state': 'Silver',
})
# ---
# name: test_sensors[sensor.erics273_follower-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.erics273_follower',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Follower',
'platform': 'xbox',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': <XboxSensor.FOLLOWER: 'follower'>,
'unique_id': '2533274913657542_follower',
'unit_of_measurement': 'people',
})
# ---
# name: test_sensors[sensor.erics273_follower-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'erics273 Follower',
'unit_of_measurement': 'people',
}),
'context': <ANY>,
'entity_id': 'sensor.erics273_follower',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '18',
})
# ---
# name: test_sensors[sensor.erics273_following-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.erics273_following',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Following',
'platform': 'xbox',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': <XboxSensor.FOLLOWING: 'following'>,
'unique_id': '2533274913657542_following',
'unit_of_measurement': 'people',
})
# ---
# name: test_sensors[sensor.erics273_following-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'erics273 Following',
'unit_of_measurement': 'people',
}),
'context': <ANY>,
'entity_id': 'sensor.erics273_following',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '12',
})
# ---
# name: test_sensors[sensor.erics273_gamerscore-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@@ -144,6 +242,55 @@
'state': '0',
})
# ---
# name: test_sensors[sensor.erics273_last_online-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.erics273_last_online',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last online',
'platform': 'xbox',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': <XboxSensor.LAST_ONLINE: 'last_online'>,
'unique_id': '2533274913657542_last_online',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[sensor.erics273_last_online-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'timestamp',
'friendly_name': 'erics273 Last online',
}),
'context': <ANY>,
'entity_id': 'sensor.erics273_last_online',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2020-10-08T04:19:58+00:00',
})
# ---
# name: test_sensors[sensor.erics273_status-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@@ -240,6 +387,104 @@
'state': 'Gold',
})
# ---
# name: test_sensors[sensor.gsr_ae_follower-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.gsr_ae_follower',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Follower',
'platform': 'xbox',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': <XboxSensor.FOLLOWER: 'follower'>,
'unique_id': '271958441785640_follower',
'unit_of_measurement': 'people',
})
# ---
# name: test_sensors[sensor.gsr_ae_follower-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'GSR Ae Follower',
'unit_of_measurement': 'people',
}),
'context': <ANY>,
'entity_id': 'sensor.gsr_ae_follower',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '105',
})
# ---
# name: test_sensors[sensor.gsr_ae_following-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.gsr_ae_following',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Following',
'platform': 'xbox',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': <XboxSensor.FOLLOWING: 'following'>,
'unique_id': '271958441785640_following',
'unit_of_measurement': 'people',
})
# ---
# name: test_sensors[sensor.gsr_ae_following-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'GSR Ae Following',
'unit_of_measurement': 'people',
}),
'context': <ANY>,
'entity_id': 'sensor.gsr_ae_following',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '121',
})
# ---
# name: test_sensors[sensor.gsr_ae_gamerscore-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@@ -337,6 +582,55 @@
'state': 'unknown',
})
# ---
# name: test_sensors[sensor.gsr_ae_last_online-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.gsr_ae_last_online',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last online',
'platform': 'xbox',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': <XboxSensor.LAST_ONLINE: 'last_online'>,
'unique_id': '271958441785640_last_online',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[sensor.gsr_ae_last_online-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'timestamp',
'friendly_name': 'GSR Ae Last online',
}),
'context': <ANY>,
'entity_id': 'sensor.gsr_ae_last_online',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2020-10-09T00:12:27+00:00',
})
# ---
# name: test_sensors[sensor.gsr_ae_status-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@@ -433,6 +727,104 @@
'state': 'Gold',
})
# ---
# name: test_sensors[sensor.ikken_hissatsuu_follower-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.ikken_hissatsuu_follower',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Follower',
'platform': 'xbox',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': <XboxSensor.FOLLOWER: 'follower'>,
'unique_id': '2533274838782903_follower',
'unit_of_measurement': 'people',
})
# ---
# name: test_sensors[sensor.ikken_hissatsuu_follower-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Ikken Hissatsuu Follower',
'unit_of_measurement': 'people',
}),
'context': <ANY>,
'entity_id': 'sensor.ikken_hissatsuu_follower',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '81',
})
# ---
# name: test_sensors[sensor.ikken_hissatsuu_following-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.ikken_hissatsuu_following',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Following',
'platform': 'xbox',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': <XboxSensor.FOLLOWING: 'following'>,
'unique_id': '2533274838782903_following',
'unit_of_measurement': 'people',
})
# ---
# name: test_sensors[sensor.ikken_hissatsuu_following-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Ikken Hissatsuu Following',
'unit_of_measurement': 'people',
}),
'context': <ANY>,
'entity_id': 'sensor.ikken_hissatsuu_following',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '73',
})
# ---
# name: test_sensors[sensor.ikken_hissatsuu_gamerscore-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@@ -530,6 +922,55 @@
'state': '8',
})
# ---
# name: test_sensors[sensor.ikken_hissatsuu_last_online-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.ikken_hissatsuu_last_online',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last online',
'platform': 'xbox',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': <XboxSensor.LAST_ONLINE: 'last_online'>,
'unique_id': '2533274838782903_last_online',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[sensor.ikken_hissatsuu_last_online-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'timestamp',
'friendly_name': 'Ikken Hissatsuu Last online',
}),
'context': <ANY>,
'entity_id': 'sensor.ikken_hissatsuu_last_online',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_sensors[sensor.ikken_hissatsuu_status-entry]
EntityRegistryEntrySnapshot({
'aliases': set({