Ten recipes: lamp, colour lamp, thermostat, blind, lock (deferred), contact sensor (ChangeReport), scene, doorbell (raise), typed errors, and a plug as an ES module. Each reads ALEX2MQTT_USERNAME, _PASSWORD and _ROOT_TOPIC and names the ones that are missing. The nine examples of 1.5.2 move to examples/legacy unchanged. test/examples.test.js starts every file with node, its broker connection sent to a broker on 127.0.0.1 (test/helpers/loopback.js), discovers the device, sends directives and checks the answers. A legacy file is started and its discovery compared with the answer the 1.5.2 build gave, recorded in test/fixtures/legacy-examples. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
76 lines
3.3 KiB
JavaScript
76 lines
3.3 KiB
JavaScript
// A lamp that shows a colour or a white: Alexa.ColorController and Alexa.ColorTemperatureController, with power
|
|
// and brightness. It reports the colour or the colour temperature, whichever it shows.
|
|
//
|
|
// ALEX2MQTT_USERNAME=... ALEX2MQTT_PASSWORD=... ALEX2MQTT_ROOT_TOPIC=... node examples/color-lamp.js
|
|
//
|
|
// "alex2node" is the installed package; inside this checkout it resolves to the built dist/.
|
|
const { Alex2MQTT, AlexaErrors, PowerController, BrightnessController, ColorController, ColorTemperatureController } = require("alex2node");
|
|
|
|
const missing = ["ALEX2MQTT_USERNAME", "ALEX2MQTT_PASSWORD", "ALEX2MQTT_ROOT_TOPIC"].filter((name) => !process.env[name]);
|
|
if (missing.length > 0) {
|
|
console.error(`${missing.join(", ")} not set. Set the MQTT user name, the password and the root topic of your Alex2MQTT account.`);
|
|
process.exit(1);
|
|
}
|
|
const { ALEX2MQTT_USERNAME, ALEX2MQTT_PASSWORD, ALEX2MQTT_ROOT_TOPIC } = process.env;
|
|
|
|
const bridge = new Alex2MQTT(ALEX2MQTT_USERNAME, ALEX2MQTT_PASSWORD, ALEX2MQTT_ROOT_TOPIC);
|
|
bridge.on("connect", () => console.log("connected, discover the devices in the Alexa app"));
|
|
bridge.on("error", (err) => console.error("bridge:", err.message));
|
|
|
|
// The whites Alexa asks for by name: warm, soft, white, daylight, cool
|
|
const WHITES = [2200, 2700, 4000, 5500, 7000];
|
|
// color is null while the lamp shows a white
|
|
const lamp = { on: false, brightness: 100, color: null, kelvin: 2700 };
|
|
|
|
const device = bridge.addDevice({ endpointId: "floor-lamp", name: "Floor Lamp", categories: ["LIGHT"] });
|
|
const power = device.add(PowerController);
|
|
const brightness = device.add(BrightnessController);
|
|
const color = device.add(ColorController);
|
|
const white = device.add(ColorTemperatureController);
|
|
|
|
device.state((s) => {
|
|
s.set(power, "powerState", lamp.on ? "ON" : "OFF").set(brightness, "brightness", lamp.brightness);
|
|
if (lamp.color) s.set(color, "color", { ...lamp.color, brightness: lamp.brightness / 100 });
|
|
else s.set(white, "colorTemperatureInKelvin", lamp.kelvin);
|
|
s.health("OK");
|
|
});
|
|
|
|
power.on("TurnOn", (ctx) => {
|
|
lamp.on = true;
|
|
return ctx.respond();
|
|
});
|
|
power.on("TurnOff", (ctx) => {
|
|
lamp.on = false;
|
|
return ctx.respond();
|
|
});
|
|
brightness.on("SetBrightness", (ctx) => {
|
|
lamp.brightness = ctx.payload.brightness;
|
|
lamp.on = true;
|
|
return ctx.respond();
|
|
});
|
|
// SetColor comes with brightness 1 whatever the lamp shows: the lamp takes hue and saturation and keeps its brightness
|
|
color.on("SetColor", (ctx) => {
|
|
const { hue, saturation } = ctx.payload.color;
|
|
lamp.color = { hue, saturation };
|
|
lamp.on = true;
|
|
return ctx.respond();
|
|
});
|
|
white.on("SetColorTemperature", (ctx) => {
|
|
lamp.kelvin = Math.min(7000, Math.max(2200, ctx.payload.colorTemperatureInKelvin));
|
|
lamp.color = null;
|
|
lamp.on = true;
|
|
return ctx.respond();
|
|
});
|
|
// "Warmer" and "cooler" have no meaning while the lamp shows a colour. A handler that throws answers with the error.
|
|
function step(by) {
|
|
return (ctx) => {
|
|
if (lamp.color) throw AlexaErrors.notSupportedInCurrentMode("The lamp shows a colour", "COLOR");
|
|
const next = WHITES.indexOf(WHITES.find((kelvin) => kelvin >= lamp.kelvin) ?? 7000) + by;
|
|
lamp.kelvin = WHITES[Math.min(WHITES.length - 1, Math.max(0, next))];
|
|
return ctx.respond();
|
|
};
|
|
}
|
|
white.on("IncreaseColorTemperature", step(1));
|
|
white.on("DecreaseColorTemperature", step(-1));
|
|
|
|
bridge.connect();
|