Offbeat Iot
Get started
Using the Fitbit integration

Using the Fitbit integration

you can read and create Fitbit data by sending json requests from your device:

get activities summary
Request
{
  "fitbit.activities" : ""
}
Example response
{
  "caloriesOut" : 2628,
  "activityCalories" : 525,
  "endpointId" : "test-endpoint-id",
  "steps" : 1698,
  "veryActiveMinutes" : 0,
  "caloriesBMR" : 1973,
  "sedentaryMinutes" : 802
}
JSON example
void sendFitbitActivitiesJson(WebSocketsClient& socket) {
  String body;
  if (!offbeat::fitbit::examples::json::buildStringRequest("fitbit.activities", "", body)) {
    Serial.println("Unable to build fitbit.activities request");
    return;
  }

  socket.sendTXT(body);
  Serial.println("REQUEST_SENT=fitbit.activities");
}

void handleFitbitActivitiesJsonResponse(uint8_t* payload, size_t length) {
  StaticJsonDocument<1024> document;
  JsonObjectConst root;
  offbeat::fitbit::examples::json::ParseStatus status =
      offbeat::fitbit::examples::json::parseRoot(payload, length, document, root);

  if (status == offbeat::fitbit::examples::json::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.activities response");
    return;
  }

  offbeat::fitbit::examples::json::printLine(
      "Calories out: ",
      offbeat::fitbit::examples::json::readLong(root["caloriesOut"]));
  offbeat::fitbit::examples::json::printLine(
      "Activity calories: ",
      offbeat::fitbit::examples::json::readLong(root["activityCalories"]));
  offbeat::fitbit::examples::json::printLine(
      "Steps: ",
      offbeat::fitbit::examples::json::readLong(root["steps"]));
  offbeat::fitbit::examples::json::printLine(
      "Very active minutes: ",
      offbeat::fitbit::examples::json::readLong(root["veryActiveMinutes"]));
  offbeat::fitbit::examples::json::printLine(
      "Calories BMR: ",
      offbeat::fitbit::examples::json::readLong(root["caloriesBMR"]));
  offbeat::fitbit::examples::json::printLine(
      "Sedentary minutes: ",
      offbeat::fitbit::examples::json::readLong(root["sedentaryMinutes"]));
  offbeat::fitbit::examples::json::printEndpoint(root);
  Serial.println("TEST:PASS");
}
CBOR example
void sendFitbitActivitiesCbor(WebSocketsClient& socket) {
  uint8_t encoded[128];
  size_t encodedLength =
      offbeat::fitbit::examples::cbor::buildStringRequest("fitbit.activities", "", encoded, sizeof(encoded));
  if (encodedLength == 0) {
    Serial.println("Unable to build fitbit.activities request");
    return;
  }

  socket.sendBIN(encoded, encodedLength);
  Serial.println("REQUEST_SENT=fitbit.activities");
}

