UNPKG

@elshaer/homebridge-lg-thinq

Version:

A Homebridge plugin for controlling/monitoring LG ThinQ device via LG ThinQ platform.

800 lines 39.7 kB
"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