如何用Node.js实现设备温度越限仅触发一次告警通知?
Got it, let's fix this duplicate alert issue! The core problem here is your current code sends a notification every time it gets an out-of-range temperature reading, with no memory of whether we already alerted for that same state. We need to add a simple state tracker to only trigger alerts when the temperature status changes.
First, let's break down the solution: we'll track the last alert state so we know when to send a new notification, and when to skip duplicates.
Step 1: Add a Persistent State Tracker
Declare a variable outside your MQTT message handler to store the last alert status. This needs to persist across multiple temperature readings, so don't define it inside the function that processes incoming data.
// Tracks the last alert state: 'normal', 'high_temp', 'low_temp' let lastAlertState = 'normal';
If you're monitoring multiple devices (different MQTT topics), use an object to track state per device instead:
// Track state for each individual device const deviceAlertStates = {}; // Initialize state when a new device is first detected if (!deviceAlertStates[topic]) { deviceAlertStates[topic] = 'normal'; }
Step 2: Revised Alert Logic with State Checks
Update your code to only send alerts if the current temperature status doesn't match the last one. Here's the full revised code:
// Inside your MQTT message handler function const currentTemp = parseFloat(temperature); // Ensure temperature is a number // For single device tracking if (currentTemp > 25) { // Only send alert if we haven't already alerted for high temp if (lastAlertState !== 'high_temp') { const mailOptions = { from: 'sender@gmail.com', to: 'receiver@tssb.com.my', subject: '⚠️ Temperature Alert: High Threshold Exceeded', text: `Device with topic ${topic} reports a temperature of ${currentTemp}°C, which is above the 25°C threshold.` }; transporter.sendMail(mailOptions, (error, info) => { if (error) { console.error('High temp email failed:', error); } else { console.log('High temp alert sent:', info.response); // Update state after successful alert lastAlertState = 'high_temp'; } }); } } else if (currentTemp < 19) { // Only send alert if we haven't already alerted for low temp if (lastAlertState !== 'low_temp') { // Send email alert const mailOptions = { from: 'sender@gmail.com', to: 'receiver@tssb.com.my', subject: '⚠️ Temperature Alert: Low Threshold Exceeded', text: `Device with topic ${topic} reports a temperature of ${currentTemp}°C, which is below the 19°C threshold.` }; transporter.sendMail(mailOptions, (error, info) => { if (error) { console.error('Low temp email failed:', error); } else { console.log('Low temp email sent:', info.response); } }); // Send SMS alert const from = 'Nexmo'; const to = 'phone number'; const smsText = `Alert: Device ${topic} temp is ${currentTemp}°C (below 19°C threshold)`; nexmo.message.sendSms(from, to, smsText, (error, response) => { if (error) { console.error('Low temp SMS failed:', error); } else if (response.messages[0].status !== '0') { console.error('Nexmo error:', response); } else { console.log('Low temp SMS sent:', response); // Update state after successful SMS lastAlertState = 'low_temp'; } }); } } else { // Temperature is back to normal, reset the alert state if (lastAlertState !== 'normal') { lastAlertState = 'normal'; console.log(`Device ${topic} temp returned to normal (${currentTemp}°C), alert state reset.`); } }
Key Improvements Explained
- State Validation: We only trigger alerts when the current temperature condition differs from the last alert state, preventing duplicates.
- Descriptive Messages: Updated email subjects and text to be more actionable and clear.
- Error Handling: Added more specific error logging to make debugging easier.
- Normal State Reset: When temperature returns to the 19-25°C range, we reset the state so future out-of-range readings will trigger alerts again.
For multiple devices, replace lastAlertState with deviceAlertStates[topic] in all checks and updates.
内容的提问来源于stack exchange,提问作者johnhour

