homebridge-eufy-security
Version:
Control Eufy Security from homebridge.
201 lines • 8.78 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseAccessory = void 0;
const eufy_security_client_1 = require("eufy-security-client");
const events_1 = require("events");
const utils_1 = require("../utils/utils");
/**
* Determine if the serviceType is an instance of Service.
*
* @param {WithUUID<typeof Service> | Service} serviceType - The service type to be checked.
* @returns {boolean} Returns true if the serviceType is an instance of Service, otherwise false.
*/
function isServiceInstance(serviceType) {
// eslint-disable-next-line
return typeof serviceType === 'object';
}
class BaseAccessory extends events_1.EventEmitter {
platform;
accessory;
device;
servicesInUse = [];
SN;
name;
log;
constructor(platform, accessory,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
device) {
super();
this.platform = platform;
this.accessory = accessory;
this.device = device;
this.device = device;
this.SN = this.device.getSerial();
this.name = this.device.getName();
this.log = utils_1.log.getSubLogger({
name: '',
prefix: [this.name],
});
this.registerCharacteristic({
serviceType: utils_1.SERV.AccessoryInformation,
characteristicType: utils_1.CHAR.Manufacturer,
getValue: () => 'Eufy',
});
this.registerCharacteristic({
serviceType: utils_1.SERV.AccessoryInformation,
characteristicType: utils_1.CHAR.Name,
getValue: () => this.name || 'Unknowm',
});
this.registerCharacteristic({
serviceType: utils_1.SERV.AccessoryInformation,
characteristicType: utils_1.CHAR.Model,
getValue: () => eufy_security_client_1.DeviceType[this.device.getDeviceType()] || 'Unknowm',
});
this.registerCharacteristic({
serviceType: utils_1.SERV.AccessoryInformation,
characteristicType: utils_1.CHAR.SerialNumber,
getValue: () => this.SN || 'Unknowm',
});
this.registerCharacteristic({
serviceType: utils_1.SERV.AccessoryInformation,
characteristicType: utils_1.CHAR.FirmwareRevision,
getValue: () => this.device.getSoftwareVersion() || 'Unknowm',
});
this.registerCharacteristic({
serviceType: utils_1.SERV.AccessoryInformation,
characteristicType: utils_1.CHAR.HardwareRevision,
getValue: () => this.device.getHardwareVersion() || 'Unknowm',
});
if (this.platform.config.enableDetailedLogging) {
this.device.on('raw property changed', this.handleRawPropertyChange.bind(this));
this.device.on('property changed', this.handlePropertyChange.bind(this));
}
this.logPropertyKeys();
}
// Function to extract and log keys
logPropertyKeys() {
this.log.debug(`Property Keys:`, this.device.getProperties());
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
handleRawPropertyChange(device, type, value) {
this.log.debug(`Raw Property Changes:`, type, value);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
handlePropertyChange(device, name, value) {
this.log.debug(`Property Changes:`, name, value);
}
/**
* Register characteristics for a given Homebridge service.
*
* This method handles the registration of Homebridge characteristics.
* It includes optional features like value debouncing and event triggers.
*
* @param {Object} params - Parameters needed for registering characteristics.
*/
registerCharacteristic({ characteristicType, serviceType, getValue, setValue, onValue, onSimpleValue, onMultipleValue, name, serviceSubType, setValueDebounceTime = 0, }) {
this.log.debug(`REGISTER CHARACTERISTIC ${serviceType.name} / ${characteristicType.name} / ${name}`);
const service = this.getService(serviceType, name, serviceSubType);
const characteristic = service.getCharacteristic(characteristicType);
this.log.debug(`REGISTER CHARACTERISTIC (${service.UUID}) / (${characteristic.UUID})`);
if (getValue) {
characteristic.onGet(async (data) => {
const value = getValue(data, characteristic, service);
this.log.debug(`GET '${serviceType.name} / ${characteristicType.name}':`, value);
return value;
});
}
if (setValue && setValueDebounceTime) {
let timeoutId = null;
characteristic.onSet(async (value) => {
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
timeoutId = null;
setValue(value, characteristic, service);
}, setValueDebounceTime);
});
}
else if (setValue) {
characteristic.onSet(async (value) => {
Promise.resolve(setValue(value, characteristic, service));
});
}
if (onSimpleValue) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.device.on(onSimpleValue, (device, value) => {
this.log.info(`ON '${serviceType.name} / ${characteristicType.name} / ${onSimpleValue}':`, value);
characteristic.updateValue(value);
});
}
if (onValue) {
this.log.debug(`ON '${serviceType.name} / ${characteristicType.name}'`);
onValue(service, characteristic);
}
if (onMultipleValue) {
// Attach the common event handler to each event type
onMultipleValue.forEach(eventType => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.device.on(eventType, (device, value) => {
this.log.info(`ON '${serviceType.name} / ${characteristicType.name} / ${eventType}':`, value);
characteristic.updateValue(value);
});
});
}
}
/**
* Retrieve an existing service or create a new one if it doesn't exist.
*
* @param {ServiceType} serviceType - The type of service to retrieve or create.
* @param {string} [name] - The name of the service (optional).
* @param {string} [subType] - The subtype of the service (optional).
* @returns {Service} Returns the existing or newly created service.
* @throws Will throw an error if there are overlapping services.
*/
getService(serviceType, name = this.name, subType) {
if (isServiceInstance(serviceType)) {
return serviceType;
}
const existingService = subType ? this.accessory.getServiceById(serviceType, subType) : this.accessory.getService(serviceType);
const service = existingService ||
this.accessory.addService(serviceType, name, subType);
if (existingService &&
existingService.displayName &&
name !== existingService.displayName) {
throw new Error(`Overlapping services for device ${this.name} - ${name} != ${existingService.displayName} - ${serviceType}`);
}
if (!this.servicesInUse.includes(service)) {
this.servicesInUse.push(service);
}
return service;
}
pruneUnusedServices() {
const safeServiceUUIDs = [
utils_1.SERV.CameraRTPStreamManagement.UUID,
];
this.accessory.services.forEach((service) => {
if (!this.servicesInUse.includes(service) &&
!safeServiceUUIDs.includes(service.UUID)) {
this.log.debug(`Pruning unused service ${service.UUID} ${service.displayName || service.name}`);
this.accessory.removeService(service);
}
});
}
handleDummyEventGet(serviceName) {
const characteristicValues = {
'EventSnapshotsActive': utils_1.CHAR.EventSnapshotsActive.DISABLE,
'HomeKitCameraActive': utils_1.CHAR.HomeKitCameraActive.OFF,
};
const currentValue = characteristicValues[serviceName];
if (currentValue === undefined) {
throw new Error(`Invalid serviceName: ${serviceName}`);
}
this.log.debug(`IGNORE GET ${serviceName}: ${currentValue}`);
return Promise.resolve(currentValue);
}
handleDummyEventSet(serviceName, value) {
this.log.debug(`IGNORE SET ${serviceName}: ${value}`);
}
}
exports.BaseAccessory = BaseAccessory;
//# sourceMappingURL=BaseAccessory.js.map