Concepts
Dormi exposes two surfaces for third-party automation, configured in Settings → Automation inside the app:
- Control — Dormi accepts intents from other apps to start, stop, snooze, or resume monitoring.
- Expose — Dormi broadcasts events whenever monitoring state, device mode, or noise detection changes.
Both features are off by default. Control additionally requires a shared secret that you set in Dormi's settings; every incoming intent must carry this secret, otherwise it is rejected.
Why the secret? Dormi's Control receiver is exported — any app on the device can send it an intent. The shared secret is the only thing distinguishing a real automation app from anything else, so pick one that isn't trivially guessable and don't paste it into screenshots.
Code samples below show the primary com.sleekbit.dormi package. For Dormi² or Dormi³, substitute com.sleekbit.dormi2 / com.sleekbit.dormi3 in every intent action prefix and every package, and read every "Dormi" UI label as "Dormi²" / "Dormi³". Class names stay the same.
| applicationId | com.sleekbit.dormi |
| Action prefix | com.sleekbit.dormi.automation.action.… |
| Event prefix | com.sleekbit.dormi.automation.event.… |
| Activity target | com.sleekbit.dormi/com.sleekbit.dormi.ui.BmActivity |
| Receiver target | com.sleekbit.dormi/com.sleekbit.dormi.automation.Control |
Receivers must be runtime-registered. Dormi sends Expose broadcasts with FLAG_RECEIVER_REGISTERED_ONLY. This is on purpose — third-party automation apps don't know about Dormi at install time, they wire up receivers at runtime. Manifest-declared <receiver> entries will never fire. Tasker, Automate, and the Home Assistant Companion all register at runtime, so this just works for the supported tools.
Actions
Every action's intent action string is the prefix com.sleekbit.dormi.automation.action. followed by the name in the table.
| Action | Wire it up | Notes |
|---|---|---|
MONITORING_START |
Send asActivity start
Targetcom.sleekbit.dormi/com.sleekbit.dormi.ui.BmActivity
Extrassecret
|
See prerequisites below. |
MONITORING_STOP |
Send asBroadcast
Targetcom.sleekbit.dormi/com.sleekbit.dormi.automation.Control
Extrassecret
|
Idempotent — returns "already stopped" if nothing is running. |
MONITORING_SNOOZE |
Send asBroadcast
Targetcom.sleekbit.dormi/com.sleekbit.dormi.automation.Control
Extrassecret
|
Snoozes for 10 minutes. Resets the timer if already snoozed. Rejected when stopped, starting, or reconnecting. |
MONITORING_RESUME |
Send asBroadcast
Targetcom.sleekbit.dormi/com.sleekbit.dormi.automation.Control
Extrassecret
|
No-op when already monitoring. Rejected when stopped, starting, or reconnecting. |
EXPOSE_STATE |
Send asBroadcast
Targetcom.sleekbit.dormi/com.sleekbit.dormi.automation.Control
Extrassecret, target_pkg (required)
|
One-shot state pull. You don't need this if Expose is enabled and you're already listening — Dormi already broadcasts changes. Use it to fetch the current state on demand (e.g., when your automation just started) or while Expose is off — EXPOSE_STATE is intentionally not gated by the Expose toggle, so it works even when continuous broadcasts are turned off. target_pkg = receiving package, or any to broadcast system-wide. |
Tag every action. All actions accept an optional tag extra (string). Dormi shows it in a toast and records it in the in-app Activity Log alongside the action's outcome — invaluable when debugging which automation fired what. Set it to something memorable like from_tasker or bedtime_routine.
MONITORING_START prerequisites
MONITORING_START is the only action sent as an Activity start, not a broadcast. This is deliberate: starting monitoring without a visible user surface would violate Google Play policy, so Dormi brings its own UI to the foreground and runs a 10-second countdown the user can cancel.
For the request to succeed, all of these must hold:
- Dormi is paired with another device and the shared secret is set.
- The target device's role: CHILD mode also requires
RECORD_AUDIOpermission to be granted. POST_NOTIFICATIONSpermission granted (Android 13+).ACCESS_LOCAL_NETWORKpermission granted (Android 17+).- The user has exempted Dormi from battery optimizations (Settings → Apps → Dormi → Battery).
- Dormi's UI can reach the foreground (no other app is blocking activity starts, e.g. lock-screen restrictions on some OEMs).
If any check fails, the request aborts and the reason is logged to the in-app Activity Log. The countdown also aborts if the user navigates away from Dormi during the 10 seconds, or taps to cancel.
Already-running short-circuit. If monitoring is in any non-stopped state when the intent arrives (including starting, snoozed, or reconnecting), Dormi returns "already running" immediately, before checking any prerequisite and without bringing the UI to the foreground or starting a countdown. This makes MONITORING_START safe to fire from automations that don't know whether a session is already in progress.
Outcome is two-phase, and asynchronous. The prerequisite check above happens immediately when the activity starts and reports either "countdown starting" or "waiting for activity start" in the Activity Log. The real outcome — "started", or "aborted, <reason>" — arrives 10–20 seconds later, after the countdown completes (or is interrupted). Both phases are logged with your tag extra, so an automation that needs to act on the final result should poll the Activity Log or listen for the MONITORING_STATE_CHANGED Expose event rather than rely on the synchronous reply.
Result codes
Only Control broadcasts can return a result code, and only when sent as ordered broadcasts. MONITORING_START is an activity start and never produces one. For the broadcast actions, Dormi sets:
RESULT_OK(-1) — handled successfully. Message describes what happened (e.g. "snoozed", "already stopped").RESULT_CANCELED(0) — rejected. Message describes why (e.g. "secret mismatch", "device not paired", "not monitoring").
Note that not every tool can read these. Tasker's Send Intent can be configured for ordered broadcasts; Automate's Send broadcast block and Home Assistant Companion's command_broadcast_intent currently cannot. In those cases, use the Activity Log for verification instead.
Events
When Expose is enabled, Dormi broadcasts these events. Every event's action string is the prefix com.sleekbit.dormi.automation.event. followed by the name in the table.
| Event | When it fires | Extras |
|---|---|---|
MONITORING_STATE_CHANGED |
Monitoring state, device mode, or noise-detection flag changes. |
monitoring_state — one of stopped, starting, monitoring, snoozed, reconnectingdevice_mode — child or parentnoise_detected — true or false
|
CRASH |
Dormi crashes. Sent before the process exits, so delivery is best-effort. | None. |
reconnecting is parent-mode only: the parent has lost contact with the child and the child's true state is unknown until reconnection.
noise_detected is only meaningful while monitoring_state = monitoring. Dormi forces it to false in every other state so you don't have to special-case stale flags.
Recipes
Pick the tool you use and what you want to do. Recipes assume Control and/or Expose are already enabled in Dormi's settings. The Class values below stay com.sleekbit.dormi.* across all editions — only the Package and Action prefix change with the target app you picked above.
Tasker
Start monitoring
- Add a Send Intent action (System category).
- Action:
com.sleekbit.dormi.automation.action.MONITORING_START - Package:
com.sleekbit.dormi - Class:
com.sleekbit.dormi.ui.BmActivity - Target:
Activity - Extras:
secret:your_secret(optionally append,tag:from_tasker)
Stop monitoring
- Add a Send Intent action.
- Action:
com.sleekbit.dormi.automation.action.MONITORING_STOP - Package:
com.sleekbit.dormi - Class:
com.sleekbit.dormi.automation.Control - Target:
Broadcast Receiver - Extras:
secret:your_secret
Snooze monitoring
- Add a Send Intent action.
- Action:
com.sleekbit.dormi.automation.action.MONITORING_SNOOZE - Package:
com.sleekbit.dormi - Class:
com.sleekbit.dormi.automation.Control - Target:
Broadcast Receiver - Extras:
secret:your_secret
Resume monitoring
- Add a Send Intent action.
- Action:
com.sleekbit.dormi.automation.action.MONITORING_RESUME - Package:
com.sleekbit.dormi - Class:
com.sleekbit.dormi.automation.Control - Target:
Broadcast Receiver - Extras:
secret:your_secret
Query current state
You normally don't need this — if Expose is enabled in Dormi, every state change already triggers a broadcast you can catch with the Receive state-change events recipe. Use this only to fetch state on demand (e.g. when your Tasker profile just initialized).
- Add a Send Intent action.
- Action:
com.sleekbit.dormi.automation.action.EXPOSE_STATE - Package:
com.sleekbit.dormi - Class:
com.sleekbit.dormi.automation.Control - Target:
Broadcast Receiver - Extras:
secret:your_secret,target_pkg:net.dinglisch.android.taskerm
The reply arrives as a MONITORING_STATE_CHANGED broadcast — catch it with the Receive state-change events profile.
Receive state-change events
- Create a new Profile → Event → System → Intent Received.
- Action:
com.sleekbit.dormi.automation.event.MONITORING_STATE_CHANGED - In the linked task, the extras are exposed as Tasker variables:
%monitoring_state,%device_mode,%noise_detected.
Receive crash event
- Create a new Profile → Event → System → Intent Received.
- Action:
com.sleekbit.dormi.automation.event.CRASH - The event has no extras — its arrival is the signal. Link a task that does whatever you need (notify, log, send a message).
Automate
Start monitoring
- Add a Start activity block.
- Action:
com.sleekbit.dormi.automation.action.MONITORING_START - Package:
com.sleekbit.dormi - Class:
com.sleekbit.dormi.ui.BmActivity - Extras: key
secret= your secret (string).
Stop monitoring
- Add a Send broadcast block.
- Action:
com.sleekbit.dormi.automation.action.MONITORING_STOP - Package:
com.sleekbit.dormi - Receiver:
com.sleekbit.dormi.automation.Control - Extras: key
secret= your secret (string).
Snooze monitoring
- Add a Send broadcast block.
- Action:
com.sleekbit.dormi.automation.action.MONITORING_SNOOZE - Package:
com.sleekbit.dormi - Receiver:
com.sleekbit.dormi.automation.Control - Extras: key
secret= your secret (string).
Resume monitoring
- Add a Send broadcast block.
- Action:
com.sleekbit.dormi.automation.action.MONITORING_RESUME - Package:
com.sleekbit.dormi - Receiver:
com.sleekbit.dormi.automation.Control - Extras: key
secret= your secret (string).
Query current state
You normally don't need this — if Expose is enabled in Dormi, every state change already triggers a broadcast you can catch with the Receive state-change events recipe. Use this only to fetch state on demand.
- Add a Send broadcast block.
- Action:
com.sleekbit.dormi.automation.action.EXPOSE_STATE - Package:
com.sleekbit.dormi - Receiver:
com.sleekbit.dormi.automation.Control - Extras: two string entries —
secret= your secret, andtarget_pkg=com.llamalab.automate.
The reply arrives as a MONITORING_STATE_CHANGED broadcast — catch it with the Receive state-change events recipe below.
Receive state-change events
- Add a Broadcast receive block (looped, so it re-arms after each event).
- Action:
com.sleekbit.dormi.automation.event.MONITORING_STATE_CHANGED - In Output, bind extras to flow variables:
monitoring_state,device_mode,noise_detected.
Receive crash event
- Add a Broadcast receive block (looped).
- Action:
com.sleekbit.dormi.automation.event.CRASH - No extras to bind. Its arrival is the signal — wire it to whatever you want to happen on crash.
Home Assistant Companion
Sending intents to Dormi requires the Home Assistant Companion app to be installed on the phone where Dormi runs. Home Assistant on the server calls the Companion's notify service with the command_broadcast_intent or command_activity message.
Start monitoring
Service call from an automation, script, or button:
action: notify.mobile_app_<your_device>
data:
message: command_activity
data:
intent_action: com.sleekbit.dormi.automation.action.MONITORING_START
intent_package_name: com.sleekbit.dormi
intent_class_name: com.sleekbit.dormi.ui.BmActivity
intent_extras: "secret:your_secret,tag:from_ha"
Stop monitoring
action: notify.mobile_app_<your_device>
data:
message: command_broadcast_intent
data:
intent_action: com.sleekbit.dormi.automation.action.MONITORING_STOP
intent_package_name: com.sleekbit.dormi
intent_class_name: com.sleekbit.dormi.automation.Control
intent_extras: "secret:your_secret"
Snooze monitoring
action: notify.mobile_app_<your_device>
data:
message: command_broadcast_intent
data:
intent_action: com.sleekbit.dormi.automation.action.MONITORING_SNOOZE
intent_package_name: com.sleekbit.dormi
intent_class_name: com.sleekbit.dormi.automation.Control
intent_extras: "secret:your_secret"
Resume monitoring
action: notify.mobile_app_<your_device>
data:
message: command_broadcast_intent
data:
intent_action: com.sleekbit.dormi.automation.action.MONITORING_RESUME
intent_package_name: com.sleekbit.dormi
intent_class_name: com.sleekbit.dormi.automation.Control
intent_extras: "secret:your_secret"
Query current state
You normally don't need this — if Expose is enabled in Dormi, every state change already flows into HA via the Receive state-change events recipe. Use this only to fetch state on demand.
action: notify.mobile_app_<your_device>
data:
message: command_broadcast_intent
data:
intent_action: com.sleekbit.dormi.automation.action.EXPOSE_STATE
intent_package_name: com.sleekbit.dormi
intent_class_name: com.sleekbit.dormi.automation.Control
intent_extras: "secret:your_secret,target_pkg:io.homeassistant.companion.android"
The reply lands in HA as an android.intent_received event — handle it with the Receive state-change events recipe below.
Receive state-change events
- In the Companion app on the phone, open Settings → Companion app → Manage sensors → Last update trigger. In its Intent action field, add
com.sleekbit.dormi.automation.event.MONITORING_STATE_CHANGED. See the Last Update Trigger sensor docs for details. - The Companion will then forward every matching broadcast to HA as an
android.intent_receivedevent with extras as top-level keys undertrigger.event.data. - Define template sensors in
configuration.yamlthat materialize the state and noise flag as proper HA entities you can chart, automate against, and expose to the dashboard:
template:
- trigger:
- trigger: event
event_type: android.intent_received
event_data:
intent: com.sleekbit.dormi.automation.event.MONITORING_STATE_CHANGED
device_id: <your device id>
sensor:
- name: Dormi Session State
unique_id: "e77e0a24-b564-4e49-8fe0-88975198affd"
state: "{{ trigger.event.data.monitoring_state }}"
attributes:
noise_detected: "{{ trigger.event.data.noise_detected }}"
device_mode: "{{ trigger.event.data.device_mode }}"
- trigger:
- trigger: event
event_type: android.intent_received
event_data:
intent: com.sleekbit.dormi.automation.event.MONITORING_STATE_CHANGED
device_id: <your device id>
binary_sensor:
- name: Dormi Noise Detected
unique_id: "d22eb5ea-e66e-4dc1-a946-67485316ed3d"
state: "{{ trigger.event.data.noise_detected == 'true' }}"
Replace each unique_id with your own GUIDs (any UUID will do — they just have to be stable). The device_id in the event_data filter scopes the sensors to a single phone, so events from other phones forwarding to the same HA instance don't bleed in. See Finding your device_id below.
Finding your device_id
Open Home Assistant → Developer Tools → Events. In the Listen to events panel, type android.intent_received and click Start listening. Then trigger a Dormi state change on the phone (toggle snooze, start/stop monitoring, etc.). The event will appear in the panel; copy the device_id value from its data and paste it into the event_data filter above. The same readout is also useful for sanity-checking that the expected extras (monitoring_state, noise_detected, device_mode) arrive with the values you expect.
Receive crash event
In the Companion app, open Settings → Companion app → Manage sensors → Last update trigger and add com.sleekbit.dormi.automation.event.CRASH to the Intent action field (one per line — keep MONITORING_STATE_CHANGED there too if you've already added it). The event has no extras; its arrival in HA as an android.intent_received event with that action is the signal. Trigger off it directly from an automation:
automation:
- alias: Dormi crashed
triggers:
- trigger: event
event_type: android.intent_received
event_data:
intent: com.sleekbit.dormi.automation.event.CRASH
device_id: <your device id>
actions:
- action: notify.persistent_notification
data:
message: "Dormi crashed on phone — check the device."
Verifying & troubleshooting
The Activity Log is your first stop. Open Dormi → Activity Log. Every Control request — successful or rejected — is recorded there with the action name, your tag extra if you included one, and the outcome. If you don't see anything when you fire your intent, Dormi didn't receive it, which narrows the problem to the sending side (wrong action, wrong package/class, missing secret, the secret didn't match).
Common silent-failure modes:
- "automation not enabled" — Control isn't turned on in Dormi's settings.
- "secret mismatch" — the
secretextra doesn't match what's in Dormi's settings. Copy-paste mistakes and trailing whitespace are typical culprits. - "device not paired" — Dormi isn't paired with another device yet. Automation only works on paired devices.
- EXPOSE_STATE rejected with "extra key 'target_pkg' missing" — you forgot the
target_pkgextra. Set it to the receiver's package name or toany. - No state-change events arrive — confirm Expose is on, then confirm the receiving app actually registers receivers at runtime (Tasker / Automate / HA Companion all do). Manifest
<receiver>entries will never see these broadcasts. - MONITORING_START reports an abort — check the list of prerequisites above. The Activity Log message names exactly which one failed.
Testing with ADB
Useful for smoke-testing without setting up Tasker/Automate/HA first.
Start monitoring
adb shell am start \
-a com.sleekbit.dormi.automation.action.MONITORING_START \
-n com.sleekbit.dormi/com.sleekbit.dormi.ui.BmActivity \
--es secret your_secret \
--es tag adb_start
Stop / Snooze / Resume
adb shell am broadcast \
-a com.sleekbit.dormi.automation.action.MONITORING_SNOOZE \
-n com.sleekbit.dormi/com.sleekbit.dormi.automation.Control \
--es secret your_secret \
--es tag adb_snooze
Query current state (broadcast to all)
adb shell am broadcast \
-a com.sleekbit.dormi.automation.action.EXPOSE_STATE \
-n com.sleekbit.dormi/com.sleekbit.dormi.automation.Control \
--es secret your_secret \
--es target_pkg any \
--es tag adb_query
Run adb logcat | grep DORMI in another shell to see Dormi's own log lines while you experiment.