PebbleKit
Introducing 2-way communication
Available in Pebble Kit 1.1
Download from developer.getpebble.com
Requires Pebble firmware 1.10.2
New opportunities for developers!
• Watchfaces augmented with data from the internet
• Remote controls for internet connec...
TWO-WAY COMMUNICATION OVERVIEW
Both sides can push updates
Updates are key-value pairs (dictionary)
{
/* icon */ 0: (uint8) 3,
/* temp */ 1: “42°C”
}
Key must be an integer
Value can only be a string, bytes, int or int8
App-channels identified by a shared UUID
42c86ea4-1c3e-4a07-b889-2cccca914198
Acknowledgements provided by the framework
Not all apps require two-way communication
CURRENT LIMITATIONS
Only the watchapp in the foreground can
send and receive notifications
Communication must be initiated by the
phone
Only one 3rd-party app at a time
Apps need to be whitelisted by Pebble
USING TWO-WAY COMMUNICATION
Pebble
AppMessage PBWatch Intent Bus
AndroidiOS
AppMessage Generic updates exchange
static void s_main(void *params) {
static PebbleAppHandlers s_handlers = {
...
.messaging_info = {
.buffer_sizes = {
.inbo...
static void s_main(void *params) {
static PebbleAppHandlers s_handlers = {
/* ... */
.messaging_info = {
/* ... */
.defaul...
void my_in_rcv_handler(DictionaryIterator *received, void *context) {
// incoming message received
}
void my_in_drp_handle...
DictionaryIterator *iter;
// Reserve the output buffer
app_message_out_get(&iter);
// Fill the buffer
dict_write_*(iter, ....
// Write data directly
dict_write_data(iter, KEY_DATA, data, sizeof(data));
dict_write_cstring(iter, KEY_STR, string);
dic...
Tuple *tuple = dict_read_first(&iter);
while (tuple) {
switch (tuple->key) {
case KEY_TO_A_DATA_VALUE:
foo(tuple->value->d...
dict_calc_buffer_size(2, sizeof(uint8_t), sizeof(char) * 8);
Evaluate the size of a dictionary
Dictionary
size = 1 + nTuples * 7 + Size1 + Size2 + ...
Evaluate the size of a dictionary
Dictionary
iOS Using AppMessage on iOS
[watch appMessagesGetIsSupported:^(PBWatch *watch, BOOL isAppMessagesSupported) {
if (isAppMessagesSupported) {
uint8_t by...
NSNumber *iconKey = @(0);
NSNumber *temperatureKey = @(1);
NSDictionary *update = @{ iconKey:[NSNumber numberWithUint8:wea...
id updateHandler;
/* ... */
[ourWatch appMessagesGetIsSupported:
^(PBWatch *watch, BOOL isAppMessagesSupported) {
if(updat...
Android Using AppMessage on Android
if (PebbleKit.areAppMessagesSupported()) {
PebbleDictionary data = new PebbleDictionary();
data.addUint8(ICON_KEY, (byte) ...
public class MyDataReceiver extends PebbleDataReceiver {
@Override
public void receiveData(final Context context,
final in...
Pebble
AppMessage PBWatch Intent Bus
AndroidiOS
AppSync
AppSync Synchronize watch fields
AppMessage
AppSync
A convenience layer on top of AppMessage
Maintains and updates a Dictionary
Provides a callback called ...
static void s_main(void *params) {
static PebbleAppHandlers s_handlers = {
...
.messaging_info = {
.buffer_sizes = {
.inbo...
Tuplet initial_values[] = {
TupletInteger(WEATHER_ICON_KEY, (uint8_t) 1),
TupletCString(WEATHER_TEMPERATURE_KEY, "42°C"),
...
#include <...>
AppSync sync;
uint8_t sync_buffer[32];
Reserve global memory to store a AppSync struct
Reserve global memor...
app_sync_init(&sync, sync_buffer, sizeof(sync_buffer),
initial_values, ARRAY_LENGTH(initial_values),
sync_tuple_changed_ca...
void sync_tuple_changed_callback(const uint32_t key,
const Tuple* new_tuple, const Tuple* old_tuple, void* context)
{
// U...
Tuplet new_tuples[] = {
TupletInteger(WEATHER_ICON_KEY, (uint8_t) 3),
TupletCString(WEATHER_TEMPERATURE_KEY, "73°C"),
};
a...
Pebble
AppMessage PBWatch Intent Bus
AndroidiOS
AppSync
THANK YOU!
@pebbledev
THANK YOU!
@pebbledev
Upcoming SlideShare
Loading in …5
×

Pebble Development - Using AppMessage for two way communication

8,165 views

Published on

This presentation introduces the AppMessage framework which is part of Pebble SDK. It allows developer to exchange messages between a watch and a phone with just a few APIs.

Pebble SDK is available from http://developer.getpebble.com

Published in: Technology, Business
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
8,165
On SlideShare
0
From Embeds
0
Number of Embeds
2,403
Actions
Shares
0
Downloads
40
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Pebble Development - Using AppMessage for two way communication

  1. 1. PebbleKit Introducing 2-way communication
  2. 2. Available in Pebble Kit 1.1 Download from developer.getpebble.com Requires Pebble firmware 1.10.2
  3. 3. New opportunities for developers! • Watchfaces augmented with data from the internet • Remote controls for internet connected devices • Multi-player Pebble games • 4sq/Facebook/Yelp Check-in Apps • Sports/Weather/News/Traffic tickers • Emergency beacon activator • Deeper sports integration • Bitcoin price trackers
  4. 4. TWO-WAY COMMUNICATION OVERVIEW
  5. 5. Both sides can push updates
  6. 6. Updates are key-value pairs (dictionary)
  7. 7. { /* icon */ 0: (uint8) 3, /* temp */ 1: “42°C” } Key must be an integer Value can only be a string, bytes, int or int8
  8. 8. App-channels identified by a shared UUID 42c86ea4-1c3e-4a07-b889-2cccca914198
  9. 9. Acknowledgements provided by the framework
  10. 10. Not all apps require two-way communication
  11. 11. CURRENT LIMITATIONS
  12. 12. Only the watchapp in the foreground can send and receive notifications
  13. 13. Communication must be initiated by the phone Only one 3rd-party app at a time Apps need to be whitelisted by Pebble
  14. 14. USING TWO-WAY COMMUNICATION
  15. 15. Pebble AppMessage PBWatch Intent Bus AndroidiOS
  16. 16. AppMessage Generic updates exchange
  17. 17. static void s_main(void *params) { static PebbleAppHandlers s_handlers = { ... .messaging_info = { .buffer_sizes = { .inbound = 64, // inbound buffer size in bytes .outbound = 16, // outbound buffer size in bytes }, }, }; app_event_loop(params, &s_handlers); } AppMessage Declare in/out buffer sizes in your PebbleAppHandlers struct
  18. 18. static void s_main(void *params) { static PebbleAppHandlers s_handlers = { /* ... */ .messaging_info = { /* ... */ .default_callbacks.callbacks = { .out_sent = my_out_sent_handler, .out_failed = my_out_fail_handler, .in_received = my_in_rcv_handler, .in_dropped = my_in_drp_handler, }, }, }; app_event_loop(params, &s_handlers); } Declare four new callbacks AppMessage
  19. 19. void my_in_rcv_handler(DictionaryIterator *received, void *context) { // incoming message received } void my_in_drp_handler(void *context, AppMessageResult reason) { // incoming message dropped } void my_out_sent_handler(DictionaryIterator *sent, void *context) { // outgoing message was delivered } void my_out_fail_handler(DictionaryIterator *failed, AppMessageResult reason, void *context) { // outgoing message failed } Implement your callbacks AppMessage
  20. 20. DictionaryIterator *iter; // Reserve the output buffer app_message_out_get(&iter); // Fill the buffer dict_write_*(iter, ...); dict_write_end(iter); // Send the message app_message_out_send(); // Release the output buffer app_message_out_release(); Send messages AppMessage
  21. 21. // Write data directly dict_write_data(iter, KEY_DATA, data, sizeof(data)); dict_write_cstring(iter, KEY_STR, string); dict_write_int(iter, KEY_INT, value, sizeof(value) /*bytes*/, true /*signed*/); dict_write_uint8(iter, KEY_INT8, value8); // Or use the Tuplet* constructs Tuplet tuplet = TupletInteger(CMD_KEY, value); dict_write_tuplet(iter, &tuplet); Writing into a dictionary Dictionary
  22. 22. Tuple *tuple = dict_read_first(&iter); while (tuple) { switch (tuple->key) { case KEY_TO_A_DATA_VALUE: foo(tuple->value->data, tuple->length); break; case KEY_TO_A_STRING_VALUE: bar(tuple->value->cstring); break; case KEY_TO_A_INT32_VALUE: foobar(tuple->value->int32); break; case KEY_TO_A_UINT8_VALUE: foobar(tuple->value->uint8); break; } tuple = dict_read_next(&iter); } Reading from a dictionary Dictionary
  23. 23. dict_calc_buffer_size(2, sizeof(uint8_t), sizeof(char) * 8); Evaluate the size of a dictionary Dictionary
  24. 24. size = 1 + nTuples * 7 + Size1 + Size2 + ... Evaluate the size of a dictionary Dictionary
  25. 25. iOS Using AppMessage on iOS
  26. 26. [watch appMessagesGetIsSupported:^(PBWatch *watch, BOOL isAppMessagesSupported) { if (isAppMessagesSupported) { uint8_t bytes[] = {0x42, 0xc8, /* ... */, 0x91, 0x41, 0x98}; NSData *uuid = [NSData dataWithBytes:bytes length:sizeof(bytes)]; [watch appMessagesSetUUID:uuid]; } }]; Find out if the watch supports two-way communication Register your channel with the shared UUID iOS
  27. 27. NSNumber *iconKey = @(0); NSNumber *temperatureKey = @(1); NSDictionary *update = @{ iconKey:[NSNumber numberWithUint8:weatherIconID], temperatureKey: @"42°C" }; [_targetWatch appMessagesPushUpdate:update onSent:^(PBWatch *watch, NSDictionary *update, NSError *error) { if (!error) { // :) } } ]; Push updates to the watch iOS
  28. 28. id updateHandler; /* ... */ [ourWatch appMessagesGetIsSupported: ^(PBWatch *watch, BOOL isAppMessagesSupported) { if(updateHandler) [ourWatch appMessagesRemoveUpdateHandler:updateHandler]; updateHandler = [watch appMessagesAddReceiveUpdateHandler: ^BOOL(PBWatch *watch, NSDictionary *update) { /* process message */ return YES; } ]; }]; Receive updates from the watch iOS
  29. 29. Android Using AppMessage on Android
  30. 30. if (PebbleKit.areAppMessagesSupported()) { PebbleDictionary data = new PebbleDictionary(); data.addUint8(ICON_KEY, (byte) weatherIconId); data.addString(TEMP_KEY, "42°C"); PebbleKit.sendDataToPebble(getApplicationContext(), UUID, data); } Find out if the watch supports two-way communication Push an update to the watch Android
  31. 31. public class MyDataReceiver extends PebbleDataReceiver { @Override public void receiveData(final Context context, final int transactionId, final PebbleDictionary data) { /* Process data */ PebbleKit.sendAckToPebble(getApplicationContext(), transactionId); } } /* ... */ PebbleDataReceiver receiver = new PebbleDataReceiver(UUID); PebbleKit.registerReceivedDataHandler(getApplicationContext(), receiver); Register to receive updates You must acknowledge updates Android
  32. 32. Pebble AppMessage PBWatch Intent Bus AndroidiOS AppSync
  33. 33. AppSync Synchronize watch fields
  34. 34. AppMessage AppSync A convenience layer on top of AppMessage Maintains and updates a Dictionary Provides a callback called whenever the Dictionary changes
  35. 35. static void s_main(void *params) { static PebbleAppHandlers s_handlers = { ... .messaging_info = { .buffer_sizes = { .inbound = 64, // inbound buffer size in bytes .outbound = 16, // outbound buffer size in bytes }, }, }; app_event_loop(params, &s_handlers); } You still need to declare the input / output buffers
  36. 36. Tuplet initial_values[] = { TupletInteger(WEATHER_ICON_KEY, (uint8_t) 1), TupletCString(WEATHER_TEMPERATURE_KEY, "42°C"), }; Prepare the initial values of your data
  37. 37. #include <...> AppSync sync; uint8_t sync_buffer[32]; Reserve global memory to store a AppSync struct Reserve global memory to store your dictionary
  38. 38. app_sync_init(&sync, sync_buffer, sizeof(sync_buffer), initial_values, ARRAY_LENGTH(initial_values), sync_tuple_changed_callback, sync_error_callback, NULL); Initialize the synchronization
  39. 39. void sync_tuple_changed_callback(const uint32_t key, const Tuple* new_tuple, const Tuple* old_tuple, void* context) { // Update your layers // Do not forget to call layer_mark_dirty() } Process the first (and subsequent) update
  40. 40. Tuplet new_tuples[] = { TupletInteger(WEATHER_ICON_KEY, (uint8_t) 3), TupletCString(WEATHER_TEMPERATURE_KEY, "73°C"), }; app_sync_set(&sync, new_tuples, 2); You can update the value on the Watch side The callback will be called when the app has acknowledged
  41. 41. Pebble AppMessage PBWatch Intent Bus AndroidiOS AppSync
  42. 42. THANK YOU! @pebbledev
  43. 43. THANK YOU! @pebbledev

×