Wait, is this peak ?
Build, push image, and notify Watchtower / build-image (push) Successful in 3m32s
Build, push image, and notify Watchtower / notify (push) Successful in 13s

This commit is contained in:
2026-08-04 18:21:20 +02:00
parent caf81d4bbb
commit 5c60017e8d
13 changed files with 249 additions and 89 deletions
+51 -21
View File
@@ -34,9 +34,12 @@ class MicrowaveState:
# Global state trackers
microwave_states = {"2": MicrowaveState.IDLE}
cooking_data_cache = {} # Replaces cooking_queue
button_state = False
async_event_queue = None
# Async synchronization trackers for MQTT IR sensors responses
ir_data_cache = {} # mw_id -> dict of IR readings
ir_data_events = {} # mw_id -> asyncio.Event()
# --- HARDWARE SETUP ---
lora = get_lora()
@@ -141,20 +144,47 @@ async def handle_new_dish(microwave_id, detected_height):
"""Triggered when a new dish is placed inside."""
microwave_states[microwave_id] = MicrowaveState.ANALYZING
print(f"\n[{microwave_id}] 🍽️ Dish detected at {detected_height:.1f} cm! Requesting IR from microwave...")
# 1. Ask microwave for IR temp via MQTT
mqtt_client.publish(config.MQTT_TOPIC_COOKING, payloads.mqtt_cooking_init(microwave_id), qos=config.MQTT_QOS)
# 2. Read local sensors (passing detected_height to prevent GPIO collision)
sensors = await asyncio.to_thread(read_local_sensors, microwave_id, detected_height)
# Check if state changed while taking photos
if microwave_states[microwave_id] != MicrowaveState.ANALYZING:
# 1. Setup synchronization event and clear previous cache for this microwave
event = asyncio.Event()
ir_data_events[microwave_id] = event
ir_data_cache.pop(microwave_id, None)
# 2. Send IR request to ESP32 via MQTT immediately
mqtt_client.publish(
config.MQTT_TOPIC_COOKING,
payloads.mqtt_cooking_init(microwave_id),
qos=config.MQTT_QOS
)
# 3. Start local sensor reading in parallel
sensor_task = asyncio.create_task(asyncio.to_thread(read_local_sensors, microwave_id, detected_height))
# 4. Wait for local sensors to finish reading
sensors_data = await sensor_task
# Check if dish was removed while reading sensors
if microwave_states.get(microwave_id) != MicrowaveState.ANALYZING:
print(f"[{microwave_id}] Dish removed during sensor read. Aborting.")
ir_data_events.pop(microwave_id, None)
return
cooking_data_cache[microwave_id] = sensors
print(f"[{microwave_id}] Local sensors cached. Waiting for MQTT IR data...")
# 5. Wait for MQTT IR data (if it already arrived, event.wait() returns instantly)
try:
await asyncio.wait_for(event.wait(), timeout=10.0)
ir_payload = ir_data_cache.get(microwave_id, {})
sensors_data["ir_initial_temp"] = ir_payload.get("dish_temp")
sensors_data["ir_ambient_temp"] = ir_payload.get("ambient_temp")
print(f"[{microwave_id}] IR data synchronized successfully: {ir_payload}")
except asyncio.TimeoutError:
print(f"[{microwave_id}] ⚠️ Timeout waiting for MQTT IR data from ESP32.")
sensors_data["ir_initial_temp"] = None
sensors_data["ir_ambient_temp"] = None
finally:
ir_data_events.pop(microwave_id, None)
# 6. Dispatch cloud request task
asyncio.create_task(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."""
@@ -236,14 +266,13 @@ async def process_messages_task():
)
elif topic == sensor_topic:
mw_id = data.get("id_microwave")
mw_id = str(data.get("id_microwave"))
print(f"[MQTT] Sensor data received for microwave {mw_id}: {data}")
if mw_id and microwave_states.get(mw_id) == MicrowaveState.ANALYZING:
sensors = cooking_data_cache.get(mw_id)
if sensors:
sensors["ir_initial_temp"] = data.get("dish_temp")
sensors["ir_ambient_temp"] = data.get("ambient_temp")
asyncio.create_task(request_cloud_cooking_plan(mw_id, sensors))
# Store IR data and notify the waiting dish handler
ir_data_cache[mw_id] = data
if mw_id in ir_data_events:
ir_data_events[mw_id].set()
async def get_filtered_dish_height(samples=3, delay=0.04):
"""Reads ultrasonic sensor multiple times and returns the median, discarding invalid zeros."""
@@ -299,8 +328,9 @@ async def monitor_dish_height_task():
microwave_states[mw_id] = MicrowaveState.IDLE
if current_state == MicrowaveState.COOKING:
_stop_hardware(mw_id)
if mw_id in cooking_data_cache:
del cooking_data_cache[mw_id]
# Remove from IR cache and events
ir_data_cache.pop(mw_id, None)
ir_data_events.pop(mw_id, None)
await asyncio.sleep(0.3)
+7 -3
View File
@@ -11,7 +11,8 @@ grovepi.pinMode(button, "INPUT")
button_callback = None
def read_button_state():
if not grove_lock.acquire(timeout=0.05):
# Increase timeout slightly so the button thread can wait for long I2C sensor reads to finish
if not grove_lock.acquire(timeout=0.2):
return None
try:
return grovepi.digitalRead(button)
@@ -26,15 +27,18 @@ def monitor_button():
last_button_state = button_switch_state
while True:
time.sleep(0.04)
current_state = read_button_state()
if current_state is not None:
# Rising edge detection (0 -> 1 transition)
if current_state == 1 and last_button_state == 0:
if button_callback:
button_callback()
last_button_state = current_state
time.sleep(0.02) # Fast 20ms poll when lock is clear
else:
# Lock was busy; retry quickly without updating last_button_state
time.sleep(0.01)
def start_button_monitoring_thread():
threading.Thread(target=monitor_button, daemon=True).start()
+1 -1
View File
@@ -7,7 +7,7 @@ lora.configure()
print("Raspberry Pi : En attente active de JSON...")
while True:
paquet = lora.receive_packet(timeout_ms=5000)
paquet = lora.receive_reliable(timeout_ms=5000)
if paquet:
# Plus besoin de décoder du HEX ou de parser du JSON manuellement !
groupe = paquet['group']