@homebridge-plugins/homebridge-smarthq
Version:
The SmartHQ plugin allows you to interact with SmartHQ Devices in HomeKit and with Siri.
743 lines • 37.4 kB
JavaScript
import axios from 'axios';
import { interval, startWith } from 'rxjs';
import { ERD_TYPES } from '../settings.js';
import { deviceBase } from './device.js';
var PowerState;
(function (PowerState) {
PowerState["ON"] = "01";
PowerState["OFF"] = "00";
})(PowerState || (PowerState = {}));
var TemperatureUnit;
(function (TemperatureUnit) {
TemperatureUnit["FAHRENHEIT"] = "00";
TemperatureUnit["CELSIUS"] = "01";
})(TemperatureUnit || (TemperatureUnit = {}));
var FanSetting;
(function (FanSetting) {
FanSetting["AUTO"] = "01";
FanSetting["LOW"] = "02";
FanSetting["MED"] = "04";
FanSetting["HIGH"] = "08";
})(FanSetting || (FanSetting = {}));
var FilterStatus;
(function (FilterStatus) {
FilterStatus["OK"] = "00";
FilterStatus["CLEAN"] = "01";
})(FilterStatus || (FilterStatus = {}));
var AcSwingMode;
(function (AcSwingMode) {
AcSwingMode["DISABLED"] = "00";
AcSwingMode["ENABLED"] = "01";
})(AcSwingMode || (AcSwingMode = {}));
var OperationMode;
(function (OperationMode) {
OperationMode["COOL"] = "00";
OperationMode["FAN_ONLY"] = "01";
OperationMode["ENERGY_SAVER"] = "02";
OperationMode["HEAT"] = "03";
OperationMode["DRY"] = "04";
})(OperationMode || (OperationMode = {}));
export class SmartHQAirConditioner extends deviceBase {
platform;
accessory;
device;
// HeaterCooler service
HEATER_COOLER_SVC_NAME = 'AIR_CONDITIONER';
heaterCoolerSvc;
// Mode SwitchServices
MODE_SWITCH_SVC_PREFIX = 'AIR_CONDITIONER_MODE';
modeSwitchSvc;
constructor(platform, accessory, device) {
super(platform, accessory, device);
this.platform = platform;
this.accessory = accessory;
this.device = device;
// HeaterCooler service
this.heaterCoolerSvc = this.accessory.getService(this.HEATER_COOLER_SVC_NAME)
?? this.accessory.addService(this.platform.Service.HeaterCooler, accessory.displayName, this.HEATER_COOLER_SVC_NAME);
// Mode SwitchServices
this.modeSwitchSvc = {
[OperationMode.COOL]: this.accessory.getService(`${this.MODE_SWITCH_SVC_PREFIX}_COOL`)
?? this.accessory.addService(this.platform.Service.Switch, `${accessory.displayName} Cool Mode`, `${this.MODE_SWITCH_SVC_PREFIX}_COOL`),
[OperationMode.FAN_ONLY]: this.accessory.getService(`${this.MODE_SWITCH_SVC_PREFIX}_FAN_ONLY`)
?? this.accessory.addService(this.platform.Service.Switch, `${accessory.displayName} Fan Only Mode`, `${this.MODE_SWITCH_SVC_PREFIX}_FAN_ONLY`),
[OperationMode.ENERGY_SAVER]: this.accessory.getService(`${this.MODE_SWITCH_SVC_PREFIX}_ENERGY_SAVER`)
?? this.accessory.addService(this.platform.Service.Switch, `${accessory.displayName} Energy Saver Mode`, `${this.MODE_SWITCH_SVC_PREFIX}_ENERGY_SAVER`),
[OperationMode.HEAT]: this.accessory.getService(`${this.MODE_SWITCH_SVC_PREFIX}_HEAT`)
?? this.accessory.addService(this.platform.Service.Switch, `${accessory.displayName} Heat Mode`, `${this.MODE_SWITCH_SVC_PREFIX}_HEAT`),
[OperationMode.DRY]: this.accessory.getService(`${this.MODE_SWITCH_SVC_PREFIX}_DRY`)
?? this.accessory.addService(this.platform.Service.Switch, `${accessory.displayName} Dry Mode`, `${this.MODE_SWITCH_SVC_PREFIX}_DRY`),
};
// Active
this.heaterCoolerSvc
.getCharacteristic(this.platform.Characteristic.Active)
.onGet(this.handleGetActive.bind(this))
.onSet(this.handleSetActive.bind(this));
// Current mode
this.heaterCoolerSvc
.getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState)
.setProps({
validValues: [
this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE,
this.platform.Characteristic.CurrentHeaterCoolerState.IDLE,
this.platform.Characteristic.CurrentHeaterCoolerState.HEATING,
this.platform.Characteristic.CurrentHeaterCoolerState.COOLING,
],
})
.onGet(this.handleGetCurrentHeaterCoolerState.bind(this));
// Target mode (HEAT and COOL)
this.heaterCoolerSvc
.getCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState)
.setProps({
validValues: [
this.platform.Characteristic.TargetHeaterCoolerState.HEAT,
this.platform.Characteristic.TargetHeaterCoolerState.COOL,
],
})
.onGet(this.handleGetTargetHeaterCoolerState.bind(this))
.onSet(this.handleSetTargetHeaterCoolerState.bind(this));
// Ambient temp
this.heaterCoolerSvc
.getCharacteristic(this.platform.Characteristic.CurrentTemperature)
.onGet(this.handleGetCurrentTemperature.bind(this));
// Target temperature
this.heaterCoolerSvc
.getCharacteristic(this.platform.Characteristic.CoolingThresholdTemperature)
.setProps({
minValue: 17.7778, // 64F
maxValue: 30, // 86F
})
.onGet(this.handleGetCoolingThresholdTemperature.bind(this))
.onSet(this.handleSetCoolingThresholdTemperature.bind(this));
// Heating threshold temperature
this.heaterCoolerSvc
.getCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature)
.setProps({
minValue: 17.7778, // 64F
maxValue: 30, // 86F
})
.onGet(this.handleGetHeatingThresholdTemperature.bind(this))
.onSet(this.handleSetHeatingThresholdTemperature.bind(this));
// Rotation speed
this.heaterCoolerSvc
.getCharacteristic(this.platform.Characteristic.RotationSpeed)
.onGet(this.handleGetRotationSpeed.bind(this))
.onSet(this.handleSetRotationSpeed.bind(this));
// Display units
this.heaterCoolerSvc
.getCharacteristic(this.platform.Characteristic.TemperatureDisplayUnits)
.onGet(this.handleGetTemperatureDisplayUnits.bind(this))
.onSet(this.handleSetTemperatureDisplayUnits.bind(this));
// Filter
this.heaterCoolerSvc
.getCharacteristic(this.platform.Characteristic.FilterChangeIndication)
.onGet(this.handleGetFilterChangeIndication.bind(this));
// Swing mode
this.heaterCoolerSvc
.getCharacteristic(this.platform.Characteristic.SwingMode)
.onGet(this.handleGetSwingMode.bind(this))
.onSet(this.handleSetSwingMode.bind(this));
// Modes
for (const mode of Object.values(OperationMode)) {
this.modeSwitchSvc[mode]
.getCharacteristic(this.platform.Characteristic.On)
.onGet(this.handleGetOperationMode.bind(this, mode))
.onSet(this.handleSetOperationMode.bind(this, mode));
this.modeSwitchSvc[mode]
.getCharacteristic(this.platform.Characteristic.Name)
.onGet(this.handleGetOperationModeName.bind(this, mode));
}
// Start an update interval to refresh state
interval(this.deviceRefreshRate * 1000)
.pipe(startWith(0))
.subscribe(this.refreshState.bind(this));
}
// API
async getErdValue(erd) {
try {
const response = await axios.get(`/appliance/${this.accessory.context.device.applianceId}/erd/${erd}`);
return response.data.value;
}
catch (cause) {
throw new Error(axios.isAxiosError(cause) && cause.response
? `Failed to fetch ERD: ${cause.response.data.message}`
: `Failed to fetch ERD: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
}
}
async setErdValue(erd, value) {
try {
await axios.post(`/appliance/${this.accessory.context.device.applianceId}/erd/${erd}`, {
kind: 'appliance#erdListEntry',
userId: this.accessory.context.userId,
applianceId: this.accessory.context.device.applianceId,
erd,
value,
});
this.platform.log.debug(`[${this.accessory.displayName}] Set ERD ${erd}=${value}`);
}
catch (cause) {
throw new Error(axios.isAxiosError(cause) && cause.response
? `Failed to set ERD ${erd}=${value}: ${cause.response.data.message}`
: `Failed to set ERD ${erd}=${value}: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
}
}
async getPowerState() {
const erdValue = await this.getErdValue(ERD_TYPES.AIR_CONDITIONER_POWER_STATUS);
return erdValue;
}
async setPowerState(value) {
await this.setErdValue(ERD_TYPES.AIR_CONDITIONER_POWER_STATUS, value);
this.platform.log.debug(`[${this.accessory.displayName}] Set power state to ${value}`);
}
async getAmbientTemperature() {
try {
const erdValue = await this.getErdValue(ERD_TYPES.AIR_CONDITIONER_AMBIENT_TEMPERATURE);
const temperatureInFahrenheit = Number.parseInt(erdValue, 16); // erdValue is a hex string representing the temperature in Fahrenheit
return this.fahrenheitToCelsius(temperatureInFahrenheit); // homekit expects Celsius
}
catch (cause) {
throw new Error(`Failed to get current temperature: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
}
}
async getTemperature() {
try {
const erdValue = await this.getErdValue(ERD_TYPES.AIR_CONDITIONER_TARGET_TEMPERATURE);
const temperatureInFahrenheit = Number.parseInt(erdValue, 16); // erdValue is a hex string representing the temperature in Fahrenheit
return this.fahrenheitToCelsius(temperatureInFahrenheit); // homekit expects Celsius
}
catch (cause) {
throw new Error(`Failed to get target temperature: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
}
}
async setTemperature(value) {
try {
const temperatureInFahrenheit = this.celsiusToFahrenheit(value);
const hexTemperature = Math.round(temperatureInFahrenheit).toString(16).padStart(4, '0').toUpperCase(); // Convert to hex and ensure it's 4 characters long
await this.setErdValue(ERD_TYPES.AIR_CONDITIONER_TARGET_TEMPERATURE, hexTemperature);
this.platform.log.debug(`[${this.accessory.displayName}] Set temperature to ${value}°C (${temperatureInFahrenheit}°F)`);
}
catch (cause) {
throw new Error(`Failed to set target temperature: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
}
}
async getTemperatureDisplayUnits() {
try {
const value = await this.getErdValue(ERD_TYPES.AIR_CONDITIONER_TEMPERATURE_UNIT);
return value;
}
catch (cause) {
throw new Error(`Failed to get temperature display units: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
}
}
async setTemperatureDisplayUnits(value) {
try {
await this.setErdValue(ERD_TYPES.AIR_CONDITIONER_TEMPERATURE_UNIT, value);
this.platform.log.debug(`[${this.accessory.displayName}] Set temperature display units to ${value}`);
}
catch (cause) {
throw new Error(`Failed to set temperature display units: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
}
}
async getOperationMode() {
try {
const value = await this.getErdValue(ERD_TYPES.AIR_CONDITIONER_OPERATION_MODE);
return value;
}
catch (cause) {
throw new Error(`Failed to get operation mode: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
}
}
async setOperationMode(value) {
try {
await this.setErdValue(ERD_TYPES.AIR_CONDITIONER_OPERATION_MODE, value);
this.platform.log.debug(`[${this.accessory.displayName}] Set operation mode to ${value}`);
}
catch (cause) {
throw new Error(`Failed to set operation mode: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
}
}
async getFanSetting() {
try {
const value = await this.getErdValue(ERD_TYPES.AIR_CONDITIONER_FAN_SETTING);
return value;
}
catch (cause) {
throw new Error(`Failed to get fan setting: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
}
}
async setFanSetting(value) {
try {
await this.setErdValue(ERD_TYPES.AIR_CONDITIONER_FAN_SETTING, value);
this.platform.log.debug(`[${this.accessory.displayName}] Set fan setting to ${value}`);
}
catch (cause) {
throw new Error(`Failed to set fan setting: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
}
}
async getFilterStatus() {
try {
const value = await this.getErdValue(ERD_TYPES.AIR_CONDITIONER_FILTER_STATUS);
return value;
}
catch (cause) {
throw new Error(`Failed to get filter status: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
}
}
async getSwingMode() {
try {
const value = await this.getErdValue(ERD_TYPES.AIR_CONDITIONER_SWING_MODE);
return value;
}
catch (cause) {
// Some devices (e.g. PHNT10CC) do not support the swing mode ERD and return a 400 error
const axiosCause = cause instanceof Error ? cause.cause : null;
if (axios.isAxiosError(axiosCause) && axiosCause.response?.status === 400) {
this.platform.log.debug(`[${this.accessory.displayName}] Swing mode not supported by this device, defaulting to disabled`);
return AcSwingMode.DISABLED;
}
throw new Error(`Failed to get swing mode: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
}
}
async setSwingMode(value) {
try {
await this.setErdValue(ERD_TYPES.AIR_CONDITIONER_SWING_MODE, value);
this.platform.log.debug(`[${this.accessory.displayName}] Set swing mode to ${value}`);
}
catch (cause) {
throw new Error(`Failed to set swing mode: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
}
}
// Characteristic handlers
// active
async handleGetActive() {
try {
const powerState = await this.getPowerState();
return powerState === PowerState.ON
? this.platform.Characteristic.Active.ACTIVE
: this.platform.Characteristic.Active.INACTIVE;
}
catch (cause) {
const error = new Error(`Failed to handle get active: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleSetActive(value) {
try {
const [powerState, ambientTemperature, targetTemperature, operationMode] = await Promise.all([
this.getPowerState(),
this.getAmbientTemperature(),
this.getTemperature(),
this.getOperationMode(),
]);
if (value === this.platform.Characteristic.Active.ACTIVE) {
// If the air conditioner is currently off, turn it on
if (powerState === PowerState.OFF) {
await this.setPowerState(PowerState.ON);
// There's a bug (feature?) in SmartHQ where it resets operation mode when turning on the air conditioner
// so we need to set it back to the previous mode
await this.setOperationMode(operationMode);
}
// Keep mode switches in sync
for (const mode of Object.values(OperationMode)) {
this.modeSwitchSvc[mode].updateCharacteristic(this.platform.Characteristic.On, mode === operationMode);
}
// Update CurrentHeaterCoolerState
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState, operationMode === OperationMode.HEAT
? (ambientTemperature >= targetTemperature
? this.platform.Characteristic.CurrentHeaterCoolerState.IDLE
: this.platform.Characteristic.CurrentHeaterCoolerState.HEATING)
: (ambientTemperature <= targetTemperature
? this.platform.Characteristic.CurrentHeaterCoolerState.IDLE
: this.platform.Characteristic.CurrentHeaterCoolerState.COOLING));
return;
}
if (powerState === PowerState.ON) {
await this.setPowerState(PowerState.OFF);
}
// Keep mode switches in sync
for (const mode of Object.values(OperationMode)) {
this.modeSwitchSvc[mode].updateCharacteristic(this.platform.Characteristic.On, false);
}
// Keep TargetHeaterCoolerState in sync
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState, this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE);
}
catch (cause) {
const error = new Error(`Failed to handle set active: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleGetCurrentHeaterCoolerState() {
try {
const [powerState, ambientTemperature, targetTemperature, operationMode] = await Promise.all([
this.getPowerState(),
this.getAmbientTemperature(),
this.getTemperature(),
this.getOperationMode(),
]);
if (powerState === PowerState.OFF) {
return this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE;
}
if (operationMode === OperationMode.HEAT) {
if (ambientTemperature >= targetTemperature) {
return this.platform.Characteristic.CurrentHeaterCoolerState.IDLE;
}
// Keep TargetHeaterCoolerState in sync
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState, this.platform.Characteristic.TargetHeaterCoolerState.HEAT);
return this.platform.Characteristic.CurrentHeaterCoolerState.HEATING;
}
if (ambientTemperature <= targetTemperature) {
return this.platform.Characteristic.CurrentHeaterCoolerState.IDLE;
}
// Keep TargetHeaterCoolerState in sync
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState, this.platform.Characteristic.TargetHeaterCoolerState.COOL);
return this.platform.Characteristic.CurrentHeaterCoolerState.COOLING;
}
catch (cause) {
const error = new Error(`Failed to handle get current heater cooler state: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleGetTargetHeaterCoolerState() {
try {
const operationMode = await this.getOperationMode();
return operationMode === OperationMode.HEAT
? this.platform.Characteristic.TargetHeaterCoolerState.HEAT
: this.platform.Characteristic.TargetHeaterCoolerState.COOL;
}
catch (cause) {
const error = new Error(`Failed to handle get target heater cooler state: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleSetTargetHeaterCoolerState(value) {
try {
const powerState = await this.getPowerState();
// Turn on the air conditioner if it's currently off
if (powerState === PowerState.OFF) {
await this.setPowerState(PowerState.ON);
}
if (value === this.platform.Characteristic.TargetHeaterCoolerState.HEAT) {
await this.setOperationMode(OperationMode.HEAT);
// Keep CurrentHeaterCoolerState in sync with TargetHeaterCoolerState
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState, this.platform.Characteristic.CurrentHeaterCoolerState.HEATING);
// Keep mode switches in sync
for (const mode of Object.values(OperationMode)) {
this.modeSwitchSvc[mode].updateCharacteristic(this.platform.Characteristic.On, mode === OperationMode.HEAT);
}
}
else {
await this.setOperationMode(OperationMode.COOL);
// Keep CurrentHeaterCoolerState in sync with TargetHeaterCoolerState
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState, this.platform.Characteristic.CurrentHeaterCoolerState.COOLING);
// Keep mode switches in sync
for (const mode of Object.values(OperationMode)) {
this.modeSwitchSvc[mode].updateCharacteristic(this.platform.Characteristic.On, mode === OperationMode.COOL);
}
}
}
catch (cause) {
const error = new Error(`Failed to handle set target heater cooler state: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleGetCurrentTemperature() {
try {
const value = await this.getAmbientTemperature();
return value;
}
catch (cause) {
const error = new Error(`Failed to handle get current temperature: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleGetCoolingThresholdTemperature() {
try {
const value = await this.getTemperature();
return value;
}
catch (cause) {
const error = new Error(`Failed to handle get cooling threshold temperature: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleSetCoolingThresholdTemperature(value) {
try {
const targetTemperature = Number.parseFloat(value);
await this.setTemperature(targetTemperature);
}
catch (cause) {
const error = new Error(`Failed to handle set cooling threshold temperature: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleGetHeatingThresholdTemperature() {
try {
const value = await this.getTemperature();
return value;
}
catch (cause) {
const error = new Error(`Failed to handle get heating threshold temperature: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleSetHeatingThresholdTemperature(value) {
try {
const targetTemperature = Number.parseFloat(value);
await this.setTemperature(targetTemperature);
}
catch (cause) {
const error = new Error(`Failed to handle set heating threshold temperature: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleGetRotationSpeed() {
try {
const value = await this.getFanSetting();
switch (value) {
case FanSetting.AUTO:
return 0;
case FanSetting.LOW:
return 33;
case FanSetting.MED:
return 66;
case FanSetting.HIGH:
return 100;
default:
throw new Error(`Unknown fan setting: ${value}`);
}
}
catch (cause) {
const error = new Error(`Failed to handle get fan setting: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleSetRotationSpeed(value) {
try {
const speed = value;
// AUTO
if (speed === 0) {
await this.setFanSetting(FanSetting.AUTO);
return;
}
// LOW
if (speed <= 33) {
await this.setFanSetting(FanSetting.LOW);
return;
}
// MED
if (speed <= 66) {
await this.setFanSetting(FanSetting.MED);
return;
}
// HIGH
await this.setFanSetting(FanSetting.HIGH);
}
catch (cause) {
const error = new Error(`Failed to handle set fan setting: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleGetTemperatureDisplayUnits() {
try {
const value = await this.getTemperatureDisplayUnits();
return value === TemperatureUnit.FAHRENHEIT
? this.platform.Characteristic.TemperatureDisplayUnits.FAHRENHEIT
: this.platform.Characteristic.TemperatureDisplayUnits.CELSIUS;
}
catch (cause) {
const error = new Error(`Failed to handle get temperature display units: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleSetTemperatureDisplayUnits(value) {
try {
const temperatureUnit = value === this.platform.Characteristic.TemperatureDisplayUnits.FAHRENHEIT
? TemperatureUnit.FAHRENHEIT
: TemperatureUnit.CELSIUS;
await this.setTemperatureDisplayUnits(temperatureUnit);
}
catch (cause) {
const error = new Error(`Failed to handle set temperature display units: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleGetFilterChangeIndication() {
try {
const value = await this.getFilterStatus();
return value === FilterStatus.OK
? this.platform.Characteristic.FilterChangeIndication.FILTER_OK
: this.platform.Characteristic.FilterChangeIndication.CHANGE_FILTER;
}
catch (cause) {
const error = new Error(`Failed to handle get filter change indication: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleGetSwingMode() {
try {
const value = await this.getSwingMode();
return value === AcSwingMode.ENABLED
? this.platform.Characteristic.SwingMode.SWING_ENABLED
: this.platform.Characteristic.SwingMode.SWING_DISABLED;
}
catch (cause) {
const error = new Error(`Failed to handle get swing mode: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleSetSwingMode(value) {
try {
const swingMode = value === this.platform.Characteristic.SwingMode.SWING_ENABLED
? AcSwingMode.ENABLED
: AcSwingMode.DISABLED;
await this.setSwingMode(swingMode);
}
catch (cause) {
const error = new Error(`Failed to handle set swing mode: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleGetOperationMode(mode) {
try {
const [powerState, currentOperationMode] = await Promise.all([
this.getPowerState(),
this.getOperationMode(),
]);
// If the air conditioner is off, all modes are off
if (powerState === PowerState.OFF) {
return false;
}
return currentOperationMode === mode;
}
catch (cause) {
const error = new Error(`Failed to handle get operation mode ${mode}: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
async handleSetOperationMode(mode, value) {
try {
const [powerState, currentOperationMode] = await Promise.all([
this.getPowerState(),
this.getOperationMode(),
]);
// turn on the Air Conditioner if it's currently off
if (value && powerState === PowerState.OFF) {
await this.setPowerState(PowerState.ON);
// Keep Active in sync
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.Active, this.platform.Characteristic.Active.ACTIVE);
// Keep CurrentHeaterCoolerState in sync
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState, mode === OperationMode.HEAT
? this.platform.Characteristic.CurrentHeaterCoolerState.HEATING
: this.platform.Characteristic.CurrentHeaterCoolerState.COOLING);
// Keep TargetHeaterCoolerState in sync
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState, mode === OperationMode.HEAT
? this.platform.Characteristic.TargetHeaterCoolerState.HEAT
: this.platform.Characteristic.TargetHeaterCoolerState.COOL);
// turn off the Air Conditioner if the user turned off the current mode
}
else if (!value && currentOperationMode === mode && powerState === PowerState.ON) {
await this.setPowerState(PowerState.OFF);
// Keep Active in sync
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.Active, this.platform.Characteristic.Active.INACTIVE);
// Keep CurrentHeaterCoolerState in sync
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState, this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE);
}
if (value) {
await this.setOperationMode(mode);
}
// switch the rest off
for (const m of Object.values(OperationMode)) {
this.modeSwitchSvc[m].updateCharacteristic(this.platform.Characteristic.On, m === mode);
}
}
catch (cause) {
const error = new Error(`Failed to handle set operation mode ${mode}: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
handleGetOperationModeName(mode) {
try {
switch (mode) {
case OperationMode.COOL:
return 'Cool Mode';
case OperationMode.FAN_ONLY:
return 'Fan Only Mode';
case OperationMode.ENERGY_SAVER:
return 'Energy Saver Mode';
case OperationMode.HEAT:
return 'Heat Mode';
case OperationMode.DRY:
return 'Dry Mode';
default:
throw new Error(`Unknown operation mode: ${mode}`);
}
}
catch (cause) {
const error = new Error(`Failed to handle get operation mode name for ${mode}: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
// Refresh state
async refreshState() {
try {
// active
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.Active, await this.handleGetActive());
// Current mode
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState, await this.handleGetCurrentHeaterCoolerState());
// Target mode
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState, await this.handleGetTargetHeaterCoolerState());
// Ambient temp
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, await this.handleGetCurrentTemperature());
// Target temperature
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.CoolingThresholdTemperature, await this.handleGetCoolingThresholdTemperature());
// Heating threshold temperature
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature, await this.handleGetHeatingThresholdTemperature());
// Rotation speed
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.RotationSpeed, await this.handleGetRotationSpeed());
// Display units
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.TemperatureDisplayUnits, await this.handleGetTemperatureDisplayUnits());
// Filter
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.FilterChangeIndication, await this.handleGetFilterChangeIndication());
// Swing mode
this.heaterCoolerSvc.updateCharacteristic(this.platform.Characteristic.SwingMode, await this.handleGetSwingMode());
// Modes
for (const mode of Object.values(OperationMode)) {
this.modeSwitchSvc[mode].updateCharacteristic(this.platform.Characteristic.On, await this.handleGetOperationMode(mode));
}
this.platform.log.debug(`[${this.accessory.displayName}] Refreshed state`);
}
catch (cause) {
const error = new Error(`Failed to refresh state for ${this.accessory.displayName}: ${cause instanceof Error ? cause.message : 'An unknown error occurred'}`, { cause });
this.platform.log.error(`[${this.accessory.displayName}] ${error.message}`);
throw error;
}
}
// Helpers
fahrenheitToCelsius(fahrenheit) {
return (fahrenheit - 32) * 5 / 9;
}
celsiusToFahrenheit(celsius) {
return (celsius * 9 / 5) + 32;
}
}
//# sourceMappingURL=airConditioner.js.map