UNPKG

@shadman-a/homebridge-my-ac

Version:

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

331 lines 16.4 kB
import { BaseDevice } from '../baseDevice.js'; import { cToF, fToC } from '../helper.js'; export default class Refrigerator extends BaseDevice { platform; accessory; serviceFreezer; serviceFridge; serviceDoorOpened; serviceExpressMode; serviceExpressFridge; serviceEcoFriendly; serviceWaterFilter; constructor(platform, accessory, logger) { super(platform, accessory, logger); this.platform = platform; this.accessory = accessory; const { Service: { ContactSensor, Switch, ServiceLabel, FilterMaintenance, }, Characteristic, } = this.platform; const device = accessory.context.device; const serviceLabel = accessory.getService(ServiceLabel); if (serviceLabel) { accessory.removeService(serviceLabel); } this.serviceFridge = this.createThermostat('Fridge', 'fridgeTemp'); if (this.serviceFridge) { this.serviceFridge.updateCharacteristic(Characteristic.TargetTemperature, this.Status.fridgeTemperature); } this.serviceFreezer = this.createThermostat('Freezer', 'freezerTemp'); if (this.serviceFreezer) { this.serviceFreezer.updateCharacteristic(Characteristic.TargetTemperature, this.Status.freezerTemperature); } // Door open state this.serviceDoorOpened = accessory.getService(ContactSensor); if (!this.serviceDoorOpened) { this.serviceDoorOpened = accessory.addService(ContactSensor, 'Refrigerator Door Closed'); this.serviceDoorOpened.addOptionalCharacteristic(Characteristic.ConfiguredName); this.serviceDoorOpened.updateCharacteristic(Characteristic.ConfiguredName, 'Refrigerator Door Closed'); } this.serviceExpressMode = accessory.getService('Express Freezer'); if (this.config.ref_express_freezer && device.snapshot && 'expressMode' in device.snapshot.refState) { if (!this.serviceExpressMode) { this.serviceExpressMode = accessory.addService(Switch, 'Express Freezer', 'Express Freezer'); this.serviceExpressMode.addOptionalCharacteristic(Characteristic.ConfiguredName); this.serviceExpressMode.updateCharacteristic(Characteristic.ConfiguredName, 'Express Freezer'); } this.serviceExpressMode.getCharacteristic(Characteristic.On).onSet(this.setExpressMode.bind(this)); } else if (this.serviceExpressMode) { accessory.removeService(this.serviceExpressMode); this.serviceExpressMode = undefined; } this.serviceExpressFridge = accessory.getService('Express Fridge'); if (this.config.ref_express_fridge && device.snapshot && 'expressFridge' in device.snapshot.refState) { if (!this.serviceExpressFridge) { this.serviceExpressFridge = accessory.addService(Switch, 'Express Fridge', 'Express Fridge'); this.serviceExpressFridge.addOptionalCharacteristic(Characteristic.ConfiguredName); this.serviceExpressFridge.updateCharacteristic(Characteristic.ConfiguredName, 'Express Fridge'); } this.serviceExpressFridge.getCharacteristic(Characteristic.On).onSet(this.setExpressFridge.bind(this)); } else if (this.serviceExpressFridge) { accessory.removeService(this.serviceExpressFridge); this.serviceExpressFridge = undefined; } this.serviceEcoFriendly = accessory.getService('Eco Friendly'); if (this.config.ref_eco_friendly && device.snapshot && 'ecoFriendly' in device.snapshot.refState) { if (!this.serviceEcoFriendly) { this.serviceEcoFriendly = accessory.addService(Switch, 'Eco Friendly', 'Eco Friendly'); this.serviceEcoFriendly.addOptionalCharacteristic(Characteristic.ConfiguredName); this.serviceEcoFriendly.updateCharacteristic(Characteristic.ConfiguredName, 'Eco Friendly'); } this.serviceEcoFriendly.getCharacteristic(Characteristic.On).onSet(this.setEcoFriendly.bind(this)); } else if (this.serviceEcoFriendly) { accessory.removeService(this.serviceEcoFriendly); this.serviceEcoFriendly = undefined; } if (this.Status.hasFeature('waterFilter')) { this.serviceWaterFilter = accessory.getService('Water Filter Maintenance'); if (!this.serviceWaterFilter) { this.serviceWaterFilter = accessory.addService(FilterMaintenance, 'Water Filter Maintenance', 'Water Filter Maintenance'); this.serviceWaterFilter.addOptionalCharacteristic(Characteristic.ConfiguredName); this.serviceWaterFilter.updateCharacteristic(Characteristic.ConfiguredName, 'Water Filter Maintenance'); } this.serviceWaterFilter.updateCharacteristic(Characteristic.Name, 'Water Filter Maintenance'); } } get config() { return Object.assign({}, { ref_express_freezer: false, ref_express_fridge: false, ref_eco_friendly: false, }, super.config); } get Status() { return new RefrigeratorStatus(this.accessory.context.device.snapshot?.refState, this.accessory.context.device.deviceModel); } /** * update accessory characteristic by device */ updateAccessoryCharacteristic(device) { super.updateAccessoryCharacteristic(device); const { Characteristic, Characteristic: { FilterLifeLevel, FilterChangeIndication, }, } = this.platform; const tempBetween = (props, value) => { return Math.min(Math.max(props.minValue, value), props.maxValue); }; if (this.serviceFreezer) { const t = tempBetween(this.serviceFreezer.getCharacteristic(Characteristic.TargetTemperature).props, this.Status.freezerTemperature); this.serviceFreezer.updateCharacteristic(Characteristic.CurrentTemperature, t); this.serviceFreezer.updateCharacteristic(Characteristic.TargetTemperature, t); } if (this.serviceFridge) { const t = tempBetween(this.serviceFridge.getCharacteristic(Characteristic.TargetTemperature).props, this.Status.fridgeTemperature); this.serviceFridge.updateCharacteristic(Characteristic.CurrentTemperature, t); this.serviceFridge.updateCharacteristic(Characteristic.TargetTemperature, t); } if (this.serviceDoorOpened) { const contactSensorValue = this.Status.isDoorClosed ? Characteristic.ContactSensorState.CONTACT_DETECTED : Characteristic.ContactSensorState.CONTACT_NOT_DETECTED; this.serviceDoorOpened.updateCharacteristic(Characteristic.ContactSensorState, contactSensorValue); } if (device.snapshot) { if (this.config.ref_express_freezer && 'expressMode' in device.snapshot.refState && this.serviceExpressMode) { this.serviceExpressMode.updateCharacteristic(Characteristic.On, this.Status.isExpressModeOn); } if (this.config.ref_express_fridge && 'expressFridge' in device.snapshot.refState && this.serviceExpressFridge) { this.serviceExpressFridge.updateCharacteristic(Characteristic.On, this.Status.isExpressFridgeOn); } if (this.config.ref_eco_friendly && 'ecoFriendly' in device.snapshot.refState && this.serviceEcoFriendly) { this.serviceEcoFriendly.updateCharacteristic(Characteristic.On, this.Status.isEcoFriendlyOn); } } if (this.Status.hasFeature('waterFilter') && this.serviceWaterFilter) { this.serviceWaterFilter.updateCharacteristic(FilterLifeLevel, this.Status.waterFilterRemain); this.serviceWaterFilter.updateCharacteristic(FilterChangeIndication, this.Status.waterFilterRemain < 5 ? FilterChangeIndication.CHANGE_FILTER : FilterChangeIndication.FILTER_OK); } } async setExpressMode(value) { const device = this.accessory.context.device; const On = device.deviceModel.lookupMonitorName('expressMode', '@CP_ON_EN_W'); const Off = device.deviceModel.lookupMonitorName('expressMode', '@CP_OFF_EN_W'); this.platform.ThinQ?.deviceControl(device.id, { dataKey: null, dataValue: null, dataSetList: { refState: { expressMode: value ? On : Off, tempUnit: this.Status.tempUnit, }, }, dataGetList: null, }); this.platform.log.debug('Set Express Freezer ->', value); } async setExpressFridge(value) { const device = this.accessory.context.device; const On = device.deviceModel.lookupMonitorName('expressFridge', '@CP_ON_EN_W'); const Off = device.deviceModel.lookupMonitorName('expressFridge', '@CP_OFF_EN_W'); this.platform.ThinQ?.deviceControl(device.id, { dataKey: null, dataValue: null, dataSetList: { refState: { expressFridge: value ? On : Off, tempUnit: this.Status.tempUnit, }, }, dataGetList: null, }); this.platform.log.debug('Set Express Fridge ->', value); } async setEcoFriendly(value) { const device = this.accessory.context.device; const On = device.deviceModel.lookupMonitorName('ecoFriendly', '@CP_ON_EN_W'); const Off = device.deviceModel.lookupMonitorName('ecoFriendly', '@CP_OFF_EN_W'); this.platform.ThinQ?.deviceControl(device.id, { dataKey: null, dataValue: null, dataSetList: { refState: { ecoFriendly: value ? On : Off, tempUnit: this.Status.tempUnit, }, }, dataGetList: null, }); this.platform.log.debug('Set Eco Friendly ->', value); } async tempUnit() { const { Characteristic: { TemperatureDisplayUnits, }, } = this.platform; return this.Status.tempUnit === 'CELSIUS' ? TemperatureDisplayUnits.CELSIUS : TemperatureDisplayUnits.FAHRENHEIT; } /** * create a thermostat service */ createThermostat(name, key) { const device = this.accessory.context.device; if (!this.Status.hasFeature(key)) { return; } const { Characteristic } = this.platform; const isCelsius = this.Status.tempUnit === 'CELSIUS'; let service = this.accessory.getService(name); if (!service) { service = this.accessory.addService(this.platform.Service.Thermostat, name, name); service.addOptionalCharacteristic(Characteristic.ConfiguredName); service.updateCharacteristic(Characteristic.ConfiguredName, name); } // Restrict to Cool only service.updateCharacteristic(Characteristic.CurrentHeatingCoolingState, Characteristic.CurrentHeatingCoolingState.COOL) .getCharacteristic(Characteristic.CurrentHeatingCoolingState) .setProps({ validValues: [Characteristic.CurrentHeatingCoolingState.COOL], // Hide other states }); service.getCharacteristic(Characteristic.TargetHeatingCoolingState) .updateValue(Characteristic.TargetHeatingCoolingState.COOL) .setProps({ validValues: [Characteristic.TargetHeatingCoolingState.COOL], // Hide Heat/Auto/Off }); service.getCharacteristic(Characteristic.TemperatureDisplayUnits).setProps({ minValue: Characteristic.TemperatureDisplayUnits.CELSIUS, maxValue: Characteristic.TemperatureDisplayUnits.FAHRENHEIT, }).onGet(this.tempUnit.bind(this)); const valueMapping = device.deviceModel.monitoringValueMapping(key + '_C') || device.deviceModel.monitoringValueMapping(key); if (!valueMapping) { this.logger.error(`[Refrigerator] [${this.accessory.context.device.name}] No value mapping found for ${key}`); return service; } const values = Object.values(valueMapping) .map(value => { if (value && typeof value === 'object' && 'label' in value) { return parseInt(value.label); } return parseInt(value); }) .filter(value => { return !isNaN(value); }); service.getCharacteristic(Characteristic.TargetTemperature) .updateValue(Math.min(...values)) .onSet(async (value) => { let indexValue; if (this.Status.tempUnit === 'FAHRENHEIT') { indexValue = device.deviceModel.lookupMonitorName(key + '_F', cToF(value).toString()) || device.deviceModel.lookupMonitorName(key, cToF(value).toString()); } else { indexValue = device.deviceModel.lookupMonitorName(key + '_C', value.toString()) || device.deviceModel.lookupMonitorName(key, value.toString()); } if (!indexValue) { throw new this.platform.api.hap.HapStatusError(-70410 /* this.platform.api.hap.HAPStatus.INVALID_VALUE_IN_REQUEST */); } await this.setTemperature(key, indexValue); }) .setProps({ minValue: Math.min(...values), maxValue: Math.max(...values), minStep: isCelsius ? 1 : 0.1 }); return service; } async setTemperature(key, temp) { const device = this.accessory.context.device; await this.platform.ThinQ?.deviceControl(device.id, { dataKey: null, dataValue: null, dataSetList: { refState: { [key]: parseInt(temp), tempUnit: this.Status.tempUnit, }, }, dataGetList: null, }); } } export class RefrigeratorStatus { data; deviceModel; constructor(data, deviceModel) { this.data = data; this.deviceModel = deviceModel; } get freezerTemperature() { if (this.tempUnit === 'FAHRENHEIT') { return fToC(parseInt(`${this.deviceModel.lookupMonitorValue2('freezerTemp_F', this.data?.freezerTemp, '0')}`)); } return parseInt(`${this.deviceModel.lookupMonitorValue2('freezerTemp_C', this.data?.freezerTemp, '0')}`); } get fridgeTemperature() { if (this.tempUnit === 'FAHRENHEIT') { return fToC(parseInt(`${this.deviceModel.lookupMonitorValue2('fridgeTemp_F', this.data?.fridgeTemp, '0')}`)); } return parseInt(`${this.deviceModel.lookupMonitorValue2('fridgeTemp_C', this.data?.fridgeTemp, '0')}`); } get isDoorClosed() { return this.data?.atLeastOneDoorOpen === 'CLOSE'; } get isExpressModeOn() { return this.data?.expressMode === this.deviceModel.lookupMonitorName('expressMode', '@CP_ON_EN_W'); } get isExpressFridgeOn() { return this.data?.expressFridge === this.deviceModel.lookupMonitorName('expressFridge', '@CP_ON_EN_W'); } get isEcoFriendlyOn() { return this.data?.ecoFriendly === this.deviceModel.lookupMonitorName('ecoFriendly', '@CP_ON_EN_W'); } get tempUnit() { return this.data?.tempUnit || 'CELSIUS'; } get waterFilterRemain() { if ('waterFilter1RemainP' in this.data) { return this.data?.waterFilter1RemainP || 0; } if ('waterFilter' in this.data) { const usedInMonth = parseInt(this.data?.waterFilter.match(/(\d)_/)[1]); if (isNaN(usedInMonth)) { return 0; } return (12 - usedInMonth) / 12 * 100; } return this.data?.waterFilter1RemainP || 0; } hasFeature(key) { const visibleItem = this.deviceModel.data.Config?.visibleItems?.find((item) => item.Feature === key || item.feature === key); if (!visibleItem) { return false; } else if (visibleItem.ControlTitle === undefined && visibleItem.controlTitle === undefined) { return false; } return true; } } //# sourceMappingURL=Refrigerator.js.map