First test

This commit is contained in:
dennis authored and Dennis Twardowsky committed 2023-02-02 22:53:41 +01:00
1 parent d5961e4464
commit 0637aeb2f3
7 files changed
+128 -89

No files matched your search

+1 -1
View File
@@ -114,7 +114,7 @@ This will launch an instance of Homebridge in debug mode which will restart ever
You can now start customising the plugin template to suit your requirements. You can now start customising the plugin template to suit your requirements.
* [`src/platform.ts`](./src/platform.ts) - this is where your device setup and discovery should go. * [`src/platform.ts`](./src/platform.ts) - this is where your device setup and discovery should go.
* [`src/platformAccessory.ts`](./src/platformAccessory.ts) - this is where your accessory control logic should go, you can rename or create multiple instances of this file for each accessory type you need to implement as part of your platform plugin. You can refer to the [developer documentation](https://developers.homebridge.io/) to see what characteristics you need to implement for each service type. * [`src/accessoryInput.ts`](./src/accessoryInput.ts) - this is where your accessory control logic should go, you can rename or create multiple instances of this file for each accessory type you need to implement as part of your platform plugin. You can refer to the [developer documentation](https://developers.homebridge.io/) to see what characteristics you need to implement for each service type.
* [`config.schema.json`](./config.schema.json) - update the config schema to match the config you expect from the user. See the [Plugin Config Schema Documentation](https://developers.homebridge.io/#/config-schema). * [`config.schema.json`](./config.schema.json) - update the config schema to match the config you expect from the user. See the [Plugin Config Schema Documentation](https://developers.homebridge.io/#/config-schema).
## Versioning Your Plugin ## Versioning Your Plugin
+14 -2
View File
@@ -1,5 +1,5 @@
{ {
"pluginAlias": "ExampleHomebridgePlugin", "pluginAlias": "MultiTapSwitch",
"pluginType": "platform", "pluginType": "platform",
"singular": true, "singular": true,
"schema": { "schema": {
@@ -9,7 +9,19 @@
"title": "Name", "title": "Name",
"type": "string", "type": "string",
"required": true, "required": true,
"default": "Example Dynamic Platform" "default": "Scene Switcher"
},
"numScenes": {
"title": "Number of Scenes",
"type": "number",
"required": true,
"default": 4
},
"secondsToKeep": {
"title": "Holding Time",
"type": "number",
"required": true,
"default": 5
} }
} }
} }
+3 -3
View File
@@ -1,13 +1,13 @@
{ {
"name": "homebridge-plugin-name", "name": "homebridge-multitap-switch",
"version": "1.0.0", "version": "1.0.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "homebridge-plugin-name", "name": "homebridge-multitap-switch",
"version": "1.0.0", "version": "1.0.0",
"license": "Apache-2.0", "license": "MIT",
"devDependencies": { "devDependencies": {
"@types/node": "^16.10.9", "@types/node": "^16.10.9",
"@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/eslint-plugin": "^5.0.0",
+63 -30
View File
@@ -1,53 +1,81 @@
import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge'; import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
import { ExampleHomebridgePlatform } from './platform'; import { MultiTapSwitchPlatform } from './platform';
import {TIMEOUT} from 'dns';
/** /**
* Platform Accessory * Platform Accessory
* An instance of this class is created for each accessory your platform registers * An instance of this class is created for each accessory your platform registers
* Each accessory may expose multiple services of different service types. * Each accessory may expose multiple services of different service types.
*/ */
export class ExamplePlatformAccessory { export class DeviceAccessory {
private service: Service; private serviceIn: Service;
private serviceOut: Service;
/** private readonly singleButtonEvents = {
* These are just used to create a working example minValue: this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
* You should implement your own code to track the state of your accessory maxValue: this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
*/ validValues: [
private exampleStates = { this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
On: false, ],
Brightness: 100,
}; };
private currentState = {
"On": Boolean,
"NumScenes": Number,
"KeepSeconds": Number,
"Timeout": TIMEOUT
};
private readonly triggerButtons: Service[] = [];
constructor( constructor(
private readonly platform: ExampleHomebridgePlatform, private readonly platform: MultiTapSwitchPlatform,
private readonly accessory: PlatformAccessory, private readonly accessory: PlatformAccessory,
private readonly numOfButtons: number,
) { ) {
// set accessory information // set accessory information
this.accessory.getService(this.platform.Service.AccessoryInformation)! this.accessory.getService(this.platform.Service.AccessoryInformation)!
.setCharacteristic(this.platform.Characteristic.Manufacturer, 'Default-Manufacturer') .setCharacteristic(this.platform.Characteristic.Manufacturer, 'TippyTapper Solutions')
.setCharacteristic(this.platform.Characteristic.Model, 'Default-Model') .setCharacteristic(this.platform.Characteristic.Model, 'SceneButton-000')
.setCharacteristic(this.platform.Characteristic.SerialNumber, 'Default-Serial'); .setCharacteristic(this.platform.Characteristic.SerialNumber, 'DE:AD:BE:EF:00:00');
// get the LightBulb service if it exists, otherwise create a new LightBulb service
// you can create multiple services for each accessory this.serviceIn = this.accessory.getService(this.platform.Service.Switch)
this.service = this.accessory.getService(this.platform.Service.Lightbulb) || this.accessory.addService(this.platform.Service.Lightbulb); || this.accessory.addService(this.platform.Service.Switch);
this.serviceOut = this.accessory.getService(this.platform.Service.ServiceLabel)
|| this.accessory.addService(this.platform.Service.ServiceLabel);
this.serviceOut.setCharacteristic(this.platform.Characteristic.ServiceLabelNamespace, '')
this.serviceOut.setCharacteristic(this.platform.Characteristic.ServiceLabelIndex, 1);
// Create configured number of scene buttons
for (let i = 1; i <= numOfButtons; i++) {
const newButton = this.accessory.addService(this.platform.Service.StatelessProgrammableSwitch);
this.serviceOut.addLinkedService(newButton);
this.triggerButtons.push(newButton);
newButton.getCharacteristic(this.platform.Characteristic.ProgrammableSwitchEvent)
.setProps(this.singleButtonEvents);
newButton.setCharacteristic(this.platform.Characteristic.ServiceLabelIndex, i);
}
// set the service name, this is what is displayed as the default name on the Home app // set the service name, this is what is displayed as the default name on the Home app
// in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method. // in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method.
this.service.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.exampleDisplayName); this.serviceOut.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.exampleDisplayName);
// each service must implement at-minimum the "required characteristics" for the given service type // each service must implement at-minimum the "required characteristics" for the given service type
// see https://developers.homebridge.io/#/service/Lightbulb // see https://developers.homebridge.io/#/service/Lightbulb
// register handlers for the On/Off Characteristic // register handlers for the On/Off Characteristic
this.service.getCharacteristic(this.platform.Characteristic.On) this.serviceOut.getCharacteristic(this.platform.Characteristic.On)
.onSet(this.setOn.bind(this)) // SET - bind to the `setOn` method below .onSet(this.setOn.bind(this)) // SET - bind to the `setOn` method below
.onGet(this.getOn.bind(this)); // GET - bind to the `getOn` method below .onGet(this.getOn.bind(this)); // GET - bind to the `getOn` method below
// register handlers for the Brightness Characteristic // register handlers for the Brightness Characteristic
this.service.getCharacteristic(this.platform.Characteristic.Brightness) this.serviceOut.getCharacteristic(this.platform.Characteristic.Brightness)
.onSet(this.setBrightness.bind(this)); // SET - bind to the 'setBrightness` method below .onSet(this.setBrightness.bind(this)); // SET - bind to the 'setBrightness` method below
/** /**
@@ -62,11 +90,11 @@ export class ExamplePlatformAccessory {
*/ */
// Example: add two "motion sensor" services to the accessory // Example: add two "motion sensor" services to the accessory
const motionSensorOneService = this.accessory.getService('Motion Sensor One Name') || const inputService = this.accessory.getService(this.accessory.displayName + ' Trigger') ||
this.accessory.addService(this.platform.Service.MotionSensor, 'Motion Sensor One Name', 'YourUniqueIdentifier-1'); this.accessory.addService(this.platform.Service.MotionSensor, this.accessory.displayName + ' Trigger', 'YourUniqueIdentifier-1');
const motionSensorTwoService = this.accessory.getService('Motion Sensor Two Name') || const outputService = this.accessory.getService(this.accessory.displayName + ' SceneSwitch') ||
this.accessory.addService(this.platform.Service.MotionSensor, 'Motion Sensor Two Name', 'YourUniqueIdentifier-2'); this.accessory.addService(this.platform.Service.MotionSensor, this.accessory.displayName + ' SceneSwitch', 'YourUniqueIdentifier-2');
/** /**
* Updating characteristics values asynchronously. * Updating characteristics values asynchronously.
@@ -83,12 +111,13 @@ export class ExamplePlatformAccessory {
motionDetected = !motionDetected; motionDetected = !motionDetected;
// push the new value to HomeKit // push the new value to HomeKit
motionSensorOneService.updateCharacteristic(this.platform.Characteristic.MotionDetected, motionDetected); inputService.updateCharacteristic(this.platform.Characteristic.MotionDetected, motionDetected);
motionSensorTwoService.updateCharacteristic(this.platform.Characteristic.MotionDetected, !motionDetected); outputService.updateCharacteristic(this.platform.Characteristic.MotionDetected, !motionDetected);
this.platform.log.debug('Triggering motionSensorOneService:', motionDetected); this.platform.log.debug('Triggering motionSensorOneService:', motionDetected);
this.platform.log.debug('Triggering motionSensorTwoService:', !motionDetected); this.platform.log.debug('Triggering motionSensorTwoService:', !motionDetected);
}, 10000); }, 10000);
} }
/** /**
@@ -97,8 +126,12 @@ export class ExamplePlatformAccessory {
*/ */
async setOn(value: CharacteristicValue) { async setOn(value: CharacteristicValue) {
// implement your own code to turn your device on/off // implement your own code to turn your device on/off
this.exampleStates.On = value as boolean; this.currentState.On = value as boolean;
this.currentState.Timeout = setTimeout(() => {
this.currentState.On = false;
this.setOn(false);
}, 1000 * 10);
this.platform.log.debug('Set Characteristic On ->', value); this.platform.log.debug('Set Characteristic On ->', value);
} }
@@ -117,7 +150,7 @@ export class ExamplePlatformAccessory {
*/ */
async getOn(): Promise<CharacteristicValue> { async getOn(): Promise<CharacteristicValue> {
// implement your own code to check if the device is on // implement your own code to check if the device is on
const isOn = this.exampleStates.On; const isOn = this.currentState.On;
this.platform.log.debug('Get Characteristic On ->', isOn); this.platform.log.debug('Get Characteristic On ->', isOn);
@@ -133,9 +166,9 @@ export class ExamplePlatformAccessory {
*/ */
async setBrightness(value: CharacteristicValue) { async setBrightness(value: CharacteristicValue) {
// implement your own code to set the brightness // implement your own code to set the brightness
this.exampleStates.Brightness = value as number; //this.currentState.KeepSeconds = value as number;
this.platform.log.debug('Set Characteristic Brightness -> ', value); this.platform.log.debug('Set Characteristic KeepSeconds -> ', value);
} }
} }
+2 -2
View File
@@ -1,11 +1,11 @@
import { API } from 'homebridge'; import { API } from 'homebridge';
import { PLATFORM_NAME } from './settings'; import { PLATFORM_NAME } from './settings';
import { ExampleHomebridgePlatform } from './platform'; import { MultiTapSwitchPlatform } from './platform';
/** /**
* This method registers the platform with Homebridge * This method registers the platform with Homebridge
*/ */
export = (api: API) => { export = (api: API) => {
api.registerPlatform(PLATFORM_NAME, ExampleHomebridgePlatform); api.registerPlatform(PLATFORM_NAME, MultiTapSwitchPlatform);
}; };
+43 -49
View File
@@ -1,14 +1,14 @@
import { API, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service, Characteristic } from 'homebridge'; import { API, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service, Characteristic } from 'homebridge';
import { PLATFORM_NAME, PLUGIN_NAME } from './settings'; import { PLATFORM_NAME, PLUGIN_NAME } from './settings';
import { ExamplePlatformAccessory } from './platformAccessory'; import { DeviceAccessory } from './accessory';
/** /**
* HomebridgePlatform * HomebridgePlatform
* This class is the main constructor for your plugin, this is where you should * This class is the main constructor for your plugin, this is where you should
* parse the user config and discover/register accessories with Homebridge. * parse the user config and discover/register accessories with Homebridge.
*/ */
export class ExampleHomebridgePlatform implements DynamicPlatformPlugin { export class MultiTapSwitchPlatform implements DynamicPlatformPlugin {
public readonly Service: typeof Service = this.api.hap.Service; public readonly Service: typeof Service = this.api.hap.Service;
public readonly Characteristic: typeof Characteristic = this.api.hap.Characteristic; public readonly Characteristic: typeof Characteristic = this.api.hap.Characteristic;
@@ -44,6 +44,10 @@ export class ExampleHomebridgePlatform implements DynamicPlatformPlugin {
this.accessories.push(accessory); this.accessories.push(accessory);
} }
defineUuid(name: string | undefined, serial: string): string {
return this.api.hap.uuid.generate(name + '_' + serial);
}
/** /**
* This is an example method showing how to register discovered accessories. * This is an example method showing how to register discovered accessories.
* Accessories must only be registered once, previously created accessories * Accessories must only be registered once, previously created accessories
@@ -54,63 +58,53 @@ export class ExampleHomebridgePlatform implements DynamicPlatformPlugin {
// EXAMPLE ONLY // EXAMPLE ONLY
// A real plugin you would discover accessories from the local network, cloud services // A real plugin you would discover accessories from the local network, cloud services
// or a user-defined array in the platform config. // or a user-defined array in the platform config.
const exampleDevices = [
{
exampleUniqueId: 'ABCD',
exampleDisplayName: 'Bedroom',
},
{
exampleUniqueId: 'EFGH',
exampleDisplayName: 'Kitchen',
},
];
// loop over the discovered devices and register each one if it has not already been registered // generate a unique id for the accessory this should be generated from
for (const device of exampleDevices) { // something globally unique, but constant, for example, the device serial
// number or MAC address
//const uuid = this.api.hap.uuid.generate(device.exampleUniqueId);
const uuid = this.defineUuid(this.config.name, "0");
// generate a unique id for the accessory this should be generated from // see if an accessory with the same uuid has already been registered and restored from
// something globally unique, but constant, for example, the device serial // the cached devices we stored in the `configureAccessory` method above
// number or MAC address const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
const uuid = this.api.hap.uuid.generate(device.exampleUniqueId);
// see if an accessory with the same uuid has already been registered and restored from if (existingAccessory) {
// the cached devices we stored in the `configureAccessory` method above // the accessory already exists
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid); this.log.info('Restoring existing accessory from cache:', existingAccessory.displayName);
if (existingAccessory) { // if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
// the accessory already exists // existingAccessory.context.device = device;
this.log.info('Restoring existing accessory from cache:', existingAccessory.displayName); // this.api.updatePlatformAccessories([existingAccessory]);
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.: // create the accessory handler for the restored accessory
// existingAccessory.context.device = device; // this is imported from `accessoryInput.ts`
// this.api.updatePlatformAccessories([existingAccessory]); new DeviceAccessory(this, existingAccessory, this.config.numScenes);
// create the accessory handler for the restored accessory // it is possible to remove platform accessories at any time using `api.unregisterPlatformAccessories`, eg.:
// this is imported from `platformAccessory.ts` // remove platform accessories when no longer present
new ExamplePlatformAccessory(this, existingAccessory); // this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory]);
// this.log.info('Removing existing accessory from cache:', existingAccessory.displayName);
} else {
// the accessory does not yet exist, so we need to create it
this.log.info('Adding INPUT:', this.config.name);
// it is possible to remove platform accessories at any time using `api.unregisterPlatformAccessories`, eg.: // create a new accessory
// remove platform accessories when no longer present const accessory = new this.api.platformAccessory(<string>this.config.name, uuid);
// this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory]);
// this.log.info('Removing existing accessory from cache:', existingAccessory.displayName);
} else {
// the accessory does not yet exist, so we need to create it
this.log.info('Adding new accessory:', device.exampleDisplayName);
// create a new accessory // store a copy of the device object in the `accessory.context`
const accessory = new this.api.platformAccessory(device.exampleDisplayName, uuid); // the `context` property can be used to store any data about the accessory you may need
accessory.context.device = {
"numScenes": this.config.numScenes,
"keepSeconds": this.config.keepSeconds
};
// store a copy of the device object in the `accessory.context` // create the accessory handler for the newly create accessory
// the `context` property can be used to store any data about the accessory you may need // this is imported from `accessoryInput.ts`
accessory.context.device = device; new DeviceAccessory(this, accessory, this.config.numScenes);
// create the accessory handler for the newly create accessory // link the accessory to your platform
// this is imported from `platformAccessory.ts` this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
new ExamplePlatformAccessory(this, accessory);
// link the accessory to your platform
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
}
} }
} }
} }
+2 -2
View File
@@ -1,9 +1,9 @@
/** /**
* This is the name of the platform that users will use to register the plugin in the Homebridge config.json * This is the name of the platform that users will use to register the plugin in the Homebridge config.json
*/ */
export const PLATFORM_NAME = 'ExampleHomebridgePlugin'; export const PLATFORM_NAME = 'MultiTapSwitch';
/** /**
* This must match the name of your plugin as defined the package.json * This must match the name of your plugin as defined the package.json
*/ */
export const PLUGIN_NAME = 'homebridge-plugin-name'; export const PLUGIN_NAME = 'homebridge-multitap-switch';