Offbeat-IoT · Small devices. Big APIs.
Integrations
Spotify Integration Google Health Integration Todoist Integration Google Calendar Integration Alexa Integration Google Home Integration
Built-in
Time Integration Ponder Integration Encouragement Integration API OTA updates
Using the Alexa integration

Using the Alexa integration

These sections show the websocket JSON sent to the device for the supported Alexa directives together with matching Arduino device examples from microcontroller-examples.

set brightness
Websocket command (JSON)
{
  "brightness" : 59,
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"brightness": 59, "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaBrightnessPercent(const char* endpointId, long brightnessPercent) {
  Serial.print("Set brightness percent on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(brightnessPercent);

  Serial.print("BRIGHTNESS_PERCENT=");
  Serial.println(brightnessPercent);
}

void applyAlexaBrightnessWeight(const char* endpointId, long brightnessWeight) {
  Serial.print("Adjust brightness weight on ");
  Serial.print(endpointId);
  Serial.print(" by ");
  Serial.println(brightnessWeight);

  Serial.print("BRIGHTNESS_WEIGHT=");
  Serial.println(brightnessWeight);
}

void handleAlexaBrightnessCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa brightness command");
    return;
  }

  const char* endpointId = offbeat::alexa::examples::readEndpointId(root);
  JsonVariantConst brightnessPercent = root[offbeat::alexa::examples::kAdjustBrightnessPercentKey];
  JsonVariantConst brightnessWeight = root[offbeat::alexa::examples::kAdjustBrightnessWeightKey];

  if (!brightnessPercent.isNull()) {
    applyAlexaBrightnessPercent(endpointId, offbeat::alexa::examples::readLong(brightnessPercent));
  } else if (!brightnessWeight.isNull()) {
    applyAlexaBrightnessWeight(endpointId, offbeat::alexa::examples::readLong(brightnessWeight));
  } else {
    Serial.println("No Alexa brightness payload");
    return;
  }

  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
adjust brightness
Websocket command (JSON)
{
  "endpointId" : "the endpoint id",
  "adjustBrightnessWeight" : -3
}
Websocket command (CBOR)
{"endpointId": "the endpoint id", "adjustBrightnessWeight": -3}
Arduino device example
void applyAlexaBrightnessPercent(const char* endpointId, long brightnessPercent) {
  Serial.print("Set brightness percent on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(brightnessPercent);

  Serial.print("BRIGHTNESS_PERCENT=");
  Serial.println(brightnessPercent);
}

void applyAlexaBrightnessWeight(const char* endpointId, long brightnessWeight) {
  Serial.print("Adjust brightness weight on ");
  Serial.print(endpointId);
  Serial.print(" by ");
  Serial.println(brightnessWeight);

  Serial.print("BRIGHTNESS_WEIGHT=");
  Serial.println(brightnessWeight);
}

void handleAlexaBrightnessCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa brightness command");
    return;
  }

  const char* endpointId = offbeat::alexa::examples::readEndpointId(root);
  JsonVariantConst brightnessPercent = root[offbeat::alexa::examples::kAdjustBrightnessPercentKey];
  JsonVariantConst brightnessWeight = root[offbeat::alexa::examples::kAdjustBrightnessWeightKey];

  if (!brightnessPercent.isNull()) {
    applyAlexaBrightnessPercent(endpointId, offbeat::alexa::examples::readLong(brightnessPercent));
  } else if (!brightnessWeight.isNull()) {
    applyAlexaBrightnessWeight(endpointId, offbeat::alexa::examples::readLong(brightnessWeight));
  } else {
    Serial.println("No Alexa brightness payload");
    return;
  }

  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
set color
Websocket command (JSON)
{
  "saturation" : 0.7138,
  "brightness" : 0.6524,
  "endpointId" : "the endpoint id",
  "hue" : 350.5
}
Websocket command (CBOR)
{"saturation": 0.7138, "brightness": 0.6524, "endpointId": "the endpoint id", "hue": 350.5}
Arduino device example
void applyAlexaColorCommand(const char* endpointId, double hue, double saturation, double brightness) {
  Serial.print("Set color on ");
  Serial.println(endpointId);
  offbeat::alexa::examples::printLine("Hue: ", hue, 4);
  offbeat::alexa::examples::printLine("Saturation: ", saturation, 4);
  offbeat::alexa::examples::printLine("Brightness: ", brightness, 4);

  Serial.print("HUE=");
  Serial.println(hue, 4);
  Serial.print("SATURATION=");
  Serial.println(saturation, 4);
  Serial.print("BRIGHTNESS=");
  Serial.println(brightness, 4);
}

void handleAlexaColorCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa color command");
    return;
  }

  JsonVariantConst hueValue = root[offbeat::alexa::examples::kHueKey];
  JsonVariantConst saturationValue = root[offbeat::alexa::examples::kSaturationKey];
  JsonVariantConst brightnessValue = root[offbeat::alexa::examples::kBrightnessKey];
  if (hueValue.isNull() || saturationValue.isNull() || brightnessValue.isNull()) {
    Serial.println("Incomplete Alexa color payload");
    return;
  }

  applyAlexaColorCommand(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readDouble(hueValue),
      offbeat::alexa::examples::readDouble(saturationValue),
      offbeat::alexa::examples::readDouble(brightnessValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
turn on
Websocket command (JSON)
{
  "endpointId" : "the endpoint id",
  "powerstate" : "TurnOn"
}
Websocket command (CBOR)
{"endpointId": "the endpoint id", "powerstate": "TurnOn"}
Arduino device example
void applyAlexaPowerState(const char* endpointId, const char* powerState) {
  Serial.print("Apply Alexa power command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(powerState);

  if (strcmp(powerState, "TurnOn") == 0) {
    Serial.println("Turn your relay or transistor on here");
  } else if (strcmp(powerState, "TurnOff") == 0) {
    Serial.println("Turn your relay or transistor off here");
  } else {
    Serial.println("Unsupported Alexa power command");
    return;
  }

  Serial.print("POWERSTATE=");
  Serial.println(powerState);
}

void handleAlexaPowerCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa power command");
    return;
  }

  JsonVariantConst powerStateValue = root[offbeat::alexa::examples::kPowerStateKey];
  if (powerStateValue.isNull()) {
    Serial.println("No Alexa powerstate payload");
    return;
  }

  applyAlexaPowerState(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(powerStateValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
turn off
Websocket command (JSON)
{
  "endpointId" : "the endpoint id",
  "powerstate" : "TurnOff"
}
Websocket command (CBOR)
{"endpointId": "the endpoint id", "powerstate": "TurnOff"}
Arduino device example
void applyAlexaPowerState(const char* endpointId, const char* powerState) {
  Serial.print("Apply Alexa power command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(powerState);

  if (strcmp(powerState, "TurnOn") == 0) {
    Serial.println("Turn your relay or transistor on here");
  } else if (strcmp(powerState, "TurnOff") == 0) {
    Serial.println("Turn your relay or transistor off here");
  } else {
    Serial.println("Unsupported Alexa power command");
    return;
  }

  Serial.print("POWERSTATE=");
  Serial.println(powerState);
}

void handleAlexaPowerCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa power command");
    return;
  }

  JsonVariantConst powerStateValue = root[offbeat::alexa::examples::kPowerStateKey];
  if (powerStateValue.isNull()) {
    Serial.println("No Alexa powerstate payload");
    return;
  }

  applyAlexaPowerState(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(powerStateValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
turn on a toggle controller
Websocket command (JSON)
{
  "endpointId" : "the endpoint id",
  "petdoor.powerstate" : "TurnOn"
}
Websocket command (CBOR)
{"endpointId": "the endpoint id", "petdoor.powerstate": "TurnOn"}
Arduino device example
void applyAlexaPowerState(const char* endpointId, const char* powerState) {
  Serial.print("Apply Alexa power command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(powerState);

  if (strcmp(powerState, "TurnOn") == 0) {
    Serial.println("Turn your relay or transistor on here");
  } else if (strcmp(powerState, "TurnOff") == 0) {
    Serial.println("Turn your relay or transistor off here");
  } else {
    Serial.println("Unsupported Alexa power command");
    return;
  }

  Serial.print("POWERSTATE=");
  Serial.println(powerState);
}

void handleAlexaPowerCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa power command");
    return;
  }

  JsonVariantConst powerStateValue = root[offbeat::alexa::examples::kPowerStateKey];
  if (powerStateValue.isNull()) {
    Serial.println("No Alexa powerstate payload");
    return;
  }

  applyAlexaPowerState(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(powerStateValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
turn off a toggle controller
Websocket command (JSON)
{
  "endpointId" : "the endpoint id",
  "petdoor.powerstate" : "TurnOff"
}
Websocket command (CBOR)
{"endpointId": "the endpoint id", "petdoor.powerstate": "TurnOff"}
Arduino device example
void applyAlexaPowerState(const char* endpointId, const char* powerState) {
  Serial.print("Apply Alexa power command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(powerState);

  if (strcmp(powerState, "TurnOn") == 0) {
    Serial.println("Turn your relay or transistor on here");
  } else if (strcmp(powerState, "TurnOff") == 0) {
    Serial.println("Turn your relay or transistor off here");
  } else {
    Serial.println("Unsupported Alexa power command");
    return;
  }

  Serial.print("POWERSTATE=");
  Serial.println(powerState);
}

void handleAlexaPowerCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa power command");
    return;
  }

  JsonVariantConst powerStateValue = root[offbeat::alexa::examples::kPowerStateKey];
  if (powerStateValue.isNull()) {
    Serial.println("No Alexa powerstate payload");
    return;
  }

  applyAlexaPowerState(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(powerStateValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
adjust speaker volume using Alexa.StepSpeaker
Websocket command (JSON)
{
  "endpointId" : "the endpoint id",
  "volumesteps" : 20
}
Websocket command (CBOR)
{"endpointId": "the endpoint id", "volumesteps": 20}
Arduino device example
void applyAlexaSpeakerVolume(const char* endpointId, long volumePercent) {
  Serial.print("Set speaker volume on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(volumePercent);

  Serial.print("VOLUME=");
  Serial.println(volumePercent);
}

void applyAlexaSpeakerVolumeSteps(const char* endpointId, long volumeSteps) {
  Serial.print("Adjust speaker volume steps on ");
  Serial.print(endpointId);
  Serial.print(" by ");
  Serial.println(volumeSteps);

  Serial.print("VOLUME_STEPS=");
  Serial.println(volumeSteps);
}

void applyAlexaSpeakerMute(const char* endpointId, bool muted) {
  Serial.print("Set mute on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(muted ? "true" : "false");

  Serial.print("MUTE=");
  Serial.println(muted ? "true" : "false");
}

void handleAlexaSpeakerCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa speaker command");
    return;
  }

  const char* endpointId = offbeat::alexa::examples::readEndpointId(root);
  JsonVariantConst volumeValue = root[offbeat::alexa::examples::kVolumeKey];
  JsonVariantConst volumeStepsValue = root[offbeat::alexa::examples::kVolumeStepsKey];
  JsonVariantConst muteValue = root[offbeat::alexa::examples::kMuteKey];

  if (!volumeValue.isNull()) {
    applyAlexaSpeakerVolume(endpointId, offbeat::alexa::examples::readLong(volumeValue));
  } else if (!volumeStepsValue.isNull()) {
    applyAlexaSpeakerVolumeSteps(endpointId, offbeat::alexa::examples::readLong(volumeStepsValue));
  } else if (!muteValue.isNull()) {
    applyAlexaSpeakerMute(endpointId, offbeat::alexa::examples::readBool(muteValue));
  } else {
    Serial.println("No Alexa speaker payload");
    return;
  }

  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
adjust speaker volume using Alexa.Speaker
Websocket command (JSON)
{
  "endpointId" : "the endpoint id",
  "volumesteps" : 20
}
Websocket command (CBOR)
{"endpointId": "the endpoint id", "volumesteps": 20}
Arduino device example
void applyAlexaSpeakerVolume(const char* endpointId, long volumePercent) {
  Serial.print("Set speaker volume on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(volumePercent);

  Serial.print("VOLUME=");
  Serial.println(volumePercent);
}

void applyAlexaSpeakerVolumeSteps(const char* endpointId, long volumeSteps) {
  Serial.print("Adjust speaker volume steps on ");
  Serial.print(endpointId);
  Serial.print(" by ");
  Serial.println(volumeSteps);

  Serial.print("VOLUME_STEPS=");
  Serial.println(volumeSteps);
}

void applyAlexaSpeakerMute(const char* endpointId, bool muted) {
  Serial.print("Set mute on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(muted ? "true" : "false");

  Serial.print("MUTE=");
  Serial.println(muted ? "true" : "false");
}

void handleAlexaSpeakerCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa speaker command");
    return;
  }

  const char* endpointId = offbeat::alexa::examples::readEndpointId(root);
  JsonVariantConst volumeValue = root[offbeat::alexa::examples::kVolumeKey];
  JsonVariantConst volumeStepsValue = root[offbeat::alexa::examples::kVolumeStepsKey];
  JsonVariantConst muteValue = root[offbeat::alexa::examples::kMuteKey];

  if (!volumeValue.isNull()) {
    applyAlexaSpeakerVolume(endpointId, offbeat::alexa::examples::readLong(volumeValue));
  } else if (!volumeStepsValue.isNull()) {
    applyAlexaSpeakerVolumeSteps(endpointId, offbeat::alexa::examples::readLong(volumeStepsValue));
  } else if (!muteValue.isNull()) {
    applyAlexaSpeakerMute(endpointId, offbeat::alexa::examples::readBool(muteValue));
  } else {
    Serial.println("No Alexa speaker payload");
    return;
  }

  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
mute speaker using Alexa.StepSpeaker
Websocket command (JSON)
{
  "endpointId" : "the endpoint id",
  "mute" : false
}
Websocket command (CBOR)
{"endpointId": "the endpoint id", "mute": false}
Arduino device example
void applyAlexaSpeakerVolume(const char* endpointId, long volumePercent) {
  Serial.print("Set speaker volume on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(volumePercent);

  Serial.print("VOLUME=");
  Serial.println(volumePercent);
}

void applyAlexaSpeakerVolumeSteps(const char* endpointId, long volumeSteps) {
  Serial.print("Adjust speaker volume steps on ");
  Serial.print(endpointId);
  Serial.print(" by ");
  Serial.println(volumeSteps);

  Serial.print("VOLUME_STEPS=");
  Serial.println(volumeSteps);
}

void applyAlexaSpeakerMute(const char* endpointId, bool muted) {
  Serial.print("Set mute on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(muted ? "true" : "false");

  Serial.print("MUTE=");
  Serial.println(muted ? "true" : "false");
}

void handleAlexaSpeakerCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa speaker command");
    return;
  }

  const char* endpointId = offbeat::alexa::examples::readEndpointId(root);
  JsonVariantConst volumeValue = root[offbeat::alexa::examples::kVolumeKey];
  JsonVariantConst volumeStepsValue = root[offbeat::alexa::examples::kVolumeStepsKey];
  JsonVariantConst muteValue = root[offbeat::alexa::examples::kMuteKey];

  if (!volumeValue.isNull()) {
    applyAlexaSpeakerVolume(endpointId, offbeat::alexa::examples::readLong(volumeValue));
  } else if (!volumeStepsValue.isNull()) {
    applyAlexaSpeakerVolumeSteps(endpointId, offbeat::alexa::examples::readLong(volumeStepsValue));
  } else if (!muteValue.isNull()) {
    applyAlexaSpeakerMute(endpointId, offbeat::alexa::examples::readBool(muteValue));
  } else {
    Serial.println("No Alexa speaker payload");
    return;
  }

  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
set speaker volume
Websocket command (JSON)
{
  "volume" : 30,
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"volume": 30, "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaSpeakerVolume(const char* endpointId, long volumePercent) {
  Serial.print("Set speaker volume on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(volumePercent);

  Serial.print("VOLUME=");
  Serial.println(volumePercent);
}

void applyAlexaSpeakerVolumeSteps(const char* endpointId, long volumeSteps) {
  Serial.print("Adjust speaker volume steps on ");
  Serial.print(endpointId);
  Serial.print(" by ");
  Serial.println(volumeSteps);

  Serial.print("VOLUME_STEPS=");
  Serial.println(volumeSteps);
}

void applyAlexaSpeakerMute(const char* endpointId, bool muted) {
  Serial.print("Set mute on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(muted ? "true" : "false");

  Serial.print("MUTE=");
  Serial.println(muted ? "true" : "false");
}

void handleAlexaSpeakerCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa speaker command");
    return;
  }

  const char* endpointId = offbeat::alexa::examples::readEndpointId(root);
  JsonVariantConst volumeValue = root[offbeat::alexa::examples::kVolumeKey];
  JsonVariantConst volumeStepsValue = root[offbeat::alexa::examples::kVolumeStepsKey];
  JsonVariantConst muteValue = root[offbeat::alexa::examples::kMuteKey];

  if (!volumeValue.isNull()) {
    applyAlexaSpeakerVolume(endpointId, offbeat::alexa::examples::readLong(volumeValue));
  } else if (!volumeStepsValue.isNull()) {
    applyAlexaSpeakerVolumeSteps(endpointId, offbeat::alexa::examples::readLong(volumeStepsValue));
  } else if (!muteValue.isNull()) {
    applyAlexaSpeakerMute(endpointId, offbeat::alexa::examples::readBool(muteValue));
  } else {
    Serial.println("No Alexa speaker payload");
    return;
  }

  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
adjust speaker volume using Alexa.Speaker volume
Websocket command (JSON)
{
  "endpointId" : "the endpoint id",
  "volumesteps" : 30
}
Websocket command (CBOR)
{"endpointId": "the endpoint id", "volumesteps": 30}
Arduino device example
void applyAlexaSpeakerVolume(const char* endpointId, long volumePercent) {
  Serial.print("Set speaker volume on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(volumePercent);

  Serial.print("VOLUME=");
  Serial.println(volumePercent);
}

void applyAlexaSpeakerVolumeSteps(const char* endpointId, long volumeSteps) {
  Serial.print("Adjust speaker volume steps on ");
  Serial.print(endpointId);
  Serial.print(" by ");
  Serial.println(volumeSteps);

  Serial.print("VOLUME_STEPS=");
  Serial.println(volumeSteps);
}

void applyAlexaSpeakerMute(const char* endpointId, bool muted) {
  Serial.print("Set mute on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(muted ? "true" : "false");

  Serial.print("MUTE=");
  Serial.println(muted ? "true" : "false");
}

void handleAlexaSpeakerCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa speaker command");
    return;
  }

  const char* endpointId = offbeat::alexa::examples::readEndpointId(root);
  JsonVariantConst volumeValue = root[offbeat::alexa::examples::kVolumeKey];
  JsonVariantConst volumeStepsValue = root[offbeat::alexa::examples::kVolumeStepsKey];
  JsonVariantConst muteValue = root[offbeat::alexa::examples::kMuteKey];

  if (!volumeValue.isNull()) {
    applyAlexaSpeakerVolume(endpointId, offbeat::alexa::examples::readLong(volumeValue));
  } else if (!volumeStepsValue.isNull()) {
    applyAlexaSpeakerVolumeSteps(endpointId, offbeat::alexa::examples::readLong(volumeStepsValue));
  } else if (!muteValue.isNull()) {
    applyAlexaSpeakerMute(endpointId, offbeat::alexa::examples::readBool(muteValue));
  } else {
    Serial.println("No Alexa speaker payload");
    return;
  }

  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
mute speaker using Alexa.Speaker
Websocket command (JSON)
{
  "endpointId" : "the endpoint id",
  "mute" : false
}
Websocket command (CBOR)
{"endpointId": "the endpoint id", "mute": false}
Arduino device example
void applyAlexaSpeakerVolume(const char* endpointId, long volumePercent) {
  Serial.print("Set speaker volume on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(volumePercent);

  Serial.print("VOLUME=");
  Serial.println(volumePercent);
}

void applyAlexaSpeakerVolumeSteps(const char* endpointId, long volumeSteps) {
  Serial.print("Adjust speaker volume steps on ");
  Serial.print(endpointId);
  Serial.print(" by ");
  Serial.println(volumeSteps);

  Serial.print("VOLUME_STEPS=");
  Serial.println(volumeSteps);
}

void applyAlexaSpeakerMute(const char* endpointId, bool muted) {
  Serial.print("Set mute on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(muted ? "true" : "false");

  Serial.print("MUTE=");
  Serial.println(muted ? "true" : "false");
}

void handleAlexaSpeakerCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa speaker command");
    return;
  }

  const char* endpointId = offbeat::alexa::examples::readEndpointId(root);
  JsonVariantConst volumeValue = root[offbeat::alexa::examples::kVolumeKey];
  JsonVariantConst volumeStepsValue = root[offbeat::alexa::examples::kVolumeStepsKey];
  JsonVariantConst muteValue = root[offbeat::alexa::examples::kMuteKey];

  if (!volumeValue.isNull()) {
    applyAlexaSpeakerVolume(endpointId, offbeat::alexa::examples::readLong(volumeValue));
  } else if (!volumeStepsValue.isNull()) {
    applyAlexaSpeakerVolumeSteps(endpointId, offbeat::alexa::examples::readLong(volumeStepsValue));
  } else if (!muteValue.isNull()) {
    applyAlexaSpeakerMute(endpointId, offbeat::alexa::examples::readBool(muteValue));
  } else {
    Serial.println("No Alexa speaker payload");
    return;
  }

  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
playback fast forward
Websocket command (JSON)
{
  "playerControl" : "Next",
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"playerControl": "Next", "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaPlaybackCommand(const char* endpointId, const char* playerControl) {
  Serial.print("Apply playback command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(playerControl);

  if (strcmp(playerControl, "Play") == 0) {
    Serial.println("Start playback here");
  } else if (strcmp(playerControl, "Pause") == 0) {
    Serial.println("Pause playback here");
  } else if (strcmp(playerControl, "Stop") == 0) {
    Serial.println("Stop playback here");
  } else if (strcmp(playerControl, "Next") == 0) {
    Serial.println("Skip to the next item here");
  } else if (strcmp(playerControl, "Prev") == 0) {
    Serial.println("Go to the previous item here");
  } else {
    Serial.println("Unsupported Alexa playback command");
    return;
  }

  Serial.print("PLAYER_CONTROL=");
  Serial.println(playerControl);
}

void handleAlexaPlaybackCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa playback command");
    return;
  }

  JsonVariantConst playerControlValue = root[offbeat::alexa::examples::kPlayerControlKey];
  if (playerControlValue.isNull()) {
    Serial.println("No Alexa playback payload");
    return;
  }

  applyAlexaPlaybackCommand(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(playerControlValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
playback next
Websocket command (JSON)
{
  "playerControl" : "Next",
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"playerControl": "Next", "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaPlaybackCommand(const char* endpointId, const char* playerControl) {
  Serial.print("Apply playback command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(playerControl);

  if (strcmp(playerControl, "Play") == 0) {
    Serial.println("Start playback here");
  } else if (strcmp(playerControl, "Pause") == 0) {
    Serial.println("Pause playback here");
  } else if (strcmp(playerControl, "Stop") == 0) {
    Serial.println("Stop playback here");
  } else if (strcmp(playerControl, "Next") == 0) {
    Serial.println("Skip to the next item here");
  } else if (strcmp(playerControl, "Prev") == 0) {
    Serial.println("Go to the previous item here");
  } else {
    Serial.println("Unsupported Alexa playback command");
    return;
  }

  Serial.print("PLAYER_CONTROL=");
  Serial.println(playerControl);
}

void handleAlexaPlaybackCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa playback command");
    return;
  }

  JsonVariantConst playerControlValue = root[offbeat::alexa::examples::kPlayerControlKey];
  if (playerControlValue.isNull()) {
    Serial.println("No Alexa playback payload");
    return;
  }

  applyAlexaPlaybackCommand(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(playerControlValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
playback pause
Websocket command (JSON)
{
  "playerControl" : "Pause",
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"playerControl": "Pause", "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaPlaybackCommand(const char* endpointId, const char* playerControl) {
  Serial.print("Apply playback command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(playerControl);

  if (strcmp(playerControl, "Play") == 0) {
    Serial.println("Start playback here");
  } else if (strcmp(playerControl, "Pause") == 0) {
    Serial.println("Pause playback here");
  } else if (strcmp(playerControl, "Stop") == 0) {
    Serial.println("Stop playback here");
  } else if (strcmp(playerControl, "Next") == 0) {
    Serial.println("Skip to the next item here");
  } else if (strcmp(playerControl, "Prev") == 0) {
    Serial.println("Go to the previous item here");
  } else {
    Serial.println("Unsupported Alexa playback command");
    return;
  }

  Serial.print("PLAYER_CONTROL=");
  Serial.println(playerControl);
}

void handleAlexaPlaybackCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa playback command");
    return;
  }

  JsonVariantConst playerControlValue = root[offbeat::alexa::examples::kPlayerControlKey];
  if (playerControlValue.isNull()) {
    Serial.println("No Alexa playback payload");
    return;
  }

  applyAlexaPlaybackCommand(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(playerControlValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
playback play
Websocket command (JSON)
{
  "playerControl" : "Play",
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"playerControl": "Play", "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaPlaybackCommand(const char* endpointId, const char* playerControl) {
  Serial.print("Apply playback command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(playerControl);

  if (strcmp(playerControl, "Play") == 0) {
    Serial.println("Start playback here");
  } else if (strcmp(playerControl, "Pause") == 0) {
    Serial.println("Pause playback here");
  } else if (strcmp(playerControl, "Stop") == 0) {
    Serial.println("Stop playback here");
  } else if (strcmp(playerControl, "Next") == 0) {
    Serial.println("Skip to the next item here");
  } else if (strcmp(playerControl, "Prev") == 0) {
    Serial.println("Go to the previous item here");
  } else {
    Serial.println("Unsupported Alexa playback command");
    return;
  }

  Serial.print("PLAYER_CONTROL=");
  Serial.println(playerControl);
}

void handleAlexaPlaybackCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa playback command");
    return;
  }

  JsonVariantConst playerControlValue = root[offbeat::alexa::examples::kPlayerControlKey];
  if (playerControlValue.isNull()) {
    Serial.println("No Alexa playback payload");
    return;
  }

  applyAlexaPlaybackCommand(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(playerControlValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
playback previous
Websocket command (JSON)
{
  "playerControl" : "Prev",
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"playerControl": "Prev", "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaPlaybackCommand(const char* endpointId, const char* playerControl) {
  Serial.print("Apply playback command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(playerControl);

  if (strcmp(playerControl, "Play") == 0) {
    Serial.println("Start playback here");
  } else if (strcmp(playerControl, "Pause") == 0) {
    Serial.println("Pause playback here");
  } else if (strcmp(playerControl, "Stop") == 0) {
    Serial.println("Stop playback here");
  } else if (strcmp(playerControl, "Next") == 0) {
    Serial.println("Skip to the next item here");
  } else if (strcmp(playerControl, "Prev") == 0) {
    Serial.println("Go to the previous item here");
  } else {
    Serial.println("Unsupported Alexa playback command");
    return;
  }

  Serial.print("PLAYER_CONTROL=");
  Serial.println(playerControl);
}

void handleAlexaPlaybackCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa playback command");
    return;
  }

  JsonVariantConst playerControlValue = root[offbeat::alexa::examples::kPlayerControlKey];
  if (playerControlValue.isNull()) {
    Serial.println("No Alexa playback payload");
    return;
  }

  applyAlexaPlaybackCommand(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(playerControlValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
playback rewind
Websocket command (JSON)
{
  "playerControl" : "Prev",
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"playerControl": "Prev", "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaPlaybackCommand(const char* endpointId, const char* playerControl) {
  Serial.print("Apply playback command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(playerControl);

  if (strcmp(playerControl, "Play") == 0) {
    Serial.println("Start playback here");
  } else if (strcmp(playerControl, "Pause") == 0) {
    Serial.println("Pause playback here");
  } else if (strcmp(playerControl, "Stop") == 0) {
    Serial.println("Stop playback here");
  } else if (strcmp(playerControl, "Next") == 0) {
    Serial.println("Skip to the next item here");
  } else if (strcmp(playerControl, "Prev") == 0) {
    Serial.println("Go to the previous item here");
  } else {
    Serial.println("Unsupported Alexa playback command");
    return;
  }

  Serial.print("PLAYER_CONTROL=");
  Serial.println(playerControl);
}

void handleAlexaPlaybackCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa playback command");
    return;
  }

  JsonVariantConst playerControlValue = root[offbeat::alexa::examples::kPlayerControlKey];
  if (playerControlValue.isNull()) {
    Serial.println("No Alexa playback payload");
    return;
  }

  applyAlexaPlaybackCommand(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(playerControlValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
playback start over
Websocket command (JSON)
{
  "playerControl" : "Prev",
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"playerControl": "Prev", "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaPlaybackCommand(const char* endpointId, const char* playerControl) {
  Serial.print("Apply playback command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(playerControl);

  if (strcmp(playerControl, "Play") == 0) {
    Serial.println("Start playback here");
  } else if (strcmp(playerControl, "Pause") == 0) {
    Serial.println("Pause playback here");
  } else if (strcmp(playerControl, "Stop") == 0) {
    Serial.println("Stop playback here");
  } else if (strcmp(playerControl, "Next") == 0) {
    Serial.println("Skip to the next item here");
  } else if (strcmp(playerControl, "Prev") == 0) {
    Serial.println("Go to the previous item here");
  } else {
    Serial.println("Unsupported Alexa playback command");
    return;
  }

  Serial.print("PLAYER_CONTROL=");
  Serial.println(playerControl);
}

void handleAlexaPlaybackCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa playback command");
    return;
  }

  JsonVariantConst playerControlValue = root[offbeat::alexa::examples::kPlayerControlKey];
  if (playerControlValue.isNull()) {
    Serial.println("No Alexa playback payload");
    return;
  }

  applyAlexaPlaybackCommand(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(playerControlValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
playback stop
Websocket command (JSON)
{
  "playerControl" : "Stop",
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"playerControl": "Stop", "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaPlaybackCommand(const char* endpointId, const char* playerControl) {
  Serial.print("Apply playback command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(playerControl);

  if (strcmp(playerControl, "Play") == 0) {
    Serial.println("Start playback here");
  } else if (strcmp(playerControl, "Pause") == 0) {
    Serial.println("Pause playback here");
  } else if (strcmp(playerControl, "Stop") == 0) {
    Serial.println("Stop playback here");
  } else if (strcmp(playerControl, "Next") == 0) {
    Serial.println("Skip to the next item here");
  } else if (strcmp(playerControl, "Prev") == 0) {
    Serial.println("Go to the previous item here");
  } else {
    Serial.println("Unsupported Alexa playback command");
    return;
  }

  Serial.print("PLAYER_CONTROL=");
  Serial.println(playerControl);
}

void handleAlexaPlaybackCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa playback command");
    return;
  }

  JsonVariantConst playerControlValue = root[offbeat::alexa::examples::kPlayerControlKey];
  if (playerControlValue.isNull()) {
    Serial.println("No Alexa playback payload");
    return;
  }

  applyAlexaPlaybackCommand(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(playerControlValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
skip channels
Websocket command (JSON)
{
  "skipChannel" : 1,
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"skipChannel": 1, "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaSetChannel(const char* endpointId, long channelNumber) {
  Serial.print("Set channel on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(channelNumber);

  Serial.print("SET_CHANNEL=");
  Serial.println(channelNumber);
}

void applyAlexaSkipChannel(const char* endpointId, long channelOffset) {
  Serial.print("Skip channel on ");
  Serial.print(endpointId);
  Serial.print(" by ");
  Serial.println(channelOffset);

  Serial.print("SKIP_CHANNEL=");
  Serial.println(channelOffset);
}

void handleAlexaChannelCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa channel command");
    return;
  }

  const char* endpointId = offbeat::alexa::examples::readEndpointId(root);
  JsonVariantConst setChannelValue = root[offbeat::alexa::examples::kSetChannelKey];
  JsonVariantConst skipChannelValue = root[offbeat::alexa::examples::kSkipChannelKey];

  if (!setChannelValue.isNull()) {
    applyAlexaSetChannel(endpointId, offbeat::alexa::examples::readLong(setChannelValue));
  } else if (!skipChannelValue.isNull()) {
    applyAlexaSkipChannel(endpointId, offbeat::alexa::examples::readLong(skipChannelValue));
  } else {
    Serial.println("No Alexa channel payload");
    return;
  }

  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
change channel
Websocket command (JSON)
{
  "endpointId" : "the endpoint id",
  "SetChannel" : 1
}
Websocket command (CBOR)
{"endpointId": "the endpoint id", "SetChannel": 1}
Arduino device example
void applyAlexaSetChannel(const char* endpointId, long channelNumber) {
  Serial.print("Set channel on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.println(channelNumber);

  Serial.print("SET_CHANNEL=");
  Serial.println(channelNumber);
}

void applyAlexaSkipChannel(const char* endpointId, long channelOffset) {
  Serial.print("Skip channel on ");
  Serial.print(endpointId);
  Serial.print(" by ");
  Serial.println(channelOffset);

  Serial.print("SKIP_CHANNEL=");
  Serial.println(channelOffset);
}

void handleAlexaChannelCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa channel command");
    return;
  }

  const char* endpointId = offbeat::alexa::examples::readEndpointId(root);
  JsonVariantConst setChannelValue = root[offbeat::alexa::examples::kSetChannelKey];
  JsonVariantConst skipChannelValue = root[offbeat::alexa::examples::kSkipChannelKey];

  if (!setChannelValue.isNull()) {
    applyAlexaSetChannel(endpointId, offbeat::alexa::examples::readLong(setChannelValue));
  } else if (!skipChannelValue.isNull()) {
    applyAlexaSkipChannel(endpointId, offbeat::alexa::examples::readLong(skipChannelValue));
  } else {
    Serial.println("No Alexa channel payload");
    return;
  }

  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
set blind tilt
Websocket command (JSON)
{
  "setTiltPercent" : 60,
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"setTiltPercent": 60, "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaBlindTiltPercent(const char* endpointId, long tiltPercent) {
  long clampedTiltPercent = clampPercent(tiltPercent);
  long tiltDegrees = percentToDegrees(clampedTiltPercent);

  Serial.print("Set blind tilt on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.print(clampedTiltPercent);
  Serial.println("%");

  Serial.print("TILT_PERCENT=");
  Serial.println(clampedTiltPercent);
  Serial.print("TILT_DEGREES=");
  Serial.println(tiltDegrees);
}

void adjustAlexaBlindTiltPercent(const char* endpointId, long tiltPercentDelta) {
  Serial.print("Adjust blind tilt on ");
  Serial.print(endpointId);
  Serial.print(" by ");
  Serial.print(tiltPercentDelta);
  Serial.println("%");

  Serial.print("TILT_DELTA_PERCENT=");
  Serial.println(tiltPercentDelta);
  Serial.println("Update your tracked tilt state before driving the motor.");
}

void handleAlexaBlindTiltCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa blind tilt command");
    return;
  }

  const char* endpointId = offbeat::alexa::examples::readEndpointId(root);
  JsonVariantConst rangeValue = root[offbeat::alexa::examples::kRangeValueKey];
  JsonVariantConst rangeValueDelta = root[offbeat::alexa::examples::kRangeValueDeltaKey];

  if (!rangeValue.isNull()) {
    applyAlexaBlindTiltPercent(
        endpointId, offbeat::alexa::examples::readLong(rangeValue));
  } else if (!rangeValueDelta.isNull()) {
    adjustAlexaBlindTiltPercent(
        endpointId, offbeat::alexa::examples::readLong(rangeValueDelta));
  } else {
    Serial.println("No Alexa blind tilt payload");
    return;
  }

  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
adjust blind tilt
Websocket command (JSON)
{
  "adjustTiltPercent" : 10,
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"adjustTiltPercent": 10, "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaBlindTiltPercent(const char* endpointId, long tiltPercent) {
  long clampedTiltPercent = clampPercent(tiltPercent);
  long tiltDegrees = percentToDegrees(clampedTiltPercent);

  Serial.print("Set blind tilt on ");
  Serial.print(endpointId);
  Serial.print(" to ");
  Serial.print(clampedTiltPercent);
  Serial.println("%");

  Serial.print("TILT_PERCENT=");
  Serial.println(clampedTiltPercent);
  Serial.print("TILT_DEGREES=");
  Serial.println(tiltDegrees);
}

void adjustAlexaBlindTiltPercent(const char* endpointId, long tiltPercentDelta) {
  Serial.print("Adjust blind tilt on ");
  Serial.print(endpointId);
  Serial.print(" by ");
  Serial.print(tiltPercentDelta);
  Serial.println("%");

  Serial.print("TILT_DELTA_PERCENT=");
  Serial.println(tiltPercentDelta);
  Serial.println("Update your tracked tilt state before driving the motor.");
}

void handleAlexaBlindTiltCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa blind tilt command");
    return;
  }

  const char* endpointId = offbeat::alexa::examples::readEndpointId(root);
  JsonVariantConst rangeValue = root[offbeat::alexa::examples::kRangeValueKey];
  JsonVariantConst rangeValueDelta = root[offbeat::alexa::examples::kRangeValueDeltaKey];

  if (!rangeValue.isNull()) {
    applyAlexaBlindTiltPercent(
        endpointId, offbeat::alexa::examples::readLong(rangeValue));
  } else if (!rangeValueDelta.isNull()) {
    adjustAlexaBlindTiltPercent(
        endpointId, offbeat::alexa::examples::readLong(rangeValueDelta));
  } else {
    Serial.println("No Alexa blind tilt payload");
    return;
  }

  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
activate scene
Websocket command (JSON)
{
  "endpointId" : "the endpoint id",
  "scenestate" : "TurnOn"
}
Websocket command (CBOR)
{"endpointId": "the endpoint id", "scenestate": "TurnOn"}
Arduino device example
void applyAlexaSceneState(const char* endpointId, const char* sceneState) {
  Serial.print("Apply scene command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(sceneState);

  if (strcmp(sceneState, "TurnOn") == 0) {
    Serial.println("Activate the scene here");
  } else if (strcmp(sceneState, "TurnOff") == 0) {
    Serial.println("Deactivate the scene here");
  } else {
    Serial.println("Unsupported Alexa scene command");
    return;
  }

  Serial.print("SCENESTATE=");
  Serial.println(sceneState);
}

void handleAlexaSceneCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa scene command");
    return;
  }

  JsonVariantConst sceneStateValue = root[offbeat::alexa::examples::kSceneStateKey];
  if (sceneStateValue.isNull()) {
    Serial.println("No Alexa scene payload");
    return;
  }

  applyAlexaSceneState(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(sceneStateValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
deactivate scene
Websocket command (JSON)
{
  "endpointId" : "the endpoint id",
  "scenestate" : "TurnOff"
}
Websocket command (CBOR)
{"endpointId": "the endpoint id", "scenestate": "TurnOff"}
Arduino device example
void applyAlexaSceneState(const char* endpointId, const char* sceneState) {
  Serial.print("Apply scene command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(sceneState);

  if (strcmp(sceneState, "TurnOn") == 0) {
    Serial.println("Activate the scene here");
  } else if (strcmp(sceneState, "TurnOff") == 0) {
    Serial.println("Deactivate the scene here");
  } else {
    Serial.println("Unsupported Alexa scene command");
    return;
  }

  Serial.print("SCENESTATE=");
  Serial.println(sceneState);
}

void handleAlexaSceneCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa scene command");
    return;
  }

  JsonVariantConst sceneStateValue = root[offbeat::alexa::examples::kSceneStateKey];
  if (sceneStateValue.isNull()) {
    Serial.println("No Alexa scene payload");
    return;
  }

  applyAlexaSceneState(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(sceneStateValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
set thermostat mode
Websocket command (JSON)
{
  "thermMode" : "COOL",
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"thermMode": "COOL", "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaPowerState(const char* endpointId, const char* powerState) {
  Serial.print("Apply Alexa power command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(powerState);

  if (strcmp(powerState, "TurnOn") == 0) {
    Serial.println("Turn your relay or transistor on here");
  } else if (strcmp(powerState, "TurnOff") == 0) {
    Serial.println("Turn your relay or transistor off here");
  } else {
    Serial.println("Unsupported Alexa power command");
    return;
  }

  Serial.print("POWERSTATE=");
  Serial.println(powerState);
}

void handleAlexaPowerCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa power command");
    return;
  }

  JsonVariantConst powerStateValue = root[offbeat::alexa::examples::kPowerStateKey];
  if (powerStateValue.isNull()) {
    Serial.println("No Alexa powerstate payload");
    return;
  }

  applyAlexaPowerState(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(powerStateValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
set target temperature
Websocket command (JSON)
{
  "setTargetTemp" : "20.0;CELSIUS",
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"setTargetTemp": "20.0;CELSIUS", "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaPowerState(const char* endpointId, const char* powerState) {
  Serial.print("Apply Alexa power command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(powerState);

  if (strcmp(powerState, "TurnOn") == 0) {
    Serial.println("Turn your relay or transistor on here");
  } else if (strcmp(powerState, "TurnOff") == 0) {
    Serial.println("Turn your relay or transistor off here");
  } else {
    Serial.println("Unsupported Alexa power command");
    return;
  }

  Serial.print("POWERSTATE=");
  Serial.println(powerState);
}

void handleAlexaPowerCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa power command");
    return;
  }

  JsonVariantConst powerStateValue = root[offbeat::alexa::examples::kPowerStateKey];
  if (powerStateValue.isNull()) {
    Serial.println("No Alexa powerstate payload");
    return;
  }

  applyAlexaPowerState(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(powerStateValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
adjust target temperature
Websocket command (JSON)
{
  "adjTargetTemp" : "-3.0;CELSIUS",
  "endpointId" : "the endpoint id"
}
Websocket command (CBOR)
{"adjTargetTemp": "-3.0;CELSIUS", "endpointId": "the endpoint id"}
Arduino device example
void applyAlexaPowerState(const char* endpointId, const char* powerState) {
  Serial.print("Apply Alexa power command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(powerState);

  if (strcmp(powerState, "TurnOn") == 0) {
    Serial.println("Turn your relay or transistor on here");
  } else if (strcmp(powerState, "TurnOff") == 0) {
    Serial.println("Turn your relay or transistor off here");
  } else {
    Serial.println("Unsupported Alexa power command");
    return;
  }

  Serial.print("POWERSTATE=");
  Serial.println(powerState);
}

void handleAlexaPowerCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa power command");
    return;
  }

  JsonVariantConst powerStateValue = root[offbeat::alexa::examples::kPowerStateKey];
  if (powerStateValue.isNull()) {
    Serial.println("No Alexa powerstate payload");
    return;
  }

  applyAlexaPowerState(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(powerStateValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}
set mode
Websocket command (JSON)
{
  "endpointId" : "the endpoint id",
  "setMode" : "normal"
}
Websocket command (CBOR)
{"endpointId": "the endpoint id", "setMode": "normal"}
Arduino device example
void applyAlexaPowerState(const char* endpointId, const char* powerState) {
  Serial.print("Apply Alexa power command for ");
  Serial.print(endpointId);
  Serial.print(": ");
  Serial.println(powerState);

  if (strcmp(powerState, "TurnOn") == 0) {
    Serial.println("Turn your relay or transistor on here");
  } else if (strcmp(powerState, "TurnOff") == 0) {
    Serial.println("Turn your relay or transistor off here");
  } else {
    Serial.println("Unsupported Alexa power command");
    return;
  }

  Serial.print("POWERSTATE=");
  Serial.println(powerState);
}

void handleAlexaPowerCommand(uint8_t* payload, size_t length) {
  StaticJsonDocument<256> document;
  JsonObjectConst root;
  offbeat::alexa::examples::ParseStatus status =
      offbeat::alexa::examples::parseRoot(payload, length, document, root);

  if (status == offbeat::alexa::examples::ParseStatus::kInvalidPayload) {
    Serial.println("Unable to parse Alexa power command");
    return;
  }

  JsonVariantConst powerStateValue = root[offbeat::alexa::examples::kPowerStateKey];
  if (powerStateValue.isNull()) {
    Serial.println("No Alexa powerstate payload");
    return;
  }

  applyAlexaPowerState(
      offbeat::alexa::examples::readEndpointId(root),
      offbeat::alexa::examples::readString(powerStateValue));
  offbeat::alexa::examples::printEndpoint(root);
  Serial.println("TEST:PASS");
}

Live camera view

Offbeat’s Alexa integration can show a live camera view on an Echo Show through Alexa.CameraStreamController.

The device does not talk to Alexa directly and does not serve a stream URL. Offbeat handles the InitializeCameraStreams directive, asks the device to push JPEG frames over its existing WebSocket, relays those frames to the media gateway, and the gateway transcodes them to H.264 MPEG-TS HLS and serves a short-lived, signed HTTPS URL that Alexa fetches.

Note
This is Alexa.CameraStreamController (HLS), not Alexa.RTCSessionController (WebRTC).
Note
The device contract is assistant-agnostic. The same firmware (or mock) streams identically whether the device is linked to Alexa or Google Home: it receives the same startVideo/stopVideo commands and pushes the same binary JPEG frames and motion readings. The platform adapts the stream to each assistant. To use one camera with both, link the device to each assistant and enable the CameraStreamController capability for each - no device-side change is required (see Live camera view on the Google Home page).

Declaring a camera

A device is treated as a camera when the operator, in the app:

  1. opens the device and adds the CameraStreamController capability (Your devices → device → Device integrations → Alexa → Configure → check CameraStreamController → Update),

  2. sets the device’s display category to CAMERA, and

  3. opens the camera settings for the device and enables the camera stream and its resolution.

The device id used on the WebSocket connection (?device=<endpointId>) is the endpoint id Alexa sees. Once declared, Offbeat advertises Alexa.CameraStreamController with a cameraStreamConfigurations block (protocol HLS, the configured resolution, authorizationTypes NONE, videoCodecs H264, audioCodecs NONE) so Alexa discovers the camera.

Device commands (server to device)

Offbeat sends these over the device’s existing WebSocket connection.

Start live view

Sent when Alexa starts a live view. The value is the requested frame rate in frames per second (default 5).

Websocket command (JSON)
{"startVideo": 5}

The device must start sending JPEG frames (see Camera frames) until it receives stopVideo.

Stop live view

Sent when the live view ends (or when the stream is torn down).

Websocket command (JSON)
{"stopVideo": ""}

The device must stop sending frames.

Device notifications (device to server)

Camera frames

While streaming, send each captured frame as a binary WebSocket message: the raw JPEG bytes, not JSON, on the same connection, at roughly the requested frame rate.

Do not publish a stream URL and do not upload snapshots - Offbeat relays the frames to the media gateway, which produces the HLS stream and the still image Alexa needs. The imageUri (still) is served by Offbeat from the live frame, so the device never provides it.

Typical settings: MJPEG 640x480 (configurable to 800x600) at 5 fps.

Motion detected

Report motion with the motion reading on the same connection.

{"motion": "ON"}

ON (case-insensitive) means motion detected. Report on change; the reference firmware also repeats it roughly every 30 seconds.

Motion cleared
{"motion": "OFF"}

Any value other than ON is treated as "not detected". Offbeat maps this reading to Alexa.MotionSensor (DETECTED / NOT_DETECTED) and reports it to Alexa.

Message envelope and connection

  • Device-to-server messages are bare {"<key>": <value>} objects.

  • The device is identified by its WebSocket connection (wss://www.offbeat-iot.com/ws?device=<endpointId>). If a payload must carry the device explicitly, use "deviceId" - not "endpointId":

{"deviceId": "YOUR_DEVICE_ID", "motion": "ON"}
  • Prefer one device per connection. Reconnect with backoff if the socket drops.

  • The device only needs outbound wss:// access; it never exposes a public URL. Offbeat and the media gateway provide the HTTPS stream that Alexa fetches.

Codec, profile and resolution

The device sends MJPEG (JPEG frames); the media gateway transcodes them to H.264 MPEG-TS HLS, which is what the Echo Show plays. Discovery and the InitializeCameraStreams response both advertise the codec as H264 (the codec only - the profile is not part of the advertisement).

Amazon’s camera relay is strict about the H.264 profile:

  • It decodes only the Baseline or Main profile. libx264’s default (High) is not decodable and fails silently: the Echo shows the still, then "the camera isn’t responding".

  • Every segment must carry in-band SPS/PPS (parameter sets repeated in each segment); without them the relay cannot begin decoding mid-stream.

The media gateway therefore encodes with:

ffmpeg -c:v libx264 -profile:v baseline -x264-params repeat-headers=1 ...

Resolutions 640x480 and 800x600 are supported (within Alexa’s 480-1080 px range); the default frame rate is 5.

Startup and preload

Amazon’s relay fetches the signed uri immediately after the InitializeCameraStreams response, within a ~6 second budget. If the playlist is not live yet, the relay gets the gateway’s 404 ("no active stream"), fetches nothing else, and the Echo shows the still followed by "the camera isn’t responding".

The server must therefore have the playlist live (HTTP 200) before responding to InitializeCameraStreams. Offbeat does this in CameraStreamInitializeHandler: after telling the device to start streaming it polls the signed stream URI until it returns 200, bounded by alexa.camera.preload-timeout-ms (default 3500 ms, kept under the 6 second budget), then responds. On timeout it still responds so the flow is never blocked. The device’s first frame should therefore arrive within a couple of seconds of startVideo.

Relay access (for debugging)

The stream must be reachable by Amazon’s camera relay over public HTTPS on port 443 with a trusted certificate (the signed URL is self-authorizing: authorizationType NONE). A relay fetch looks like this in an access log:

98.94.44.153 - - [10/Oct/2026:10:51:00 +0000] "GET /s/<token>/index.m3u8 HTTP/1.1" 200 0 "-" "GStreamer souphttpsrc libsoup/2.48.1"
  • User agent: GStreamer souphttpsrc libsoup/2.48.1.

  • Source addresses: Amazon AWS ASNs 16509 and 14618.

  • After index.m3u8 returns 200, the relay fetches seg*.ts continuously; the still (snapshot.jpg) is fetched separately.

If the playlist is fetched once and returns 404, that is the startup race above. If the playlist returns 200 but no segments are requested, suspect the H.264 profile or the in-band SPS/PPS.