From d3745e15bef50605a53300fdea2342cbbb466af4 Mon Sep 17 00:00:00 2001 From: Ron Date: Sat, 19 Oct 2024 23:01:39 +0100 Subject: [PATCH] some minor body metrics related changes --- README.md | 16 ++++++++++ src/etekcity_esf551_ble/body_metrics.py | 39 +++++++++++++------------ 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 44d3d48..f5c0c2f 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,22 @@ The main class for interacting with the scale. - `hw_version`: Get the hardware version of the scale (read-only). - `sw_version`: Get the software version of the scale (read-only). +### `EtekcitySmartFitnessScaleWithBodyMetrics` + +An extended version of EtekcitySmartFitnessScale that automatically calculates body metrics. + +#### Methods: + +- `__init__(self, address: str, notification_callback: Callable[[ScaleData], None], sex: Sex, birthdate: date, height_m: float, display_unit: WeightUnit = None)` +- `async_start()`: Start scanning for and connecting to the scale. +- `async_stop()`: Stop the connection to the scale. + +#### Properties: + +- `display_unit`: Get or set the display unit (WeightUnit.KG, WeightUnit.LB or WeightUnit.ST). Returns None if the display unit is currently unknown (not set by the user and not yet received from the scale together with a stable weight measurement). +- `hw_version`: Get the hardware version of the scale (read-only). +- `sw_version`: Get the software version of the scale (read-only). + ### `WeightUnit` An enum representing the possible display units: diff --git a/src/etekcity_esf551_ble/body_metrics.py b/src/etekcity_esf551_ble/body_metrics.py index b4a774f..abf0cef 100644 --- a/src/etekcity_esf551_ble/body_metrics.py +++ b/src/etekcity_esf551_ble/body_metrics.py @@ -1,5 +1,4 @@ from collections.abc import Callable -from dataclasses import asdict, dataclass from datetime import date from enum import IntEnum from functools import cached_property @@ -14,8 +13,10 @@ class Sex(IntEnum): Female = 1 -@dataclass class BodyMetrics: + """ + Class for calculating various body composition metrics based on weight, height, age, sex, and impedance. + """ def __init__(self, weight_kg: float, height_m: float, age: int, sex: Sex, impedance: int): self.weight = weight_kg self.height = height_m @@ -309,17 +310,19 @@ def metabolic_age(self) -> int: return max(18, self.age + 8 - age_adjustment_factor) -def calc_age(birthday: str) -> int: + +def _calc_age(birthdate: date) -> int: today = date.today() - birthdate = date.fromisoformat(birthday) years = today.year - birthdate.year - if today.month < birthdate.month or ( - today.month == birthdate.month and today.day < birthdate.day - ): + if today.month < birthdate.month or (today.month == birthdate.month and today.day < birthdate.day): years -= 1 return years +def _as_dictionary(obj: BodyMetrics) -> dict[str, int | float]: + return{prop: getattr(obj, prop) for prop in dir(obj) if not prop.startswith('__')} + + class EtekcitySmartFitnessScaleWithBodyMetrics(EtekcitySmartFitnessScale): def __init__( self, @@ -336,22 +339,20 @@ def __init__( self._original_callback = notification_callback super().__init__( address, - lambda data: self.wrapped_notification_callback( + lambda data: self._wrapped_notification_callback( self._sex, self._birthdate, self._height_m, data ), display_unit, ) - - def wrapped_notification_callback( + + def _wrapped_notification_callback( self, sex: Sex, birthdate: date, height_m: float, data: ScaleData ) -> None: - data.measurements |= asdict( - BodyMetrics( - data.measurements[WEIGHT_KEY], - height_m, - calc_age(birthdate), - sex, - data.measurements[IMPEDANCE_KEY], - ) - ) + data.measurements |= _as_dictionary(BodyMetrics( + data.measurements[WEIGHT_KEY], + height_m, + _calc_age(birthdate), + sex, + data.measurements[IMPEDANCE_KEY], + )) self._original_callback(data)