pebble/devsite/source/_guides/events-and-services/events.md
2025-02-24 18:58:29 -08:00

10 KiB

title description guide_group order related_docs
Event Services How to use the various asynchronous event services to power app features. events-and-services 5
TickTimerService
ConnectionService
AccelerometerService
BatteryStateService
HealthService
AppFocusService
CompassService

All Pebble apps are executed in three phases, which are summarized below:

  • Initialization - all code from the beginning of main() is run to set up all the components of the app.

  • Event Loop - the app waits for and responds to any event services it has subscribed to.

  • Deinitialization - when the app is exiting (i.e.: the user has pressed Back from the last Window in the stack) app_event_loop() returns, and all deinitialization code is run before the app exits.

Once app_event_loop() is called, execution of main() pauses and all further activities are performed when events from various Event Service types occur. This continues until the app is exiting, and is typically handled in the following pattern:

static void init() {
  // Initialization code here
}

static void deinit() {
  // Deinitialization code here
}

int main(void) {
  init();
  app_event_loop();
  deinit();
}

Types of Events

There are multiple types of events an app can receive from various event services. These are described in the table below, along with their handler signature and a brief description of what they do:

Event Service Handler(s) Description
TickTimerService TickHandler Most useful for watchfaces. Allows apps to be notified when a second, minute, hour, day, month or year ticks by.
ConnectionService ConnectionHandler Allows apps to know when the Bluetooth connection with the phone connects and disconnects.
AccelerometerService AccelDataHandler
AccelTapHandler
Allows apps to receive raw data or tap events from the onboard accelerometer.
BatteryStateService BatteryStateHandler Allows apps to read the state of the battery, as well as whether the watch is plugged in and charging.
HealthService HealthEventHandler Allows apps to be notified to changes in various HealthMetric values as the user performs physical activities.
AppFocusService AppFocusHandler Allows apps to know when they are obscured by another window, such as when a notification modal appears.
CompassService CompassHeadingHandler Allows apps to read a compass heading, including calibration status of the sensor.

In addition, many other APIs also operate through the use of various callbacks including MenuLayer, AppMessage, Timer, and Wakeup, but these are not considered to be 'event services' in the same sense.

Using Event Services

The event services described in this guide are all used in the same manner - the app subscribes an implementation of one or more handlers, and is notified by the system when an event of that type occurs. In addition, most also include a 'peek' style API to read a single data item or status value on demand. This can be useful to determine the initial service state when a watchapp starts. Apps can subscribe to as many of these services as they require, and can also unsubscribe at any time to stop receiving events.

Each event service is briefly discussed below with multiple snippets - handler implementation example, subscribing to the service, and any 'peek' API.

Tick Timer Service

The TickTimerService allows an app to be notified when different units of time change. This is decided based upon the TimeUnits value specified when a subscription is added.

The struct tm pointer provided in the handler is a standard C object that contains many data fields describing the current time. This can be used with strftime() to obtain a human-readable string.

static void tick_handler(struct tm *tick_time, TimeUnits changed) {
  static char s_buffer[8];

  // Read time into a string buffer
  strftime(s_buffer, sizeof(s_buffer), "%H:%M", tick_time);

  APP_LOG(APP_LOG_LEVEL_INFO, "Time is now %s", s_buffer);
}
// Get updates when the current minute changes
tick_timer_service_subscribe(MINUTE_UNIT, tick_handler);

The TickTimerService has no 'peek' API, but a similar effect can be achieved using the time() and localtime() APIs.

Connection Service

The ConnectionService uses a handler for each of two connection types:

  • pebble_app_connection_handler - the connection to the Pebble app on the phone, analogous with the bluetooth connection state.

  • pebblekit_connection_handler - the connection to an iOS companion app, if applicable. Will never occur on Android.

Either one is optional, but at least one must be specified for a valid subscription.

static void app_connection_handler(bool connected) {
  APP_LOG(APP_LOG_LEVEL_INFO, "Pebble app %sconnected", connected ? "" : "dis");
}

