Add full support and examples for thermostat

This commit is contained in:
David 2025-05-10 12:21:51 +00:00
parent 7f051dfdcb
commit f4d07b589c
12 changed files with 307 additions and 32 deletions

11
dist/Alex2Node.js vendored
View file

@ -56,7 +56,7 @@ class Alex2MQTT extends events_1.EventEmitter {
}
else if (this.debugLogging) {
console.log(`[Alex2Node.ts] Discovery payloads published to ${topic + "_r"}`);
console.log(deviceArray);
console.log(JSON.stringify(deviceArray, null, 2));
}
});
}
@ -102,14 +102,19 @@ class Alex2MQTT extends events_1.EventEmitter {
this.emit("error", err);
});
}
registerDevice(name, endpointId) {
registerDevice(name, endpointId, displayCategory) {
if (!this.client) {
throw new Error("Must call connect before creating devices");
}
if (this.debugLogging) {
console.log(`[Alex2Node.ts] Creating new device with endpoint: ${endpointId}`);
}
const device = new Device_1.default(this.client, this.rootTopic, name, endpointId);
const normalizedCategory = displayCategory === null
? null
: Array.isArray(displayCategory)
? displayCategory
: [displayCategory];
const device = new Device_1.default(this.client, this.rootTopic, name, endpointId, normalizedCategory);
this.devices.push(device);
return device;
}

View file

@ -164,11 +164,12 @@ class AlexaInterface {
case AlexaInterfaceType.SCENE_CONTROLLER:
case AlexaInterfaceType.SEEK_CONTROLLER:
case AlexaInterfaceType.TEMPERATURE_SENSOR:
case AlexaInterfaceType.THERMOSTAT_CONTROLLER:
case AlexaInterfaceType.TOGGLE_CONTROLLER:
return "3";
case AlexaInterfaceType.LAUNCHER:
return "1.1";
case AlexaInterfaceType.THERMOSTAT_CONTROLLER:
return "3.2";
case AlexaInterfaceType.ENDPOINT_HEALTH:
return "3.3";
default:
@ -197,6 +198,13 @@ class AlexaInterface {
return ["toggleState"];
case AlexaInterfaceType.TEMPERATURE_SENSOR:
return ["temperature"];
case AlexaInterfaceType.THERMOSTAT_CONTROLLER:
return [
"lowerSetpoint",
"upperSetpoint",
"thermostatMode",
"adaptiveRecoveryStatus",
];
case AlexaInterfaceType.APPLICATION_STATE_REPORTER:
case AlexaInterfaceType.AUDIO_PLAY_QUEUE:
case AlexaInterfaceType.AUTHORIZATION_CONTROLLER:
@ -238,7 +246,6 @@ class AlexaInterface {
case AlexaInterfaceType.SMART_VISION_SNAPSHOT_PROVIDER:
case AlexaInterfaceType.SPEAKER:
case AlexaInterfaceType.STEP_SPEAKER:
case AlexaInterfaceType.THERMOSTAT_CONTROLLER:
case AlexaInterfaceType.THERMOSTAT_CONTROLLER_CONFIGURATION:
case AlexaInterfaceType.THERMOSTAT_CONTROLLER_HVAC_COMPONENTS:
case AlexaInterfaceType.THERMOSTAT_CONTROLLER_SCHEDULE:
@ -261,9 +268,15 @@ class AlexaInterface {
properties: {
retrievable: this.retrievable,
proactivelyReported: this.proactivelyReported,
supported: [{ name: this.getProps()[0] }],
supported: this.getProps().map(name => ({ name })),
},
};
if (this.type == AlexaInterfaceType.THERMOSTAT_CONTROLLER) {
doc.configuration = {
"supportedModes": ["HEAT", "COOL", "AUTO", "OFF"],
"supportsScheduling": false
};
}
if (this.instance) {
doc.instance = this.instance;
}

View file

@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AlexaStatusMessage = exports.TemperatureSensorScale = exports.PowerController = exports.EndpointHealth = void 0;
exports.AlexaStatusMessage = exports.TemperatureSensorScale = exports.PowerController = exports.ThermostatMode = exports.EndpointHealth = void 0;
const uuid_1 = require("uuid");
const AlexaInterface_1 = require("./AlexaInterface");
var EndpointHealth;
@ -8,6 +8,15 @@ var EndpointHealth;
EndpointHealth["OK"] = "OK";
EndpointHealth["UNREACHABLE"] = "UNREACHABLE";
})(EndpointHealth || (exports.EndpointHealth = EndpointHealth = {}));
var ThermostatMode;
(function (ThermostatMode) {
ThermostatMode["OFF"] = "OFF";
ThermostatMode["HEAT"] = "HEAT";
ThermostatMode["COOL"] = "COOL";
ThermostatMode["AUTO"] = "AUTO";
ThermostatMode["ECO"] = "ECO";
ThermostatMode["CUSTOM"] = "CUSTOM";
})(ThermostatMode || (exports.ThermostatMode = ThermostatMode = {}));
var PowerController;
(function (PowerController) {
PowerController["ON"] = "ON";
@ -57,6 +66,18 @@ class AlexaStatusMessage {
this.context.properties.push(prop);
return this;
}
addThermostatModeProp(mode, uncertaintyInMs = 0) {
return this.addProperty(AlexaInterface_1.AlexaInterfaceType.THERMOSTAT_CONTROLLER, "thermostatMode", mode, uncertaintyInMs);
}
addThermostatControllerProp(name, scale, value, uncertaintyInMs = 0) {
const tempValue = {
value: scale === TemperatureSensorScale.FAHRENHEIT
? (value - 32) * (5 / 9)
: value,
scale: "CELSIUS",
};
return this.addProperty(AlexaInterface_1.AlexaInterfaceType.THERMOSTAT_CONTROLLER, name, tempValue, uncertaintyInMs);
}
addHealthProp(health, uncertaintyInMs = 0) {
return this.addProperty(AlexaInterface_1.AlexaInterfaceType.ENDPOINT_HEALTH, "connectivity", { value: health }, uncertaintyInMs);
}

8
dist/Device.js vendored
View file

@ -5,7 +5,7 @@ const DisplayCategory_1 = require("./DisplayCategory");
const events_1 = require("events");
const AlexaStatusMessage_1 = require("./AlexaStatusMessage");
class Device extends events_1.EventEmitter {
constructor(mqttClient, rootTopic, name, endpointId, displayCategory = DisplayCategory_1.DisplayCategory.LIGHT, description = "Alexa to Node.js bridge", manufacturerName = "Alex2Node", manufacturer = "Alex2Node", model = "Alex2Node_v1.0.0") {
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;
@ -29,10 +29,10 @@ class Device extends events_1.EventEmitter {
return this.endpointId;
}
setDisplayCategory(category) {
this.displayCategory = category;
this.displayCategory = Array.isArray(category) ? category : [category];
}
getDisplayCategory() {
return this.displayCategory;
return this.displayCategory || [DisplayCategory_1.DisplayCategory.LIGHT];
}
setDescription(description) {
this.description = description;
@ -82,7 +82,7 @@ class Device extends events_1.EventEmitter {
friendlyName: this.name,
description: this.description,
manufacturerName: this.manufacturerName,
displayCategories: [this.displayCategory],
displayCategories: this.getDisplayCategory(),
additionalAttributes: {
manufacturer: this.manufacturer,
model: this.model,

7
dist/index.js vendored
View file

@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PowerController = exports.AlexaActions = exports.ActionMapping = exports.AlexaInterfaceType = exports.Alex2MQTT = void 0;
exports.ThermostatMode = exports.TemperatureSensorScale = exports.EndpointHealth = exports.PowerController = exports.DisplayCategory = exports.AlexaActions = exports.ActionMapping = exports.AlexaInterfaceType = exports.Alex2MQTT = void 0;
var Alex2Node_1 = require("./Alex2Node");
Object.defineProperty(exports, "Alex2MQTT", { enumerable: true, get: function () { return __importDefault(Alex2Node_1).default; } });
var AlexaInterface_1 = require("./AlexaInterface");
@ -11,5 +11,10 @@ Object.defineProperty(exports, "AlexaInterfaceType", { enumerable: true, get: fu
var ActionMapping_1 = require("./ActionMapping");
Object.defineProperty(exports, "ActionMapping", { enumerable: true, get: function () { return ActionMapping_1.ActionMapping; } });
Object.defineProperty(exports, "AlexaActions", { enumerable: true, get: function () { return ActionMapping_1.AlexaActions; } });
var DisplayCategory_1 = require("./DisplayCategory");
Object.defineProperty(exports, "DisplayCategory", { enumerable: true, get: function () { return DisplayCategory_1.DisplayCategory; } });
var AlexaStatusMessage_1 = require("./AlexaStatusMessage");
Object.defineProperty(exports, "PowerController", { enumerable: true, get: function () { return AlexaStatusMessage_1.PowerController; } });
Object.defineProperty(exports, "EndpointHealth", { enumerable: true, get: function () { return AlexaStatusMessage_1.EndpointHealth; } });
Object.defineProperty(exports, "TemperatureSensorScale", { enumerable: true, get: function () { return AlexaStatusMessage_1.TemperatureSensorScale; } });
Object.defineProperty(exports, "ThermostatMode", { enumerable: true, get: function () { return AlexaStatusMessage_1.ThermostatMode; } });