diff --git a/server.js b/server.js index a2c78c7..1baae3d 100644 --- a/server.js +++ b/server.js @@ -519,10 +519,8 @@ function evaluateAlarms(readings, outputChanges = []) { // 1. Output State Change Triggers if (trigger.outputChange && outputChanges.length > 0) { - // config: { target: "Dev:1", toState: "on" } - // or "Any" - const target = trigger.outputChange.target; // "Dev:1:out" or "any" - const curState = trigger.outputChange.state; // "on" or "off" + const target = trigger.outputChange.target; + const curState = trigger.outputChange.state; const match = outputChanges.find(c => { const k = `${c.devName}:${c.port}`; @@ -534,8 +532,8 @@ function evaluateAlarms(readings, outputChanges = []) { if (match) triggered = true; } - // 2. Sensor Triggers (Existing Logic) - let sensorDetails = []; // Track sensor values for logging + // 2. Sensor Triggers (with DB fallback for external sensors like CO2) + let sensorDetails = []; if (!triggered && trigger.sensors && trigger.sensors.length > 0) { const results = trigger.sensors.map(cond => { const sensorId = cond.sensor; @@ -544,24 +542,38 @@ function evaluateAlarms(readings, outputChanges = []) { const parts = sensorId.split(':'); const devName = parts[0]; + const portNum = parts.length > 1 ? parseInt(parts[1]) : null; const type = parts.length === 2 ? parts[1] : parts[2]; - const reading = readings.find(r => r.devName === devName); - if (!reading) { - sensorDetails.push({ sensor: sensorId, value: 'NO_READING', operator, threshold }); - return false; - } - let value = null; - if (type === 'temp') value = reading.temp_c; - if (type === 'humidity') value = reading.humidity; - if (type === 'level') { - const portNum = parseInt(parts[1]); + + // First try live readings from API + const reading = readings.find(r => r.devName === devName); + + if (type === 'temp' && reading) value = reading.temp_c; + if (type === 'humidity' && reading) value = reading.humidity; + if (type === 'level' && reading && portNum !== null) { const p = reading.ports.find(rp => rp.port === portNum); if (p) value = p.speak; } - // Track the sensor value for logging + // Fallback: Query database for recent readings (for external sensors like CO2) + if (value === null && portNum !== null) { + try { + const dbReading = db.prepare(` + SELECT level FROM readings + WHERE dev_name = ? AND port = ? + ORDER BY timestamp DESC LIMIT 1 + `).get(devName, portNum); + if (dbReading && dbReading.level !== null) { + value = dbReading.level; + } + } catch (e) { + console.error('DB fallback read error:', e); + } + } + + // Track sensor value for logging sensorDetails.push({ sensor: sensorId, value: value, operator, threshold }); if (value === null || value === undefined) return false; @@ -584,16 +596,15 @@ function evaluateAlarms(readings, outputChanges = []) { } if (triggered) { - // Build detailed sensor info string const sensorInfo = sensorDetails.map(s => - `${s.sensor}: ${s.value === null ? 'NULL' : s.value === 'NO_READING' ? 'NO_READING' : s.value} (${s.operator} ${s.threshold})` + `${s.sensor}: ${s.value === null ? 'NULL' : s.value} (${s.operator} ${s.threshold})` ).join(', '); console.log(`ALARM TRIGGERED: ${alarm.name} | Sensors: ${sensorInfo}`); alarmStates.set(alarm.id, Date.now()); const action = JSON.parse(alarm.action_data); const msg = `🚨 ALARM: ${alarm.name}\n\n${action.message || 'No message'}\n\nšŸ“Š Sensor Values:\n${sensorDetails.map(s => - `• ${s.sensor}: ${s.value === null ? 'NULL' : s.value === 'NO_READING' ? 'NO_READING' : s.value} (threshold: ${s.operator} ${s.threshold})` + `• ${s.sensor}: ${s.value === null ? 'NULL' : s.value} (threshold: ${s.operator} ${s.threshold})` ).join('\n')}`; sendTelegramNotification(msg); } diff --git a/src/client/LevelChart.js b/src/client/LevelChart.js index d2aef3d..137e785 100644 --- a/src/client/LevelChart.js +++ b/src/client/LevelChart.js @@ -56,7 +56,7 @@ export default function LevelChart({ data, isLight, isCO2, range }) { // CO2 needs different Y-axis scale (ppm range) const yScale = isCO2 - ? { suggestedMin: 400, suggestedMax: 2000 } + ? { suggestedMin: 200, suggestedMax: 900 } : { suggestedMin: 0, suggestedMax: 10, ticks: { stepSize: 1 } }; const options = {