Wait, is this peak ?
This commit is contained in:
@@ -5,6 +5,11 @@ import shared.deviceTypes as deviceTypes
|
||||
import shared.config as config
|
||||
import shared.payloads as payloads
|
||||
import shared.cookingState as cookingState
|
||||
import shared.safeQueue as safeQueue
|
||||
try:
|
||||
import shared.lora_device as lora_device
|
||||
except ImportError:
|
||||
pass # No need
|
||||
try:
|
||||
import shared.uart_comm as uart_comm
|
||||
except ImportError:
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
DEBUG=True
|
||||
|
||||
# LoRa
|
||||
HEARTBEAT_INTERVAL = 30
|
||||
LORA_HEARTBEAT_INTERVAL = 30
|
||||
|
||||
# MQTT
|
||||
MQTT_BROKER_HOST = "192.168.50.1"
|
||||
|
||||
+27
-9
@@ -13,6 +13,7 @@ class CookingState:
|
||||
self.temperature_provider = temperature_provider
|
||||
self.on_state_change = on_state_change
|
||||
self.on_refresh = on_refresh
|
||||
self.on_pause = None
|
||||
|
||||
self.state = CookingStates.COOKING
|
||||
self.paused = False
|
||||
@@ -24,6 +25,7 @@ class CookingState:
|
||||
self.estimated_remaining_time = float(cook_time)
|
||||
self._last_temperature_sample = None
|
||||
self._last_refresh_signature = None
|
||||
self._stirred = False
|
||||
|
||||
def set_temperature_provider(self, temperature_provider):
|
||||
self.temperature_provider = temperature_provider
|
||||
@@ -33,6 +35,9 @@ class CookingState:
|
||||
|
||||
def set_refresh_callback(self, callback):
|
||||
self.on_refresh = callback
|
||||
|
||||
def set_pause_callback(self, callback):
|
||||
self.on_pause = callback
|
||||
|
||||
def pause(self):
|
||||
if self.paused:
|
||||
@@ -40,8 +45,9 @@ class CookingState:
|
||||
|
||||
self.paused = True
|
||||
self._pause_started_at = time.time()
|
||||
self._notify_refresh(force=True)
|
||||
|
||||
# self._notify_refresh(force=True)
|
||||
if self.on_pause:
|
||||
self.on_pause(self)
|
||||
def unpause(self):
|
||||
if not self.paused:
|
||||
return
|
||||
@@ -50,15 +56,16 @@ class CookingState:
|
||||
if self._pause_started_at is not None:
|
||||
self._paused_duration += now - self._pause_started_at
|
||||
|
||||
self._pause_started_at = None
|
||||
# self._pause_started_at = None
|
||||
self.paused = False
|
||||
self._notify_refresh(force=True)
|
||||
# self._notify_refresh(force=True)
|
||||
|
||||
def toggle_pause(self):
|
||||
if self.paused:
|
||||
self.unpause()
|
||||
else:
|
||||
self.pause()
|
||||
self.on_pause(self)
|
||||
|
||||
def set_state(self, state):
|
||||
if self.state == state:
|
||||
@@ -154,6 +161,8 @@ class CookingState:
|
||||
self.on_refresh(self)
|
||||
|
||||
def update_tick(self):
|
||||
if self.state == CookingStates.IDLE:
|
||||
return self.state
|
||||
if self.paused:
|
||||
self._notify_refresh()
|
||||
return self.state
|
||||
@@ -169,18 +178,20 @@ class CookingState:
|
||||
now = time.time()
|
||||
elapsed_time = self.get_elapsed_time()
|
||||
self.estimated_remaining_time = self.get_remaining_time_estimation()
|
||||
|
||||
print(elapsed_time, self.cook_time, self.current_dish_temp, self.target_temp, self._paused_duration, self._pause_started_at, now)
|
||||
|
||||
if self.current_dish_temp is not None:
|
||||
if elapsed_time < (self.cook_time / 2.0) and self.current_dish_temp >= self.target_temp:
|
||||
if elapsed_time < (self.cook_time / 2.0) and self.current_dish_temp >= self.target_temp and (self._paused_duration == None or self._paused_duration < 5): # If the dish is heating too fast, we require stirring
|
||||
self.state = CookingStates.STIRRING_REQUIRED
|
||||
self.pause()
|
||||
elif elapsed_time >= self.cook_time and self.current_dish_temp >= (self.target_temp - self.TEMPERATURE_TOLERANCE):
|
||||
self.state = CookingStates.DONE
|
||||
elif self.state == CookingStates.DONE and self.current_dish_temp < (self.target_temp - self.TEMPERATURE_TOLERANCE):
|
||||
self.state = CookingStates.COOKING
|
||||
elif elapsed_time >= self.cook_time * 1.25: # If the dish is not heating up
|
||||
elif elapsed_time >= self.cook_time * 1.25 and (self._paused_duration == None or self._paused_duration < 5): # If the dish is not heating up
|
||||
self.state = CookingStates.STIRRING_REQUIRED
|
||||
self.pause()
|
||||
elif self._pause_started_at != None and (self._pause_started_at + self._paused_duration) < (now - (self.cook_time * 0.75)): # If the dish had to be pause and it's been a long time, we stop the cooking
|
||||
self.state = CookingStates.DONE
|
||||
|
||||
self._last_temperature_sample = (now, self.current_dish_temp)
|
||||
|
||||
@@ -196,4 +207,11 @@ class CookingStates:
|
||||
STIRRING_REQUIRED = 1
|
||||
DONE = 2
|
||||
ALERT = 3 # Microwave is too hot internally or other alerts
|
||||
IDLE = 4 # Waiting for cooking parameters to be set, or after cooking is done
|
||||
IDLE = 4 # Waiting for cooking parameters to be set, or after cooking is done
|
||||
|
||||
@staticmethod
|
||||
def get_state_name(state_val):
|
||||
for key, value in CookingStates.__dict__.items():
|
||||
if value == state_val and not key.startswith('__'):
|
||||
return key
|
||||
return "UNKNOWN"
|
||||
@@ -344,7 +344,7 @@ else:
|
||||
print(f"[RPi LoRa Serial] Transmitting HEX payload: {hex_payload}")
|
||||
cmd = f"AT+PSEND={hex_payload}"
|
||||
resp = self._send_at_cmd(cmd, wait_time=0.25) # Wait for RF TX to finish
|
||||
print(f"[RPi LoRa Serial] AT+PSEND response: {resp.strip().replace(chr(10), ' | ')}")
|
||||
print(f"[RPi LoRa Serial] AT+PSEND response: {resp}")
|
||||
|
||||
# Re-enable continuous receive mode after transmission completes
|
||||
self._send_at_cmd("AT+PRECV=65535", wait_time=0.05)
|
||||
|
||||
@@ -303,6 +303,17 @@ class BrokerClient:
|
||||
pass
|
||||
finally:
|
||||
self._client = None
|
||||
|
||||
def ping(self):
|
||||
"""Thread-safe PINGREQ wrapper for MicroPython."""
|
||||
if self._client is None:
|
||||
return
|
||||
if IS_MICROPYTHON:
|
||||
with self._lock:
|
||||
return self._client.ping()
|
||||
else:
|
||||
# Paho handles keepalives automatically via loop_start/loop
|
||||
pass
|
||||
|
||||
def __enter__(self):
|
||||
self.connect()
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import _thread
|
||||
|
||||
class SafeQueue:
|
||||
"""A lightweight, thread-safe FIFO queue for MicroPython."""
|
||||
def __init__(self, maxsize=20):
|
||||
self._queue = []
|
||||
self._lock = _thread.allocate_lock()
|
||||
self.maxsize = maxsize
|
||||
|
||||
def put(self, item) -> bool:
|
||||
"""Push an item to the end of the queue. Returns False if queue is full."""
|
||||
with self._lock:
|
||||
if len(self._queue) < self.maxsize:
|
||||
self._queue.append(item)
|
||||
return True
|
||||
else:
|
||||
print("[Queue Warning] Buffer full, dropping oldest message.")
|
||||
self._queue.pop(0) # Drop oldest to make room
|
||||
self._queue.append(item)
|
||||
return False
|
||||
|
||||
def get(self):
|
||||
"""Pop and return the oldest item from the queue, or None if empty."""
|
||||
with self._lock:
|
||||
if self._queue:
|
||||
return self._queue.pop(0)
|
||||
return None
|
||||
|
||||
def empty(self) -> bool:
|
||||
"""Check if the queue has no items."""
|
||||
with self._lock:
|
||||
return len(self._queue) == 0
|
||||
|
||||
def size(self) -> int:
|
||||
"""Return current number of queued items."""
|
||||
with self._lock:
|
||||
return len(self._queue)
|
||||
Reference in New Issue
Block a user