Add sensors for Withings Goals (#102468)
parent
f0f3a43b09
commit
235a3486ee
|
@ -56,6 +56,7 @@ from .const import (
|
|||
CONF_USE_WEBHOOK,
|
||||
DEFAULT_TITLE,
|
||||
DOMAIN,
|
||||
GOALS_COORDINATOR,
|
||||
LOGGER,
|
||||
MEASUREMENT_COORDINATOR,
|
||||
SLEEP_COORDINATOR,
|
||||
|
@ -63,6 +64,7 @@ from .const import (
|
|||
from .coordinator import (
|
||||
WithingsBedPresenceDataUpdateCoordinator,
|
||||
WithingsDataUpdateCoordinator,
|
||||
WithingsGoalsDataUpdateCoordinator,
|
||||
WithingsMeasurementDataUpdateCoordinator,
|
||||
WithingsSleepDataUpdateCoordinator,
|
||||
)
|
||||
|
@ -160,6 +162,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
BED_PRESENCE_COORDINATOR: WithingsBedPresenceDataUpdateCoordinator(
|
||||
hass, client
|
||||
),
|
||||
GOALS_COORDINATOR: WithingsGoalsDataUpdateCoordinator(hass, client),
|
||||
}
|
||||
|
||||
for coordinator in coordinators.values():
|
||||
|
|
|
@ -16,6 +16,7 @@ PUSH_HANDLER = "push_handler"
|
|||
MEASUREMENT_COORDINATOR = "measurement_coordinator"
|
||||
SLEEP_COORDINATOR = "sleep_coordinator"
|
||||
BED_PRESENCE_COORDINATOR = "bed_presence_coordinator"
|
||||
GOALS_COORDINATOR = "goals_coordinator"
|
||||
|
||||
LOGGER = logging.getLogger(__package__)
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ from datetime import datetime, timedelta
|
|||
from typing import TypeVar
|
||||
|
||||
from aiowithings import (
|
||||
Goals,
|
||||
MeasurementType,
|
||||
NotificationCategory,
|
||||
SleepSummary,
|
||||
|
@ -170,3 +171,17 @@ class WithingsBedPresenceDataUpdateCoordinator(WithingsDataUpdateCoordinator[Non
|
|||
|
||||
async def _internal_update_data(self) -> None:
|
||||
"""Update coordinator data."""
|
||||
|
||||
|
||||
class WithingsGoalsDataUpdateCoordinator(WithingsDataUpdateCoordinator[Goals]):
|
||||
"""Withings goals coordinator."""
|
||||
|
||||
_default_update_interval = timedelta(hours=1)
|
||||
|
||||
def webhook_subscription_listener(self, connected: bool) -> None:
|
||||
"""Call when webhook status changed."""
|
||||
# Webhooks aren't available for this datapoint, so we keep polling
|
||||
|
||||
async def _internal_update_data(self) -> Goals:
|
||||
"""Retrieve goals data."""
|
||||
return await self._client.get_goals()
|
||||
|
|
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
|||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
|
||||
from aiowithings import MeasurementType, SleepSummary
|
||||
from aiowithings import Goals, MeasurementType, SleepSummary
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
|
@ -27,6 +27,7 @@ from homeassistant.helpers.typing import StateType
|
|||
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
GOALS_COORDINATOR,
|
||||
MEASUREMENT_COORDINATOR,
|
||||
SCORE_POINTS,
|
||||
SLEEP_COORDINATOR,
|
||||
|
@ -37,6 +38,7 @@ from .const import (
|
|||
)
|
||||
from .coordinator import (
|
||||
WithingsDataUpdateCoordinator,
|
||||
WithingsGoalsDataUpdateCoordinator,
|
||||
WithingsMeasurementDataUpdateCoordinator,
|
||||
WithingsSleepDataUpdateCoordinator,
|
||||
)
|
||||
|
@ -396,6 +398,64 @@ SLEEP_SENSORS = [
|
|||
]
|
||||
|
||||
|
||||
STEP_GOAL = "steps"
|
||||
SLEEP_GOAL = "sleep"
|
||||
WEIGHT_GOAL = "weight"
|
||||
|
||||
|
||||
@dataclass
|
||||
class WithingsGoalsSensorEntityDescriptionMixin:
|
||||
"""Mixin for describing withings data."""
|
||||
|
||||
value_fn: Callable[[Goals], StateType]
|
||||
|
||||
|
||||
@dataclass
|
||||
class WithingsGoalsSensorEntityDescription(
|
||||
SensorEntityDescription, WithingsGoalsSensorEntityDescriptionMixin
|
||||
):
|
||||
"""Immutable class for describing withings data."""
|
||||
|
||||
|
||||
GOALS_SENSORS: dict[str, WithingsGoalsSensorEntityDescription] = {
|
||||
STEP_GOAL: WithingsGoalsSensorEntityDescription(
|
||||
key="step_goal",
|
||||
value_fn=lambda goals: goals.steps,
|
||||
icon="mdi:shoe-print",
|
||||
translation_key="step_goal",
|
||||
native_unit_of_measurement="Steps",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SLEEP_GOAL: WithingsGoalsSensorEntityDescription(
|
||||
key="sleep_goal",
|
||||
value_fn=lambda goals: goals.sleep,
|
||||
icon="mdi:bed-clock",
|
||||
translation_key="sleep_goal",
|
||||
native_unit_of_measurement=UnitOfTime.SECONDS,
|
||||
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
||||
device_class=SensorDeviceClass.DURATION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
WEIGHT_GOAL: WithingsGoalsSensorEntityDescription(
|
||||
key="weight_goal",
|
||||
value_fn=lambda goals: goals.weight,
|
||||
translation_key="weight_goal",
|
||||
native_unit_of_measurement=UnitOfMass.KILOGRAMS,
|
||||
device_class=SensorDeviceClass.WEIGHT,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def get_current_goals(goals: Goals) -> set[str]:
|
||||
"""Return a list of present goals."""
|
||||
result = set()
|
||||
for goal in (STEP_GOAL, SLEEP_GOAL, WEIGHT_GOAL):
|
||||
if getattr(goals, goal):
|
||||
result.add(goal)
|
||||
return result
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
|
@ -406,8 +466,6 @@ async def async_setup_entry(
|
|||
DOMAIN
|
||||
][entry.entry_id][MEASUREMENT_COORDINATOR]
|
||||
|
||||
current_measurement_types = set(measurement_coordinator.data)
|
||||
|
||||
entities: list[SensorEntity] = []
|
||||
entities.extend(
|
||||
WithingsMeasurementSensor(
|
||||
|
@ -417,6 +475,8 @@ async def async_setup_entry(
|
|||
if measurement_type in MEASUREMENT_SENSORS
|
||||
)
|
||||
|
||||
current_measurement_types = set(measurement_coordinator.data)
|
||||
|
||||
def _async_measurement_listener() -> None:
|
||||
"""Listen for new measurements and add sensors if they did not exist."""
|
||||
received_measurement_types = set(measurement_coordinator.data)
|
||||
|
@ -431,6 +491,31 @@ async def async_setup_entry(
|
|||
)
|
||||
|
||||
measurement_coordinator.async_add_listener(_async_measurement_listener)
|
||||
|
||||
goals_coordinator: WithingsGoalsDataUpdateCoordinator = hass.data[DOMAIN][
|
||||
entry.entry_id
|
||||
][GOALS_COORDINATOR]
|
||||
|
||||
current_goals = get_current_goals(goals_coordinator.data)
|
||||
|
||||
entities.extend(
|
||||
WithingsGoalsSensor(goals_coordinator, GOALS_SENSORS[goal])
|
||||
for goal in current_goals
|
||||
)
|
||||
|
||||
def _async_goals_listener() -> None:
|
||||
"""Listen for new goals and add sensors if they did not exist."""
|
||||
received_goals = get_current_goals(goals_coordinator.data)
|
||||
new_goals = received_goals - current_goals
|
||||
if new_goals:
|
||||
current_goals.update(new_goals)
|
||||
async_add_entities(
|
||||
WithingsGoalsSensor(goals_coordinator, GOALS_SENSORS[goal])
|
||||
for goal in new_goals
|
||||
)
|
||||
|
||||
goals_coordinator.async_add_listener(_async_goals_listener)
|
||||
|
||||
sleep_coordinator: WithingsSleepDataUpdateCoordinator = hass.data[DOMAIN][
|
||||
entry.entry_id
|
||||
][SLEEP_COORDINATOR]
|
||||
|
@ -492,3 +577,17 @@ class WithingsSleepSensor(WithingsSensor):
|
|||
def available(self) -> bool:
|
||||
"""Return if the sensor is available."""
|
||||
return super().available and self.coordinator.data is not None
|
||||
|
||||
|
||||
class WithingsGoalsSensor(WithingsSensor):
|
||||
"""Implementation of a Withings goals sensor."""
|
||||
|
||||
coordinator: WithingsGoalsDataUpdateCoordinator
|
||||
|
||||
entity_description: WithingsGoalsSensorEntityDescription
|
||||
|
||||
@property
|
||||
def native_value(self) -> StateType:
|
||||
"""Return the state of the entity."""
|
||||
assert self.coordinator.data
|
||||
return self.entity_description.value_fn(self.coordinator.data)
|
||||
|
|
|
@ -134,6 +134,15 @@
|
|||
},
|
||||
"wakeup_time": {
|
||||
"name": "Wakeup time"
|
||||
},
|
||||
"step_goal": {
|
||||
"name": "Step goal"
|
||||
},
|
||||
"sleep_goal": {
|
||||
"name": "Sleep goal"
|
||||
},
|
||||
"weight_goal": {
|
||||
"name": "Weight goal"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ from datetime import timedelta
|
|||
import time
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from aiowithings import Device, MeasurementGroup, SleepSummary, WithingsClient
|
||||
from aiowithings import Device, Goals, MeasurementGroup, SleepSummary, WithingsClient
|
||||
from aiowithings.models import NotificationConfiguration
|
||||
import pytest
|
||||
|
||||
|
@ -148,8 +148,12 @@ def mock_withings():
|
|||
for not_conf in notification_json["profiles"]
|
||||
]
|
||||
|
||||
goals_json = load_json_object_fixture("withings/goals.json")
|
||||
goals = Goals.from_api(goals_json)
|
||||
|
||||
mock = AsyncMock(spec=WithingsClient)
|
||||
mock.get_devices.return_value = devices
|
||||
mock.get_goals.return_value = goals
|
||||
mock.get_measurement_in_period.return_value = measurement_groups
|
||||
mock.get_measurement_since.return_value = measurement_groups
|
||||
mock.get_sleep_summary_since.return_value = sleep_summaries
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"steps": 10000,
|
||||
"sleep": 28800,
|
||||
"weight": {
|
||||
"value": 70500,
|
||||
"unit": -3
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"weight": {
|
||||
"value": 70500,
|
||||
"unit": -3
|
||||
}
|
||||
}
|
|
@ -1,255 +1,5 @@
|
|||
# serializer version: 1
|
||||
# name: test_all_entities
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'weight',
|
||||
'friendly_name': 'henk Weight',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_weight',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '70',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.1
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'weight',
|
||||
'friendly_name': 'henk Fat mass',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_fat_mass',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '5',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.10
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Diastolic blood pressure',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'mmhg',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_diastolic_blood_pressure',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '70',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.11
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Systolic blood pressure',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'mmhg',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_systolic_blood_pressure',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '100',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.12
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Heart pulse',
|
||||
'icon': 'mdi:heart-pulse',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'bpm',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_heart_pulse',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '60',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.13
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk SpO2',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': '%',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_spo2',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '0.95',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.14
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'weight',
|
||||
'friendly_name': 'henk Hydration',
|
||||
'icon': 'mdi:water',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_hydration',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '0.95',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.15
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'speed',
|
||||
'friendly_name': 'henk Pulse wave velocity',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfSpeed.METERS_PER_SECOND: 'm/s'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_pulse_wave_velocity',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '100',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.16
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk VO2 max',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'ml/min/kg',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_vo2_max',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '100',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.17
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Vascular age',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_vascular_age',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '100',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.18
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'weight',
|
||||
'friendly_name': 'henk Extracellular water',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_extracellular_water',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '100',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.19
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'weight',
|
||||
'friendly_name': 'henk Intracellular water',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_intracellular_water',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '100',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.2
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'weight',
|
||||
'friendly_name': 'henk Fat free mass',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_fat_free_mass',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '60',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.20
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Breathing disturbances intensity',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_breathing_disturbances_intensity',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '10',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.21
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'henk Deep sleep',
|
||||
'icon': 'mdi:sleep',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_deep_sleep',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '26220',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.22
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'henk Time to sleep',
|
||||
'icon': 'mdi:sleep',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_time_to_sleep',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '780',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.23
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'henk Time to wakeup',
|
||||
'icon': 'mdi:sleep-off',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_time_to_wakeup',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '996',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.24
|
||||
# name: test_all_entities[sensor.henk_average_heart_rate]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Average heart rate',
|
||||
|
@ -264,69 +14,7 @@
|
|||
'state': '83',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.25
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Maximum heart rate',
|
||||
'icon': 'mdi:heart-pulse',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'bpm',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_maximum_heart_rate',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '108',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.26
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Minimum heart rate',
|
||||
'icon': 'mdi:heart-pulse',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'bpm',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_minimum_heart_rate',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '58',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.27
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'henk Light sleep',
|
||||
'icon': 'mdi:sleep',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_light_sleep',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '58440',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.28
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'henk REM sleep',
|
||||
'icon': 'mdi:sleep',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_rem_sleep',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '17280',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.29
|
||||
# name: test_all_entities[sensor.henk_average_respiratory_rate]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Average respiratory rate',
|
||||
|
@ -340,122 +28,22 @@
|
|||
'state': '14',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.3
|
||||
# name: test_all_entities[sensor.henk_body_temperature]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'weight',
|
||||
'friendly_name': 'henk Muscle mass',
|
||||
'device_class': 'temperature',
|
||||
'friendly_name': 'henk Body temperature',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_muscle_mass',
|
||||
'entity_id': 'sensor.henk_body_temperature',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '50',
|
||||
'state': '40',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.30
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Maximum respiratory rate',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'br/min',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_maximum_respiratory_rate',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '20',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.31
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Minimum respiratory rate',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'br/min',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_minimum_respiratory_rate',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '10',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.32
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Sleep score',
|
||||
'icon': 'mdi:medal',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'points',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_sleep_score',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '90',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.33
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Snoring',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_snoring',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '1044',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.34
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Snoring episode count',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_snoring_episode_count',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '87',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.35
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Wakeup count',
|
||||
'icon': 'mdi:sleep-off',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'times',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_wakeup_count',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '8',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.36
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'henk Wakeup time',
|
||||
'icon': 'mdi:sleep-off',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_wakeup_time',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '3468',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.4
|
||||
# name: test_all_entities[sensor.henk_bone_mass]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'weight',
|
||||
|
@ -471,7 +59,124 @@
|
|||
'state': '10',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.5
|
||||
# name: test_all_entities[sensor.henk_breathing_disturbances_intensity]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Breathing disturbances intensity',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_breathing_disturbances_intensity',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '10',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_deep_sleep]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'henk Deep sleep',
|
||||
'icon': 'mdi:sleep',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_deep_sleep',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '26220',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_diastolic_blood_pressure]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Diastolic blood pressure',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'mmhg',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_diastolic_blood_pressure',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '70',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_extracellular_water]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'weight',
|
||||
'friendly_name': 'henk Extracellular water',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_extracellular_water',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '100',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_fat_free_mass]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'weight',
|
||||
'friendly_name': 'henk Fat free mass',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_fat_free_mass',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '60',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_fat_mass]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'weight',
|
||||
'friendly_name': 'henk Fat mass',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_fat_mass',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '5',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_fat_ratio]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Fat ratio',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': '%',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_fat_ratio',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '0.07',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_heart_pulse]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Heart pulse',
|
||||
'icon': 'mdi:heart-pulse',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'bpm',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_heart_pulse',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '60',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_height]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'distance',
|
||||
|
@ -486,37 +191,158 @@
|
|||
'state': '2',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.6
|
||||
# name: test_all_entities[sensor.henk_hydration]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'temperature',
|
||||
'friendly_name': 'henk Temperature',
|
||||
'device_class': 'weight',
|
||||
'friendly_name': 'henk Hydration',
|
||||
'icon': 'mdi:water',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_temperature',
|
||||
'entity_id': 'sensor.henk_hydration',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '40',
|
||||
'state': '0.95',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.7
|
||||
# name: test_all_entities[sensor.henk_intracellular_water]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'temperature',
|
||||
'friendly_name': 'henk Body temperature',
|
||||
'device_class': 'weight',
|
||||
'friendly_name': 'henk Intracellular water',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_body_temperature',
|
||||
'entity_id': 'sensor.henk_intracellular_water',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '40',
|
||||
'state': '100',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.8
|
||||
# name: test_all_entities[sensor.henk_light_sleep]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'henk Light sleep',
|
||||
'icon': 'mdi:sleep',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_light_sleep',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '58440',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_maximum_heart_rate]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Maximum heart rate',
|
||||
'icon': 'mdi:heart-pulse',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'bpm',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_maximum_heart_rate',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '108',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_maximum_respiratory_rate]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Maximum respiratory rate',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'br/min',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_maximum_respiratory_rate',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '20',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_minimum_heart_rate]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Minimum heart rate',
|
||||
'icon': 'mdi:heart-pulse',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'bpm',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_minimum_heart_rate',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '58',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_minimum_respiratory_rate]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Minimum respiratory rate',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'br/min',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_minimum_respiratory_rate',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '10',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_muscle_mass]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'weight',
|
||||
'friendly_name': 'henk Muscle mass',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_muscle_mass',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '50',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_pulse_wave_velocity]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'speed',
|
||||
'friendly_name': 'henk Pulse wave velocity',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfSpeed.METERS_PER_SECOND: 'm/s'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_pulse_wave_velocity',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '100',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_rem_sleep]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'henk REM sleep',
|
||||
'icon': 'mdi:sleep',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_rem_sleep',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '17280',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_skin_temperature]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'temperature',
|
||||
|
@ -531,17 +357,237 @@
|
|||
'state': '20',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities.9
|
||||
# name: test_all_entities[sensor.henk_sleep_goal]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Fat ratio',
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'henk Sleep goal',
|
||||
'icon': 'mdi:bed-clock',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_sleep_goal',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '28800',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_sleep_score]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Sleep score',
|
||||
'icon': 'mdi:medal',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'points',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_sleep_score',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '90',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_snoring]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Snoring',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_snoring',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '1044',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_snoring_episode_count]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Snoring episode count',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_snoring_episode_count',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '87',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_spo2]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk SpO2',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': '%',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_fat_ratio',
|
||||
'entity_id': 'sensor.henk_spo2',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '0.07',
|
||||
'state': '0.95',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_step_goal]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Step goal',
|
||||
'icon': 'mdi:shoe-print',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'Steps',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_step_goal',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '10000',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_systolic_blood_pressure]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Systolic blood pressure',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'mmhg',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_systolic_blood_pressure',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '100',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_temperature]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'temperature',
|
||||
'friendly_name': 'henk Temperature',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_temperature',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '40',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_time_to_sleep]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'henk Time to sleep',
|
||||
'icon': 'mdi:sleep',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_time_to_sleep',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '780',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_time_to_wakeup]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'henk Time to wakeup',
|
||||
'icon': 'mdi:sleep-off',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_time_to_wakeup',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '996',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_vascular_age]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Vascular age',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_vascular_age',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '100',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_vo2_max]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk VO2 max',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'ml/min/kg',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_vo2_max',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '100',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_wakeup_count]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'henk Wakeup count',
|
||||
'icon': 'mdi:sleep-off',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'times',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_wakeup_count',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '8',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_wakeup_time]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'henk Wakeup time',
|
||||
'icon': 'mdi:sleep-off',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_wakeup_time',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '3468',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_weight]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'weight',
|
||||
'friendly_name': 'henk Weight',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_weight',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '70',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.henk_weight_goal]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'weight',
|
||||
'friendly_name': 'henk Weight goal',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.henk_weight_goal',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '70.5',
|
||||
})
|
||||
# ---
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from datetime import timedelta
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from aiowithings import MeasurementGroup
|
||||
from aiowithings import Goals, MeasurementGroup
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
|
@ -38,7 +38,9 @@ async def test_all_entities(
|
|||
|
||||
assert entity_entries
|
||||
for entity_entry in entity_entries:
|
||||
assert hass.states.get(entity_entry.entity_id) == snapshot
|
||||
assert hass.states.get(entity_entry.entity_id) == snapshot(
|
||||
name=entity_entry.entity_id
|
||||
)
|
||||
|
||||
|
||||
async def test_update_failed(
|
||||
|
@ -135,3 +137,29 @@ async def test_update_new_measurement_creates_new_sensor(
|
|||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get("sensor.henk_fat_mass") is not None
|
||||
|
||||
|
||||
async def test_update_new_goals_creates_new_sensor(
|
||||
hass: HomeAssistant,
|
||||
withings: AsyncMock,
|
||||
polling_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test fetching new goals will add a new sensor."""
|
||||
goals_json = load_json_object_fixture("withings/goals_1.json")
|
||||
goals = Goals.from_api(goals_json)
|
||||
withings.get_goals.return_value = goals
|
||||
await setup_integration(hass, polling_config_entry, False)
|
||||
|
||||
assert hass.states.get("sensor.henk_step_goal") is None
|
||||
assert hass.states.get("sensor.henk_weight_goal") is not None
|
||||
|
||||
goals_json = load_json_object_fixture("withings/goals.json")
|
||||
goals = Goals.from_api(goals_json)
|
||||
withings.get_goals.return_value = goals
|
||||
|
||||
freezer.tick(timedelta(hours=1))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get("sensor.henk_step_goal") is not None
|
||||
|
|
Loading…
Reference in New Issue