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 addresshour(int): required, range0..23minutes(int): required, range0..59days(ArrayList<Integer>): optional, repetition days usingjava.util.Calendarconstantstitle(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:alltimetitle
hour(int): required fortimeminutes(int): optional fortimetitle(String): required fortitle
Repetition Days¶
If days is present, use Calendar weekday constants:
Calendar.MONDAYCalendar.TUESDAYCalendar.WEDNESDAYCalendar.THURSDAYCalendar.FRIDAYCalendar.SATURDAYCalendar.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
houris provided, alarms with that hour match - if only
minutesis 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:10does not match - an alarm at
09:30does not match - an alarm at
06:30matches
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
hourorminutesfor set - invalid hour/minute values
- unsupported dismiss mode
- missing
titlefor 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
Recommended Workflow¶
The recommended workflow for third-party apps is title-based ownership:
- dismiss your old alarms by title
- 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=allmay be the simplest reset strategy before re-creating alarms.
Reference Implementation¶
The current Gadgetbridge behavior is covered by: