mirror of
https://github.com/home-assistant/core.git
synced 2025-08-07 22:55:10 +02:00
Add modernized fitbit battery level sensor
This commit is contained in:
@@ -38,6 +38,7 @@ from homeassistant.const import (
|
|||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.data_entry_flow import FlowResultType
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
from homeassistant.helpers.device_registry import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.icon import icon_for_battery_level
|
from homeassistant.helpers.icon import icon_for_battery_level
|
||||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
||||||
@@ -508,6 +509,17 @@ FITBIT_RESOURCE_BATTERY = FitbitSensorEntityDescription(
|
|||||||
scope=FitbitScope.DEVICE,
|
scope=FitbitScope.DEVICE,
|
||||||
entity_category=EntityCategory.DIAGNOSTIC,
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
)
|
)
|
||||||
|
FITBIT_RESOURCE_BATTERY_LEVEL = FitbitSensorEntityDescription(
|
||||||
|
key="devices/battery_level",
|
||||||
|
translation_key="battery_level",
|
||||||
|
name="Battery Level",
|
||||||
|
icon="mdi:battery",
|
||||||
|
scope=FitbitScope.DEVICE,
|
||||||
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
|
has_entity_name=True,
|
||||||
|
device_class=SensorDeviceClass.BATTERY,
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
)
|
||||||
|
|
||||||
FITBIT_RESOURCES_KEYS: Final[list[str]] = [
|
FITBIT_RESOURCES_KEYS: Final[list[str]] = [
|
||||||
desc.key
|
desc.key
|
||||||
@@ -657,7 +669,7 @@ async def async_setup_entry(
|
|||||||
async_add_entities(entities, True)
|
async_add_entities(entities, True)
|
||||||
|
|
||||||
if data.device_coordinator and is_allowed_resource(FITBIT_RESOURCE_BATTERY):
|
if data.device_coordinator and is_allowed_resource(FITBIT_RESOURCE_BATTERY):
|
||||||
async_add_entities(
|
battery_entities: list[SensorEntity] = [
|
||||||
FitbitBatterySensor(
|
FitbitBatterySensor(
|
||||||
data.device_coordinator,
|
data.device_coordinator,
|
||||||
user_profile.encoded_id,
|
user_profile.encoded_id,
|
||||||
@@ -666,7 +678,17 @@ async def async_setup_entry(
|
|||||||
enable_default_override=is_explicit_enable(FITBIT_RESOURCE_BATTERY),
|
enable_default_override=is_explicit_enable(FITBIT_RESOURCE_BATTERY),
|
||||||
)
|
)
|
||||||
for device in data.device_coordinator.data.values()
|
for device in data.device_coordinator.data.values()
|
||||||
|
]
|
||||||
|
battery_entities.extend(
|
||||||
|
FitbitBatteryLevelSensor(
|
||||||
|
data.device_coordinator,
|
||||||
|
user_profile.encoded_id,
|
||||||
|
FITBIT_RESOURCE_BATTERY_LEVEL,
|
||||||
|
device=device,
|
||||||
)
|
)
|
||||||
|
for device in data.device_coordinator.data.values()
|
||||||
|
)
|
||||||
|
async_add_entities(battery_entities)
|
||||||
|
|
||||||
|
|
||||||
class FitbitSensor(SensorEntity):
|
class FitbitSensor(SensorEntity):
|
||||||
@@ -714,7 +736,7 @@ class FitbitSensor(SensorEntity):
|
|||||||
|
|
||||||
|
|
||||||
class FitbitBatterySensor(CoordinatorEntity, SensorEntity):
|
class FitbitBatterySensor(CoordinatorEntity, SensorEntity):
|
||||||
"""Implementation of a Fitbit sensor."""
|
"""Implementation of a Fitbit battery sensor."""
|
||||||
|
|
||||||
entity_description: FitbitSensorEntityDescription
|
entity_description: FitbitSensorEntityDescription
|
||||||
_attr_attribution = ATTRIBUTION
|
_attr_attribution = ATTRIBUTION
|
||||||
@@ -731,10 +753,13 @@ class FitbitBatterySensor(CoordinatorEntity, SensorEntity):
|
|||||||
super().__init__(coordinator)
|
super().__init__(coordinator)
|
||||||
self.entity_description = description
|
self.entity_description = description
|
||||||
self.device = device
|
self.device = device
|
||||||
self._attr_unique_id = f"{user_profile_id}_{description.key}"
|
|
||||||
if device is not None:
|
|
||||||
self._attr_name = f"{device.device_version} Battery"
|
self._attr_name = f"{device.device_version} Battery"
|
||||||
self._attr_unique_id = f"{self._attr_unique_id}_{device.id}"
|
self._attr_unique_id = f"{user_profile_id}_{description.key}_{device.id}"
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
identifiers={(DOMAIN, f"{user_profile_id}_{device.id}")},
|
||||||
|
name=device.device_version,
|
||||||
|
model=device.device_version,
|
||||||
|
)
|
||||||
|
|
||||||
if enable_default_override:
|
if enable_default_override:
|
||||||
self._attr_entity_registry_enabled_default = True
|
self._attr_entity_registry_enabled_default = True
|
||||||
@@ -765,3 +790,41 @@ class FitbitBatterySensor(CoordinatorEntity, SensorEntity):
|
|||||||
self.device = self.coordinator.data[self.device.id]
|
self.device = self.coordinator.data[self.device.id]
|
||||||
self._attr_native_value = self.device.battery
|
self._attr_native_value = self.device.battery
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
|
||||||
|
class FitbitBatteryLevelSensor(CoordinatorEntity, SensorEntity):
|
||||||
|
"""Implementation of a Fitbit battery sensor."""
|
||||||
|
|
||||||
|
entity_description: FitbitSensorEntityDescription
|
||||||
|
_attr_attribution = ATTRIBUTION
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: FitbitDeviceCoordinator,
|
||||||
|
user_profile_id: str,
|
||||||
|
description: FitbitSensorEntityDescription,
|
||||||
|
device: FitbitDevice,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the Fitbit sensor."""
|
||||||
|
super().__init__(coordinator)
|
||||||
|
self.entity_description = description
|
||||||
|
self.device = device
|
||||||
|
self._attr_unique_id = f"{user_profile_id}_{description.key}_{device.id}"
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
identifiers={(DOMAIN, f"{user_profile_id}_{device.id}")},
|
||||||
|
name=device.device_version,
|
||||||
|
model=device.device_version,
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_added_to_hass(self) -> None:
|
||||||
|
"""When entity is added to hass update state from existing coordinator data."""
|
||||||
|
await super().async_added_to_hass()
|
||||||
|
self._handle_coordinator_update()
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _handle_coordinator_update(self) -> None:
|
||||||
|
"""Handle updated data from the coordinator."""
|
||||||
|
self.device = self.coordinator.data[self.device.id]
|
||||||
|
self._attr_native_value = self.device.battery_level
|
||||||
|
self.async_write_ha_state()
|
||||||
|
@@ -27,6 +27,13 @@
|
|||||||
"default": "[%key:common::config_flow::create_entry::authenticated%]"
|
"default": "[%key:common::config_flow::create_entry::authenticated%]"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"entity": {
|
||||||
|
"sensor": {
|
||||||
|
"battery_level": {
|
||||||
|
"name": "Battery Level"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"issues": {
|
"issues": {
|
||||||
"deprecated_yaml_no_import": {
|
"deprecated_yaml_no_import": {
|
||||||
"title": "Fitbit YAML configuration is being removed",
|
"title": "Fitbit YAML configuration is being removed",
|
||||||
|
@@ -228,7 +228,7 @@ async def test_sensors(
|
|||||||
("devices_response", "monitored_resources"),
|
("devices_response", "monitored_resources"),
|
||||||
[([DEVICE_RESPONSE_CHARGE_2, DEVICE_RESPONSE_ARIA_AIR], ["devices/battery"])],
|
[([DEVICE_RESPONSE_CHARGE_2, DEVICE_RESPONSE_ARIA_AIR], ["devices/battery"])],
|
||||||
)
|
)
|
||||||
async def test_device_battery_level(
|
async def test_device_battery(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
fitbit_config_setup: None,
|
fitbit_config_setup: None,
|
||||||
sensor_platform_setup: Callable[[], Awaitable[bool]],
|
sensor_platform_setup: Callable[[], Awaitable[bool]],
|
||||||
@@ -272,6 +272,45 @@ async def test_device_battery_level(
|
|||||||
assert entry.unique_id == f"{PROFILE_USER_ID}_devices/battery_016713257"
|
assert entry.unique_id == f"{PROFILE_USER_ID}_devices/battery_016713257"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("devices_response", "monitored_resources"),
|
||||||
|
[([DEVICE_RESPONSE_CHARGE_2, DEVICE_RESPONSE_ARIA_AIR], ["devices/battery"])],
|
||||||
|
)
|
||||||
|
async def test_device_battery_level(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
fitbit_config_setup: None,
|
||||||
|
sensor_platform_setup: Callable[[], Awaitable[bool]],
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
) -> None:
|
||||||
|
"""Test battery level sensor for devices."""
|
||||||
|
|
||||||
|
assert await sensor_platform_setup()
|
||||||
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
|
assert len(entries) == 1
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.charge_2_battery_level")
|
||||||
|
assert state
|
||||||
|
assert state.state == "60"
|
||||||
|
assert state.attributes == {
|
||||||
|
"attribution": "Data provided by Fitbit.com",
|
||||||
|
"friendly_name": "Charge 2 Battery Level",
|
||||||
|
"icon": "mdi:battery",
|
||||||
|
"device_class": "battery",
|
||||||
|
"unit_of_measurement": "%",
|
||||||
|
}
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.aria_air_battery_level")
|
||||||
|
assert state
|
||||||
|
assert state.state == "95"
|
||||||
|
assert state.attributes == {
|
||||||
|
"attribution": "Data provided by Fitbit.com",
|
||||||
|
"friendly_name": "Aria Air Battery Level",
|
||||||
|
"icon": "mdi:battery",
|
||||||
|
"device_class": "battery",
|
||||||
|
"unit_of_measurement": "%",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
(
|
(
|
||||||
"monitored_resources",
|
"monitored_resources",
|
||||||
@@ -552,6 +591,7 @@ async def test_settings_scope_config_entry(
|
|||||||
states = hass.states.async_all()
|
states = hass.states.async_all()
|
||||||
assert [s.entity_id for s in states] == [
|
assert [s.entity_id for s in states] == [
|
||||||
"sensor.charge_2_battery",
|
"sensor.charge_2_battery",
|
||||||
|
"sensor.charge_2_battery_level",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user