Air Quality Monitor
Portable C application for collecting, storing, and analyzing air quality sensor readings
Loading...
Searching...
No Matches
main.c
1#include "core/aqm_db.h"
2#include "core/aqm_paths.h"
3#include "core/aqm_platform.h"
4#include "core/globals.h"
5#include "sensor/sensor_info.h"
6#include "sensor/sensor_detector.h"
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <time.h>
11
12void fetch_data(void);
13void check_alerts(void);
14void export_to_csv(void);
15void configure_limits(void);
16void generate_statistics(void);
17void backup_database(void);
18void cleanup_old_data(void);
19void interval_collection(void);
20void generate_pdf_report(void);
21int load_config(void);
22void save_config(void);
23static void show_menu(void);
24static void configure_sensor_runtime(void);
25static void configure_multi_sensor(void);
26static void wait_for_menu_return(void);
27
28int main(void) {
29 aqm_paths_init();
30 init_sensor_configs();
31 srand((unsigned)time(NULL));
32
33 if (!load_config()) {
34 printf("Configuration file not found. Please configure the settings.\n");
35 configure_limits();
36 save_config();
37 } else {
38 printf("Configuration loaded successfully.\n");
39 }
40
41 if (aqm_db_init() != 0) {
42 fprintf(stderr, "Database initialization failed.\n");
43 return 1;
44 }
45
46 show_menu();
47 return 0;
48}
49
50static void show_menu(void) {
51 int option;
52 char input[64];
53
54 do {
55 printf("\n=== Air Quality Monitor ===\n");
56 printf("1. Start data collection\n");
57 printf("2. Fetch data\n");
58 printf("3. Check alerts\n");
59 printf("4. Export to CSV\n");
60 printf("5. Generate statistics\n");
61 printf("6. Backup database\n");
62 printf("7. Cleanup old data\n");
63 printf("8. Generate PDF report\n");
64 printf("9. Configure limits and settings\n");
65 printf("10. Show sensor runtime info\n");
66 printf("11. Configure sensor/plugin runtime\n");
67 printf("12. Auto-detect sensors\n");
68 printf("13. Configure multi-sensor setup\n");
69 printf("0. Exit\n");
70 printf("Select an option: ");
71
72 if (!fgets(input, sizeof(input), stdin) || !aqm_parse_int(input, &option)) {
73 printf("Invalid input.\n");
74 continue;
75 }
76
77 switch (option) {
78 case 1:
79 interval_collection();
80 break;
81 case 2:
82 fetch_data();
83 break;
84 case 3:
85 check_alerts();
86 break;
87 case 4:
88 export_to_csv();
89 break;
90 case 5:
91 generate_statistics();
92 break;
93 case 6:
94 backup_database();
95 break;
96 case 7:
97 cleanup_old_data();
98 break;
99 case 8:
100 generate_pdf_report();
101 break;
102 case 9:
103 configure_limits();
104 save_config();
105 break;
106 case 10:
107 show_sensor_runtime_info();
108 break;
109 case 11:
110 configure_sensor_runtime();
111 save_config();
112 break;
113 case 12:
114 run_auto_detection_and_prompt();
115 save_config();
116 break;
117 case 13:
118 configure_multi_sensor();
119 save_config();
120 break;
121 case 0:
122 printf("Exiting program...\n");
123 break;
124 default:
125 printf("Invalid option. Try again.\n");
126 }
127
128 if (option != 0)
129 wait_for_menu_return();
130 } while (option != 0);
131}
132
133static void wait_for_menu_return(void) {
134 char input[8];
135 printf("\nPress Enter to return to the menu...");
136 (void)fgets(input, sizeof(input), stdin);
137}
138
139static void configure_sensor_runtime(void) {
140 const char *allowed_modes[] = {"mock", "dht22", "bme680", "pms5003", "mh-z19", "mhz19"};
141 const size_t allowed_count = sizeof(allowed_modes) / sizeof(allowed_modes[0]);
142 char input[256];
143
144 printf("\nSensor/plugin runtime configuration:\n");
145 printf("Current mode: %s\n", sensor_mode);
146 printf("Plugins enabled: %s\n", sensor_plugins_enabled ? "yes" : "no");
147 printf("Custom plugin path: %s\n", sensor_plugin_path[0] ? sensor_plugin_path : "(none)");
148
149 printf("Enable plugins? (1=yes, 0=no, Enter=keep): ");
150 if (fgets(input, sizeof(input), stdin) && input[0] != '\n') {
151 int enabled;
152 if (aqm_parse_int(input, &enabled))
153 sensor_plugins_enabled = enabled ? 1 : 0;
154 }
155
156 printf("Sensor mode [mock|dht22|bme680|pms5003|mh-z19] (Enter=keep): ");
157 if (fgets(input, sizeof(input), stdin) && input[0] != '\n') {
158 aqm_trim_crlf(input);
159 if (input[0]) {
160 int ok = 0;
161 for (size_t i = 0; i < allowed_count; i++) {
162 if (strcmp(input, allowed_modes[i]) == 0) {
163 ok = 1;
164 break;
165 }
166 }
167 if (ok) {
168 size_t n = strlen(input);
169 if (n >= sizeof(sensor_mode))
170 n = sizeof(sensor_mode) - 1;
171 memcpy(sensor_mode, input, n);
172 sensor_mode[n] = '\0';
173 } else {
174 printf("Invalid sensor mode. Keeping current mode.\n");
175 }
176 }
177 }
178
179 printf("Custom plugin path (Enter=keep, '-'=clear): ");
180 if (fgets(input, sizeof(input), stdin) && input[0] != '\n') {
181 aqm_trim_crlf(input);
182 if (strcmp(input, "-") == 0) {
183 sensor_plugin_path[0] = '\0';
184 } else if (input[0]) {
185 snprintf(sensor_plugin_path, sizeof(sensor_plugin_path), "%s", input);
186 }
187 }
188
189 printf("Runtime sensor settings updated.\n");
190}
191
192static void configure_multi_sensor(void) {
193 const char *allowed_modes[] = {"dht22", "bme680", "pms5003", "mhz19"};
194 const size_t allowed_count = sizeof(allowed_modes) / sizeof(allowed_modes[0]);
195 char input[256];
196
197 printf("\n=== Multi-Sensor Configuration ===\n");
198 printf("Currently configured sensors: %d\n", active_sensor_count);
199
200 for (int i = 0; i < active_sensor_count; i++) {
201 printf(" %d. Mode: %s, Path: %s, Enabled: %s\n",
202 i + 1,
203 sensor_configs[i].mode,
204 sensor_configs[i].plugin_path[0] ? sensor_configs[i].plugin_path : "(default)",
205 sensor_configs[i].enabled ? "yes" : "no");
206 }
207
208 printf("\nOptions:\n");
209 printf("1. Add a new sensor\n");
210 printf("2. Remove a sensor\n");
211 printf("3. Enable/Disable a sensor\n");
212 printf("4. Clear all sensors\n");
213 printf("0. Back to main menu\n");
214 printf("Select an option: ");
215
216 int option;
217 if (!fgets(input, sizeof(input), stdin) || !aqm_parse_int(input, &option)) {
218 printf("Invalid input.\n");
219 return;
220 }
221
222 switch (option) {
223 case 1:
224 if (active_sensor_count >= MAX_SENSORS) {
225 printf("Maximum number of sensors (%d) reached.\n", MAX_SENSORS);
226 return;
227 }
228
229 printf("\nAvailable sensor modes:\n");
230 for (size_t i = 0; i < allowed_count; i++) {
231 printf(" - %s\n", allowed_modes[i]);
232 }
233
234 printf("\nEnter sensor mode: ");
235 if (fgets(input, sizeof(input), stdin)) {
236 aqm_trim_crlf(input);
237 int ok = 0;
238 for (size_t i = 0; i < allowed_count; i++) {
239 if (strcmp(input, allowed_modes[i]) == 0) {
240 ok = 1;
241 break;
242 }
243 }
244
245 if (ok) {
246 SensorConfig *config = &sensor_configs[active_sensor_count];
247 // Intentional: mode[32] stores max 31 chars + null
248 strncpy(config->mode, input, sizeof(config->mode) - 1);
249 config->mode[sizeof(config->mode) - 1] = '\0';
250 config->plugin_path[0] = '\0'; // Use default path
251 config->enabled = 1;
252 active_sensor_count++;
253 printf("Sensor %s added successfully.\n", input);
254 } else {
255 printf("Invalid sensor mode.\n");
256 }
257 }
258 break;
259
260 case 2:
261 if (active_sensor_count == 0) {
262 printf("No sensors configured.\n");
263 return;
264 }
265
266 printf("\nEnter sensor number to remove (1-%d): ", active_sensor_count);
267 int idx;
268 if (fgets(input, sizeof(input), stdin) && aqm_parse_int(input, &idx) && idx >= 1 && idx <= active_sensor_count) {
269 for (int i = idx - 1; i < active_sensor_count - 1; i++) {
270 sensor_configs[i] = sensor_configs[i + 1];
271 }
272 sensor_configs[active_sensor_count - 1].mode[0] = '\0';
273 sensor_configs[active_sensor_count - 1].plugin_path[0] = '\0';
274 sensor_configs[active_sensor_count - 1].enabled = 0;
275 active_sensor_count--;
276 printf("Sensor removed successfully.\n");
277 } else {
278 printf("Invalid sensor number.\n");
279 }
280 break;
281
282 case 3:
283 if (active_sensor_count == 0) {
284 printf("No sensors configured.\n");
285 return;
286 }
287
288 printf("\nEnter sensor number to toggle (1-%d): ", active_sensor_count);
289 int toggle_idx;
290 if (fgets(input, sizeof(input), stdin) && aqm_parse_int(input, &toggle_idx) && toggle_idx >= 1 && toggle_idx <= active_sensor_count) {
291 sensor_configs[toggle_idx - 1].enabled = !sensor_configs[toggle_idx - 1].enabled;
292 printf("Sensor %s is now %s.\n",
293 sensor_configs[toggle_idx - 1].mode,
294 sensor_configs[toggle_idx - 1].enabled ? "enabled" : "disabled");
295 } else {
296 printf("Invalid sensor number.\n");
297 }
298 break;
299
300 case 4:
301 printf("\nAre you sure you want to clear all sensors? (y/n): ");
302 if (fgets(input, sizeof(input), stdin) && (input[0] == 'y' || input[0] == 'Y')) {
303 init_sensor_configs();
304 printf("All sensors cleared.\n");
305 } else {
306 printf("Operation canceled.\n");
307 }
308 break;
309
310 case 0:
311 return;
312
313 default:
314 printf("Invalid option.\n");
315 }
316}
Configuration for one sensor slot in multi-sensor mode.
Definition globals.h:48
char mode[32]
Sensor mode identifier, e.g.
Definition globals.h:50
char plugin_path[256]
Path to the plugin library; empty string means use the default resolved by resolve_default_plugin_pat...
Definition globals.h:53
int enabled
Non-zero if this sensor slot is active for data collection.
Definition globals.h:55