UNPKG

homebridge-econet-rheem

Version:

Homebridge plugin for control of Rheem and Ruud thermostats and water heaters

265 lines 11.2 kB
import { CustomCharacteristic, isCustomCharacteristic } from '../characteristic/custom.js'; import { EveCharacteristic, isEveCharacteristic } from '../characteristic/eve.js'; import { strings } from '../../i18n/i18n.js'; import { AuthType } from '../../model/auth.js'; import { HKCharacteristicKey, MQTTKey } from '../../model/enums.js'; import { MQTT } from '../../model/mqtt.js'; import { debounce } from '../../tools/debounce.js'; import { LogType } from '../../tools/log.js'; import { Properties } from '../../tools/properties.js'; import getVersion from '../../tools/version.js'; export class BaseAccessory { dependency; data; name; mqttClient; accessoryService; updateHandlers = new Map(); constructor(dependency, data) { this.dependency = dependency; this.data = data; this.name = this.getValue(data['@NAME']) ?? data.device_type; this.platformAccessory.getService(dependency.Service.AccessoryInformation) .setCharacteristic(dependency.Characteristic.Name, this.name) .setCharacteristic(dependency.Characteristic.ConfiguredName, this.name) .setCharacteristic(dependency.Characteristic.Manufacturer, strings.general.brand) .setCharacteristic(dependency.Characteristic.Model, data.device_type) .setCharacteristic(dependency.Characteristic.SerialNumber, data.serial_number) .setCharacteristic(dependency.Characteristic.FirmwareRevision, getVersion()); const mqttDependency = { log: dependency.log, parentName: this.name, email: dependency.email, auth: dependency.auth, serialNumber: data.serial_number, macAddress: data.mac_address, debug: dependency.debug, }; this.mqttClient = MQTT.connect(mqttDependency, this); const serviceInstance = dependency.Service[this.getAccessoryType()]; this.accessoryService = dependency.platformAccessory.getService(serviceInstance) || dependency.platformAccessory.addService(serviceInstance); } get Characteristic() { return this.dependency.Characteristic; } get platformAccessory() { return this.dependency.platformAccessory; } get log() { return this.dependency.log; } get service() { return this.accessoryService; } get identifier() { return this.data.serial_number; } get isDeviceAuth() { return this.dependency.auth.type === AuthType.DEVICE; } getMQTTKey(mqttKeys) { if (this.isDeviceAuth) { return mqttKeys.device; } return mqttKeys.user; } mqttMessageReceived(message) { if (!this.isDeviceAuth && message.serial_number !== this.identifier) { return; } for (const key of Object.keys(message)) { const value = this.getValue(message[key]); this.updateHandlers.get(key)?.forEach(handler => { handler(value); }); } } publish(mqttKey, value) { const payload = {}; payload[mqttKey] = value; this.publishPayload(payload); } publishPayload(payload) { if (!this.isDeviceAuth) { payload.serial_number = this.data.serial_number; payload.device_name = this.data.device_name; } this.mqttClient?.publish(payload); } teardown() { this.mqttClient?.teardown(); } setCharacteristicValue(key, value) { return this.accessoryService.getCharacteristic(this.Characteristic[key]).onGet(() => { return value; })?.setValue(value); } getProperty(key) { return Properties.get(this.identifier, key); } setProperty(key, value) { Properties.set(this.identifier, key, value); } getValue(input) { return typeof input === 'object' && input !== null && 'value' in input ? input.value : input; } setUpdateHandler(mqttKeys, onUpdateHandler) { const mqttKey = this.getMQTTKey(mqttKeys); const handlers = this.updateHandlers.get(mqttKey) ?? []; handlers.push(onUpdateHandler); this.updateHandlers.set(mqttKey, handlers); } setup(characteristicKey, startingValue, mqttKeys, onUpdateHandler, onSetHandler) { const mqttKey = this.getMQTTKey(mqttKeys); if (mqttKey === MQTTKey.UNDEFINED || mqttKey === MQTTKey.UNKNOWN) { if (this.service.testCharacteristic(this.characteristicFromKey(characteristicKey))) { const characteristic = this.service.getCharacteristic(this.characteristicFromKey(characteristicKey)); this.service.removeCharacteristic(characteristic); } return; } const characteristic = this.setupGet(characteristicKey, startingValue, mqttKey, onUpdateHandler); if (onSetHandler !== undefined) { this.setupSet(characteristicKey, onSetHandler); } return characteristic; } setupGet(characteristicKey, startingValue, mqttKey, onUpdateHandler) { if (this.isOptionalCharacteristic(characteristicKey) && !this.service.testCharacteristic(this.characteristicFromKey(characteristicKey))) { this.service.addOptionalCharacteristic(this.characteristicFromKey(characteristicKey)); } const characteristic = this.service.getCharacteristic(this.characteristicFromKey(characteristicKey)); characteristic.setValue(startingValue); this.setProperty(characteristicKey, startingValue); characteristic.onGet(async () => { return this.getProperty(characteristicKey) ?? null; }); const handlers = this.updateHandlers.get(mqttKey) ?? []; handlers.push(onUpdateHandler); this.updateHandlers.set(mqttKey, handlers); return characteristic; } setupSet(characteristicKey, onSetHandler) { if (this.isOptionalCharacteristic(characteristicKey)) { this.service.addOptionalCharacteristic(this.characteristicFromKey(characteristicKey)); } const characteristic = this.service.getCharacteristic(this.characteristicFromKey(characteristicKey)); characteristic.onSet(onSetHandler); } bindOnUpdateNumericBoolean(charKey, logTrue, logFalse) { return (async (value) => { if (typeof value !== 'number') { this.log.error(strings.accessory.badValue, this.name, 'number', charKey, `${value.toString()}`); return; } this.onUpdate(charKey, value, value === 1 ? logTrue : logFalse); }).bind(this); } bindOnUpdateNumeric(charKey, logTemplate, callback) { return (async (value) => { if (typeof value !== 'number') { this.log.error(strings.accessory.badValue, this.name, 'number', charKey, `'${value.toString()}'`); return; } const characteristic = this.service.getCharacteristic(this.characteristicFromKey(charKey)); const minValue = characteristic.props.minValue; const maxValue = characteristic.props.maxValue; if (minValue !== undefined && value < minValue) { this.logIfDesired(LogType.WARNING, strings.accessory.outOfRange, charKey, `'${value.toString()}'`, `'${minValue.toString()}'`); value = minValue; } else if (maxValue !== undefined && value > maxValue) { this.logIfDesired(LogType.WARNING, strings.accessory.outOfRange, charKey, `'${value.toString()}'`, `'${maxValue.toString()}'`); value = maxValue; } const logString = logTemplate.replace('%d', value.toString()); this.onUpdate(charKey, value, logString); callback?.(value); }).bind(this); } bindOnSetNumericBoolean(charKey, mqttKeys, logTrue, logFalse, debounce = false) { return (async (value) => { const logTemplate = value === 1 ? logTrue : logFalse; this.onSetNumeric(charKey, mqttKeys, value, value, logTemplate, debounce); }).bind(this); } bindOnSetNumeric(charKey, mqttKeys, logTemplate, debounce = false) { return (async (value) => { this.onSetNumeric(charKey, mqttKeys, value, value, logTemplate, debounce); }).bind(this); } onUpdate(key, value, logString = undefined) { if (value === this.getProperty(key)) { return false; } this.setProperty(key, value); this.service.updateCharacteristic(this.characteristicFromKey(key), value); if (logString) { this.logIfDesired(logString); } return true; } onSet(charKey, mqttKeys, value, publish, logString) { if (logString && value !== this.getProperty(charKey)) { this.logIfDesired(logString); } this.setProperty(charKey, value); this.service.updateCharacteristic(this.characteristicFromKey(charKey), value); const mqttKey = this.getMQTTKey(mqttKeys); this.publish(mqttKey, publish); } onSetNumeric(charKey, mqttKeys, value, publish, logTemplate, doDebounce) { if (typeof value !== 'number') { this.log.error(strings.accessory.badValue, this.name, 'number', charKey, `'${value}'`); return; } const task = () => { const logString = logTemplate.replace('%d', publish.toString()); this.onSet(charKey, mqttKeys, value, publish, logString); }; if (doDebounce) { debounce(`${this.identifier}_${charKey}`, task); } else { task(); } } // eslint-disable-next-line @typescript-eslint/no-explicit-any characteristicFromKey(key) { if (isCustomCharacteristic(key)) { return CustomCharacteristic(key, this.Characteristic); } if (isEveCharacteristic(key)) { return EveCharacteristic(key); } return this.Characteristic[key]; } isOptionalCharacteristic(key) { return key === HKCharacteristicKey.StatusFault || isCustomCharacteristic(key) || isEveCharacteristic(key); } recordHistory(type, entry, updateLastActivation = false) { this.dependency.history.record(this, type, entry, updateLastActivation); } logIfDesired(levelOrMessage, ...rest) { if (this.dependency.disableLogging && !this.dependency.debug) { return; } if (typeof levelOrMessage === 'string') { this.log.always(levelOrMessage, this.name, ...rest); return; } const [message, ...parameters] = rest; switch (levelOrMessage) { case LogType.WARNING: this.log.warning(message, this.name, ...parameters); break; case LogType.ERROR: this.log.error(message, this.name, ...parameters); break; default: this.log.always(message, this.name, ...parameters); break; } } } //# sourceMappingURL=base.js.map