Skip to content

Alarms Intent API

Not yet released

Support for this feature has been added to Gadgetbridge's codebase, but is not yet released. It is already available in the nightly releases.

This API was added in pull request #6088, and allows third party apps to create and dismiss alarms on a device.

Requirements

  • The API must be enabled in the device-specific developer settings.
  • The device must support alarms
  • The intent package name must match the package name for the version of Gadgetbridge you are running.

Set alarm

  • Action: nodomain.freeyourgadget.gadgetbridge.command.SET_ALARM
  • Extras: None.
    • device (String): target device MAC address
    • hour (int): required, range 0..23
    • minutes (int): required, range 0..59
    • days (ArrayList<Integer>): optional, repetition days using java.util.Calendar constants
    • title (String): optional, alarm title stored in Gadgetbridge's local DB and forwarded to the device if the device supports alarm titles

Dismiss alarm

  • Action: nodomain.freeyourgadget.gadgetbridge.command.DISMISS_ALARM
  • Extras: None.
  • mode (String): required, one of:
    • all
    • time
    • title
  • hour (int): required for time
  • minutes (int): optional for time
  • title (String): required for title

Repetition Days

If days is present, use Calendar weekday constants:

  • Calendar.MONDAY
  • Calendar.TUESDAY
  • Calendar.WEDNESDAY
  • Calendar.THURSDAY
  • Calendar.FRIDAY
  • Calendar.SATURDAY
  • Calendar.SUNDAY

If days is omitted or empty, the alarm is treated as non-repeating.

Set Alarm Behavior

When setting an alarm, Gadgetbridge does not target a slot ID.

Instead, it searches for the next reusable slot with these conditions:

  • the alarm is currently disabled
  • the alarm title is empty or null

This is intentional:

  • slot IDs are not stable to rely on them
  • titled alarms are treated as protected
  • dismissed alarms with titles are not overwritten by this API

Titles are supported by this API even on devices that do not support alarm titles natively; titles are still stored in Gadgetbridge's local database and the user can also protect alarms from being overwritten by this API by setting them manually.

Implications:

  • if you want your own alarms to be dismissable and reusable by this API define a unique long title for the alarms coming from your app
  • if the user gives a personal alarm a title, that slot is protected from reuse
  • you can still bypass this by dismissing all alarms from the device, but this is destructive and shouldn't be done

If no free untitled slot exists, the set operation is ignored.

Dismiss Alarm Behavior

Mode all

Dismisses all alarms and clears their titles. This will ignore whether the alarm has a title or not. We strongly disencourage the use of all, unless your user understands the implication and wishes their device's alarms to be fully managed by you.

Mode title

Dismisses alarms whose title contains the provided title string.

Matching details:

  • uses substring matching, not exact equality
  • case-sensitive

If the provided title is part of the stored alarm title, the alarm matches and is dismissed.

Example:

  • stored title MyExternalAppAlarm #1
  • dismiss title MyExternalAppAlarm
  • this matches

Mode time

Dismisses alarms by time.

You must provide:

  • hour

You may also provide:

  • minutes

Matching details:

  • if only hour is provided, alarms with that hour match
  • if only minutes is provided, the request is invalid
  • if both are provided, both hour and minute must match

Example:

  • requested hour=6, minutes=30
  • an alarm at 06:10 does not match
  • an alarm at 09:30 does not match
  • an alarm at 06:30 matches

When an alarm is dismissed, Gadgetbridge:

  • disables it
  • clears its title

Clearing the title makes the slot reusable by the set API, because this API only overwrites alarms without a title.

Error Handling

Invalid requests are ignored and logged by Gadgetbridge.

Examples:

  • missing device
  • invalid MAC address
  • unknown device
  • disabled API setting on the device
  • missing hour or minutes for set
  • invalid hour/minute values
  • unsupported dismiss mode
  • missing title for title-based dismiss
  • no reusable slot available

The caller does not receive a structured response.

Source of Truth

The Gadgetbridge database is the source of truth for this API.

This means:

  • titles are stored locally in Gadgetbridge even if the device itself does not support transmitting alarm titles
  • device-only changes are not automatically preserved unless they have already been reflected into Gadgetbridge's DB

The recommended workflow for third-party apps is title-based ownership:

  1. dismiss your old alarms by title
  2. create your new alarms using the same title

This works well because:

  • title-based dismiss uses a contains check
  • alarms dismissed through this API have their title cleared
  • only alarms without a title are reused by the set API

In other words, titles are the safest way to identify and manage the alarms created by your app.

Examples

Kotlin Example

Set an alarm

import android.content.Intent
import java.util.ArrayList
import java.util.Calendar

