Examples as Arduino sketches: one folder per device type, each its own endpointId, Wi-Fi with a timeout

Light, DimmableLight, ColorTemperatureLight, ColorLight, TemperatureSensor, ContactSensor, Blind,
Thermostat, Lock, Scene, Doorbell and MultiDevice on the 2.0 API: addCapability(row, instance), one
onDirective() handler, the report helpers, ChangeReports from loop(), a deferred answer for the lock.
Wi-Fi is waited for 30 s, then the sketch says what to check and carries on.

examples/README.md has what each sketch does, its limits and the measured sizes for d1_mini: Light
takes 30,616 bytes of static RAM and 332,565 of flash; all 17 sketches build with 0 warnings.
test/test_examples compares the discovery object of every new sketch: 147 host tests (were 135).
The sketches were compiled, not run on a board.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
David 2026-09-28 21:41:51 +00:00
parent 7369883479
commit 69b4d59896
15 changed files with 2061 additions and 1 deletions

View file

@ -0,0 +1,154 @@
// ColorLight: an RGB lamp (Alexa.PowerController, Alexa.BrightnessController, Alexa.ColorController).
//
// Alexa names a color by hue (0 to 360 degrees), saturation and brightness (0 to 1). The sketch keeps the three,
// turns them into red, green and blue and drives three PWM outputs. SetColor sets the brightness too; SetBrightness
// changes the brightness and leaves hue and saturation alone.
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <Alex2ESP.h>
// Wi-Fi and the credentials of your Alex2MQTT account
const char *WIFI_SSID = "";
const char *WIFI_PASSWORD = "";
const char *ALEXA_USERNAME = "";
const char *ALEXA_PASSWORD = "";
const char *ALEXA_ROOT_TOPIC = "";
const uint8_t RED_PIN = 14; // D5 on a Wemos D1 mini, high = lit
const uint8_t GREEN_PIN = 12; // D6
const uint8_t BLUE_PIN = 13; // D7
Alex2ESP alexa;
bool lampOn = false;
float hue = 0; // degrees
float saturation = 0; // 0 to 1: 0 is white
int brightness = 100; // percent
// Joins the Wi-Fi network and returns after 30 s at the latest. Without a connection the sketch carries on: the
// ESP8266 keeps trying, and alexa.loop() opens the MQTT session once Wi-Fi is up.
void connectWiFi()
{
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.printf("\n[WIFI] Connecting to \"%s\"\n", WIFI_SSID);
unsigned long started = millis();
while (WiFi.status() != WL_CONNECTED && millis() - started < 30000)
{
delay(100);
}
if (WiFi.status() == WL_CONNECTED)
{
Serial.printf("[WIFI] Connected, IP address %s\n", WiFi.localIP().toString().c_str());
}
else
{
Serial.printf("[WIFI] No connection after 30 s (status %d): check WIFI_SSID and WIFI_PASSWORD. Still trying.\n",
WiFi.status());
}
}
// Hue, saturation and brightness as the share of red, green and blue, 0 to 100 each
void writeLamp()
{
float value = lampOn ? brightness : 0;
float sector = hue / 60;
int whole = static_cast<int>(sector) % 6;
float part = sector - static_cast<int>(sector);
float low = value * (1 - saturation);
float falling = value * (1 - saturation * part);
float rising = value * (1 - saturation * (1 - part));
float red = value, green = value, blue = value;
switch (whole)
{
case 0: green = rising; blue = low; break;
case 1: red = falling; blue = low; break;
case 2: red = low; blue = rising; break;
case 3: red = low; green = falling; break;
case 4: red = rising; green = low; break;
default: green = low; blue = falling; break;
}
analogWrite(RED_PIN, static_cast<int>(red + 0.5f));
analogWrite(GREEN_PIN, static_cast<int>(green + 0.5f));
analogWrite(BLUE_PIN, static_cast<int>(blue + 0.5f));
}
// The state of the lamp: what the answer to a directive and the answer to ReportState carry
void sendState(AlexaStatusMessage message)
{
message.addHealthProp(EndpointHealth::OK)
.addPowerControllerProp(lampOn ? PowerController::ON : PowerController::OFF)
.addBrightnessControllerProp(brightness)
.addColorControllerProp(hue, saturation, brightness / 100.0f)
.send();
}
void onDirective(AlexaDirective &directive)
{
if (directive.isReportState())
{
sendState(directive.stateReport());
return;
}
if (directive.is("TurnOn") || directive.is("TurnOff"))
{
lampOn = directive.is("TurnOn");
}
else if (directive.is("SetBrightness"))
{
brightness = constrain(directive.payload["brightness"] | brightness, 0, 100);
}
else if (directive.is("AdjustBrightness"))
{
brightness = constrain(brightness + (directive.payload["brightnessDelta"] | 0), 0, 100);
}
else if (directive.is("SetColor"))
{
JsonVariantConst color = directive.payload["color"];
hue = constrain(color["hue"] | hue, 0.0f, 360.0f);
saturation = constrain(color["saturation"] | saturation, 0.0f, 1.0f);
brightness = constrain(static_cast<int>((color["brightness"] | brightness / 100.0f) * 100 + 0.5f), 0, 100);
}
else
{
directive.error(AlexaErrorType::INVALID_DIRECTIVE, "This lamp switches, dims and changes its color").send();
return;
}
writeLamp();
sendState(directive.response());
}
void setup()
{
Serial.begin(74880);
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
analogWriteRange(100);
writeLamp();
connectWiFi();
// MQTT user name, MQTT password, root topic
alexa.begin(ALEXA_USERNAME, ALEXA_PASSWORD, ALEXA_ROOT_TOPIC);
// The name Alexa shows, and the id of the endpoint: every device of an account has its own
AlexaDevice *lamp = alexa.getDevice("Color Lamp", "esp-color-light");
lamp->setDisplayCategory(DisplayCategory::LIGHT);
lamp->addCapability(AlexaInterfaces::PowerController);
lamp->addCapability(AlexaInterfaces::BrightnessController);
lamp->addCapability(AlexaInterfaces::ColorController);
lamp->addCapability(AlexaInterfaces::EndpointHealth);
lamp->onDirective(onDirective);
}
void loop()
{
alexa.loop();
}