Alloy provides access to Pebble hardware sensors and button input through simple JavaScript APIs. Sensors follow the ECMA-419 Sensor Class Pattern, while the Button class is a Pebble-specific API.
Note: All code in this guide runs on the watch in
src/embeddedjs/main.js.
Handle button presses using the Button class:
import Button from "pebble/button";
new Button({
types: ["select", "up", "down", "back"],
onPush(down, type) {
console.log((down ? "press " : "release ") + type);
}
});
Note: If your app includes
"back"in thetypesarray, the back button no longer exits the app automatically - press and hold back to exit instead. If you don't include"back", pressing back exits as usual.
| Type | Description |
|---|---|
"select" |
Middle button (center right) |
"up" |
Top button |
"down" |
Bottom button |
"back" |
Back button (left side) |
The onPush callback receives two parameters:
down - Boolean: true when pressed, false when releasedtype - String: which button was pressedRead motion data from the accelerometer:
import Accelerometer from "embedded:sensor/Accelerometer";
const accel = new Accelerometer({
onSample() {
const sample = this.sample();
console.log("accel " + sample.x + ", " + sample.y + ", " + sample.z);
},
onTap(direction) {
console.log("single tap " + direction);
},
onDoubleTap(direction) {
console.log("double tap " + direction);
}
});
// Configure sample rate (Hz)
accel.configure({ hz: 10 });
The sample() method returns an object with:
| Property | Description |
|---|---|
x |
Acceleration on X axis |
y |
Acceleration on Y axis |
z |
Acceleration on Z axis |
| Event | Description |
|---|---|
onSample() |
Called when new sensor data is available |
onTap(direction) |
Called on single tap gesture |
onDoubleTap(direction) |
Called on double tap gesture |
accel.configure({
hz: 10 // Sample rate in Hz (samples per second)
});
Read the magnetic heading from the compass:
import Compass from "embedded:sensor/Compass";
const compass = new Compass({
onSample() {
const sample = this.sample();
console.log("heading " + sample.heading);
}
});
| Property | Description |
|---|---|
heading |
Magnetic heading in degrees (0-360) |
Get the user's GPS location via the phone:
import Location from "embedded:sensor/Location";
const location = new Location({
onSample() {
const sample = this.sample();
console.log("Location: " + sample.latitude + ", " + sample.longitude);
this.close();
}
});
The Location sensor follows the same ECMA-419 pattern as other sensors but has a few differences:
this.close() after receiving the sample. Location is a
request, not a continuous monitor.@moddable/pebbleproxy package."location" to the capabilities array in
package.json.| Property | Type | Description |
|---|---|---|
latitude |
Number | Latitude in decimal degrees |
longitude |
Number | Longitude in decimal degrees |
You can optionally configure the location request immediately after creating the instance:
location.configure({
enableHighAccuracy: false,
timeout: 5000,
maximumAge: 0
});
| Option | Description |
|---|---|
enableHighAccuracy |
Request high-accuracy GPS (uses more battery) |
timeout |
Maximum time in ms to wait for a location |
maximumAge |
Accept a cached location up to this many ms old |
The Location sensor requires the @moddable/pebbleproxy package. Set up
src/pkjs/index.js:
const moddableProxy = require("@moddable/pebbleproxy");
Pebble.addEventListener('ready', moddableProxy.readyReceived);
Pebble.addEventListener('appmessage', moddableProxy.appMessageReceived);
No custom location code is needed in PKJS - the proxy handles GPS lookup automatically.
Monitor battery level and charging state:
import Battery from "embedded:sensor/Battery";
const battery = new Battery({
onSample() {
const sample = this.sample();
console.log("battery " + sample.percent + "%, charging " +
sample.charging + ", plugged " + sample.plugged);
}
});
// Get current state immediately
const status = battery.sample();
console.log("battery " + status.percent + "%");
| Property | Type | Description |
|---|---|---|
percent |
Number | Battery level (0-100) |
charging |
Boolean | Whether battery is charging |
plugged |
Boolean | Whether charger is connected |
Monitor connection to the phone:
function logConnected() {
console.log("App connected: " + watch.connected.app);
console.log("PebbleKitJS connected: " + watch.connected.pebblekit);
}
watch.addEventListener('connected', logConnected);
logConnected();
The watch.connected object has two properties:
| Property | Description |
|---|---|
app |
Whether the Pebble app is connected |
pebblekit |
Whether PebbleKit JS is ready for messaging |
Here's a complete example that displays sensor data:
import Poco from "commodetto/Poco";
import Button from "pebble/button";
import Accelerometer from "embedded:sensor/Accelerometer";
import Battery from "embedded:sensor/Battery";
const render = new Poco(screen);
const font = new render.Font("Gothic-Regular", 18);
const black = render.makeColor(0, 0, 0);
const white = render.makeColor(255, 255, 255);
let accelData = { x: 0, y: 0, z: 0 };
let batteryPercent = 0;
let lastButton = "none";
// Setup accelerometer
const accel = new Accelerometer({
onSample() {
accelData = this.sample();
draw();
}
});
accel.configure({ hz: 10 });
// Setup battery monitor
const battery = new Battery({
onSample() {
batteryPercent = this.sample().percent;
draw();
}
});
batteryPercent = battery.sample().percent;
// Setup button handler
new Button({
types: ["select", "up", "down"],
onPush(down, type) {
if (down) {
lastButton = type;
draw();
}
}
});
function draw() {
render.begin();
render.fillRectangle(white, 0, 0, render.width, render.height);
render.drawText("Battery: " + batteryPercent + "%", font, black, 10, 10);
render.drawText("Button: " + lastButton, font, black, 10, 35);
render.drawText("Accel X: " + accelData.x.toFixed(2), font, black, 10, 60);
render.drawText("Accel Y: " + accelData.y.toFixed(2), font, black, 10, 85);
render.drawText("Accel Z: " + accelData.z.toFixed(2), font, black, 10, 110);
render.end();
}
draw();
When using the Pebble emulator, you can simulate sensor input:
$ pebble emu-battery --percent 20 --charging --qemu localhost:12344
$ pebble emu-accel tilt-left --qemu localhost:12344
Clean up resources: Sensors continue to consume power while active. Stop them when not needed.
Appropriate sample rates: Higher accelerometer sample rates use more power. Use the lowest rate that meets your needs.
Handle disconnection gracefully: Check connection status before attempting network operations.
The Pebble Examples repository includes sensor and input examples:
hellobutton - subscribing to button press and release eventshelloaccelerometer - reading accelerometer data and detecting tapshellobattery - monitoring battery level and charging statehellolocation - getting GPS location from the phonepiu/apps/gravity - visualizes accelerometer readings with an animated displaypiu/apps/compass - visualizes compass readings with a rotating compass rose