fun sendSetAlarm(context: android.content.Context, mac: String) {
    val intent = Intent("nodomain.freeyourgadget.gadgetbridge.command.SET_ALARM").apply {
        // Replace with the package name for the version of Gadgetbridge you are running
        `package` = "nodomain.freeyourgadget.gadgetbridge"
        putExtra("device", mac)
        putExtra("hour", 7)
        putExtra("minutes", 30)
        putExtra("title", "Morning run")
        putIntegerArrayListExtra(
            "days",
            arrayListOf(
                Calendar.MONDAY,
                Calendar.WEDNESDAY,
                Calendar.FRIDAY
            )
        )
    }

    context.sendBroadcast(intent)
}

Dismiss alarms by title

import android.content.Intent

fun dismissByTitle(context: android.content.Context, mac: String) {
    val intent = Intent("nodomain.freeyourgadget.gadgetbridge.command.DISMISS_ALARM").apply {
        // Replace with the package name for the version of Gadgetbridge you are running
        `package` = "nodomain.freeyourgadget.gadgetbridge"
        putExtra("device", mac)
        putExtra("mode", "title")
        putExtra("title", "Morning run")
    }

    context.sendBroadcast(intent)
}

Dismiss alarms by time

import android.content.Intent

fun dismissByTime(context: android.content.Context, mac: String) {
    val intent = Intent("nodomain.freeyourgadget.gadgetbridge.command.DISMISS_ALARM").apply {
        // Replace with the package name for the version of Gadgetbridge you are running
        `package` = "nodomain.freeyourgadget.gadgetbridge"
        putExtra("device", mac)
        putExtra("mode", "time")
        putExtra("hour", 7)
        putExtra("minutes", 30)
    }

    context.sendBroadcast(intent)
}

Dismiss all alarms

import android.content.Intent

fun dismissAll(context: android.content.Context, mac: String) {
    val intent = Intent("nodomain.freeyourgadget.gadgetbridge.command.DISMISS_ALARM").apply {
        // Replace with the package name for the version of Gadgetbridge you are running
        `package` = "nodomain.freeyourgadget.gadgetbridge"
        putExtra("device", mac)
        putExtra("mode", "all")
    }

    context.sendBroadcast(intent)
}

Java Example

import android.content.Context;
import android.content.Intent;

import java.util.ArrayList;
import java.util.Calendar;

public class GadgetbridgeAlarmApiExample {
    public static void setAlarm(final Context context, final String macAddress) {
        final Intent intent = new Intent("nodomain.freeyourgadget.gadgetbridge.command.SET_ALARM");
        // Replace with the package name for the version of Gadgetbridge you are running
        intent.setPackage("nodomain.freeyourgadget.gadgetbridge");
        intent.putExtra("device", macAddress);
        intent.putExtra("hour", 6);
        intent.putExtra("minutes", 45);
        intent.putExtra("title", "Gym");

        final ArrayList<Integer> days = new ArrayList<>();
        days.add(Calendar.MONDAY);
        days.add(Calendar.TUESDAY);
        days.add(Calendar.THURSDAY);
        intent.putIntegerArrayListExtra("days", days);

        context.sendBroadcast(intent);
    }

    public static void dismissByTitle(final Context context, final String macAddress, final String title) {
        final Intent intent = new Intent("nodomain.freeyourgadget.gadgetbridge.command.DISMISS_ALARM");
        // Replace with the package name for the version of Gadgetbridge you are running
        intent.setPackage("nodomain.freeyourgadget.gadgetbridge");
        intent.putExtra("device", macAddress);
        intent.putExtra("mode", "title");
        intent.putExtra("title", title);
        context.sendBroadcast(intent);
    }
}

adb Example

Replace gadgetbridge_package_name with the package name for the version of Gadgetbridge you are running.

Set alarm

adb shell am broadcast \
  -a nodomain.freeyourgadget.gadgetbridge.command.SET_ALARM \
  --es device "AA:BB:CC:DD:EE:FF" \
  --ei hour 7 \
  --ei minutes 30 \
  --es title "Morning run" \
  gadgetbridge_package_name

Dismiss by title

adb shell am broadcast \
  -a nodomain.freeyourgadget.gadgetbridge.command.DISMISS_ALARM \
  --es device "AA:BB:CC:DD:EE:FF" \
  --es mode "title" \
  --es title "Morning run" \
  gadgetbridge_package_name

Dismiss all

adb shell am broadcast \
  -a nodomain.freeyourgadget.gadgetbridge.command.DISMISS_ALARM \
  --es device "AA:BB:CC:DD:EE:FF" \
  --es mode "all" \
  gadgetbridge_package_name

Practical Recommendations

  • Always set a title for alarms created by your app.
  • Use title-based dismiss whenever possible.
  • Do not rely on slot ordering or slot identity.
  • Be aware that title matching is case-sensitive and substring-based.
  • If your app fully manages the device alarms, mode=all may be the simplest reset strategy before re-creating alarms.

Reference Implementation

The current Gadgetbridge behavior is covered by: