iotlabkit 1.0.1__tar.gz → 1.0.3__tar.gz

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.
Files changed (40) hide show
  1. {iotlabkit-1.0.1/src/iotlabkit.egg-info → iotlabkit-1.0.3}/PKG-INFO +1 -1
  2. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/pyproject.toml +1 -1
  3. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/__init__.py +1 -1
  4. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/registry.py +3 -0
  5. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/templates/program_05.py +60 -19
  6. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/templates/program_06.py +47 -16
  7. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/templates/program_10.py +58 -17
  8. {iotlabkit-1.0.1 → iotlabkit-1.0.3/src/iotlabkit.egg-info}/PKG-INFO +1 -1
  9. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/LICENSE +0 -0
  10. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/README.md +0 -0
  11. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/setup.cfg +0 -0
  12. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/cli.py +0 -0
  13. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/coap_util.py +0 -0
  14. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/data/beijing_air/beijing_sample.csv +0 -0
  15. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/data/india_air/city_day_sample.csv +0 -0
  16. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/data/occupancy/datatraining.txt +0 -0
  17. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/doctor.py +0 -0
  18. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/generator.py +0 -0
  19. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/templates/program_07.py +0 -0
  20. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/templates/program_08.py +0 -0
  21. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/templates/program_09.py +0 -0
  22. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/templates/program_11.py +0 -0
  23. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/templates/program_12.py +0 -0
  24. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/templates/program_13.py +0 -0
  25. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/templates/program_14.py +0 -0
  26. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/templates/program_15.py +0 -0
  27. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/templates/program_16.py +0 -0
  28. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit/templates/program_17.py +0 -0
  29. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit.egg-info/SOURCES.txt +0 -0
  30. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit.egg-info/dependency_links.txt +0 -0
  31. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit.egg-info/entry_points.txt +0 -0
  32. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit.egg-info/requires.txt +0 -0
  33. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/src/iotlabkit.egg-info/top_level.txt +0 -0
  34. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/tests/test_api_parsing.py +0 -0
  35. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/tests/test_cli.py +0 -0
  36. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/tests/test_coap_util.py +0 -0
  37. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/tests/test_doctor.py +0 -0
  38. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/tests/test_generator.py +0 -0
  39. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/tests/test_ml_pipeline.py +0 -0
  40. {iotlabkit-1.0.1 → iotlabkit-1.0.3}/tests/test_registry.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: iotlabkit
3
- Version: 1.0.1
3
+ Version: 1.0.3
4
4
  Summary: A Beginner-Friendly IoT Lab Code Generator for MSc/MCA Practicals (Programs 5-17)
5
5
  Author: IoT Lab Contributors
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "iotlabkit"
7
- version = "1.0.1"
7
+ version = "1.0.3"
8
8
  description = "A Beginner-Friendly IoT Lab Code Generator for MSc/MCA Practicals (Programs 5-17)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -4,7 +4,7 @@ Designed for MSc/MCA Semester 3 IoT Laboratory practicals (Programs 5-17).
4
4
  Generates clean, working, self-contained project templates in Learning and Exam modes.
5
5
  """
6
6
 
7
- __version__ = "1.0.1"
7
+ __version__ = "1.0.3"
8
8
  __author__ = "IoT Lab Contributors"
9
9
  __license__ = "MIT"
10
10
 
@@ -81,6 +81,7 @@ PROGRAMS: Dict[int, ProgramInfo] = {
81
81
  "dashboard.py",
82
82
  "supabase_schema.sql",
83
83
  "firebase_setup.md",
84
+ "init_db.py",
84
85
  ],
85
86
  prerequisites=[
86
87
  "Python 3.9+",
@@ -130,6 +131,7 @@ PROGRAMS: Dict[int, ProgramInfo] = {
130
131
  "publisher.py",
131
132
  "dashboard.py",
132
133
  "supabase_schema.sql",
134
+ "init_db.py",
133
135
  ],
134
136
  prerequisites=[
135
137
  "Python 3.9+",
@@ -323,6 +325,7 @@ PROGRAMS: Dict[int, ProgramInfo] = {
323
325
  "dashboard.py",
324
326
  "supabase_schema.sql",
325
327
  "coap_core.py",
328
+ "init_db.py",
326
329
  ],
327
330
  prerequisites=[
328
331
  "Python 3.9+",
@@ -16,10 +16,10 @@ def generate(target_dir: str, mode: str = "learning") -> Dict[str, str]:
16
16
  files[".env.example"] = (
17
17
  "PORT=5000\n"
18
18
  "HOST=127.0.0.1\n"
19
- "CLOUD_PROVIDER=supabase\n"
19
+ "CLOUD_PROVIDER=firebase\n"
20
+ "FIREBASE_DATABASE_URL=https://your-project.firebaseio.com\n"
20
21
  "SUPABASE_URL=https://your-project.supabase.co\n"
21
22
  "SUPABASE_KEY=your-supabase-key\n"
22
- "FIREBASE_DATABASE_URL=https://your-project.firebaseio.com\n"
23
23
  )
24
24
 
25
25
  files[".gitignore"] = (
@@ -43,9 +43,10 @@ def generate(target_dir: str, mode: str = "learning") -> Dict[str, str]:
43
43
  "# Firebase Setup Guide\n\n"
44
44
  "1. Open https://console.firebase.google.com/ and create a project.\n"
45
45
  "2. Go to Build -> Realtime Database -> Create Database.\n"
46
- "3. Select test mode rules.\n"
47
- "4. Copy database URL to .env under FIREBASE_DATABASE_URL.\n"
48
- "5. Set CLOUD_PROVIDER=firebase in .env.\n"
46
+ "3. Select 'Start in test mode' rules.\n"
47
+ "4. Copy the database URL (e.g. https://your-project-rtdb.firebaseio.com/).\n"
48
+ "5. Paste the URL into .env under FIREBASE_DATABASE_URL.\n"
49
+ "6. Tables/paths are created automatically on first insert (zero SQL needed).\n"
49
50
  )
50
51
 
51
52
  # server.py
@@ -60,22 +61,28 @@ def generate(target_dir: str, mode: str = "learning") -> Dict[str, str]:
60
61
  "app = Flask(__name__)\n\n"
61
62
  "HOST = os.getenv('HOST', '127.0.0.1')\n"
62
63
  "PORT = int(os.getenv('PORT', 5000))\n"
63
- "CLOUD_PROVIDER = os.getenv('CLOUD_PROVIDER', 'supabase').lower().strip()\n"
64
+ "CLOUD_PROVIDER = os.getenv('CLOUD_PROVIDER', 'firebase').lower().strip()\n"
65
+ "FIREBASE_URL = os.getenv('FIREBASE_DATABASE_URL', '').rstrip('/')\n"
64
66
  "SUPABASE_URL = os.getenv('SUPABASE_URL', '').rstrip('/')\n"
65
67
  "SUPABASE_KEY = os.getenv('SUPABASE_KEY', '')\n"
66
- "FIREBASE_URL = os.getenv('FIREBASE_DATABASE_URL', '').rstrip('/')\n"
67
68
  "LOCAL_BACKUP = os.path.join(os.path.dirname(__file__), 'data', 'local_telemetry.json')\n\n"
69
+ "def save_to_firebase(record):\n"
70
+ " if not FIREBASE_URL or 'your-project' in FIREBASE_URL:\n"
71
+ " return False\n"
72
+ " try:\n"
73
+ " resp = requests.post(f'{FIREBASE_URL}/sensor_telemetry.json', json=record, timeout=5)\n"
74
+ " return resp.status_code == 200\n"
75
+ " except Exception:\n"
76
+ " return False\n\n"
68
77
  "def save_to_supabase(record):\n"
69
78
  " if not SUPABASE_URL or not SUPABASE_KEY or 'your-project' in SUPABASE_URL:\n"
70
79
  " return False\n"
71
- " headers = {'apikey': SUPABASE_KEY, 'Authorization': f'Bearer {SUPABASE_KEY}', 'Content-Type': 'application/json'}\n"
72
- " resp = requests.post(f'{SUPABASE_URL}/rest/v1/sensor_telemetry', json=record, headers=headers, timeout=5)\n"
73
- " return resp.status_code in (200, 201, 204)\n\n"
74
- "def save_to_firebase(record):\n"
75
- " if not FIREBASE_URL or 'your-firebase' in FIREBASE_URL:\n"
76
- " return False\n"
77
- " resp = requests.post(f'{FIREBASE_URL}/sensor_telemetry.json', json=record, timeout=5)\n"
78
- " return resp.status_code == 200\n\n"
80
+ " try:\n"
81
+ " headers = {'apikey': SUPABASE_KEY, 'Authorization': f'Bearer {SUPABASE_KEY}', 'Content-Type': 'application/json'}\n"
82
+ " resp = requests.post(f'{SUPABASE_URL}/rest/v1/sensor_telemetry', json=record, headers=headers, timeout=5)\n"
83
+ " return resp.status_code in (200, 201, 204)\n"
84
+ " except Exception:\n"
85
+ " return False\n\n"
79
86
  "def save_local(record):\n"
80
87
  " os.makedirs(os.path.dirname(LOCAL_BACKUP), exist_ok=True)\n"
81
88
  " data = []\n"
@@ -100,16 +107,25 @@ def generate(target_dir: str, mode: str = "learning") -> Dict[str, str]:
100
107
  " 'created_at': datetime.now(timezone.utc).isoformat()\n"
101
108
  " }\n"
102
109
  " saved_cloud = False\n"
103
- " if CLOUD_PROVIDER == 'supabase':\n"
104
- " saved_cloud = save_to_supabase(record)\n"
105
- " elif CLOUD_PROVIDER == 'firebase':\n"
110
+ " if CLOUD_PROVIDER == 'firebase':\n"
106
111
  " saved_cloud = save_to_firebase(record)\n"
112
+ " elif CLOUD_PROVIDER == 'supabase':\n"
113
+ " saved_cloud = save_to_supabase(record)\n"
107
114
  " save_local(record)\n"
108
- " status = 'Cloud Stored' if saved_cloud else 'Saved Locally'\n"
115
+ " status = 'Stored in Cloud' if saved_cloud else 'Saved Locally'\n"
109
116
  " print(f\"[{datetime.now().strftime('%H:%M:%S')}] Telemetry: Temp={temp}C, Humidity={hum}% -> {status}\")\n"
110
117
  " return jsonify({'message': 'Accepted', 'cloud_synced': saved_cloud, 'record': record}), 201\n\n"
111
118
  "@app.route('/api/telemetry', methods=['GET'])\n"
112
119
  "def get_telemetry():\n"
120
+ " if CLOUD_PROVIDER == 'firebase' and FIREBASE_URL and 'your-project' not in FIREBASE_URL:\n"
121
+ " try:\n"
122
+ " resp = requests.get(f'{FIREBASE_URL}/sensor_telemetry.json', timeout=4)\n"
123
+ " if resp.status_code == 200 and resp.json():\n"
124
+ " data = resp.json()\n"
125
+ " if isinstance(data, dict):\n"
126
+ " return jsonify(list(reversed(list(data.values())))), 200\n"
127
+ " except Exception:\n"
128
+ " pass\n"
113
129
  " if os.path.exists(LOCAL_BACKUP):\n"
114
130
  " with open(LOCAL_BACKUP, 'r', encoding='utf-8') as f:\n"
115
131
  " data = json.load(f)\n"
@@ -120,6 +136,31 @@ def generate(target_dir: str, mode: str = "learning") -> Dict[str, str]:
120
136
  " app.run(host=HOST, port=PORT, debug=False)\n"
121
137
  )
122
138
 
139
+ files["init_db.py"] = (
140
+ "import os\n"
141
+ "import requests\n"
142
+ "from dotenv import load_dotenv\n\n"
143
+ "load_dotenv()\n\n"
144
+ "FIREBASE_URL = os.getenv('FIREBASE_DATABASE_URL', '').rstrip('/')\n"
145
+ "SUPABASE_URL = os.getenv('SUPABASE_URL', '').rstrip('/')\n\n"
146
+ "def check():\n"
147
+ " print('Database Check:')\n"
148
+ " if FIREBASE_URL and 'your-project' not in FIREBASE_URL:\n"
149
+ " try:\n"
150
+ " r = requests.get(f'{FIREBASE_URL}/.json?shallow=true', timeout=5)\n"
151
+ " if r.status_code == 200:\n"
152
+ " print('Firebase: Connected. Tables are created automatically on first insert.')\n"
153
+ " return True\n"
154
+ " except Exception as e:\n"
155
+ " print('Firebase note:', e)\n"
156
+ " if SUPABASE_URL and 'your-project' not in SUPABASE_URL:\n"
157
+ " print('Supabase configured. Schema is in supabase_schema.sql.')\n"
158
+ " print('Local database: Ready (data/local_telemetry.json)')\n"
159
+ " return True\n\n"
160
+ "if __name__ == '__main__':\n"
161
+ " check()\n"
162
+ )
163
+
123
164
  # client_sender.py
124
165
  files["client_sender.py"] = (
125
166
  "import argparse\n"
@@ -17,10 +17,10 @@ def generate(target_dir: str, mode: str = "learning") -> Dict[str, str]:
17
17
  "MQTT_BROKER=broker.hivemq.com\n"
18
18
  "MQTT_PORT=1883\n"
19
19
  "MQTT_TOPIC=iot/lab/telemetry\n"
20
- "CLOUD_PROVIDER=supabase\n"
20
+ "CLOUD_PROVIDER=firebase\n"
21
+ "FIREBASE_DATABASE_URL=https://your-project.firebaseio.com\n"
21
22
  "SUPABASE_URL=https://your-project.supabase.co\n"
22
23
  "SUPABASE_KEY=your-supabase-key\n"
23
- "FIREBASE_DATABASE_URL=https://your-project.firebaseio.com\n"
24
24
  )
25
25
 
26
26
  files[".gitignore"] = (
@@ -55,22 +55,28 @@ def generate(target_dir: str, mode: str = "learning") -> Dict[str, str]:
55
55
  "BROKER = os.getenv('MQTT_BROKER', 'broker.hivemq.com')\n"
56
56
  "PORT = int(os.getenv('MQTT_PORT', 1883))\n"
57
57
  "TOPIC = os.getenv('MQTT_TOPIC', 'iot/lab/telemetry')\n"
58
- "CLOUD_PROVIDER = os.getenv('CLOUD_PROVIDER', 'supabase').lower().strip()\n"
58
+ "CLOUD_PROVIDER = os.getenv('CLOUD_PROVIDER', 'firebase').lower().strip()\n"
59
+ "FIREBASE_URL = os.getenv('FIREBASE_DATABASE_URL', '').rstrip('/')\n"
59
60
  "SUPABASE_URL = os.getenv('SUPABASE_URL', '').rstrip('/')\n"
60
61
  "SUPABASE_KEY = os.getenv('SUPABASE_KEY', '')\n"
61
- "FIREBASE_URL = os.getenv('FIREBASE_DATABASE_URL', '').rstrip('/')\n"
62
62
  "LOCAL_BACKUP = os.path.join(os.path.dirname(__file__), 'data', 'local_mqtt_telemetry.json')\n\n"
63
- "def save_to_supabase(record):\n"
64
- " if not SUPABASE_URL or not SUPABASE_KEY or 'your-project' in SUPABASE_URL:\n"
65
- " return False\n"
66
- " headers = {'apikey': SUPABASE_KEY, 'Authorization': f'Bearer {SUPABASE_KEY}', 'Content-Type': 'application/json'}\n"
67
- " resp = requests.post(f'{SUPABASE_URL}/rest/v1/mqtt_telemetry', json=record, headers=headers, timeout=5)\n"
68
- " return resp.status_code in (200, 201, 204)\n\n"
69
63
  "def save_to_firebase(record):\n"
70
64
  " if not FIREBASE_URL or 'your-firebase' in FIREBASE_URL:\n"
71
65
  " return False\n"
72
- " resp = requests.post(f'{FIREBASE_URL}/mqtt_telemetry.json', json=record, timeout=5)\n"
73
- " return resp.status_code == 200\n\n"
66
+ " try:\n"
67
+ " resp = requests.post(f'{FIREBASE_URL}/mqtt_telemetry.json', json=record, timeout=5)\n"
68
+ " return resp.status_code == 200\n"
69
+ " except Exception:\n"
70
+ " return False\n\n"
71
+ "def save_to_supabase(record):\n"
72
+ " if not SUPABASE_URL or not SUPABASE_KEY or 'your-project' in SUPABASE_URL:\n"
73
+ " return False\n"
74
+ " try:\n"
75
+ " headers = {'apikey': SUPABASE_KEY, 'Authorization': f'Bearer {SUPABASE_KEY}', 'Content-Type': 'application/json'}\n"
76
+ " resp = requests.post(f'{SUPABASE_URL}/rest/v1/mqtt_telemetry', json=record, headers=headers, timeout=5)\n"
77
+ " return resp.status_code in (200, 201, 204)\n"
78
+ " except Exception:\n"
79
+ " return False\n\n"
74
80
  "def save_local(record):\n"
75
81
  " os.makedirs(os.path.dirname(LOCAL_BACKUP), exist_ok=True)\n"
76
82
  " data = []\n"
@@ -103,12 +109,12 @@ def generate(target_dir: str, mode: str = "learning") -> Dict[str, str]:
103
109
  " 'created_at': datetime.now(timezone.utc).isoformat()\n"
104
110
  " }\n"
105
111
  " saved = False\n"
106
- " if CLOUD_PROVIDER == 'supabase':\n"
107
- " saved = save_to_supabase(record)\n"
108
- " elif CLOUD_PROVIDER == 'firebase':\n"
112
+ " if CLOUD_PROVIDER == 'firebase':\n"
109
113
  " saved = save_to_firebase(record)\n"
114
+ " elif CLOUD_PROVIDER == 'supabase':\n"
115
+ " saved = save_to_supabase(record)\n"
110
116
  " save_local(record)\n"
111
- " status = 'Cloud Stored' if saved else 'Saved Locally'\n"
117
+ " status = 'Stored in Cloud' if saved else 'Saved Locally'\n"
112
118
  " print(f\"[{datetime.now().strftime('%H:%M:%S')}] Received on {msg.topic}: Temp={temp}C, Hum={hum}% -> {status}\")\n"
113
119
  " except Exception as e:\n"
114
120
  " print('Message parse error:', e)\n\n"
@@ -123,6 +129,31 @@ def generate(target_dir: str, mode: str = "learning") -> Dict[str, str]:
123
129
  " main()\n"
124
130
  )
125
131
 
132
+ files["init_db.py"] = (
133
+ "import os\n"
134
+ "import requests\n"
135
+ "from dotenv import load_dotenv\n\n"
136
+ "load_dotenv()\n\n"
137
+ "FIREBASE_URL = os.getenv('FIREBASE_DATABASE_URL', '').rstrip('/')\n"
138
+ "SUPABASE_URL = os.getenv('SUPABASE_URL', '').rstrip('/')\n\n"
139
+ "def check():\n"
140
+ " print('Database Check:')\n"
141
+ " if FIREBASE_URL and 'your-project' not in FIREBASE_URL:\n"
142
+ " try:\n"
143
+ " r = requests.get(f'{FIREBASE_URL}/.json?shallow=true', timeout=5)\n"
144
+ " if r.status_code == 200:\n"
145
+ " print('Firebase: Connected. Tables are created automatically on first insert.')\n"
146
+ " return True\n"
147
+ " except Exception as e:\n"
148
+ " print('Firebase note:', e)\n"
149
+ " if SUPABASE_URL and 'your-project' not in SUPABASE_URL:\n"
150
+ " print('Supabase configured. Schema is in supabase_schema.sql.')\n"
151
+ " print('Local database: Ready (data/local_mqtt_telemetry.json)')\n"
152
+ " return True\n\n"
153
+ "if __name__ == '__main__':\n"
154
+ " check()\n"
155
+ )
156
+
126
157
  # publisher.py
127
158
  files["publisher.py"] = (
128
159
  "import argparse\n"
@@ -18,10 +18,10 @@ def generate(target_dir: str, mode: str = "learning") -> Dict[str, str]:
18
18
  "LONGITUDE=76.3419\n"
19
19
  "COAP_HOST=127.0.0.1\n"
20
20
  "COAP_PORT=56830\n"
21
- "CLOUD_PROVIDER=supabase\n"
21
+ "CLOUD_PROVIDER=firebase\n"
22
+ "FIREBASE_DATABASE_URL=https://your-firebase-project.firebaseio.com\n"
22
23
  "SUPABASE_URL=https://your-project-ref.supabase.co\n"
23
24
  "SUPABASE_KEY=your-supabase-anon-key\n"
24
- "FIREBASE_DATABASE_URL=https://your-firebase-project.firebaseio.com\n"
25
25
  )
26
26
 
27
27
  files[".gitignore"] = (
@@ -143,22 +143,28 @@ def generate(target_dir: str, mode: str = "learning") -> Dict[str, str]:
143
143
  "load_dotenv()\n\n"
144
144
  "COAP_HOST = os.getenv('COAP_HOST', '127.0.0.1')\n"
145
145
  "COAP_PORT = int(os.getenv('COAP_PORT', 56830))\n"
146
- "CLOUD_PROVIDER = os.getenv('CLOUD_PROVIDER', 'supabase').lower().strip()\n"
146
+ "CLOUD_PROVIDER = os.getenv('CLOUD_PROVIDER', 'firebase').lower().strip()\n"
147
+ "FIREBASE_URL = os.getenv('FIREBASE_DATABASE_URL', '').rstrip('/')\n"
147
148
  "SUPABASE_URL = os.getenv('SUPABASE_URL', '').rstrip('/')\n"
148
149
  "SUPABASE_KEY = os.getenv('SUPABASE_KEY', '')\n"
149
- "FIREBASE_URL = os.getenv('FIREBASE_DATABASE_URL', '').rstrip('/')\n"
150
150
  "LOCAL_BACKUP = os.path.join(os.path.dirname(__file__), 'data', 'local_coap_env.json')\n\n"
151
- "def save_to_supabase(record):\n"
152
- " if not SUPABASE_URL or not SUPABASE_KEY or 'your-project' in SUPABASE_URL:\n"
153
- " return False\n"
154
- " headers = {'apikey': SUPABASE_KEY, 'Authorization': f'Bearer {SUPABASE_KEY}', 'Content-Type': 'application/json'}\n"
155
- " resp = requests.post(f'{SUPABASE_URL}/rest/v1/coap_environmental_records', json=record, headers=headers, timeout=5)\n"
156
- " return resp.status_code in (200, 201, 204)\n\n"
157
151
  "def save_to_firebase(record):\n"
158
152
  " if not FIREBASE_URL or 'your-firebase' in FIREBASE_URL:\n"
159
153
  " return False\n"
160
- " resp = requests.post(f'{FIREBASE_URL}/coap_environmental_records.json', json=record, timeout=5)\n"
161
- " return resp.status_code == 200\n\n"
154
+ " try:\n"
155
+ " resp = requests.post(f'{FIREBASE_URL}/coap_environmental_records.json', json=record, timeout=5)\n"
156
+ " return resp.status_code == 200\n"
157
+ " except Exception:\n"
158
+ " return False\n\n"
159
+ "def save_to_supabase(record):\n"
160
+ " if not SUPABASE_URL or not SUPABASE_KEY or 'your-project' in SUPABASE_URL:\n"
161
+ " return False\n"
162
+ " try:\n"
163
+ " headers = {'apikey': SUPABASE_KEY, 'Authorization': f'Bearer {SUPABASE_KEY}', 'Content-Type': 'application/json'}\n"
164
+ " resp = requests.post(f'{SUPABASE_URL}/rest/v1/coap_environmental_records', json=record, headers=headers, timeout=5)\n"
165
+ " return resp.status_code in (200, 201, 204)\n"
166
+ " except Exception:\n"
167
+ " return False\n\n"
162
168
  "def save_locally(record):\n"
163
169
  " os.makedirs(os.path.dirname(LOCAL_BACKUP), exist_ok=True)\n"
164
170
  " records = []\n"
@@ -193,12 +199,12 @@ def generate(target_dir: str, mode: str = "learning") -> Dict[str, str]:
193
199
  " print(f\" O3 : {data.get('ozone')} ug/m3\")\n"
194
200
  " print(f\" European AQI : {data.get('european_aqi')}\")\n\n"
195
201
  " cloud_ok = False\n"
196
- " if CLOUD_PROVIDER == 'supabase':\n"
197
- " cloud_ok = save_to_supabase(data)\n"
198
- " elif CLOUD_PROVIDER == 'firebase':\n"
202
+ " if CLOUD_PROVIDER == 'firebase':\n"
199
203
  " cloud_ok = save_to_firebase(data)\n"
204
+ " elif CLOUD_PROVIDER == 'supabase':\n"
205
+ " cloud_ok = save_to_supabase(data)\n"
200
206
  " save_locally(data)\n\n"
201
- " status_msg = 'Stored in cloud' if cloud_ok else 'Saved locally'\n"
207
+ " status_msg = 'Stored in Cloud' if cloud_ok else 'Saved locally'\n"
202
208
  " print(f\"Status: {status_msg}\")\n"
203
209
  " except Exception as err:\n"
204
210
  " print(f\"Request failed: {err}\")\n\n"
@@ -206,6 +212,31 @@ def generate(target_dir: str, mode: str = "learning") -> Dict[str, str]:
206
212
  " main()\n"
207
213
  )
208
214
 
215
+ files["init_db.py"] = (
216
+ "import os\n"
217
+ "import requests\n"
218
+ "from dotenv import load_dotenv\n\n"
219
+ "load_dotenv()\n\n"
220
+ "FIREBASE_URL = os.getenv('FIREBASE_DATABASE_URL', '').rstrip('/')\n"
221
+ "SUPABASE_URL = os.getenv('SUPABASE_URL', '').rstrip('/')\n\n"
222
+ "def check():\n"
223
+ " print('Database Check:')\n"
224
+ " if FIREBASE_URL and 'your-firebase' not in FIREBASE_URL:\n"
225
+ " try:\n"
226
+ " r = requests.get(f'{FIREBASE_URL}/.json?shallow=true', timeout=5)\n"
227
+ " if r.status_code == 200:\n"
228
+ " print('Firebase: Connected. Tables are created automatically on first insert.')\n"
229
+ " return True\n"
230
+ " except Exception as e:\n"
231
+ " print('Firebase note:', e)\n"
232
+ " if SUPABASE_URL and 'your-project' not in SUPABASE_URL:\n"
233
+ " print('Supabase configured. Schema is in supabase_schema.sql.')\n"
234
+ " print('Local database: Ready (data/local_coap_env.json)')\n"
235
+ " return True\n\n"
236
+ "if __name__ == '__main__':\n"
237
+ " check()\n"
238
+ )
239
+
209
240
  files["dashboard.py"] = (
210
241
  "import os\n"
211
242
  "import json\n"
@@ -214,11 +245,21 @@ def generate(target_dir: str, mode: str = "learning") -> Dict[str, str]:
214
245
  "from dotenv import load_dotenv\n\n"
215
246
  "load_dotenv()\n\n"
216
247
  "st.title('CoAP Environmental Monitoring')\n\n"
217
- "CLOUD_PROVIDER = os.getenv('CLOUD_PROVIDER', 'supabase').lower().strip()\n"
248
+ "CLOUD_PROVIDER = os.getenv('CLOUD_PROVIDER', 'firebase').lower().strip()\n"
249
+ "FIREBASE_URL = os.getenv('FIREBASE_DATABASE_URL', '').rstrip('/')\n"
218
250
  "SUPABASE_URL = os.getenv('SUPABASE_URL', '').rstrip('/')\n"
219
251
  "SUPABASE_KEY = os.getenv('SUPABASE_KEY', '')\n"
220
252
  "LOCAL_BACKUP = os.path.join(os.path.dirname(__file__), 'data', 'local_coap_env.json')\n\n"
221
253
  "def fetch_records():\n"
254
+ " if CLOUD_PROVIDER == 'firebase' and FIREBASE_URL and 'your-firebase' not in FIREBASE_URL:\n"
255
+ " try:\n"
256
+ " resp = requests.get(f'{FIREBASE_URL}/coap_environmental_records.json', timeout=4)\n"
257
+ " if resp.status_code == 200 and resp.json():\n"
258
+ " data = resp.json()\n"
259
+ " if isinstance(data, dict):\n"
260
+ " return list(reversed(list(data.values())))\n"
261
+ " except Exception:\n"
262
+ " pass\n"
222
263
  " if CLOUD_PROVIDER == 'supabase' and SUPABASE_URL and 'your-project' not in SUPABASE_URL:\n"
223
264
  " try:\n"
224
265
  " headers = {'apikey': SUPABASE_KEY, 'Authorization': f'Bearer {SUPABASE_KEY}'}\n"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: iotlabkit
3
- Version: 1.0.1
3
+ Version: 1.0.3
4
4
  Summary: A Beginner-Friendly IoT Lab Code Generator for MSc/MCA Practicals (Programs 5-17)
5
5
  Author: IoT Lab Contributors
6
6
  License: MIT
File without changes
File without changes
File without changes
File without changes