You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
7.1 KiB
C
188 lines
7.1 KiB
C
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <linux/i2c-dev.h>
|
|
#include <time.h> // Necesario para la fecha y hora
|
|
#include <sqlite3.h>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
// Controladores
|
|
#include "bmp180.h"
|
|
#include "htu21d.h"
|
|
#include "sen0472_o3.h"
|
|
#include "sen0471_no2.h"
|
|
#include "sen0470_so2.h"
|
|
#include "sen0466_co.h"
|
|
|
|
// Definimos la ruta donde vivirá tu base de datos final
|
|
#define RUTA_BD "/var/www/html/AirQualityMicrostation/Database/microestacionAQ.db" // Ajusta esta ruta a tu carpeta real
|
|
|
|
void guardar_lote_en_bd(const char *ruta_lote) {
|
|
sqlite3 *bd;
|
|
char *mensaje_error = 0;
|
|
|
|
// 1. Abrimos o creamos la base de datos
|
|
if (sqlite3_open(RUTA_BD, &bd) != SQLITE_OK) {
|
|
printf("Error: No se pudo abrir la base de datos: %s\n", sqlite3_errmsg(bd));
|
|
return;
|
|
}
|
|
|
|
// 2. Creamos la tabla si no existe
|
|
const char *instruccion_crear =
|
|
"CREATE TABLE IF NOT EXISTS mediciones ("
|
|
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
|
"fecha_hora TEXT, presion REAL, temperatura REAL, "
|
|
"humedad REAL, ozono REAL, no2 REAL, co INTEGER, so2 REAL, "
|
|
"ica INTEGER, banda_ica TEXT);";
|
|
|
|
if (sqlite3_exec(bd, instruccion_crear, 0, 0, &mensaje_error) != SQLITE_OK) {
|
|
printf("Error al crear tabla: %s\n", mensaje_error);
|
|
sqlite3_free(mensaje_error);
|
|
}
|
|
|
|
// 3. Abrimos el archivo temporal que contiene las lecturas de los últimos 5 minutos
|
|
FILE *archivo = fopen(ruta_lote, "r");
|
|
if (archivo == NULL) {
|
|
printf("Advertencia: No se encontró el archivo temporal para guardar.\n");
|
|
sqlite3_close(bd);
|
|
return;
|
|
}
|
|
|
|
// Arreglo temporal para guardar cada línea de texto que leamos
|
|
char linea[256];
|
|
|
|
// 4. Leemos el archivo línea por línea hasta llegar al final
|
|
while (fgets(linea, sizeof(linea), archivo)) {
|
|
char fecha_hora[64];
|
|
double presion, temperatura, humedad, ozono, no2, so2;
|
|
int co;
|
|
|
|
// 5. Extraemos los valores separados por comas
|
|
// El formato %[^,] significa "lee todo el texto hasta encontrar una coma"
|
|
if (sscanf(linea, "%[^,],%lf,%lf,%lf,%lf,%lf,%d,%lf",
|
|
fecha_hora, &presion, &temperatura, &humedad,
|
|
&ozono, &no2, &co, &so2) == 8) {
|
|
|
|
// 6. Armamos la instrucción de inserción con los valores exactos
|
|
char instruccion_insertar[512];
|
|
sprintf(instruccion_insertar,
|
|
"INSERT INTO mediciones (fecha_hora, presion, temperatura, humedad, ozono, no2, co, so2, ica, banda_ica) "
|
|
"VALUES ('%s', %.2f, %.2f, %.2f, %.2f, %.2f, %d, %.2f, NULL, NULL);",
|
|
fecha_hora, presion, temperatura, humedad, ozono, no2, co, so2);
|
|
// 7. Ejecutamos la inserción en la base de datos
|
|
if (sqlite3_exec(bd, instruccion_insertar, 0, 0, &mensaje_error) != SQLITE_OK) {
|
|
printf("Error al insertar fila: %s\n", mensaje_error);
|
|
sqlite3_free(mensaje_error);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 8. Limpiamos y cerramos todo
|
|
fclose(archivo);
|
|
sqlite3_close(bd);
|
|
}
|
|
|
|
int main() {
|
|
// --- Apertura de los buses ---
|
|
// Bus principal: Clima (BMP180 y HTU21D)
|
|
int fd_principal = open("/dev/i2c-1", O_RDWR);
|
|
if (fd_principal < 0) {
|
|
printf("Error: No se pudo abrir el bus I2C principal.\n");
|
|
return 1;
|
|
}
|
|
|
|
// Bus secundario: Gases (Familia DFRobot)
|
|
int fd_secundario = open("/dev/i2c-3", O_RDWR);
|
|
if (fd_secundario < 0) {
|
|
printf("Error: No se pudo abrir el bus I2C secundario.\n");
|
|
return 1;
|
|
}
|
|
|
|
// --- Configuración inicial ---
|
|
printf("Iniciando microestación...\n");
|
|
|
|
// BMP180 en el bus principal (Conexión e inicialización)
|
|
ioctl(fd_principal, I2C_SLAVE, 0x77); // <- LÍNEA NUEVA
|
|
BMP180_CalibData calibracion_bmp;
|
|
bmp180_init(fd_principal, &calibracion_bmp);
|
|
|
|
// Sensores de gas en el bus secundario
|
|
changeQA_O3(fd_secundario);
|
|
changeQA_NO2(fd_secundario);
|
|
changeQA_CO(fd_secundario);
|
|
changeQA_SO2(fd_secundario);
|
|
|
|
double presion, temp_htu, humedad, ozono, dioxido_nitrogeno, dioxido_azufre;
|
|
int monoxido;
|
|
int contador_bd = 0;
|
|
|
|
// --- Ciclo continuo de monitoreo ---
|
|
while (1) {
|
|
// 1. Obtener la fecha y hora actual del sistema
|
|
time_t t = time(NULL);
|
|
struct tm tm = *localtime(&t);
|
|
char fecha_hora[64];
|
|
// Formato: Año-Mes-Día Hora:Minuto:Segundo
|
|
sprintf(fecha_hora, "%04d-%02d-%02d %02d:%02d:%02d",
|
|
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
|
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
|
|
|
// 2. Extracción de datos separada por buses
|
|
// Bus Principal
|
|
ioctl(fd_principal, I2C_SLAVE, 0x77); // Recuperamos el control del bus para el bmp180
|
|
bmp180_get_pressure(fd_principal, &calibracion_bmp, 2, &presion);
|
|
getTemperature(fd_principal, &temp_htu);
|
|
getHumidity(fd_principal, &humedad);
|
|
|
|
// Bus Secundario
|
|
getO3(fd_secundario, &ozono);
|
|
getNO2(fd_secundario, &dioxido_nitrogeno);
|
|
getCO(fd_secundario, &monoxido);
|
|
getSO2(fd_secundario, &dioxido_azufre);
|
|
|
|
// 3. Escribir el estado actual (Sobrescribir archivo para el comando terminal)
|
|
FILE *archivo_actual = fopen("/dev/shm/aql_actual.txt", "w");
|
|
if (archivo_actual != NULL) {
|
|
fprintf(archivo_actual, "PRES=%.2f\n", presion);
|
|
fprintf(archivo_actual, "TEMP=%.2f\n", temp_htu);
|
|
fprintf(archivo_actual, "HUM=%.2f\n", humedad);
|
|
fprintf(archivo_actual, "O3=%.2f\n", ozono);
|
|
fprintf(archivo_actual, "NO2=%.2f\n", dioxido_nitrogeno);
|
|
fprintf(archivo_actual, "CO=%d\n", monoxido);
|
|
fprintf(archivo_actual, "SO2=%.2f\n", dioxido_azufre);
|
|
fprintf(archivo_actual, "FECHA=\"%s\"\n", fecha_hora);
|
|
fclose(archivo_actual);
|
|
}
|
|
|
|
// 4. Escribir el historial temporal (Agregar línea para la Base de Datos)
|
|
// Usamos "a" (append) para añadir sin borrar lo anterior
|
|
FILE *archivo_lote = fopen("/dev/shm/lote_bd.csv", "a");
|
|
if (archivo_lote != NULL) {
|
|
// Guardamos todo separado por comas para facilitar la lectura posterior
|
|
fprintf(archivo_lote, "%s,%.2f,%.2f,%.2f,%.2f,%.2f,%d,%.2f\n",
|
|
fecha_hora, presion, temp_htu, humedad, ozono, dioxido_nitrogeno, monoxido, dioxido_azufre);
|
|
fclose(archivo_lote);
|
|
}
|
|
|
|
// 5. Lógica de almacenamiento masivo en la Base de Datos (Cada 5 minutos)
|
|
contador_bd++;
|
|
if (contador_bd >= 30) {
|
|
// Llamamos a la función pasándole la ruta del archivo temporal
|
|
guardar_lote_en_bd("/dev/shm/lote_bd.csv");
|
|
|
|
// Una vez guardado, borramos el archivo de lote para empezar de cero
|
|
FILE *limpiar_lote = fopen("/dev/shm/lote_bd.csv", "w");
|
|
if (limpiar_lote != NULL) fclose(limpiar_lote);
|
|
|
|
contador_bd = 0;
|
|
}
|
|
|
|
// Esperar 10 segundos
|
|
sleep(10);
|
|
}
|
|
|
|
close(fd_principal);
|
|
close(fd_secundario);
|
|
return 0;
|
|
} |