homebridge
Version:
HomeKit support for the impatient
236 lines • 10.4 kB
JavaScript
import { EventEmitter } from 'node:events';
import hapNodeJs from '@homebridge/hap-nodejs';
import semver from 'semver';
import { Logger } from './logger.js';
import { PlatformAccessory } from './platformAccessory.js';
import { PluginManager } from './pluginManager.js';
import { User } from './user.js';
import getVersion from './version.js';
const log = Logger.internal;
// eslint-disable-next-line no-restricted-syntax
export var PluginType;
(function (PluginType) {
PluginType["ACCESSORY"] = "accessory";
PluginType["PLATFORM"] = "platform";
})(PluginType || (PluginType = {}));
// eslint-disable-next-line no-restricted-syntax
export var APIEvent;
(function (APIEvent) {
/**
* Event is fired once homebridge has finished with booting up and initializing all components and plugins.
* When this event is fired it is possible that the Bridge accessory isn't published yet, if homebridge still needs
* to wait for some {@see StaticPlatformPlugin | StaticPlatformPlugins} to finish accessory creation.
*/
APIEvent["DID_FINISH_LAUNCHING"] = "didFinishLaunching";
/**
* This event is fired when homebridge gets shutdown. This could be a regular shutdown or an unexpected crash.
* At this stage all Accessories are already unpublished and all PlatformAccessories are already saved to disk!
*/
APIEvent["SHUTDOWN"] = "shutdown";
})(APIEvent || (APIEvent = {}));
// eslint-disable-next-line no-restricted-syntax
export var InternalAPIEvent;
(function (InternalAPIEvent) {
InternalAPIEvent["REGISTER_ACCESSORY"] = "registerAccessory";
InternalAPIEvent["REGISTER_PLATFORM"] = "registerPlatform";
InternalAPIEvent["PUBLISH_EXTERNAL_ACCESSORIES"] = "publishExternalAccessories";
InternalAPIEvent["REGISTER_PLATFORM_ACCESSORIES"] = "registerPlatformAccessories";
InternalAPIEvent["UPDATE_PLATFORM_ACCESSORIES"] = "updatePlatformAccessories";
InternalAPIEvent["UNREGISTER_PLATFORM_ACCESSORIES"] = "unregisterPlatformAccessories";
// Matter events (matching HAP pattern)
InternalAPIEvent["PUBLISH_EXTERNAL_MATTER_ACCESSORIES"] = "publishExternalMatterAccessories";
InternalAPIEvent["REGISTER_MATTER_PLATFORM_ACCESSORIES"] = "registerMatterPlatformAccessories";
InternalAPIEvent["UPDATE_MATTER_PLATFORM_ACCESSORIES"] = "updateMatterPlatformAccessories";
InternalAPIEvent["UNREGISTER_MATTER_PLATFORM_ACCESSORIES"] = "unregisterMatterPlatformAccessories";
InternalAPIEvent["UNREGISTER_EXTERNAL_MATTER_ACCESSORIES"] = "unregisterExternalMatterAccessories";
InternalAPIEvent["UPDATE_MATTER_ACCESSORY_STATE"] = "updateMatterAccessoryState";
})(InternalAPIEvent || (InternalAPIEvent = {}));
// eslint-disable-next-line ts/no-unsafe-declaration-merging
export class HomebridgeAPI extends EventEmitter {
version = 2.7; // homebridge API version
serverVersion = getVersion(); // homebridge node module version
// ------------------ LEGACY EXPORTS FOR PRE TYPESCRIPT ------------------
user = User;
hap = hapNodeJs;
hapLegacyTypes = hapNodeJs.LegacyTypes; // used for older accessories/platforms
platformAccessory = PlatformAccessory;
// ------------------------------------------------------------------------
/**
* Internal state tracking whether Matter is enabled for this bridge
*/
matterEnabled = false;
/**
* Internal reference to MatterServer for API methods that need return values
* @internal
*/
_matterServer = null;
/**
* Internal reference to MatterBridgeManager for checking external servers
* @internal
*/
_matterManager = null;
/**
* Pending external accessory registrations
* Map of registration ID to resolve function
* @internal
*/
_pendingExternalRegistrations = new Map();
/**
* Lazy-loaded Matter API implementation
*/
_matterAPI;
/**
* Matter Protocol API (lazy-loaded).
*
* Returns the loaded MatterAPI instance, or `undefined` when Matter is not
* configured for this bridge. Server / ChildBridgeFork call
* {@link loadMatterAPI} before plugins run on Matter-enabled bridges, so
* plugins observe a defined value here whenever {@link isMatterEnabled}
* returns true.
*/
get matter() {
return this._matterAPI;
}
/**
* Load Matter API implementation. Idempotent.
*
* Called by Server / ChildBridgeFork during startup when Matter is
* configured for the bridge, before plugin initialization. Plugins should
* not call this directly — use {@link matter} instead.
*
* @internal
*/
async loadMatterAPI() {
if (!this._matterAPI) {
const { MatterAPIImpl } = await import('./matter/MatterAPIImpl.js');
this._matterAPI = new MatterAPIImpl(this);
}
}
constructor() {
super();
}
/**
* Internal method to set Matter enabled status
* Called by Server or ChildBridgeFork after Matter initialization
* @internal
*/
_setMatterEnabled(enabled) {
this.matterEnabled = enabled;
}
/**
* Internal method to set MatterServer reference
* Called by Server or ChildBridgeFork after creating MatterServer
* @internal
*/
_setMatterServer(server) {
this._matterServer = server;
}
/**
* Internal method to set MatterBridgeManager reference
* Called by Server or ChildBridgeFork to allow API access to external servers
* @internal
*/
_setMatterManager(manager) {
this._matterManager = manager;
}
/**
* Internal method to resolve pending external accessory registrations
* Called by MatterBridgeManager when external accessories finish publishing
* @internal
*/
_resolveExternalRegistration(registrationId) {
const resolve = this._pendingExternalRegistrations.get(registrationId);
if (resolve) {
resolve();
this._pendingExternalRegistrations.delete(registrationId);
}
}
versionGreaterOrEqual(version) {
return semver.gte(this.serverVersion, version);
}
static isDynamicPlatformPlugin(platformPlugin) {
return 'configureAccessory' in platformPlugin;
}
static isStaticPlatformPlugin(platformPlugin) {
return 'accessories' in platformPlugin;
}
signalFinished() {
this.emit("didFinishLaunching" /* APIEvent.DID_FINISH_LAUNCHING */);
}
signalShutdown() {
this.emit("shutdown" /* APIEvent.SHUTDOWN */);
}
registerAccessory(pluginIdentifier, accessoryName, constructor) {
if (typeof accessoryName === 'function') {
constructor = accessoryName;
accessoryName = pluginIdentifier;
this.emit("registerAccessory" /* InternalAPIEvent.REGISTER_ACCESSORY */, accessoryName, constructor);
}
else {
this.emit("registerAccessory" /* InternalAPIEvent.REGISTER_ACCESSORY */, accessoryName, constructor, pluginIdentifier);
}
}
registerPlatform(pluginIdentifier, platformName, constructor) {
if (typeof platformName === 'function') {
constructor = platformName;
platformName = pluginIdentifier;
this.emit("registerPlatform" /* InternalAPIEvent.REGISTER_PLATFORM */, platformName, constructor);
}
else {
this.emit("registerPlatform" /* InternalAPIEvent.REGISTER_PLATFORM */, platformName, constructor, pluginIdentifier);
}
}
publishExternalAccessories(pluginIdentifier, accessories) {
if (!PluginManager.isQualifiedPluginIdentifier(pluginIdentifier)) {
log.info(`One of your plugins incorrectly registered an external accessory using the platform name (${pluginIdentifier}) and not the plugin identifier. Please report this to the developer!`);
}
accessories.forEach((accessory) => {
// noinspection SuspiciousTypeOfGuard
if (!(accessory instanceof PlatformAccessory)) {
throw new TypeError(`${pluginIdentifier} attempt to register an accessory that isn't PlatformAccessory!`);
}
accessory._associatedPlugin = pluginIdentifier;
});
this.emit("publishExternalAccessories" /* InternalAPIEvent.PUBLISH_EXTERNAL_ACCESSORIES */, accessories);
}
registerPlatformAccessories(pluginIdentifier, platformName, accessories) {
accessories.forEach((accessory) => {
// noinspection SuspiciousTypeOfGuard
if (!(accessory instanceof PlatformAccessory)) {
throw new TypeError(`${pluginIdentifier} - ${platformName} attempt to register an accessory that isn't PlatformAccessory!`);
}
accessory._associatedPlugin = pluginIdentifier;
accessory._associatedPlatform = platformName;
});
this.emit("registerPlatformAccessories" /* InternalAPIEvent.REGISTER_PLATFORM_ACCESSORIES */, accessories);
}
updatePlatformAccessories(accessories) {
this.emit("updatePlatformAccessories" /* InternalAPIEvent.UPDATE_PLATFORM_ACCESSORIES */, accessories);
}
unregisterPlatformAccessories(pluginIdentifier, platformName, accessories) {
accessories.forEach((accessory) => {
// noinspection SuspiciousTypeOfGuard
if (!(accessory instanceof PlatformAccessory)) {
throw new TypeError(`${pluginIdentifier} - ${platformName} attempt to unregister an accessory that isn't PlatformAccessory!`);
}
});
this.emit("unregisterPlatformAccessories" /* InternalAPIEvent.UNREGISTER_PLATFORM_ACCESSORIES */, accessories);
}
/**
* Check if Matter is available in this version of Homebridge
* @returns true if Homebridge version satisfies >= 2.0.0-alpha.0
*/
isMatterAvailable() {
return semver.gte(this.serverVersion, '2.0.0-alpha.0');
}
/**
* Check if Matter is enabled for this bridge
* For main bridge: returns true if Matter is enabled in `bridge.matter` config
* For child bridge: returns true if Matter is enabled in the `_bridge.matter` config
* @returns true if Matter is enabled
*/
isMatterEnabled() {
return this.matterEnabled;
}
}
//# sourceMappingURL=api.js.map