From 271fe2ca70c624883b39a0f2bd9494dba77aba4a Mon Sep 17 00:00:00 2001 From: Noah Date: Tue, 21 Apr 2026 13:59:24 +0300 Subject: [PATCH] feat: add IoT Flask logger for ESP32 sensor telemetry --- iot/logging/README.md | 42 +++++++------ iot/logging/app.py | 113 +++++++++++++++++++++++++++++++++++ iot/logging/requirements.txt | 1 + 3 files changed, 134 insertions(+), 22 deletions(-) create mode 100644 iot/logging/app.py create mode 100644 iot/logging/requirements.txt diff --git a/iot/logging/README.md b/iot/logging/README.md index 2fec724..4553a72 100644 --- a/iot/logging/README.md +++ b/iot/logging/README.md @@ -1,27 +1,25 @@ -# IoT Logging Server +# IoT Sensor Logger -This is a simple Flask-based server for ingesting sensor data from IoT devices (e.g., ESP32). +Lightweight Flask service that receives telemetry from ESP32 sensor nodes +and stores it in SQLite for the LifeLine-ICT platform. -## Usage +## Run -1. Install dependencies: - ```bash - pip install flask - ``` -2. Run the server: - ```bash - python log_data.py - ``` -3. The server will listen on port 5000 for POST requests to `/data`. - -## Example Payload -``` -{ - "sensor_id": 1, - "metric": "temperature", - "value": 23.5, - "timestamp": "2025-10-11T12:00:00Z" -} +```bash +pip install -r requirements.txt +python app.py ``` -All received data is logged to `logs/sensor_data.log`. +## Endpoints + +- `GET /health` — Check service is running +- `POST /log` — Submit sensor telemetry (JSON) +- `GET /logs` — View last 50 telemetry records + +## Sample Request + +```bash +curl -X POST http://localhost:5000/log \ + -H "Content-Type: application/json" \ + -d '{"sensor_id":"ESP32-001","temperature":24.5,"humidity":68.2,"flood_level":12.3}' +``` \ No newline at end of file diff --git a/iot/logging/app.py b/iot/logging/app.py new file mode 100644 index 0000000..152f111 --- /dev/null +++ b/iot/logging/app.py @@ -0,0 +1,113 @@ +""" +LifeLine-ICT IoT Sensor Logger +A lightweight Flask service that receives and stores +telemetry data from ESP32 field sensor nodes. +""" + +from flask import Flask, request, jsonify +import sqlite3 +import os +from datetime import datetime + +app = Flask(__name__) +DB_PATH = os.path.join(os.path.dirname(__file__), 'telemetry.db') + + +def init_db(): + """Initialize the SQLite database and create the telemetry table.""" + conn = sqlite3.connect(DB_PATH) + conn.execute(''' + CREATE TABLE IF NOT EXISTS telemetry ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + sensor_id TEXT NOT NULL, + temperature REAL, + humidity REAL, + flood_level REAL, + timestamp TEXT NOT NULL, + received_at TEXT NOT NULL + ) + ''') + conn.commit() + conn.close() + + +@app.route('/health', methods=['GET']) +def health(): + """Health check endpoint.""" + return jsonify({"status": "ok", "service": "LifeLine-ICT IoT Logger"}), 200 + + +@app.route('/log', methods=['POST']) +def log_telemetry(): + """ + Receive telemetry data from an ESP32 sensor node. + + Expected JSON payload: + { + "sensor_id": "ESP32-001", + "temperature": 24.5, + "humidity": 68.2, + "flood_level": 12.3, + "timestamp": "2026-04-21T10:30:00Z" + } + """ + data = request.get_json(silent=True) + + if not data: + return jsonify({"error": "Invalid JSON payload"}), 400 + + sensor_id = data.get('sensor_id') + if not sensor_id: + return jsonify({"error": "sensor_id is required"}), 400 + + temperature = data.get('temperature') + humidity = data.get('humidity') + flood_level = data.get('flood_level') + timestamp = data.get('timestamp', datetime.utcnow().isoformat()) + received_at = datetime.utcnow().isoformat() + + conn = sqlite3.connect(DB_PATH) + conn.execute(''' + INSERT INTO telemetry + (sensor_id, temperature, humidity, flood_level, timestamp, received_at) + VALUES (?, ?, ?, ?, ?, ?) + ''', (sensor_id, temperature, humidity, flood_level, timestamp, received_at)) + conn.commit() + conn.close() + + return jsonify({ + "status": "logged", + "sensor_id": sensor_id, + "received": received_at + }), 201 + + +@app.route('/logs', methods=['GET']) +def get_logs(): + """Return the 50 most recent telemetry entries.""" + conn = sqlite3.connect(DB_PATH) + cursor = conn.execute( + 'SELECT * FROM telemetry ORDER BY received_at DESC LIMIT 50' + ) + rows = cursor.fetchall() + conn.close() + + logs = [ + { + "id": row[0], + "sensor_id": row[1], + "temperature": row[2], + "humidity": row[3], + "flood_level": row[4], + "timestamp": row[5], + "received_at": row[6], + } + for row in rows + ] + return jsonify({"count": len(logs), "logs": logs}), 200 + + +if __name__ == '__main__': + init_db() + print("LifeLine-ICT IoT Logger running on http://0.0.0.0:5000") + app.run(host='0.0.0.0', port=5000, debug=True) \ No newline at end of file diff --git a/iot/logging/requirements.txt b/iot/logging/requirements.txt new file mode 100644 index 0000000..0f800fc --- /dev/null +++ b/iot/logging/requirements.txt @@ -0,0 +1 @@ +flask==3.0.0 \ No newline at end of file