homebridge-resideo
Version:
The Resideo plugin allows you to access your Resideo device(s) from HomeKit.
700 lines • 43.5 kB
JavaScript
// import { request } from 'undici';
import { interval, Subject } from 'rxjs';
import { debounceTime, skipWhile, take, tap } from 'rxjs/operators';
import { DeviceURL } from '../settings.js';
import { HomeKitModes, ResideoModes, toCelsius, toFahrenheit } from '../utils.js';
import { deviceBase } from './device.js';
/**
* Platform Accessory
* An instance of this class is created for each accessory your platform registers
* Each accessory may expose multiple services of different service types.
*/
export class RoomSensorThermostat extends deviceBase {
platform;
group;
// Services
Thermostat;
HumiditySensor;
// Others - T9 Only
roomPriorityStatus;
// Thermostat Update
thermostatUpdateInProgress;
doThermostatUpdate;
// Room Updates
roomUpdateInProgress;
doRoomUpdate;
// Fan Updates
fanUpdateInProgress;
doFanUpdate;
constructor(platform, accessory, location, device, sensorAccessory, group) {
super(platform, accessory, location, device, sensorAccessory, group);
this.platform = platform;
this.group = group;
// this is subject we use to track when we need to POST Room Priority changes to the Resideo API for Room Changes - T9 Only
this.doRoomUpdate = new Subject();
this.roomUpdateInProgress = false;
// this is subject we use to track when we need to POST Thermostat changes to the Resideo API
this.doThermostatUpdate = new Subject();
this.thermostatUpdateInProgress = false;
// Initialize Thermostat Service
accessory.context.Thermostat = accessory.context.Thermostat ?? {};
this.Thermostat = {
Name: accessory.context.Thermostat.Name ?? `${accessory.displayName} Thermostat`,
Service: accessory.getService(this.hap.Service.Thermostat) ?? this.accessory.addService(this.hap.Service.Thermostat),
TargetTemperature: accessory.context.TargetTemperature ?? 20,
CurrentTemperature: accessory.context.CurrentTemperature ?? 20,
TemperatureDisplayUnits: accessory.context.TemperatureDisplayUnits,
TargetHeatingCoolingState: accessory.context.TargetHeatingCoolingState ?? this.hap.Characteristic.TargetHeatingCoolingState.AUTO,
CurrentHeatingCoolingState: accessory.context.CurrentHeatingCoolingState ?? this.hap.Characteristic.CurrentHeatingCoolingState.OFF,
CoolingThresholdTemperature: accessory.context.CoolingThresholdTemperature ?? 20,
HeatingThresholdTemperature: accessory.context.HeatingThresholdTemperature ?? 22,
};
accessory.context.Thermostat = this.Thermostat;
// Service Name
this.Thermostat.Service
.setCharacteristic(this.hap.Characteristic.Name, this.Thermostat.Name)
.setCharacteristic(this.hap.Characteristic.CurrentHeatingCoolingState, this.Thermostat.CurrentHeatingCoolingState)
.getCharacteristic(this.hap.Characteristic.TemperatureDisplayUnits)
.onGet(() => {
this.Thermostat.TemperatureDisplayUnits = device.units === 'Celsius'
? this.hap.Characteristic.TemperatureDisplayUnits.CELSIUS
: this.hap.Characteristic.TemperatureDisplayUnits.FAHRENHEIT;
accessory.context.TemperatureDisplayUnits = this.Thermostat.TemperatureDisplayUnits;
this.debugLog(`${this.device.deviceClass} ${accessory.displayName} TemperatureDisplayUnits: ${this.Thermostat.TemperatureDisplayUnits}`);
return this.Thermostat.TemperatureDisplayUnits;
})
.onSet(this.setTemperatureDisplayUnits.bind(this));
// Set Min and Max
if (device.minHeatSetpoint && device.maxHeatSetpoint) {
this.debugLog(`${this.device.deviceClass} ${accessory.displayName} minHeatSetpoint: ${device.minHeatSetpoint}, maxHeatSetpoint: ${device.maxHeatSetpoint}, TemperatureDisplayUnits: ${this.Thermostat.TemperatureDisplayUnits}`);
const minValue = toCelsius(device.minHeatSetpoint, Number(this.Thermostat.TemperatureDisplayUnits));
const maxValue = toCelsius(device.maxHeatSetpoint, Number(this.Thermostat.TemperatureDisplayUnits));
this.debugLog(`${sensorAccessory.accessoryAttribute.type} ${this.device.deviceClass} ${accessory.displayName} minValue: ${minValue}, maxValue: ${maxValue}`);
if (device.changeableValues.heatCoolMode === 'Heat') {
this.debugLog(`${sensorAccessory.accessoryAttribute.type} ${this.device.deviceClass} ${accessory.displayName} mode: ${device.changeableValues.heatCoolMode}`);
this.Thermostat.Service
.getCharacteristic(this.hap.Characteristic.TargetTemperature)
.setProps({
minValue,
maxValue,
minStep: 0.5,
})
.onGet(() => {
return this.Thermostat.TargetTemperature;
});
}
else {
this.debugLog(`${sensorAccessory.accessoryAttribute.type} ${this.device.deviceClass} ${accessory.displayName} mode: ${device.changeableValues.heatCoolMode}`);
this.Thermostat.Service
.getCharacteristic(this.hap.Characteristic.TargetTemperature)
.setProps({
minValue,
maxValue,
minStep: 0.5,
})
.onGet(() => {
return this.Thermostat.TargetTemperature;
});
}
}
// The value property of TargetHeaterCoolerState must be one of the following:
// AUTO = 3; HEAT = 1; COOL = 2; OFF = 0;
// Set control bindings
const TargetState = [4];
TargetState.pop();
if (this.device.allowedModes?.includes('Cool')) {
TargetState.push(this.hap.Characteristic.TargetHeatingCoolingState.COOL);
}
if (this.device.allowedModes?.includes('Heat')) {
TargetState.push(this.hap.Characteristic.TargetHeatingCoolingState.HEAT);
}
if (this.device.allowedModes?.includes('Off')) {
TargetState.push(this.hap.Characteristic.TargetHeatingCoolingState.OFF);
}
if (this.device.allowedModes?.includes('Auto') || this.device.thermostat?.show_auto) {
TargetState.push(this.hap.Characteristic.TargetHeatingCoolingState.AUTO);
}
this.debugLog(`${this.device.deviceClass} ${this.accessory.displayName} allowedModes: ${this.device.allowedModes}`);
this.debugLog(`${this.device.deviceClass} ${this.accessory.displayName} Only Show These Modes: ${JSON.stringify(TargetState)}`);
this.Thermostat.Service
.getCharacteristic(this.hap.Characteristic.TargetHeatingCoolingState)
.setProps({
validValues: TargetState,
})
.onGet(() => {
return this.Thermostat.TargetHeatingCoolingState;
})
.onSet(this.setTargetHeatingCoolingState.bind(this));
this.Thermostat.Service
.getCharacteristic(this.hap.Characteristic.HeatingThresholdTemperature)
.onGet(() => {
return this.Thermostat.HeatingThresholdTemperature;
})
.onSet(this.setHeatingThresholdTemperature.bind(this));
this.Thermostat.Service
.getCharacteristic(this.hap.Characteristic.CoolingThresholdTemperature)
.onGet(() => {
return this.Thermostat.CoolingThresholdTemperature;
})
.onSet(this.setCoolingThresholdTemperature.bind(this));
this.Thermostat.Service
.getCharacteristic(this.hap.Characteristic.TargetTemperature)
.onGet(() => {
return this.Thermostat.TargetTemperature;
})
.onSet(this.setTargetTemperature.bind(this));
// Initialize Humidity Sensor Service
if (device.thermostat?.hide_humidity) {
if (this.HumiditySensor) {
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Humidity Sensor Service`);
this.HumiditySensor.Service = this.accessory.getService(this.hap.Service.HumiditySensor);
accessory.removeService(this.HumiditySensor.Service);
}
else {
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Humidity Sensor Service Not Found`);
}
}
else if (device.indoorHumidity) {
this.debugLog(`Thermostat: ${accessory.displayName} Add Humidity Sensor Service`);
accessory.context.HumiditySensor = accessory.context.HumiditySensor ?? {};
this.HumiditySensor = {
Name: accessory.context.HumiditySensor.Name ?? `${accessory.displayName} Humidity Sensor`,
Service: accessory.getService(this.hap.Service.HumiditySensor) ?? accessory.addService(this.hap.Service.HumiditySensor),
CurrentRelativeHumidity: accessory.context.CurrentRelativeHumidity ?? 50,
};
accessory.context.HumiditySensor = this.HumiditySensor;
// Initialize Humidity Sensor Characteristic
this.HumiditySensor.Service
.setCharacteristic(this.hap.Characteristic.Name, this.HumiditySensor.Name);
this.HumiditySensor.Service
.getCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity)
.setProps({
minStep: 0.1,
})
.onGet(() => {
return this.HumiditySensor.CurrentRelativeHumidity;
});
}
else {
this.debugLog(`Thermostat: ${accessory.displayName} Humidity Sensor Service Not Added`);
}
// Initial Refresh
this.refreshStatus();
// Retrieve initial values and updateHomekit
this.updateHomeKitCharacteristics();
// Start an update interval
interval(this.deviceRefreshRate * 1000)
.pipe(skipWhile(() => this.thermostatUpdateInProgress))
.subscribe(async () => {
await this.refreshStatus();
await this.refreshSensorStatus();
});
// Watch for thermostat change events
// We put in a debounce of 100ms so we don't make duplicate calls
if (device.thermostat?.roompriority?.deviceType === 'Thermostat') {
this.doRoomUpdate
.pipe(tap(() => {
this.roomUpdateInProgress = true;
}), debounceTime(this.devicePushRate * 500))
.subscribe(async () => {
try {
await this.refreshRoomPriority();
}
catch (e) {
const action = 'refreshRoomPriority';
if (this.device.retry) {
// Refresh the status from the API
interval(5000)
.pipe(skipWhile(() => this.thermostatUpdateInProgress))
.pipe(take(1))
.subscribe(async () => {
await this.refreshRoomPriority();
});
}
this.resideoAPIError(e, action);
this.apiError(e);
}
try {
await this.pushRoomChanges();
}
catch (e) {
const action = 'pushRoomChanges';
if (this.device.retry) {
// Refresh the status from the API
interval(5000)
.pipe(skipWhile(() => this.thermostatUpdateInProgress))
.pipe(take(1))
.subscribe(async () => {
await this.pushRoomChanges();
});
}
this.resideoAPIError(e, action);
this.apiError(e);
}
this.roomUpdateInProgress = false;
// Refresh the status from the API
interval(5000)
.pipe(skipWhile(() => this.thermostatUpdateInProgress))
.pipe(take(1))
.subscribe(async () => {
await this.refreshStatus();
});
});
}
this.doThermostatUpdate
.pipe(tap(() => {
this.thermostatUpdateInProgress = true;
}), debounceTime(this.devicePushRate * 1000))
.subscribe(async () => {
try {
await this.pushChanges();
}
catch (e) {
const action = 'pushChanges';
if (this.device.retry) {
// Refresh the status from the API
interval(5000)
.pipe(skipWhile(() => this.thermostatUpdateInProgress))
.pipe(take(1))
.subscribe(async () => {
await this.pushChanges();
});
}
this.resideoAPIError(e, action);
this.apiError(e);
}
this.thermostatUpdateInProgress = false;
// Refresh the status from the API
interval(5000)
.pipe(skipWhile(() => this.thermostatUpdateInProgress))
.pipe(take(1))
.subscribe(async () => {
await this.refreshStatus();
});
});
}
/**
* Parse the device status from the Resideo api
*/
async parseStatus() {
// Parse the device status
if (this.device.units === 'Fahrenheit') {
this.Thermostat.TemperatureDisplayUnits = this.hap.Characteristic.TemperatureDisplayUnits.FAHRENHEIT;
}
if (this.device.units === 'Celsius') {
this.Thermostat.TemperatureDisplayUnits = this.hap.Characteristic.TemperatureDisplayUnits.CELSIUS;
}
// Parse the Sensor Accessory status
if (this.sensorAccessory) {
const accessoryValue = this.sensorAccessory.accessoryValue
?? { indoorTemperature: 20, indoorHumidity: 50 };
this.Thermostat.CurrentTemperature = toCelsius(accessoryValue.indoorTemperature, Number(this.Thermostat.TemperatureDisplayUnits));
this.debugLog(`${this.sensorAccessory.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} CurrentTemperature: ${this.Thermostat.CurrentTemperature}`);
if (!this.device.thermostat?.hide_humidity && accessoryValue.indoorHumidity) {
if (this.HumiditySensor) {
this.HumiditySensor.CurrentRelativeHumidity = accessoryValue.indoorHumidity;
this.debugLog(`${this.sensorAccessory.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} CurrentRelativeHumidity: ${this.HumiditySensor.CurrentRelativeHumidity}`);
}
}
}
// Parse the Thermostat status
if (this.device.changeableValues.heatSetpoint > 0) {
this.Thermostat.HeatingThresholdTemperature = toCelsius(this.device.changeableValues.heatSetpoint, Number(this.Thermostat.TemperatureDisplayUnits));
}
if (this.device.changeableValues.coolSetpoint > 0) {
this.Thermostat.CoolingThresholdTemperature = toCelsius(this.device.changeableValues.coolSetpoint, Number(this.Thermostat.TemperatureDisplayUnits));
}
this.Thermostat.TargetHeatingCoolingState = HomeKitModes[this.device.changeableValues.mode];
/**
* The CurrentHeatingCoolingState is either 'Heat', 'Cool', or 'Off'
* CurrentHeatingCoolingState = OFF = 0, HEAT = 1, COOL = 2
*/
switch (this.device.operationStatus.mode) {
case 'Heat':
this.Thermostat.CurrentHeatingCoolingState = this.hap.Characteristic.CurrentHeatingCoolingState.HEAT; // 1
break;
case 'Cool':
this.Thermostat.CurrentHeatingCoolingState = this.hap.Characteristic.CurrentHeatingCoolingState.COOL; // 2
break;
default:
this.Thermostat.CurrentHeatingCoolingState = this.hap.Characteristic.CurrentHeatingCoolingState.OFF; // 0
}
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} CurrentHeatingCoolingState: ${this.Thermostat.CurrentHeatingCoolingState}`);
// Set the TargetTemperature value based on the current mode
if (this.Thermostat.TargetHeatingCoolingState === this.hap.Characteristic.TargetHeatingCoolingState.HEAT) {
if (this.device.changeableValues.heatSetpoint > 0) {
this.Thermostat.TargetTemperature = toCelsius(this.device.changeableValues.heatSetpoint, Number(this.Thermostat.TemperatureDisplayUnits));
}
}
else {
if (this.device.changeableValues.coolSetpoint > 0) {
this.Thermostat.TargetTemperature = toCelsius(this.device.changeableValues.coolSetpoint, Number(this.Thermostat.TemperatureDisplayUnits));
}
}
}
/**
* Asks the Resideo Home API for the latest device information
*/
async refreshStatus() {
try {
const device = (await this.platform.axios.get(`${DeviceURL}/thermostats/${this.device.deviceID}`, {
params: {
locationId: this.location.locationID,
},
})).data;
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${device.deviceClass} ${this.accessory.displayName} (refreshStatus) device: ${JSON.stringify(device)}`);
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${device.deviceClass} ${this.accessory.displayName} Fetched update for: ${this.device.name} from Resideo API: ${JSON.stringify(this.device.changeableValues)}`);
this.device = device;
this.parseStatus();
this.updateHomeKitCharacteristics();
}
catch (e) {
const action = 'refreshStatus';
if (this.device.retry) {
// Refresh the status from the API
interval(5000)
.pipe(skipWhile(() => this.thermostatUpdateInProgress))
.pipe(take(1))
.subscribe(async () => {
await this.refreshStatus();
});
}
this.resideoAPIError(e, action);
this.apiError(e);
}
}
/**
* Asks the Resideo Home API for the latest device information
*/
async refreshSensorStatus() {
try {
if (this.device.thermostat?.roompriority?.deviceType === 'Thermostat') {
if (typeof this.device.deviceID === 'string' && this.device.deviceID.startsWith('LCC')) {
if (this.device.deviceModel.startsWith('T9')) {
if (this.device.groups) {
const groups = this.device.groups;
for (const group of groups) {
const roomsensors = await this.platform.getCurrentSensorData(this.location, this.device, group);
if (roomsensors.rooms) {
const rooms = roomsensors.rooms;
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} roomsensors: ${JSON.stringify(roomsensors)}`);
for (const accessories of rooms) {
if (accessories) {
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} accessories: ${JSON.stringify(accessories)}`);
for (const sensorAccessory of accessories.accessories) {
if (sensorAccessory.accessoryAttribute) {
if (sensorAccessory.accessoryAttribute.type) {
if (sensorAccessory.accessoryAttribute.type.startsWith('IndoorAirSensor')) {
this.sensorAccessory = sensorAccessory;
this.parseStatus();
this.debugLog(`${sensorAccessory.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} accessoryAttribute: ${JSON.stringify(this.sensorAccessory?.accessoryAttribute)}`);
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} Name: ${this.sensorAccessory?.accessoryAttribute.name}, Software Version: ${this.sensorAccessory?.accessoryAttribute.softwareRevision}`);
}
}
}
}
}
}
}
}
}
}
}
}
this.updateHomeKitCharacteristics();
}
catch (e) {
const action = 'refreshSensorStatus';
if (this.device.retry) {
// Refresh the status from the API
interval(5000)
.pipe(skipWhile(() => this.thermostatUpdateInProgress))
.pipe(take(1))
.subscribe(async () => {
await this.refreshSensorStatus();
});
}
this.resideoAPIError(e, action);
this.apiError(e);
}
}
async refreshRoomPriority() {
if (this.device.thermostat?.roompriority?.deviceType === 'Thermostat') {
try {
const roomPriorityStatus = (await this.platform.axios.get(`${DeviceURL}/thermostats/${this.device.deviceID}/priority`, {
params: {
locationId: this.location.locationID,
},
})).data;
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} (refreshRoomPriority) roomPriorityStatus: ${JSON.stringify(roomPriorityStatus)}`);
}
catch (e) {
const action = 'refreshRoomPriority';
if (this.device.retry) {
// Refresh the status from the API
interval(5000)
.pipe(skipWhile(() => this.thermostatUpdateInProgress))
.pipe(take(1))
.subscribe(async () => {
await this.refreshRoomPriority();
});
}
this.resideoAPIError(e, action);
this.apiError(e);
}
}
this.parseStatus();
this.updateHomeKitCharacteristics();
}
/**
* Pushes the requested changes for Room Priority to the Resideo API
*/
async pushRoomChanges() {
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} Room Priority,
Current Room: ${JSON.stringify(this.roomPriorityStatus.currentPriority.selectedRooms)}, Changing Room: [${this.sensorAccessory?.accessoryId}]`);
if (`[${this.sensorAccessory?.accessoryId}]` !== `[${this.roomPriorityStatus.currentPriority.selectedRooms}]`) {
const payload = {
currentPriority: {
priorityType: this.device.thermostat?.roompriority?.priorityType,
},
};
if (this.device.thermostat?.roompriority?.priorityType === 'PickARoom') {
payload.currentPriority.selectedRooms = [this.sensorAccessory?.accessoryId];
}
/**
* For "LCC-" devices only.
* "NoHold" will return to schedule.
* "TemporaryHold" will hold the set temperature until "nextPeriodTime".
* "PermanentHold" will hold the setpoint until user requests another change.
*/
if (this.device.thermostat?.roompriority?.deviceType === 'Thermostat') {
if (this.device.thermostat?.roompriority.priorityType === 'FollowMe') {
this.successLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} sent request to Resideo API, Priority Type: ${this.device.thermostat?.roompriority.priorityType} Built-in Occupancy Sensor(s) Will be used to set Priority Automatically.`);
}
else if (this.device.thermostat?.roompriority.priorityType === 'WholeHouse') {
this.successLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} sent request to Resideo API, Priority Type: ${this.device.thermostat?.roompriority.priorityType}`);
}
else if (this.device.thermostat?.roompriority.priorityType === 'PickARoom') {
this.successLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} sent request to Resideo API, Room Priority: ${this.sensorAccessory?.accessoryAttribute.name}, Priority Type: ${this.device.thermostat?.roompriority.priorityType}`);
}
// Make the API request
try {
await this.platform.axios.put(`${DeviceURL}/thermostats/${this.device.deviceID}/priority`, payload, {
params: {
locationId: this.location.locationID,
},
});
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} pushRoomChanges: ${JSON.stringify(payload)}`);
}
catch (e) {
const action = 'pushRoomChanges';
if (this.device.retry) {
// Refresh the status from the API
interval(5000)
.pipe(skipWhile(() => this.thermostatUpdateInProgress))
.pipe(take(1))
.subscribe(async () => {
await this.pushRoomChanges();
});
}
this.resideoAPIError(e, action);
this.apiError(e);
}
}
// Refresh the status from the API
await this.refreshSensorStatus();
}
}
/**
* Pushes the requested changes to the Resideo API
*/
async pushChanges() {
try {
const payload = {
mode: await this.ResideoMode(),
thermostatSetpointStatus: this.device.thermostat?.thermostatSetpointStatus,
autoChangeoverActive: this.device.changeableValues.autoChangeoverActive,
};
// Set the heat and cool set point value based on the selected mode
switch (this.Thermostat.TargetHeatingCoolingState) {
case this.hap.Characteristic.TargetHeatingCoolingState.HEAT:
payload.heatSetpoint = toFahrenheit(Number(this.Thermostat.TargetTemperature), Number(this.Thermostat.TemperatureDisplayUnits));
payload.coolSetpoint = toFahrenheit(Number(this.Thermostat.CoolingThresholdTemperature), Number(this.Thermostat.TemperatureDisplayUnits));
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} TargetHeatingCoolingState (HEAT): ${this.Thermostat.TargetHeatingCoolingState}, TargetTemperature: ${toFahrenheit(Number(this.Thermostat.TargetTemperature), Number(this.Thermostat.TemperatureDisplayUnits))} heatSetpoint, CoolingThresholdTemperature: ${toFahrenheit(Number(this.Thermostat.CoolingThresholdTemperature), Number(this.Thermostat.TemperatureDisplayUnits))} coolSetpoint`);
break;
case this.hap.Characteristic.TargetHeatingCoolingState.COOL:
payload.coolSetpoint = toFahrenheit(Number(this.Thermostat.TargetTemperature), Number(this.Thermostat.TemperatureDisplayUnits));
payload.heatSetpoint = toFahrenheit(Number(this.Thermostat.HeatingThresholdTemperature), Number(this.Thermostat.TemperatureDisplayUnits));
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} TargetHeatingCoolingState (COOL): ${this.Thermostat.TargetHeatingCoolingState}, TargetTemperature: ${toFahrenheit(Number(this.Thermostat.TargetTemperature), Number(this.Thermostat.TemperatureDisplayUnits))} coolSetpoint, CoolingThresholdTemperature: ${toFahrenheit(Number(this.Thermostat.HeatingThresholdTemperature), Number(this.Thermostat.TemperatureDisplayUnits))} heatSetpoint`);
break;
case this.hap.Characteristic.TargetHeatingCoolingState.AUTO:
payload.coolSetpoint = toFahrenheit(Number(this.Thermostat.CoolingThresholdTemperature), Number(this.Thermostat.TemperatureDisplayUnits));
payload.heatSetpoint = toFahrenheit(Number(this.Thermostat.HeatingThresholdTemperature), Number(this.Thermostat.TemperatureDisplayUnits));
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} TargetHeatingCoolingState (AUTO): ${this.Thermostat.TargetHeatingCoolingState}, CoolingThresholdTemperature: ${toFahrenheit(Number(this.Thermostat.CoolingThresholdTemperature), Number(this.Thermostat.TemperatureDisplayUnits))} coolSetpoint, HeatingThresholdTemperature: ${toFahrenheit(Number(this.Thermostat.HeatingThresholdTemperature), Number(this.Thermostat.TemperatureDisplayUnits))} heatSetpoint`);
break;
default:
payload.coolSetpoint = toFahrenheit(Number(this.Thermostat.CoolingThresholdTemperature), Number(this.Thermostat.TemperatureDisplayUnits));
payload.heatSetpoint = toFahrenheit(Number(this.Thermostat.HeatingThresholdTemperature), Number(this.Thermostat.TemperatureDisplayUnits));
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} TargetHeatingCoolingState (OFF): ${this.Thermostat.TargetHeatingCoolingState}, CoolingThresholdTemperature: ${toFahrenheit(Number(this.Thermostat.CoolingThresholdTemperature), Number(this.Thermostat.TemperatureDisplayUnits))} coolSetpoint, HeatingThresholdTemperature: ${toFahrenheit(Number(this.Thermostat.HeatingThresholdTemperature), Number(this.Thermostat.TemperatureDisplayUnits))} heatSetpoint`);
}
this.successLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} set request (${JSON.stringify(payload)}) to Resideo API.`);
// Make the API request
await this.platform.axios.post(`${DeviceURL}/thermostats/${this.device.deviceID}`, payload, {
params: {
locationId: this.location.locationID,
},
});
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} pushChanges: ${JSON.stringify(payload)}`);
}
catch (e) {
const action = 'pushChanges';
if (this.device.retry) {
// Refresh the status from the API
interval(5000)
.pipe(skipWhile(() => this.thermostatUpdateInProgress))
.pipe(take(1))
.subscribe(async () => {
await this.pushChanges();
});
}
this.resideoAPIError(e, action);
this.apiError(e);
}
}
async ResideoMode() {
let resideoMode;
switch (this.Thermostat.TargetHeatingCoolingState) {
case this.hap.Characteristic.TargetHeatingCoolingState.HEAT:
resideoMode = ResideoModes.Heat;
break;
case this.hap.Characteristic.TargetHeatingCoolingState.COOL:
resideoMode = ResideoModes.Cool;
break;
case this.hap.Characteristic.TargetHeatingCoolingState.AUTO:
resideoMode = ResideoModes.Auto;
break;
case this.hap.Characteristic.TargetHeatingCoolingState.OFF:
resideoMode = ResideoModes.Off;
break;
default:
resideoMode = 'Unknown';
this.debugErrorLog(`${this.device.deviceClass} ${this.accessory.displayName} Unknown TargetHeatingCoolingState: ${this.Thermostat.TargetHeatingCoolingState}`);
}
return resideoMode;
}
/**
* Updates the status for each of the HomeKit Characteristics
*/
async updateHomeKitCharacteristics() {
if (this.Thermostat.TemperatureDisplayUnits === undefined) {
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} TemperatureDisplayUnits: ${this.Thermostat.TemperatureDisplayUnits}`);
}
else {
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.TemperatureDisplayUnits, this.Thermostat.TemperatureDisplayUnits);
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} updateCharacteristic TemperatureDisplayUnits: ${this.Thermostat.TemperatureDisplayUnits}`);
}
if (this.Thermostat.CurrentTemperature === undefined) {
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} CurrentTemperature: ${this.Thermostat.CurrentTemperature}`);
}
else {
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, this.Thermostat.CurrentTemperature);
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} updateCharacteristic CurrentTemperature: ${this.Thermostat.CurrentTemperature}`);
}
if (this.HumiditySensor?.CurrentRelativeHumidity === undefined) {
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} CurrentRelativeHumidity: ${this.HumiditySensor?.CurrentRelativeHumidity}`);
}
else {
this.HumiditySensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, this.HumiditySensor.CurrentRelativeHumidity);
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} updateCharacteristic CurrentRelativeHumidity: ${this.HumiditySensor.CurrentRelativeHumidity}`);
}
if (this.Thermostat.TargetTemperature === undefined) {
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} TargetTemperature: ${this.Thermostat.TargetTemperature}`);
}
else {
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.TargetTemperature, this.Thermostat.TargetTemperature);
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} updateCharacteristic TargetTemperature: ${this.Thermostat.TargetTemperature}`);
}
if (this.Thermostat.HeatingThresholdTemperature === undefined) {
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} HeatingThresholdTemperature: ${this.Thermostat.HeatingThresholdTemperature}`);
}
else {
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.HeatingThresholdTemperature, this.Thermostat.HeatingThresholdTemperature);
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} updateCharacteristic HeatingThresholdTemperature: ${this.Thermostat.HeatingThresholdTemperature}`);
}
if (this.Thermostat.CoolingThresholdTemperature === undefined) {
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} CoolingThresholdTemperature: ${this.Thermostat.CoolingThresholdTemperature}`);
}
else {
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.CoolingThresholdTemperature, this.Thermostat.CoolingThresholdTemperature);
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} updateCharacteristic CoolingThresholdTemperature: ${this.Thermostat.CoolingThresholdTemperature}`);
}
if (this.Thermostat.TargetHeatingCoolingState === undefined) {
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} TargetHeatingCoolingState: ${this.Thermostat.TargetHeatingCoolingState}`);
}
else {
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.TargetHeatingCoolingState, this.Thermostat.TargetHeatingCoolingState);
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} updateCharacteristic TargetHeatingCoolingState: ${this.Thermostat.TargetHeatingCoolingState}`);
}
if (this.Thermostat.CurrentHeatingCoolingState === undefined) {
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} CurrentHeatingCoolingState: ${this.Thermostat.CurrentHeatingCoolingState}`);
}
else {
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.CurrentHeatingCoolingState, this.Thermostat.CurrentHeatingCoolingState);
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} updateCharacteristic CurrentHeatingCoolingState: ${this.Thermostat.TargetHeatingCoolingState}`);
}
}
async apiError(e) {
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.TemperatureDisplayUnits, e);
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, e);
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, e);
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.TargetTemperature, e);
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.HeatingThresholdTemperature, e);
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.CoolingThresholdTemperature, e);
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.TargetHeatingCoolingState, e);
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.CurrentHeatingCoolingState, e);
// throw new this.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}
async setTargetHeatingCoolingState(value) {
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} Set TargetHeatingCoolingState: ${value}`);
this.Thermostat.TargetHeatingCoolingState = value;
// Set the TargetTemperature value based on the selected mode
if (this.Thermostat.TargetHeatingCoolingState === this.hap.Characteristic.TargetHeatingCoolingState.HEAT) {
this.Thermostat.TargetTemperature = toCelsius(this.device.changeableValues.heatSetpoint, Number(this.Thermostat.TemperatureDisplayUnits));
}
else {
this.Thermostat.TargetTemperature = toCelsius(this.device.changeableValues.coolSetpoint, Number(this.Thermostat.TemperatureDisplayUnits));
}
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.TargetTemperature, this.Thermostat.TargetTemperature);
if (this.Thermostat.TargetHeatingCoolingState !== HomeKitModes[this.device.changeableValues.mode]) {
this.doRoomUpdate.next();
this.doThermostatUpdate.next();
}
}
async setHeatingThresholdTemperature(value) {
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} Set HeatingThresholdTemperature: ${value}`);
this.Thermostat.HeatingThresholdTemperature = value;
this.doThermostatUpdate.next();
}
async setCoolingThresholdTemperature(value) {
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} Set CoolingThresholdTemperature: ${value}`);
this.Thermostat.CoolingThresholdTemperature = value;
this.doThermostatUpdate.next();
}
async setTargetTemperature(value) {
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} Set TargetTemperature: ${value}`);
this.Thermostat.TargetTemperature = value;
this.doThermostatUpdate.next();
}
async setTemperatureDisplayUnits(value) {
this.debugLog(`${this.sensorAccessory?.accessoryAttribute.type} ${this.device.deviceClass} ${this.accessory.displayName} Set TemperatureDisplayUnits: ${value}`);
this.warnLog('Changing the Hardware Display Units from HomeKit is not supported.');
this.Thermostat.TemperatureDisplayUnits = this.device.units === 'Celsius'
? this.hap.Characteristic.TemperatureDisplayUnits.CELSIUS
: this.hap.Characteristic.TemperatureDisplayUnits.FAHRENHEIT;
// change the temp units back to the one the Resideo API said the thermostat was set to
setTimeout(() => {
this.Thermostat.Service.updateCharacteristic(this.hap.Characteristic.TemperatureDisplayUnits, this.Thermostat.TemperatureDisplayUnits);
}, 100);
}
}
//# sourceMappingURL=roomsensorthermostats.js.map