@elshaer/homebridge-lg-thinq
Version:
A Homebridge plugin for controlling/monitoring LG ThinQ device via LG ThinQ platform.
800 lines • 39.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ACStatus = exports.FanSpeed = exports.ACModelType = void 0;
const baseDevice_1 = require("../baseDevice");
const DeviceModel_1 = require("../lib/DeviceModel");
const helper_1 = require("../helper");
var ACModelType;
(function (ACModelType) {
ACModelType["AWHP"] = "AWHP";
ACModelType["RAC"] = "RAC";
})(ACModelType = exports.ACModelType || (exports.ACModelType = {}));
var FanSpeed;
(function (FanSpeed) {
FanSpeed[FanSpeed["LOW"] = 2] = "LOW";
FanSpeed[FanSpeed["LOW_MEDIUM"] = 3] = "LOW_MEDIUM";
FanSpeed[FanSpeed["MEDIUM"] = 4] = "MEDIUM";
FanSpeed[FanSpeed["MEDIUM_HIGH"] = 5] = "MEDIUM_HIGH";
FanSpeed[FanSpeed["HIGH"] = 6] = "HIGH";
})(FanSpeed = exports.FanSpeed || (exports.FanSpeed = {}));
var OpMode;
(function (OpMode) {
OpMode[OpMode["AUTO"] = 6] = "AUTO";
OpMode[OpMode["COOL"] = 0] = "COOL";
OpMode[OpMode["HEAT"] = 4] = "HEAT";
OpMode[OpMode["FAN"] = 2] = "FAN";
OpMode[OpMode["DRY"] = 1] = "DRY";
OpMode[OpMode["AIR_CLEAN"] = 5] = "AIR_CLEAN";
})(OpMode || (OpMode = {}));
class AirConditioner extends baseDevice_1.baseDevice {
constructor(platform, accessory) {
var _a;
super(platform, accessory);
this.platform = platform;
this.accessory = accessory;
this.jetModeModels = ['RAC_056905'];
this.quietModeModels = ['WINF_056905'];
this.energySaveModeModels = ['WINF_056905', 'RAC_056905'];
this.airCleanModels = ['RAC_056905'];
this.currentTargetState = 2; // default target: COOL
const device = this.accessory.context.device;
const { Service: { TemperatureSensor, HumiditySensor, Switch, Lightbulb, }, } = this.platform;
this.createHeaterCoolerService();
this.service.addOptionalCharacteristic(this.platform.customCharacteristics.TotalConsumption);
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.ac_air_quality) && this.Status.airQuality) {
this.createAirQualityService();
}
else if (this.serviceAirQuality) {
accessory.removeService(this.serviceAirQuality);
}
this.serviceSensor = accessory.getService(TemperatureSensor);
if (this.config.ac_temperature_sensor) {
this.serviceSensor = this.serviceSensor || accessory.addService(TemperatureSensor);
this.serviceSensor.updateCharacteristic(platform.Characteristic.StatusActive, false);
this.serviceSensor.addLinkedService(this.service);
}
else if (this.serviceSensor) {
accessory.removeService(this.serviceSensor);
this.serviceSensor = null;
}
this.serviceHumiditySensor = accessory.getService(HumiditySensor);
if (this.config.ac_humidity_sensor) {
this.serviceHumiditySensor = this.serviceHumiditySensor || accessory.addService(HumiditySensor);
this.serviceHumiditySensor.updateCharacteristic(platform.Characteristic.StatusActive, false);
this.serviceSensor.addLinkedService(this.service);
}
else if (this.serviceHumiditySensor) {
accessory.removeService(this.serviceHumiditySensor);
this.serviceHumiditySensor = null;
}
this.serviceLight = accessory.getService(Lightbulb);
if (this.config.ac_led_control) {
this.serviceLight = this.serviceLight || accessory.addService(Lightbulb);
this.serviceLight.getCharacteristic(platform.Characteristic.On)
.onSet(this.setLight.bind(this))
.updateValue(false); // off as default
this.serviceLight.addLinkedService(this.service);
}
else if (this.serviceLight) {
accessory.removeService(this.serviceLight);
this.serviceLight = null;
}
if (this.config.ac_fan_control) {
this.createFanService();
}
else if (this.serviceFanV2) {
accessory.removeService(this.serviceFanV2);
}
// more feature
if (this.config.ac_jet_control && this.isJetModeEnabled(device)) {
this.serviceJetMode = accessory.getService('Jet Mode') || accessory.addService(Switch, 'Jet Mode', 'Jet Mode');
this.serviceJetMode.updateCharacteristic(platform.Characteristic.Name, 'Jet Mode');
this.serviceJetMode.getCharacteristic(platform.Characteristic.On)
.onSet(this.setJetModeActive.bind(this));
}
else if (this.serviceJetMode) {
accessory.removeService(this.serviceJetMode);
this.serviceJetMode = null;
}
if (this.quietModeModels.includes(device.model)) {
this.serviceQuietMode = accessory.getService('Quiet mode') || accessory.addService(Switch, 'Quiet mode', 'Quiet mode');
this.serviceQuietMode.updateCharacteristic(platform.Characteristic.Name, 'Quiet mode');
this.serviceQuietMode.getCharacteristic(platform.Characteristic.On)
.onSet(this.setQuietModeActive.bind(this));
}
this.serviceEnergySaveMode = accessory.getService('Energy save');
if (this.energySaveModeModels.includes(device.model) && this.config.ac_energy_save) {
if (!this.serviceEnergySaveMode) {
this.serviceEnergySaveMode = accessory.addService(Switch, 'Energy save', 'Energy save');
}
this.serviceEnergySaveMode.updateCharacteristic(platform.Characteristic.Name, 'Energy save');
this.serviceEnergySaveMode.getCharacteristic(platform.Characteristic.On)
.onSet(this.setEnergySaveActive.bind(this));
}
else if (this.serviceEnergySaveMode) {
accessory.removeService(this.serviceEnergySaveMode);
this.serviceEnergySaveMode = null;
}
this.serviceAirClean = accessory.getService('Air Purify');
if (this.airCleanModels.includes(device.model) && this.config.ac_air_clean) {
if (!this.serviceAirClean) {
this.serviceAirClean = accessory.addService(Switch, 'Air Purify', 'Air Purify');
}
this.serviceAirClean.updateCharacteristic(platform.Characteristic.Name, 'Air Purify');
this.serviceAirClean.getCharacteristic(platform.Characteristic.On)
.onSet(this.setAirCleanActive.bind(this));
}
else if (this.serviceAirClean) {
accessory.removeService(this.serviceAirClean);
this.serviceAirClean = null;
}
this.setupButton(device);
// send request every minute to update temperature
// https://github.com/nVuln/homebridge-lg-thinq/issues/177
setInterval(() => {
var _a;
if (device.online) {
(_a = this.platform.ThinQ) === null || _a === void 0 ? void 0 : _a.deviceControl(device.id, {
dataKey: 'airState.mon.timeout',
dataValue: '70',
}, 'Set', 'allEventEnable', 'control').then(() => {
// success
});
}
}, 60000);
}
get config() {
return Object.assign({}, {
ac_swing_mode: 'BOTH',
ac_air_quality: false,
ac_mode: 'BOTH',
ac_temperature_sensor: false,
ac_humidity_sensor: false,
ac_led_control: false,
ac_fan_control: false,
ac_jet_control: false,
ac_temperature_unit: 'C',
ac_buttons: [],
ac_air_clean: true,
ac_energy_save: true,
}, super.config);
}
get Status() {
return new ACStatus(this.accessory.context.device.snapshot, this.accessory.context.device, this.config);
}
async setEnergySaveActive(value) {
var _a;
const device = this.accessory.context.device;
if (this.Status.isPowerOn && this.Status.opMode === 0) {
(_a = this.platform.ThinQ) === null || _a === void 0 ? void 0 : _a.deviceControl(device.id, {
dataKey: 'airState.powerSave.basic',
dataValue: value ? 1 : 0,
}).then(() => {
device.data.snapshot['airState.powerSave.basic'] = value ? 1 : 0;
this.updateAccessoryCharacteristic(device);
});
}
}
async setAirCleanActive(value) {
var _a;
const device = this.accessory.context.device;
if (this.Status.isPowerOn && this.Status.opMode === 0) {
(_a = this.platform.ThinQ) === null || _a === void 0 ? void 0 : _a.deviceControl(device.id, {
dataKey: 'airState.wMode.airClean',
dataValue: value ? 1 : 0,
}).then(() => {
device.data.snapshot['airState.wMode.airClean'] = value ? 1 : 0;
this.updateAccessoryCharacteristic(device);
});
}
}
async setQuietModeActive(value) {
var _a;
const device = this.accessory.context.device;
if (this.Status.isPowerOn && this.Status.opMode === 0) {
(_a = this.platform.ThinQ) === null || _a === void 0 ? void 0 : _a.deviceControl(device.id, {
dataKey: 'airState.miscFuncState.silentAWHP',
dataValue: value ? 1 : 0,
}).then(() => {
device.data.snapshot['airState.miscFuncState.silentAWHP'] = value ? 1 : 0;
this.updateAccessoryCharacteristic(device);
});
}
}
async setJetModeActive(value) {
var _a;
const device = this.accessory.context.device;
if (this.Status.isPowerOn && this.Status.opMode === 0) {
(_a = this.platform.ThinQ) === null || _a === void 0 ? void 0 : _a.deviceControl(device.id, {
dataKey: 'airState.wMode.jet',
dataValue: value ? 1 : 0,
}).then(() => {
device.data.snapshot['airState.wMode.jet'] = value ? 1 : 0;
this.updateAccessoryCharacteristic(device);
});
}
}
async setFanState(value) {
var _a;
if (!this.Status.isPowerOn) {
return;
}
const device = this.accessory.context.device;
const { TargetFanState } = this.platform.Characteristic;
const windStrength = value === TargetFanState.AUTO ? 8 : FanSpeed.HIGH; // 8 mean fan auto mode
return (_a = this.platform.ThinQ) === null || _a === void 0 ? void 0 : _a.deviceControl(device.id, {
dataKey: 'airState.windStrength',
dataValue: windStrength,
}).then(() => {
device.data.snapshot['airState.windStrength'] = windStrength;
this.updateAccessoryCharacteristic(device);
});
}
updateAccessoryCharacteristic(device) {
var _a, _b;
this.accessory.context.device = device;
const { Characteristic, Characteristic: { Active, CurrentHeaterCoolerState, }, } = this.platform;
this.service.updateCharacteristic(Characteristic.Active, this.Status.isPowerOn ? Active.ACTIVE : Active.INACTIVE);
if (this.Status.currentTemperature) {
this.service.updateCharacteristic(Characteristic.CurrentTemperature, this.Status.currentTemperature);
}
if (!this.Status.isPowerOn) {
this.service.updateCharacteristic(Characteristic.CurrentHeaterCoolerState, Characteristic.CurrentHeaterCoolerState.INACTIVE);
}
else if ([OpMode.COOL].includes(this.Status.opMode)) {
this.service.updateCharacteristic(Characteristic.CurrentHeaterCoolerState, Characteristic.CurrentHeaterCoolerState.COOLING);
this.service.updateCharacteristic(Characteristic.TargetHeaterCoolerState, Characteristic.TargetHeaterCoolerState.COOL);
}
else if ([OpMode.HEAT].includes(this.Status.opMode)) {
this.service.updateCharacteristic(Characteristic.CurrentHeaterCoolerState, Characteristic.CurrentHeaterCoolerState.HEATING);
this.service.updateCharacteristic(Characteristic.TargetHeaterCoolerState, Characteristic.TargetHeaterCoolerState.HEAT);
}
else if ([OpMode.AUTO, -1].includes(this.Status.opMode)) {
// auto mode, detect based on current & target temperature
if (this.Status.currentTemperature < this.Status.targetTemperature) {
this.service.updateCharacteristic(Characteristic.CurrentHeaterCoolerState, Characteristic.CurrentHeaterCoolerState.HEATING);
this.service.updateCharacteristic(Characteristic.TargetHeaterCoolerState, Characteristic.TargetHeaterCoolerState.HEAT);
}
else {
this.service.updateCharacteristic(Characteristic.CurrentHeaterCoolerState, Characteristic.CurrentHeaterCoolerState.COOLING);
this.service.updateCharacteristic(Characteristic.TargetHeaterCoolerState, Characteristic.TargetHeaterCoolerState.COOL);
}
}
else {
// another mode
}
if (this.Status.targetTemperature) {
if (this.service.getCharacteristic(CurrentHeaterCoolerState).value === CurrentHeaterCoolerState.HEATING) {
this.service.updateCharacteristic(Characteristic.HeatingThresholdTemperature, this.Status.targetTemperature);
}
if (this.service.getCharacteristic(CurrentHeaterCoolerState).value === CurrentHeaterCoolerState.COOLING) {
this.service.updateCharacteristic(Characteristic.CoolingThresholdTemperature, this.Status.targetTemperature);
}
}
this.service.updateCharacteristic(Characteristic.RotationSpeed, this.Status.windStrength);
// eslint-disable-next-line max-len
this.service.updateCharacteristic(Characteristic.SwingMode, this.Status.isSwingOn ? Characteristic.SwingMode.SWING_ENABLED : Characteristic.SwingMode.SWING_DISABLED);
this.service.updateCharacteristic(this.platform.customCharacteristics.TotalConsumption, this.Status.currentConsumption);
// air quality
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.ac_air_quality) && this.serviceAirQuality && this.Status.airQuality && this.Status.airQuality.isOn) {
this.serviceAirQuality.updateCharacteristic(Characteristic.AirQuality, this.Status.airQuality.overall);
if (this.Status.airQuality.PM2) {
this.serviceAirQuality.updateCharacteristic(Characteristic.PM2_5Density, this.Status.airQuality.PM2);
}
if (this.Status.airQuality.PM10) {
this.serviceAirQuality.updateCharacteristic(Characteristic.PM10Density, this.Status.airQuality.PM10);
}
}
// temperature sensor
if (this.config.ac_temperature_sensor && this.serviceSensor) {
this.serviceSensor.updateCharacteristic(Characteristic.CurrentTemperature, this.Status.currentTemperature);
this.serviceSensor.updateCharacteristic(Characteristic.StatusActive, this.Status.isPowerOn);
}
// humidity sensor
if (this.config.ac_humidity_sensor && this.serviceHumiditySensor) {
this.serviceHumiditySensor.updateCharacteristic(Characteristic.CurrentRelativeHumidity, this.Status.currentRelativeHumidity);
this.serviceHumiditySensor.updateCharacteristic(Characteristic.StatusActive, this.Status.isPowerOn);
}
// handle fan service
if (((_b = this.config) === null || _b === void 0 ? void 0 : _b.ac_fan_control) && this.serviceFanV2) {
this.serviceFanV2.updateCharacteristic(Characteristic.Active, this.Status.isPowerOn ? Active.ACTIVE : Active.INACTIVE);
this.serviceFanV2.updateCharacteristic(Characteristic.RotationSpeed, this.Status.windStrength);
// eslint-disable-next-line max-len
this.serviceFanV2.updateCharacteristic(Characteristic.SwingMode, this.Status.isSwingOn ? Characteristic.SwingMode.SWING_ENABLED : Characteristic.SwingMode.SWING_DISABLED);
}
if (this.config.ac_led_control && this.serviceLight) {
this.serviceLight.updateCharacteristic(Characteristic.On, this.Status.isLightOn);
}
// more feature
if (this.isJetModeEnabled(device) && this.serviceJetMode) {
this.serviceJetMode.updateCharacteristic(Characteristic.On, !!device.snapshot['airState.wMode.jet']);
}
if (this.quietModeModels.includes(device.model) && this.serviceQuietMode) {
this.serviceQuietMode.updateCharacteristic(Characteristic.On, !!device.snapshot['airState.miscFuncState.silentAWHP']);
}
if (this.energySaveModeModels.includes(device.model) && this.config.ac_energy_save) {
this.serviceEnergySaveMode.updateCharacteristic(Characteristic.On, !!device.snapshot['airState.powerSave.basic']);
}
if (this.airCleanModels.includes(device.model) && this.config.ac_air_clean) {
this.serviceAirClean.updateCharacteristic(Characteristic.On, !!device.snapshot['airState.wMode.airClean']);
}
}
async setLight(value) {
var _a;
if (!this.Status.isPowerOn) {
return;
}
const device = this.accessory.context.device;
(_a = this.platform.ThinQ) === null || _a === void 0 ? void 0 : _a.deviceControl(device.id, {
dataKey: 'airState.lightingState.displayControl',
dataValue: value ? 1 : 0,
}).then(() => {
device.data.snapshot['airState.lightingState.displayControl'] = value ? 1 : 0;
this.updateAccessoryCharacteristic(device);
});
}
async setTargetState(value) {
this.platform.log.debug('Set target AC mode = ', value);
this.currentTargetState = value;
const { Characteristic: { TargetHeaterCoolerState, }, } = this.platform;
// Map HomeKit states to LG opModes
let opMode;
switch (value) {
case TargetHeaterCoolerState.AUTO:
opMode = OpMode.AUTO; // LG’s AUTO mode = 6
break;
case TargetHeaterCoolerState.HEAT:
opMode = OpMode.HEAT; // LG’s HEAT mode = 4
break;
case TargetHeaterCoolerState.COOL:
opMode = OpMode.COOL; // LG’s COOL mode = 0
break;
default:
opMode = this.Status.opMode; // Keep current mode
}
if (opMode !== this.Status.opMode) {
await this.setOpMode(opMode);
}
}
async setActive(value) {
var _a;
const device = this.accessory.context.device;
const isOn = value ? 1 : 0;
this.platform.log.debug('Set power on = ', isOn, ' - current status = ', this.Status.isPowerOn);
if (this.Status.isPowerOn && isOn) {
return; // don't send same status
}
(_a = this.platform.ThinQ) === null || _a === void 0 ? void 0 : _a.deviceControl(device.id, {
dataKey: 'airState.operation',
dataValue: isOn,
}, 'Operation').then(success => {
if (success) {
device.data.snapshot['airState.operation'] = isOn;
}
this.updateAccessoryCharacteristic(device);
});
}
async setTargetTemperature(value) {
var _a;
if (!this.Status.isPowerOn) {
return;
}
const device = this.accessory.context.device;
const temperature = this.Status.convertTemperatureCelsiusFromHomekitToLG(value);
if (temperature === this.Status.targetTemperature) {
return;
}
(_a = this.platform.ThinQ) === null || _a === void 0 ? void 0 : _a.deviceControl(device.id, {
dataKey: 'airState.tempState.target',
dataValue: temperature,
}).then(() => {
device.data.snapshot['airState.tempState.target'] = temperature;
this.updateAccessoryCharacteristic(device);
});
}
async setFanSpeed(value) {
var _a;
if (!this.Status.isPowerOn) {
return;
}
const speedValue = Math.max(1, Math.round(value));
this.platform.log.info('Set fan speed = ', speedValue);
const device = this.accessory.context.device;
const windStrength = parseInt(Object.keys(FanSpeed)[speedValue - 1]) || FanSpeed.HIGH;
(_a = this.platform.ThinQ) === null || _a === void 0 ? void 0 : _a.deviceControl(device.id, {
dataKey: 'airState.windStrength',
dataValue: windStrength,
});
}
async setSwingMode(value) {
var _a, _b, _c;
if (!this.Status.isPowerOn) {
return;
}
const swingValue = !!value ? '100' : '0';
const device = this.accessory.context.device;
if (this.config.ac_swing_mode === 'BOTH') {
(_a = this.platform.ThinQ) === null || _a === void 0 ? void 0 : _a.deviceControl(device.id, {
dataKey: null,
dataValue: null,
dataSetList: {
'airState.wDir.vStep': swingValue,
'airState.wDir.hStep': swingValue,
},
dataGetList: null,
}, 'Set', 'favoriteCtrl').then(() => {
device.data.snapshot['airState.wDir.vStep'] = swingValue;
device.data.snapshot['airState.wDir.hStep'] = swingValue;
this.updateAccessoryCharacteristic(device);
});
}
else if (this.config.ac_swing_mode === 'VERTICAL') {
(_b = this.platform.ThinQ) === null || _b === void 0 ? void 0 : _b.deviceControl(device.id, {
dataKey: 'airState.wDir.vStep',
dataValue: swingValue,
}).then(() => {
device.data.snapshot['airState.wDir.vStep'] = swingValue;
this.updateAccessoryCharacteristic(device);
});
}
else if (this.config.ac_swing_mode === 'HORIZONTAL') {
(_c = this.platform.ThinQ) === null || _c === void 0 ? void 0 : _c.deviceControl(device.id, {
dataKey: 'airState.wDir.hStep',
dataValue: swingValue,
}).then(() => {
device.data.snapshot['airState.wDir.hStep'] = swingValue;
this.updateAccessoryCharacteristic(device);
});
}
}
async setOpMode(opMode) {
var _a;
const device = this.accessory.context.device;
(_a = this.platform.ThinQ) === null || _a === void 0 ? void 0 : _a.deviceControl(device.id, {
dataKey: 'airState.opMode',
dataValue: opMode,
});
}
isJetModeEnabled(device) {
return this.jetModeModels.includes(device.model); // cool mode only
}
createFanService() {
const { Service: { Fanv2, }, Characteristic, } = this.platform;
const device = this.accessory.context.device;
// fan controller
this.serviceFanV2 = this.accessory.getService(Fanv2) || this.accessory.addService(Fanv2);
this.serviceFanV2.addLinkedService(this.service);
this.serviceFanV2.getCharacteristic(Characteristic.Active)
.onGet(() => {
return this.Status.isPowerOn ? Characteristic.Active.ACTIVE : Characteristic.Active.INACTIVE;
})
.onSet((value) => {
const isOn = value;
if ((this.Status.isPowerOn && isOn) || (!this.Status.isPowerOn && !isOn)) {
return;
}
// do not allow change status via home app, revert to prev status in 0.1s
setTimeout(() => {
// eslint-disable-next-line max-len
this.serviceFanV2.updateCharacteristic(Characteristic.Active, this.Status.isPowerOn ? Characteristic.Active.ACTIVE : Characteristic.Active.INACTIVE);
this.serviceFanV2.updateCharacteristic(Characteristic.RotationSpeed, this.Status.windStrength);
}, 100);
})
.updateValue(Characteristic.Active.INACTIVE);
this.serviceFanV2.getCharacteristic(Characteristic.Name).updateValue(device.name + ' - Fan');
this.serviceFanV2.getCharacteristic(Characteristic.CurrentFanState)
.onGet(() => {
return this.Status.isPowerOn ? Characteristic.CurrentFanState.BLOWING_AIR : Characteristic.CurrentFanState.INACTIVE;
})
.setProps({
validValues: [Characteristic.CurrentFanState.INACTIVE, Characteristic.CurrentFanState.BLOWING_AIR],
})
.updateValue(Characteristic.CurrentFanState.INACTIVE);
this.serviceFanV2.getCharacteristic(Characteristic.TargetFanState)
.onSet(this.setFanState.bind(this));
this.serviceFanV2.getCharacteristic(Characteristic.RotationSpeed)
.setProps({
minValue: 0,
maxValue: Object.keys(FanSpeed).length / 2,
minStep: 0.1,
})
.updateValue(this.Status.windStrength)
.onSet(this.setFanSpeed.bind(this));
this.serviceFanV2.getCharacteristic(Characteristic.SwingMode)
.onSet(this.setSwingMode.bind(this))
.updateValue(this.Status.isSwingOn ? Characteristic.SwingMode.SWING_ENABLED : Characteristic.SwingMode.SWING_DISABLED);
}
createAirQualityService() {
const { Service: { AirQualitySensor, }, } = this.platform;
this.serviceAirQuality = this.accessory.getService(AirQualitySensor) || this.accessory.addService(AirQualitySensor);
}
createHeaterCoolerService() {
const { Service: { HeaterCooler, }, Characteristic, } = this.platform;
const device = this.accessory.context.device;
this.service = this.accessory.getService(HeaterCooler) || this.accessory.addService(HeaterCooler, device.name);
this.service.setCharacteristic(Characteristic.Name, device.name);
this.service.getCharacteristic(Characteristic.Active)
.updateValue(Characteristic.Active.INACTIVE)
.onSet(this.setActive.bind(this));
this.service.getCharacteristic(Characteristic.CurrentHeaterCoolerState)
.updateValue(Characteristic.CurrentHeaterCoolerState.INACTIVE);
if (this.config.ac_mode === 'BOTH') {
this.service.getCharacteristic(Characteristic.TargetHeaterCoolerState)
.setProps({
validValues: [
Characteristic.TargetHeaterCoolerState.AUTO,
Characteristic.TargetHeaterCoolerState.COOL,
Characteristic.TargetHeaterCoolerState.HEAT,
],
})
.updateValue(Characteristic.TargetHeaterCoolerState.COOL);
}
else if (this.config.ac_mode === 'COOLING') {
this.service.getCharacteristic(Characteristic.TargetHeaterCoolerState)
.setProps({
validValues: [
Characteristic.TargetHeaterCoolerState.COOL,
],
})
.updateValue(Characteristic.TargetHeaterCoolerState.COOL);
}
else if (this.config.ac_mode === 'HEATING') {
this.service.getCharacteristic(Characteristic.TargetHeaterCoolerState)
.setProps({
validValues: [
Characteristic.TargetHeaterCoolerState.HEAT,
],
})
.updateValue(Characteristic.TargetHeaterCoolerState.HEAT);
}
this.service.getCharacteristic(Characteristic.TargetHeaterCoolerState)
.onSet(this.setTargetState.bind(this));
if (this.Status.currentTemperature) {
this.service.updateCharacteristic(Characteristic.CurrentTemperature, this.Status.currentTemperature);
}
/**
* DHW 15 - 80: support.airState.tempState.waterTempHeatMin - support.airState.tempState.waterTempHeatMax
* heating 15 - 65:
* cooling 5 - 27: support.airState.tempState.waterTempCoolMin - support.airState.tempState.waterTempCoolMax
*/
const currentTemperatureValue = device.deviceModel.value('airState.tempState.current');
if (currentTemperatureValue) {
this.service.getCharacteristic(Characteristic.CurrentTemperature)
.setProps({
minValue: this.Status.convertTemperatureCelsiusFromLGToHomekit(currentTemperatureValue.min),
maxValue: this.Status.convertTemperatureCelsiusFromLGToHomekit(currentTemperatureValue.max),
minStep: 0.01,
});
}
let heatLowLimitKey, heatHighLimitKey, coolLowLimitKey, coolHighLimitKey;
if (this.Status.type === ACModelType.AWHP) {
heatLowLimitKey = 'support.airState.tempState.waterTempHeatMin';
heatHighLimitKey = 'support.airState.tempState.waterTempHeatMax';
coolLowLimitKey = 'support.airState.tempState.waterTempCoolMin';
coolHighLimitKey = 'support.airState.tempState.waterTempCoolMax';
}
else {
heatLowLimitKey = 'support.heatLowLimit';
heatHighLimitKey = 'support.heatHighLimit';
coolLowLimitKey = 'support.coolLowLimit';
coolHighLimitKey = 'support.coolHighLimit';
}
const targetTemperature = (minRange, maxRange) => {
let temperature = {
type: DeviceModel_1.ValueType.Range,
min: 0,
max: 0,
step: 0.01,
};
if (minRange && maxRange) {
const minRangeOptions = Object.values(minRange.options);
const maxRangeOptions = Object.values(maxRange.options);
if (minRangeOptions.length > 1) {
temperature.min = Math.min(...minRangeOptions.filter(v => v !== 0));
}
if (maxRangeOptions.length > 1) {
temperature.max = Math.max(...maxRangeOptions.filter(v => v !== 0));
}
}
if (!temperature || !temperature.min || !temperature.max) {
temperature = device.deviceModel.value('airState.tempState.limitMin');
}
if (!temperature || !temperature.min || !temperature.max) {
temperature = device.deviceModel.value('airState.tempState.target');
}
return temperature;
};
const tempHeatMinRange = device.deviceModel.value(heatLowLimitKey);
const tempHeatMaxRange = device.deviceModel.value(heatHighLimitKey);
const targetHeatTemperature = targetTemperature(tempHeatMinRange, tempHeatMaxRange);
if (targetHeatTemperature) {
this.service.getCharacteristic(Characteristic.HeatingThresholdTemperature)
.setProps({
minValue: this.Status.convertTemperatureCelsiusFromLGToHomekit(targetHeatTemperature.min),
maxValue: this.Status.convertTemperatureCelsiusFromLGToHomekit(targetHeatTemperature.max),
minStep: targetHeatTemperature.step || 0.01,
})
.updateValue(this.Status.convertTemperatureCelsiusFromLGToHomekit(targetHeatTemperature.min));
}
const tempCoolMinRange = device.deviceModel.value(coolLowLimitKey);
const tempCoolMaxRange = device.deviceModel.value(coolHighLimitKey);
const targetCoolTemperature = targetTemperature(tempCoolMinRange, tempCoolMaxRange);
if (targetCoolTemperature) {
this.service.getCharacteristic(Characteristic.CoolingThresholdTemperature)
.setProps({
minValue: this.Status.convertTemperatureCelsiusFromLGToHomekit(targetCoolTemperature.min),
maxValue: this.Status.convertTemperatureCelsiusFromLGToHomekit(targetCoolTemperature.max),
minStep: targetHeatTemperature.step || 0.01,
})
.updateValue(this.Status.convertTemperatureCelsiusFromLGToHomekit(targetCoolTemperature.min));
}
this.service.getCharacteristic(Characteristic.CoolingThresholdTemperature)
.onSet(this.setTargetTemperature.bind(this));
this.service.getCharacteristic(Characteristic.HeatingThresholdTemperature)
.onSet(this.setTargetTemperature.bind(this));
this.service.getCharacteristic(Characteristic.RotationSpeed)
.setProps({
minValue: 0,
maxValue: Object.keys(FanSpeed).length / 2,
minStep: 0.1,
})
.onSet(this.setFanSpeed.bind(this));
this.service.getCharacteristic(Characteristic.SwingMode)
.onSet(this.setSwingMode.bind(this));
}
setupButton(device) {
if (!this.config.ac_buttons.length) {
return;
}
this.serviceLabelButtons = this.accessory.getService('Buttons')
|| this.accessory.addService(this.platform.Service.ServiceLabel, 'Buttons', 'Buttons');
// remove all buttons before
for (let i = 0; i < this.serviceLabelButtons.linkedServices.length; i++) {
this.accessory.removeService(this.serviceLabelButtons.linkedServices[i]);
}
for (let i = 0; i < this.config.ac_buttons.length; i++) {
this.setupButtonOpmode(device, this.config.ac_buttons[i].name, parseInt(this.config.ac_buttons[i].op_mode));
}
}
setupButtonOpmode(device, name, opMode) {
const { Service: { Switch, }, Characteristic, } = this.platform;
const serviceButton = this.accessory.getService(name) || this.accessory.addService(Switch, name, name);
serviceButton.updateCharacteristic(this.platform.Characteristic.Name, name);
serviceButton.getCharacteristic(this.platform.Characteristic.On)
.onGet(() => {
return this.Status.opMode === opMode;
})
.onSet(async (value) => {
if (value) {
if (this.Status.opMode !== opMode) {
await this.setOpMode(opMode).then(() => {
device.data.snapshot['airState.opMode'] = opMode;
this.updateAccessoryCharacteristic(device);
});
}
}
else {
await this.setOpMode(OpMode.COOL).then(async () => {
device.data.snapshot['airState.opMode'] = OpMode.COOL;
this.updateAccessoryCharacteristic(device);
await this.setTargetState(this.currentTargetState);
});
}
});
serviceButton.addOptionalCharacteristic(Characteristic.ConfiguredName);
if (!serviceButton.getCharacteristic(Characteristic.ConfiguredName).value) {
serviceButton.updateCharacteristic(Characteristic.ConfiguredName, name);
}
this.serviceLabelButtons.addLinkedService(serviceButton);
}
}
exports.default = AirConditioner;
class ACStatus {
constructor(data, device, config) {
this.data = data;
this.device = device;
this.config = config;
}
/**
* detect fahrenheit unit device by country code
* list: us
*/
get isFahrenheitUnit() {
var _a, _b;
return ((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.ac_temperature_unit) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === 'f';
}
convertTemperatureCelsiusFromHomekitToLG(temperatureInCelsius) {
if (!this.isFahrenheitUnit) {
return temperatureInCelsius;
}
const temperatureInFahrenheit = Math.round((0, helper_1.cToF)(temperatureInCelsius)); // convert temperature to fahrenheit by normal algorithm
// lookup celsius value by fahrenheit value from table TempFahToCel
const temperature = this.device.deviceModel.lookupMonitorValue('TempFahToCel', temperatureInFahrenheit.toString());
if (temperature === undefined) {
return temperatureInCelsius;
}
return temperature;
}
/**
* algorithm conversion LG vs Homekit is different
* so we need to handle it before submit to homekit
*/
convertTemperatureCelsiusFromLGToHomekit(temperatureInCelsius) {
if (!this.isFahrenheitUnit) {
return temperatureInCelsius;
}
// lookup fahrenheit value by celsius value from table TempCelToFah
let temperatureInFahrenheit = parseInt(this.device.deviceModel.lookupMonitorValue('TempCelToFah', temperatureInCelsius));
if (isNaN(temperatureInFahrenheit)) {
// lookup again in table TempFahToCel
temperatureInFahrenheit = parseInt(this.device.deviceModel.lookupMonitorValue('TempFahToCel', temperatureInCelsius));
}
// if not found in both tables, return original value
if (isNaN(temperatureInFahrenheit)) {
return temperatureInCelsius;
}
// convert F to C, truncate number to 2 decimal places without rounding
// custom fToC function, original in helper.ts
const celsius = parseFloat(String((temperatureInFahrenheit - 32) * 5 / 9));
const withoutRounded = celsius.toString().match(/^-?\d+(?:\.\d{0,2})?/);
if (withoutRounded) {
return parseFloat(withoutRounded[0]);
}
return celsius.toFixed(2);
}
get opMode() {
return this.data['airState.opMode'];
}
get isPowerOn() {
return !!this.data['airState.operation'];
}
get currentRelativeHumidity() {
const humidity = parseInt(this.data['airState.humidity.current']);
if (humidity > 100) {
return humidity / 10;
}
return humidity;
}
get currentTemperature() {
return this.convertTemperatureCelsiusFromLGToHomekit(this.data['airState.tempState.current']);
}
get targetTemperature() {
return this.convertTemperatureCelsiusFromLGToHomekit(this.data['airState.tempState.target']);
}
get airQuality() {
// air quality not available
if (!('airState.quality.overall' in this.data) && !('airState.quality.PM2' in this.data) && !('airState.quality.PM10' in this.data)) {
return null;
}
return {
isOn: this.isPowerOn || this.data['airState.quality.sensorMon'],
overall: parseInt(this.data['airState.quality.overall']),
PM2: parseInt(this.data['airState.quality.PM2'] || '0'),
PM10: parseInt(this.data['airState.quality.PM10'] || '0'),
};
}
// fan service
get windStrength() {
const index = Object.keys(FanSpeed).indexOf(parseInt(this.data['airState.windStrength']).toString());
return index !== -1 ? index + 1 : Object.keys(FanSpeed).length / 2;
}
get isSwingOn() {
const vStep = Math.floor((this.data['airState.wDir.vStep'] || 0) / 100), hStep = Math.floor((this.data['airState.wDir.hStep'] || 0) / 100);
return !!(vStep + hStep);
}
get isLightOn() {
return !!this.data['airState.lightingState.displayControl'];
}
get currentConsumption() {
const consumption = parseInt(this.data['airState.energy.onCurrent']);
if (isNaN(consumption)) {
return 0;
}
return consumption / 100;
}
get type() {
return this.device.deviceModel.data.Info.modelType || ACModelType.RAC;
}
}
exports.ACStatus = ACStatus;
//# sourceMappingURL=AirConditioner.js.map