Bluetooth
AppMessage
Callbacks
Connection Issues
Troubleshooting

Not receiving AppMessage callbacks when sending message inside a bluetooth connection event

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

On Pebble, a Bluetooth connection event tells you the transport state changed, not that the AppMessage channel is immediately ready for reliable application traffic. If you send an AppMessage inside the connection callback and never receive the usual success or failure callbacks, the most likely cause is that the messaging layer is not fully ready yet or was not initialized correctly.

Initialize AppMessage First

Before sending anything, register AppMessage callbacks and open the inbox and outbox. If app_message_open() has not been called, outbound messaging will not work correctly.

c
1#include <pebble.h>
2
3static void inbox_received_callback(DictionaryIterator *iter, void *context) {
4  APP_LOG(APP_LOG_LEVEL_INFO, "Inbox received");
5}
6
7static void outbox_sent_callback(DictionaryIterator *iter, void *context) {
8  APP_LOG(APP_LOG_LEVEL_INFO, "Outbox sent");
9}
10
11static void outbox_failed_callback(DictionaryIterator *iter, AppMessageResult reason, void *context) {
12  APP_LOG(APP_LOG_LEVEL_ERROR, "Outbox failed: %d", reason);
13}
14
15static void init_messaging(void) {
16  app_message_register_inbox_received(inbox_received_callback);
17  app_message_register_outbox_sent(outbox_sent_callback);
18  app_message_register_outbox_failed(outbox_failed_callback);
19  app_message_open(128, 128);
20}

That setup should happen during app initialization, not lazily inside the Bluetooth callback.

Why Sending Inside the Connection Event Fails

The connection callback fires as soon as Pebble notices the phone connection state. At that moment, AppMessage may still be reconnecting, the phone-side app may not be ready, or the transport queues may not be initialized enough for a reliable round trip.

So code like this is risky:

c
1static void bluetooth_handler(bool connected) {
2  if (connected) {
3    DictionaryIterator *iter;
4    if (app_message_outbox_begin(&iter) == APP_MSG_OK) {
5      dict_write_cstring(iter, 1, "hello");
6      app_message_outbox_send();
7    }
8  }
9}

It may sometimes work and sometimes fail silently depending on timing.

Delay the Send Slightly

A practical fix is to defer the send by a short timer. That gives the connection and phone-side app time to settle.

c
1#include <pebble.h>
2
3static AppTimer *s_timer;
4
5static void send_message(void *data) {
6  DictionaryIterator *iter;
7  AppMessageResult result = app_message_outbox_begin(&iter);
8  if (result != APP_MSG_OK) {
9    APP_LOG(APP_LOG_LEVEL_ERROR, "outbox_begin failed: %d", result);
10    return;
11  }
12
13  dict_write_cstring(iter, 1, "hello");
14  result = app_message_outbox_send();
15  APP_LOG(APP_LOG_LEVEL_INFO, "outbox_send result: %d", result);
16}
17
18static void bluetooth_handler(bool connected) {
19  if (connected) {
20    s_timer = app_timer_register(1000, send_message, NULL);
21  }
22}

A one-second delay is usually enough for this class of issue, though the exact value depends on the rest of the app lifecycle.

Check Return Codes Aggressively

If callbacks are missing, inspect every return code. app_message_outbox_begin() and app_message_outbox_send() tell you immediately whether the request was even queued.

If the queue is busy, you may receive an error such as APP_MSG_BUSY. If the buffers are too small, you can get message-size errors. Those failures are easier to debug than waiting for a callback that never arrives.

Separate Transport Events from Application Protocol

Bluetooth connection state is only one signal. Good Pebble apps treat it as a hint that communication might be possible soon, not as proof that a request-response exchange should start immediately.

A safer design is:

  1. Bluetooth reconnects.
  2. Watch delays briefly or waits for a known ready signal.
  3. Watch sends a small sync request.
  4. Phone app responds normally through AppMessage.

That design is much more stable than treating the connection event itself as the message trigger.

Common Pitfalls

A common mistake is forgetting app_message_open(). Without opening the channel, callback registration alone is not enough.

Another issue is sending too early in the Bluetooth handler. The transport may exist, but the AppMessage path is not ready for your payload yet.

Developers also sometimes ignore return codes and assume missing callbacks indicate a callback bug. In many cases the message never entered the queue in the first place.

Summary

  • Initialize AppMessage during app startup, not inside the Bluetooth callback.
  • Do not assume a Bluetooth connection event means the messaging layer is immediately ready.
  • Delay the send slightly after reconnection.
  • Check app_message_outbox_begin() and app_message_outbox_send() return codes.
  • Treat connection events as transport signals, not application-level readiness signals.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.