"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const AlexaInterface_js_1 = require("./AlexaInterface.js"); const DisplayCategory_js_1 = require("./DisplayCategory.js"); const events_1 = require("events"); const crypto_1 = require("crypto"); const AlexaStatusMessage_js_1 = require("./AlexaStatusMessage.js"); const AlexaErrorResponse_js_1 = require("./AlexaErrorResponse.js"); class Device extends events_1.EventEmitter { constructor(mqttClient, rootTopic, name, endpointId, displayCategory, description = "Alexa to Node.js bridge", manufacturerName = "Alex2Node", manufacturer = "Alex2Node", model = "Alex2Node_v1.0.0") { super(); this.mqttClient = mqttClient; this.rootTopic = rootTopic; this.name = name; this.endpointId = endpointId; this.displayCategory = displayCategory; this.description = description; this.manufacturerName = manufacturerName; this.manufacturer = manufacturer; this.model = model; this.softwareVersion = "1.0.0"; this.capabilities = []; } /** Internal (1.5.2): Alex2MQTT.connect() re-binds every registered device to its new broker client after a disconnect(). */ setMqttClient(client) { this.mqttClient = client; } getName() { return this.name; } setName(name) { this.name = name; } getEndpointId() { return this.endpointId; } setDisplayCategory(category) { this.displayCategory = Array.isArray(category) ? category : [category]; } getDisplayCategory() { return this.displayCategory || [DisplayCategory_js_1.DisplayCategory.LIGHT]; } setDescription(description) { this.description = description; } getDescription() { return this.description; } getErrorMessage(correlationToken) { const msg = new AlexaErrorResponse_js_1.AlexaErrorResponse(correlationToken, this.rootTopic, this.endpointId, this.mqttClient); msg.onPublishError = this.onPublishError; return msg; } getStatusMessage(correlationToken, isResponse = false, isDeferred = false) { const msg = new AlexaStatusMessage_js_1.AlexaStatusMessage(correlationToken, this.rootTopic, this.endpointId, this.mqttClient, isResponse, isDeferred); msg.onPublishError = this.onPublishError; return msg; } /** * A proactive Alexa.ChangeReport (1.5.1): add the changed properties (the default target), optionally * .unchanged() then the others, and .send() - it goes to /changeReport, which Alex2MQTT forwards to the Alexa * event gateway with the user's token. Alexa only accepts it for capabilities registered with proactivelyReported. */ getChangeReport(cause = "PHYSICAL_INTERACTION") { const msg = new AlexaStatusMessage_js_1.AlexaStatusMessage("", this.rootTopic, this.endpointId, this.mqttClient, false, false, cause); msg.onPublishError = this.onPublishError; return msg; } /** * Alexa.SceneController: answer an Activate / Deactivate directive with ActivationStarted / DeactivationStarted * (1.5.1). Resolves with the topic published to, or "" when the publish failed (never rejects, 1.5.2). */ sendSceneResponse(correlationToken, activated, cause = "VOICE_INTERACTION", sendAsync = false) { const payload = { context: {}, event: { header: { namespace: "Alexa.SceneController", name: activated ? "ActivationStarted" : "DeactivationStarted", messageId: (0, crypto_1.randomUUID)(), correlationToken, payloadVersion: "3" }, endpoint: { endpointId: this.endpointId }, payload: { cause: { type: cause }, timestamp: new Date().toISOString() }, }, }; const topic = `${this.rootTopic}/${this.endpointId}/${sendAsync ? "deferredResponse" : "alexaResponce"}`; return new Promise((resolve) => { this.mqttClient.publish(topic, JSON.stringify(payload), (err) => { if (!err) return resolve(topic); if (this.onPublishError) this.onPublishError(err); // -> the bridge's "error" event (when somebody listens) resolve(""); // 1.5.1 rejected here, and an un-caught send() then killed the host on any broker hiccup }); }); } getCapabilities() { return this.capabilities.slice(); } setManufacturerName(name) { this.manufacturerName = name; } getManufacturerName() { return this.manufacturerName; } setManufacturer(manufacturer) { this.manufacturer = manufacturer; } getManufacturer() { return this.manufacturer; } setModel(model) { this.model = model; } getModel() { return this.model; } getSoftwareVersion() { return this.softwareVersion; } /** Add a capability. 1.5.1: options.retrievable / proactivelyReported / instance (a change report needs proactivelyReported). */ addCapability(type, options = {}) { const newCapability = new AlexaInterface_js_1.AlexaInterface(type, options.retrievable ?? true, options.proactivelyReported ?? false, options.instance ?? ""); this.capabilities.push(newCapability); // console.log( // `Created new interface with type: ${newCapability.getTypeString()}` // ); return newCapability; } getJSON() { return { endpointId: this.endpointId, friendlyName: this.name, description: this.description, manufacturerName: this.manufacturerName, displayCategories: this.getDisplayCategory(), additionalAttributes: { manufacturer: this.manufacturer, model: this.model, serialNumber: "Alex2Node", firmwareVersion: "1.0.0", softwareVersion: this.softwareVersion, customIdentifier: "Alex2Node", }, capabilities: this.capabilities.map((cap) => cap.getJSON()), }; } } exports.default = Device;