From eba673e2535ff2d5c85df8b85eb0edd05ea8e943 Mon Sep 17 00:00:00 2001 From: Carlos Molinet Date: Fri, 15 Nov 2024 21:19:11 +0100 Subject: [PATCH 1/4] Add flow rate feature --- aioacaia/acaiascale.py | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/aioacaia/acaiascale.py b/aioacaia/acaiascale.py index 7752cc6..0a2e7eb 100644 --- a/aioacaia/acaiascale.py +++ b/aioacaia/acaiascale.py @@ -6,6 +6,7 @@ import logging import time +from collections import deque from collections.abc import Awaitable, Callable from dataclasses import dataclass @@ -94,6 +95,9 @@ def __init__( self._device_state: AcaiaDeviceState | None = None self._weight: float | None = None + # flow rate + self.weight_history = deque(maxlen=20) # Limit to 20 entries + # queue self._queue: asyncio.Queue = asyncio.Queue() self._add_to_queue_lock = asyncio.Lock() @@ -138,6 +142,45 @@ def timer(self) -> int: return 0 return int(self._timer_stop - self._timer_start) + + @property + def flow_rate(self) -> float: + + if len(self.weight_history) < 4: + return None + + now = time.time() + flows = [] + + # Calculate flow rates using 3 readings ago + for i in range(3, len(self.weight_history)): + prev_time, prev_weight = self.weight_history[i - 3] + curr_time, curr_weight = self.weight_history[i] + + time_diff = curr_time - prev_time + weight_diff = curr_weight - prev_weight + + # Ignore weights older than 5 seconds + if now - prev_time > 5: + continue + + # Validate weight difference and flow rate limits + flow = weight_diff / time_diff + if flow <= 20.0: # Flow rate limit + flows.append(flow) + + if not flows: + return None + + # Compute the Exponential Moving Average (EMA) + alpha = 2 / (len(flows) + 1) # EMA weighting factor + ema = flows[0] # Initialize EMA with the first flow rate + + for flow in flows[1:]: + ema = alpha * flow + (1 - alpha) * ema + + _LOGGER.debug("Flow rate: %.2f g/s", ema) + return ema def device_disconnected_handler( self, @@ -438,6 +481,16 @@ async def on_bluetooth_data_received( elif isinstance(msg, Message): self._weight = msg.value + timestamp = time.time() + + # Check if weight is increasing before appending + if not self.weight_history or msg.value > self.weight_history[-1][1]: + self.weight_history.append((timestamp, msg.value)) + elif msg.value < self.weight_history[-1][1] - 1: + # Clear history if weight decreases (1gr margin error) + self.weight_history.clear() + self.weight_history.append((timestamp, msg.value)) + if msg.timer_running is not None: self.timer_running = msg.timer_running _LOGGER.debug("Got weight %s", str(msg.value)) From 67e1abc597467386b7de73dab181abd25785fd29 Mon Sep 17 00:00:00 2001 From: carlosmolinet Date: Sat, 16 Nov 2024 11:46:46 +0100 Subject: [PATCH 2/4] Update aioacaia/acaiascale.py Co-authored-by: Josef Zweck <24647999+zweckj@users.noreply.github.com> --- aioacaia/acaiascale.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aioacaia/acaiascale.py b/aioacaia/acaiascale.py index 0a2e7eb..31fb4bb 100644 --- a/aioacaia/acaiascale.py +++ b/aioacaia/acaiascale.py @@ -144,7 +144,8 @@ def timer(self) -> int: return int(self._timer_stop - self._timer_start) @property - def flow_rate(self) -> float: + def flow_rate(self) -> float | None: + if len(self.weight_history) < 4: return None From 2573a3a76ff2a0e2c4f266156cd0c1dcc0caf088 Mon Sep 17 00:00:00 2001 From: carlosmolinet Date: Sat, 16 Nov 2024 11:47:00 +0100 Subject: [PATCH 3/4] Update aioacaia/acaiascale.py Co-authored-by: Josef Zweck <24647999+zweckj@users.noreply.github.com> --- aioacaia/acaiascale.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aioacaia/acaiascale.py b/aioacaia/acaiascale.py index 31fb4bb..82a5464 100644 --- a/aioacaia/acaiascale.py +++ b/aioacaia/acaiascale.py @@ -96,7 +96,8 @@ def __init__( self._weight: float | None = None # flow rate - self.weight_history = deque(maxlen=20) # Limit to 20 entries + self.weight_history: deque[tuple[float, float]] = deque(maxlen=20) # Limit to 20 entries + # queue self._queue: asyncio.Queue = asyncio.Queue() From 48363c58c1264c20e2231326ab7558539342c354 Mon Sep 17 00:00:00 2001 From: Carlos Molinet Date: Sat, 16 Nov 2024 12:09:39 +0100 Subject: [PATCH 4/4] Remove old weights from the list --- aioacaia/acaiascale.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aioacaia/acaiascale.py b/aioacaia/acaiascale.py index 82a5464..f423530 100644 --- a/aioacaia/acaiascale.py +++ b/aioacaia/acaiascale.py @@ -146,14 +146,17 @@ def timer(self) -> int: @property def flow_rate(self) -> float | None: + now = time.time() + flows = [] + # Remove old readings (more than 5 seconds) + self.weight_history = [ + (t, w) for t, w in self.weight_history if now - t <= 5 + ] if len(self.weight_history) < 4: return None - now = time.time() - flows = [] - # Calculate flow rates using 3 readings ago for i in range(3, len(self.weight_history)): prev_time, prev_weight = self.weight_history[i - 3] @@ -162,9 +165,6 @@ def flow_rate(self) -> float | None: time_diff = curr_time - prev_time weight_diff = curr_weight - prev_weight - # Ignore weights older than 5 seconds - if now - prev_time > 5: - continue # Validate weight difference and flow rate limits flow = weight_diff / time_diff