void handleFitbitActivitiesCborResponse(uint8_t* payload, size_t length) {
  CborBuffer buffer(1024);
  cn_cbor* root = NULL;
  offbeat::fitbit::examples::cbor::ParseStatus status =
      offbeat::fitbit::examples::cbor::parseRoot(payload, length, buffer, root);

  if (status == offbeat::fitbit::examples::cbor::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.activities response");
    return;
  }

  offbeat::fitbit::examples::cbor::printLine(
      "Calories out: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(root, "caloriesOut")));
  offbeat::fitbit::examples::cbor::printLine(
      "Activity calories: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(root, "activityCalories")));
  offbeat::fitbit::examples::cbor::printLine(
      "Steps: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(root, "steps")));
  offbeat::fitbit::examples::cbor::printLine(
      "Very active minutes: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(root, "veryActiveMinutes")));
  offbeat::fitbit::examples::cbor::printLine(
      "Calories BMR: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(root, "caloriesBMR")));
  offbeat::fitbit::examples::cbor::printLine(
      "Sedentary minutes: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(root, "sedentaryMinutes")));
  offbeat::fitbit::examples::cbor::printEndpoint(root);
  Serial.println("TEST:PASS");
}
get body (weight + fat)
Request
{
  "fitbit.get.body" : ""
}
Example response
{
  "fat" : 15,
  "weight" : 200,
  "endpointId" : "test-endpoint-id",
  "bmi" : 25.91
}
JSON example
void sendFitbitGetBodyJson(WebSocketsClient& socket) {
  String body;
  if (!offbeat::fitbit::examples::json::buildStringRequest("fitbit.get.body", "", body)) {
    Serial.println("Unable to build fitbit.get.body request");
    return;
  }

  socket.sendTXT(body);
  Serial.println("REQUEST_SENT=fitbit.get.body");
}

void handleFitbitGetBodyJsonResponse(uint8_t* payload, size_t length) {
  StaticJsonDocument<1024> document;
  JsonObjectConst root;
  offbeat::fitbit::examples::json::ParseStatus status =
      offbeat::fitbit::examples::json::parseRoot(payload, length, document, root);

  if (status == offbeat::fitbit::examples::json::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.body response");
    return;
  }

  offbeat::fitbit::examples::json::printLine(
      "Body fat: ",
      offbeat::fitbit::examples::json::readLong(root["fat"]));
  offbeat::fitbit::examples::json::printLine(
      "Weight: ",
      offbeat::fitbit::examples::json::readLong(root["weight"]));
  offbeat::fitbit::examples::json::printLine(
      "BMI: ",
      offbeat::fitbit::examples::json::readDouble(root["bmi"]),
      2);
  offbeat::fitbit::examples::json::printEndpoint(root);
  Serial.println("TEST:PASS");
}
CBOR example
void sendFitbitGetBodyCbor(WebSocketsClient& socket) {
  uint8_t encoded[128];
  size_t encodedLength =
      offbeat::fitbit::examples::cbor::buildStringRequest("fitbit.get.body", "", encoded, sizeof(encoded));
  if (encodedLength == 0) {
    Serial.println("Unable to build fitbit.get.body request");
    return;
  }

  socket.sendBIN(encoded, encodedLength);
  Serial.println("REQUEST_SENT=fitbit.get.body");
}

void handleFitbitGetBodyCborResponse(uint8_t* payload, size_t length) {
  CborBuffer buffer(1024);
  cn_cbor* root = NULL;
  offbeat::fitbit::examples::cbor::ParseStatus status =
      offbeat::fitbit::examples::cbor::parseRoot(payload, length, buffer, root);

  if (status == offbeat::fitbit::examples::cbor::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.body response");
    return;
  }

  offbeat::fitbit::examples::cbor::printLine(
      "Body fat: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(root, "fat")));
  offbeat::fitbit::examples::cbor::printLine(
      "Weight: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(root, "weight")));
  offbeat::fitbit::examples::cbor::printLine(
      "BMI: ",
      offbeat::fitbit::examples::cbor::readDouble(offbeat::fitbit::examples::cbor::findField(root, "bmi")),
      2);
  offbeat::fitbit::examples::cbor::printEndpoint(root);
  Serial.println("TEST:PASS");
}
get weight
Request
{
  "fitbit.get.weight" : "14-07-2024"
}
Example response
{
  "weight" : 200,
  "endpointId" : "test-endpoint-id",
  "bmi" : 25.91
}
JSON example
constexpr char kGetWeightJsonValue[] = "14-07-2024";

void sendFitbitGetWeightJson(WebSocketsClient& socket) {
  String body;
  if (!offbeat::fitbit::examples::json::buildStringRequest("fitbit.get.weight", kGetWeightJsonValue, body)) {
    Serial.println("Unable to build fitbit.get.weight request");
    return;
  }

  socket.sendTXT(body);
  Serial.println("REQUEST_SENT=fitbit.get.weight");
}

void handleFitbitGetWeightJsonResponse(uint8_t* payload, size_t length) {
  StaticJsonDocument<1024> document;
  JsonObjectConst root;
  offbeat::fitbit::examples::json::ParseStatus status =
      offbeat::fitbit::examples::json::parseRoot(payload, length, document, root);

  if (status == offbeat::fitbit::examples::json::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.weight response");
    return;
  }

  Serial.print("Requested date: ");
  Serial.println(kGetWeightJsonValue);
  offbeat::fitbit::examples::json::printLine(
      "Weight: ",
      offbeat::fitbit::examples::json::readLong(root["weight"]));
  offbeat::fitbit::examples::json::printLine(
      "BMI: ",
      offbeat::fitbit::examples::json::readDouble(root["bmi"]),
      2);
  offbeat::fitbit::examples::json::printEndpoint(root);
  Serial.println("TEST:PASS");
}
CBOR example
constexpr char kGetWeightCborValue[] = "14-07-2024";

void sendFitbitGetWeightCbor(WebSocketsClient& socket) {
  uint8_t encoded[128];
  size_t encodedLength = offbeat::fitbit::examples::cbor::buildStringRequest(
      "fitbit.get.weight", kGetWeightCborValue, encoded, sizeof(encoded));
  if (encodedLength == 0) {
    Serial.println("Unable to build fitbit.get.weight request");
    return;
  }

  socket.sendBIN(encoded, encodedLength);
  Serial.println("REQUEST_SENT=fitbit.get.weight");
}

void handleFitbitGetWeightCborResponse(uint8_t* payload, size_t length) {
  CborBuffer buffer(1024);
  cn_cbor* root = NULL;
  offbeat::fitbit::examples::cbor::ParseStatus status =
      offbeat::fitbit::examples::cbor::parseRoot(payload, length, buffer, root);

  if (status == offbeat::fitbit::examples::cbor::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.weight response");
    return;
  }

  Serial.print("Requested date: ");
  Serial.println(kGetWeightCborValue);
  offbeat::fitbit::examples::cbor::printLine(
      "Weight: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(root, "weight")));
  offbeat::fitbit::examples::cbor::printLine(
      "BMI: ",
      offbeat::fitbit::examples::cbor::readDouble(offbeat::fitbit::examples::cbor::findField(root, "bmi")),
      2);
  offbeat::fitbit::examples::cbor::printEndpoint(root);
  Serial.println("TEST:PASS");
}
get current weight
Request
{
  "fitbit.get.current.weight" : ""
}
Example response
{
  "weight" : 100,
  "endpointId" : "test-endpoint-id",
  "weightUnit" : "METRIC"
}
JSON example
void sendFitbitGetCurrentWeightJson(WebSocketsClient& socket) {
  String body;
  if (!offbeat::fitbit::examples::json::buildStringRequest("fitbit.get.current.weight", "", body)) {
    Serial.println("Unable to build fitbit.get.current.weight request");
    return;
  }

  socket.sendTXT(body);
  Serial.println("REQUEST_SENT=fitbit.get.current.weight");
}

void handleFitbitGetCurrentWeightJsonResponse(uint8_t* payload, size_t length) {
  StaticJsonDocument<1024> document;
  JsonObjectConst root;
  offbeat::fitbit::examples::json::ParseStatus status =
      offbeat::fitbit::examples::json::parseRoot(payload, length, document, root);

  if (status == offbeat::fitbit::examples::json::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.current.weight response");
    return;
  }

  offbeat::fitbit::examples::json::printLine(
      "Current weight: ",
      offbeat::fitbit::examples::json::readLong(root["weight"]));
  offbeat::fitbit::examples::json::printLine(
      "Weight unit: ",
      offbeat::fitbit::examples::json::readString(root["weightUnit"]));
  offbeat::fitbit::examples::json::printEndpoint(root);
  Serial.println("TEST:PASS");
}
CBOR example
void sendFitbitGetCurrentWeightCbor(WebSocketsClient& socket) {
  uint8_t encoded[128];
  size_t encodedLength = offbeat::fitbit::examples::cbor::buildStringRequest(
      "fitbit.get.current.weight", "", encoded, sizeof(encoded));
  if (encodedLength == 0) {
    Serial.println("Unable to build fitbit.get.current.weight request");
    return;
  }

  socket.sendBIN(encoded, encodedLength);
  Serial.println("REQUEST_SENT=fitbit.get.current.weight");
}

void handleFitbitGetCurrentWeightCborResponse(uint8_t* payload, size_t length) {
  CborBuffer buffer(1024);
  cn_cbor* root = NULL;
  offbeat::fitbit::examples::cbor::ParseStatus status =
      offbeat::fitbit::examples::cbor::parseRoot(payload, length, buffer, root);

  if (status == offbeat::fitbit::examples::cbor::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.current.weight response");
    return;
  }

  offbeat::fitbit::examples::cbor::printLine(
      "Current weight: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(root, "weight")));
  offbeat::fitbit::examples::cbor::printLine(
      "Weight unit: ",
      offbeat::fitbit::examples::cbor::readString(offbeat::fitbit::examples::cbor::findField(root, "weightUnit")));
  offbeat::fitbit::examples::cbor::printEndpoint(root);
  Serial.println("TEST:PASS");
}
get weight goal
Request
{
  "fitbit.get.weight.goal" : ""
}
Example response
{
  "weightGoal" : {
    "goalType" : "LOSE",
    "startDate" : "2018-06-13",
    "startWeight" : 105.28,
    "weight" : 99.79,
    "weightThreshold" : 0.05
  },
  "endpointId" : "test-endpoint-id"
}
JSON example
void sendFitbitGetWeightGoalJson(WebSocketsClient& socket) {
  String body;
  if (!offbeat::fitbit::examples::json::buildStringRequest("fitbit.get.weight.goal", "", body)) {
    Serial.println("Unable to build fitbit.get.weight.goal request");
    return;
  }

  socket.sendTXT(body);
  Serial.println("REQUEST_SENT=fitbit.get.weight.goal");
}

void handleFitbitGetWeightGoalJsonResponse(uint8_t* payload, size_t length) {
  StaticJsonDocument<1024> document;
  JsonObjectConst root;
  offbeat::fitbit::examples::json::ParseStatus status =
      offbeat::fitbit::examples::json::parseRoot(payload, length, document, root);

  if (status == offbeat::fitbit::examples::json::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.weight.goal response");
    return;
  }

  JsonObjectConst weightGoal = root["weightGoal"].as<JsonObjectConst>();
  if (weightGoal.isNull()) {
    Serial.println("No weightGoal payload");
    return;
  }

  offbeat::fitbit::examples::json::printLine(
      "Goal type: ",
      offbeat::fitbit::examples::json::readString(weightGoal["goalType"]));
  offbeat::fitbit::examples::json::printLine(
      "Start date: ",
      offbeat::fitbit::examples::json::readString(weightGoal["startDate"]));
  offbeat::fitbit::examples::json::printLine(
      "Start weight: ",
      offbeat::fitbit::examples::json::readDouble(weightGoal["startWeight"]),
      2);
  offbeat::fitbit::examples::json::printLine(
      "Target weight: ",
      offbeat::fitbit::examples::json::readDouble(weightGoal["weight"]),
      2);
  offbeat::fitbit::examples::json::printLine(
      "Weight threshold: ",
      offbeat::fitbit::examples::json::readDouble(weightGoal["weightThreshold"]),
      2);
  offbeat::fitbit::examples::json::printEndpoint(root);
  Serial.println("TEST:PASS");
}
CBOR example
void sendFitbitGetWeightGoalCbor(WebSocketsClient& socket) {
  uint8_t encoded[128];
  size_t encodedLength = offbeat::fitbit::examples::cbor::buildStringRequest(
      "fitbit.get.weight.goal", "", encoded, sizeof(encoded));
  if (encodedLength == 0) {
    Serial.println("Unable to build fitbit.get.weight.goal request");
    return;
  }

  socket.sendBIN(encoded, encodedLength);
  Serial.println("REQUEST_SENT=fitbit.get.weight.goal");
}

void handleFitbitGetWeightGoalCborResponse(uint8_t* payload, size_t length) {
  CborBuffer buffer(1024);
  cn_cbor* root = NULL;
  offbeat::fitbit::examples::cbor::ParseStatus status =
      offbeat::fitbit::examples::cbor::parseRoot(payload, length, buffer, root);

  if (status == offbeat::fitbit::examples::cbor::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.weight.goal response");
    return;
  }

  cn_cbor* weightGoal = offbeat::fitbit::examples::cbor::findField(root, "weightGoal");
  if (weightGoal == NULL || weightGoal->type != CN_CBOR_MAP) {
    Serial.println("No weightGoal payload");
    return;
  }

  offbeat::fitbit::examples::cbor::printLine(
      "Goal type: ",
      offbeat::fitbit::examples::cbor::readString(offbeat::fitbit::examples::cbor::findField(weightGoal, "goalType")));
  offbeat::fitbit::examples::cbor::printLine(
      "Start date: ",
      offbeat::fitbit::examples::cbor::readString(offbeat::fitbit::examples::cbor::findField(weightGoal, "startDate")));
  offbeat::fitbit::examples::cbor::printLine(
      "Start weight: ",
      offbeat::fitbit::examples::cbor::readDouble(offbeat::fitbit::examples::cbor::findField(weightGoal, "startWeight")),
      2);
  offbeat::fitbit::examples::cbor::printLine(
      "Target weight: ",
      offbeat::fitbit::examples::cbor::readDouble(offbeat::fitbit::examples::cbor::findField(weightGoal, "weight")),
      2);
  offbeat::fitbit::examples::cbor::printLine(
      "Weight threshold: ",
      offbeat::fitbit::examples::cbor::readDouble(offbeat::fitbit::examples::cbor::findField(weightGoal, "weightThreshold")),
      2);
  offbeat::fitbit::examples::cbor::printEndpoint(root);
  Serial.println("TEST:PASS");
}
create weight log
Request
{
  "fitbit.create.weight" : "100"
}
Example response
{
  "endpointId" : "test-endpoint-id",
  "fitbit.create.weight" : {
    "result" : "OK"
  }
}
JSON example
constexpr char kCreateWeightJsonValue[] = "100";

void sendFitbitCreateWeightJson(WebSocketsClient& socket) {
  String body;
  if (!offbeat::fitbit::examples::json::buildStringRequest("fitbit.create.weight", kCreateWeightJsonValue, body)) {
    Serial.println("Unable to build fitbit.create.weight request");
    return;
  }

  socket.sendTXT(body);
  Serial.println("REQUEST_SENT=fitbit.create.weight");
}

void handleFitbitCreateWeightJsonResponse(uint8_t* payload, size_t length) {
  StaticJsonDocument<1024> document;
  JsonObjectConst root;
  offbeat::fitbit::examples::json::ParseStatus status =
      offbeat::fitbit::examples::json::parseRoot(payload, length, document, root);

  if (status == offbeat::fitbit::examples::json::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.create.weight response");
    return;
  }

  JsonObjectConst response = root["fitbit.create.weight"].as<JsonObjectConst>();
  if (response.isNull()) {
    Serial.println("No fitbit.create.weight payload");
    return;
  }

  Serial.print("Requested weight: ");
  Serial.println(kCreateWeightJsonValue);
  offbeat::fitbit::examples::json::printLine(
      "Result: ",
      offbeat::fitbit::examples::json::readString(response["result"]));
  offbeat::fitbit::examples::json::printEndpoint(root);
  Serial.println("TEST:PASS");
}
CBOR example
constexpr char kCreateWeightCborValue[] = "100";

void sendFitbitCreateWeightCbor(WebSocketsClient& socket) {
  uint8_t encoded[128];
  size_t encodedLength = offbeat::fitbit::examples::cbor::buildStringRequest(
      "fitbit.create.weight", kCreateWeightCborValue, encoded, sizeof(encoded));
  if (encodedLength == 0) {
    Serial.println("Unable to build fitbit.create.weight request");
    return;
  }

  socket.sendBIN(encoded, encodedLength);
  Serial.println("REQUEST_SENT=fitbit.create.weight");
}

void handleFitbitCreateWeightCborResponse(uint8_t* payload, size_t length) {
  CborBuffer buffer(1024);
  cn_cbor* root = NULL;
  offbeat::fitbit::examples::cbor::ParseStatus status =
      offbeat::fitbit::examples::cbor::parseRoot(payload, length, buffer, root);

  if (status == offbeat::fitbit::examples::cbor::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.create.weight response");
    return;
  }

  cn_cbor* response = offbeat::fitbit::examples::cbor::findField(root, "fitbit.create.weight");
  if (response == NULL || response->type != CN_CBOR_MAP) {
    Serial.println("No fitbit.create.weight payload");
    return;
  }

  Serial.print("Requested weight: ");
  Serial.println(kCreateWeightCborValue);
  offbeat::fitbit::examples::cbor::printLine(
      "Result: ",
      offbeat::fitbit::examples::cbor::readString(offbeat::fitbit::examples::cbor::findField(response, "result")));
  offbeat::fitbit::examples::cbor::printEndpoint(root);
  Serial.println("TEST:PASS");
}
create fat log
Request
{
  "fitbit.create.fat" : "21"
}
Example response
{
  "fitbit.create.fat" : {
    "result" : "OK"
  },
  "endpointId" : "test-endpoint-id"
}
JSON example
constexpr char kCreateFatJsonValue[] = "21";

void sendFitbitCreateFatJson(WebSocketsClient& socket) {
  String body;
  if (!offbeat::fitbit::examples::json::buildStringRequest("fitbit.create.fat", kCreateFatJsonValue, body)) {
    Serial.println("Unable to build fitbit.create.fat request");
    return;
  }

  socket.sendTXT(body);
  Serial.println("REQUEST_SENT=fitbit.create.fat");
}

void handleFitbitCreateFatJsonResponse(uint8_t* payload, size_t length) {
  StaticJsonDocument<1024> document;
  JsonObjectConst root;
  offbeat::fitbit::examples::json::ParseStatus status =
      offbeat::fitbit::examples::json::parseRoot(payload, length, document, root);

  if (status == offbeat::fitbit::examples::json::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.create.fat response");
    return;
  }

  JsonObjectConst response = root["fitbit.create.fat"].as<JsonObjectConst>();
  if (response.isNull()) {
    Serial.println("No fitbit.create.fat payload");
    return;
  }

  Serial.print("Requested fat value: ");
  Serial.println(kCreateFatJsonValue);
  offbeat::fitbit::examples::json::printLine(
      "Result: ",
      offbeat::fitbit::examples::json::readString(response["result"]));
  offbeat::fitbit::examples::json::printEndpoint(root);
  Serial.println("TEST:PASS");
}
CBOR example
constexpr char kCreateFatCborValue[] = "21";

void sendFitbitCreateFatCbor(WebSocketsClient& socket) {
  uint8_t encoded[128];
  size_t encodedLength = offbeat::fitbit::examples::cbor::buildStringRequest(
      "fitbit.create.fat", kCreateFatCborValue, encoded, sizeof(encoded));
  if (encodedLength == 0) {
    Serial.println("Unable to build fitbit.create.fat request");
    return;
  }

  socket.sendBIN(encoded, encodedLength);
  Serial.println("REQUEST_SENT=fitbit.create.fat");
}

void handleFitbitCreateFatCborResponse(uint8_t* payload, size_t length) {
  CborBuffer buffer(1024);
  cn_cbor* root = NULL;
  offbeat::fitbit::examples::cbor::ParseStatus status =
      offbeat::fitbit::examples::cbor::parseRoot(payload, length, buffer, root);

  if (status == offbeat::fitbit::examples::cbor::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.create.fat response");
    return;
  }

  cn_cbor* response = offbeat::fitbit::examples::cbor::findField(root, "fitbit.create.fat");
  if (response == NULL || response->type != CN_CBOR_MAP) {
    Serial.println("No fitbit.create.fat payload");
    return;
  }

  Serial.print("Requested fat value: ");
  Serial.println(kCreateFatCborValue);
  offbeat::fitbit::examples::cbor::printLine(
      "Result: ",
      offbeat::fitbit::examples::cbor::readString(offbeat::fitbit::examples::cbor::findField(response, "result")));
  offbeat::fitbit::examples::cbor::printEndpoint(root);
  Serial.println("TEST:PASS");
}
create food log
Request
{
  "fitbit.create.food.log" : {
    "foodId" : 5678,
    "mealTypeId" : 1,
    "unitId" : "ml",
    "amount" : "5"
  }
}
Example response
{
  "fitbit.create.food.log" : {
    "result" : "OK"
  },
  "endpointId" : "test-endpoint-id"
}
JSON example
constexpr char kCreateFoodAmount[] = "5";
constexpr long kCreateFoodId = 5678;
constexpr long kCreateFoodMealTypeId = 1;
constexpr char kCreateFoodUnitId[] = "ml";

void sendFitbitCreateFoodLogJson(WebSocketsClient& socket) {
  String body;
  if (!offbeat::fitbit::examples::json::buildObjectRequest(
          "fitbit.create.food.log",
          body,
          [](JsonObject value) {
            value["amount"] = kCreateFoodAmount;
            value["foodId"] = kCreateFoodId;
            value["mealTypeId"] = kCreateFoodMealTypeId;
            value["unitId"] = kCreateFoodUnitId;
          })) {
    Serial.println("Unable to build fitbit.create.food.log request");
    return;
  }

  socket.sendTXT(body);
  Serial.println("REQUEST_SENT=fitbit.create.food.log");
}

void handleFitbitCreateFoodLogJsonResponse(uint8_t* payload, size_t length) {
  StaticJsonDocument<1024> document;
  JsonObjectConst root;
  offbeat::fitbit::examples::json::ParseStatus status =
      offbeat::fitbit::examples::json::parseRoot(payload, length, document, root);

  if (status == offbeat::fitbit::examples::json::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.create.food.log response");
    return;
  }

  JsonObjectConst response = root["fitbit.create.food.log"].as<JsonObjectConst>();
  if (response.isNull()) {
    Serial.println("No fitbit.create.food.log payload");
    return;
  }

  offbeat::fitbit::examples::json::printLine("Food ID: ", kCreateFoodId);
  offbeat::fitbit::examples::json::printLine("Meal type ID: ", kCreateFoodMealTypeId);
  offbeat::fitbit::examples::json::printLine("Amount: ", kCreateFoodAmount);
  offbeat::fitbit::examples::json::printLine("Unit ID: ", kCreateFoodUnitId);
  offbeat::fitbit::examples::json::printLine(
      "Result: ",
      offbeat::fitbit::examples::json::readString(response["result"]));
  offbeat::fitbit::examples::json::printEndpoint(root);
  Serial.println("TEST:PASS");
}
CBOR example
constexpr char kCreateFoodAmountCbor[] = "5";
constexpr long kCreateFoodIdCbor = 5678;
constexpr long kCreateFoodMealTypeIdCbor = 1;
constexpr char kCreateFoodUnitIdCbor[] = "ml";

void sendFitbitCreateFoodLogCbor(WebSocketsClient& socket) {
  uint8_t encoded[192];
  size_t encodedLength = offbeat::fitbit::examples::cbor::buildObjectRequest(
      "fitbit.create.food.log",
      encoded,
      sizeof(encoded),
      [](CborObject& value) {
        value.set("amount", kCreateFoodAmountCbor);
        value.set("foodId", static_cast<long>(kCreateFoodIdCbor));
        value.set("mealTypeId", static_cast<long>(kCreateFoodMealTypeIdCbor));
        value.set("unitId", kCreateFoodUnitIdCbor);
      });
  if (encodedLength == 0) {
    Serial.println("Unable to build fitbit.create.food.log request");
    return;
  }

  socket.sendBIN(encoded, encodedLength);
  Serial.println("REQUEST_SENT=fitbit.create.food.log");
}

void handleFitbitCreateFoodLogCborResponse(uint8_t* payload, size_t length) {
  CborBuffer buffer(1024);
  cn_cbor* root = NULL;
  offbeat::fitbit::examples::cbor::ParseStatus status =
      offbeat::fitbit::examples::cbor::parseRoot(payload, length, buffer, root);

  if (status == offbeat::fitbit::examples::cbor::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.create.food.log response");
    return;
  }

  cn_cbor* response = offbeat::fitbit::examples::cbor::findField(root, "fitbit.create.food.log");
  if (response == NULL || response->type != CN_CBOR_MAP) {
    Serial.println("No fitbit.create.food.log payload");
    return;
  }

  offbeat::fitbit::examples::cbor::printLine("Food ID: ", kCreateFoodIdCbor);
  offbeat::fitbit::examples::cbor::printLine("Meal type ID: ", kCreateFoodMealTypeIdCbor);
  offbeat::fitbit::examples::cbor::printLine("Amount: ", kCreateFoodAmountCbor);
  offbeat::fitbit::examples::cbor::printLine("Unit ID: ", kCreateFoodUnitIdCbor);
  offbeat::fitbit::examples::cbor::printLine(
      "Result: ",
      offbeat::fitbit::examples::cbor::readString(offbeat::fitbit::examples::cbor::findField(response, "result")));
  offbeat::fitbit::examples::cbor::printEndpoint(root);
  Serial.println("TEST:PASS");
}
get food log
Request
{
  "fitbit.food" : ""
}
Example response
{
  "fitbit.food.log" : {
    "sodium" : 760,
    "fiber" : 5,
    "carbs" : 46,
    "protein" : 18,
    "fat" : 3.5,
    "calories" : 280,
    "water" : 0
  },
  "endpointId" : "test-endpoint-id"
}
JSON example
void sendFitbitGetFoodLogJson(WebSocketsClient& socket) {
  String body;
  if (!offbeat::fitbit::examples::json::buildStringRequest("fitbit.food", "", body)) {
    Serial.println("Unable to build fitbit.food request");
    return;
  }

  socket.sendTXT(body);
  Serial.println("REQUEST_SENT=fitbit.food");
}

void handleFitbitGetFoodLogJsonResponse(uint8_t* payload, size_t length) {
  StaticJsonDocument<1024> document;
  JsonObjectConst root;
  offbeat::fitbit::examples::json::ParseStatus status =
      offbeat::fitbit::examples::json::parseRoot(payload, length, document, root);

  if (status == offbeat::fitbit::examples::json::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.food response");
    return;
  }

  JsonObjectConst foodLog = root["fitbit.food.log"].as<JsonObjectConst>();
  if (foodLog.isNull()) {
    Serial.println("No fitbit.food.log payload");
    return;
  }

  offbeat::fitbit::examples::json::printLine(
      "Calories: ",
      offbeat::fitbit::examples::json::readLong(foodLog["calories"]));
  offbeat::fitbit::examples::json::printLine(
      "Carbs: ",
      offbeat::fitbit::examples::json::readLong(foodLog["carbs"]));
  offbeat::fitbit::examples::json::printLine(
      "Fat: ",
      offbeat::fitbit::examples::json::readDouble(foodLog["fat"]),
      1);
  offbeat::fitbit::examples::json::printLine(
      "Fiber: ",
      offbeat::fitbit::examples::json::readLong(foodLog["fiber"]));
  offbeat::fitbit::examples::json::printLine(
      "Protein: ",
      offbeat::fitbit::examples::json::readLong(foodLog["protein"]));
  offbeat::fitbit::examples::json::printLine(
      "Sodium: ",
      offbeat::fitbit::examples::json::readLong(foodLog["sodium"]));
  offbeat::fitbit::examples::json::printLine(
      "Water: ",
      offbeat::fitbit::examples::json::readLong(foodLog["water"]));
  offbeat::fitbit::examples::json::printEndpoint(root);
  Serial.println("TEST:PASS");
}
CBOR example
void sendFitbitGetFoodLogCbor(WebSocketsClient& socket) {
  uint8_t encoded[128];
  size_t encodedLength =
      offbeat::fitbit::examples::cbor::buildStringRequest("fitbit.food", "", encoded, sizeof(encoded));
  if (encodedLength == 0) {
    Serial.println("Unable to build fitbit.food request");
    return;
  }

  socket.sendBIN(encoded, encodedLength);
  Serial.println("REQUEST_SENT=fitbit.food");
}

void handleFitbitGetFoodLogCborResponse(uint8_t* payload, size_t length) {
  CborBuffer buffer(1024);
  cn_cbor* root = NULL;
  offbeat::fitbit::examples::cbor::ParseStatus status =
      offbeat::fitbit::examples::cbor::parseRoot(payload, length, buffer, root);

  if (status == offbeat::fitbit::examples::cbor::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.food response");
    return;
  }

  cn_cbor* foodLog = offbeat::fitbit::examples::cbor::findField(root, "fitbit.food.log");
  if (foodLog == NULL || foodLog->type != CN_CBOR_MAP) {
    Serial.println("No fitbit.food.log payload");
    return;
  }

  offbeat::fitbit::examples::cbor::printLine(
      "Calories: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(foodLog, "calories")));
  offbeat::fitbit::examples::cbor::printLine(
      "Carbs: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(foodLog, "carbs")));
  offbeat::fitbit::examples::cbor::printLine(
      "Fat: ",
      offbeat::fitbit::examples::cbor::readDouble(offbeat::fitbit::examples::cbor::findField(foodLog, "fat")),
      1);
  offbeat::fitbit::examples::cbor::printLine(
      "Fiber: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(foodLog, "fiber")));
  offbeat::fitbit::examples::cbor::printLine(
      "Protein: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(foodLog, "protein")));
  offbeat::fitbit::examples::cbor::printLine(
      "Sodium: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(foodLog, "sodium")));
  offbeat::fitbit::examples::cbor::printLine(
      "Water: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(foodLog, "water")));
  offbeat::fitbit::examples::cbor::printEndpoint(root);
  Serial.println("TEST:PASS");
}
get food goal
Request
{
  "fitbit.get.food.goal" : ""
}
Example response
{
  "fitbit.food.goal" : {
    "calories" : 2910
  },
  "endpointId" : "test-endpoint-id"
}
JSON example
void sendFitbitGetFoodGoalJson(WebSocketsClient& socket) {
  String body;
  if (!offbeat::fitbit::examples::json::buildStringRequest("fitbit.get.food.goal", "", body)) {
    Serial.println("Unable to build fitbit.get.food.goal request");
    return;
  }

  socket.sendTXT(body);
  Serial.println("REQUEST_SENT=fitbit.get.food.goal");
}

void handleFitbitGetFoodGoalJsonResponse(uint8_t* payload, size_t length) {
  StaticJsonDocument<1024> document;
  JsonObjectConst root;
  offbeat::fitbit::examples::json::ParseStatus status =
      offbeat::fitbit::examples::json::parseRoot(payload, length, document, root);

  if (status == offbeat::fitbit::examples::json::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.food.goal response");
    return;
  }

  JsonObjectConst foodGoal = root["fitbit.food.goal"].as<JsonObjectConst>();
  if (foodGoal.isNull()) {
    Serial.println("No fitbit.food.goal payload");
    return;
  }

  offbeat::fitbit::examples::json::printLine(
      "Daily calorie goal: ",
      offbeat::fitbit::examples::json::readLong(foodGoal["calories"]));
  offbeat::fitbit::examples::json::printEndpoint(root);
  Serial.println("TEST:PASS");
}
CBOR example
void sendFitbitGetFoodGoalCbor(WebSocketsClient& socket) {
  uint8_t encoded[128];
  size_t encodedLength =
      offbeat::fitbit::examples::cbor::buildStringRequest("fitbit.get.food.goal", "", encoded, sizeof(encoded));
  if (encodedLength == 0) {
    Serial.println("Unable to build fitbit.get.food.goal request");
    return;
  }

  socket.sendBIN(encoded, encodedLength);
  Serial.println("REQUEST_SENT=fitbit.get.food.goal");
}

void handleFitbitGetFoodGoalCborResponse(uint8_t* payload, size_t length) {
  CborBuffer buffer(1024);
  cn_cbor* root = NULL;
  offbeat::fitbit::examples::cbor::ParseStatus status =
      offbeat::fitbit::examples::cbor::parseRoot(payload, length, buffer, root);

  if (status == offbeat::fitbit::examples::cbor::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.food.goal response");
    return;
  }

  cn_cbor* foodGoal = offbeat::fitbit::examples::cbor::findField(root, "fitbit.food.goal");
  if (foodGoal == NULL || foodGoal->type != CN_CBOR_MAP) {
    Serial.println("No fitbit.food.goal payload");
    return;
  }

  offbeat::fitbit::examples::cbor::printLine(
      "Daily calorie goal: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(foodGoal, "calories")));
  offbeat::fitbit::examples::cbor::printEndpoint(root);
  Serial.println("TEST:PASS");
}
get water log
Request
{
  "fitbit.get.water" : ""
}
Example response
{
  "fitbit.get.water" : {
    "water" : 0.0
  },
  "endpointId" : "test-endpoint-id"
}
JSON example
void sendFitbitGetWaterJson(WebSocketsClient& socket) {
  String body;
  if (!offbeat::fitbit::examples::json::buildStringRequest("fitbit.get.water", "", body)) {
    Serial.println("Unable to build fitbit.get.water request");
    return;
  }

  socket.sendTXT(body);
  Serial.println("REQUEST_SENT=fitbit.get.water");
}

void handleFitbitGetWaterJsonResponse(uint8_t* payload, size_t length) {
  StaticJsonDocument<1024> document;
  JsonObjectConst root;
  offbeat::fitbit::examples::json::ParseStatus status =
      offbeat::fitbit::examples::json::parseRoot(payload, length, document, root);

  if (status == offbeat::fitbit::examples::json::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.water response");
    return;
  }

  JsonObjectConst water = root["fitbit.get.water"].as<JsonObjectConst>();
  if (water.isNull()) {
    Serial.println("No fitbit.get.water payload");
    return;
  }

  offbeat::fitbit::examples::json::printLine(
      "Water intake: ",
      offbeat::fitbit::examples::json::readDouble(water["water"]),
      1);
  offbeat::fitbit::examples::json::printEndpoint(root);
  Serial.println("TEST:PASS");
}
CBOR example
void sendFitbitGetWaterCbor(WebSocketsClient& socket) {
  uint8_t encoded[128];
  size_t encodedLength =
      offbeat::fitbit::examples::cbor::buildStringRequest("fitbit.get.water", "", encoded, sizeof(encoded));
  if (encodedLength == 0) {
    Serial.println("Unable to build fitbit.get.water request");
    return;
  }

  socket.sendBIN(encoded, encodedLength);
  Serial.println("REQUEST_SENT=fitbit.get.water");
}

void handleFitbitGetWaterCborResponse(uint8_t* payload, size_t length) {
  CborBuffer buffer(1024);
  cn_cbor* root = NULL;
  offbeat::fitbit::examples::cbor::ParseStatus status =
      offbeat::fitbit::examples::cbor::parseRoot(payload, length, buffer, root);

  if (status == offbeat::fitbit::examples::cbor::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.water response");
    return;
  }

  cn_cbor* water = offbeat::fitbit::examples::cbor::findField(root, "fitbit.get.water");
  if (water == NULL || water->type != CN_CBOR_MAP) {
    Serial.println("No fitbit.get.water payload");
    return;
  }

  offbeat::fitbit::examples::cbor::printLine(
      "Water intake: ",
      offbeat::fitbit::examples::cbor::readDouble(offbeat::fitbit::examples::cbor::findField(water, "water")),
      1);
  offbeat::fitbit::examples::cbor::printEndpoint(root);
  Serial.println("TEST:PASS");
}
create water log
Request
{
  "fitbit.create.water.log" : {
    "amount" : "124",
    "unit" : "ml"
  }
}
Example response
{
  "fitbit.create.water.log" : {
    "result" : "OK"
  },
  "endpointId" : "test-endpoint-id"
}
JSON example
constexpr char kCreateWaterAmount[] = "124";
constexpr char kCreateWaterUnit[] = "ml";

void sendFitbitCreateWaterLogJson(WebSocketsClient& socket) {
  String body;
  if (!offbeat::fitbit::examples::json::buildObjectRequest(
          "fitbit.create.water.log",
          body,
          [](JsonObject value) {
            value["amount"] = kCreateWaterAmount;
            value["unit"] = kCreateWaterUnit;
          })) {
    Serial.println("Unable to build fitbit.create.water.log request");
    return;
  }

  socket.sendTXT(body);
  Serial.println("REQUEST_SENT=fitbit.create.water.log");
}

void handleFitbitCreateWaterLogJsonResponse(uint8_t* payload, size_t length) {
  StaticJsonDocument<1024> document;
  JsonObjectConst root;
  offbeat::fitbit::examples::json::ParseStatus status =
      offbeat::fitbit::examples::json::parseRoot(payload, length, document, root);

  if (status == offbeat::fitbit::examples::json::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.create.water.log response");
    return;
  }

  JsonObjectConst response = root["fitbit.create.water.log"].as<JsonObjectConst>();
  if (response.isNull()) {
    Serial.println("No fitbit.create.water.log payload");
    return;
  }

  offbeat::fitbit::examples::json::printLine("Amount: ", kCreateWaterAmount);
  offbeat::fitbit::examples::json::printLine("Unit: ", kCreateWaterUnit);
  offbeat::fitbit::examples::json::printLine(
      "Result: ",
      offbeat::fitbit::examples::json::readString(response["result"]));
  offbeat::fitbit::examples::json::printEndpoint(root);
  Serial.println("TEST:PASS");
}
CBOR example
constexpr char kCreateWaterAmountCbor[] = "124";
constexpr char kCreateWaterUnitCbor[] = "ml";

void sendFitbitCreateWaterLogCbor(WebSocketsClient& socket) {
  uint8_t encoded[192];
  size_t encodedLength = offbeat::fitbit::examples::cbor::buildObjectRequest(
      "fitbit.create.water.log",
      encoded,
      sizeof(encoded),
      [](CborObject& value) {
        value.set("amount", kCreateWaterAmountCbor);
        value.set("unit", kCreateWaterUnitCbor);
      });
  if (encodedLength == 0) {
    Serial.println("Unable to build fitbit.create.water.log request");
    return;
  }

  socket.sendBIN(encoded, encodedLength);
  Serial.println("REQUEST_SENT=fitbit.create.water.log");
}

void handleFitbitCreateWaterLogCborResponse(uint8_t* payload, size_t length) {
  CborBuffer buffer(1024);
  cn_cbor* root = NULL;
  offbeat::fitbit::examples::cbor::ParseStatus status =
      offbeat::fitbit::examples::cbor::parseRoot(payload, length, buffer, root);

  if (status == offbeat::fitbit::examples::cbor::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.create.water.log response");
    return;
  }

  cn_cbor* response = offbeat::fitbit::examples::cbor::findField(root, "fitbit.create.water.log");
  if (response == NULL || response->type != CN_CBOR_MAP) {
    Serial.println("No fitbit.create.water.log payload");
    return;
  }

  offbeat::fitbit::examples::cbor::printLine("Amount: ", kCreateWaterAmountCbor);
  offbeat::fitbit::examples::cbor::printLine("Unit: ", kCreateWaterUnitCbor);
  offbeat::fitbit::examples::cbor::printLine(
      "Result: ",
      offbeat::fitbit::examples::cbor::readString(offbeat::fitbit::examples::cbor::findField(response, "result")));
  offbeat::fitbit::examples::cbor::printEndpoint(root);
  Serial.println("TEST:PASS");
}
get water goal
Request
{
  "fitbit.get.water.goal" : ""
}
Example response
{
  "fitbit.get.water.goal" : {
    "goal" : 24,
    "startDate" : "2019-03-21"
  },
  "endpointId" : "test-endpoint-id"
}
JSON example
void sendFitbitGetWaterGoalJson(WebSocketsClient& socket) {
  String body;
  if (!offbeat::fitbit::examples::json::buildStringRequest("fitbit.get.water.goal", "", body)) {
    Serial.println("Unable to build fitbit.get.water.goal request");
    return;
  }

  socket.sendTXT(body);
  Serial.println("REQUEST_SENT=fitbit.get.water.goal");
}

void handleFitbitGetWaterGoalJsonResponse(uint8_t* payload, size_t length) {
  StaticJsonDocument<1024> document;
  JsonObjectConst root;
  offbeat::fitbit::examples::json::ParseStatus status =
      offbeat::fitbit::examples::json::parseRoot(payload, length, document, root);

  if (status == offbeat::fitbit::examples::json::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.water.goal response");
    return;
  }

  JsonObjectConst waterGoal = root["fitbit.get.water.goal"].as<JsonObjectConst>();
  if (waterGoal.isNull()) {
    Serial.println("No fitbit.get.water.goal payload");
    return;
  }

  offbeat::fitbit::examples::json::printLine(
      "Goal: ",
      offbeat::fitbit::examples::json::readLong(waterGoal["goal"]));
  offbeat::fitbit::examples::json::printLine(
      "Start date: ",
      offbeat::fitbit::examples::json::readString(waterGoal["startDate"]));
  offbeat::fitbit::examples::json::printEndpoint(root);
  Serial.println("TEST:PASS");
}
CBOR example
void sendFitbitGetWaterGoalCbor(WebSocketsClient& socket) {
  uint8_t encoded[128];
  size_t encodedLength =
      offbeat::fitbit::examples::cbor::buildStringRequest("fitbit.get.water.goal", "", encoded, sizeof(encoded));
  if (encodedLength == 0) {
    Serial.println("Unable to build fitbit.get.water.goal request");
    return;
  }

  socket.sendBIN(encoded, encodedLength);
  Serial.println("REQUEST_SENT=fitbit.get.water.goal");
}

void handleFitbitGetWaterGoalCborResponse(uint8_t* payload, size_t length) {
  CborBuffer buffer(1024);
  cn_cbor* root = NULL;
  offbeat::fitbit::examples::cbor::ParseStatus status =
      offbeat::fitbit::examples::cbor::parseRoot(payload, length, buffer, root);

  if (status == offbeat::fitbit::examples::cbor::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.water.goal response");
    return;
  }

  cn_cbor* waterGoal = offbeat::fitbit::examples::cbor::findField(root, "fitbit.get.water.goal");
  if (waterGoal == NULL || waterGoal->type != CN_CBOR_MAP) {
    Serial.println("No fitbit.get.water.goal payload");
    return;
  }

  offbeat::fitbit::examples::cbor::printLine(
      "Goal: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(waterGoal, "goal")));
  offbeat::fitbit::examples::cbor::printLine(
      "Start date: ",
      offbeat::fitbit::examples::cbor::readString(offbeat::fitbit::examples::cbor::findField(waterGoal, "startDate")));
  offbeat::fitbit::examples::cbor::printEndpoint(root);
  Serial.println("TEST:PASS");
}
get sleep log
Request
{
  "fitbit.get.sleep" : ""
}
Example response
{
  "fitbit.get.sleep" : {
    "totalMinutesAsleep" : 384,
    "stagesWake" : 78,
    "totalTimeInBed" : 462,
    "stagesDeep" : 104,
    "stageLight" : 205,
    "totalSleepRecords" : 1,
    "stagesRem" : 75
  },
  "endpointId" : "test-endpoint-id"
}
JSON example
void sendFitbitGetSleepJson(WebSocketsClient& socket) {
  String body;
  if (!offbeat::fitbit::examples::json::buildStringRequest("fitbit.get.sleep", "", body)) {
    Serial.println("Unable to build fitbit.get.sleep request");
    return;
  }

  socket.sendTXT(body);
  Serial.println("REQUEST_SENT=fitbit.get.sleep");
}

void handleFitbitGetSleepJsonResponse(uint8_t* payload, size_t length) {
  StaticJsonDocument<1024> document;
  JsonObjectConst root;
  offbeat::fitbit::examples::json::ParseStatus status =
      offbeat::fitbit::examples::json::parseRoot(payload, length, document, root);

  if (status == offbeat::fitbit::examples::json::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.sleep response");
    return;
  }

  JsonObjectConst sleep = root["fitbit.get.sleep"].as<JsonObjectConst>();
  if (sleep.isNull()) {
    Serial.println("No fitbit.get.sleep payload");
    return;
  }

  offbeat::fitbit::examples::json::printLine(
      "Minutes asleep: ",
      offbeat::fitbit::examples::json::readLong(sleep["totalMinutesAsleep"]));
  offbeat::fitbit::examples::json::printLine(
      "Minutes awake: ",
      offbeat::fitbit::examples::json::readLong(sleep["stagesWake"]));
  offbeat::fitbit::examples::json::printLine(
      "Time in bed: ",
      offbeat::fitbit::examples::json::readLong(sleep["totalTimeInBed"]));
  offbeat::fitbit::examples::json::printLine(
      "Deep sleep: ",
      offbeat::fitbit::examples::json::readLong(sleep["stagesDeep"]));
  offbeat::fitbit::examples::json::printLine(
      "Light sleep: ",
      offbeat::fitbit::examples::json::readLong(sleep["stageLight"]));
  offbeat::fitbit::examples::json::printLine(
      "REM sleep: ",
      offbeat::fitbit::examples::json::readLong(sleep["stagesRem"]));
  offbeat::fitbit::examples::json::printLine(
      "Sleep records: ",
      offbeat::fitbit::examples::json::readLong(sleep["totalSleepRecords"]));
  offbeat::fitbit::examples::json::printEndpoint(root);
  Serial.println("TEST:PASS");
}
CBOR example
void sendFitbitGetSleepCbor(WebSocketsClient& socket) {
  uint8_t encoded[128];
  size_t encodedLength =
      offbeat::fitbit::examples::cbor::buildStringRequest("fitbit.get.sleep", "", encoded, sizeof(encoded));
  if (encodedLength == 0) {
    Serial.println("Unable to build fitbit.get.sleep request");
    return;
  }

  socket.sendBIN(encoded, encodedLength);
  Serial.println("REQUEST_SENT=fitbit.get.sleep");
}

void handleFitbitGetSleepCborResponse(uint8_t* payload, size_t length) {
  CborBuffer buffer(1024);
  cn_cbor* root = NULL;
  offbeat::fitbit::examples::cbor::ParseStatus status =
      offbeat::fitbit::examples::cbor::parseRoot(payload, length, buffer, root);

  if (status == offbeat::fitbit::examples::cbor::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.sleep response");
    return;
  }

  cn_cbor* sleep = offbeat::fitbit::examples::cbor::findField(root, "fitbit.get.sleep");
  if (sleep == NULL || sleep->type != CN_CBOR_MAP) {
    Serial.println("No fitbit.get.sleep payload");
    return;
  }

  offbeat::fitbit::examples::cbor::printLine(
      "Minutes asleep: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(sleep, "totalMinutesAsleep")));
  offbeat::fitbit::examples::cbor::printLine(
      "Minutes awake: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(sleep, "stagesWake")));
  offbeat::fitbit::examples::cbor::printLine(
      "Time in bed: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(sleep, "totalTimeInBed")));
  offbeat::fitbit::examples::cbor::printLine(
      "Deep sleep: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(sleep, "stagesDeep")));
  offbeat::fitbit::examples::cbor::printLine(
      "Light sleep: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(sleep, "stageLight")));
  offbeat::fitbit::examples::cbor::printLine(
      "REM sleep: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(sleep, "stagesRem")));
  offbeat::fitbit::examples::cbor::printLine(
      "Sleep records: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(sleep, "totalSleepRecords")));
  offbeat::fitbit::examples::cbor::printEndpoint(root);
  Serial.println("TEST:PASS");
}
get sleep goal
Request
{
  "fitbit.get.sleep.goal" : ""
}
Example response
{
  "fitbit.get.sleep.goal" : {
    "consistency.flowId" : 2,
    "goal.minDuration" : 480
  },
  "endpointId" : "test-endpoint-id"
}
JSON example
void sendFitbitGetSleepGoalJson(WebSocketsClient& socket) {
  String body;
  if (!offbeat::fitbit::examples::json::buildStringRequest("fitbit.get.sleep.goal", "", body)) {
    Serial.println("Unable to build fitbit.get.sleep.goal request");
    return;
  }

  socket.sendTXT(body);
  Serial.println("REQUEST_SENT=fitbit.get.sleep.goal");
}

void handleFitbitGetSleepGoalJsonResponse(uint8_t* payload, size_t length) {
  StaticJsonDocument<1024> document;
  JsonObjectConst root;
  offbeat::fitbit::examples::json::ParseStatus status =
      offbeat::fitbit::examples::json::parseRoot(payload, length, document, root);

  if (status == offbeat::fitbit::examples::json::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.sleep.goal response");
    return;
  }

  JsonObjectConst sleepGoal = root["fitbit.get.sleep.goal"].as<JsonObjectConst>();
  if (sleepGoal.isNull()) {
    Serial.println("No fitbit.get.sleep.goal payload");
    return;
  }

  offbeat::fitbit::examples::json::printLine(
      "Minimum duration: ",
      offbeat::fitbit::examples::json::readLong(sleepGoal["goal.minDuration"]));
  offbeat::fitbit::examples::json::printLine(
      "Consistency flow ID: ",
      offbeat::fitbit::examples::json::readLong(sleepGoal["consistency.flowId"]));
  offbeat::fitbit::examples::json::printEndpoint(root);
  Serial.println("TEST:PASS");
}
CBOR example
void sendFitbitGetSleepGoalCbor(WebSocketsClient& socket) {
  uint8_t encoded[128];
  size_t encodedLength =
      offbeat::fitbit::examples::cbor::buildStringRequest("fitbit.get.sleep.goal", "", encoded, sizeof(encoded));
  if (encodedLength == 0) {
    Serial.println("Unable to build fitbit.get.sleep.goal request");
    return;
  }

  socket.sendBIN(encoded, encodedLength);
  Serial.println("REQUEST_SENT=fitbit.get.sleep.goal");
}

void handleFitbitGetSleepGoalCborResponse(uint8_t* payload, size_t length) {
  CborBuffer buffer(1024);
  cn_cbor* root = NULL;
  offbeat::fitbit::examples::cbor::ParseStatus status =
      offbeat::fitbit::examples::cbor::parseRoot(payload, length, buffer, root);

  if (status == offbeat::fitbit::examples::cbor::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse fitbit.get.sleep.goal response");
    return;
  }

  cn_cbor* sleepGoal = offbeat::fitbit::examples::cbor::findField(root, "fitbit.get.sleep.goal");
  if (sleepGoal == NULL || sleepGoal->type != CN_CBOR_MAP) {
    Serial.println("No fitbit.get.sleep.goal payload");
    return;
  }

  offbeat::fitbit::examples::cbor::printLine(
      "Minimum duration: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(sleepGoal, "goal.minDuration")));
  offbeat::fitbit::examples::cbor::printLine(
      "Consistency flow ID: ",
      offbeat::fitbit::examples::cbor::readLong(offbeat::fitbit::examples::cbor::findField(sleepGoal, "consistency.flowId")));
  offbeat::fitbit::examples::cbor::printEndpoint(root);
  Serial.println("TEST:PASS");
}
Examples