homebridge-framework
Version:
Framework for easy creation of homebridge plugins.
214 lines (183 loc) • 7.71 kB
text/typescript
import { PlatformAccessory } from 'homebridge';
import { HomebridgePlatform } from './homebridge-platform';
import { Service } from './service';
import { Categories as Category, Service as HapService } from 'hap-nodejs';
import { AccessoryInformation } from './accessory-information';
/**
* Represents a wrapper around HAP accessories with with support for auto-removal of unused services.
*/
export class Accessory {
/**
* Initializes a new Accessory instance.
* @param platform The homebridge platform.
* @param name The name that should be displayed in HomeKit.
* @param id The identifier of the accessory.
* @param subType The sub type of the accessory. May be omitted if the ID is already unique.
* @param category The category of the accessory, which determines the icon in the Apple Home app.
* @param isExternal Determines whether the accessory is an external accessory (in contrast to bridged accessories).
*/
constructor(platform: HomebridgePlatform<any>, name: string, id: string, subType?: string, category?: Category, isExternal?: boolean) {
this._platform = platform;
this._name = name;
this._id = id;
this._subType = subType || null;
this._isExternal = isExternal || false;
// Checks if the accessory has been cached
if (!this.isExternal) {
const platformAccessory = this.platform.cachedPlatformAccessories.find(a => a.context.id === id && a.context.subType === (subType || null));
if (platformAccessory) {
this._platformAccessory = platformAccessory;
return;
}
}
// Creates the new accessory
this._platformAccessory = new this.platform.api.platformAccessory(name, this.platform.api.hap.uuid.generate(this.uniqueId), category) as PlatformAccessory;
this.platformAccessory.context.id = id;
this.platformAccessory.context.subType = (subType || null);
// Registers the accessory
if (!this.isExternal) {
this.platform.api.registerPlatformAccessories(this.platform.pluginName, this.platform.platformName, [this.platformAccessory]);
}
}
/**
* Contains the parent platform.
*/
private _platform: HomebridgePlatform<any>;
/**
* Gets the parent platform.
* @internal
*/
public get platform(): HomebridgePlatform<any> {
return this._platform;
}
/**
* Contains the platform accessory.
*/
private _platformAccessory: PlatformAccessory;
/**
* Gets the platform accessory.
* @internal
*/
public get platformAccessory(): PlatformAccessory {
return this._platformAccessory;
}
/**
* Contains the name that should be displayed in HomeKit.
*/
private _name: string;
/**
* Gets the name that should be displayed in HomeKit.
*/
public get name(): string {
return this._name;
}
/**
* Contains the identifier of the accessory. Is unique in combination with the sub type.
*/
private _id: string;
/**
* Gets the identifier of the accessory. Is unique in combination with the sub type.
*/
public get id(): string {
return this._id;
}
/**
* Contains the sub type of the accessory. Is unique in combination with the ID.
*/
private _subType: string|null;
/**
* Gets the sub type of the accessory. Is unique in combination with the ID.
*/
public get subType(): string|null {
return this._subType;
}
/**
* Contains a value that determines whether the accessory is an external accessory (in contrast to bridged accessories).
*/
private _isExternal: boolean = false;
/**
* Gets a value that determines whether the accessory is an external accessory (in contrast to bridged accessories).
*/
public get isExternal(): boolean {
return this._isExternal;
}
/**
* Gets the unique identifier of the accessory, which is made up from the ID and the sub type.
*/
public get uniqueId(): string {
return `${this.id}-${(this.subType || '')}`;
}
/**
* Updates the accessory information service.
* @param information The accessory information.
*/
public setInformation(information: AccessoryInformation) {
// Makes sure the accessory information service is used
const accessoryInformationService = this.useService(this.platform.api.hap.Service.AccessoryInformation, this.name);
// Updates the information characteristics
if (information.manufacturer != null) {
accessoryInformationService.useCharacteristic(this.platform.api.hap.Characteristic.Manufacturer, information.manufacturer);
}
if (information.model != null) {
accessoryInformationService.useCharacteristic(this.platform.api.hap.Characteristic.Model, information.model);
}
if (information.serialNumber != null) {
accessoryInformationService.useCharacteristic(this.platform.api.hap.Characteristic.SerialNumber, information.serialNumber);
}
if (information.firmwareRevision != null) {
accessoryInformationService.useCharacteristic(this.platform.api.hap.Characteristic.FirmwareRevision, information.firmwareRevision);
}
if (information.hardwareRevision != null) {
accessoryInformationService.useCharacteristic(this.platform.api.hap.Characteristic.HardwareRevision, information.hardwareRevision);
}
}
/**
* Contains the services.
*/
private _services: Array<Service> = new Array<Service>();
/**
* Gets the services.
*/
public get services(): Array<Service> {
return this._services;
}
/**
* Defines a service for usage with the accessory. When defining a service, it is marked as used and thus not removed from HomeKit after the initialization.
* @param type The type of the service.
* @param name The name that should be displayed in HomeKit.
* @param subType The sub type of the service. May be omitted if the type is already unique.
*/
public useService(type: typeof HapService, name: string, subType?: string): Service {
// Checks if the service has already been defined for usage
let service = this.services.find(s => s.type === type && s.subType === (subType || null));
if (service) {
return service;
}
// Creates a new service and returns it
service = new Service(this, type, name, subType);
this.services.push(service);
return service;
}
/**
* Removes all cached services that have not been defined for usage.
*/
public removeUnusedServices() {
const services = this.platformAccessory.services.slice();
for (let service of services) {
// The accessory information service is always required
if (service.UUID === this.platform.api.hap.Service.AccessoryInformation.UUID) {
continue;
}
// Removes the unused services
if (service.subtype) {
if (!this.services.some(d => service.UUID === d.hapService.UUID && service.subtype === d.hapService.subtype)) {
this.platformAccessory.removeService(service);
}
} else {
if (!this.services.some(d => service.UUID === d.hapService.UUID && !d.hapService.subtype)) {
this.platformAccessory.removeService(service);
}
}
}
}
}