Add full support and examples for thermostat
This commit is contained in:
parent
7f051dfdcb
commit
f4d07b589c
12 changed files with 307 additions and 32 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import mqtt, { MqttClient } from "mqtt";
|
||||
import Device from "./Device";
|
||||
import { EventEmitter } from "events";
|
||||
import { DisplayCategory } from "./DisplayCategory";
|
||||
|
||||
class Alex2MQTT extends EventEmitter {
|
||||
private client: MqttClient | null = null;
|
||||
|
|
@ -15,7 +16,6 @@ class Alex2MQTT extends EventEmitter {
|
|||
) {
|
||||
super(); // Initialize EventEmitter
|
||||
}
|
||||
|
||||
|
||||
connect(): void {
|
||||
const options = {
|
||||
|
|
@ -69,7 +69,7 @@ class Alex2MQTT extends EventEmitter {
|
|||
topic + "_r"
|
||||
}`
|
||||
);
|
||||
console.log(deviceArray);
|
||||
console.log(JSON.stringify(deviceArray, null, 2));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
@ -106,8 +106,8 @@ class Alex2MQTT extends EventEmitter {
|
|||
);
|
||||
}
|
||||
device.emit("ReportState", payload);
|
||||
}else{
|
||||
device.emit("Event", payload,payload.header.namespace);
|
||||
} else {
|
||||
device.emit("Event", payload, payload.header.namespace);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -120,7 +120,11 @@ class Alex2MQTT extends EventEmitter {
|
|||
});
|
||||
}
|
||||
|
||||
registerDevice(name: string, endpointId: string): Device {
|
||||
registerDevice(
|
||||
name: string,
|
||||
endpointId: string,
|
||||
displayCategory: DisplayCategory | DisplayCategory[] | null
|
||||
): Device {
|
||||
if (!this.client) {
|
||||
throw new Error("Must call connect before creating devices");
|
||||
}
|
||||
|
|
@ -129,7 +133,20 @@ class Alex2MQTT extends EventEmitter {
|
|||
`[Alex2Node.ts] Creating new device with endpoint: ${endpointId}`
|
||||
);
|
||||
}
|
||||
const device = new Device(this.client!, this.rootTopic, name, endpointId);
|
||||
const normalizedCategory =
|
||||
displayCategory === null
|
||||
? null
|
||||
: Array.isArray(displayCategory)
|
||||
? displayCategory
|
||||
: [displayCategory];
|
||||
|
||||
const device = new Device(
|
||||
this.client!,
|
||||
this.rootTopic,
|
||||
name,
|
||||
endpointId,
|
||||
normalizedCategory
|
||||
);
|
||||
this.devices.push(device);
|
||||
return device;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,11 +176,12 @@ export 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:
|
||||
|
|
@ -210,7 +211,13 @@ export 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:
|
||||
|
|
@ -252,7 +259,6 @@ export 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:
|
||||
|
|
@ -277,9 +283,15 @@ export 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,15 @@ export enum EndpointHealth {
|
|||
UNREACHABLE = "UNREACHABLE",
|
||||
}
|
||||
|
||||
export enum ThermostatMode {
|
||||
OFF = "OFF",
|
||||
HEAT = "HEAT",
|
||||
COOL = "COOL",
|
||||
AUTO = "AUTO",
|
||||
ECO = "ECO",
|
||||
CUSTOM = "CUSTOM",
|
||||
}
|
||||
|
||||
export enum PowerController {
|
||||
ON = "ON",
|
||||
OFF = "OFF",
|
||||
|
|
@ -101,6 +110,38 @@ export class AlexaStatusMessage {
|
|||
this.context.properties.push(prop);
|
||||
return this;
|
||||
}
|
||||
public addThermostatModeProp(
|
||||
mode: string,
|
||||
uncertaintyInMs = 0
|
||||
): this {
|
||||
return this.addProperty(
|
||||
AlexaInterfaceType.THERMOSTAT_CONTROLLER,
|
||||
"thermostatMode",
|
||||
mode,
|
||||
uncertaintyInMs
|
||||
);
|
||||
}
|
||||
|
||||
public addThermostatControllerProp(
|
||||
name: "lowerSetpoint" | "upperSetpoint" | "targetSetpoint",
|
||||
scale: TemperatureSensorScale,
|
||||
value: number,
|
||||
uncertaintyInMs = 0
|
||||
): this {
|
||||
const tempValue = {
|
||||
value:
|
||||
scale === TemperatureSensorScale.FAHRENHEIT
|
||||
? (value - 32) * (5 / 9)
|
||||
: value,
|
||||
scale: "CELSIUS",
|
||||
};
|
||||
return this.addProperty(
|
||||
AlexaInterfaceType.THERMOSTAT_CONTROLLER,
|
||||
name,
|
||||
tempValue,
|
||||
uncertaintyInMs
|
||||
);
|
||||
}
|
||||
|
||||
public addHealthProp(health: EndpointHealth, uncertaintyInMs = 0): this {
|
||||
return this.addProperty(
|
||||
|
|
@ -191,7 +232,7 @@ export class AlexaStatusMessage {
|
|||
context: this.context,
|
||||
event: this.event,
|
||||
};
|
||||
const topic = `${this.rootTopic}/${this.endpointId}/alexaResponce`;//Yes this should be response but it is incorrect in both Alex2MQTT and Alex2ESP so for consistency is is wrong here too
|
||||
const topic = `${this.rootTopic}/${this.endpointId}/alexaResponce`; //Yes this should be response but it is incorrect in both Alex2MQTT and Alex2ESP so for consistency is is wrong here too
|
||||
const payloadStr = JSON.stringify(payload);
|
||||
|
||||
this.mqttClient.publish(topic, payloadStr, (err) => {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class Device extends EventEmitter {
|
|||
private rootTopic: string,
|
||||
public name: string,
|
||||
public endpointId: string,
|
||||
public displayCategory: DisplayCategory = DisplayCategory.LIGHT,
|
||||
public displayCategory: Array<DisplayCategory> | null,
|
||||
public description: string = "Alexa to Node.js bridge",
|
||||
public manufacturerName: string = "Alex2Node",
|
||||
public manufacturer: string = "Alex2Node",
|
||||
|
|
@ -34,12 +34,12 @@ class Device extends EventEmitter {
|
|||
return this.endpointId;
|
||||
}
|
||||
|
||||
setDisplayCategory(category: DisplayCategory): void {
|
||||
this.displayCategory = category;
|
||||
setDisplayCategory(category: DisplayCategory | DisplayCategory[]): void {
|
||||
this.displayCategory = Array.isArray(category) ? category : [category];
|
||||
}
|
||||
|
||||
getDisplayCategory(): DisplayCategory {
|
||||
return this.displayCategory;
|
||||
|
||||
getDisplayCategory(): Array<DisplayCategory> {
|
||||
return this.displayCategory ||[DisplayCategory.LIGHT];
|
||||
}
|
||||
|
||||
setDescription(description: string): void {
|
||||
|
|
@ -111,7 +111,7 @@ class Device extends EventEmitter {
|
|||
friendlyName: this.name,
|
||||
description: this.description,
|
||||
manufacturerName: this.manufacturerName,
|
||||
displayCategories: [this.displayCategory],
|
||||
displayCategories: this.getDisplayCategory(),
|
||||
additionalAttributes: {
|
||||
manufacturer: this.manufacturer,
|
||||
model: this.model,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
export { default as Alex2MQTT } from './Alex2Node';
|
||||
export { AlexaInterfaceType } from './AlexaInterface';
|
||||
export { ActionMapping, AlexaActions } from './ActionMapping';
|
||||
export { PowerController } from './AlexaStatusMessage';
|
||||
export {DisplayCategory} from "./DisplayCategory";
|
||||
export { PowerController,EndpointHealth,TemperatureSensorScale,ThermostatMode } from './AlexaStatusMessage';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue