← Lumen

Lumen Docs · April 2026

Physical Button Triggers

Bind any MQTT-published button to a Lumen CallKit ring. Press a €12 Sonoff SNZB-01 at your front door and your iPhone rings exactly like a real doorbell — with a live camera snapshot, no Reolink required.

What This Does

Lumen’s Physical Button Trigger feature connects any button that publishes to MQTT — a Sonoff SNZB-01 or any Zigbee button via Zigbee2MQTT, a Shelly button over Wi-Fi, a custom ESP32 board, or any Home Assistant input_button or event entity — to a CallKit incoming-call ring on your iPhone. When the button is pressed, Lumen’s relay receives the MQTT message, evaluates your match rule, and fires a VoIP push that iOS renders as a full-screen incoming call with a camera snapshot from Frigate.

The practical result: a €15 Zigbee button mounted next to your front door becomes a smart doorbell that rings your iPhone the moment a visitor presses it, showing you a live snapshot from your door camera. Physical button presses are a deliberate human action — so this feature is free for all Lumen users, with no Pro subscription required. Pro is only needed for AI auto-detection calls on more than one camera.

Lumen Physical Buttons settings screen showing Sonoff SNZB-01 doorbell binding

How It Works

The whole feature is a four-hop chain: your button publishes to MQTT, your relay reads it, Apple wakes your phone via VoIP push, and CallKit shows the incoming-call screen. The Lumen iOS app itself never connects to your MQTT broker directly — everything stays on your LAN except the final encrypted APNs hop.

  ┌──────────────────────────┐
  │  Button (Aqara, Sonoff,  │
  │  Shelly, ESP32, HA…)     │
  └────────────┬─────────────┘
               │ 1. publishes MQTT message on press
               ▼
  ┌──────────────────────────┐
  │  Your MQTT broker        │   (Mosquitto, HA add-on,
  │  (LAN-side)              │    EMQX — anything)
  └────────────┬─────────────┘
               │ 2. relay subscribes to all configured topics
               ▼
  ┌──────────────────────────┐
  │  Lumen relay             │   Self-hosted on your LAN
  │  (Docker / LXC / Mac)    │   or reachable via Tailscale.
  └────────────┬─────────────┘   Holds button configs +
               │                  per-device VoIP tokens.
               │ 3. match rule passes → fires VoIP push
               ▼
  ┌──────────────────────────┐
  │  Apple APNs              │   Encrypted Apple-side hop —
  │  (gateway.push.apple)    │   the only step off your LAN.
  └────────────┬─────────────┘
               │ 4. iOS wakes Lumen via PushKit
               ▼
  ┌──────────────────────────┐
  │  Lumen on iPhone         │   CallKit shows incoming
  │  CallKit incoming call   │   call with Frigate snapshot.
  └──────────────────────────┘

A couple of things worth pointing out about this design:

  • The iPhone never sees MQTT. All MQTT traffic stays between your button, your broker, and your relay — all of which live on your LAN. There’s no MQTT client on iOS, no broker credentials in the Lumen app, no exposed topics over the internet.
  • The relay is yours. You self-host it on Docker, an LXC container, a Raspberry Pi, or a Mac mini. LorisLabs does not run it for you. Your button configurations and HA entity names never leave your LAN — the relay stores them in a local JSON file.
  • Only the VoIP push leaves your LAN. When a button fires, the relay sends a short encrypted VoIP push through Apple Push Notification service so iOS can wake the app even when it’s killed. The push payload is tiny: camera name + button id, nothing else.
  • Frigate’s MQTT broker is fine to reuse. If you already run Frigate, its broker can host your buttons too — one less thing to configure. The relay just needs read access to it.

Prerequisites

  • Frigate NVR running with an MQTT broker accessible from the relay. The relay must be reachable from your iOS devices (local network or Tailscale).
  • Lumen for Frigate installed on your iPhone (free download — no Pro required for button bindings).
  • A button that publishes to MQTT — one of the following:
    • Sonoff SNZB-01 (or any Zigbee button) via Zigbee2MQTT
    • Shelly Button 1 or Plus i4 via the Shelly app MQTT config
    • Custom ESP32 / ESPHome firmware that publishes to a topic on press
    • Home Assistant input_button helper or event entity (the relay discovers these automatically via HA MQTT discovery)

Worked Setups

Three concrete examples, ordered from easiest to most hands-on. If you run Home Assistant, start with Setup 1 — it’s the recommended path for the vast majority of Lumen users and requires no MQTT topic hunting.

Setup 1 — Home Assistant (recommended for HA users)

If your button is already in Home Assistant — as a binary_sensor for a wall doorbell, an event entity for a Z2M / Z-Wave button, an input_button helper triggered by an automation, or a device_automation action — you do not need to find the topic by hand. The Lumen relay reads HA’s MQTT Discovery stream and lists every compatible entity in the app for you.

Why this is the smoothest path:

  • Auto-fill, no typing. Tap an entity in the Discover list and Lumen fills in the topic, match rule, and display name automatically.
  • Heterogeneous devices, one path. Whether the button is Zigbee (via Z2M / ZHA), Z-Wave, Matter, ESPHome, or a virtual input_button fired by an automation, HA exposes them all under the same Discovery format. Lumen sees them uniformly.
  • Personal info stays local. The HA entity friendly names (which often include room or person names) never leave your LAN — the discovery cache lives in the relay process.

Steps:

  1. Confirm HA’s MQTT integration is configured and pointing at your broker (Settings → Devices & Services → MQTT). The default topic prefix homeassistant works out of the box; if you customised it, set LUMEN_HA_DISCOVERY_PREFIX on the relay to match.
  2. Make sure the button you want to use is actually exposed to MQTT Discovery. For Z2M buttons this is automatic when MQTT integration is enabled. For an input_button helper, make sure it’s referenced by at least one HA automation that publishes its press — HA only emits Discovery for entities reachable through MQTT.
  3. In Lumen: Settings → Doorbell & Calls → Physical Buttons → Add Button. The editor opens on the Discover tab.
  4. Tap your entity in the list. Topic, JSONPath, and match rule auto-fill from HA’s discovery payload (e.g. an Aqara button comes pre-filled with $.action · equals single).
  5. Pick the cameras you want the call to ring. Tap Send test push to verify the CallKit ring before saving.

The Discover tab also surfaces buttons that aren’t doorbell-shaped — any action-emitting entity is fair game. Useful if you want a Lutron pico or an ESPHome custom switch to ring you when triggered.

Compatible buttons most users already own — all work via the HA Discover path:

  • Aqara WXKG11LM / WXKG13LM via Z2M or HA Zigbee integration
  • IKEA Trådfri shortcut button via Z2M
  • Sonoff SNZB-01 / SNZB-01P via Z2M
  • Hue dimmer / smart button via the Hue HA integration
  • Any virtual input_button helper triggered by an HA automation (motion sensor, NFC tag, etc.)

Setup 2 — Sonoff SNZB-01 via Zigbee2MQTT (without HA)

If you run Z2M without Home Assistant, pair the Sonoff SNZB-01 to your Zigbee2MQTT coordinator. Z2M publishes action events to zigbee2mqtt/<device_friendly_name>/action as a JSON payload (e.g. {"action":"single"}, {"action":"double"}, {"action":"long"}). In Lumen, open Settings → Doorbell & Calls → Physical Buttons → Add Button, switch to Manual, and enter:

  • Topic: zigbee2mqtt/sonoff_button/action (use your device’s friendly name from Z2M)
  • JSONPath: $.action
  • Match rule: Equals — single
  • Cameras to ring: select your front door camera (and any others)

Tap Send test push to verify the CallKit ring fires before saving. A single press now rings your iPhone; double-press and long-press are ignored unless you add separate bindings for them.

Sonoff SNZB-01 — typically around €10–14, no hub required when used with a Z2M USB dongle:

Amazon US Amazon UK Amazon FR

Search Amazon for “Sonoff SNZB-01” (sometimes listed as “Sonoff Zigbee Wireless Switch”). The newer SNZB-01P is identical for our purposes. Aqara’s WXKG11LM/WXKG13LM works the same way if you already own one — same {"action": ...} payload via Z2M.

Setup 3 — Shelly Button via Shelly App (no HA, no Z2M)

If you don’t run HA or Z2M, the Shelly Button is the path of least resistance: Wi-Fi, no hub, configures over the manufacturer app. Enable MQTT in the Shelly app under Internet & Security → MQTT. The Shelly Button 1 publishes to shellies/shellybutton1-<device_id>/input_event/0 as a JSON payload like {"event":"S","event_cnt":1}, where S means single press. In Lumen, use Manual mode with:

  • Topic: shellies/shellybutton1-XXXXXX/input_event/0 (replace XXXXXX with your Shelly’s device ID from the Shelly app)
  • JSONPath: $.event
  • Match rule: Equals — S
  • Cameras to ring: your door camera(s)

Shelly Button 1 — Wi-Fi, no hub, works over your existing MQTT broker:

Amazon US Amazon UK Amazon FR

Discover vs Manual

Use Discover when your button is a Home Assistant entity. The relay caches HA MQTT discovery messages from the moment it starts, so all your HA buttons, binary sensors, and device automations appear in the picker instantly. Tapping an entity auto-fills every field with the best guess for topic and match rule based on the entity’s component type.

Use Manual for any button that publishes to MQTT directly — Z2M devices, Shelly, ESPHome, or anything not registered with Home Assistant. You supply the topic and match rule yourself. If you’re unsure of the exact topic, use an MQTT client like MQTT Explorer on your Mac or phone to observe traffic while pressing the button.

Match Rules Explained

Each binding has a Match rule that controls which messages on the topic actually trigger a ring. There are three modes:

Any message
Fires on every message received on the topic, regardless of payload content. Use this for buttons that only publish on press (no release message) or where you don’t care about the payload value. Example: Shelly Plus i4 channel configured for single-press events only.
Equals value
Fires only when the payload (or the JSONPath-extracted field) exactly matches a string you specify. Example: Sonoff SNZB-01 Z2M action topic with single — long-press and double-press are ignored. For JSON payloads, set the JSONPath field to the path of the value you want to match (e.g. $.action or $.event).
Regex
Fires when the payload (or JSONPath-extracted field) matches a regular expression. Example: ESPHome firmware that publishes different press types as press_short, press_double, etc. — use ^press_short$ to match only the short press. Regex patterns are validated on-device before save; invalid patterns and patterns over 256 characters are rejected with an error message.

JSONPath subset

The JSONPath field supports a simple subset sufficient for most MQTT payloads: $.field, $.parent.child, and $.array[0]. Wildcards and filter expressions ([?()]) are not supported. If you need to match against the full raw payload string, leave the JSONPath field empty.

Multi-Camera Ring

A single button binding can ring multiple cameras simultaneously. In the binding editor, toggle on every camera you want to ring when the button is pressed. When triggered, Lumen fires a separate CallKit push for each selected camera — your phone groups them into a single incoming-call notification showing the camera names. This is useful for an entrance button that you want to associate with both a front-door camera and a porch camera at the same time.

Troubleshooting

⚠️ “Topic not seen recently” warning on a binding
The relay’s discovery cache has not seen any message on this topic since the relay started. Check that the button’s MQTT broker matches the one Frigate uses, and press the button once — the warning clears after the first message is received.
No entities appear in the Discover tab
The relay subscribes to homeassistant/+/+/config at startup. If you use a non-default HA MQTT discovery prefix, set the LUMEN_HA_DISCOVERY_PREFIX environment variable on the relay to match. Retained discovery messages republish on subscribe, so a relay restart picks them up automatically.
Regex rejected at save
Lumen validates regex patterns on-device using NSRegularExpression. Patterns over 256 characters are rejected unconditionally. Simplify the pattern or switch to an Equals rule if possible.
Button press fires no ring
Verify the topic is subscribed (check relay logs), the match rule evaluates to true for the actual payload (use MQTT Explorer to inspect the live message), and the binding is enabled (toggle in the list). Also confirm the camera selected in the binding has a valid VoIP token registered with the relay.

Privacy

Button bindings and the HA discovery cache are entirely LAN-side. The relay stores binding configurations in a local JSON file and subscribes to your MQTT broker over your private network — no button event data, entity names, or topic names are sent to any LorisLabs server or third-party cloud. The GET /auto-call/discover endpoint is only reachable on your local network or Tailscale, same as the existing Frigate API. Home Assistant entity names (which can include personal information like room names) never leave your local relay process.

This page contains affiliate links. If you buy through them, we earn a small commission at no extra cost to you.