Alex2Node/examples/lock.js
David 8379a65d78 examples: one runnable file per recipe on the 2.0 API, the 1.x files in examples/legacy
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>
2026-09-28 21:38:07 +00:00

49 lines
2 KiB
JavaScript

// A lock whose bolt takes longer than the 7 seconds Alex2MQTT waits for an answer: Alexa.LockController. The
// handler sends a DeferredResponse at once and the Response when the bolt has moved. Alex2MQTT waits 10 seconds for
// the Response after a DeferredResponse.
//
// ALEX2MQTT_USERNAME=... ALEX2MQTT_PASSWORD=... ALEX2MQTT_ROOT_TOPIC=... node examples/lock.js
//
// "alex2node" is the installed package; inside this checkout it resolves to the built dist/.
const { Alex2MQTT, LockController } = 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));
// How long the bolt takes, in seconds
const BOLT_SECONDS = Number(process.env.BOLT_SECONDS ?? 8);
const lock = { state: "LOCKED" };
const moveBolt = (state) => new Promise((resolve) => {
setTimeout(() => {
lock.state = state;
resolve();
}, BOLT_SECONDS * 1000);
});
const device = bridge.addDevice({ endpointId: "front-door-lock", name: "Front Door", categories: ["SMARTLOCK"] });
const bolt = device.add(LockController);
device.state((s) => s.set(bolt, "lockState", lock.state).health("OK"));
function move(state) {
return async (ctx) => {
// The argument is optional: how many seconds the answer will take
await ctx.defer(Math.ceil(BOLT_SECONDS));
await moveBolt(state);
// After defer() the answer goes to <root>/<endpointId>/deferredResponse
return ctx.respond();
};
}
bolt.on("Lock", move("LOCKED"));
bolt.on("Unlock", move("UNLOCKED"));
bridge.connect();