static void kit_connection_handler(bool connected) {
  APP_LOG(APP_LOG_LEVEL_INFO, "PebbleKit %sconnected", connected ? "" : "dis"); 
}
connection_service_subscribe((ConnectionHandlers) {
  .pebble_app_connection_handler = app_connection_handler,
  .pebblekit_connection_handler = kit_connection_handler
});
// Peek at either the Pebble app or PebbleKit connections
bool app_connection = connection_service_peek_pebble_app_connection();
bool kit_connection = connection_service_peek_pebblekit_connection();

Accelerometer Service

The AccelerometerService can be used in two modes - tap events and raw data events. AccelTapHandler and AccelDataHandler are used for each of these respective use cases. See the {% guide_link events-and-services/accelerometer %} guide for more information.

Data Events

static void accel_data_handler(AccelData *data, uint32_t num_samples) {
  APP_LOG(APP_LOG_LEVEL_INFO, "Got %d new samples", (int)num_samples);
}
const int num_samples = 10;

// Subscribe to data events
accel_data_service_subscribe(num_samples, accel_data_handler);
// Peek at the last reading
AccelData data;
accel_service_peek(&data);

Tap Events

static void accel_tap_handler(AccelAxisType axis, int32_t direction) {
  APP_LOG(APP_LOG_LEVEL_INFO, "Tap event received");
}
// Subscribe to tap events
accel_tap_service_subscribe(accel_tap_handler);

Battery State Service

The BatteryStateService allows apps to examine the state of the battery, and whether or not is is plugged in and charging.

static void battery_state_handler(BatteryChargeState charge) {
  // Report the current charge percentage
  APP_LOG(APP_LOG_LEVEL_INFO, "Battery charge is %d%%", 
                                                    (int)charge.charge_percent);
}
// Get battery state updates
battery_state_service_subscribe(battery_state_handler);
// Peek at the current battery state
BatteryChargeState state = battery_state_service_peek();

Health Service

The HealthService uses the HealthEventHandler to notify a subscribed app when new data pertaining to a HealthMetric is available. See the {% guide_link events-and-services/health %} guide for more information.

static void health_handler(HealthEventType event, void *context) {
  if(event == HealthEventMovementUpdate) {
    APP_LOG(APP_LOG_LEVEL_INFO, "New health movement event");
  }
}
// Subscribe to health-related events
health_service_events_subscribe(health_handler, NULL);

App Focus Service

The AppFocusService operates in two modes - basic and complete.

Basic Subscription

A basic subscription involves only one handler which will be fired when the app is moved in or out of focus, and any animated transition has completed.

static void focus_handler(bool in_focus) {
  APP_LOG(APP_LOG_LEVEL_INFO, "App is %s in focus", in_focus ? "now" : "not");
}
// Add a basic subscription
app_focus_service_subscribe(focus_handler);

Complete Subscription

A complete subscription will notify the app with more detail about changes in focus using two handlers in an AppFocusHandlers object:

  • .will_focus - represents a change in focus that is about to occur, such as the start of a transition animation to or from a modal window. will_focus will be true if the app will be in focus at the end of the transition.

  • .did_focus - represents the end of a transition. did_focus will be true if the app is now completely in focus and the animation has finished.

void will_focus_handler(bool will_focus) {
  APP_LOG(APP_LOG_LEVEL_INFO, "Will %s focus", will_focus ? "gain" : "lose");
}

void did_focus_handler(bool did_focus) {
  APP_LOG(APP_LOG_LEVEL_INFO, "%s focus", did_focus ? "Gained" : "Lost");
}
// Subscribe to both types of events
app_focus_service_subscribe_handlers((AppFocusHandlers) {
  .will_focus = will_focus_handler,
  .did_focus = did_focus_handler
});

Compass Service

The CompassService provides access to regular updates about the watch's magnetic compass heading, if it is calibrated. See the {% guide_link events-and-services/compass %} guide for more information.

static void compass_heading_handler(CompassHeadingData heading_data) {
  // Is the compass calibrated?
  if(heading_data.compass_status == CompassStatusCalibrated) {
    APP_LOG(APP_LOG_LEVEL_INFO, "Calibrated! Heading is %ld",
                             TRIGANGLE_TO_DEG(heading_data.magnetic_heading));
  }
}
// Subscribe to compass heading updates
compass_service_subscribe(compass_heading_handler);
// Peek the compass heading data
CompassHeadingData data;
compass_service_peek(&data);