unfolder 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,283 @@
1
+ 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.
2
+
3
+ pip install flask requests supabase python-dotenv
4
+
5
+ iot_http_dashboard/
6
+ │
7
+ ├── app.py
8
+ ├── sensor.py
9
+ ├── .env
10
+ ├── requirements.txt
11
+ │
12
+ └── templates/
13
+ └── index.html
14
+
15
+ supabase:
16
+
17
+ CREATE TABLE sensor_readings (
18
+ id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
19
+ temperature FLOAT NOT NULL,
20
+ humidity FLOAT NOT NULL,
21
+ created_at TIMESTAMPTZ DEFAULT NOW()
22
+ );
23
+
24
+ .env:
25
+
26
+ SUPABASE_URL=https://YOUR_PROJECT_ID.supabase.co
27
+ SUPABASE_KEY=YOUR_SERVICE_ROLE_KEY
28
+
29
+ app.py:
30
+
31
+
32
+ from flask import Flask, request, jsonify, render_template
33
+ from supabase import create_client
34
+ from dotenv import load_dotenv
35
+ import os
36
+
37
+ load_dotenv()
38
+
39
+ app = Flask(__name__)
40
+
41
+ # Supabase connection
42
+ SUPABASE_URL = os.getenv("SUPABASE_URL")
43
+ SUPABASE_KEY = os.getenv("SUPABASE_KEY")
44
+
45
+ if not SUPABASE_URL or not SUPABASE_KEY:
46
+ raise ValueError(
47
+ "SUPABASE_URL and SUPABASE_KEY must be set in the .env file"
48
+ )
49
+
50
+ supabase = create_client(SUPABASE_URL, SUPABASE_KEY)
51
+
52
+
53
+ # Dashboard
54
+ @app.route("/")
55
+ def dashboard():
56
+ return render_template("index.html")
57
+
58
+
59
+ # REST API: Receive and store sensor data
60
+ @app.route("/api/readings", methods=["POST"])
61
+ def receive_data():
62
+ data = request.get_json(silent=True)
63
+
64
+ if not isinstance(data, dict):
65
+ return jsonify({"error": "Invalid JSON data"}), 400
66
+
67
+ try:
68
+ temperature = float(data["temperature"])
69
+ humidity = float(data["humidity"])
70
+
71
+ if not (-50 <= temperature <= 100):
72
+ return jsonify({"error": "Invalid temperature value"}), 400
73
+
74
+ if not (0 <= humidity <= 100):
75
+ return jsonify({"error": "Invalid humidity value"}), 400
76
+
77
+ except (KeyError, TypeError, ValueError):
78
+ return jsonify({"error": "Temperature and humidity must be valid numbers"}), 400
79
+
80
+ reading = {
81
+ "temperature": temperature,
82
+ "humidity": humidity
83
+ }
84
+
85
+ try:
86
+ result = supabase.table("sensor_readings").insert(reading).execute()
87
+
88
+ return jsonify({
89
+ "message": "Data stored successfully",
90
+ "data": result.data
91
+ }), 201
92
+
93
+ except Exception as e:
94
+ return jsonify({"error": str(e)}), 500
95
+
96
+
97
+ # REST API: Retrieve sensor records
98
+ @app.route("/api/readings", methods=["GET"])
99
+ def get_data():
100
+ result = (
101
+ supabase.table("sensor_readings")
102
+ .select("*")
103
+ .order("created_at", desc=True)
104
+ .limit(50)
105
+ .execute()
106
+ )
107
+
108
+ return jsonify(result.data)
109
+
110
+
111
+ if __name__ == "__main__":
112
+ app.run(debug=True, use_reloader=False)
113
+
114
+ sensor.py:
115
+
116
+
117
+ import requests
118
+ import random
119
+ import time
120
+
121
+ URL = "http://127.0.0.1:5000/api/readings"
122
+
123
+ print("Temperature and Humidity Sensor Started")
124
+
125
+ while True:
126
+
127
+ temperature = round(random.uniform(20, 40), 2)
128
+ humidity = round(random.uniform(40, 90), 2)
129
+
130
+ data = {
131
+ "temperature": temperature,
132
+ "humidity": humidity
133
+ }
134
+
135
+ try:
136
+ response = requests.post(URL, json=data, timeout=10)
137
+ response.raise_for_status()
138
+
139
+ print("Temperature:", temperature, "°C")
140
+ print("Humidity:", humidity, "%")
141
+ print("Server Response:", response.json())
142
+ print("--------------------------")
143
+
144
+ except requests.exceptions.RequestException as e:
145
+ print("Connection Error:", e)
146
+
147
+ time.sleep(5)
148
+
149
+
150
+ templates/index.html:
151
+
152
+
153
+ <!DOCTYPE html>
154
+ <html>
155
+ <head>
156
+ <title>IoT Sensor Dashboard</title>
157
+
158
+ <meta name="viewport" content="width=device-width, initial-scale=1">
159
+
160
+ <style>
161
+ body {
162
+ font-family: Arial;
163
+ background: #eef2f7;
164
+ text-align: center;
165
+ padding: 30px;
166
+ }
167
+
168
+ h1 {
169
+ color: #1e293b;
170
+ }
171
+
172
+ .cards {
173
+ display: flex;
174
+ justify-content: center;
175
+ gap: 20px;
176
+ flex-wrap: wrap;
177
+ }
178
+
179
+ .card {
180
+ background: white;
181
+ padding: 25px;
182
+ width: 220px;
183
+ border-radius: 12px;
184
+ box-shadow: 0 3px 10px #ccc;
185
+ }
186
+
187
+ .value {
188
+ font-size: 35px;
189
+ color: #2563eb;
190
+ font-weight: bold;
191
+ }
192
+
193
+ table {
194
+ margin: 30px auto;
195
+ width: 90%;
196
+ background: white;
197
+ border-collapse: collapse;
198
+ }
199
+
200
+ th, td {
201
+ padding: 12px;
202
+ border: 1px solid #ddd;
203
+ }
204
+
205
+ th {
206
+ background: #2563eb;
207
+ color: white;
208
+ }
209
+ </style>
210
+ </head>
211
+
212
+ <body>
213
+
214
+ <h1>IoT Temperature & Humidity Dashboard</h1>
215
+
216
+ <div class="cards">
217
+
218
+ <div class="card">
219
+ <h2>Temperature</h2>
220
+ <div class="value" id="temperature">-- °C</div>
221
+ </div>
222
+
223
+ <div class="card">
224
+ <h2>Humidity</h2>
225
+ <div class="value" id="humidity">-- %</div>
226
+ </div>
227
+
228
+ </div>
229
+
230
+ <h2>Sensor Reading History</h2>
231
+
232
+ <table>
233
+ <thead>
234
+ <tr>
235
+ <th>Temperature (°C)</th>
236
+ <th>Humidity (%)</th>
237
+ <th>Timestamp</th>
238
+ </tr>
239
+ </thead>
240
+
241
+ <tbody id="readings"></tbody>
242
+ </table>
243
+
244
+ <script>
245
+ async function loadReadings() {
246
+
247
+ const response = await fetch("/api/readings");
248
+ const data = await response.json();
249
+
250
+ if (data.length > 0) {
251
+
252
+ document.getElementById("temperature").innerText =
253
+ data[0].temperature + " °C";
254
+
255
+ document.getElementById("humidity").innerText =
256
+ data[0].humidity + " %";
257
+ }
258
+
259
+ const table = document.getElementById("readings");
260
+
261
+ table.innerHTML = "";
262
+
263
+ data.forEach(item => {
264
+
265
+ const row = `
266
+ <tr>
267
+ <td>${item.temperature}</td>
268
+ <td>${item.humidity}</td>
269
+ <td>${new Date(item.created_at).toLocaleString()}</td>
270
+ </tr>
271
+ `;
272
+
273
+ table.innerHTML += row;
274
+ });
275
+ }
276
+
277
+ loadReadings();
278
+
279
+ setInterval(loadReadings, 5000);
280
+ </script>
281
+
282
+ </body>
283
+ </html>
@@ -0,0 +1,376 @@
1
+ 6.Develop a dashboard that receives sensor data through the MQTT protocol, stores the data in a cloud database (Supabase / Firebase), retrieves the stored records using a web application, and displays the sensor readings on a web dashboard.
2
+
3
+ pip install flask paho-mqtt supabase python-dotenv
4
+
5
+
6
+ iot_mqtt_dashboard/
7
+ │
8
+ ├── app.py
9
+ ├── publisher.py
10
+ ├── .env
11
+ ├── requirements.txt
12
+ │
13
+ └── templates/
14
+ └── index.html
15
+
16
+
17
+ supabase:
18
+
19
+ CREATE TABLE mqtt_readings (
20
+ id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
21
+ temperature FLOAT NOT NULL,
22
+ humidity FLOAT NOT NULL,
23
+ created_at TIMESTAMPTZ DEFAULT NOW()
24
+ );
25
+
26
+
27
+ .env:
28
+
29
+ SUPABASE_URL=https://YOUR_PROJECT_ID.supabase.co
30
+ SUPABASE_KEY=YOUR_SERVICE_ROLE_KEY
31
+
32
+ publisher.py:
33
+
34
+ import paho.mqtt.client as mqtt
35
+ import random
36
+ import json
37
+ import time
38
+ import threading
39
+
40
+ # MQTT configuration
41
+ BROKER = "test.mosquitto.org"
42
+ PORT = 1883
43
+ TOPIC = "iot/sensor"
44
+
45
+ connected = threading.Event()
46
+
47
+
48
+ def on_connect(client, userdata, flags, reason_code, properties):
49
+ if reason_code.is_failure:
50
+ connected.clear()
51
+ print("MQTT connection failed:", reason_code)
52
+ else:
53
+ connected.set()
54
+ print("Connected to MQTT Broker!")
55
+
56
+
57
+ def on_disconnect(client, userdata, disconnect_flags, reason_code, properties):
58
+ connected.clear()
59
+ print("Disconnected from MQTT Broker:", reason_code)
60
+
61
+
62
+ client = mqtt.Client(
63
+ callback_api_version=mqtt.CallbackAPIVersion.VERSION2,
64
+ client_id="sensor_publisher",
65
+ protocol=mqtt.MQTTv311
66
+ )
67
+
68
+ client.on_connect = on_connect
69
+ client.on_disconnect = on_disconnect
70
+
71
+ try:
72
+ print("Connecting to MQTT Broker...")
73
+ client.connect(BROKER, PORT, 60)
74
+ client.loop_start()
75
+
76
+ while True:
77
+ if not connected.wait(timeout=2):
78
+ print("Waiting for MQTT connection...")
79
+ continue
80
+
81
+ temperature = round(random.uniform(20, 40), 2)
82
+ humidity = round(random.uniform(40, 90), 2)
83
+
84
+ data = {
85
+ "temperature": temperature,
86
+ "humidity": humidity
87
+ }
88
+
89
+ payload = json.dumps(data)
90
+
91
+ result = client.publish(TOPIC, payload, qos=1)
92
+
93
+ if result.rc == mqtt.MQTT_ERR_SUCCESS:
94
+ try:
95
+ result.wait_for_publish(timeout=10)
96
+
97
+ if result.is_published():
98
+ print("Published successfully:", payload)
99
+ else:
100
+ print("Publishing timed out")
101
+
102
+ except RuntimeError as e:
103
+ print("Publishing error:", e)
104
+ else:
105
+ print("Publish failed:", mqtt.error_string(result.rc))
106
+
107
+ time.sleep(5)
108
+
109
+ except KeyboardInterrupt:
110
+ print("\nPublisher stopped.")
111
+
112
+ except Exception as e:
113
+ print("Error:", e)
114
+
115
+ finally:
116
+ client.loop_stop()
117
+ client.disconnect()
118
+ print("MQTT connection closed.")
119
+
120
+
121
+ app.py:
122
+
123
+
124
+ from flask import Flask, jsonify, render_template
125
+ from supabase import create_client
126
+ from dotenv import load_dotenv
127
+ import paho.mqtt.client as mqtt
128
+ import os
129
+ import json
130
+ import threading
131
+
132
+ load_dotenv()
133
+
134
+ app = Flask(__name__)
135
+
136
+ # Supabase connection
137
+ SUPABASE_URL = os.getenv("SUPABASE_URL")
138
+ SUPABASE_KEY = os.getenv("SUPABASE_KEY")
139
+
140
+ if not SUPABASE_URL or not SUPABASE_KEY:
141
+ raise ValueError(
142
+ "SUPABASE_URL and SUPABASE_KEY must be set in the .env file"
143
+ )
144
+
145
+ supabase = create_client(SUPABASE_URL, SUPABASE_KEY)
146
+
147
+ # MQTT configuration
148
+ BROKER = "test.mosquitto.org"
149
+ PORT = 1883
150
+ TOPIC = "iot/sensor"
151
+
152
+
153
+ # MQTT callback
154
+ def on_connect(client, userdata, flags, reason_code, properties):
155
+ if reason_code.is_failure:
156
+ print("MQTT connection failed:", reason_code)
157
+ return
158
+
159
+ print("Connected to MQTT Broker!")
160
+
161
+ result, mid = client.subscribe(TOPIC)
162
+
163
+ if result == mqtt.MQTT_ERR_SUCCESS:
164
+ print("Subscribed to:", TOPIC)
165
+ else:
166
+ print("Subscription failed:", mqtt.error_string(result))
167
+
168
+
169
+ # Receive MQTT messages
170
+ def on_message(client, userdata, msg):
171
+
172
+ try:
173
+ data = json.loads(msg.payload.decode())
174
+
175
+ temperature = float(data["temperature"])
176
+ humidity = float(data["humidity"])
177
+
178
+ reading = {
179
+ "temperature": temperature,
180
+ "humidity": humidity
181
+ }
182
+
183
+ # Store in Supabase
184
+ supabase.table("mqtt_readings").insert(reading).execute()
185
+
186
+ print("Received and Stored:", reading)
187
+
188
+ except Exception as e:
189
+ print("Error:", e)
190
+
191
+
192
+ # MQTT subscriber
193
+ mqtt_client = mqtt.Client(
194
+ callback_api_version=mqtt.CallbackAPIVersion.VERSION2,
195
+ client_id="dashboard_subscriber"
196
+ )
197
+
198
+ mqtt_client.on_connect = on_connect
199
+ mqtt_client.on_message = on_message
200
+
201
+
202
+ # Start MQTT in background thread
203
+ def start_mqtt():
204
+ while True:
205
+ try:
206
+ print("Connecting to MQTT broker...")
207
+ mqtt_client.connect(BROKER, PORT, 60)
208
+ mqtt_client.loop_forever()
209
+
210
+ except Exception as e:
211
+ print("MQTT connection error:", e)
212
+ print("Retrying in 5 seconds...")
213
+ import time
214
+ time.sleep(5)
215
+
216
+
217
+ threading.Thread(target=start_mqtt, daemon=True).start()
218
+
219
+
220
+ # Dashboard
221
+ @app.route("/")
222
+ def dashboard():
223
+ return render_template("index.html")
224
+
225
+
226
+ # Retrieve records from Supabase
227
+ @app.route("/api/readings")
228
+ def get_readings():
229
+
230
+ result = (
231
+ supabase.table("mqtt_readings")
232
+ .select("*")
233
+ .order("created_at", desc=True)
234
+ .limit(50)
235
+ .execute()
236
+ )
237
+
238
+ return jsonify(result.data)
239
+
240
+
241
+ if __name__ == "__main__":
242
+ app.run(debug=True, use_reloader=False)
243
+
244
+
245
+ templates/index.html:
246
+
247
+
248
+ <!DOCTYPE html>
249
+ <html>
250
+ <head>
251
+ <title>MQTT IoT Dashboard</title>
252
+
253
+ <meta name="viewport" content="width=device-width, initial-scale=1">
254
+
255
+ <style>
256
+ body {
257
+ font-family: Arial;
258
+ background: #eef2f7;
259
+ text-align: center;
260
+ padding: 30px;
261
+ }
262
+
263
+ h1 {
264
+ color: #1e293b;
265
+ }
266
+
267
+ .cards {
268
+ display: flex;
269
+ justify-content: center;
270
+ gap: 20px;
271
+ flex-wrap: wrap;
272
+ }
273
+
274
+ .card {
275
+ background: white;
276
+ padding: 25px;
277
+ width: 220px;
278
+ border-radius: 12px;
279
+ box-shadow: 0 3px 10px #ccc;
280
+ }
281
+
282
+ .value {
283
+ font-size: 35px;
284
+ color: #2563eb;
285
+ font-weight: bold;
286
+ }
287
+
288
+ table {
289
+ margin: 30px auto;
290
+ width: 90%;
291
+ background: white;
292
+ border-collapse: collapse;
293
+ }
294
+
295
+ th, td {
296
+ padding: 12px;
297
+ border: 1px solid #ddd;
298
+ }
299
+
300
+ th {
301
+ background: #2563eb;
302
+ color: white;
303
+ }
304
+ </style>
305
+ </head>
306
+
307
+ <body>
308
+
309
+ <h1>MQTT IoT Sensor Dashboard</h1>
310
+
311
+ <div class="cards">
312
+
313
+ <div class="card">
314
+ <h2>Temperature</h2>
315
+ <div class="value" id="temperature">-- °C</div>
316
+ </div>
317
+
318
+ <div class="card">
319
+ <h2>Humidity</h2>
320
+ <div class="value" id="humidity">-- %</div>
321
+ </div>
322
+
323
+ </div>
324
+
325
+ <h2>Sensor Reading History</h2>
326
+
327
+ <table>
328
+ <thead>
329
+ <tr>
330
+ <th>Temperature (°C)</th>
331
+ <th>Humidity (%)</th>
332
+ <th>Timestamp</th>
333
+ </tr>
334
+ </thead>
335
+
336
+ <tbody id="readings"></tbody>
337
+ </table>
338
+
339
+ <script>
340
+ async function loadReadings() {
341
+
342
+ const response = await fetch("/api/readings");
343
+ const data = await response.json();
344
+
345
+ if (data.length > 0) {
346
+
347
+ document.getElementById("temperature").innerText =
348
+ data[0].temperature + " °C";
349
+
350
+ document.getElementById("humidity").innerText =
351
+ data[0].humidity + " %";
352
+ }
353
+
354
+ const table = document.getElementById("readings");
355
+
356
+ table.innerHTML = "";
357
+
358
+ data.forEach(item => {
359
+
360
+ table.innerHTML += `
361
+ <tr>
362
+ <td>${item.temperature}</td>
363
+ <td>${item.humidity}</td>
364
+ <td>${new Date(item.created_at).toLocaleString()}</td>
365
+ </tr>
366
+ `;
367
+ });
368
+ }
369
+
370
+ loadReadings();
371
+
372
+ setInterval(loadReadings, 5000);
373
+ </script>
374
+
375
+ </body>
376
+ </html>