Sensor Offline alerts while traveling, twice
A safety app I run pinged me every hour with "Sensor Offline — no data from IFTTT in the last 24 hours" while I was on a trip. That sensor is the motion detector at home. Of course it's quiet — I'm not home. Took two fix passes to actually shut up.
What was happening
The cron that watches "expected sources" (IFTTT, smart-home hubs, etc.) was flagging the home motion source silent. The dedupe key was hourly, so a new alert was created every hour for the same ongoing condition.
Real cause: there was no away-from-home check at all. If you leave the house, all the home-tied passive sources go quiet by design. The cron didn't know that.
What I found
Pass one (2026-04-18):
- The dedupe key was
source_health_alert_*_{hour}. New hour, new key, new alert. Fixed by changing the key to a sorted signature of the silent source set with a 24-hour TTL — one alert per outage, not one per hour. - Added
getUserHomeStatus()that returnshome/away/unknownbased on the user's most recent activity with lat/lon, cross-checked against their home geofence. - Home-tied sources (
ifttt,smarthome,hue,wyze) are filtered out of the silent-source set when status isaway.
Smoke-tested, deployed, looked clean. Then woke up the next morning and got "Sensor Offline" again.
Pass two (2026-04-19):
The suppression was conditional on status === 'away'. But after
an overnight gap of >4 hours, the last GPS fix was stale enough
that getUserHomeStatus returned 'unknown' (with a reason of
location_stale). The check bypassed the suppression and the
alert fired again.
There was also a separate latent issue — my home geofence in the DB had been left at a default (a Manhattan lat/lon, not my actual home). So even with fresh GPS, "home" would never match. The stale case is what slipped through, but the geofence default needed fixing too.
The fix
One line change in the condition:
// before
if ($homeStatus['status'] === 'away') {
$silentSources = array_diff($silentSources, HOME_TIED_SOURCES);
}
// after
if ($homeStatus['status'] !== 'home') {
$silentSources = array_diff($silentSources, HOME_TIED_SOURCES);
}
Home-tied sources are now suppressed whenever we're not certain the user is home. Hard safety alerts (SOS, deadman switch, real inactivity threshold) ride a different code path, so failing closed on Sensor Offline doesn't mask anything actually dangerous.
Also bumped the log line to include the unknown reason so the
next time I'm reading CloudWatch I can tell at a glance whether
suppression was based on away vs location_stale.
Deployed by patching the file directly into the existing Lambda
zip and pushing via aws lambda update-function-code — no full
serverless deploy needed for a one-file change.
What I'd do differently
When you have a tri-state (home / away / unknown), default to the
safe behavior on unknown. The original code defaulted to
"suppression off" on unknown, which is the less safe behavior
for a Sensor Offline alert — you want fewer false pages, not
more.
Also: when something is "fixed" after pass one but reproduces the
next morning, the pass-one fix didn't cover the case. Don't mark
it shipped, mark it shipped-for-the-condition-I-saw. The
overnight stale-GPS path was identical from the suppression code's
perspective but different from getUserHomeStatus's.