Retries with cloud
Still need to to be able to reset the cooking_state so hat the user can reinsert a dish
This commit is contained in:
+37
-7
@@ -35,7 +35,9 @@ class MicrowaveState:
|
|||||||
# Global state trackers
|
# Global state trackers
|
||||||
microwave_states = {"2": MicrowaveState.IDLE}
|
microwave_states = {"2": MicrowaveState.IDLE}
|
||||||
button_state = False
|
button_state = False
|
||||||
|
cloud_alert = False # Global status flag for screen / UI display
|
||||||
async_event_queue = None
|
async_event_queue = None
|
||||||
|
|
||||||
# Async synchronization trackers for MQTT IR sensors responses
|
# Async synchronization trackers for MQTT IR sensors responses
|
||||||
ir_data_cache = {} # mw_id -> dict of IR readings
|
ir_data_cache = {} # mw_id -> dict of IR readings
|
||||||
ir_data_events = {} # mw_id -> asyncio.Event()
|
ir_data_events = {} # mw_id -> asyncio.Event()
|
||||||
@@ -109,7 +111,7 @@ button.start_button_monitoring_thread()
|
|||||||
|
|
||||||
# --- HARDWARE CONTROLLERS ---
|
# --- HARDWARE CONTROLLERS ---
|
||||||
def _stop_hardware(microwave_id: str):
|
def _stop_hardware(microwave_id: str):
|
||||||
print(f"[{microwave_id}] /!\ Emergency stop issued to hardware.")
|
print(f"[{microwave_id}] /!\\ Emergency stop issued to hardware.")
|
||||||
# TODO: Add LoRa STOP command here
|
# TODO: Add LoRa STOP command here
|
||||||
|
|
||||||
# --- ASYNC COOKING LOGIC ---
|
# --- ASYNC COOKING LOGIC ---
|
||||||
@@ -187,7 +189,8 @@ async def handle_new_dish(microwave_id, detected_height):
|
|||||||
asyncio.create_task(request_cloud_cooking_plan(microwave_id, sensors_data))
|
asyncio.create_task(request_cloud_cooking_plan(microwave_id, sensors_data))
|
||||||
|
|
||||||
async def request_cloud_cooking_plan(microwave_id, sensors_data):
|
async def request_cloud_cooking_plan(microwave_id, sensors_data):
|
||||||
"""Sends all data to the cloud and starts the microwave if successful."""
|
"""Sends all data to the cloud with up to 3 retries (30s interval)."""
|
||||||
|
global cloud_alert
|
||||||
microwave_states[microwave_id] = MicrowaveState.WAITING_FOR_CLOUD
|
microwave_states[microwave_id] = MicrowaveState.WAITING_FOR_CLOUD
|
||||||
URL = "https://smartwave.matthiasg.dev/cooking-params"
|
URL = "https://smartwave.matthiasg.dev/cooking-params"
|
||||||
|
|
||||||
@@ -196,11 +199,20 @@ async def request_cloud_cooking_plan(microwave_id, sensors_data):
|
|||||||
sensors_data["camera_image"] = base64.b64encode(sensors_data["camera_image"]).decode("utf-8")
|
sensors_data["camera_image"] = base64.b64encode(sensors_data["camera_image"]).decode("utf-8")
|
||||||
|
|
||||||
print(f"[{microwave_id}] Requesting cooking plan from cloud app...")
|
print(f"[{microwave_id}] Requesting cooking plan from cloud app...")
|
||||||
try:
|
|
||||||
response = await asyncio.to_thread(requests.post, URL, json=sensors_data, timeout=30)
|
|
||||||
|
|
||||||
|
max_retries = 3
|
||||||
|
retry_delay_seconds = 30
|
||||||
|
|
||||||
|
for attempt in range(1, max_retries + 1):
|
||||||
|
if microwave_states.get(microwave_id) != MicrowaveState.WAITING_FOR_CLOUD:
|
||||||
|
print(f"[{microwave_id}] Dish removed or state changed. Aborting API request.")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
print(f"[{microwave_id}] Connection attempt {attempt}/{max_retries}...")
|
||||||
|
response = await asyncio.to_thread(requests.post, URL, json=sensors_data, timeout=30)
|
||||||
# Abort if state changed (e.g. user removed dish while waiting for wifi)
|
# Abort if state changed (e.g. user removed dish while waiting for wifi)
|
||||||
if microwave_states[microwave_id] != MicrowaveState.WAITING_FOR_CLOUD:
|
if microwave_states.get(microwave_id) != MicrowaveState.WAITING_FOR_CLOUD:
|
||||||
print(f"[{microwave_id}] Dish removed during API request. Discarding API plan.")
|
print(f"[{microwave_id}] Dish removed during API request. Discarding API plan.")
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -212,19 +224,34 @@ async def request_cloud_cooking_plan(microwave_id, sensors_data):
|
|||||||
|
|
||||||
if c_time is None or c_power is None or c_temp is None:
|
if c_time is None or c_power is None or c_temp is None:
|
||||||
print(f"[{microwave_id}] ❌ Invalid plan received: {response.json()}")
|
print(f"[{microwave_id}] ❌ Invalid plan received: {response.json()}")
|
||||||
microwave_states[microwave_id] = MicrowaveState.DONE # Fail safe
|
microwave_states[microwave_id] = MicrowaveState.DONE
|
||||||
return
|
return
|
||||||
|
|
||||||
print(f"[{microwave_id}] Cloud Plan Received! Starting microwave: {c_time}s @ {c_power}W")
|
print(f"[{microwave_id}] Cloud Plan Received! Starting microwave: {c_time}s @ {c_power}W")
|
||||||
|
cloud_alert = False # Reset alert flag on success
|
||||||
microwave_states[microwave_id] = MicrowaveState.COOKING
|
microwave_states[microwave_id] = MicrowaveState.COOKING
|
||||||
mqtt_client.publish(
|
mqtt_client.publish(
|
||||||
config.MQTT_TOPIC_COOKING,
|
config.MQTT_TOPIC_COOKING,
|
||||||
payloads.mqtt_cooking_config(microwave_id, c_time, c_power, c_temp),
|
payloads.mqtt_cooking_config(microwave_id, c_time, c_power, c_temp),
|
||||||
qos=config.MQTT_QOS
|
qos=config.MQTT_QOS
|
||||||
)
|
)
|
||||||
|
return
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[{microwave_id}] Cloud API Error: {e}")
|
print(f"[{microwave_id}] Cloud API Error (Attempt {attempt}/{max_retries}): {e}")
|
||||||
|
|
||||||
|
if attempt < max_retries:
|
||||||
|
print(f"[{microwave_id}] Retrying in {retry_delay_seconds} seconds...")
|
||||||
|
# Interruptible wait loop in case user removes the dish mid-wait
|
||||||
|
for _ in range(retry_delay_seconds):
|
||||||
|
if microwave_states.get(microwave_id) != MicrowaveState.WAITING_FOR_CLOUD:
|
||||||
|
print(f"[{microwave_id}] State changed during retry wait. Aborting retries.")
|
||||||
|
return
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
# Executed only if all 3 retries failed
|
||||||
|
print(f"[{microwave_id}] All 3 cloud retries failed. Setting global alert flag.")
|
||||||
|
cloud_alert = True
|
||||||
microwave_states[microwave_id] = MicrowaveState.DONE
|
microwave_states[microwave_id] = MicrowaveState.DONE
|
||||||
|
|
||||||
# --- MAIN LOGIC TASKS ---
|
# --- MAIN LOGIC TASKS ---
|
||||||
@@ -292,6 +319,7 @@ async def get_filtered_dish_height(samples=3, delay=0.04):
|
|||||||
|
|
||||||
async def monitor_dish_height_task():
|
async def monitor_dish_height_task():
|
||||||
"""Monitors presence of dish with hysteresis and debouncing."""
|
"""Monitors presence of dish with hysteresis and debouncing."""
|
||||||
|
global cloud_alert
|
||||||
mw_id = "2"
|
mw_id = "2"
|
||||||
consecutive_present = 0
|
consecutive_present = 0
|
||||||
consecutive_absent = 0
|
consecutive_absent = 0
|
||||||
@@ -326,6 +354,8 @@ async def monitor_dish_height_task():
|
|||||||
consecutive_absent = 0
|
consecutive_absent = 0
|
||||||
print(f"\n[{mw_id}] Dish Removed! Resetting state to IDLE.")
|
print(f"\n[{mw_id}] Dish Removed! Resetting state to IDLE.")
|
||||||
microwave_states[mw_id] = MicrowaveState.IDLE
|
microwave_states[mw_id] = MicrowaveState.IDLE
|
||||||
|
cloud_alert = False # Reset error alert on dish removal
|
||||||
|
|
||||||
if current_state == MicrowaveState.COOKING:
|
if current_state == MicrowaveState.COOKING:
|
||||||
_stop_hardware(mw_id)
|
_stop_hardware(mw_id)
|
||||||
# Remove from IR cache and events
|
# Remove from IR cache and events
|
||||||
|
|||||||
Reference in New Issue
Block a user