diff --git a/cloud/APIs/edamam.py b/cloud/APIs/edamam.py index 68e6709..1387d6e 100644 --- a/cloud/APIs/edamam.py +++ b/cloud/APIs/edamam.py @@ -6,7 +6,7 @@ import json EDAMAM_APP_ID__FOOD = os.getenv("EDAMAM_APP_ID__FOOD", None) EDAMAM_APP_KEY__FOOD = os.getenv("EDAMAM_APP_KEY__FOOD", None) -SAVE_EDAMAM_API_TOKEN = os.getenv("SAVE_EDAMAM_API_TOKEN", False) +SAVEUP_EDAMAM_API_TOKEN = os.getenv("SAVEUP_EDAMAM_API_TOKEN", False) class EdamamAPI: """Wrapper around Edamam Food Database API 2.0 (Vision & Nutrients)""" @@ -17,7 +17,7 @@ class EdamamAPI: pass def analyze_dish_image(self, image_file_path: str): - if SAVE_EDAMAM_API_TOKEN: + if SAVEUP_EDAMAM_API_TOKEN: time.sleep(3) return json.loads(""" { diff --git a/cloud/app.py b/cloud/app.py index 1250527..2287692 100644 --- a/cloud/app.py +++ b/cloud/app.py @@ -3,6 +3,7 @@ import base64 import uuid import datetime import sys +import json from flask import Flask, request, jsonify from pymongo import MongoClient from APIs import generate, EdamamAPI @@ -112,14 +113,23 @@ def cooking_params(): def telemetry(): data = request.get_json() - if not data: + if data is None: return jsonify({"error": "Invalid or missing JSON payload"}), 400 + # If the payload was double-encoded as a string, deserialize it + if isinstance(data, str): + try: + data = json.loads(data) + except (json.JSONDecodeError, TypeError): + return jsonify({"error": "String payload could not be parsed as JSON"}), 400 + + if not isinstance(data, dict): + return jsonify({"error": "Expected a JSON object/dictionary"}), 400 + # Stamp UTC timestamp for Node-RED queries data["received_at"] = datetime.datetime.now(datetime.timezone.utc).isoformat() try: - # Mongo creates '_id' automatically upon insertion telemetry_collection.insert_one(data) return jsonify({"status": "success", "message": "Telemetry saved"}), 200 diff --git a/orchestrateur/main.py b/orchestrateur/main.py index 440f943..99708f0 100644 --- a/orchestrateur/main.py +++ b/orchestrateur/main.py @@ -415,10 +415,10 @@ async def handle_telemetry_request(endpoint: str): # 1. Fetch systemd logs asynchronously logs_list = await get_systemd_logs(lines=200, service_name="smartwave") - # 2. Unpack temperature and humidity from sensors.temp_hum + # 2. Unpack temperature and humidity ambient_temp, ambient_humidity = temp_hum.get_temperature_and_humidity_with_retry() - # 3. Build the telemetry payload + # 3. Build the telemetry payload (returns a JSON string) telemetry_payload = payloads.telemetry_payload( device_id=DEVICE_ID, microwave_states=microwave_states, @@ -431,14 +431,18 @@ async def handle_telemetry_request(endpoint: str): logs=logs_list ) - print(telemetry_payload) print(f"[Telemetry] Sending payload with {len(logs_list)} log entries...") - # 4. Offload blocking HTTP POST to thread pool + # 4. Wait for he microwave turn to send the telemetry data to the cloud endpoint + timeout = int(DEVICE_ID.split("_")[-1]) * config.TELEMETRY_SEND_INTERVAL + print(f"[Telemetry] Waiting for {timeout}s before sending telemetry to avoid collisions...") + await asyncio.sleep(timeout) + + # 5. Offload blocking HTTP POST to thread pool response = await asyncio.to_thread( requests.post, endpoint, - json=telemetry_payload, + data=telemetry_payload, # <-- Changed from json=telemetry_payload headers={"Content-Type": "application/json"}, timeout=15 ) diff --git a/shared/config.py b/shared/config.py index 4540c5e..094cec1 100644 --- a/shared/config.py +++ b/shared/config.py @@ -18,4 +18,7 @@ MQTT_HELLO_INTERVAL = 30 # Microwave Model COOKING_COMPARTMENT_HEIGHT = 30 # cm -BUZZER_ACTIVATED = False \ No newline at end of file +BUZZER_ACTIVATED = False + +# TELEMETRY +TELEMETRY_SEND_INTERVAL = 3 \ No newline at end of file