App reference¶
This page lists what a BattleTime app can declare, read, answer, show and ask for. writing-apps.md shows how an app is written, compiler.md the language the compiler takes, and app-runtime.md how the watch runs it.
Every name comes from the battletime package: values, events, effects and functions from battletime,
widgets from battletime/widgets, ready-made components from battletime/components, icons from
battletime/icons and shared library functions from battletime/lib.
Declaring an app¶
export default define_app({...}) says who the app is:
| Field | Holds |
|---|---|
id |
The app's id, which names its folder: up to 32 bytes. The watch takes letters, digits, - and _; repository apps use lower-case words joined by hyphens, such as four-in-a-row. |
name |
The name the launcher shows. |
icon |
A shared library icon, such as icons.timer, or a PNG beside the source, such as "./icon.png". |
kind |
"app", the default, or "face"; a watch face cannot take the button. |
group |
The launcher group the app starts in, such as "games": up to 16 letters, digits, - and _. apps.md lists the usual ones. |
screens |
One component per screen, main first. go("name") moves between them. |
define_app takes no list of permissions: the compiler works them out (see
Permissions).
| State | Is |
|---|---|
signal(start) |
A value that lasts while the app is open. |
persisted("key", start) |
A value kept across restarts, under its key. |
useSignal(start) |
A value for that place in a component. |
computed(() => ...) |
A value worked out from others. |
State may hold numbers, booleans, Instant, Duration, one of the app's own literal strings,
records of a fixed shape and fixed-length arrays of those; see Records and arrays.
| Constant | Value |
|---|---|
SECOND, MINUTE, HOUR, DAY |
Durations in milliseconds. |
EVERY_DAY |
0b1111111, a day mask with every day set. |
STEP_HISTORY_DAYS |
7, the days step_history keeps. |
System values¶
System values are read-only signals the runtime keeps current. Reading one in a view or a
computed makes that binding depend on it, so it redraws when the value changes and at no other
time. Reading them needs no permission unless the table says so.
Time, battery and activity¶
| Value | Type | Holds |
|---|---|---|
now |
Instant |
The current time. A binding that reads it redraws as often as its format shows, such as once a minute for HH:mm. |
utc_offset |
Duration |
The local time zone's offset, set by the phone. |
battery_percent |
Int |
The charge, 0 to 100. It only rises on the charger and only falls off it, stays at 99 while charging and reads 100 once full. |
is_charging |
Bool |
Whether the watch is on its charger and still charging. |
battery_millivolts |
Int |
The battery's voltage, smoothed over the last few minutes. |
steps_today |
Int |
Steps since local midnight. |
step_history |
object | trip, the steps since reset_step_trip(); days, today and the six days before, each with its total, read by how many days back it is (step_history.value.days[1].total is yesterday); and hours, each with its steps, read at days_back * 24 + hour. |
heart_rate |
Int |
The last heart rate measured, in beats per minute, or 0. |
heart_rate_measured_at |
Instant |
When heart_rate was measured. |
heart_rate_status |
Int |
The sensor's state: 0 stopped, 1 no skin, 2 settling, 3 measuring. |
is_heart_rate_running |
Bool |
Whether the sensor is measuring for any app. |
shake_speed |
Int |
How fast the wrist shakes now, 0 to about 4095, as InfiniTime counts it. Kept current only while the open screen shows it. |
next_alarm |
Instant \| null |
When the alarm app rings next while closed, or null. |
Phone and notifications¶
| Value | Type | Holds |
|---|---|---|
is_phone_connected |
Bool |
Whether the phone is connected. |
is_bluetooth_enabled |
Bool |
Whether Bluetooth is on. It is on again after every restart. |
unread_notifications |
Int |
How many kept notifications are unread. |
notifications |
list | The latest 5 notifications, newest first; needs notifications. Each has id (for dismiss_notification; an app's own are negative), app, title, body, time, icon and color. |
current_call |
object | The latest call: caller, its name or number, and state, incoming, answered or ended. Needs phone. |
current_music |
object | The phone's player: artist, track, is_playing, position and length. Needs phone. |
current_navigation |
object | turn, instruction, distance in metres and progress_percent. Needs phone. |
current_weather |
object | temperature, condition, low, high, sunrise, sunset, location and received_at, each null until the phone sends it, and forecast, up to 5 coming days of condition, low and high. Temperatures are whole degrees Celsius. |
The watch picks each notification's icon and color from its app:
app |
Icon | Colour |
|---|---|---|
Call, Phone |
phone |
success |
Missed call, or Phone with the body Missed call |
phone_missed |
danger |
SMS |
sms |
blue #3078f8 |
Messages |
chat |
blue |
Voicemail |
voicemail |
blue |
Email |
notification |
warning |
Schedule, Calendar |
calendar |
purple #a850f8 |
News |
news |
accent |
Alert |
bell |
accent |
| Any other | notification |
accent |
The watch keeps up to 24 bytes of a notification's app, 32 of its title and 120 of its body.
The latest music, weather and navigation are kept in RAM, so an app shows them by reading these
values; the music, weather and navigation events are for reacting when they change.
Settings¶
settings holds the user's choices, which apps read and change with set_setting:
| Setting | Holds |
|---|---|
uses_24_hour_clock, uses_metric_units |
Booleans. |
step_goal |
The day's step goal. |
screen_timeout_seconds |
5 to 300. |
always_on_screen |
Whether the screen dims instead of turning off. |
chimes |
0 off, 1 every hour, 2 every half hour. |
theme |
The preset theme's number (dark, light, ocean, forest, sunset, contrast), or -1 for the user's own colours. |
allows_updates |
0 off, 1 on, 2 on until the next restart. |
wake_on_touch |
0 only the button wakes the screen, 1 a tap, 2 a double tap. |
alarms_in_do_not_disturb |
Whether alarms and timers still ring in do not disturb. |
heart_rate_interval |
0 off, 1 continuous, then every 30 seconds, minute, 5, 10 or 30 minutes. |
raise_to_wake, lower_to_sleep, shake_to_wake |
Wake gestures. |
shake_threshold |
0 to 4095, the shake_speed a shake must pass to wake the screen. |
sleep_mode |
Do not disturb that also turns off every wake gesture and the always-on screen. |
watch_face |
The number of the face shown, made from its id as companion-protocol.md says, or 0 with no face on. |
gadgetbridge_name |
Whether the watch advertises as InfiniTime for Gadgetbridge. |
| Value | Type | Holds |
|---|---|---|
is_do_not_disturb |
Bool |
Whether do not disturb is on. |
brightness |
Int |
The backlight level, 1 to 3. |
watch_face_name |
Text |
The name of the face shown, or nothing. |
Apps and storage¶
| Value | Type | Holds |
|---|---|---|
installed_apps |
list | Every app a launcher lists, group by group: .name, .id (for open_app) and .icon. |
launcher_groups |
list | The groups holding at least one app: .name, .icon, and .first and .count, the run of installed_apps each holds. With no launcher file every app is in one group, Other. |
launcher_style |
Text |
folders, sections, pages or list. |
launcher_view |
Text |
list or grid. |
packages |
list | Every installed app and face, in id order: .name, .id (for set_app_enabled), .is_face, .enabled, .memory, the heap it needs, and .refusal, why turning it the other way would be refused: 0 it would not, 1 it needs more memory than an app can have, 2 the launcher would run out of memory, 3 the launcher stays on, 4 the last watch face stays on, 5 it is the open app. |
app_memory_budget |
Int |
The most heap an open app may need, in bytes. |
current_folder |
object | The folder open_folder last listed: path, such as /apps, and entries, up to 64 of .name, .size in bytes and .is_folder, folders first. A folder's size is the sum of the files inside it. |
free_storage_kilobytes |
Int |
The space left in the file system, counted when the app opens. |
The watch itself¶
| Value | Type | Holds |
|---|---|---|
firmware_version |
Text |
Such as 0.1.0+1b19aed, with a * for a build with uncommitted changes. |
firmware_build_date |
Text |
The UTC day the firmware was built. |
firmware_state |
Int |
0 confirmed, 1 on trial after an update, 2 rolled back to. |
started_at |
Instant |
When the watch last started. |
reset_reason |
Text |
Why it last restarted: Fault at 0x…, Last run panicked, or the chip's reasons, such as watchdog. |
bootloader_version, bootloader_build_date |
Text |
From the bootloader's version record, or "". Looked up the first time an app reads it. |
bootloader_crc |
Int \| null |
The bootloader's CRC-32, or null when unreadable. |
bluetooth_address |
Int |
The advertised address as one 48-bit number. |
flash_id |
Int |
The external flash's JEDEC ID, 0x0B4016 for the XT25F32B, or 0. |
touch_chip_id, touch_firmware_version |
Int |
0xB4 for a CST816S, or 0. |
accelerometer_chip_id |
Int |
0x11 for a BMA421, 0x13 for a BMA425, or 0. |
free_heap_bytes, least_free_heap_bytes |
Int |
The heap's free bytes when the app opened, and the fewest since start. |
allocation_failures |
Int |
Allocations the heap refused since start. |
stack_overflows |
Int |
Stack overflows into the guard, counted until the power goes. |
tasks |
list | The firmware's tasks: .name, .runs and .busy_milliseconds. |
current_screen, the name of the screen on display, exists only in the browser preview; the
compiler refuses it, so keep a screen's name in a signal.
Events¶
Events call an app's handlers, which receive the event's fields as their argument. Handlers run one at a time, to the end.
Touch¶
Touch events belong to the widget touched. A widget with no handler for an event lets it pass to the widget behind it, and then to the screen.
| Prop | Fields | When |
|---|---|---|
onClick |
x, y |
A short tap. |
onLongPress |
x, y |
A finger held still for half a second. |
onDoubleClick |
x, y |
Two taps close together, as the touch panel reports them. |
onPress, onRelease |
x, y |
A finger landing and lifting. |
onDrag |
x, y, start_x, start_y |
A finger moving while down. |
onSwipe |
direction |
A slide up, down, left or right, set on a screen. |
A stroke of 40 pixels is a swipe while the finger is still down, and a quick flick of 20 pixels is
one as it lifts. A touch on a CellGrid, ButtonMatrix or AppList carries value, the cell,
button or app touched.
Inside an app every swipe is the app's own, and a right swipe does not go back. A swipe the
screen's onSwipe ignores, changing nothing and asking for nothing, goes on to the shell, so an app
opened from the quick-app ring that uses only up and down still steps round the ring.
Side button¶
Apps never hear the side button. A click goes back one of the app's screens, running the screen's
onHide as it leaves; on the app's first screen the shell goes back a step. On the watch face a
click turns the screen off. A long press or a 2 second hold goes to the face, and a double click
opens the notifications. A 5 second hold always resets the watch.
Widget values and screens¶
| Prop | On | Fields |
|---|---|---|
onChange |
Slider, Switch, Checkbox, Roller, and the rollers, DayButtons, Stepper and ConfirmBox |
value |
onPageChange |
Pages |
page |
onScrollEnd |
Scroll, List, AppList, TextFile |
offset, once the scroll, or a flung list's glide, ends |
onShow, onHide |
a Screen |
none; the screen comes into view or leaves it |
A widget whose value is a signal, such as <Slider value={volume} /> without .value, writes the
new value back itself, so onChange is only needed for anything else to happen.
System events¶
on(event, handler, options), at the top of the file and before define_app, connects a handler
to an event. Each becomes one of the image's subscriptions, so on inside a handler is an error.
Events other than the app's own life call their handler even while the app is closed, unless given
while_open: true.
on("open", start);
on("tick", update, { every: MINUTE });
on("time", ring, { at: next_ring_at });
on("shake", roll, { while_open: true, at_most_every: SECOND });
| Option | Means |
|---|---|
while_open |
true makes it come only while the app is open, which needs no background permission. Written out. |
every |
How often tick, heart_rate and acceleration come: milliseconds such as MINUTE, or a period such as { seconds: 1 } (milliseconds, seconds, minutes, hours), known when compiling. |
at |
When time comes, an Instant or a signal holding one; or the time of day daily comes, { hour, minute } or a signal holding one. |
days |
The weekdays daily comes on, a constant 7-bit mask with Monday in bit 0; every day when left out. |
at_most_every |
Skips the handler until this long has passed since it last ran. The handler must be a function the app defines. |
| Event | Fields | When |
|---|---|---|
open, close |
none | The app comes to the front, or leaves it. |
screen_on, screen_off |
none | The display turns on or off while the app is in front. |
tick |
time |
Every every, lined up with the clock, at most every 20 ms. Under a minute needs while_open: true. |
time |
time |
Once, at an absolute time. A signal reschedules it when it changes, and null turns it off. A time already passed comes at once. |
daily |
time |
At a local time of day, on the weekdays in days. A signal holding null turns it off. |
minute, hour, day |
time |
The local minute, hour or day changes, or the phone sets the clock. |
heart_rate |
beats_per_minute, confidence |
A measurement every every. Apps asking share one measurement. |
steps |
steps_today |
The step count changes, at most once a minute. |
step_goal |
steps_today |
The day's step goal is reached. |
shake |
kind |
A shake, found while the app is open and the screen is on. |
wrist_raise, wrist_tap, wrist_double_tap, still, moving |
kind |
Accepted, but the watch does not send them yet. |
acceleration |
x, y, z in thousandths of g |
Raw readings every every, at most 10 a second. Needs while_open: true, and comes only while the screen is on. |
battery_low, charging_starts, charging_stops, charging_completes |
percent |
The battery goes low, or charging starts, stops or completes. |
phone_connects, phone_disconnects |
is_connected |
The phone connects or disconnects. |
notification |
id, app, title, body, time |
A notification arrives from the phone. |
call |
kind, caller |
A call is incoming, answered or ended. |
music, weather, navigation |
none | The phone's player, forecast or navigation changes; read the new values from current_music, current_weather or current_navigation. |
settings_change |
key |
A setting changes, from the watch or the phone. key is its name as set_setting takes it, or do_not_disturb. |
When several of the same event are waiting, only the latest is delivered. A closed app hears only
its timers: tick, time, daily, the clock changes and heart_rate. A handler run in the
background may vibrate and notify; wake_screen brings the app to the front on the screen its go
named.
Widgets¶
The app host draws each widget from its values. The second column of each table names the LVGL widget it matches, where there is one. Each widget takes the common props plus its own.
Common props¶
| Prop | Holds |
|---|---|
x, y |
A place in pixels inside the parent's padding, taking the widget out of the flow. |
width, height |
Pixels, or "100%" and other percentages; left out, the layout decides. size (or diameter) sets both. |
grow |
The share of spare space this widget takes in a Row or Column. |
padding, margin |
Space inside and outside the widget. Both start at 0. |
background, color, border_color |
"#rrggbb" or a theme name: background, surface, text, muted, accent, success, warning or danger. A theme name follows the user's theme. |
border_width, radius |
The border and corner rounding. |
font |
One of the fonts. |
align |
start, center or end, across the parent's flow. |
opacity |
0 to 255, multiplied down through children. |
animate |
Accepted, but the watch does not animate yet; the value jumps. |
Containers (Screen, Column, Row, Card, Page, Scroll, List) also take gap, the
pixels between children, justify along the flow (start, center, end, space_between) and
align_items across it (those, and stretch). A Button takes disabled, which greys it out and
ignores touches.
Keep 8 pixels between content and the screen's edges, with padding={8} on the screen, and 6 to 8
pixels between controls, with gap. Leave the padding out only for content meant to fill the
screen, such as a game board.
Fonts¶
| Font | Capital height | Use |
|---|---|---|
small |
12 px | Dense text, such as a list's second line. |
normal |
14 px | Body text; the default. |
medium |
22 px | Headings and values. |
large |
31 px | Big values. |
huge |
57 px | A clock face's digits. |
giant |
87 px | The biggest digits; proportional, the rest monospaced. |
condensed |
35 px | Narrow tall text, such as a stopwatch's time. |
dot_matrix |
7 dots | Digits, capitals, -, :, . and / drawn as dots; lower case shows as capitals. |
Every text font draws printable ASCII, the Latin-1 letters and signs, curly quotes, dashes, the
ellipsis, bullet and euro sign, and °±×÷←✓✕. All live in the shared library.
Layout¶
| Widget | LVGL | Use |
|---|---|---|
Screen |
The outermost widget of a screen: a Column, or a Row with direction="row". Takes onSwipe, onShow and onHide, and the touch events. |
|
Column, Row |
container, flex | Children one after another, down or across. |
Grid |
container, grid | Children in rows of columns, such as a keypad. |
Stack |
container | Children on top of each other, such as text over an image. |
Scroll |
scroll view | Content longer than its space, scrolled by dragging and flung to glide. |
List |
list | A scrolling list of rows. A .map inside it is one repeated row, and with a fixed row height the watch builds only the rows on screen. |
Pages |
tile view | Pages side by side, one on show, swiped left and right with a wipe, and a bar along the bottom. value is the page on show; onPageChange hears each turn, and an app that turns pages itself binds value to a signal it also sets there. A swipe past either end goes to the screen's onSwipe. |
Page |
One page of a Pages: a Column that fills it, or with scrolls a Scroll. scrolls is written out. |
Scroll and List take:
| Prop | Holds |
|---|---|
direction |
"column", the default, to scroll down, or "row" to scroll across; a repeated row across a List needs a fixed width to be built only while in view. |
scrolling |
"smooth", the default, follows the finger and glides when flung; "pages" settles on a whole page when the finger lifts: a drag of 20 pixels or more turns the page. |
scroll_bar |
false leaves the bar out. While the content is longer than the widget, the watch draws a 2-pixel bar down its right edge, or along the bottom when it runs across, and keeps 4 pixels for it: a thumb over a dim track, or a segment per page. |
All three are written out in the source.
Showing things¶
| Widget | LVGL | Use and props |
|---|---|---|
Label |
label | Text. text_align (left, center, right); long_mode: wrap (the default, at spaces), scroll (one line, sliding back and forth) or clip. |
Icon |
image | A shared library icon, drawn in color at size. |
Image |
image | src, a PNG beside the source or a library icon; recolor draws a one-colour image in that colour; width and height for one that is not square. |
Line |
line | points, a fixed-length array of { x, y } in the parent's pixels, joined in order; thickness. |
Arc |
arc | A ring or part of one from value between minimum and maximum; start_angle, end_angle, thickness, track_color, diameter. Its children are stacked in its middle. It cannot be dragged yet. |
Bar |
bar | A straight progress bar: value, minimum, maximum, track_color. |
Led |
led | A dot in color, with diameter. |
Chart |
chart | values, one array drawn in color, with minimum and maximum. series takes only its first series on the watch. |
Scale |
scale | Ticks around a dial: ticks, major_every, labels for the major ticks, major_color, skip for ticks to leave out, start_angle and end_angle for a part dial, and value with needle_color for a gauge. |
AnalogClock |
Hands for time (normally now.value): show_seconds, hour_color, minute_color, second_color, hour_length, minute_length, second_length, and hand_style (line, tapered, rounded). |
|
CellGrid |
A board of coloured cells from one array, such as Life, Snake or 2048, as one widget however many cells. See below. | |
BatteryGauge |
A battery outline filled to value percent, with a bolt while charging; single_color, show_bolt, show_percent. |
|
StatusRow |
Status icons chosen by status_flags (1 notifications, 2 the phone, 4 an alarm), then a battery; icon_size, gap, and the battery props. |
|
Badge |
An icon with text beside it as one widget; icon_size, gap, recolor for the icon. |
|
AppList |
The installed apps, each its icon and name, as one widget however many. See below. | |
TextFile |
A text file from storage, wrapped and scrolled: path, font_path (a file naming small, normal, medium or large, which wins over font), placeholder shown in muted while the file is missing or empty, and scrolling and scroll_bar. Only the lines near the view are read into RAM. The file is read when its screen opens; at most 32,767 pixels of lines are shown. |
|
TextLines |
The last lines of text kept as character codes: codes, an array signal, and length, how many are in use. Wraps at spaces and breaks at new lines. |
|
BitmapFile |
A one-bit picture from storage, such as a QR code: path, and value, a number written after the path, so path="/qr/" with value={2} shows /qr/2. The file is a width and a height of at most 120, then each row packed eight pixels to a byte, leftmost in the high bit; set pixels draw in color, each as large a square as fits. |
CellGrid props: columns, rows, cell_size (the side of one cell; without it the cells grow to
fill the widget), cell_gap (pixels between cells), cell_shape (square, rounded, round),
cells (one number per cell, a colour from palette), palette (a constant array or an array
signal), show_numbers with number_map and number_colors to draw each non-zero cell's number,
and onClick and onDrag receiving { value }, the cell's number.
AppList props: gap between rows, color for icons and names, first and count for one run of
installed_apps, sections for every app under its group's name, columns above 1 for square
cells that many across, scrolling and scroll_bar, and onClick receiving { value }, the app's
place in installed_apps. Rows are 52 pixels tall.
Input¶
| Widget | LVGL | Use and props |
|---|---|---|
Button |
button | A tappable button with text or an icon; disabled. Its background is surface and its radius 12 unless set. |
ClickArea |
An invisible area that takes touches; its children are stacked down it. | |
Switch |
switch | On or off; value a boolean or a signal. |
Checkbox |
checkbox | Ticked or not, with its children as the label; value a boolean or a signal. |
Slider |
slider | A value dragged along a track: value, minimum, maximum, step. |
Roller |
roller | A wheel of options; value is the chosen option's number. |
ButtonMatrix |
button matrix | A grid of buttons drawn as one widget: rows, an array of rows of labels, written out; onClick receives { value }, the button counted across the rows; highlighted lists labels drawn in the accent colour (the first 32 buttons only). |
NumberRoller |
Rollers for a number from minimum to maximum, padded to digits. |
|
TimeRollers |
Hour and minute rollers for value, a minute of the day; twelve_hour adds AM and PM. |
|
DurationRollers |
Rollers for value in seconds; show_hours. |
|
DayButtons |
Seven day buttons over value, a day mask; columns a row. |
|
Stepper |
Minus and plus buttons around the value or its text, stepping by step between minimum and maximum. |
|
ConfirmBox |
A question and two buttons: text holds the cancel button's text, the confirm button's and the question, each on its own line; onChange sends 1 or 0. |
The rollers, DayButtons, Stepper and ConfirmBox send the new value to onChange; the
components below bind them to signals.
Components¶
These come from battletime/components, built from the widgets above. The compiler inlines each into
the app.
| Component | Use |
|---|---|
Card |
A rounded panel in surface, radius 12, padding 10 and gap 4 unless set: the standard block of an app's layout. |
Header |
A screen's title row, with an optional icon and color. |
ScrollBar |
For paging by hand: one segment per page down the right edge for page of pages. Put it straight in a Screen without padding, and pad the content beside it by 4 or more; Pages draws its own bar. |
BatteryIcon |
The watch's own battery as one widget: show_percent, color, single_color, show_bolt. |
StatusIcons |
The status row bound to the system: notifications while any are unread, the phone while connected, the alarm with show_alarm, then the battery. icon_size, gap, color, battery_color, align. |
StepsBadge, HeartRateBadge, TemperatureBadge |
Today's steps, the heart rate while measured, or the temperature in the wearer's units, beside an icon. icon_size, gap, icon_color, align; TemperatureBadge takes the weather icon. |
ConfirmDialog |
A question with two buttons, shown while the open signal is true and closing itself on either: confirm_text, cancel_text, onConfirm, onCancel. |
NumberPicker, TimePicker, DurationPicker |
Rollers writing back to a signal. TimePicker follows the 12 or 24 hour setting. |
WeekdayPicker |
Day buttons toggling a signal of day bits, Monday in bit 0; columns a row. |
Icons¶
icons.<name> names a shared library icon: alarm, backspace, battery, bell, bell_off,
bluetooth, calculator, calendar, charging, chart, chat, check, clear, clock,
close, clouds, dice, few_clouds, flag, flashlight, game, heart, heavy_clouds,
info, level, metronome, minus, mist, moon, music, navigation, news, next,
none (empty), note, notification, pause, phone, phone_missed, pine_logo, play,
plus, previous, qr_code, rain, remote, settings, showers, sms, snow, steps,
stop, stopwatch, sun, thunderstorm, timer, the turn_ arrows (arrive, left, right,
roundabout, sharp_left, sharp_right, slight_left, slight_right, straight, u_turn),
voicemail, volume_down, volume_up, weather, weather_night_clear and
weather_night_cloudy.
| Function | Gives |
|---|---|
icon_named(name) |
The icon of that name, for one chosen by state, such as icon_named(`turn_${turn}`). |
library_icon(index) |
The icon at that place in the library's order (ICON_NAMES in compiler/src/types.rs), or none outside it, for an icon a file chose by number. New icons go at the end. |
Not available yet¶
The compiler knows these LVGL names, but the SDK offers no component for them and the watch draws
each as an empty box: Tabs, RichText, AnimatedImage, ArcLabel, Table, Calendar,
ImageButton, Radio, Spinbox, Dropdown, TextArea and Keyboard. Spinner is in the SDK
and the preview but draws as an empty box on the watch. These props are left out with a warning:
brightness on Led, visible_rows on Roller, kind on Chart and rounded on Line.
Left out for good: a canvas, whose pixel buffer would not fit in RAM (draw with Line, Arc and
Image); windows and message boxes, which Header and ConfirmDialog cover.
Effects¶
Effects are calls a handler makes to ask the system to do something. They run after the handler finishes without failing, in the order they were called.
Haptics¶
| Effect | Does |
|---|---|
vibrate(milliseconds) |
Runs the motor once, capped at 2 seconds. |
vibrate_pattern(pattern) |
tap, double_tap, notification, alarm, success or failure. alarm repeats until stop_vibrating(), the app closes, or a minute passes. |
stop_vibrating() |
Stops any pattern this app started. |
During do not disturb the watch plays only vibrate_pattern("alarm"), and only while
settings.alarms_in_do_not_disturb is on; every other vibration, notify's included, is skipped.
Display and navigation¶
| Effect | Does |
|---|---|
set_brightness(level) |
Sets the backlight, 1 to 3, until the app closes. |
keep_screen_on(on) |
Stops the screen turning off by itself while this app is in front. |
wake_screen() |
Turns the screen on and brings this app to the front. |
screen_off() |
Turns the screen off now. |
go(screen) |
Shows another of this app's screens. From an onSwipe it slides in the way the swipe went; otherwise it wipes in from the right. |
back() |
Returns to the previous screen, or leaves the app from its first one. |
open_app(id) |
Opens another installed app; the id may be worked out, such as installed_apps.value[i].id. |
close() |
Leaves the app for the watch face. |
show_toast(text) |
Shows a short message over the screen for two seconds. |
Notifications and phone¶
| Effect | Does |
|---|---|
notify(title, body) |
Adds a notification on the watch under the app's name. |
dismiss_notification(id) |
Removes a notification. |
mark_notifications_read() |
Marks every notification read. |
send_to_phone(channel, data) |
Sends the companion {"t":"app","ch":channel,"d":data}, such as send_to_phone("remote", { button: 2 }). data is up to 4 whole numbers; the channel and keys are written out, each 1 to 32 letters, digits, _ or -. See companion-protocol.md. |
music_control(command) |
play, pause, next, previous, volume_up or volume_down. |
call_control(command) |
answer, reject or mute the current call. |
find_phone(on) |
Makes the phone ring, or stops it. |
request_music_state(), request_navigation_state() |
Asks the companion for the player's state or the navigation step now; the answer arrives as the music or navigation event. Gadgetbridge ignores them. |
Sensors¶
| Effect | Does |
|---|---|
measure_heart_rate() |
Takes one reading now; it updates heart_rate. |
start_heart_rate(), stop_heart_rate() |
Measures continuously while the app is open; it stops when the app closes. stop_heart_rate() ends only this app's own measuring. |
set_heart_rate_led(on, brightness, period) |
Drives the sensor's LED directly, such as for a beacon: brightness 0 to 3, period the flash period in milliseconds, 0 for steady. Turned off when the app closes. |
reset_step_trip() |
Starts step_history.trip from zero. |
System and storage¶
| Effect | Does |
|---|---|
set_setting(key, value) |
Changes a setting by name: any key of settings, brightness (1 to 3), do_not_disturb or bluetooth. Booleans are 1 or 0, and a value outside its limits is ignored. |
set_do_not_disturb(on) |
Turns do not disturb on or off. |
set_bluetooth(on) |
Turns Bluetooth on or off; a restart turns it on again. |
set_clock(year, day_of_year, minute_of_day) |
Sets the clock to a local time at 00 seconds; day_of_year counts from 1, minute_of_day from 0. A day or minute that does not exist, or a year outside 1970 to 2200, is ignored. |
step_watch_face(steps) |
Shows the face steps places on among the faces turned on, wrapping round, and saves it in watch_face. |
set_app_enabled(id, on) |
Turns an installed app or face on or off; does nothing when packages gives a refusal. |
confirm_firmware() |
Keeps a firmware on trial, so a restart no longer rolls it back. |
roll_back_firmware() |
Restarts a firmware on trial without confirming it, bringing back the one before. |
open_folder(path) |
Lists a folder into current_folder soon after the handler ends. The path may be worked out, such as `${current_folder.value.path}/..`; .. never climbs above the top, and a path over 64 bytes lists nothing. Needs 1,600 B more heap. |
prefetch_file(path, offset, length) |
Starts reading up to 4,096 bytes of a file into RAM in the background, so the next file_bytes of that part takes them without waiting. One part is held at a time. Needs 4 KB more heap. |
log(text) |
Writes a line to the debug log. |
Functions¶
These are plain functions, usable in views, computed and handlers unless marked otherwise.
Numbers¶
Every number is a 64-bit whole number; there are no fractions. For decimals, keep a fixed number of
places in a whole number and show it with format_fixed. A bare / is refused: write
Math.trunc(a / b), Math.floor, Math.ceil or Math.round to say how it rounds. Math.min,
Math.max and Math.abs are accepted, and so are &, |, ^, ~, << and >>. Overflow,
division by zero and a shift outside 0 to 63 fail the call.
| Function | Returns |
|---|---|
random_int(lowest, highest) |
A random whole number between the two, both included. Handlers only. |
clamp(value, lowest, highest) |
value kept between the two. |
Text¶
Template literals, such as `${steps} steps`, join text and numbers.
| Function | Returns |
|---|---|
format_number(number, minimum_digits?) |
The number as text, padded with zeros. |
format_fixed(value, places, trim?) |
format_fixed(1250, 3) is 1.250; with trim, trailing zero decimals are left off. |
format_duration(duration, pattern) |
The duration in a pattern, such as "mm:ss". |
format_time(instant, pattern) |
The local time in a pattern, such as "dddd D MMMM", or a named pattern. |
format_temperature(celsius) |
The temperature in the user's units, with its sign. |
to_upper(text) |
The text in capitals. |
pad_start(text, width, character?) |
The text padded in front with spaces, or one literal character. |
text_length(text) |
The number of characters. |
slice_text(text, start, end?) |
Part of the text, counted in characters; negative counts from the end. |
join(texts, separator) |
The texts of a fixed-length array joined. |
text_from_codes(codes, length) |
Text from the first length character codes of an array signal. |
.toUpperCase(), .slice(), .padStart() and .length work on text too.
Format patterns¶
A pattern is a literal string, or a ? : choice between literals, so the compiler checks it, and
the watch checks it again at install. Text inside [brackets] is copied as it is, and so is any
character that is not a letter.
| Time token | Shows |
|---|---|
YYYY |
The year, such as 2026. |
MMMM, MMM |
The month's name, such as October or Oct. |
MM, M |
The month's number, 01 to 12 or 1 to 12. |
DD, D |
The day of the month. |
dddd, ddd |
The weekday's name, such as Sunday or Sun. |
HH, H |
The hour on a 24 hour clock. |
hh, h |
The hour on a 12 hour clock. |
mm, m |
The minute. |
ss, s |
The second. |
a, A |
am or pm, AM or PM. |
The named patterns follow the 12 or 24 hour setting: "clock" is HH:mm or h:mm,
"clock_with_seconds" adds :ss, and "date" is YYYY-MM-DD.
| Duration token | Shows |
|---|---|
hh, h |
Hours. |
mm, m |
Minutes. |
ss, s |
Seconds. |
cc |
Hundredths of a second, two digits. |
The largest unit in a duration pattern shows the whole amount, so mm:ss shows 75 minutes as
75:03. A binding redraws as often as the smallest unit its pattern shows: every second with ss,
ten times a second with cc, and otherwise once a minute.
Time¶
All in local time.
| Function | Returns |
|---|---|
year_of, month_of, day_of, hour_of, minute_of, second_of |
That part of an instant. |
weekday_of(instant) |
0 to 6, Monday first. |
start_of_minute, start_of_hour, start_of_day |
The start of that local minute, hour or day. A view that shows only these redraws once a minute. |
next_time_of_day(after, { hour, minute }, days?) |
The first instant after after at that time, on one of days. |
day_of_year(instant) |
1 to 366. |
iso_week_of(instant) |
The ISO 8601 week number. |
Shared library¶
From battletime/lib. These run in the shared library, so an app
carries only a 5-byte call, except sine, cosine and point_on_circle, which work only with
arguments known when compiling.
| Function | Returns |
|---|---|
sine(degrees), cosine(degrees) |
In thousandths. |
point_on_circle(center_x, center_y, radius, degrees) |
{ x, y }, 0 degrees at the top, clockwise. |
display_hour(instant) |
0 to 23 on a 24 hour clock, else 1 to 12. |
minute_of_day(instant) |
0 to 1439. |
is_night(instant) |
Whether it is between sunset and sunrise, or 18:00 to 06:00 until the phone sends them. |
steps_since(base) |
Steps since today's count was base, counting on after midnight's reset. |
temperature_in_unit(celsius) |
Whole degrees in the wearer's units. |
digit_of(value, place) |
One decimal digit: place 1 for the units, 10 for the tens. |
sunday_week_of(instant) |
The week counted from the year's first Sunday, as strftime's %U. |
days_in_year(year) |
366 or 365. |
weather_icon_at(instant) |
The current weather's icon, with the moon at night. |
weather_condition_name(condition) |
Clear, Cloudy, Rain, Showers, Thunder, Snow or Mist. |
temperature_color(celsius) |
InfiniTime's colour for a temperature, blue when freezing to deep orange when hot. |
format_time_of_day(hour, minute) |
07:30, or 07:30 AM on a 12 hour clock. |
day_mask_name(days) |
Once, Every day, Weekdays, Weekends, or a letter a day such as M-W----. |
Records and arrays¶
State may hold records of a fixed shape and fixed-length arrays of numbers or records, such as a
list of alarms { hour, minute, days, enabled }. A handler may write one element, as in
board.value[cell] = 2, or one field, as in alarms.value[i].enabled = true; writes apply when the
handler finishes, and later reads in the same handler see them.
Text in state can only be one of the app's own literal strings. Keep text made while running as an
array of character codes and show it with text_from_codes or TextLines.
Assigning a whole array follows JavaScript: the right side reads the old array throughout. A local
holds one value, so an array cannot be kept in a handler's const or let. An app's state is at
most 2 KB and 64 variables, one array at most 1 KB, and each array stores its elements in 1, 2, 4 or
8 bytes, whichever fits. One handler may change at most 16 variables and 1 KB of state.
| Function | Returns |
|---|---|
range(count) |
0 to count - 1, with count known when compiling. |
array.map(...) |
A new array of the same length. |
array.includes(value), array.indexOf(value) |
Whether the value is there, and where, or -1. |
count_where(array, test) |
How many elements pass the test. |
count_of(array, value) |
How many elements equal the value. |
nth_index_of(array, value, n) |
Where the nth element equal to the value is, from 0, or -1. |
arrays_equal(first, second) |
Whether two arrays of one length hold the same elements. |
line_through(grid, width, cell, value) |
The longest line of the value through the cell, across, down or diagonally. |
slide_grid(grid, width, direction) |
The grid slid as in 2048, equal pairs merging once. |
slide_points(grid, width, direction), slide_changes(...), can_slide(grid, width) |
What a slide scores, whether it changes the grid, and whether any slide would. |
count_inversions(array) |
How many pairs are out of order, at most 64 elements. |
shuffled(array, first, count) |
The array with count elements from first in a random order. Handlers only. |
push_shift(array, value), unshift_pop(array, value) |
The array moved one place with the value added at the end or the front, as for a history of laps. |
life_step(grid, width, live_value) |
The Game of Life's next generation on a wrapping grid, at most 16 wide. |
file_bytes(path, length, offset?) |
length bytes of a file from offset, each 0 to 255, 0 past the end or when the file is missing. path is written out and length known when compiling; offset may be worked out, to page through a file larger than RAM. Read when the handler runs, unless prefetch_file already read that part. |
The functions from count_of down, and includes and indexOf on an array signal of numbers, run
natively in the firmware, so they cost a few bytes where a loop costs dozens. Their arrays must be
signals of numbers or parameters given one. slide_grid, life_step, push_shift, unshift_pop,
shuffled and file_bytes give a whole array, so they may only be assigned to an array signal of
the same length in a handler, as in board.value = life_step(board.value, 16, 1). A grid is
numbered across each row from the top left.
Control flow¶
if, for ... of over a fixed-length array, early return, break and continue are allowed.
A call runs at most 200,000 steps; a game search should stop well inside that, or split its work
across several calls.
Permissions¶
The compiler works out the permissions an app needs from the effects, events and system values it uses, and reports them; the image does not hold them yet.
| Permission | Covers |
|---|---|
heart_rate |
The heart_rate event, the heart rate effects and set_heart_rate_led. |
motion |
The motion events, such as shake, and acceleration. |
notifications |
Reading notifications, the notification event and the notification effects. |
phone |
call_control, music_control, find_phone, request_music_state, request_navigation_state, reading current_call, current_music and current_navigation, and the call, music and navigation events. |
phone_messages |
send_to_phone. |
internet |
Web requests, which the bytecode does not carry yet. |
settings |
set_setting, set_do_not_disturb, set_bluetooth, set_app_enabled, set_clock, step_watch_face, confirm_firmware and roll_back_firmware. |
wake |
wake_screen. |
background |
Events other than the app's own life connected without while_open: true. |
Reading other system values and files, the screen, haptics and navigation need no permission.
Not in the bytecode yet¶
vibrate_sequence and http_request are in the SDK, but the compiler refuses them, because they
need an array or object argument. The message and http_response events are not in the image
format.