1.5.2: send() never rejects (status, error, scene, change report: resolves the topic or "" and reports the failure through the bridge's error event when listened to - 1.5.1 rejected, and an un-caught .send() killed the host on any broker hiccup); types ship (declaration: true, dist/*.d.ts tracked; addSupportedModes takes {value, modeResources}, ActionMapping payload optional, addHealthProp accepts EndpointHealth or the string); disconnect()/connect() re-binds devices to the new client; registerDevice returns the existing device on a duplicate endpointId (warning via the log hook, console.warn without one); ThermostatController discovery lists targetSetpoint and drops adaptiveRecoveryStatus; the UNSUPORTED INTERFACE TYPE stderr spam goes through the log hook. Examples: require("alex2node"), an error listener in each, EndpointHealth.OK, neutral endpoint ids, BlindControl reads correlationToken from the header, the thermostat reports Fahrenheit as Fahrenheit, ExamplePowerController is power-only again + new ExamplePowerControllerWithBrightness. readme (install from Forgejo, 1.5.2 changelog, table syntax), LICENSE (MIT); tests for the non-rejecting send, reconnect, duplicate, thermostat discovery and the shipped declaration signatures (8/8 on an in-process broker).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
717af632de
commit
275f00f8a7
35 changed files with 1011 additions and 176 deletions
17
dist/Alex2Node.js
vendored
17
dist/Alex2Node.js
vendored
|
|
@ -8,6 +8,7 @@ const mqtt_1 = __importDefault(require("mqtt"));
|
|||
const Device_1 = __importDefault(require("./Device"));
|
||||
const events_1 = require("events");
|
||||
const DisplayCategory_1 = require("./DisplayCategory");
|
||||
const AlexaInterface_1 = require("./AlexaInterface");
|
||||
exports.DEFAULT_HOST = "mqtt://Alex2MQTT.stormysdream.club:1883";
|
||||
/**
|
||||
* The Alexa-to-MQTT bridge: one broker connection for a user's root topic, a set of registered devices, discovery and
|
||||
|
|
@ -60,6 +61,8 @@ class Alex2MQTT extends events_1.EventEmitter {
|
|||
return;
|
||||
const options = Object.assign({ username: this.username, password: this.password, reconnectPeriod: 1000, connectTimeout: 10000 }, (this.options.mqtt || {}));
|
||||
this.client = mqtt_1.default.connect(this.MqttHost, options);
|
||||
for (const d of this.devices)
|
||||
d.setMqttClient(this.client); // after a disconnect(): the devices publish through the new client
|
||||
this.client.on("connect", () => {
|
||||
this.connected = true;
|
||||
this.log("Connected to MQTT broker");
|
||||
|
|
@ -82,6 +85,10 @@ class Alex2MQTT extends events_1.EventEmitter {
|
|||
this.log("Discovery request received, getting device json...");
|
||||
const deviceArray = this.devices.map((device) => device.getJSON());
|
||||
this.lastDiscoveryAt = new Date().toISOString();
|
||||
for (const device of this.devices) // a capability the library has no property list for goes out with supported: []
|
||||
for (const cap of device.getCapabilities())
|
||||
if (cap.getProps().length === 0 && cap.getType() !== AlexaInterface_1.AlexaInterfaceType.SCENE_CONTROLLER)
|
||||
this.log(`${device.endpointId}: no property list known for ${cap.getTypeString()}, discovery lists it with no supported properties`);
|
||||
this.client.publish(topic + "_r", JSON.stringify(deviceArray), (err) => {
|
||||
if (err) {
|
||||
this.fail(err);
|
||||
|
|
@ -137,6 +144,15 @@ class Alex2MQTT extends events_1.EventEmitter {
|
|||
if (!this.client) {
|
||||
throw new Error("Must call connect before creating devices");
|
||||
}
|
||||
const existing = this.devices.find((d) => d.endpointId === endpointId);
|
||||
if (existing) { // 1.5.2: endpointIds are unique per root topic; 1.5.1 added a second device that never got a directive
|
||||
const warning = `warning: registerDevice("${endpointId}") is already registered as "${existing.name}", returning that device`;
|
||||
if (this.options.log)
|
||||
this.options.log(warning);
|
||||
else
|
||||
console.warn(`[Alex2Node.ts] ${warning}`); // visible without a log hook too
|
||||
return existing;
|
||||
}
|
||||
this.log(`Creating new device with endpoint: ${endpointId}`);
|
||||
const normalizedCategory = displayCategory === null
|
||||
? [DisplayCategory_1.DisplayCategory.LIGHT]
|
||||
|
|
@ -144,6 +160,7 @@ class Alex2MQTT extends events_1.EventEmitter {
|
|||
? displayCategory
|
||||
: [displayCategory || DisplayCategory_1.DisplayCategory.LIGHT];
|
||||
const device = new Device_1.default(this.client, this.rootTopic, name, endpointId, normalizedCategory);
|
||||
device.onPublishError = (err) => this.fail(err); // a failed publish is an "error" event (when listened to), never a rejected send()
|
||||
this.devices.push(device);
|
||||
return device;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue