5.Develop an application that send temperature and humidity sensor data to a cloud server through an HTTP-based REST API, stores the received data in a cloud database(Supabase / Firebase), and displays the sensor readings on a web-based dashboard.

pip install flask requests supabase python-dotenv

iot_http_dashboard/
│
├── app.py
├── sensor.py
├── .env
├── requirements.txt
│
└── templates/
    └── index.html

supabase:

CREATE TABLE sensor_readings (
    id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    temperature FLOAT NOT NULL,
    humidity FLOAT NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

.env:

SUPABASE_URL=https://YOUR_PROJECT_ID.supabase.co
SUPABASE_KEY=YOUR_SERVICE_ROLE_KEY

app.py:


from flask import Flask, request, jsonify, render_template
from supabase import create_client
from dotenv import load_dotenv
import os

load_dotenv()

app = Flask(__name__)

# Supabase connection
SUPABASE_URL = os.getenv("SUPABASE_URL")
SUPABASE_KEY = os.getenv("SUPABASE_KEY")

if not SUPABASE_URL or not SUPABASE_KEY:
    raise ValueError(
        "SUPABASE_URL and SUPABASE_KEY must be set in the .env file"
    )

supabase = create_client(SUPABASE_URL, SUPABASE_KEY)


# Dashboard
@app.route("/")
def dashboard():
    return render_template("index.html")


# REST API: Receive and store sensor data
@app.route("/api/readings", methods=["POST"])
def receive_data():
    data = request.get_json(silent=True)

    if not isinstance(data, dict):
        return jsonify({"error": "Invalid JSON data"}), 400

    try:
        temperature = float(data["temperature"])
        humidity = float(data["humidity"])

        if not (-50 <= temperature <= 100):
            return jsonify({"error": "Invalid temperature value"}), 400

        if not (0 <= humidity <= 100):
            return jsonify({"error": "Invalid humidity value"}), 400

    except (KeyError, TypeError, ValueError):
        return jsonify({"error": "Temperature and humidity must be valid numbers"}), 400

    reading = {
        "temperature": temperature,
        "humidity": humidity
    }

    try:
        result = supabase.table("sensor_readings").insert(reading).execute()

        return jsonify({
            "message": "Data stored successfully",
            "data": result.data
        }), 201

    except Exception as e:
        return jsonify({"error": str(e)}), 500


# REST API: Retrieve sensor records
@app.route("/api/readings", methods=["GET"])
def get_data():
    result = (
        supabase.table("sensor_readings")
        .select("*")
        .order("created_at", desc=True)
        .limit(50)
        .execute()
    )

    return jsonify(result.data)


if __name__ == "__main__":
    app.run(debug=True, use_reloader=False)

sensor.py:


import requests
import random
import time

URL = "http://127.0.0.1:5000/api/readings"

print("Temperature and Humidity Sensor Started")

while True:

    temperature = round(random.uniform(20, 40), 2)
    humidity = round(random.uniform(40, 90), 2)

    data = {
        "temperature": temperature,
        "humidity": humidity
    }

    try:
        response = requests.post(URL, json=data, timeout=10)
        response.raise_for_status()

        print("Temperature:", temperature, "°C")
        print("Humidity:", humidity, "%")
        print("Server Response:", response.json())
        print("--------------------------")

    except requests.exceptions.RequestException as e:
        print("Connection Error:", e)

    time.sleep(5)


templates/index.html:


<!DOCTYPE html>
<html>
<head>
    <title>IoT Sensor Dashboard</title>

    <meta name="viewport" content="width=device-width, initial-scale=1">

    <style>
        body {
            font-family: Arial;
            background: #eef2f7;
            text-align: center;
            padding: 30px;
        }

        h1 {
            color: #1e293b;
        }

        .cards {
            display: flex;
            justify-content: center;
            gap: 20px;
            flex-wrap: wrap;
        }

        .card {
            background: white;
            padding: 25px;
            width: 220px;
            border-radius: 12px;
            box-shadow: 0 3px 10px #ccc;
        }

        .value {
            font-size: 35px;
            color: #2563eb;
            font-weight: bold;
        }

        table {
            margin: 30px auto;
            width: 90%;
            background: white;
            border-collapse: collapse;
        }

        th, td {
            padding: 12px;
            border: 1px solid #ddd;
        }

        th {
            background: #2563eb;
            color: white;
        }
    </style>
</head>

<body>

    <h1>IoT Temperature & Humidity Dashboard</h1>

    <div class="cards">

        <div class="card">
            <h2>Temperature</h2>
            <div class="value" id="temperature">-- °C</div>
        </div>

        <div class="card">
            <h2>Humidity</h2>
            <div class="value" id="humidity">-- %</div>
        </div>

    </div>

    <h2>Sensor Reading History</h2>

    <table>
        <thead>
            <tr>
                <th>Temperature (°C)</th>
                <th>Humidity (%)</th>
                <th>Timestamp</th>
            </tr>
        </thead>

        <tbody id="readings"></tbody>
    </table>

    <script>
        async function loadReadings() {

            const response = await fetch("/api/readings");
            const data = await response.json();

            if (data.length > 0) {

                document.getElementById("temperature").innerText =
                    data[0].temperature + " °C";

                document.getElementById("humidity").innerText =
                    data[0].humidity + " %";
            }

            const table = document.getElementById("readings");

            table.innerHTML = "";

            data.forEach(item => {

                const row = `
                    <tr>
                        <td>${item.temperature}</td>
                        <td>${item.humidity}</td>
                        <td>${new Date(item.created_at).toLocaleString()}</td>
                    </tr>
                `;

                table.innerHTML += row;
            });
        }

        loadReadings();

        setInterval(loadReadings, 5000);
    </script>

</body>
</html>
