1#include "core/aqm_db.h"
2#include "core/globals.h"
7 return (d->pm25 > limit_pm25 || d->pm10 > limit_pm10 || d->co > limit_co || d->no2 > limit_no2 ||
8 d->o3 > limit_o3 || d->so2 > limit_so2);
11void check_alerts(
void) {
13 if (aqm_db_open(&db) != 0)
16 sqlite3_stmt *st = NULL;
18 "SELECT r.sensor_id, r.model, r.measured_at, r.pm25, r.pm10, r.co, r.no2, r.o3, r.so2 "
19 "FROM readings r ORDER BY r.measured_at DESC LIMIT 1;";
21 if (sqlite3_prepare_v2(db, sql, -1, &st, NULL) != SQLITE_OK) {
22 fprintf(stderr,
"Query failed: %s\n", sqlite3_errmsg(db));
27 if (sqlite3_step(st) != SQLITE_ROW) {
28 printf(
"No readings in database yet.\n");
36 const char *model = (
const char *)sqlite3_column_text(st, 1);
37 const char *ts = (
const char *)sqlite3_column_text(st, 2);
38 snprintf(d.
model,
sizeof(d.
model),
"%s", model ? model :
"");
40 d.pm25 = (float)sqlite3_column_double(st, 3);
41 d.pm10 = (float)sqlite3_column_double(st, 4);
42 d.co = (float)sqlite3_column_double(st, 5);
43 d.no2 = (float)sqlite3_column_double(st, 6);
44 d.o3 = (float)sqlite3_column_double(st, 7);
45 d.so2 = (float)sqlite3_column_double(st, 8);
50 if (exceeds_limits(&d)) {
51 printf(
"ALERT: Latest sample exceeds configured limits (sensor %d, model %s, %s).\n", d.
sensor_id, d.
model,
53 printf(
" PM2.5 %.4f (limit %.4f) PM10 %.4f (limit %.4f) CO %.4f (limit %.4f)\n", d.pm25,
54 limit_pm25, d.pm10, limit_pm10, d.co, limit_co);
55 printf(
" NO2 %.6f (limit %.6f) O3 %.6f (limit %.6f) SO2 %.6f (limit %.6f)\n", d.no2, limit_no2,
56 d.o3, limit_o3, d.so2, limit_so2);
58 printf(
"Latest reading is within configured limits (sensor %d, model %s, %s).\n", d.
sensor_id, d.
model,
One air quality reading: pollutant values plus sensor/timestamp metadata.
char timestamp[32]
Reading timestamp, formatted "%Y-%m-%d %H:%M:%S".
char model[64]
Sensor model name, e.g.
int sensor_id
Numeric sensor identifier, matches SensorPlugin::sensor_id.