or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

configuration.mdcore-api.mdhap-integration.mdindex.mdlogging.mdplatform-accessories.mdplugin-system.md
tile.json

plugin-system.mddocs/

Plugin System

The Homebridge plugin system provides a comprehensive architecture for extending HomeKit functionality through standardized plugin interfaces. It supports four distinct plugin types: Accessory plugins, Dynamic Platform plugins, Static Platform plugins, and Independent Platform plugins, each designed for specific use cases and device management patterns.

Capabilities

Plugin Initializer

The main entry point for every Homebridge plugin, called once during plugin loading.

/**
 * Plugin initializer function - required default export for every plugin
 * Called once when the plugin is loaded from disk
 */
interface PluginInitializer {
  /** 
   * Initialize the plugin and register accessories/platforms
   * @param api - The Homebridge API instance
   */
  (api: API): void | Promise<void>;
}

Usage Examples:

// Basic plugin initializer
const plugin: PluginInitializer = (api: API) => {
  api.registerAccessory("my-plugin", "LightAccessory", LightAccessory);
  api.registerPlatform("my-plugin", "MyPlatform", MyPlatform);
};

export = plugin;

// Async plugin initializer
const asyncPlugin: PluginInitializer = async (api: API) => {
  // Perform async initialization
  await initializeExternalLibrary();
  
  api.registerAccessory("my-plugin", "AsyncAccessory", AsyncAccessory);
};

export = asyncPlugin;

Plugin Types

Enumeration of available plugin types.

/**
 * Types of plugins supported by Homebridge
 */
enum PluginType {
  /** Single accessory plugin */
  ACCESSORY = "accessory",
  /** Platform plugin (manages multiple accessories) */
  PLATFORM = "platform"
}

Accessory Plugins

Single accessory plugins that expose one HomeKit accessory per configuration entry.

/**
 * Constructor interface for accessory plugins
 */
interface AccessoryPluginConstructor {
  new(logger: Logging, config: AccessoryConfig, api: API): AccessoryPlugin;
}

/**
 * Interface for accessory plugin implementations
 * Represents a single HomeKit accessory
 */
interface AccessoryPlugin {
  /** Optional identification method called when user requests accessory identification */
  identify?(): void;
  
  /** 
   * Return all services exposed by this accessory
   * Called once during startup - set up all event handlers before returning
   */
  getServices(): Service[];
  
  /** 
   * Return all controllers exposed by this accessory (optional)
   * Used for camera controllers, remote controllers, etc.
   */
  getControllers?(): Controller[];
}

Usage Examples:

import { AccessoryPlugin, Logger, AccessoryConfig, API, Service } from "homebridge";

class LightAccessory implements AccessoryPlugin {
  private service: Service;
  private isOn = false;

  constructor(
    private log: Logger,
    private config: AccessoryConfig,
    private api: API
  ) {
    this.service = new this.api.hap.Service.Lightbulb(this.config.name);
    
    // Set up characteristic handlers
    this.service.getCharacteristic(this.api.hap.Characteristic.On)
      .onGet(this.getOn.bind(this))
      .onSet(this.setOn.bind(this));
      
    this.log.info("Light accessory initialized:", this.config.name);
  }

  identify() {
    this.log.info("Identify requested for:", this.config.name);
  }

  getServices(): Service[] {
    return [this.service];
  }

  private async getOn() {
    this.log.debug("Getting power state:", this.isOn);
    return this.isOn;
  }

  private async setOn(value: boolean) {
    this.log.info("Setting power state to:", value);
    this.isOn = value;
    // Control actual device here
  }
}

// Register the accessory
export = (api: API) => {
  api.registerAccessory("my-plugin", "LightAccessory", LightAccessory);
};

Platform Plugin Base

Base interface extended by all platform plugin types.

/**
 * Constructor interface for platform plugins
 */
interface PlatformPluginConstructor<Config extends PlatformConfig = PlatformConfig> {
  new(logger: Logging, config: Config, api: API): DynamicPlatformPlugin | StaticPlatformPlugin | IndependentPlatformPlugin;
}

/**
 * Base interface for platform plugins (not exported publicly)
 * Extended by specific platform plugin types
 */
interface PlatformPlugin {}

Dynamic Platform Plugins

Platform plugins that can dynamically add, remove, and update accessories during runtime.

/**
 * Dynamic platform plugin interface
 * Manages accessories that can be added/removed during runtime
 * All accessories are cached to disk and restored on restart
 */
interface DynamicPlatformPlugin extends PlatformPlugin {
  /**
   * Called for each cached accessory restored from disk on startup
   * Use this to restore event handlers and device connections
   * @param accessory - The cached platform accessory to configure
   */
  configureAccessory(accessory: PlatformAccessory): void;
}

Usage Examples:

import { DynamicPlatformPlugin, Logger, PlatformConfig, API, PlatformAccessory } from "homebridge";

interface MyPlatformConfig extends PlatformConfig {
  deviceHubUrl: string;
  pollingInterval?: number;
}

class MyDynamicPlatform implements DynamicPlatformPlugin {
  private accessories: PlatformAccessory[] = [];

  constructor(
    private log: Logger,
    private config: MyPlatformConfig,
    private api: API
  ) {
    this.api.on("didFinishLaunching", () => {
      this.discoverDevices();
    });
  }

  configureAccessory(accessory: PlatformAccessory) {
    this.log.info("Configuring cached accessory:", accessory.displayName);
    
    // Restore event handlers for cached accessory
    this.setupAccessoryServices(accessory);
    this.accessories.push(accessory);
  }

  private async discoverDevices() {
    // Discover devices from external service
    const devices = await this.fetchDevicesFromHub();
    
    for (const device of devices) {
      const uuid = this.api.hap.uuid.generate(device.id);
      let accessory = this.accessories.find(acc => acc.UUID === uuid);
      
      if (!accessory) {
        // Create new accessory
        accessory = new this.api.platformAccessory(device.name, uuid);
        this.setupAccessoryServices(accessory);
        
        // Register with Homebridge
        this.api.registerPlatformAccessories("my-plugin", "MyPlatform", [accessory]);
        this.accessories.push(accessory);
      }
      
      // Update accessory context
      accessory.context.device = device;
    }
  }

  private setupAccessoryServices(accessory: PlatformAccessory) {
    const service = accessory.getService(this.api.hap.Service.Lightbulb) ||
      accessory.addService(this.api.hap.Service.Lightbulb);
      
    service.getCharacteristic(this.api.hap.Characteristic.On)
      .onGet(() => this.getDeviceState(accessory))
      .onSet((value) => this.setDeviceState(accessory, value));
  }
}

Static Platform Plugins

Platform plugins that return a fixed set of accessories at startup.

/**
 * Static platform plugin interface
 * Returns a fixed set of accessories at startup
 * Accessories are created fresh on each restart
 */
interface StaticPlatformPlugin extends PlatformPlugin {
  /**
   * Return all accessories provided by this platform
   * Called once during startup
   * @param callback - Callback to provide the accessories array
   */
  accessories(callback: (accessories: AccessoryPlugin[]) => void): void;
}

Usage Examples:

import { StaticPlatformPlugin, Logger, PlatformConfig, API, AccessoryPlugin } from "homebridge";

class MyStaticPlatform implements StaticPlatformPlugin {
  constructor(
    private log: Logger,
    private config: PlatformConfig & { devices: any[] },
    private api: API
  ) {}

  accessories(callback: (accessories: AccessoryPlugin[]) => void) {
    const accessories: AccessoryPlugin[] = [];
    
    // Create accessories from config
    for (const deviceConfig of this.config.devices) {
      const accessory = new DeviceAccessory(this.log, deviceConfig, this.api);
      accessories.push(accessory);
    }
    
    this.log.info("Created", accessories.length, "accessories");
    callback(accessories);
  }
}

class DeviceAccessory implements AccessoryPlugin {
  private service: Service;

  constructor(
    private log: Logger,
    private config: any,
    private api: API
  ) {
    this.service = new this.api.hap.Service.Switch(this.config.name);
    this.service.getCharacteristic(this.api.hap.Characteristic.On)
      .onGet(() => this.getState())
      .onSet((value) => this.setState(value));
  }

  getServices(): Service[] {
    return [this.service];
  }

  private async getState() {
    // Return device state
    return false;
  }

  private async setState(value: boolean) {
    // Set device state
    this.log.info("Setting", this.config.name, "to", value);
  }
}

Independent Platform Plugins

Platform plugins that don't expose any accessories but perform background tasks.

/**
 * Independent platform plugin interface
 * Performs background tasks without exposing accessories to HomeKit
 * Used for services, integrations, or system utilities
 */
interface IndependentPlatformPlugin extends PlatformPlugin {
  // No required methods - plugin handles its own lifecycle
}

Usage Examples:

import { IndependentPlatformPlugin, Logger, PlatformConfig, API } from "homebridge";

class SystemMonitorPlatform implements IndependentPlatformPlugin {
  private monitoringInterval?: NodeJS.Timeout;

  constructor(
    private log: Logger,
    private config: PlatformConfig & { interval?: number },
    private api: API
  ) {
    this.api.on("didFinishLaunching", () => {
      this.startMonitoring();
    });

    this.api.on("shutdown", () => {
      this.stopMonitoring();
    });
  }

  private startMonitoring() {
    const interval = this.config.interval || 60000; // 1 minute default
    
    this.monitoringInterval = setInterval(() => {
      this.checkSystemHealth();
    }, interval);
    
    this.log.info("System monitoring started");
  }

  private stopMonitoring() {
    if (this.monitoringInterval) {
      clearInterval(this.monitoringInterval);
      this.monitoringInterval = undefined;
    }
    this.log.info("System monitoring stopped");
  }

  private checkSystemHealth() {
    // Perform system health checks
    this.log.debug("System health check completed");
  }
}

Types

interface AccessoryConfig extends Record<string, any> {
  /** Accessory type identifier */
  accessory: string;
  /** Display name for the accessory */
  name: string;
  /** Optional custom UUID base */
  uuid_base?: string;
  /** Optional bridge configuration for child bridges */
  _bridge?: BridgeConfiguration;
}

interface PlatformConfig extends Record<string, any> {
  /** Platform type identifier */
  platform: string;
  /** Optional display name for the platform */
  name?: string;
  /** Optional bridge configuration for child bridges */
  _bridge?: BridgeConfiguration;
}