@@ -43,6 +43,7 @@ def __init__(self, hass: HomeAssistant, entry: EufyLifeConfigEntry) -> None:
4343 self ._update_count = 0
4444 self ._last_successful_update = None
4545 self ._consecutive_failures = 0
46+ self ._last_device_timestamp = None # Track last measurement timestamp
4647
4748 # Get update interval from config, fallback to default
4849 update_interval_seconds = entry .data .get (CONF_UPDATE_INTERVAL , DEFAULT_UPDATE_INTERVAL )
@@ -145,6 +146,15 @@ async def _fetch_data(self) -> dict[str, Any]:
145146 if device_data :
146147 _LOGGER .info ("Device data endpoint returned %d records, processing..." , len (device_data ))
147148 processed_device_data = await self ._process_device_data (device_data )
149+
150+ # Log what data we received
151+ if processed_device_data :
152+ for customer_id , customer_data in processed_device_data .items ():
153+ last_update = customer_data .get ("last_update" )
154+ if last_update :
155+ _LOGGER .info ("Customer %s: latest measurement at %s" ,
156+ customer_id [:8 ], last_update .strftime ('%Y-%m-%d %H:%M:%S' ))
157+
148158 return processed_device_data
149159 else :
150160 _LOGGER .warning ("No device data available from API" )
@@ -154,17 +164,27 @@ async def _fetch_device_data(self) -> dict[str, Any]:
154164 """Fetch recent device data from EufyLife API."""
155165 data = self .entry .runtime_data
156166
157- # Calculate timestamp for lookback period (configurable, default 30 days)
158167 import time as time_module
159- lookback_days = self .entry .data .get (CONF_DATA_LOOKBACK_DAYS , DEFAULT_DATA_LOOKBACK_DAYS )
160- since_timestamp = int (time_module .time ()) - (lookback_days * 24 * 3600 )
161168
162- _LOGGER .info (
163- "Fetching device data since timestamp %d (%d days lookback, %s)" ,
164- since_timestamp ,
165- lookback_days ,
166- datetime .fromtimestamp (since_timestamp ).strftime ('%Y-%m-%d %H:%M:%S' )
167- )
169+ # Use last device timestamp if available, otherwise use lookback period
170+ if self ._last_device_timestamp :
171+ # Get data since last measurement (add 1 second to avoid duplicates)
172+ since_timestamp = int (self ._last_device_timestamp ) + 1
173+ _LOGGER .info (
174+ "Fetching device data since last measurement: timestamp %d (%s)" ,
175+ since_timestamp ,
176+ datetime .fromtimestamp (since_timestamp ).strftime ('%Y-%m-%d %H:%M:%S' )
177+ )
178+ else :
179+ # First run - use configurable lookback period
180+ lookback_days = self .entry .data .get (CONF_DATA_LOOKBACK_DAYS , DEFAULT_DATA_LOOKBACK_DAYS )
181+ since_timestamp = int (time_module .time ()) - (lookback_days * 24 * 3600 )
182+ _LOGGER .info (
183+ "First run - fetching device data since timestamp %d (%d days lookback, %s)" ,
184+ since_timestamp ,
185+ lookback_days ,
186+ datetime .fromtimestamp (since_timestamp ).strftime ('%Y-%m-%d %H:%M:%S' )
187+ )
168188
169189 headers = {
170190 "Host" : "api.eufylife.com" ,
@@ -234,12 +254,20 @@ async def _fetch_device_data(self) -> dict[str, Any]:
234254
235255 return actual_data
236256 else :
237- _LOGGER .warning (
238- "No device data found in last %d days (since %s). "
239- "Try taking a measurement on your scale to generate new data." ,
240- lookback_days ,
241- datetime .fromtimestamp (since_timestamp ).strftime ('%Y-%m-%d %H:%M:%S' )
242- )
257+ if self ._last_device_timestamp :
258+ _LOGGER .warning (
259+ "No new device data found since last measurement (%s). "
260+ "Take a new measurement on your scale to generate fresh data." ,
261+ datetime .fromtimestamp (since_timestamp - 1 ).strftime ('%Y-%m-%d %H:%M:%S' )
262+ )
263+ else :
264+ lookback_days = self .entry .data .get (CONF_DATA_LOOKBACK_DAYS , DEFAULT_DATA_LOOKBACK_DAYS )
265+ _LOGGER .warning (
266+ "No device data found in last %d days (since %s). "
267+ "Try taking a measurement on your scale to generate new data." ,
268+ lookback_days ,
269+ datetime .fromtimestamp (since_timestamp ).strftime ('%Y-%m-%d %H:%M:%S' )
270+ )
243271 return {}
244272 else :
245273 _LOGGER .debug ("Device data request failed with status %d" , response .status )
@@ -252,8 +280,13 @@ async def _fetch_device_data(self) -> dict[str, Any]:
252280 async def _process_device_data (self , device_data : list ) -> dict [str , Any ]:
253281 """Process device data into customer format."""
254282 processed_data = {}
283+ latest_timestamp = self ._last_device_timestamp
284+ total_measurements = len (device_data )
255285
256- _LOGGER .debug ("Processing %d device data records" , len (device_data ))
286+ _LOGGER .info ("Processing %d device data records (measurements)" , total_measurements )
287+ if self ._last_device_timestamp :
288+ _LOGGER .debug ("Current last device timestamp: %s" ,
289+ datetime .fromtimestamp (self ._last_device_timestamp ).strftime ('%Y-%m-%d %H:%M:%S' ))
257290
258291 for i , record in enumerate (device_data ):
259292 try :
@@ -276,6 +309,9 @@ async def _process_device_data(self, device_data: list) -> dict[str, Any]:
276309 if update_time :
277310 try :
278311 timestamp = datetime .fromtimestamp (update_time )
312+ # Track the latest timestamp for next API call
313+ if latest_timestamp is None or update_time > latest_timestamp :
314+ latest_timestamp = update_time
279315 except Exception as ts_err :
280316 _LOGGER .debug ("Could not parse timestamp %s: %s" , update_time , ts_err )
281317
@@ -352,15 +388,27 @@ async def _process_device_data(self, device_data: list) -> dict[str, Any]:
352388
353389 # Only process if we have some meaningful measurement data
354390 if any (key in customer_data for key in ["weight" , "body_fat" , "muscle_mass" , "bmi" ]):
355- processed_data [customer_id ] = customer_data
391+ # If we already have data for this customer, keep the most recent one
392+ if customer_id in processed_data :
393+ existing_timestamp = processed_data [customer_id ].get ("last_update" )
394+ if timestamp and existing_timestamp and timestamp > existing_timestamp :
395+ processed_data [customer_id ] = customer_data
396+ _LOGGER .debug ("Updated customer %s with newer measurement (timestamp: %s)" ,
397+ customer_id [:8 ], timestamp .strftime ('%Y-%m-%d %H:%M:%S' ))
398+ else :
399+ _LOGGER .debug ("Keeping existing measurement for customer %s (older or same timestamp)" ,
400+ customer_id [:8 ])
401+ else :
402+ processed_data [customer_id ] = customer_data
356403
357404 _LOGGER .debug (
358- "Processed device record #%d for customer %s: weight=%s kg, body_fat=%s%%, muscle_mass=%s kg, bmi=%s" ,
405+ "Processed device record #%d for customer %s: weight=%s kg, body_fat=%s%%, muscle_mass=%s kg, bmi=%s, timestamp=%s " ,
359406 i , customer_id [:8 ],
360407 customer_data .get ("weight" ),
361408 customer_data .get ("body_fat" ),
362409 customer_data .get ("muscle_mass" ),
363- customer_data .get ("bmi" )
410+ customer_data .get ("bmi" ),
411+ timestamp .strftime ('%Y-%m-%d %H:%M:%S' ) if timestamp else "None"
364412 )
365413 else :
366414 _LOGGER .debug ("Device record #%d for customer %s contains no usable measurement data" ,
@@ -370,7 +418,18 @@ async def _process_device_data(self, device_data: list) -> dict[str, Any]:
370418 _LOGGER .warning ("Error processing device record #%d: %s" , i , err )
371419 continue
372420
373- _LOGGER .info ("Successfully processed device data for %d customers" , len (processed_data ))
421+ # Update the last device timestamp for next API call
422+ if latest_timestamp is not None :
423+ self ._last_device_timestamp = latest_timestamp
424+ _LOGGER .info ("Updated last device timestamp to %s for next API call" ,
425+ datetime .fromtimestamp (latest_timestamp ).strftime ('%Y-%m-%d %H:%M:%S' ))
426+
427+ _LOGGER .info ("Successfully processed %d measurements into data for %d customers" ,
428+ total_measurements , len (processed_data ))
429+
430+ if total_measurements > len (processed_data ):
431+ _LOGGER .debug ("Some measurements were for the same customers - kept most recent per customer" )
432+
374433 return processed_data
375434
376435
@@ -393,6 +452,11 @@ async def async_request_refresh(self) -> None:
393452 """Request a manual refresh of data."""
394453 _LOGGER .info ("Manual data refresh requested" )
395454 await super ().async_request_refresh ()
455+
456+ def reset_device_timestamp (self ) -> None :
457+ """Reset the device timestamp to force full data reload on next update."""
458+ self ._last_device_timestamp = None
459+ _LOGGER .info ("Device timestamp reset - next update will use full lookback period" )
396460
397461
398462async def async_setup_entry (
0 commit comments