Door unlock on iPhone SOS when Apple won't expose the event
I wanted my front door to unlock automatically when my iPhone or Watch triggered Emergency SOS or Fall Detection. The catch is that Apple does not expose those events to Shortcuts, HealthKit, or any third-party API. There is no callback you can listen for. What Apple does do is send canned SMS messages to your emergency contacts. So the workaround uses that.
What was happening
The desired flow:
iPhone SOS / Fall Detection
→ Apple sends SMS to emergency contacts (canned body + location)
→ Home Assistant unlocks the front door for some time window
→ auto-relock after N minutes
The blocker: Apple emits SMS to a phone number, not a webhook. So one of the emergency contact phone numbers needs to be a number I control that can route the inbound SMS into Home Assistant.
What I found
The simplest path is a Twilio (or any SMS provider) inbound number set as an emergency contact in Health > Medical ID. The inbound webhook fires my self-hosted HTTP gateway, which checks the sender and body against a whitelist, hits a Home Assistant REST endpoint to unlock the lock, and starts an auto-relock timer.
The bits that matter:
- Sender whitelist. The webhook accepts inbound SMS only from the sender numbers I expect (mine, and the carrier forwarding number Apple uses if it forwards). Everything else drops at the door.
- Body whitelist. Apple's SOS SMS has a stable canned prefix. Match the prefix; refuse anything else. This protects against random texts to the same Twilio number firing the unlock.
- HMAC verification on the webhook itself. Twilio signs each POST. Validate before doing anything.
- Idempotency lock. Apple sometimes re-sends the SOS SMS as the situation continues. The handler holds a five-minute cooldown lock so a flurry of SMS doesn't spam-cycle the door.
- Auto-relock timer. Default 30 minutes. The door does not stay unlocked forever just because nobody got there in time.
Rough handler shape:
@app.post('/sos')
def sos(req: Request):
if not twilio_signature_valid(req):
return 403
sender = req.form['From']
body = req.form['Body']
if sender not in ALLOWED_SOS_SENDERS:
return 204
if not body.startswith(APPLE_SOS_PREFIX):
return 204
if cooldown.active('sos'):
return 204
cooldown.set('sos', 5 * 60)
ha.call('lock.unlock', entity_id=LOCK_ENTITY)
schedule(ha.call, RELOCK_AFTER, 'lock.lock', entity_id=LOCK_ENTITY)
return 204
A manual Watch complication can hit the same endpoint with a different shared secret (so I can test or trigger it without an actual SOS).
What I'd do differently
The whole approach is a workaround for an Apple limitation I can't fix. If Apple ever exposes the SOS event to Shortcuts I'd move to that immediately and rip out the SMS relay.
For now the SMS path works and has a useful side effect: I can verify the unlock pipeline by sending a test SMS that matches the whitelist, without having to actually trigger an SOS. That is much nicer than the alternative of squeezing my Watch crown for ten seconds in the kitchen.
If you're thinking of building something like this: lean heavily on the whitelist. The cost of a false unlock from a spam text is way higher than the cost of a missed unlock from a real SOS that got filtered. Fail closed.