Battery Notification

When a Provider includes multiple components, it can be useful to notify the Seeker of the battery level for each component. One example of this would be when a earbuds case is opened and the Seeker needs to know the battery for each individual bud and the case itself.

To accomplish this, a Provider can include additional information in the advertisement, built on top of the Fast Pair Account Data described in Advertising: When not discoverable.

In addition to the Account Data, the Provider should include an additional field specifying the battery values. The packet shall contain the following:

Octet Data type Description Value Mandatory?
0 uint8 Flags 0x00
(all bits reserved for future use)
Mandatory
1 - s Account Key Data Mandatory
s + 1 uint8 Battery level length and type
0bLLLLTTTT
  • L = Number of battery values
  • T = type
0bLLLLTTTT
  • length = 0b0011 = 3 battery values
  • type = 0b0011 (show UI indication) or 0b0100 (hide UI indication)
Optional
s + 2, s + 3, s + 4 uint8 Battery values
0bSVVVVVVV
  • S = status (charging or not charging)
  • V = value
  • The battery values should be ordered as left bud (s + 2), right bud (s + 3) and case (s + 4).
0bSVVVVVVV
  • status = 0b1 (charging) or 0b0 (not charging)
  • value = battery level ranging from 0 to 100 percent, 0bS1111111 for unknown.
Optional

To prevent tampering, the Account Key Data above shall be slightly modified to include battery information when the battery values are included in the advertisement. Normally, when building the account key filter, a value V is produced by combining the account key with a salt. Instead, when battery information is also being advertised, the value V should be constructed as follows:

  1. Produce a value V, where:
    1. The first 16 bytes are K.
    2. The next bytes are the salt. See Rotation.
    3. The remaining bytes are the battery information (from s + 1 to s + 4 including the length and type byte from the table above).

As noted in the battery length and type field above, the type can be either 0b0011 or 0b0100.

  • 0b0011 - Use when the Provider wants the Seeker to show an indication in the UI of the battery values;
  • 0b0100 - Use when the Provider wants the Seeker to hide the indication if it is already showing.

One common use case for this is to use 0b0011 when the case has opened and 0b0100 when buds have been removed from the case or it has been closed again.

  //The sample code demonstrates that the headset only reports the battery level.

  #define FASTPAIR_ACCOUNT_KEY_SIZE 16

  // Salt could be a random byte.
  #define SALT_SIZE 1

  // 1st byte - Battery level length and type
  // 2nd~4th bytes - Battery values
  #define BAT_LEVEL_SIZE 3

  uint8_t V[FASTPAIR_ACCOUNT_KEY_SIZE + SALT_SIZE + BAT_LEVEL_SIZE + 1] = {0};
  int v_index = 0;

  // The first 16 bytes are K.
  uint8_t K[FASTPAIR_ACCOUNT_KEY_SIZE] = {0};
  fastpair_get_account_key_by_index(keyIndex, K);
  memcpy(V, K, FASTPAIR_ACCOUNT_KEY_SIZE);
  v_index = v_index + FASTPAIR_ACCOUNT_KEY_SIZE;

  // The next byte is the Salt.
  uint8_t randomSalt = (uint8_t)rand();
  V[v_index] = randomSalt;
  v_index = v_index + SALT_SIZE;

  // The remaining bytes are the battery information (from s + 1 to s + 4 including the length and type bytes).

  uint8_t battery_level_len = 0;
  uint8_t battery_level[BAT_LEVEL_SIZE] = {0};

  fastpair_get_bat_level(&battery_level_len, battery_level);

  // type = 0b0011 (show UI indication) or 0b0100 (hide UI indication)
  V[v_index] = (battery_level_len << 4 | (is_show_ui ? 0x3 : 0x4));
  v_index = v_index + 1;

  for (int idx = 0; idx < battery_level_len; idx++) {
          V[v_index++] = battery_level[idx];
  }

To prevent tracking, the Provider should not include raw battery data in the advertisement all the time. It can instead be sent via RFCOMM when connected to a Seeker, see Message Stream: Device Information.