"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.AlexaStatusMessage = void 0; const crypto_1 = require("crypto"); const build_js_1 = require("../messages/build.js"); const StateBuilder_js_1 = require("../messages/StateBuilder.js"); const topics = __importStar(require("../topics.js")); const transport_js_1 = require("../transport.js"); const enums_js_1 = require("./enums.js"); // The 1.x helpers report every temperature in Celsius, whatever scale the device works in function celsius(scale, value) { return { value: scale === enums_js_1.TemperatureSensorScale.FAHRENHEIT ? (value - 32) * (5 / 9) : value, scale: "CELSIUS" }; } /** * A Response, StateReport, DeferredResponse or ChangeReport as 1.x builds it: device.getStatusMessage() or * device.getChangeReport(), the add...Prop() calls, send(). The values are not checked. */ class AlexaStatusMessage { constructor(correlationToken, rootTopic, endpointId, publisher, isResponse = false, isDeferred = false, changeCause = null) { this.correlationToken = correlationToken; this.rootTopic = rootTopic; this.endpointId = endpointId; this.publisher = publisher; this.isResponse = isResponse; this.isDeferred = isDeferred; this.changeCause = changeCause; // One id for the message, however often toJSON() is called this.messageId = (0, crypto_1.randomUUID)(); this.state = new StateBuilder_js_1.StateBuilder({ target: changeCause ? "change" : "context" }); } addProperty(namespace, name, value, uncertaintyInMilliseconds = 0, instance) { this.state.setRaw(namespace, name, value, { instance, uncertaintyInMilliseconds }); return this; } /** ChangeReport: the add*Prop calls that follow describe what CHANGED (the default for a change report). */ changed() { this.state.changed(); return this; } /** ChangeReport: the add*Prop calls that follow describe the other, unchanged properties (context). */ unchanged() { this.state.unchanged(); return this; } /** True for a ChangeReport (Device.getChangeReport). */ isChangeReport() { return this.changeCause !== null; } /** * The message as it will be published (for tests and logging). A DeferredResponse has no context. Throws * MessageError for a ChangeReport without a changed property. */ toJSON() { const { endpointId, messageId, correlationToken } = this; if (this.changeCause) { return (0, build_js_1.changeReport)({ endpointId, messageId, cause: this.changeCause, changed: this.state.change, context: this.state.context }); } if (this.isDeferred) { return (0, build_js_1.deferredResponse)({ endpointId, messageId, correlationToken, estimatedDeferralInSeconds: this.estimatedDeferralInSeconds }); } const name = this.isResponse ? "Response" : "StateReport"; return (0, build_js_1.response)({ name, endpointId, messageId, correlationToken, context: this.state.context }); } addModeControllerProp(instance, value, uncertaintyInMs = 0) { return this.addProperty(enums_js_1.AlexaInterfaceType.MODE_CONTROLLER, "mode", value, uncertaintyInMs, instance); } addThermostatModeProp(mode, uncertaintyInMs = 0) { return this.addProperty(enums_js_1.AlexaInterfaceType.THERMOSTAT_CONTROLLER, "thermostatMode", mode, uncertaintyInMs); } addEstimatedDeferralTime(seconds) { if (this.isDeferred) { this.estimatedDeferralInSeconds = seconds; } else { console.warn("[AlexaStatusMessage.ts] Attempted to add estimated deferral time, but message is not marked as DeferredResponse."); } return this; } addThermostatControllerProp(name, scale, value, uncertaintyInMs = 0) { return this.addProperty(enums_js_1.AlexaInterfaceType.THERMOSTAT_CONTROLLER, name, celsius(scale, value), uncertaintyInMs); } /** Alexa.EndpointHealth connectivity: EndpointHealth.OK / UNREACHABLE (the plain strings "OK" / "UNREACHABLE" are accepted too). */ addHealthProp(health, uncertaintyInMs = 0) { return this.addProperty(enums_js_1.AlexaInterfaceType.ENDPOINT_HEALTH, "connectivity", { value: health }, uncertaintyInMs); } addPowerControllerProp(power, uncertaintyInMs = 0) { return this.addProperty(enums_js_1.AlexaInterfaceType.POWER_CONTROLLER, "powerState", power, uncertaintyInMs); } addTemperatureSensorProp(scale, value, uncertaintyInMs = 0) { return this.addProperty(enums_js_1.AlexaInterfaceType.TEMPERATURE_SENSOR, "temperature", celsius(scale, value), uncertaintyInMs); } addBrightnessControllerProp(brightness, uncertaintyInMs = 0) { return this.addProperty(enums_js_1.AlexaInterfaceType.BRIGHTNESS_CONTROLLER, "brightness", brightness, uncertaintyInMs); } addColorTemperatureControllerProp(colorTemp, uncertaintyInMs = 0) { return this.addProperty(enums_js_1.AlexaInterfaceType.COLOR_TEMPERATURE_CONTROLLER, "colorTemperatureInKelvin", colorTemp, uncertaintyInMs); } addToggleControllerProp(state, instance, uncertaintyInMs = 0) { return this.addProperty(enums_js_1.AlexaInterfaceType.TOGGLE_CONTROLLER, "toggleState", state, uncertaintyInMs, instance); } /** A property built by the caller. It goes to the context, also in a ChangeReport after changed(). */ addContextProp(prop) { this.state.add(prop, "context"); return this; } /** * Publish: a Response/StateReport to //alexaResponce (sendAsync: deferredResponse), a ChangeReport * to /changeReport (Alex2MQTT adds the user's token and posts it to the Alexa event gateway). Resolves with * the topic, or "" when nothing was published: the publish failed, or the message is a ChangeReport without a * changed property, which Alex2MQTT would drop. The error then goes to the bridge's "error" event (when listened * to). Never rejects (1.5.1 did, so an un-caught send() could kill the host). */ send(sendAsync = false) { const answer = sendAsync ? topics.deferred : topics.response; const topic = this.changeCause ? topics.changeReport(this.rootTopic) : answer(this.rootTopic, this.endpointId); return (0, transport_js_1.send)(this.publisher, topic, () => this.toJSON(), this.onPublishError); } } exports.AlexaStatusMessage = AlexaStatusMessage;