From 522a1e9d56ce8571b730c9ddf2108d58969b5044 Mon Sep 17 00:00:00 2001 From: Joost Lekkerkerker Date: Sat, 8 Jun 2024 11:56:23 +0200 Subject: [PATCH] Add support for segmental measurements in Withings (#119126) --- homeassistant/components/withings/icons.json | 18 + homeassistant/components/withings/sensor.py | 135 +-- .../components/withings/strings.json | 45 + .../withings/fixtures/measurements.json | 8 + .../withings/snapshots/test_diagnostics.ambr | 12 + .../withings/snapshots/test_sensor.ambr | 810 ++++++++++++++++++ 6 files changed, 964 insertions(+), 64 deletions(-) diff --git a/homeassistant/components/withings/icons.json b/homeassistant/components/withings/icons.json index f76761ce953..f6fb5e74136 100644 --- a/homeassistant/components/withings/icons.json +++ b/homeassistant/components/withings/icons.json @@ -19,6 +19,24 @@ "hydration": { "default": "mdi:water" }, + "muscle_mass_for_segments_left_arm": { + "default": "mdi:arm-flex" + }, + "muscle_mass_for_segments_right_arm": { + "default": "mdi:arm-flex" + }, + "fat_free_mass_for_segments_left_arm": { + "default": "mdi:arm-flex" + }, + "fat_free_mass_for_segments_right_arm": { + "default": "mdi:arm-flex" + }, + "fat_mass_for_segments_left_arm": { + "default": "mdi:arm-flex" + }, + "fat_mass_for_segments_right_arm": { + "default": "mdi:arm-flex" + }, "deep_sleep": { "default": "mdi:sleep" }, diff --git a/homeassistant/components/withings/sensor.py b/homeassistant/components/withings/sensor.py index e205af7bdda..20fd72845ae 100644 --- a/homeassistant/components/withings/sensor.py +++ b/homeassistant/components/withings/sensor.py @@ -68,10 +68,9 @@ class WithingsMeasurementSensorEntityDescription(SensorEntityDescription): MEASUREMENT_SENSORS: dict[ - tuple[MeasurementType, MeasurementPosition | None], - WithingsMeasurementSensorEntityDescription, + MeasurementType, WithingsMeasurementSensorEntityDescription ] = { - (MeasurementType.WEIGHT, None): WithingsMeasurementSensorEntityDescription( + MeasurementType.WEIGHT: WithingsMeasurementSensorEntityDescription( key="weight_kg", measurement_type=MeasurementType.WEIGHT, native_unit_of_measurement=UnitOfMass.KILOGRAMS, @@ -79,7 +78,7 @@ MEASUREMENT_SENSORS: dict[ device_class=SensorDeviceClass.WEIGHT, state_class=SensorStateClass.MEASUREMENT, ), - (MeasurementType.FAT_MASS_WEIGHT, None): WithingsMeasurementSensorEntityDescription( + MeasurementType.FAT_MASS_WEIGHT: WithingsMeasurementSensorEntityDescription( key="fat_mass_kg", measurement_type=MeasurementType.FAT_MASS_WEIGHT, translation_key="fat_mass", @@ -88,7 +87,7 @@ MEASUREMENT_SENSORS: dict[ device_class=SensorDeviceClass.WEIGHT, state_class=SensorStateClass.MEASUREMENT, ), - (MeasurementType.FAT_FREE_MASS, None): WithingsMeasurementSensorEntityDescription( + MeasurementType.FAT_FREE_MASS: WithingsMeasurementSensorEntityDescription( key="fat_free_mass_kg", measurement_type=MeasurementType.FAT_FREE_MASS, translation_key="fat_free_mass", @@ -97,7 +96,7 @@ MEASUREMENT_SENSORS: dict[ device_class=SensorDeviceClass.WEIGHT, state_class=SensorStateClass.MEASUREMENT, ), - (MeasurementType.MUSCLE_MASS, None): WithingsMeasurementSensorEntityDescription( + MeasurementType.MUSCLE_MASS: WithingsMeasurementSensorEntityDescription( key="muscle_mass_kg", measurement_type=MeasurementType.MUSCLE_MASS, translation_key="muscle_mass", @@ -106,7 +105,7 @@ MEASUREMENT_SENSORS: dict[ device_class=SensorDeviceClass.WEIGHT, state_class=SensorStateClass.MEASUREMENT, ), - (MeasurementType.BONE_MASS, None): WithingsMeasurementSensorEntityDescription( + MeasurementType.BONE_MASS: WithingsMeasurementSensorEntityDescription( key="bone_mass_kg", measurement_type=MeasurementType.BONE_MASS, translation_key="bone_mass", @@ -115,7 +114,7 @@ MEASUREMENT_SENSORS: dict[ device_class=SensorDeviceClass.WEIGHT, state_class=SensorStateClass.MEASUREMENT, ), - (MeasurementType.HEIGHT, None): WithingsMeasurementSensorEntityDescription( + MeasurementType.HEIGHT: WithingsMeasurementSensorEntityDescription( key="height_m", measurement_type=MeasurementType.HEIGHT, translation_key="height", @@ -125,17 +124,14 @@ MEASUREMENT_SENSORS: dict[ state_class=SensorStateClass.MEASUREMENT, entity_registry_enabled_default=False, ), - (MeasurementType.TEMPERATURE, None): WithingsMeasurementSensorEntityDescription( + MeasurementType.TEMPERATURE: WithingsMeasurementSensorEntityDescription( key="temperature_c", measurement_type=MeasurementType.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, ), - ( - MeasurementType.BODY_TEMPERATURE, - None, - ): WithingsMeasurementSensorEntityDescription( + MeasurementType.BODY_TEMPERATURE: WithingsMeasurementSensorEntityDescription( key="body_temperature_c", measurement_type=MeasurementType.BODY_TEMPERATURE, translation_key="body_temperature", @@ -143,10 +139,7 @@ MEASUREMENT_SENSORS: dict[ device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, ), - ( - MeasurementType.SKIN_TEMPERATURE, - None, - ): WithingsMeasurementSensorEntityDescription( + MeasurementType.SKIN_TEMPERATURE: WithingsMeasurementSensorEntityDescription( key="skin_temperature_c", measurement_type=MeasurementType.SKIN_TEMPERATURE, translation_key="skin_temperature", @@ -154,7 +147,7 @@ MEASUREMENT_SENSORS: dict[ device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, ), - (MeasurementType.FAT_RATIO, None): WithingsMeasurementSensorEntityDescription( + MeasurementType.FAT_RATIO: WithingsMeasurementSensorEntityDescription( key="fat_ratio_pct", measurement_type=MeasurementType.FAT_RATIO, translation_key="fat_ratio", @@ -162,41 +155,35 @@ MEASUREMENT_SENSORS: dict[ suggested_display_precision=2, state_class=SensorStateClass.MEASUREMENT, ), - ( - MeasurementType.DIASTOLIC_BLOOD_PRESSURE, - None, - ): WithingsMeasurementSensorEntityDescription( + MeasurementType.DIASTOLIC_BLOOD_PRESSURE: WithingsMeasurementSensorEntityDescription( key="diastolic_blood_pressure_mmhg", measurement_type=MeasurementType.DIASTOLIC_BLOOD_PRESSURE, translation_key="diastolic_blood_pressure", native_unit_of_measurement=UOM_MMHG, state_class=SensorStateClass.MEASUREMENT, ), - ( - MeasurementType.SYSTOLIC_BLOOD_PRESSURE, - None, - ): WithingsMeasurementSensorEntityDescription( + MeasurementType.SYSTOLIC_BLOOD_PRESSURE: WithingsMeasurementSensorEntityDescription( key="systolic_blood_pressure_mmhg", measurement_type=MeasurementType.SYSTOLIC_BLOOD_PRESSURE, translation_key="systolic_blood_pressure", native_unit_of_measurement=UOM_MMHG, state_class=SensorStateClass.MEASUREMENT, ), - (MeasurementType.HEART_RATE, None): WithingsMeasurementSensorEntityDescription( + MeasurementType.HEART_RATE: WithingsMeasurementSensorEntityDescription( key="heart_pulse_bpm", measurement_type=MeasurementType.HEART_RATE, translation_key="heart_pulse", native_unit_of_measurement=UOM_BEATS_PER_MINUTE, state_class=SensorStateClass.MEASUREMENT, ), - (MeasurementType.SP02, None): WithingsMeasurementSensorEntityDescription( + MeasurementType.SP02: WithingsMeasurementSensorEntityDescription( key="spo2_pct", measurement_type=MeasurementType.SP02, translation_key="spo2", native_unit_of_measurement=PERCENTAGE, state_class=SensorStateClass.MEASUREMENT, ), - (MeasurementType.HYDRATION, None): WithingsMeasurementSensorEntityDescription( + MeasurementType.HYDRATION: WithingsMeasurementSensorEntityDescription( key="hydration", measurement_type=MeasurementType.HYDRATION, translation_key="hydration", @@ -205,10 +192,7 @@ MEASUREMENT_SENSORS: dict[ state_class=SensorStateClass.MEASUREMENT, entity_registry_enabled_default=False, ), - ( - MeasurementType.PULSE_WAVE_VELOCITY, - None, - ): WithingsMeasurementSensorEntityDescription( + MeasurementType.PULSE_WAVE_VELOCITY: WithingsMeasurementSensorEntityDescription( key="pulse_wave_velocity", measurement_type=MeasurementType.PULSE_WAVE_VELOCITY, translation_key="pulse_wave_velocity", @@ -216,7 +200,7 @@ MEASUREMENT_SENSORS: dict[ device_class=SensorDeviceClass.SPEED, state_class=SensorStateClass.MEASUREMENT, ), - (MeasurementType.VO2, None): WithingsMeasurementSensorEntityDescription( + MeasurementType.VO2: WithingsMeasurementSensorEntityDescription( key="vo2_max", measurement_type=MeasurementType.VO2, translation_key="vo2_max", @@ -224,10 +208,7 @@ MEASUREMENT_SENSORS: dict[ state_class=SensorStateClass.MEASUREMENT, entity_registry_enabled_default=False, ), - ( - MeasurementType.EXTRACELLULAR_WATER, - None, - ): WithingsMeasurementSensorEntityDescription( + MeasurementType.EXTRACELLULAR_WATER: WithingsMeasurementSensorEntityDescription( key="extracellular_water", measurement_type=MeasurementType.EXTRACELLULAR_WATER, translation_key="extracellular_water", @@ -236,10 +217,7 @@ MEASUREMENT_SENSORS: dict[ state_class=SensorStateClass.MEASUREMENT, entity_registry_enabled_default=False, ), - ( - MeasurementType.INTRACELLULAR_WATER, - None, - ): WithingsMeasurementSensorEntityDescription( + MeasurementType.INTRACELLULAR_WATER: WithingsMeasurementSensorEntityDescription( key="intracellular_water", measurement_type=MeasurementType.INTRACELLULAR_WATER, translation_key="intracellular_water", @@ -248,42 +226,33 @@ MEASUREMENT_SENSORS: dict[ state_class=SensorStateClass.MEASUREMENT, entity_registry_enabled_default=False, ), - (MeasurementType.VASCULAR_AGE, None): WithingsMeasurementSensorEntityDescription( + MeasurementType.VASCULAR_AGE: WithingsMeasurementSensorEntityDescription( key="vascular_age", measurement_type=MeasurementType.VASCULAR_AGE, translation_key="vascular_age", entity_registry_enabled_default=False, ), - (MeasurementType.VISCERAL_FAT, None): WithingsMeasurementSensorEntityDescription( + MeasurementType.VISCERAL_FAT: WithingsMeasurementSensorEntityDescription( key="visceral_fat", measurement_type=MeasurementType.VISCERAL_FAT, translation_key="visceral_fat_index", entity_registry_enabled_default=False, ), - ( - MeasurementType.ELECTRODERMAL_ACTIVITY_FEET, - None, - ): WithingsMeasurementSensorEntityDescription( + MeasurementType.ELECTRODERMAL_ACTIVITY_FEET: WithingsMeasurementSensorEntityDescription( key="electrodermal_activity_feet", measurement_type=MeasurementType.ELECTRODERMAL_ACTIVITY_FEET, translation_key="electrodermal_activity_feet", native_unit_of_measurement=PERCENTAGE, entity_registry_enabled_default=False, ), - ( - MeasurementType.ELECTRODERMAL_ACTIVITY_LEFT_FOOT, - None, - ): WithingsMeasurementSensorEntityDescription( + MeasurementType.ELECTRODERMAL_ACTIVITY_LEFT_FOOT: WithingsMeasurementSensorEntityDescription( key="electrodermal_activity_left_foot", measurement_type=MeasurementType.ELECTRODERMAL_ACTIVITY_LEFT_FOOT, translation_key="electrodermal_activity_left_foot", native_unit_of_measurement=PERCENTAGE, entity_registry_enabled_default=False, ), - ( - MeasurementType.ELECTRODERMAL_ACTIVITY_RIGHT_FOOT, - None, - ): WithingsMeasurementSensorEntityDescription( + MeasurementType.ELECTRODERMAL_ACTIVITY_RIGHT_FOOT: WithingsMeasurementSensorEntityDescription( key="electrodermal_activity_right_foot", measurement_type=MeasurementType.ELECTRODERMAL_ACTIVITY_RIGHT_FOOT, translation_key="electrodermal_activity_right_foot", @@ -293,6 +262,47 @@ MEASUREMENT_SENSORS: dict[ } +def get_positional_measurement_description( + measurement_type: MeasurementType, measurement_position: MeasurementPosition +) -> WithingsMeasurementSensorEntityDescription | None: + """Get the sensor description for a measurement type.""" + if measurement_position not in ( + MeasurementPosition.TORSO, + MeasurementPosition.LEFT_ARM, + MeasurementPosition.RIGHT_ARM, + MeasurementPosition.LEFT_LEG, + MeasurementPosition.RIGHT_LEG, + ) or measurement_type not in ( + MeasurementType.MUSCLE_MASS_FOR_SEGMENTS, + MeasurementType.FAT_FREE_MASS_FOR_SEGMENTS, + MeasurementType.FAT_MASS_FOR_SEGMENTS, + ): + return None + return WithingsMeasurementSensorEntityDescription( + key=f"{measurement_type.name.lower()}_{measurement_position.name.lower()}", + measurement_type=measurement_type, + measurement_position=measurement_position, + translation_key=f"{measurement_type.name.lower()}_{measurement_position.name.lower()}", + native_unit_of_measurement=UnitOfMass.KILOGRAMS, + suggested_display_precision=2, + device_class=SensorDeviceClass.WEIGHT, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ) + + +def get_measurement_description( + measurement: tuple[MeasurementType, MeasurementPosition | None], +) -> WithingsMeasurementSensorEntityDescription | None: + """Get the sensor description for a measurement type.""" + measurement_type, measurement_position = measurement + if measurement_position is not None: + return get_positional_measurement_description( + measurement_type, measurement_position + ) + return MEASUREMENT_SENSORS.get(measurement_type) + + @dataclass(frozen=True, kw_only=True) class WithingsSleepSensorEntityDescription(SensorEntityDescription): """Immutable class for describing withings data.""" @@ -663,11 +673,9 @@ async def async_setup_entry( entities: list[SensorEntity] = [] entities.extend( - WithingsMeasurementSensor( - measurement_coordinator, MEASUREMENT_SENSORS[measurement_type] - ) + WithingsMeasurementSensor(measurement_coordinator, description) for measurement_type in measurement_coordinator.data - if measurement_type in MEASUREMENT_SENSORS + if (description := get_measurement_description(measurement_type)) is not None ) current_measurement_types = set(measurement_coordinator.data) @@ -679,11 +687,10 @@ async def async_setup_entry( if new_measurement_types: current_measurement_types.update(new_measurement_types) async_add_entities( - WithingsMeasurementSensor( - measurement_coordinator, MEASUREMENT_SENSORS[measurement_type] - ) + WithingsMeasurementSensor(measurement_coordinator, description) for measurement_type in new_measurement_types - if measurement_type in MEASUREMENT_SENSORS + if (description := get_measurement_description(measurement_type)) + is not None ) measurement_coordinator.async_add_listener(_async_measurement_listener) diff --git a/homeassistant/components/withings/strings.json b/homeassistant/components/withings/strings.json index a142dd23eac..fb86b16c3be 100644 --- a/homeassistant/components/withings/strings.json +++ b/homeassistant/components/withings/strings.json @@ -104,6 +104,51 @@ "electrodermal_activity_right_foot": { "name": "Electrodermal activity right foot" }, + "muscle_mass_for_segments_torso": { + "name": "Muscle mass in torso" + }, + "muscle_mass_for_segments_left_arm": { + "name": "Muscle mass in left arm" + }, + "muscle_mass_for_segments_right_arm": { + "name": "Muscle mass in right arm" + }, + "muscle_mass_for_segments_left_leg": { + "name": "Muscle mass in left leg" + }, + "muscle_mass_for_segments_right_leg": { + "name": "Muscle mass in right leg" + }, + "fat_free_mass_for_segments_torso": { + "name": "Fat free mass in torso" + }, + "fat_free_mass_for_segments_left_arm": { + "name": "Fat free mass in left arm" + }, + "fat_free_mass_for_segments_right_arm": { + "name": "Fat free mass in right arm" + }, + "fat_free_mass_for_segments_left_leg": { + "name": "Fat free mass in left leg" + }, + "fat_free_mass_for_segments_right_leg": { + "name": "Fat free mass in right leg" + }, + "fat_mass_for_segments_torso": { + "name": "Fat mass in torso" + }, + "fat_mass_for_segments_left_arm": { + "name": "Fat mass in left arm" + }, + "fat_mass_for_segments_right_arm": { + "name": "Fat mass in right arm" + }, + "fat_mass_for_segments_left_leg": { + "name": "Fat mass in left leg" + }, + "fat_mass_for_segments_right_leg": { + "name": "Fat mass in right leg" + }, "breathing_disturbances_intensity": { "name": "Breathing disturbances intensity" }, diff --git a/tests/components/withings/fixtures/measurements.json b/tests/components/withings/fixtures/measurements.json index 31603d9a332..9c68d2e3e47 100644 --- a/tests/components/withings/fixtures/measurements.json +++ b/tests/components/withings/fixtures/measurements.json @@ -777,6 +777,14 @@ "fm": 3, "position": 2 }, + { + "value": 489, + "type": 1, + "unit": -2, + "algo": 218235904, + "fm": 3, + "position": 2 + }, { "value": 2308, "type": 226, diff --git a/tests/components/withings/snapshots/test_diagnostics.ambr b/tests/components/withings/snapshots/test_diagnostics.ambr index 8ed8116f0c5..ca3cd2147d3 100644 --- a/tests/components/withings/snapshots/test_diagnostics.ambr +++ b/tests/components/withings/snapshots/test_diagnostics.ambr @@ -109,6 +109,10 @@ 6, None, ]), + list([ + 1, + 2, + ]), list([ 4, None, @@ -281,6 +285,10 @@ 6, None, ]), + list([ + 1, + 2, + ]), list([ 4, None, @@ -453,6 +461,10 @@ 6, None, ]), + list([ + 1, + 2, + ]), list([ 4, None, diff --git a/tests/components/withings/snapshots/test_sensor.ambr b/tests/components/withings/snapshots/test_sensor.ambr index 37635ece403..70a86c79038 100644 --- a/tests/components/withings/snapshots/test_sensor.ambr +++ b/tests/components/withings/snapshots/test_sensor.ambr @@ -965,6 +965,276 @@ 'state': '60', }) # --- +# name: test_all_entities[sensor.henk_fat_free_mass_in_left_arm-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.henk_fat_free_mass_in_left_arm', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Fat free mass in left arm', + 'platform': 'withings', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'fat_free_mass_for_segments_left_arm', + 'unique_id': 'withings_12345_fat_free_mass_for_segments_left_arm', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.henk_fat_free_mass_in_left_arm-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'weight', + 'friendly_name': 'henk Fat free mass in left arm', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.henk_fat_free_mass_in_left_arm', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '5.05', + }) +# --- +# name: test_all_entities[sensor.henk_fat_free_mass_in_left_leg-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.henk_fat_free_mass_in_left_leg', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Fat free mass in left leg', + 'platform': 'withings', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'fat_free_mass_for_segments_left_leg', + 'unique_id': 'withings_12345_fat_free_mass_for_segments_left_leg', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.henk_fat_free_mass_in_left_leg-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'weight', + 'friendly_name': 'henk Fat free mass in left leg', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.henk_fat_free_mass_in_left_leg', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '13.84', + }) +# --- +# name: test_all_entities[sensor.henk_fat_free_mass_in_right_arm-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.henk_fat_free_mass_in_right_arm', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Fat free mass in right arm', + 'platform': 'withings', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'fat_free_mass_for_segments_right_arm', + 'unique_id': 'withings_12345_fat_free_mass_for_segments_right_arm', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.henk_fat_free_mass_in_right_arm-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'weight', + 'friendly_name': 'henk Fat free mass in right arm', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.henk_fat_free_mass_in_right_arm', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '5.18', + }) +# --- +# name: test_all_entities[sensor.henk_fat_free_mass_in_right_leg-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.henk_fat_free_mass_in_right_leg', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Fat free mass in right leg', + 'platform': 'withings', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'fat_free_mass_for_segments_right_leg', + 'unique_id': 'withings_12345_fat_free_mass_for_segments_right_leg', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.henk_fat_free_mass_in_right_leg-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'weight', + 'friendly_name': 'henk Fat free mass in right leg', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.henk_fat_free_mass_in_right_leg', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '14.05', + }) +# --- +# name: test_all_entities[sensor.henk_fat_free_mass_in_torso-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.henk_fat_free_mass_in_torso', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Fat free mass in torso', + 'platform': 'withings', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'fat_free_mass_for_segments_torso', + 'unique_id': 'withings_12345_fat_free_mass_for_segments_torso', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.henk_fat_free_mass_in_torso-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'weight', + 'friendly_name': 'henk Fat free mass in torso', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.henk_fat_free_mass_in_torso', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '40.49', + }) +# --- # name: test_all_entities[sensor.henk_fat_mass-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -1019,6 +1289,276 @@ 'state': '5', }) # --- +# name: test_all_entities[sensor.henk_fat_mass_in_left_arm-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.henk_fat_mass_in_left_arm', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Fat mass in left arm', + 'platform': 'withings', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'fat_mass_for_segments_left_arm', + 'unique_id': 'withings_12345_fat_mass_for_segments_left_arm', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.henk_fat_mass_in_left_arm-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'weight', + 'friendly_name': 'henk Fat mass in left arm', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.henk_fat_mass_in_left_arm', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1.03', + }) +# --- +# name: test_all_entities[sensor.henk_fat_mass_in_left_leg-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.henk_fat_mass_in_left_leg', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Fat mass in left leg', + 'platform': 'withings', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'fat_mass_for_segments_left_leg', + 'unique_id': 'withings_12345_fat_mass_for_segments_left_leg', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.henk_fat_mass_in_left_leg-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'weight', + 'friendly_name': 'henk Fat mass in left leg', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.henk_fat_mass_in_left_leg', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2.45', + }) +# --- +# name: test_all_entities[sensor.henk_fat_mass_in_right_arm-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.henk_fat_mass_in_right_arm', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Fat mass in right arm', + 'platform': 'withings', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'fat_mass_for_segments_right_arm', + 'unique_id': 'withings_12345_fat_mass_for_segments_right_arm', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.henk_fat_mass_in_right_arm-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'weight', + 'friendly_name': 'henk Fat mass in right arm', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.henk_fat_mass_in_right_arm', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0.99', + }) +# --- +# name: test_all_entities[sensor.henk_fat_mass_in_right_leg-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.henk_fat_mass_in_right_leg', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Fat mass in right leg', + 'platform': 'withings', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'fat_mass_for_segments_right_leg', + 'unique_id': 'withings_12345_fat_mass_for_segments_right_leg', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.henk_fat_mass_in_right_leg-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'weight', + 'friendly_name': 'henk Fat mass in right leg', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.henk_fat_mass_in_right_leg', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2.33', + }) +# --- +# name: test_all_entities[sensor.henk_fat_mass_in_torso-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.henk_fat_mass_in_torso', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Fat mass in torso', + 'platform': 'withings', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'fat_mass_for_segments_torso', + 'unique_id': 'withings_12345_fat_mass_for_segments_torso', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.henk_fat_mass_in_torso-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'weight', + 'friendly_name': 'henk Fat mass in torso', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.henk_fat_mass_in_torso', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '10.99', + }) +# --- # name: test_all_entities[sensor.henk_fat_ratio-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -1940,6 +2480,276 @@ 'state': '50', }) # --- +# name: test_all_entities[sensor.henk_muscle_mass_in_left_arm-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.henk_muscle_mass_in_left_arm', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Muscle mass in left arm', + 'platform': 'withings', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'muscle_mass_for_segments_left_arm', + 'unique_id': 'withings_12345_muscle_mass_for_segments_left_arm', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.henk_muscle_mass_in_left_arm-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'weight', + 'friendly_name': 'henk Muscle mass in left arm', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.henk_muscle_mass_in_left_arm', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '4.77', + }) +# --- +# name: test_all_entities[sensor.henk_muscle_mass_in_left_leg-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.henk_muscle_mass_in_left_leg', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Muscle mass in left leg', + 'platform': 'withings', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'muscle_mass_for_segments_left_leg', + 'unique_id': 'withings_12345_muscle_mass_for_segments_left_leg', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.henk_muscle_mass_in_left_leg-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'weight', + 'friendly_name': 'henk Muscle mass in left leg', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.henk_muscle_mass_in_left_leg', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '13.09', + }) +# --- +# name: test_all_entities[sensor.henk_muscle_mass_in_right_arm-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.henk_muscle_mass_in_right_arm', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Muscle mass in right arm', + 'platform': 'withings', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'muscle_mass_for_segments_right_arm', + 'unique_id': 'withings_12345_muscle_mass_for_segments_right_arm', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.henk_muscle_mass_in_right_arm-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'weight', + 'friendly_name': 'henk Muscle mass in right arm', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.henk_muscle_mass_in_right_arm', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '4.89', + }) +# --- +# name: test_all_entities[sensor.henk_muscle_mass_in_right_leg-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.henk_muscle_mass_in_right_leg', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Muscle mass in right leg', + 'platform': 'withings', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'muscle_mass_for_segments_right_leg', + 'unique_id': 'withings_12345_muscle_mass_for_segments_right_leg', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.henk_muscle_mass_in_right_leg-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'weight', + 'friendly_name': 'henk Muscle mass in right leg', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.henk_muscle_mass_in_right_leg', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '13.29', + }) +# --- +# name: test_all_entities[sensor.henk_muscle_mass_in_torso-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.henk_muscle_mass_in_torso', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Muscle mass in torso', + 'platform': 'withings', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'muscle_mass_for_segments_torso', + 'unique_id': 'withings_12345_muscle_mass_for_segments_torso', + 'unit_of_measurement': , + }) +# --- +# name: test_all_entities[sensor.henk_muscle_mass_in_torso-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'weight', + 'friendly_name': 'henk Muscle mass in torso', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.henk_muscle_mass_in_torso', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '38.7', + }) +# --- # name: test_all_entities[sensor.henk_pause_during_last_workout-entry] EntityRegistryEntrySnapshot({ 'aliases': set({