UNPKG

@homebridge-plugins/homebridge-smarthq

Version:

The SmartHQ plugin allows you to interact with SmartHQ Devices in HomeKit and with Siri.

159 lines 7.85 kB
import { Buffer } from 'node:buffer'; import axios from 'axios'; import { interval, skipWhile } from 'rxjs'; import { ERD_TYPES } from '../settings.js'; import { deviceBase } from './device.js'; export class SmartHQIceMaker extends deviceBase { platform; device; opalProductionLimit = Infinity; oimPowerSvcName = 'Opal Power'; oimProgressSvcName = 'Opal Progress'; oimNightlightSvcName = 'Opal Nightlight'; constructor(platform, accessory, device) { super(platform, accessory, device); this.platform = platform; this.device = device; if (this.platform.config.options?.OPL) { this.opalProductionLimit = this.platform.config.options.OPL; } this.debugLog(`Opal IceMaker Features: ${JSON.stringify(accessory.context.device.features)}`); const opalIceMakerPowerService = this.accessory.getService(this.oimPowerSvcName) ?? this.accessory.addService(this.platform.Service.Switch, this.oimPowerSvcName, 'opal-power'); opalIceMakerPowerService .getCharacteristic(this.platform.Characteristic.On) .onGet(() => this.readErd(ERD_TYPES.OIM_POWER).then(r => Number.parseInt(r) !== 0)) .onSet(value => this.writeErd(ERD_TYPES.OIM_POWER, value)); const lightbulb = this.accessory.getService(this.oimNightlightSvcName) || this.accessory.addService(this.platform.Service.Lightbulb, this.oimNightlightSvcName); lightbulb.getCharacteristic(this.platform.Characteristic.On) .onGet(async () => { const currentLevel = await this.readErd(ERD_TYPES.OIM_LIGHT_LEVEL); return currentLevel !== '00'; // If the level is not OFF (00), return true (ON) }) .onSet(async (value) => { let newState; const currentLevel = await this.readErd(ERD_TYPES.OIM_LIGHT_LEVEL); if (value) { // If turning the light ON, cycle through states if (currentLevel === '00') { newState = '02'; // LOW } else if (currentLevel === '02') { newState = '01'; // HIGH } } else { newState = '00'; // OFF } await this.writeErd(ERD_TYPES.OIM_LIGHT_LEVEL, newState); this.debugLog(`Light state changed to: ${newState}`); }); lightbulb.getCharacteristic(this.platform.Characteristic.Brightness) .setProps({ minValue: 0, // Minimum value for brightness (OFF) maxValue: 100, // Maximum value for brightness (HIGH) minStep: 50, // Step value (only allow OFF, LOW, and HIGH) }) .onGet(async () => { const currentLevel = await this.readErd(ERD_TYPES.OIM_LIGHT_LEVEL); // Map the light level to brightness values if (currentLevel === '02') { // HIGH return 50; // Dim Brightness } else if (currentLevel === '01') { // LOW return 100; // Full Brightness } else { return 0; // OFF } }) .onSet(async (value) => { let newState; if (value === 50) { newState = '02'; // LOW (for dim brightness) } else if (value === 100) { newState = '01'; // HIGH (for full brightness) } else { newState = '00'; // OFF } await this.writeErd(ERD_TYPES.OIM_LIGHT_LEVEL, newState); this.debugLog(`Light brightness changed to: ${newState}`); }); // Opal Progress service const opalProgressSvc = this.accessory.getService(this.oimProgressSvcName) || this.accessory.addService(this.platform.Service.Fanv2, this.oimProgressSvcName); opalProgressSvc.getCharacteristic(this.platform.Characteristic.Active) .setProps({ // Omit PAIRED_WRITE to prevent user from setting Active to False, is read only. perms: ["ev" /* Perms.EVENTS */, "pr" /* Perms.PAIRED_READ */], }); opalProgressSvc.getCharacteristic(this.platform.Characteristic.RotationSpeed) .setProps({ format: "int" /* Formats.INT */, unit: "percentage" /* Units.PERCENTAGE */, minStep: 1, minValue: 0, maxValue: 100, perms: ["ev" /* Perms.EVENTS */, "pr" /* Perms.PAIRED_READ */], }) .removeOnGet() .removeOnSet(); // Get default accessory information service const opalIceMakerMetadataService = this.accessory.getService(''); // Metadata for Device Form, Opal Production Limit opalIceMakerMetadataService ?.getCharacteristic(this.platform.Characteristic.ProductData) .onGet(() => 'l=Production_Limit&i=OPL&t=number&d=0&p=1-100,_0_to_unset'); // Start an update interval interval(this.deviceRefreshRate * 1000) .pipe(skipWhile(() => !this.accessory.services.find(svc => svc.displayName === this.oimProgressSvcName))) .subscribe(async () => { const currentProductionValue = await this.getProductionValue(); const oimPowerSvc = this.accessory.services.find(accSvc => accSvc.displayName === this.oimPowerSvcName); const oimProgressSvc = this.accessory.services.find(accSvc => accSvc.displayName === this.oimProgressSvcName); // Math.min: If opalProductionLimit is Infinity (default/unset value), set to 100. Otherwise use the opalProductionLimit that is less than 100 const progressBarProductionValue = Math.floor((100 / Math.min(this.opalProductionLimit, 100)) * currentProductionValue); oimProgressSvc?.updateCharacteristic(this.platform.Characteristic.RotationSpeed, Math.min(progressBarProductionValue, 100)); oimProgressSvc?.updateCharacteristic(this.platform.Characteristic.Active, currentProductionValue > 0 ? 1 : 0); // If opalProductLimit is Infinity (default/unset value), the machine will turn off by itself if (currentProductionValue > this.opalProductionLimit) { oimPowerSvc?.setCharacteristic(this.platform.Characteristic.On, false); } }); } async getProductionValue() { try { const erdVal = await this.readErd(ERD_TYPES.OIM_PRODUCTION); const hexToIntVal = Buffer.from(erdVal, 'hex').readUInt8(0); const productionValue = Math.min(hexToIntVal, 100); const completionistMsg = hexToIntVal > 100 ? `, Completion: ${hexToIntVal}` : ''; this.debugSuccessLog(`Progress Svc: Value: ${productionValue}, Limit: ${this.opalProductionLimit}${completionistMsg}`); return productionValue; } catch (error) { const typedErr = error; this.errorLog(`Failed to read production value: ${typedErr.message}`); // Default to 0 if there's an error return 0; } } async readErd(erd) { const d = await axios .get(`/appliance/${this.accessory.context.device.applianceId}/erd/${erd}`); return String(d.data.value); } async writeErd(erd, value) { 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: typeof value === 'boolean' ? (value ? '01' : '00') : value, }); return undefined; } } //# sourceMappingURL=icemaker.js.map