Carpincho/src/core/ema.js
Exequiel Aramburu 2e2af3e169 Cambios
2026-09-27 20:04:22 -03:00

1369 lines
70 KiB
JavaScript

/**
* Archivo Core de EMA Libre Cliente (Carpincho).
*
* Archivo que se ejecuta en segundo plano y es el encargado, de obtener, registrar,
* calcular y publicar los registros, incluyendo los modulos necesarios para realizar
* estas tareas.
*
* LICENSE: This file is part of EMA Libre.
* EMA Libre is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EMA Libre is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EMA Libre. If not, see <http://www.gnu.org/licenses/>.
*
* @copyright Copyright (c) 2019 GUGLER (https://www.gugler.com.ar)
* @license https://www.gnu.org/licenses/gpl-3.0.html GPL License
* @version 3.0
* @link https://www.gugler.com.ar
* @since File available since Release 3.0
*/
/**************************************
*** DECLARACIONES INICIALES ******
**************************************/
var configGeneralEMA = require('./../conf/ConfiguracionGeneral.js'); // Configuracion General
const configGlobalEMA = require('./../conf/ConfiguracionGlobal.js'); // Configuracion Global
const Correo = require('./mail.js'); // Envio de correo.
var recolector = require('./recolector.js'); // Recolector de informacion USB.
const Redes = require('./redes_meteorologicas.js'); // Redes Meteorologicas disponibles.
const Validador = require('./validaciones.js'); // Validador de registros.
const fs = require('fs'); // Libreria fs para el manejo de archivos.
const util = require('util'); // Utilidades.
var Guardar = []; // Tanque diario de registros leidos (para acumulados).
var versionEMA = configGlobalEMA.ConfGlobal.Nombre + ' v' + configGlobalEMA.ConfGlobal.Version;
const http = require('http');
const https = require('https');
var DatosRecolectadosAnterior = []; // Datos recolectados de la estacion meteorologica.
APP = module.exports = {
Configuracion: {
Modo: configGeneralEMA.ConfGeneral.Modo, // Modo de funcionamiento de EMA.
Puerto: configGeneralEMA.ConfGeneral.Puerto, // Puerto de comunicacion.
IP: configGeneralEMA.ConfGeneral.IP, // IP de comunicacion.
Patch: configGeneralEMA.ConfGeneral.Ruta, // Ruta de comunicacion.
debug: configGeneralEMA.ConfGeneral.debug, // Se obtiene el nivel de debug del archivo de Conf General.
utc: configGeneralEMA.ConfGeneral.UTC, // Se obtiene la fecha en formato UTC del archivo de Conf General.
Errores: '', // Errores detectado en el funcionamiento de EMA.
TiempoContinuo: 0, // Tiempo en segundos(s) de recoleccion.
Cantidad_No_Lectura: 99999, // Cantidad de lecturas falsas admitidas.
Repeticiones: 0, // Contador de repeticiones. No parametrizable, siempre 0.
RepeticionesConError: 0, // Contador de repeticiones. No parametrizable, siempre 0.
TiempoMaximo: 0, // Contador de repeticiones. No parametrizable, siempre 0.
TiempoFueraDeLinea: 0, // Contador de tiempo fuera de linea.. No parametrizable, siempre 0.
TiempoMaximoFueraDeLinea: 300, // Tiempo en segundo fuera de linea para el envio de mail (default:3600 = 2hs).
IdsSetTimeouts: [], // Id del TimeOut del blucle continuo.
EstadoSensores: [], // Solo estado Sensores
Estado_Val_Ant: 0, // Solo estado Sensores del registro anterior para almacenar errores, ya que no se almacenan.
FechaLanzadoTimeout: 0, // fecha real de lanzamiento del TimeOut para el blucle continuo.
Run: 0, // Variable que indica que esta encendida EMA.
RunTime: 0, // Variable que indica que esta ejecutandose el Recolector.
BanderaPendientes: 0, // Bandera de Tanque enviando
CantidadPendientes: 0, // Tanque Pendientes
TanquePendiente: [], // Tanque Pendientes
UltimoRegistro: '', // Ultimo Registro Recolectado con datos de los sensores.
UltimoPublicado: [], // Ultimo Registro de las Redes Publicadas.
tempAlmacenadoPendientes: [] // Ultimo Registro de las Redes Publicadas.
},
RegistrarLog: function (reg, depurar) {
let nivel = reg.split('|')[0];
// Si el nivel de debug es mayor o igual al configurado, se registra.
if(APP.Configuracion.debug >= nivel) {
if (typeof depurar !== 'undefined') { depurar = false; }
// se convierte la fecha a la UTC parametrizada
var d = new Date();
var utc = d.getTime() + (d.getTimezoneOffset() * 60000);
var fechaHora = new Date(utc + (3600000 * (APP.Configuracion.utc)));
var horas = fechaHora.getHours();
var minutos = fechaHora.getMinutes();
var segundos = fechaHora.getSeconds();
var mes = fechaHora.getMonth() + 1;
var dia = fechaHora.getDate();
if (dia <= 9) { dia = '0' + dia; }
if (mes <= 9) { mes = '0' + mes; }
if (horas < 10) { horas = '0' + horas; }
if (minutos < 10) { minutos = '0' + minutos; }
if (segundos < 10) { segundos = '0' + segundos; }
var fecha = dia + '/' + mes + '/' + fechaHora.getFullYear() + ' ' + horas + ':' + minutos + ':' + segundos;
var registrologs = fecha + ' - ' + util.format(reg) + '\n';
// SE CONTROLA EL TAMAÑO DEL LOG SEGUN PARAMETRIA
var estadoarchivoD = fs.statSync("logs/debug.log");
var TamanioenMegaD = (estadoarchivoD.size)/ 1000000.0;
if (depurar || (TamanioenMegaD >= configGeneralEMA.ConfGeneral.debugTamanio))
{
// SE DEPURA EL ARCHIVO DE REGISTROS DE LOGS
fs.writeFile('./logs/debug.log', '', {
encoding: 'utf8',
autoClose: true
}, function (err) {
if (err) { APP.RegistrarLog('0|ERROR|🔴 Depurando archivo registro de logs :' + err); }
APP.RegistrarLog('0|PURGADO|🔴 Depurando automaticamente archivo registro de logs.');
});
} else {
// GUARDA LOS REGISTROS DE LOGS
fs.appendFile('./logs/debug.log', registrologs, {
encoding: 'utf8',
autoClose: true
}, function (err) {
if (err) {
APP.RegistrarLog('0|ERROR|🔴 Guardando registro de logs en archivo :' + err);
}
});
}
registrologs=null;fecha=null;dia=null;mes=null;segundos=null;minutos=null;horas=null;fechaHora=null;utc=null;d=null;
}
},
RepeticionesConError: function () {
return APP.Configuracion.RepeticionesConError;
},
Estado: function () {
if (APP.Configuracion.Run === 0 && APP.Configuracion.RunTime === 0) {
return [false, APP.Configuracion.Errores];
}
if (APP.Configuracion.Run === 1 && APP.Configuracion.RunTime === 0) {
return [false, APP.Configuracion.Errores];
}
if (APP.Configuracion.Run === 1 && APP.Configuracion.RunTime === 1) {
return [true, ''];
}
},
EstadoUSB: function (callback) {
try{ callback(recolector.status()); }catch(e){APP.RegistrarLog('0|CORE|🔴 Error: '+e);return false;}
},
Salir: function () {
APP.RegistrarLog('0|CORE|🔚 SALIR: Se cerro el core de EMA LIBRE. Hasta luego!!!.');
if (configGeneralEMA.ConfEmail.ActivarCorreos === true) Correo.EnviarEmail(configGeneralEMA,'EMA - OFFLINE', '<b>Estimado</b>,<br><br> Le informamos que la estación <b>' + configGeneralEMA.ConfGeneral.NombreEstacion + '</b> se detuvo y se cerro el software EMA LIBRE.<br><br>Saludos Cordiales.');
APP.Configuracion.Errores = 'Se Salio del Recolector';
},
Detener: function () {
APP.RegistrarLog('0|CORE|🔴 Se detiene el recolector de EMA LIBRE.');
APP.Configuracion.RunTime = 0;
APP.Configuracion.Errores = 'Se detuvo manualmente el Recolector';
APP.Configuracion.RepeticionesConError = 0;
APP.LimpiarM();
if(APP.Configuracion.Modo === 'Recolector_IP')
{
let PORT = APP.Configuracion.Puerto;
let HOST = APP.Configuracion.IP;
http.get(`http://${HOST}:${PORT}/detener_servidor`, (res) => {
res.on('data', (chunk) => {
});
res.on('end', () => {
APP.RegistrarLog('0|CORE|🔴 Petición de apagado enviada correctamente.');
});
}).on('error', (err) => {
APP.RegistrarLog('0|CORE|❌ Error al enviar petición');
});
}
},
Reconfigurar: function () {
APP.RegistrarLog('0|CORE|⚙️ RECONFIGURANDO: Se reconfigura el recolectorde EMA LIBRE.');
if (configGeneralEMA.ConfEmail.ActivarCorreos === true) Correo.EnviarEmail(configGeneralEMA,'EMA - CONFIG', '<b>Estimado</b>,<br><br> Le informamos que se modificó la configuración de la estación <b>' + configGeneralEMA.ConfGeneral.NombreEstacion + '</b>.<br><br>Saludos Cordiales.');
APP.Configuracion.TiempoContinuo = configGeneralEMA.ConfGeneral.Tiempo_de_Recoleccion;
APP.Configuracion.debug = configGeneralEMA.ConfGeneral.debug;
recolector.conf.debug = configGeneralEMA.ConfGeneral.debug;
APP.Configuracion.Puerto = configGeneralEMA.ConfGeneral.Puerto;
APP.Configuracion.IP = configGeneralEMA.ConfGeneral.IP;
APP.Configuracion.Patch = configGeneralEMA.ConfGeneral.Ruta;
},
Iniciar: function () {
if (APP.Configuracion.Run === 1 && APP.Configuracion.RunTime === 0) {
APP.RegistrarLog('0|CORE|🟢 INICIAR: Se inicio el recolector.');
APP.RegistrarLog('0|CORE|🛠️ DEBUG: ' + APP.Configuracion.debug);
APP.Configuracion.RunTime = 1;
if(APP.Configuracion.Modo != 'Recolector_IP') APP.Continuo();
} else {
APP.RegistrarLog('0|CORE|🔄 Hay un proceso corriendo, se elimina.');
APP.LimpiarM();
if(APP.Configuracion.Modo != 'Recolector_IP') APP.Continuo();
}
},
LimpiarM: function () {
var tamanio = APP.Configuracion.IdsSetTimeouts.length;
// Se limpias los tiempos identificados
for (tamanio;tamanio>-1;tamanio--){
clearTimeout(APP.Configuracion.IdsSetTimeouts[tamanio]);
APP.Configuracion.IdsSetTimeouts.splice(tamanio, 1);
}
// Se limpian las variables
tamanio = null;
return true;
},
Guardar_Diario: function (Datos) {
// GUARDA LOS REGISTROS DIARIOS
fs.writeFile('./logs/registro_diario.log', JSON.stringify(Datos, null, 4), {
encoding: 'utf8',
autoClose: true
}, (err) => {
if (err) {
APP.RegistrarLog('1|ERROR|🔴 Guardando registro diario en archivo :' + err);
}
});
},
TiempoActualRecolector: function (ahora = false) {
if(ahora) {return [100,100]; }
// APP.RegistrarLog(APP.Configuracion.IdsSetTimeouts);
var fechaTiempo = APP.Configuracion.FechaLanzadoTimeout;
var tiempoC = APP.Configuracion.TiempoContinuo;
if (fechaTiempo > 0) {
var Resto = 0;
Resto = (tiempoC - ((Date.now() - fechaTiempo) / 1000));
if(Resto > -1 && Resto < 150){
var porcentaje = (100 - ((Resto * 100) / tiempoC)).toFixed(0);
var segundos = (tiempoC - Resto).toFixed(1);
return [porcentaje,segundos];
}else{return [false,false];}
} else {
return [false,false];
}
},
UltimoRegistro: function () {
if (typeof APP.Configuracion.UltimoRegistro !== 'undefined' && APP.Configuracion.UltimoRegistro !== '') {
return APP.Configuracion.UltimoRegistro;
} else {
return false;
}
},
EstadoSensores: function () {
if (typeof APP.Configuracion.EstadoSensores !== 'undefined' && APP.Configuracion.EstadoSensores !== '') {
return APP.Configuracion.EstadoSensores;
} else {
return false;
}
},
UltimoPublicado: function () {
if (typeof APP.Configuracion.UltimoPublicado !== 'undefined' && APP.Configuracion.UltimoPublicado !== '') {
return APP.Configuracion.UltimoPublicado;
} else {
return false;
}
},
HayPendientes: function () {
if (APP.Configuracion.CantidadPendientes !== 0) {
return APP.Configuracion.CantidadPendientes;
} else {
return false;
}
},
// Metodo para conectar/verificar la conexion USB de la EMA USB.
Conectar: function () {
try {
if(APP.Configuracion.Modo === 'Recolector_IP'){
APP.RegistrarLog('0|CORE|🔧 Estableciendo Time Zone UTC ' + configGeneralEMA.ConfGeneral.UTC);
APP.RegistrarLog('0|CORE|🔧 Verificando Estado de la EMA...');
APP.RegistrarLog('0|CORE|🟢 Iniciando el Modo Recolector por IP/WIFI.');
APP.Configuracion.TiempoContinuo = configGeneralEMA.ConfGeneral.Tiempo_de_Recoleccion;
APP.Configuracion.debug = configGeneralEMA.ConfGeneral.debug;
// se levanta el puerto para escuchar las peticiones al puerto indicado.
const PORT = APP.Configuracion.Puerto;
const HOST = APP.Configuracion.IP;
const RUTA = APP.Configuracion.Patch; // e.g., "/datos"
const server = http.createServer((req, res) => {
const base = `http://${HOST}:${PORT}`;
let urlRaw = req.url;
// Si la ruta empieza con "/xxxx" y no tiene "?" pero sí "&", agregamos "?"
if (urlRaw.startsWith(RUTA) && !urlRaw.includes('?') && urlRaw.includes('&')) {
urlRaw = urlRaw.replace(RUTA, RUTA + '?');
}
const myURL = new URL(urlRaw, base);
const pathname = myURL.pathname.toLowerCase();
const method = req.method.toUpperCase();
const ip = req.socket.remoteAddress.replace('::ffff:', '');
APP.RegistrarLog('6|REGISTRO|📥 Recepcion IP: ' + ip + ' por ' + method + ' ruta ' + pathname);
//Para detener el servidor
if (pathname === '/detener_servidor') {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Servidor detenido');
APP.RegistrarLog('0|CORE| 🔴 Servidor detenido por botón');
server.close(() => {
});
return false;
}
//Para recibir la información de la estacion WIFI/IP
if (pathname === RUTA) {
// Comunes para ambos metodos
// se convierte la fecha a la UTC parametrizada
var d = new Date();
var utc = d.getTime() + (d.getTimezoneOffset() * 60000);
var db = new Date(utc + (3600000 * (APP.Configuracion.utc))); // UTC - Configurado
var dbutc = new Date(utc); // UTC Pura
// Se da formato a la fecha y hora
var minutos = db.getMinutes();
if (minutos <= 9) { minutos = '0' + minutos; }
var hora = db.getHours();
if (hora <= 9) { hora = '0' + hora; }
var mes = db.getMonth() + 1;
if (mes <= 9) { mes = '0' + mes; }
var dia = db.getDate();
if (dia <= 9) { dia = '0' + dia; }
var segundo = db.getSeconds();
if (segundo <= 9) { segundo = '0' + segundo; }
var fecha = dia + '/' + mes + '/' + db.getFullYear() + ' ' + hora + ':' + minutos + ':' + segundo;
var fechaISO = db.getFullYear() + '-' + mes + '-' + dia + 'T' + hora + ':' + minutos + ':' + segundo;
dia = null;
mes = null;
hora = null;
minutos = null;
segundo = null;
db = null;
utc = null;
d = null;
// UTC PURA
var minutost = dbutc.getMinutes();
if (minutost <= 9) { minutost = '0' + minutost; }
var horat = dbutc.getHours();
if (horat <= 9) { horat = '0' + horat; }
var mest = dbutc.getMonth() + 1;
if (mest <= 9) { mest = '0' + mest; }
var diat = dbutc.getDate();
if (diat <= 9) { diat = '0' + diat; }
var segundot = dbutc.getSeconds();
if (segundot <= 9) { segundot = '0' + segundot; }
var fechaUTC = dbutc.getFullYear() + '-' + mest + '-' + diat + '+' + horat + ':' + minutost + ':' + segundot;
diat = null;
mest = null;
horat = null;
minutost = null;
segundot = null;
dbutc = null;
const Etiquetas = [
'Fecha local',
'Fecha ISO',
'Temperatura exterior (°C)',
'Temperatura interior (°C)',
'Humedad exterior (%)',
'Humedad interior (%)',
'Luz (kLux)',
'Radiación UV',
'Viento (km/h)',
'Ráfaga (km/h)',
'Dirección viento (°)',
'Dirección viento (nombre)',
'Presión absoluta (hpa)',
'Presión relativa (hpa)',
'Lluvia total (mm)',
'Punto de rocío (°C)',
'Fecha UTC',
'Batería Baja (0-No/1-Si)'
];
if (method === 'GET') {
let Vector = Object.fromEntries(myURL.searchParams.entries());
//APP.RegistrarLog(`5|VECTOR|${JSON.stringify(Vector)}`);
let TemperaturaExternaC = ((parseFloat(Vector['tempf']) - 32) * 5 / 9).toFixed(2);
let TemperaturaInternaC = ((parseFloat(Vector['indoortempf']) - 32) * 5 / 9).toFixed(2);
let vientoEnKm = (parseFloat(Vector['windspeedmph']) * 1.60934).toFixed(2);
let rafagaEnKm = (parseFloat(Vector['windgustmph']) * 1.60934).toFixed(2);
let luxerIntencidad = Vector['solarradiation'] * 683; // luxerIntencidad en Luxer
let PresionR = (parseFloat(Vector['baromin']) * 33.8639).toFixed(2);
let PresionA = (parseFloat(Vector['absbaromin']) * 33.8639).toFixed(2);
// calculo del punto de rocio
let punto_de_rocio = ((parseFloat(Vector['dewptf']) - 32) * 5 / 9).toFixed(2);
punto_de_rocio = (Math.round(punto_de_rocio * 100)) / 100;
let x = Vector['winddir'];
// direccion del viento por nombre
switch (true) {
case x === 0:
VientoDireccion = 'Norte';
break;
case x > 0 && x < 90:
VientoDireccion = 'Nordeste';
break;
case x === 90:
VientoDireccion = 'Este';
break;
case x > 90 && x < 180:
VientoDireccion = 'Sudeste';
break;
case x === 180:
VientoDireccion = 'Sur';
break;
case x > 180 && x < 270:
VientoDireccion = 'Sudoeste';
break;
case x === 270:
VientoDireccion = 'Oeste';
break;
case x > 270 && x < 360:
VientoDireccion = 'Noroeste';
break;
default:
VientoDireccion = 'N/A';
}
x = null;
let lluviaTotalmm = (parseFloat(Vector['totalrainin']) * 25.4).toFixed(2);; // conversion a mm
let DatosRecolectados = [
fecha, // *0: Fecha local
fechaISO, // *1: Fecha ISO
parseFloat(TemperaturaExternaC), // *2: Temperatura exterior
parseFloat(TemperaturaInternaC), // *3: Temperatura interior
parseFloat(Vector['humidity']), // *4: Humedad exterior
parseFloat(Vector['indoorhumidity']), // *5: Humedad interior
luxerIntencidad, // *6: Luz Intencidad en Klux
parseFloat(Vector['UV']), // *7: Radiación UV
parseFloat(vientoEnKm), // *8: Velocidad viento
parseFloat(rafagaEnKm), // *9: Ráfaga
parseFloat(Vector['winddir']), // *10: Dirección viento (grados)
VientoDireccion, // *11: Dirección viento (nombre)
parseFloat(PresionA), // *12: Presión absoluta hpa
parseFloat(PresionR), // *13: Presión relativa hpa
parseFloat(lluviaTotalmm), // *14: Lluvia acumulada mm
punto_de_rocio, // *15: Punto de rocío
fechaUTC, // *16: UTC desde 'dateutc'
Vector['lowbatt'] // *17: Estado batería
];
// Se verifican cambios
if (DatosRecolectadosAnterior.length < 1) { DatosRecolectadosAnterior = DatosRecolectados;}
let cambios = {};
let bandera_cambios = false;
for (let i = 0; i < DatosRecolectados.length; i++) {
if ( i === 0 || i === 1 || i === 16) continue; // ignorar índices 0, 1 y 16 que son fechas
if (DatosRecolectados[i] !== DatosRecolectadosAnterior[i]) {
bandera_cambios = true;
cambios[Etiquetas[i]] = {
valorAnterior: DatosRecolectadosAnterior[i],
valorNuevo: DatosRecolectados[i]
};
}
}
//cambios = JSON.stringify(cambios, null, 2);
DatosRecolectados.forEach((dato, i) => {
APP.RegistrarLog(`5|REGISTRO|🗃️ ${i} - ${Etiquetas[i]}: ${dato}`);
});
// ACA SE ENVIA AL VALIDADOR Y A LAS REDES CONFIGURADAS
var Datos = [];
Datos = ['validar', DatosRecolectados,cambios,bandera_cambios];
Validador.Registros(Datos, function (errorvalidador, estadovalidador)
{
if (estadovalidador === true) {
APP.Configuracion.Repeticiones += 1;
APP.Configuracion.RepeticionesConError = 0;
APP.Configuracion.TiempoMaximo = 0;
APP.Configuracion.TiempoFueraDeLinea = 0;
APP.Configuracion.FechaLanzadoTimeout = Date.now();
APP.Registro_Diario(Datos[1],cambios,bandera_cambios);
APP.Publicar_en_Redes();
Datos = null;
} else {
APP.Configuracion.Repeticiones = 0;
APP.Configuracion.Estado_Val_Ant = errorvalidador[0];
APP.RegistrarLog('0|VALIDADOR|⚠️ Datos recolectados incorrectos: ' + errorvalidador[1]);
Datos = null;
} });
APP.Configuracion.EstadoSensores = DatosRecolectados[17];
DatosRecolectadosAnterior = DatosRecolectados; // Guardar los datos recolectados para la proxima vez.
TiempoActualRecolector(true); // para reiniciar el tiempo y sincronizar.
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Datos GET recibidos');
//TERMINA EL METODO GET
} else if (method === 'POST' || method === 'PATCH') {
// COMIENZA EL MOTODO POST
let body = '';
req.on('data', chunk => { body += chunk.toString(); });
req.on('end', () => {
// APP.RegistrarLog('5|REGISTRO|Datos formulario:'+body);
const params = new URLSearchParams(body);
const data = Object.fromEntries(params.entries());
// Se convierten las unidades necesarias
let TemperaturaExternaC = ((parseFloat(data['tempf']) - 32) * 5 / 9).toFixed(2);
let TemperaturaInternaC = ((parseFloat(data['tempinf']) - 32) * 5 / 9).toFixed(2);
let luxerIntencidad = params.get("solarradiation") * 683; // luxerIntencidad en Luxer
let vientoEnKm = (params.get('windspeedmph') * 1.60934).toFixed(2);;
let rafagaEnKm = (params.get('windgustmph') * 1.60934).toFixed(2);;
let PresionR = (parseFloat(params.get('baromabsin')) * 33.8639).toFixed(2);
let PresionA = (parseFloat(params.get('baromrelin')) * 33.8639).toFixed(2);
// calculo del punto de rocio
var punto_de_rocio = (Math.pow((params.get("humidity") / 100), 0.125)) * (112 - (-(0.9 * TemperaturaExternaC))) - (-(0.1 * TemperaturaExternaC)) - 112;
punto_de_rocio = (Math.round(punto_de_rocio * 100)) / 100;
let x = params.get("winddir");
// direccion del viento por nombre
switch (true) {
case x === 0:
VientoDireccion = 'Norte';
break;
case x > 0 && x < 90:
VientoDireccion = 'Nordeste';
break;
case x === 90:
VientoDireccion = 'Este';
break;
case x > 90 && x < 180:
VientoDireccion = 'Sudeste';
break;
case x === 180:
VientoDireccion = 'Sur';
break;
case x > 180 && x < 270:
VientoDireccion = 'Sudoeste';
break;
case x === 270:
VientoDireccion = 'Oeste';
break;
case x > 270 && x < 360:
VientoDireccion = 'Noroeste';
break;
default:
VientoDireccion = 'N/A';
}
x = null;
let lluviaTotalmm = (parseFloat(params.get('totalrainin')) * 25.4).toFixed(2); // conversion a mm
let DatosRecolectados = [
fecha, // *0: Fecha local
fechaISO, // *1: Fecha ISO
parseFloat(TemperaturaExternaC), // *2: Temperatura exterior
parseFloat(TemperaturaInternaC), // *3: Temperatura interior
parseFloat(params.get("humidity")), // *4: Humedad exterior
parseFloat(params.get("humidityin")), // *5: Humedad interior
luxerIntencidad, // *6: Luz Intencidad en Klux
parseFloat(params.get("uv")), // *7: Radiación UV
parseFloat(vientoEnKm), // *8: Velocidad viento
parseFloat(rafagaEnKm), // *9: Ráfaga
parseFloat(params.get("winddir")), // *10: Dirección viento (grados)
VientoDireccion, // *11: Dirección viento (nombre)
parseFloat(PresionA), // *12: Presión absoluta hpa
parseFloat(PresionR), // *13: Presión relativa hpa
parseFloat(lluviaTotalmm), // *14: Lluvia acumulada
punto_de_rocio, // *15: Punto de rocío
fechaUTC, // *16: UTC desde 'dateutc'
params.get('wh65batt') // *17: Estado batería
];
// Se verifican cambios
if (DatosRecolectadosAnterior.length < 1) { DatosRecolectadosAnterior = DatosRecolectados;}
let cambios = {};
let bandera_cambios = false;
for (let i = 0; i < DatosRecolectados.length; i++) {
if ( i === 0 || i === 1 || i === 16) continue; // ignorar índices 0, 1 y 16 que son fechas
if (DatosRecolectados[i] !== DatosRecolectadosAnterior[i]) {
bandera_cambios = true;
cambios[Etiquetas[i]] = {
valorAnterior: DatosRecolectadosAnterior[i],
valorNuevo: DatosRecolectados[i]
};
}
}
//cambios = JSON.stringify(cambios, null, 2);
DatosRecolectados.forEach((dato, i) => {
APP.RegistrarLog(`5|REGISTRO|🗃️ ${i} - ${Etiquetas[i]}: ${dato}`);
});
// ACA SE ENVIA AL VALIDADOR Y A LAS REDES CONFIGURADAS
var Datos = [];
Datos = ['validar', DatosRecolectados,cambios,bandera_cambios];
Validador.Registros(Datos, function (errorvalidador, estadovalidador)
{
if (estadovalidador === true) {
APP.Configuracion.Repeticiones += 1;
APP.Configuracion.RepeticionesConError = 0;
APP.Configuracion.TiempoMaximo = 0;
APP.Configuracion.TiempoFueraDeLinea = 0;
APP.Configuracion.FechaLanzadoTimeout = Date.now();
APP.Registro_Diario(Datos[1],cambios,bandera_cambios);
APP.Publicar_en_Redes();
Datos = null;
} else {
APP.Configuracion.Repeticiones = 0;
APP.Configuracion.Estado_Val_Ant = errorvalidador[0];
APP.RegistrarLog('0|VALIDADOR|⚠️ Datos recolectados incorrectos: ' + errorvalidador[1]);
Datos = null;
} });
APP.Configuracion.EstadoSensores = DatosRecolectados[17];
DatosRecolectadosAnterior = DatosRecolectados; // Guardar los datos recolectados para la proxima vez.
APP.TiempoActualRecolector(true); // para reiniciar el tiempo y sincronizar.
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Datos POST/PATCH recibidos');
});
} else {
APP.RegistrarLog('0|RECOLETOR_IP|⚠️ Dato Recibido pero metodo no encontrada: ' + method);
}
} else {
APP.RegistrarLog('0|RECOLETOR_IP|⚠️ Dato Recibido pero ruta no encontrada: ' + pathname);
}
});
server.listen(PORT, HOST, () => {
APP.RegistrarLog(`0|CORE|🟢 Servidor escuchando en ${HOST}:${PORT}`);
APP.Configuracion.Errores = `🟢 Servidor escuchando en ${HOST}:${PORT}`;
APP.Configuracion.TiempoMaximo = 0;
APP.Configuracion.Run = 1;
APP.Iniciar(); // Se llama a la funcion INICIO
});
server.on('error', (err) => {
if (err.code === 'EADDRINUSE') {
APP.RegistrarLog(`0|CORE| ❌ Error: El puerto ${PORT} ya está en uso.`);
//APP.Configuracion.Errores = '❌ Error el puerto ya está en uso.';
} else if (err.code === 'EACCES') {
APP.RegistrarLog(`0|CORE| ❌ Error: Permiso denegado para usar el puerto ${PORT}.`);
APP.Configuracion.Errores = '❌ Permiso denegado para usar el puerto.';
} else {
APP.RegistrarLog(`0|CORE| ❌ Error al iniciar servidor: ${err.message}`);
APP.Configuracion.Errores = '❌ Error al iniciar servidor.';
}
});
}else{ // RECOLECTOR USB
APP.RegistrarLog('0|CORE|Estableciendo Time Zone UTC ' + configGeneralEMA.ConfGeneral.UTC);
APP.RegistrarLog('0|CORE|Verificando Estado de la EMA...');
APP.Configuracion.TiempoContinuo = configGeneralEMA.ConfGeneral.Tiempo_de_Recoleccion;
APP.Configuracion.debug = configGeneralEMA.ConfGeneral.debug;
recolector.conf.debug = configGeneralEMA.ConfGeneral.debug;
if (recolector.status() === true || APP.Configuracion.Run === 0) {
// Verifica la plataforma donde esta corriendo
if (APP.Configuracion.Run === 0) {
station = recolector.open(); // No puedo poner var station = -> no funciona ver.
APP.RegistrarLog('0|CORE|Conectando..');
} // solo si es la primera vez, genera el recolector.
if (station === null || station === false) {
if (station === false) {
APP.Configuracion.Errores = 'Problemas con el USB, por favor desconecte y conecte el mismo';
APP.Configuracion.Run = 0;
throw new Error('Problemas con el USB, por favor desconecte y conecte el mismo.');
} else {
APP.RegistrarLog('0|CORE|Info de Estado: Fuera de Linea.');
APP.RegistrarLog('0|CORE|Info de Detalle: EMA no conectada.');
APP.RegistrarLog('0|CORE|Info de Acción: Verifique la conexion USB de la EMA.');
APP.Configuracion.Errores = 'Se espera ' + APP.Configuracion.TiempoContinuo + ' segundos y se prueba conectar nuevamente.';
throw new Error('Problemas con la lectura USB');
}
} else {
APP.RegistrarLog('0|CORE|ESTADO: Online');
APP.RegistrarLog('0|CORE|PLATAFORMA: ' + recolector.conf.plataforma);
APP.RegistrarLog('0|CORE|AUTOR:Gugler Lab');
APP.RegistrarLog('0|CORE|VERSION:' + configGlobalEMA.ConfGlobal.Version);
if (APP.Configuracion.Run === 0) {
APP.RegistrarLog('0|CORE|🟢 Se inicio el motor de EMA LIBRE.');
APP.Configuracion.Errores = 'CORE: INICIAR-> Se inicio el motor de EMA LIBRE.';
APP.Configuracion.Run = 1;
}
APP.Configuracion.TiempoMaximo = 0;
APP.Iniciar(); // Se llama a la funcion INICIO
}
} else {
if (recolector.status() === false && APP.Configuracion.Run === 0) {
throw new Error('Conexión usb no detectada, por favor verifique el cable.');
}
if (recolector.status() === false && APP.Configuracion.Run === 1) {
APP.Configuracion.Run = 0;
throw new Error('Conexión usb no detectada, se desconectó en funcionamiento.');
}
}
}
} catch (ex) {
APP.RegistrarLog('0|EXCEP|Información de la excepcion: -> ' + ex + '');
APP.Configuracion.Errores = 'EXCEP: Información de la excepcion: -> ' + ex;
var tiempo = (APP.Configuracion.TiempoMaximo + APP.Configuracion.TiempoContinuo) * 1000;
APP.Configuracion.TiempoFueraDeLinea += tiempo;
APP.RegistrarLog('0|EXCEP|Se espera ' + (tiempo / 1000) + ' segundos y se prueba conectar nuevamente ....');
APP.Configuracion.IdsSetTimeouts.push(setTimeout(APP.Conectar, tiempo));
tiempo=null;
}
},
// Metodo para comprobar el errores.
CompruebaError: function () {
// se comprueba si ya existe otra excepcion en memoria
if (process.listeners('uncaughtException').length === 0) {
process.on('uncaughtException', function (err) {
APP.Configuracion.RunTime = 0; // Se para el recolector
APP.LimpiarM();
APP.Configuracion.Repeticiones = 0;
var tiempo = (APP.Configuracion.TiempoMaximo + APP.Configuracion.TiempoContinuo) * 1000;
APP.Configuracion.TiempoFueraDeLinea += tiempo;
APP.Configuracion.Errores = err;
if ((configGeneralEMA.ConfEmail.ActivarCorreos === true) && ((APP.Configuracion.TiempoFueraDeLinea > (APP.Configuracion.TiempoMaximoFueraDeLinea * 1000)) || ((APP.Configuracion.TiempoFueraDeLinea - tiempo) < 1))) {
if ((APP.Configuracion.TiempoFueraDeLinea - tiempo) > 1) {
APP.Configuracion.TiempoMaximoFueraDeLinea = APP.Configuracion.TiempoMaximoFueraDeLinea * 2;
}
APP.RegistrarLog('1|MAIL|Se envio correo notificando que la estacion ' + configGeneralEMA.ConfGeneral.NombreEstacion + ' se encuentra fuera de linea por mas de: ' + (APP.Configuracion.TiempoFueraDeLinea / 1000) + 's o ' + (APP.Configuracion.TiempoFueraDeLinea / 1000 / 60).toFixed(2) + ' minutos');
}
APP.RegistrarLog('1|ERROR|🔴 ' + err + '.');
APP.RegistrarLog('1|ERROR|🔴 Se espera ' + (tiempo / 1000) + ' segundos ( Tiempo fuera de linea: ' + (APP.Configuracion.TiempoFueraDeLinea / 1000) + 's o ' + (APP.Configuracion.TiempoFueraDeLinea / 1000 / 60).toFixed(2) + ' minutos), luego se intenta iniciar el recolector.');
APP.Configuracion.IdsSetTimeouts.push(setTimeout(APP.Conectar, tiempo));
tiempo = null;
});
}
},
VerificarTanqueDePendientes: function (red) { // REGISTROS PENDIENTES DE ENVIAR (Solo redes Ema Center)
if (APP.Configuracion.BanderaPendientes === 0) { // Pregunto si no esta destanqueando
APP.Configuracion.TanquePendiente = [];
APP.Configuracion.BanderaPendientes = 1;
APP.RegistrarLog('3|PENDIENTE|🛢️ Verificando el tanque.');
try {
fs.readFile('./logs/TanquePendientes.log', {
encoding: 'utf8',
autoClose: true
}, function (err, data) {
try {
if (err) {
APP.RegistrarLog('1|ERROR|🛢️🔴 Intentando destanquear los registros.');
APP.Configuracion.BanderaPendientes = 0;
}
if (data.length < 10) {
APP.Configuracion.CantidadPendientes = 0;
APP.Configuracion.BanderaPendientes = 0;
APP.RegistrarLog('3|PENDIENTE|🛢️ Tanque vacio.');
} else {
Guardar = [];
var EnviarPendientes = [];
var Pendientes = JSON.parse(data);
var CantRegistros = Pendientes.length;
var intentos = 0;
APP.Configuracion.CantidadPendientes = CantRegistros;
APP.RegistrarLog('3|PENDIENTE|🛢️ Cantidad Registros en Pendientes: ' + CantRegistros);
for (var i = 0, t = CantRegistros; i < t; ++i) {
EnviarPendientes[0] = [Pendientes[i].TipoRed, Pendientes[i].Usuario, Pendientes[i].Password, Pendientes[i].Server, Pendientes[i].Puerto, Pendientes[i].Ruta, Pendientes[i].Llave_W, Pendientes[i].Nombre, 'PENDIENTE'];
EnviarPendientes[1] = Pendientes[i].registro;
EnviarPendientes[2] = Pendientes[i].idRed;
if ((red === Pendientes[i].idRed) && intentos < 3) { // Pregunto si la red online es la del registro en tanque y solo envio 3 registros pendientes
intentos = intentos + 1;
Redes.EviarRedesMeteorologicas(versionEMA, EnviarPendientes, function (red, estadored, errorRedes, idRed, registro) {
var RegistroEnviado = JSON.parse(registro);
if (estadored === 'ERROR') { // si falla el destanqueo
APP.RegistrarLog('3|PENDIENTE|🛢️🔴 Error no se pudo publicar la Red : ' + red + ' - Estado:' + estadored);
var Pendiente = {
idRed: RegistroEnviado[2],
TipoRed: RegistroEnviado[0][0],
Usuario: RegistroEnviado[0][1],
Password: RegistroEnviado[0][2],
Server: RegistroEnviado[0][3],
Puerto: RegistroEnviado[0][4],
Ruta: RegistroEnviado[0][5],
Llave_W: RegistroEnviado[0][6],
Nombre: RegistroEnviado[0][7],
registro: RegistroEnviado[1]
};
APP.Configuracion.TanquePendiente.push(Pendiente);
Pendiente = null;
} else { // si es correcto, tiene que borrar el registro ya enviado
APP.Configuracion.CantidadPendientes = APP.Configuracion.CantidadPendientes - 1;
if (APP.Configuracion.CantidadPendientes < 0) {
APP.Configuracion.CantidadPendientes = 0;
}
APP.RegistrarLog('0|RED|🌐🛢️ Red Publicada Tanque:' + red + '- Fecha Registro:' + RegistroEnviado[1].fecha + ' - Estado:' + estadored);
}
}); // CALLBACK ENVIAR RED
} else {
APP.Configuracion.TanquePendiente.push(Pendientes[i]);
}
}
APP.Configuracion.BanderaPendientes = 0;
APP.Guardar_Pendientes('', false);
EnviarPendientes = null;
}
} catch (ex) { // si hay un error en el archivo tanque de pendiente se blanquea y se vuelve a llamar la misma.
APP.RegistrarLog('1|ERROR|🔴 Tanque Pendientes corrupto.Se blanqueo el tanque diario para depurar el error. 2: ' + ex);
APP.Configuracion.TanquePendiente = [];
APP.Configuracion.BanderaPendientes = 0;
fs.writeFile('./logs/TanquePendientes.log', JSON.stringify(APP.Configuracion.TanquePendiente, null, 4), {
encoding: 'utf8',
autoClose: true
}, function (err) {
if (err) {
APP.RegistrarLog('1|ERROR|🔴 Guardando registro de prendientes de Ema Center en archivo :' + err);
}
});
}
});
} catch (ex) { // si hay un error en el archivo tanque de pendiente se blanquea y se vuelve a llamar la misma.
APP.RegistrarLog('1|ERROR|🔴 Tanque Pendientes corrupto.Se blanqueo el tanque diario para depurar el error. 1: ' +ex);
APP.Configuracion.TanquePendiente = [];
fs.writeFile('./logs/TanquePendientes.log', JSON.stringify([], null, 4), {
encoding: 'utf8',
autoClose: true
}, function (err) {
if (err) {
APP.RegistrarLog('1|ERROR|🔴 Guardando registro de prendientes de Ema Center en archivo :' + err);
}
});
}
}
},
Guardar_Pendientes: function (Datos, guardar) {
if (APP.Configuracion.BanderaPendientes === 0) { // Pregunto si no esta destanqueando
try {
if (guardar === true) {
var pendienteCompleto = null;
var TP_temp = fs.readFileSync('./logs/TanquePendientes.log', 'utf8');
APP.Configuracion.CantidadPendientes = APP.Configuracion.CantidadPendientes + 1;
var pendienteCompleto = JSON.parse(TP_temp);
for (var i = 0, t = Datos.length; i < t; ++i) {pendienteCompleto.push(Datos[i]);}
APP.Configuracion.CantidadPendientes = pendienteCompleto.length;
fs.writeFile('./logs/TanquePendientes.log', JSON.stringify(pendienteCompleto, null, 4), {
encoding: 'utf8',
autoClose: true
}, function (err) {
if (err) {
APP.RegistrarLog('1|ERROR|🔴 Guardando registro de prendientes de Ema Center en archivo :' + err);
}
});
} else {
fs.writeFile('./logs/TanquePendientes.log',JSON.stringify(APP.Configuracion.TanquePendiente, null, 4), {
encoding: 'utf8',
autoClose: true
}, function (err) {
if (err) {
APP.RegistrarLog('1|ERROR|🔴 Guardando registro de prendientes de Ema Center en archivo :' + err);
}
});
}
} catch (ex) { // si hay un error en el archivo tanque de pendiente se blanquea y se vuelve a llamar la misma.
APP.RegistrarLog('1|ERROR| 🔴 Tanque Pendientes corrupto.Se blanqueo el tanque diario para depurar el error. 3:'+ex);
APP.Configuracion.BanderaPendientes = 0;
APP.Configuracion.TanquePendiente = [];
APP.Guardar_Pendientes( '', false);
}
}
},
// Metodo para publicar en redes meteorologicas
Publicar_en_Redes: function () {
var Publicar = configGeneralEMA.ConfPublicador;
var Cantidad = Publicar.length;
var UltimoRegistro = APP.Configuracion.UltimoRegistro;
var Enviar = [];
if (typeof UltimoRegistro !== 'undefined' && UltimoRegistro !== '') {
var RegistroPublicado = '';
for (var i = 0, t = Cantidad; i < t; ++i) {
if (Publicar[i].Publicar === true) {
UltimoRegistro.tanque = false;
Enviar[0] = [Publicar[i].TipoRed, Publicar[i].Usuario, Publicar[i].Password, Publicar[i].Server, Publicar[i].Puerto, Publicar[i].Ruta, Publicar[i].Llave_W, Publicar[i].Nombre];
Enviar[1] = UltimoRegistro;
Enviar[2] = i;
Redes.EviarRedesMeteorologicas(versionEMA, Enviar, function (red, estadored, errorRedes, idRed, registro) {
var RegistroEnviado = JSON.parse(registro);
// APP.RegistrarLog(RegistroEnviado);
if (estadored === 'ERROR') { // Si hay error en publicar la red
var fechaanterior = '';
if (typeof APP.Configuracion.UltimoPublicado[idRed] === 'undefined') {
fechaanterior = '00/00/0000 00:00:00';
} else {
fechaanterior = APP.Configuracion.UltimoPublicado[idRed].fecha;
}
RegistroPublicado = {
"red": red,
"estado": false,
"fecha": fechaanterior,
"error": errorRedes
};
APP.Configuracion.UltimoPublicado[idRed] = RegistroPublicado;
APP.RegistrarLog('3|RED|🌐🔴 Red No Publicada: ' + red + ' - Estado:' + estadored + ' ' + errorRedes);
if ((red === 'emacenter') || (red === 'emacentergugler')) {
APP.RegistrarLog('0|PENDIENTE|🛢️ Se almaceno registro en el tanque de pendientes: ' + RegistroEnviado[0][7]);
RegistroEnviado[1].tanque = true;
var PendienteTemp = {
idRed: RegistroEnviado[2],
TipoRed: RegistroEnviado[0][0],
Usuario: RegistroEnviado[0][1],
Password: RegistroEnviado[0][2],
Server: RegistroEnviado[0][3],
Puerto: RegistroEnviado[0][4],
Ruta: RegistroEnviado[0][5],
Llave_W: RegistroEnviado[0][6],
Nombre: RegistroEnviado[0][7],
registro: RegistroEnviado[1]
};
APP.Configuracion.tempAlmacenadoPendientes.push(PendienteTemp);
}
} else { // Si se publico correctamente
if (((red === 'emacenter' || red === 'emacentergugler')) && ((APP.Configuracion.CantidadPendientes > 0) || (APP.Configuracion.Repeticiones < 3))) {
APP.VerificarTanqueDePendientes(idRed);
} // verifica el tanque de redes Ema Libre Center Solamente
if (estadored === 430) {
RegistroPublicado = {
"red": red,
"estado": "No enviado",
"fecha": errorRedes,
"error": "No Enviado"
};
estadored = 'No Enviado';
}else{
if (estadored === 429) {
RegistroPublicado = {
"red": red,
"estado": "Esperar",
"fecha": errorRedes,
"error": "Red Congestionada"
};
estadored = 'Congestionada';
} else {
RegistroPublicado = {
"red": red,
"estado": true,
"fecha": RegistroEnviado[1].fecha,
"error": "-"
};
}
}
APP.Configuracion.UltimoPublicado[idRed] = RegistroPublicado;
APP.RegistrarLog('3|RED|🌐 Red Publicada: ' + red + ' - Estado:' + estadored);
}
}); // CALLBACK ENVIAR RED
} else {
if (typeof APP.Configuracion.UltimoPublicado[i] !== 'undefined') {
RegistroPublicado = {
"red": APP.Configuracion.UltimoPublicado[i].red,
"estado": false,
"fecha": APP.Configuracion.UltimoPublicado[i].fecha,
"error": "Detenido"
};
APP.Configuracion.UltimoPublicado[i] = RegistroPublicado;
}
}
}
if(APP.Configuracion.tempAlmacenadoPendientes.length > 0){APP.Guardar_Pendientes(APP.Configuracion.tempAlmacenadoPendientes, true);}
APP.Configuracion.tempAlmacenadoPendientes = [];
// SE eliminan las variables
Publicar = null;
Cantidad = null;
RegistroPublicado = null;
RegistroEnviado = null;
UltimoRegistro = null;
Enviar = null;
}
},
// Metodo para obtener datos de EMA CENTER en modo visor por llave de lectura
Visor: function (cant, callback) {
var timeout = 5000;
var ServidorEMACENTER = {
hostname: 'emacenter.gugler.com.ar',
port: 443,
path: '/api/get/' + configGeneralEMA.ConfGeneral.Llave_R + '/?cant=' + cant,
method: 'GET'
};
if (typeof callback !== 'function') callback = function () {};
APP.RegistrarLog('8|VISOR|Buscando un registro en EMACENTER(' + ServidorEMACENTER.hostname + ')...');
var request = https.request(ServidorEMACENTER, function (response) {
if (response.statusCode === 200) { // RESPUESTA HTML Y COMPARA
var message = '';
response.on('data', function (chunk) {
message += chunk;
});
response.on('end', function () {
var result = message.trim();
var Respuesta = JSON.parse(result);
// Se verifica la Respuesta
// APP.RegistrarLog(Respuesta);
if (typeof Respuesta.error === 'undefined') {
APP.RegistrarLog('6|VISOR|Registro obtenido de ' + Respuesta.modelo + ' de Fecha: ' + Respuesta.registros[0].fecha);
callback(null, Respuesta);
} else {
APP.RegistrarLog('6|ERROR| 🔴 Registro con algun error.');
callback(Respuesta.error, null);
}
});
} else {
var respuesta = 'Codigo: ' + response.statusCode;
APP.RegistrarLog('6|ERROR| 🔴 No se pudo obtener el registro (Modo Visor). ' + respuesta);
callback(respuesta, null);
}
});
request.on('socket', function (socket) {
socket.setTimeout(timeout);
socket.on('timeout', function () {
APP.RegistrarLog('6|ERROR| 🔴 TimeOut cuando se intenta obtener el registro (Modo Visor). Codigo: ' + request.statusCode);
request.abort();
});
}).on('error', function (error) {
callback(error, null);
});
request.end();
},
// Metodo para el registro de lecturas obtenidas
Registro_Diario: function (Datos,Cambios,Cambio) {
// Leo El archivo de Tanque diario
var LLuviaAcumuladaTotal = 0;
var LLuviaAcumuladaDia = 0;
var LLuviaAcumuladaHora = 99999999;
var LluviaActual = 0;
var LLuviaAcumuladaMinutos = 99999999;
var luxerintencidad1hs = 0;
var tempIntMinDia = 99;
var tempIntMaxDia = -99;
var humIntMaxDia = -99;
var humIntMinDia = 99;
var tempExtMinDia = 99;
var tempExtMaxDia = -99;
var humExtMaxDia = -99;
var humExtMinDia = 99;
var puntoDeRocioMinDia = 99;
var puntoDeRocioMaxDia = -99;
var luxerIntencidadMinDia = 999999;
var luxerIntencidadMaxDia = -999999;
var luxerUvMinDia = 99;
var luxerUvMaxDia = -99;
var presionRelativaMinDia = 999999;
var presionRelativaMaxDia = -999999;
var vientoDireccionPromDia = 0;
var CantidadV = 0;
var vientoVelocidadMaxDia = -999999;
var vientoRafagasMaxDia = -999999;
fs.readFile('./logs/registro_diario.log', {
encoding: 'utf8',
autoClose: true
}, (err, data) => {
var Guardar = [];
if (err) {
APP.RegistrarLog('1|ERROR| 🔴 Tanque diario corrupto.Se blanqueo el tanque diario para depurar el error.');
APP.Guardar_Diario(Guardar);
} else {
var DepurarLog = false;
if (data.length < 10) {
APP.RegistrarLog('8|ARCHIVO|🗄️ Tanque diario vacio.');
} else {
try {
var RegistroDiario = JSON.parse(data);
var CantRegistros = RegistroDiario.length;
APP.RegistrarLog('8|ARCHIVO|🗄️ Cantidad registros diarios: ' + CantRegistros);
var RegistroNuevoDia = Datos[0].substring(0, 2);
var RegistroNuevoHora = Datos[0].substring(11, 13);
var RegistroNuevoMinuto = Datos[0].substring(14, 15);
LLuviaAcumuladaTotal = Datos[14];
LLuviaAcumuladaDia = LLuviaAcumuladaTotal - RegistroDiario[0].lluvia_acumulado_total;
for (var j = 0; j < CantRegistros; j++) { // Comprueba si no cambio de dia
var Dia = RegistroDiario[j].fecha.substring(0, 2);
var Hora = RegistroDiario[j].fecha.substring(11, 13);
var Min = RegistroDiario[j].fecha.substring(14, 15);
if (Dia === RegistroNuevoDia) {
// Se calcula los max y min diarios (ej:terperatura y humedad)
if (RegistroDiario[j].temperatura_interna > parseFloat(tempIntMaxDia)) {
tempIntMaxDia = RegistroDiario[j].temperatura_interna;
}
if (RegistroDiario[j].temperatura_interna < parseFloat(tempIntMinDia)) {
tempIntMinDia = RegistroDiario[j].temperatura_interna;
}
if (RegistroDiario[j].humedad_interna > parseFloat(humIntMaxDia)) {
humIntMaxDia = RegistroDiario[j].humedad_interna;
}
if (RegistroDiario[j].humedad_interna < parseFloat(humIntMinDia)) {
humIntMinDia = RegistroDiario[j].humedad_interna;
}
if (RegistroDiario[j].temperatura_externa > parseFloat(tempExtMaxDia)) {
tempExtMaxDia = RegistroDiario[j].temperatura_externa;
}
if (RegistroDiario[j].temperatura_externa < parseFloat(tempExtMinDia)) {
tempExtMinDia = RegistroDiario[j].temperatura_externa;
}
if (RegistroDiario[j].humedad_externa > parseFloat(humExtMaxDia)) {
humExtMaxDia = RegistroDiario[j].humedad_externa;
}
if (RegistroDiario[j].humedad_externa < parseFloat(humExtMinDia)) {
humExtMinDia = RegistroDiario[j].humedad_externa;
}
if (RegistroDiario[j].punto_de_rocio > parseFloat(puntoDeRocioMaxDia)) {
puntoDeRocioMaxDia = RegistroDiario[j].punto_de_rocio;
}
if (RegistroDiario[j].punto_de_rocio < parseFloat(puntoDeRocioMinDia)) {
puntoDeRocioMinDia = RegistroDiario[j].punto_de_rocio;
}
if (RegistroDiario[j].presion_relativa > parseFloat(presionRelativaMaxDia)) {
presionRelativaMaxDia = RegistroDiario[j].presion_relativa;
}
if (RegistroDiario[j].presion_relativa < parseFloat(presionRelativaMinDia)) {
presionRelativaMinDia = RegistroDiario[j].presion_relativa;
}
if (RegistroDiario[j].viento_velocidad > parseFloat(vientoVelocidadMaxDia)) {
vientoVelocidadMaxDia = RegistroDiario[j].viento_velocidad;
}
if (RegistroDiario[j].viento_rafagas > parseFloat(vientoRafagasMaxDia)) {
vientoRafagasMaxDia = RegistroDiario[j].viento_rafagas;
}
// Solo si existe sensor UV y LUX
if ((RegistroDiario[j].luxer_intencidad != null) || (RegistroDiario[j].luxer_intencidad != null)) {
if (RegistroDiario[j].luxer_intencidad > parseFloat(luxerIntencidadMaxDia)) {
luxerIntencidadMaxDia = RegistroDiario[j].luxer_intencidad;
}
if (RegistroDiario[j].luxer_intencidad < parseFloat(luxerIntencidadMinDia)) {
luxerIntencidadMinDia = RegistroDiario[j].luxer_intencidad;
}
if (RegistroDiario[j].luxer_uv > parseFloat(luxerUvMaxDia)) {
luxerUvMaxDia = RegistroDiario[j].luxer_uv;
}
if (RegistroDiario[j].luxer_uv < parseFloat(luxerUvMinDia)) {
luxerUvMinDia = RegistroDiario[j].luxer_uv;
}
}
vientoDireccionPromDia += RegistroDiario[j].viento_direccion;
CantidadV++;
if (Hora === RegistroNuevoHora) {
// Se calcula la lluvia acumulada hora y actual
if (RegistroDiario[j].lluvia_acumulado_total < LLuviaAcumuladaHora) {
LLuviaAcumuladaHora = RegistroDiario[j].lluvia_acumulado_total;
luxerintencidad1hs = RegistroDiario[j].luxer_intencidad;
}
if (Min === RegistroNuevoMinuto) {
if (RegistroDiario[j].lluvia_acumulado_total < LLuviaAcumuladaMinutos) {
LLuviaAcumuladaMinutos = RegistroDiario[j].lluvia_acumulado_total;
}
}
}
Guardar.push(RegistroDiario[j]);
} else {
DepurarLog = true;
}
}
vientoDireccionPromDia = vientoDireccionPromDia / CantidadV;
RegistroDiario = null;
} catch (ex) { // si hay un error en el archivo registro_diario se blanquea y se vuelve a llamar la misma.
APP.RegistrarLog('1|ERROR| 🔴 Tanque diario corrupto.Se blanqueo el tanque diario para depurar el error.');
Guardar = [];
APP.Guardar_Diario(Guardar);
}
}
// Se depurar el registro de logs
if (DepurarLog) {
APP.RegistrarLog('6|ARCHIVO|Depurando archivo de logs.', true);
}
// REGISTRO ACTUAL
LLuviaAcumuladaHora = Datos[14] - LLuviaAcumuladaHora;
LLuviaAcumuladaMinutos = Datos[14] - LLuviaAcumuladaMinutos;
if (tempIntMaxDia < -90) { tempIntMaxDia = 'S/D'; }
if (humIntMaxDia < -90) { humIntMaxDia = 'S/D'; }
if (tempIntMinDia > 90) { tempIntMinDia = 'S/D'; }
if (humIntMinDia > 90) { humIntMinDia = 'S/D'; }
if (tempExtMaxDia < -90) { tempExtMaxDia = 'S/D'; }
if (humExtMaxDia < -90) { humExtMaxDia = 'S/D'; }
if (tempExtMinDia > 90) { tempExtMinDia = 'S/D'; }
if (humExtMinDia > 90) { humExtMinDia = 'S/D'; }
if (puntoDeRocioMinDia > 90) { puntoDeRocioMinDia = 'S/D'; }
if (puntoDeRocioMaxDia < -90) { puntoDeRocioMaxDia = 'S/D'; }
if (luxerIntencidadMinDia > 900000) { luxerIntencidadMinDia = 'S/D'; }
if (luxerIntencidadMaxDia < -900000) { luxerIntencidadMaxDia = 'S/D'; }
if (luxerUvMinDia > 90) { luxerUvMinDia = 'S/D'; }
if (luxerUvMaxDia < -90) { luxerUvMaxDia = 'S/D'; }
if (presionRelativaMinDia > 900000) { presionRelativaMinDia = 'S/D'; }
if (presionRelativaMaxDia < -900000) { presionRelativaMaxDia = 'S/D'; }
if (vientoVelocidadMaxDia < -900000) { vientoVelocidadMaxDia = 'S/D'; }
if (vientoRafagasMaxDia < -900000) { vientoRafagasMaxDia = 'S/D'; }
if (LLuviaAcumuladaMinutos > 0) { LluviaActual = LLuviaAcumuladaMinutos; } else { LLuviaAcumuladaMinutos = 0; LluviaActual = 0; }
if (LLuviaAcumuladaHora < 0) { LLuviaAcumuladaHora = 0; }
if (LLuviaAcumuladaDia < 0) { LLuviaAcumuladaDia = 0; }
APP.RegistrarLog('5|REGISTRO|🌧️ Calculado - Lluvia Hora: ' + LLuviaAcumuladaHora.toFixed(2));
APP.RegistrarLog('5|REGISTRO|🌧️ Calculado - Lluvia Actual: ' + LLuviaAcumuladaMinutos.toFixed(2));
APP.RegistrarLog('5|REGISTRO|🌧️ Calculado - Lluvia Dia: ' + LLuviaAcumuladaDia.toFixed(2));
var RegistroJSON = {
fecha: Datos[0],
fechaISO: Datos[1],
fechaUTC: Datos[16],
temperatura_externa: Datos[2],
temperatura_interna: Datos[3],
humedad_externa: Datos[4],
humedad_interna: Datos[5],
punto_de_rocio: parseFloat(Datos[15].toFixed(2)),
luxer_intencidad: Datos[6],
luxer_intencidad_1hs: luxerintencidad1hs,
luxer_uv: Datos[7],
viento_velocidad: parseFloat(Datos[8].toFixed(2)),
viento_rafagas: parseFloat(Datos[9].toFixed(2)),
viento_direccion: Datos[10],
viento_direccion_nombre: Datos[11],
presion_absoluta: Datos[12],
presion_relativa: Datos[13],
lloviendo: parseFloat(LluviaActual.toFixed(2)),
lluvia_acu_hora: parseFloat(LLuviaAcumuladaHora.toFixed(2)),
lluvia_acu_diaria: parseFloat(LLuviaAcumuladaDia.toFixed(2)),
lluvia_acumulado_total: parseFloat(Datos[14].toFixed(2)),
temperatura_interna_max_dia: tempIntMaxDia,
temperatura_interna_min_dia: tempIntMinDia,
humedad_interna_max_dia: humIntMaxDia,
humedad_interna_min_dia: humIntMinDia,
temperatura_externa_max_dia: tempExtMaxDia,
temperatura_externa_min_dia: tempExtMinDia,
humedad_externa_max_dia: humExtMaxDia,
humedad_externa_min_dia: humExtMinDia,
punto_de_rocio_max_dia: puntoDeRocioMaxDia,
punto_de_rocio_min_dia: puntoDeRocioMinDia,
luxer_intencidad_max_dia: luxerIntencidadMaxDia,
luxer_intencidad_min_dia: luxerIntencidadMinDia,
luxer_uv_max_dia: luxerUvMaxDia,
luxer_uv_min_dia: luxerUvMinDia,
presion_relativa_max_dia: presionRelativaMaxDia,
presion_relativa_min_dia: presionRelativaMinDia,
viento_direccion_prom_dia: parseFloat(vientoDireccionPromDia.toFixed(2)),
viento_velocidad_max_dia: vientoVelocidadMaxDia,
viento_rafagas_max_dia: vientoRafagasMaxDia,
estado_sensores: Datos[17],
diferencia: Cambios,
cambio: Cambio,
estado_validacion_ant: APP.Configuracion.Estado_Val_Ant
};
APP.Configuracion.Estado_Val_Ant = 0;
APP.Configuracion.UltimoRegistro = RegistroJSON;
Guardar.push(RegistroJSON);
APP.Guardar_Diario(Guardar);
RegistroJSON = null;
Guardar = null;
LLuviaAcumuladaTotal = null;
LLuviaAcumuladaDia = null;
LLuviaAcumuladaHora = null;
LluviaActual = null;
LLuviaAcumuladaMinutos = null;
luxerintencidad1hs = null;
tempIntMinDia = null;
tempIntMaxDia = null;
humIntMaxDia = null;
humIntMinDia = null;
tempExtMinDia = null;
tempExtMaxDia = null;
humExtMaxDia = null;
humExtMinDia = null;
puntoDeRocioMinDia = null;
puntoDeRocioMaxDia = null;
luxerIntencidadMinDia = null;
luxerIntencidadMaxDia = null;
luxerUvMinDia = null;
luxerUvMaxDia = null;
presionRelativaMinDia = null;
presionRelativaMaxDia = null;
vientoDireccionPromDia = null;
CantidadV = null;
vientoVelocidadMaxDia = -null;
vientoRafagasMaxDia = null;
}
});
},
// Metodo de ejecucion continua (repite continuamente).
Continuo: function () {
try {
APP.LimpiarM();
APP.Configuracion.FechaLanzadoTimeout = -99;
if (APP.Configuracion.Run === 1 && APP.Configuracion.RunTime === 1) {
APP.Configuracion.TiempoMaximo = 0;
APP.CompruebaError();
APP.Configuracion.RepeticionesConError += 1;
var d = new Date();
var utc = d.getTime() + (d.getTimezoneOffset() * 60000);
var db = new Date(utc + (3600000 * (APP.Configuracion.utc)));
var minutos = db.getMinutes();
if (minutos <= 9) { minutos = '0' + minutos; }
var hora = db.getHours();
if (hora <= 9) { hora = '0' + hora; }
var mes = db.getMonth() + 1;
if (mes <= 9) { mes = '0' + mes; }
var dia = db.getDate();
if (dia <= 9) { dia = '0' + dia; }
var segundo = db.getSeconds();
if (segundo <= 9) { segundo = '0' + segundo; }
var fechac = dia + '/' + mes + '/' + db.getFullYear() + ' ' + hora + ':' + minutos + ':' + segundo;
dia = null;
mes = null;
hora = null;
minutos = null;
segundo = null;
db = null;
utc = null;
d = null;
if (recolector.status() === true) {
if (APP.Configuracion.Repeticiones > 1) APP.RegistrarLog('8|LECTURA|Inicio Lectura');
APP.RegistrarLog('8|REGISTRO|🎛️ Estado: online (' + APP.Configuracion.RepeticionesConError + ')');
APP.RegistrarLog('8|REGISTRO|🎛️ Fecha: ' + fechac);
APP.RegistrarLog('8|REGISTRO|🎛️ Tiempo Recolección: ' + APP.Configuracion.TiempoContinuo);
APP.RegistrarLog('8|REGISTRO|🎛️ Cant. Lect. sin corte: ' + APP.Configuracion.Repeticiones);
//Se busca un registro usb (PROMESA - resultado(registro,cambios, true o false(si hay cambios))
recolector.Recolectar().then((resultado)=>
{
//APP.RegistrarLog(resultado[1]);
var datosRecolectados = resultado[0];
if ((APP.Configuracion.RepeticionesConError) > APP.Configuracion.Cantidad_No_Lectura) {
APP.RegistrarLog('0|CORE|⚠️ IMPORTANTE: No se puede leer la EMA por USB. Supero la Cantidad Máxima de No Lectura definida.');
APP.RegistrarLog('0|CORE|⚠️ IMPORTANTE: Supero la Cantidad Máxima de No Lectura definida.');
throw new Error('NolecturaUSB');
}
if (typeof datosRecolectados !== 'undefined')
{
// Estado Sensores
APP.Configuracion.EstadoSensores = datosRecolectados[17];
var Datos = [];
Datos = ['validar', datosRecolectados,resultado[1],resultado[2]];
// Se pasa el registro al validador
Validador.Registros(Datos, function (errorvalidador, estadovalidador)
{
if (estadovalidador === true) {
APP.Configuracion.Repeticiones += 1;
APP.Configuracion.RepeticionesConError = 0;
APP.Configuracion.TiempoMaximo = 0;
APP.Configuracion.TiempoFueraDeLinea = 0;
APP.Registro_Diario(Datos[1],resultado[1],resultado[2]);
APP.Publicar_en_Redes();
APP.Configuracion.FechaLanzadoTimeout = Date.now();
APP.Configuracion.IdsSetTimeouts.push(setTimeout(APP.Continuo, APP.Configuracion.TiempoContinuo * 1000));
Datos = null;
} else {
APP.Configuracion.Repeticiones = 0;
APP.Configuracion.Estado_Val_Ant = errorvalidador[0];
APP.RegistrarLog('0|VALIDADOR|⚠️ Datos recolectados incorrectos: ' + errorvalidador[1]);
APP.Configuracion.FechaLanzadoTimeout = Date.now();
APP.Configuracion.IdsSetTimeouts.push(setTimeout(APP.Continuo, APP.Configuracion.TiempoContinuo * 1000));
Datos = null;
}
});
Datos = null;
} else {
APP.RegistrarLog('0|CORE|⏳ Sincronizando.');
APP.Configuracion.Repeticiones = 0;
APP.Configuracion.RepeticionesConError = 0;
APP.Configuracion.IdsSetTimeouts.push(setTimeout(APP.Continuo, 1000));
}
});
} else {
APP.RegistrarLog('0|CORE|Estación no sincronizada.');
APP.Configuracion.Repeticiones = 0;
APP.Configuracion.IdsSetTimeouts.push(setTimeout(APP.Continuo, 5000));
}
} else {
APP.RegistrarLog('0|CORE|⏹️ Recolector detenido.');
APP.Configuracion.RunTime = 0;
}
} catch (ex) {
APP.RegistrarLog('0|EXCEP|💥 Información de la excepción: -> ' + ex + '');
APP.Configuracion.Errores = 'EXCEP: Información de la excepción: -> ' + ex;
var tiempo = (APP.Configuracion.TiempoMaximo + APP.Configuracion.TiempoContinuo) * 1000;
APP.Configuracion.TiempoFueraDeLinea += tiempo;
APP.RegistrarLog('0|EXCEP|💥 Se espera ' + (tiempo / 1000) + ' segundos y se prueba conectar nuevamente ....');
APP.Configuracion.IdsSetTimeouts.push(setTimeout(APP.Conectar, tiempo));
tiempo = null;
}
}
};
// termina el Objeto/Clase
// Control de Ejecucion de Consola
var parametros = process.argv; // Se lee el parametro
if (parametros.indexOf('console') === -1) {
// No se realiza nada ya que se tiene que iniciar desde el aplicativo
APP.RegistrarLog('0|CORE|⏳ Iniciando Ema Libre en Modo gráfico o Web.');
} else {
APP.Conectar();
APP.RegistrarLog('0|CORE|⏳ Iniciando Ema Libre en Modo Consola!!!.');
}