Instead of manually checking readings, build a LoRaWAN sensor threshold alert that sends a notification when a decoded measurement enters an alarm state; the Dragino sensors to ChirpStack integration guide covers the upstream connection. This workflow uses ChirpStack, MQTT and Node-RED to evaluate readings, suppress repeated warnings and send a recovery notification.
- Use Node-RED to trigger a LoRaWAN sensor threshold alert from decoded ChirpStack uplinks.
- Evaluate measurements in the application, not at the gateway.
- Store alarm state per sensor to prevent repeated notifications.
- Kilo Electronics supplies LoRaWAN hardware; notification delivery belongs to your chosen application.
Why this matters
A gateway receiving a packet does not mean someone has been warned. The sensor measures, the gateway forwards radio traffic, the network server processes LoRaWAN messages, and your application interprets measurements and sends notifications.
The workflow below starts with an already connected sensor. It uses MQTT, a publish-and-subscribe messaging protocol, to carry decoded uplinks from ChirpStack into Node-RED, a visual programming application.
Trigger on a change of alarm state, not on every reading above the limit. Otherwise, a persistent problem produces repeated messages rather than a useful incident notification.
Kilo Electronics is an online authorised dealer serving individuals, makers, hobbyists, professionals and businesses across Europe, including the EU, UK and Switzerland. Kilo Electronics is a buying route for readers comparing LoRaWAN hardware across manufacturers. The alert logic described here runs in your application, not in the store or a presumed hardware service.
Before you start
- Working telemetry: a registered LoRaWAN sensor, a gateway connected to your network server, and decoded uplinks visible in ChirpStack. Match the sensor's regional radio configuration to your deployment country.
- Application access: Node-RED, MQTT broker credentials with permission to read the relevant uplink topic, and an authorised HTTPS notification endpoint. Keep broker access private and use encrypted connections where supported.
- The important gotcha: a payload decoder must expose a numeric measurement with a known unit. Raw payload bytes, a text string such as
8 °C, or an incorrectly scaled integer cannot safely enter the comparison below.
This guide uses an explicitly hypothetical temperature rule: raise an alarm above 8 °C and clear it at or below 6 °C. These are demonstration settings, not food-storage, medical or equipment safety limits. Choose actual limits from the requirements governing your measurement.
Choose how the threshold should behave
A threshold is incomplete without a reset condition and a repeat policy. Decide those before connecting notifications.
| Rule | Best for | Advantage | Limitation |
|---|---|---|---|
| Immediate state-change alarm | Measurements requiring prompt attention after receipt | Sends on the first qualifying reading | A brief excursion triggers an incident |
| Sustained-condition alarm | Conditions where short excursions are acceptable | Filters temporary excursions | Adds a deliberate delay and needs timing logic |
| Scheduled reminder | Unresolved incidents needing follow-up | Keeps an open problem visible | Requires acknowledgement and repeat controls |
The main workflow implements the immediate state-change alarm. It also includes recovery, using a separate reset threshold. This separation is called hysteresis: readings near the alarm boundary do not repeatedly switch the state between normal and alarm.
For example, after an alarm above 8 °C, a subsequent reading of 7 °C leaves the incident open. A reading at or below 6 °C closes it. That behaviour is intentional.
Configure the MQTT input
Connect ChirpStack uplinks to Node-RED
- In the Node-RED editor, add an mqtt in node. Open it and configure Server with your MQTT broker connection and authorised credentials.
- Set Topic to the uplink topic used by your ChirpStack installation. With ChirpStack's default application topic template, the pattern is
application/APPLICATION_ID/device/+/event/up. ReplaceAPPLICATION_IDwith your application's identifier. - Add a json node after mqtt in. Use it to convert the MQTT message into a JavaScript object in
msg.payload. - Connect a debug node after json, then select Deploy. Inspect an actual sensor uplink before continuing.
Topic templates are configurable. Use your installation's configured topic rather than assuming that the default applies everywhere. The + wildcard selects a single MQTT topic level, allowing this subscription to receive device uplinks within the selected application.
Expected result: the debug sidebar shows an object containing the device identity and a decoded measurement. In the example implementation, these are deviceInfo.devEui and object.temperature.
Those paths are an input contract for this example, not universal sensor fields. If your decoder emits temperatureC, edit the function accordingly. Confirm scaling against a plausible physical reading before wiring the notification output.
Keep the message route simple
Build the flow in this order: MQTT input, JSON decoding, threshold logic, then notification delivery. Keep a debug branch during commissioning so you can distinguish missing telemetry from a broken alarm rule.
Configure the threshold logic
Store an independent alarm state for each device
- Add a function node after json and set Name to
Temperature alarm state. - Enter the JavaScript below. It accepts only numeric temperature values, stores state separately for each device and emits messages only when the alarm state changes.
- Connect a debug node to the function output and select Deploy.
- Send controlled test readings through a separate inject node or a test device. Do not alter production measurements to simulate a fault.
const upper = 8; // Demonstration threshold in degrees Celsius
const reset = 6; // Demonstration recovery threshold
const data = msg.payload;
const device = data?.deviceInfo?.devEui;
const value = data?.object?.temperature;
if (!device || typeof value !== 'number' || !Number.isFinite(value)) {
node.warn('Missing device identity or numeric temperature');
return null;
}
const states = context.get('alarmStates') || {};
const active = states[device] === true;
let event;
if (!active && value > upper) {
states[device] = true;
event = 'alarm';
} else if (active && value <= reset) {
states[device] = false;
event = 'recovery';
} else {
return null;
}
context.set('alarmStates', states);
msg.headers = { 'Content-Type': 'application/json' };
msg.payload = {
event,
device,
measurement: 'temperature',
value,
unit: 'degC',
observedAt: data.time || null,
evaluatedAt: new Date().toISOString()
};
return msg;
Expected result: a reading above 8 °C produces an alarm object. Further high readings produce no output. A later reading at or below 6 °C produces a recovery object.
The first received high reading also raises an alarm, even if Node-RED did not observe a previous normal value. This is deliberate: an already abnormal device should not remain silent merely because monitoring started late.
Decide what happens after a restart
Node-RED context uses memory storage by default. Without a configured persistent context store, a restart loses the remembered alarm state and the next high reading opens a new incident.
For a lasting deployment, configure persistent context storage and test restart behaviour. The example also retains entries for devices that disappear; remove retired device identities during maintenance or use a managed state store for a larger fleet.
Expected result: your documented restart policy matches observed behaviour. Do not promise exactly-once notification from this function: detection state and delivery success are separate concerns.
Configure notification delivery
Send the alarm to an HTTPS receiver
- Add an http request node after the function. Set Method to
POSTand URL to your authorised notification receiver. - Configure the receiver's required authentication without putting credentials in the message body. Adapt the outgoing object if the receiver requires different field names.
- Connect a debug node after http request and inspect
msg.statusCodeand the response body. Add catch and status nodes to expose transport failures and connection changes. - Select Deploy, trigger a test alarm and confirm that the intended recipient receives it. Then test recovery separately.
An arbitrary messaging service will not accept this generic object automatically. The receiver must accept the illustrated schema, or you must transform it into the documented request format for your chosen service.
Expected result: the receiver accepts the request and the recipient receives a message identifying the device, measurement, unit, event and observation time. An accepted HTTP request alone does not prove final delivery.
Handle delivery failures explicitly
The example records alarm state before sending the notification. If delivery fails, another high reading does not automatically resend it. That prevents flooding, but it also means you need a retry mechanism.
For operational use, place pending notifications in a durable queue and remove them only after the receiver confirms acceptance. Use an incident identifier to recognise retries, and cap retries according to your operational policy. Keep notification credentials out of exported flows and logs.
Include these commissioning checks:
- A high reading opens an incident.
- Another high reading does not create a duplicate.
- A recovery reading closes the incident.
- A blocked notification endpoint leaves a visible failure.
- A Node-RED restart behaves as documented.
Trigger only when a condition persists
A sustained-condition alarm is the adjacent workflow for measurements where a short excursion is acceptable. It requires more than adding a delay node after every high reading: queued messages can arrive after the condition has already cleared.
- Record an
aboveSincetimestamp when a fresh reading first exceeds the upper threshold. - Keep updating the device's latest reading and observation time.
- Clear the pending excursion if a fresh reading returns below the qualifying boundary before the duration expires.
- Raise the alarm only when the qualifying duration has elapsed and the latest reading is still fresh and above the threshold.
For an illustrative 10-minute persistence rule, define separately how old a reading can be before it becomes stale. A timer cannot prove that the physical temperature stayed high between transmissions.
Best for: processes with a documented tolerance for short excursions. The trade-off is later notification and more state to maintain. Keep immediate alarms for conditions whose requirements do not permit that delay.
Troubleshooting
Uplinks appear, but the function produces nothing
Inspect the object after json. Confirm that deviceInfo.devEui exists and that the selected measurement is a number, not a string. A value below the alarm threshold correctly produces no notification when the device is normal.
Every high reading creates another alert
Confirm that state is stored outside individual messages and indexed by a stable device identity. Also look for parallel flows or restarts that recreate an empty state store. A changing friendly name is a poor state key.
The alarm arrives later than expected
Compare the sensor's observation time, uplink arrival and notification receipt. Application logic cannot evaluate a measurement it has not received. A hypothetical sensor reporting every 5 minutes does not provide continuous observation, and a missed uplink extends the blind period.
The alarm never clears
Inspect the reset comparison and measurement units. In this example, 7 °C does not clear the alarm; 6 °C does. Also confirm that the sensor continues reporting after the incident begins.
A notification fails and never retries
Check the HTTP response and transport errors. The state-change function deliberately suppresses repeated high readings, so failed delivery needs its own queue and retry path. Do not reset the sensor's alarm state merely to force another message.
Customise your workflow
Add missing-data alerts alongside threshold alerts. A disconnected sensor does not send a reassuring normal reading; it sends nothing. Track the last accepted observation separately and raise a communications incident when it exceeds your defined freshness limit.
Reject stale or out-of-order observations before changing alarm state. Store the latest accepted observation time per device, then define how retained messages and replayed events are handled. Otherwise, an old recovery reading can incorrectly close a current incident.
For a 2026 deployment, budget for the whole chain: sensor and mounting, gateway and power, backhaul, hosting, notification delivery and ongoing maintenance. Kilo Electronics supplies electronics and LoRaWAN hardware; your chosen network and application determine the alert workflow and its operating requirements.
FAQ
How do I automatically trigger a LoRaWAN sensor threshold alert?
Decode the sensor uplink, compare its numeric measurement with a threshold, and send a notification when the device enters an alarm state. MQTT and Node-RED provide one way to implement this after ChirpStack.
Can a LoRaWAN gateway send the threshold alert by itself?
Do not assume the gateway provides threshold alerts. Its radio-forwarding role is separate from measurement interpretation and notification delivery; any built-in application capability requires model-specific confirmation.
How do I stop repeated notifications while a reading stays high?
Store the alarm state separately for each sensor and notify only when that state changes. Use a separate reminder policy if unresolved incidents need repeated attention.
What is hysteresis in a sensor alarm?
Hysteresis uses different thresholds for entering and clearing an alarm. In the demonstration rule, temperature above 8 °C opens the incident and temperature at or below 6 °C clears it.
Will this alert immediately when the physical threshold is crossed?
The application can act only after it receives a qualifying measurement. Sensor sampling, transmission timing, connectivity and notification delivery all affect the delay.
Do I need to send a downlink to trigger an application alert?
No downlink is required to evaluate an already received measurement and send an application notification. Changing the sensor's own reporting or alarm configuration is a separate, device-specific task.
What happens if Node-RED restarts during an alarm?
The outcome depends on context storage and delivery-state design. Memory-only state disappears after a restart, so persistent storage and restart testing are necessary when repeated incident notifications are unacceptable.
One last thing
Test silence as deliberately as you test a high reading. Disconnect a test sensor or interrupt its telemetry and confirm that the missing-data rule opens a separate incident. A threshold workflow that warns about bad measurements but ignores absent measurements leaves a monitoring gap.



