// api/server.js const express = require('express'); const cors = require('cors'); const fs = require('fs/promises'); const path = require('path'); const { detectMode, executeEzoCommand } = require('./ezo-command-service'); const app = express(); const PORT = Number(process.env.PORT || 3000); const HISTORY_FILES = { temperature: 'timestamp,temperature\n', ph: 'timestamp,ph\n', do: 'timestamp,do\n', ec: 'timestamp,ec\n' }; const LOGS_DIRECTORY = process.env.LOGS_DIRECTORY ? path.resolve(process.env.LOGS_DIRECTORY) : path.join(__dirname, '..', 'logs'); app.use(cors()); app.use(express.json()); app.use('/frontend', express.static(path.join(__dirname, '..', 'frontend'))); app.use('/data', express.static(path.join(__dirname, '..', 'data'), { etag: false, maxAge: 0 })); app.use('/logs', express.static(LOGS_DIRECTORY, { etag: false, maxAge: 0 })); app.use('/config', express.static(path.join(__dirname, '..', 'config'), { etag: false, maxAge: 0 })); app.get('/', (req, res) => { res.redirect('/frontend/index.html'); }); app.get('/api/system/ezo', (req, res) => { const mode = detectMode(); res.json({ mode: mode.mode, message: mode.message }); }); // Función auxiliar para simular latencia const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms)); // Endpoint principal para obtener datos de los sensores (MOCK) app.get('/api/sensors/:type', async (req, res) => { const sensorType = req.params.type; console.log(`[GET] Petición recibida para sensor: ${sensorType}`); // Simulación de latencia I2C y procesamiento (400ms) await delay(400); const data = []; const now = new Date(); // Generamos 60 registros simulados for (let i = 60; i >= 0; i--) { const timestamp = new Date(now.getTime() - i * 1000).toISOString(); // Simulación de valores con ruido térmico/químico const mockValues = { rtd: (25.0 + (Math.random() * 0.1 - 0.05)).toFixed(2), ph: (7.2 + (Math.random() * 0.04 - 0.02)).toFixed(2), do: (8.5 + (Math.random() * 0.1 - 0.05)).toFixed(2), ec: (1050 + (Math.random() * 10 - 5)).toFixed(0) }; if (sensorType === 'all') { data.push({ Timestamp: timestamp, Temperatura_C: mockValues.rtd, pH: mockValues.ph, DO_mgL: mockValues.do, EC_uS: mockValues.ec }); } else if (mockValues[sensorType]) { data.push({ Timestamp: timestamp, Sensor: sensorType.toUpperCase(), Valor: mockValues[sensorType] }); } else { return res.status(400).json({ error: "Sensor no válido" }); } } res.json(data); }); // Consola EZO: usa I2C real en Raspberry Pi y modo demo en otros equipos. app.post('/api/sensors/:type/command', async (req, res) => { try { const result = await executeEzoCommand( req.params.type.toLowerCase(), req.body.command, { dangerousConfirmed: req.body.dangerousConfirmed === true } ); res.json(result); } catch (error) { res.status(error.status || 500).json({ success: false, error: error.message }); } }); // --- RUTAS DE GESTIÓN DE ALMACENAMIENTO --- // Variable global para simular la configuración de escritura del demonio C++ let loggingRateSeconds = 1; app.post('/api/config/logging', (req, res) => { const requestedRate = Number(req.body.rate); const allowedRates = new Set([1, 5, 10, 60]); if (!allowedRates.has(requestedRate)) { return res.status(400).json({ success: false, error: 'Frecuencia no válida' }); } loggingRateSeconds = requestedRate; console.log(`[SIMULACIÓN] Frecuencia configurada a: 1 registro cada ${loggingRateSeconds}s`); res.json({ success: true, simulated: true, rate: loggingRateSeconds, message: 'Configuración aplicada únicamente al backend simulado.' }); }); app.post('/api/history/clear', async (req, res) => { try { await Promise.all( Object.entries(HISTORY_FILES).map(([name, header]) => fs.writeFile(path.join(LOGS_DIRECTORY, `${name}.csv`), header, 'utf8') ) ); console.log('[SISTEMA] Archivos CSV históricos truncados.'); res.json({ success: true, message: 'Archivos de registro truncados correctamente.' }); } catch (error) { console.error('[ERROR] No se pudieron truncar los historiales:', error); res.status(500).json({ success: false, error: 'No se pudieron borrar los archivos históricos.' }); } }); if (require.main === module) { app.listen(PORT, () => { console.log(`[MOCK SERVER] Backend Node.js corriendo en http://localhost:${PORT}`); }); } module.exports = { app, HISTORY_FILES };