Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion eufy_sync/eufy_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,11 @@ def _fetch_raw_measurements(self, after_timestamp: int | None) -> list[EufyMeasu
logger.warning("Raw Wi-Fi fallback: fetch failed for %s: %s", device_id, e)

try:
measurements = self._parse_all(records)
measurements = []
for record in records:
m = self._parse_raw_wifi_record(record)
if m is not None:
measurements.append(m)
raw_count = len(measurements)
if self.config.customer_id:
measurements = [m for m in measurements if m.customer_id == self.config.customer_id]
Expand All @@ -332,6 +336,35 @@ def _fetch_raw_measurements(self, after_timestamp: int | None) -> list[EufyMeasu
)
return measurements

def _parse_raw_wifi_record(self, record: dict) -> EufyMeasurement | None:
raw_weight = record.get("weight")
raw_timestamp = record.get("timestamp")
if raw_weight is None or raw_timestamp is None:
logger.warning("Raw Wi-Fi record missing weight or timestamp: %s", record)
return None

try:
weight_kg = float(raw_weight)
update_time = int(raw_timestamp)
except (TypeError, ValueError):
logger.warning("Raw Wi-Fi record has invalid weight or timestamp: %s", record)
return None

if weight_kg <= 0:
logger.warning("Raw Wi-Fi record has invalid weight: %s", raw_weight)
return None

customer_id = record.get("customer_id", "unknown")
measurement_id = f"{customer_id}_{update_time}"

return EufyMeasurement(
measurement_id=measurement_id,
customer_id=customer_id,
device_id=record.get("device_id", "unknown"),
timestamp=datetime.fromtimestamp(update_time, tz=timezone.utc),
weight_kg=weight_kg,
)

def _parse_record(self, record: dict) -> EufyMeasurement | None:
scale_data = record.get("scale_data")
if not scale_data:
Expand Down
24 changes: 21 additions & 3 deletions tests/test_eufy_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,20 @@ def _record(customer_id, weight_dg, update_time):
}


def _raw_wifi_record(customer_id, weight_kg, timestamp):
return {
"id": "raw-record-id",
"weight": f"{weight_kg:.2f}",
"impedance": "112566",
"timestamp": str(timestamp),
"heart_rate": "0",
"customer_id": customer_id,
"device_id": "raw-device-id",
"user_id": "raw-user-id",
"product_code": "",
}


# ---------------------------------------------------------------------------
# Task 2: list_profiles
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -190,14 +204,15 @@ def test_get_raw_records_handles_null_list_500_and_bad_code():

def test_fetch_falls_back_to_raw_when_normal_empty():
c = _client(customer_id="a")
raw = _record("a", 800, 2_000_000_000) # year 2033, passes the window
raw = _raw_wifi_record("a", 80.0, 2_000_000_000) # year 2033, passes the window
with patch.object(c, "_get_records", return_value=[]), \
patch.object(c, "_list_device_ids", return_value=["dev1"]), \
patch.object(c, "_get_raw_records", return_value=[raw]):
measurements = c.fetch_measurements(after_timestamp=1_500_000_000)
assert len(measurements) == 1
assert measurements[0].weight_kg == 80.0
assert measurements[0].customer_id == "a"
assert measurements[0].body_fat_pct is None


def test_fetch_does_not_use_raw_when_normal_has_data():
Expand All @@ -212,7 +227,10 @@ def test_fetch_does_not_use_raw_when_normal_has_data():

def test_raw_fallback_drops_other_profiles():
c = _client(customer_id="a")
raws = [_record("a", 800, 2_000_000_000), _record("b", 600, 2_000_000_000)]
raws = [
_raw_wifi_record("a", 80.0, 2_000_000_000),
_raw_wifi_record("b", 60.0, 2_000_000_000),
]
with patch.object(c, "_get_records", return_value=[]), \
patch.object(c, "_list_device_ids", return_value=["dev1"]), \
patch.object(c, "_get_raw_records", return_value=raws):
Expand All @@ -230,7 +248,7 @@ def test_raw_fallback_degrades_when_device_list_errors():

def test_raw_fallback_degrades_on_malformed_record():
c = _client(customer_id="a")
bad = {"customer_id": "a", "update_time": 100, "scale_data": {"weight": "heavy"}}
bad = {"customer_id": "a", "timestamp": "2_000_000_000", "weight": "heavy"}
with patch.object(c, "_get_records", return_value=[]), \
patch.object(c, "_list_device_ids", return_value=["dev1"]), \
patch.object(c, "_get_raw_records", return_value=[bad]):
Expand Down
Loading