homebridge-econet-rheem
Version:
Homebridge plugin for control of Rheem and Ruud thermostats and water heaters
265 lines • 11.2 kB
JavaScript
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