Our LoRaWAN node went quiet for seven days. Here's why.
A battery-powered temperature node had sent 25 uplinks, then stopped. The battery was fine: a multimeter read 3.83 V. The node simply never spoke again until it was reset a week later.
This is a write-up of what we found. The node is a trial unit running in an operational plant room, not a product. The case study covers the build; this post goes into the debugging.
What happened
The node is built around a RAK3172 module (STM32WL) running RUI3 4.2.4. On 10 October, after 25 uplinks, the data stopped. Nothing arrived for seven days, until a manual reset on 17 October.
The battery was healthy, so this was not a flat cell. The node was not transmitting and failing; it had stopped altogether.
How we found where it stopped
The firmware writes progress markers into the chip's backup registers at key stages of the main loop. Backup registers survive a reset, so after the node was restarted we could read the markers back over ST-Link and see how far the loop had got.
The last marker written was the one just before the chip enters its deepest sleep mode (Stop2). The marker for waking up was never written.
SLEEP_ENTER <- last marker written
SLEEP_EXIT (never written)
The node went to sleep and did not wake up. That is a much narrower problem than "it stopped sending".
We should be straightforward about the limit of this finding. The markers tell us where the hang happened, not which defect in the vendor's sleep and timer code caused it. We have not proved that, so we did not fix it with one patch.
Why nothing recovered it
There was no independent watchdog. A hang in sleep is exactly the case a watchdog exists for: a timer that runs separately from the main firmware and resets the chip if nobody feeds it. Without one, the only way out of the hang was a manual reset.
A second problem: the join back-off
On 17 October we reset the node with its reset pin. The gateway was off at that point. When the gateway came back, the node still sent nothing for about 13 minutes, because its join duty-cycle back-off had run out and it was no longer retrying.
A further reset, this time over SWD, made it send a join request within 5 seconds, and uplinks resumed.
The stale battery reading
The node reads its battery voltage from an STC3100 fuel gauge. We compared its reported voltage with a multimeter. The node said 3.91 V. The meter said 3.83 V.
The gauge had returned a stale register value. Reading it after a 5-second settle gave 3.862 V.
What we changed
Because the root cause is unproven, we added several independent protections:
- Independent watchdog, 32 seconds. If the firmware stops feeding it, the chip is reset.
- Sleep capped at 20 seconds. Healthy firmware wakes well inside the 32-second watchdog window. If it does not, the watchdog resets the node.
- Join back-off from 30 seconds to 1 hour, then 4 hours after 11 hours. A node that loses its gateway retries often at first, then more slowly if the outage is long.
- A 5-second settle delay before the fuel-gauge read.
- Two patches to the vendor sleep and timer code.
With no proven cause to fix, the aim is to make another week-long silence less likely, whatever caused it.
Verification
We forced a hang on purpose. The watchdog triggered a reset, and the node rejoined the network on its own, with nobody touching it. That is the behaviour that was missing on 10 October.
What we would take into any battery-powered design
These are habits we would carry to other projects, not rules from a single node:
- Put an independent watchdog in from the first firmware build, not after the first field failure.
- Keep progress markers somewhere that survives a reset, so a hang can be read back afterwards rather than guessed at.
- Cap every sleep and every back-off, and think about what happens when the gateway or network is away for hours.
- Check a sensor reading against a meter at least once, because a plausible number can still be wrong.