The quickest way to start a plugin is the plugin template — a working dynamic platform plugin with TypeScript, ESLint and the Homebridge types already configured. Use it as a GitHub template, rename a few things, and you have a plugin that runs.
For a camera plugin, start from the camera plugin template instead, and read Cameras.
A plugin is an npm package with three things:
- The
homebridge-pluginkeyword inpackage.json. Homebridge and the Homebridge UI find plugins by this keyword, so without it your plugin is invisible. - An
enginesblock naming the Homebridge and Node versions you support, for example"homebridge": "^1.8.0 || ^2.0.0". - A
mainentry point that exports a function taking the API object.
Add transport keywords alongside homebridge-plugin so the UI knows which bridges to offer — the template already includes supports-hap.
Four files, each with one job:
-
settings.tsholdsPLATFORM_NAME(what users put in theirconfig.json) andPLUGIN_NAME(which must match the package name inpackage.json). Both are used when registering and unregistering accessories, which is why they live in one place. -
index.tsis the entry point, and does one thing — registers the platform:export default (api) => { api.registerPlatform(PLATFORM_NAME, ExampleHomebridgePlatform) }
-
platform.tsis the platform class: it receives the config, restores cached accessories inconfigureAccessory, and discovers devices oncedidFinishLaunchingfires. See Platform Plugins for the lifecycle. -
platformAccessory.tsis one accessory: it adds the services and wires up the characteristic handlers. See Service and Characteristics.
The heart of the template is the loop in discoverDevices(), and it is the pattern nearly every platform plugin uses:
- Ask the device API what exists.
- For each device, build a stable UUID from something that never changes — a serial number or device id — with
api.hap.uuid.generate(). - If an accessory with that UUID was restored from the cache, reuse it.
- If not, create one and register it with registerPlatformAccessories.
- Unregister anything in the cache that the API no longer reports, so devices removed upstream disappear from HomeKit.
Getting the UUID input right is the part worth care. It must be stable across restarts and unique per device: if it changes, HomeKit sees a brand-new accessory and the user loses their room assignment, name and automations.
The template's watch script rebuilds and restarts Homebridge whenever you change a file:
npm run watchIt builds, links the package so a local Homebridge instance picks it up, and runs nodemon. The template ships a test Homebridge config under test/ for it to use.
Run Homebridge with -D while developing so your debug logging appears.
Publish to npm as normal — see Publishing Your Plugin for what to check before the first release, how verification works, and how to add donation links.