|
| 1 | +--- |
| 2 | +title: Noonlight |
| 3 | +description: Instructions on setting up the Noonlight emergency-dispatch integration. |
| 4 | +ha_category: |
| 5 | + - Alarm |
| 6 | +ha_release: "2026.7" |
| 7 | +ha_iot_class: Cloud Polling |
| 8 | +ha_config_flow: true |
| 9 | +ha_codeowners: |
| 10 | + - '@brentb2529' |
| 11 | +ha_domain: noonlight |
| 12 | +ha_integration_type: service |
| 13 | +ha_platforms: |
| 14 | + - binary_sensor |
| 15 | + - sensor |
| 16 | +--- |
| 17 | + |
| 18 | +The **Noonlight** {% term integration %} connects Home Assistant to [Noonlight](https://www.noonlight.com)'s emergency-services dispatch API, so your automations can request a real **police**, **fire**, or **medical** response. It pairs naturally with any `alarm_control_panel` entity but is not tied to a specific alarm integration. |
| 19 | + |
| 20 | +{% important %} |
| 21 | +This integration can summon **real emergency responders** to your address. A dispatch sent to the production environment can result in police, fire, or medical personnel being sent to your home, and false dispatches may incur fines from your local authorities. |
| 22 | + |
| 23 | +Always test your automations against the **sandbox** environment first — it never alerts real responders. Selecting the production environment requires that you explicitly acknowledge a safety disclosure during setup. |
| 24 | +{% endimportant %} |
| 25 | + |
| 26 | +## Prerequisites |
| 27 | + |
| 28 | +- A [Noonlight](https://www.noonlight.com) account. |
| 29 | +- An API token from your Noonlight account portal. Use a long-lived token; it is stored by Home Assistant and used for every dispatch. |
| 30 | +- A decision about which **environment** to target: |
| 31 | + - **Sandbox** — Noonlight's testing instance. Safe to experiment with; it never alerts real responders. Recommended while you build and test automations. |
| 32 | + - **Production** — reaches real responders. Requires the safety acknowledgment during setup. |
| 33 | + - **Custom** — point at your own base URL (advanced). |
| 34 | + |
| 35 | +{% include integrations/config_flow.md %} |
| 36 | + |
| 37 | +The setup flow collects the credentials and the caller details that are sent to Noonlight on every dispatch: |
| 38 | + |
| 39 | +{% configuration_basic %} |
| 40 | +API token: |
| 41 | + description: "Your Noonlight API token from your Noonlight account portal. It is stored by Home Assistant and used for every dispatch, so use a long-lived token." |
| 42 | +Environment: |
| 43 | + description: "Which Noonlight environment to target: **Sandbox** (testing; never alerts real responders), **Production** (reaches real responders), or **Custom** (a base URL you provide). Your credentials are validated against the chosen environment before you continue." |
| 44 | +Base URL: |
| 45 | + description: "Only for the *custom* environment: the base URL of the Noonlight API to use." |
| 46 | +Name: |
| 47 | + description: "The caller name sent to responders." |
| 48 | +Phone: |
| 49 | + description: "The caller phone number. It is validated and normalized to E.164 during setup (for example, `(202) 555-0142` becomes `+12025550142`) so a malformed value is caught now instead of during an emergency." |
| 50 | +Address, city, state, and ZIP: |
| 51 | + description: "The dispatch location sent to responders. The state and ZIP are validated during setup (for example, `va` becomes `VA`)." |
| 52 | +Site / location label: |
| 53 | + description: "Optional label for this property, used when you protect more than one site (see [Multiple properties](#multiple-properties))." |
| 54 | +Default entry delay: |
| 55 | + description: "Grace window (0–120 seconds, default 30) before a dispatch fires, during which it can be canceled." |
| 56 | +De-dup window: |
| 57 | + description: "Window (default 300 seconds) during which repeat dispatches for the same service are suppressed." |
| 58 | +Granted services: |
| 59 | + description: "Which dispatch services (police, fire, or medical) this site is allowed to request." |
| 60 | +{% endconfiguration_basic %} |
| 61 | + |
| 62 | +When you select the production environment, a final **safety acknowledgment** step requires you to confirm that you understand the integration can summon real responders — and that false dispatches may incur fines — before the entry is created. |
| 63 | + |
| 64 | +## Entities |
| 65 | + |
| 66 | +Each configured site (config entry) exposes the following entities. Entity IDs include the site's slug, shown below as `<site>`. |
| 67 | + |
| 68 | +| Entity | Type | Description | |
| 69 | +| ------ | ---- | ----------- | |
| 70 | +| `binary_sensor.noonlight_<site>_dispatch_pending` | Binary sensor | `on` during the cancelable entry-delay grace window. Use it to drive a CANCEL button in your dashboard. | |
| 71 | +| `binary_sensor.noonlight_<site>_dispatch_active` | Binary sensor (safety) | `on` while a dispatch is live with Noonlight (responders requested). | |
| 72 | +| `binary_sensor.noonlight_<site>_api_reachable` | Binary sensor (connectivity, diagnostic) | `on` while the [heartbeat](#heartbeat) confirms Noonlight is reachable and your token is valid. | |
| 73 | +| `sensor.noonlight_<site>_dispatch_state` | Sensor (enum) | The single source of truth for dispatch state: `idle`, `pending`, `dispatched`, `canceled`, or `error`. | |
| 74 | +| `sensor.noonlight_<site>_last_event` | Sensor (timestamp) | When the most recent state transition occurred; the event type is exposed as an attribute. | |
| 75 | +| `sensor.noonlight_<site>_last_health_check` | Sensor (timestamp, diagnostic) | When the last successful heartbeat probe ran. | |
| 76 | + |
| 77 | +## Actions |
| 78 | + |
| 79 | +The integration registers the following {% term actions %}. The dispatch actions begin the [dispatch lifecycle](#dispatch-lifecycle): after the entry delay elapses, the alarm is sent to Noonlight using the caller and location you configured. |
| 80 | + |
| 81 | +When more than one site is configured, set the optional `account` field on any action to the config entry's title or ID to target a specific site. With a single site configured, you can omit it. |
| 82 | + |
| 83 | +### Action `noonlight.dispatch_police` |
| 84 | + |
| 85 | +Request a police dispatch through Noonlight. |
| 86 | + |
| 87 | +| Data attribute | Optional | Description | |
| 88 | +| -------------- | -------- | ----------- | |
| 89 | +| `entry_delay_seconds` | yes | Grace window (0–120 seconds) before the dispatch actually fires, during which it can be canceled. Set `0` to skip. Defaults to the site's configured entry delay. | |
| 90 | +| `instructions` | yes | Free-text context sent to responders, for example which sensor triggered the alarm. Supports templates, such as {% raw %}`Triggered by {{ trigger.to_state.name }}`{% endraw %}. | |
| 91 | +| `account` | yes | Config entry ID or title. Optional when only one site is configured. | |
| 92 | + |
| 93 | +### Action `noonlight.dispatch_fire` |
| 94 | + |
| 95 | +Request a fire dispatch through Noonlight. Accepts the same `entry_delay_seconds`, `instructions`, and `account` data attributes as the `noonlight.dispatch_police` action. |
| 96 | + |
| 97 | +### Action `noonlight.dispatch_medical` |
| 98 | + |
| 99 | +Request a medical dispatch through Noonlight. Accepts the same `entry_delay_seconds`, `instructions`, and `account` data attributes as the `noonlight.dispatch_police` action. |
| 100 | + |
| 101 | +### Action `noonlight.dispatch_all` |
| 102 | + |
| 103 | +Request police, fire, and medical in a single alarm. Accepts the same `entry_delay_seconds`, `instructions`, and `account` data attributes as the `noonlight.dispatch_police` action. |
| 104 | + |
| 105 | +### Action `noonlight.cancel` |
| 106 | + |
| 107 | +Abort a pending dispatch, or signal Noonlight that an active dispatch is a false alarm. If canceled **before** the entry-delay timer fires, no network call is made to Noonlight. If canceled **after** the dispatch has fired, a cancel is posted to Noonlight, which decides whether responders are recalled. |
| 108 | + |
| 109 | +| Data attribute | Optional | Description | |
| 110 | +| -------------- | -------- | ----------- | |
| 111 | +| `reason` | yes | Free-text reason recorded in the audit log. | |
| 112 | +| `account` | yes | Config entry ID or title. Optional when only one site is configured. | |
| 113 | + |
| 114 | +### Action `noonlight.test_dispatch` |
| 115 | + |
| 116 | +Fire a no-op round-trip against Noonlight's **sandbox**. This confirms your credentials and connectivity without alerting real responders, even when the site runs in production. |
| 117 | + |
| 118 | +| Data attribute | Optional | Description | |
| 119 | +| -------------- | -------- | ----------- | |
| 120 | +| `account` | yes | Config entry ID or title. Optional when only one site is configured. | |
| 121 | + |
| 122 | +## Dispatch lifecycle |
| 123 | + |
| 124 | +```text |
| 125 | +idle ──dispatch_*──> pending ──(entry-delay timer)──> dispatched ──(cleared)──> idle |
| 126 | + │ |
| 127 | + └──cancel──> canceled ──> idle |
| 128 | +``` |
| 129 | + |
| 130 | +- A `cancel` during the **pending** window stops the timer and never contacts Noonlight. |
| 131 | +- A `cancel` after the dispatch has fired posts a cancel to Noonlight. |
| 132 | +- While a dispatch is `dispatched`, Home Assistant polls Noonlight for the alarm's status and returns to `idle` once Noonlight reports it is resolved, canceled, or completed. |
| 133 | + |
| 134 | +## Options |
| 135 | + |
| 136 | +{% include integrations/option_flow.md %} |
| 137 | + |
| 138 | +| Option | Description | |
| 139 | +| ------ | ----------- | |
| 140 | +| Default entry delay | Grace window (in seconds) before a dispatch fires when an action does not specify one. Cancelable during this time. Default 30. | |
| 141 | +| De-dup window | After a dispatch fires, repeat dispatches for the same service within this window (in seconds) are ignored, so an oscillating alarm cannot fire repeatedly. Default 300. | |
| 142 | +| Granted services | Which dispatch services (police, fire, medical) are available for this site. | |
| 143 | +| Heartbeat interval | How often to silently verify Noonlight is reachable and your token is valid (0–1440 minutes; **0 disables it**). Default 60. | |
| 144 | + |
| 145 | +{% note %} |
| 146 | +Caller, address, and site-label changes are **not** made in the options — they change what is sent to responders, so they are handled by the [Reconfigure](#reconfigure) action instead. |
| 147 | +{% endnote %} |
| 148 | + |
| 149 | +## Reconfigure |
| 150 | + |
| 151 | +To edit the caller details, address, or [site label](#multiple-properties) sent to Noonlight, use the **Reconfigure** action on the integration entry (**Settings** > **Devices & services** > **Noonlight** > the entry's menu > **Reconfigure**). The phone number, state, and ZIP are re-validated, and you do not need to delete and re-add the entry. |
| 152 | + |
| 153 | +## Heartbeat |
| 154 | + |
| 155 | +While idle, the integration periodically runs a side-effect-free probe against Noonlight to confirm the API is reachable and your token is still valid — so a broken token or connectivity problem is caught **before** an emergency rather than during one. |
| 156 | + |
| 157 | +The result drives the `api_reachable` binary sensor and the `last_health_check` sensor. After repeated consecutive failures the integration raises a [Repair issue](#troubleshooting): an authentication failure also starts reauthentication, prompting you to paste a fresh token without re-entering your address. Once the probe succeeds again, the Repair issue clears automatically. |
| 158 | + |
| 159 | +{% note %} |
| 160 | +Noonlight's Dispatch API has no dedicated health endpoint, so the probe is a harmless read of a non-existent alarm and returns a `404`. That `404` is the **healthy** signal — it means the request reached Noonlight, the endpoint exists, and your token was accepted (a revoked token returns `401`; an outage returns a connection error or `5xx`). It is expected and is not an error against your account. Raise the interval to reduce how often it runs, or set it to `0` to disable the heartbeat entirely. |
| 161 | +{% endnote %} |
| 162 | + |
| 163 | +## Multiple properties |
| 164 | + |
| 165 | +To protect more than one property, add **one config entry per site**. Set the optional **site / location label** during setup (or later via [Reconfigure](#reconfigure)) to a name like `Site A` or `Lake House`. The label is sent to Noonlight as the alarm's `owner_id` and is prepended to the responder instructions, so you can tell which property raised an alarm. Leave it blank if you only have a single site. |
| 166 | + |
| 167 | +## Examples |
| 168 | + |
| 169 | +### Dispatch police when an alarm trips |
| 170 | + |
| 171 | +```yaml |
| 172 | +automation: |
| 173 | + - alias: "Intrusion - Noonlight police" |
| 174 | + triggers: |
| 175 | + - trigger: state |
| 176 | + entity_id: binary_sensor.front_door_glass_break |
| 177 | + to: "on" |
| 178 | + actions: |
| 179 | + - action: noonlight.dispatch_police |
| 180 | + data: |
| 181 | + entry_delay_seconds: 30 |
| 182 | + instructions: "Triggered by {{ trigger.to_state.name }}" |
| 183 | +``` |
| 184 | +
|
| 185 | +### Cancel a pending dispatch when the panel is disarmed |
| 186 | +
|
| 187 | +```yaml |
| 188 | +automation: |
| 189 | + - alias: "Disarm during entry delay - cancel Noonlight" |
| 190 | + triggers: |
| 191 | + - trigger: state |
| 192 | + entity_id: alarm_control_panel.home |
| 193 | + to: "disarmed" |
| 194 | + conditions: |
| 195 | + - condition: state |
| 196 | + entity_id: binary_sensor.noonlight_jane_doe_dispatch_pending |
| 197 | + state: "on" |
| 198 | + actions: |
| 199 | + - action: noonlight.cancel |
| 200 | + data: |
| 201 | + reason: "Panel disarmed during entry delay" |
| 202 | +``` |
| 203 | +
|
| 204 | +## Troubleshooting |
| 205 | +
|
| 206 | +The integration surfaces failures as Home Assistant [Repair issues](/integrations/repairs/): |
| 207 | +
|
| 208 | +- **Authentication failed** — Noonlight rejected the API token. Use the reauthentication prompt to paste a new token; your address and other details are kept. |
| 209 | +- **Cannot reach Noonlight** — Home Assistant could not reach the API. Check your network and (for the custom environment) your base URL. |
| 210 | +- **Unexpected Noonlight response** — Noonlight returned a response Home Assistant did not understand. Check the logs and the Noonlight status page. |
| 211 | +- **A dispatch seems ignored** — Repeat dispatches for the same service inside the [de-dup window](#options) are intentionally suppressed; look for a warning in the logs. |
| 212 | +
|
| 213 | +Running the [`noonlight.test_dispatch`](#action-noonlighttest_dispatch) action is a safe way to confirm a credential or connectivity problem without alerting responders. |
| 214 | + |
| 215 | +## Removing the integration |
| 216 | + |
| 217 | +This integration follows standard integration removal. |
| 218 | + |
| 219 | +{% include integrations/remove_device_service.md %} |
0 commit comments