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.
* [`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).
## Versioning Your Plugin
+14 -2
View File
@@ -1,5 +1,5 @@
{
"pluginAlias": "ExampleHomebridgePlugin",
"pluginAlias": "MultiTapSwitch",
"pluginType": "platform",
"singular": true,
"schema": {
@@ -9,7 +9,19 @@
"title": "Name",
"type": "string",
"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",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "homebridge-plugin-name",
"name": "homebridge-multitap-switch",
"version": "1.0.0",
"license": "Apache-2.0",
"license": "MIT",
"devDependencies": {
"@types/node": "^16.10.9",
"@typescript-eslint/eslint-plugin": "^5.0.0",
+63 -30
View File
@@ -1,53 +1,81 @@
import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
import { ExampleHomebridgePlatform } from './platform';
import { MultiTapSwitchPlatform } from './platform';
import {TIMEOUT} from 'dns';
/**
* Platform Accessory
* An instance of this class is created for each accessory your platform registers
* Each accessory may expose multiple services of different service types.
*/
export class ExamplePlatformAccessory {
private service: Service;
export class DeviceAccessory {
private serviceIn: Service;
private serviceOut: Service;
/**
* These are just used to create a working example
* You should implement your own code to track the state of your accessory
*/
private exampleStates = {
On: false,
Brightness: 100,
private readonly singleButtonEvents = {
minValue: this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
maxValue: this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
validValues: [
this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
],
};
private currentState = {
"On": Boolean,
"NumScenes": Number,
"KeepSeconds": Number,
"Timeout": TIMEOUT
};
private readonly triggerButtons: Service[] = [];
constructor(
private readonly platform: ExampleHomebridgePlatform,
private readonly platform: MultiTapSwitchPlatform,
private readonly accessory: PlatformAccessory,
private readonly numOfButtons: number,
) {
// set accessory information
this.accessory.getService(this.platform.Service.AccessoryInformation)!
.setCharacteristic(this.platform.Characteristic.Manufacturer, 'Default-Manufacturer')
.setCharacteristic(this.platform.Characteristic.Model, 'Default-Model')
.setCharacteristic(this.platform.Characteristic.SerialNumber, 'Default-Serial');
.setCharacteristic(this.platform.Characteristic.Manufacturer, 'TippyTapper Solutions')
.setCharacteristic(this.platform.Characteristic.Model, 'SceneButton-000')
.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.service = this.accessory.getService(this.platform.Service.Lightbulb) || this.accessory.addService(this.platform.Service.Lightbulb);
this.serviceIn = this.accessory.getService(this.platform.Service.Switch)
|| 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
// 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
// see https://developers.homebridge.io/#/service/Lightbulb
// 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
.onGet(this.getOn.bind(this)); // GET - bind to the `getOn` method below
// 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
/**
@@ -62,11 +90,11 @@ export class ExamplePlatformAccessory {
*/
// Example: add two "motion sensor" services to the accessory
const motionSensorOneService = this.accessory.getService('Motion Sensor One Name') ||
this.accessory.addService(this.platform.Service.MotionSensor, 'Motion Sensor One Name', 'YourUniqueIdentifier-1');
const inputService = this.accessory.getService(this.accessory.displayName + ' Trigger') ||
this.accessory.addService(this.platform.Service.MotionSensor, this.accessory.displayName + ' Trigger', 'YourUniqueIdentifier-1');
const motionSensorTwoService = this.accessory.getService('Motion Sensor Two Name') ||
this.accessory.addService(this.platform.Service.MotionSensor, 'Motion Sensor Two Name', 'YourUniqueIdentifier-2');
const outputService = this.accessory.getService(this.accessory.displayName + ' SceneSwitch') ||
this.accessory.addService(this.platform.Service.MotionSensor, this.accessory.displayName + ' SceneSwitch', 'YourUniqueIdentifier-2');
/**
* Updating characteristics values asynchronously.
@@ -83,12 +111,13 @@ export class ExamplePlatformAccessory {
motionDetected = !motionDetected;
// push the new value to HomeKit
motionSensorOneService.updateCharacteristic(this.platform.Characteristic.MotionDetected, motionDetected);
motionSensorTwoService.updateCharacteristic(this.platform.Characteristic.MotionDetected, !motionDetected);
inputService.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 motionSensorTwoService:', !motionDetected);
}, 10000);
}
/**
@@ -97,8 +126,12 @@ export class ExamplePlatformAccessory {
*/
async setOn(value: CharacteristicValue) {
// 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);
}
@@ -117,7 +150,7 @@ export class ExamplePlatformAccessory {
*/
async getOn(): Promise<CharacteristicValue> {
// 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);
@@ -133,9 +166,9 @@ export class ExamplePlatformAccessory {
*/
async setBrightness(value: CharacteristicValue) {
// 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 { PLATFORM_NAME } from './settings';
import { ExampleHomebridgePlatform } from './platform';
import { MultiTapSwitchPlatform } from './platform';
/**
* This method registers the platform with Homebridge
*/
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 { PLATFORM_NAME, PLUGIN_NAME } from './settings';
import { ExamplePlatformAccessory } from './platformAccessory';
import { DeviceAccessory } from './accessory';
/**
* HomebridgePlatform
* This class is the main constructor for your plugin, this is where you should
* 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 Characteristic: typeof Characteristic = this.api.hap.Characteristic;
@@ -44,6 +44,10 @@ export class ExampleHomebridgePlatform implements DynamicPlatformPlugin {
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.
* Accessories must only be registered once, previously created accessories
@@ -54,63 +58,53 @@ export class ExampleHomebridgePlatform implements DynamicPlatformPlugin {
// EXAMPLE ONLY
// A real plugin you would discover accessories from the local network, cloud services
// 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
for (const device of exampleDevices) {
// generate a unique id for the accessory this should be generated from
// 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
// something globally unique, but constant, for example, the device serial
// number or MAC address
const uuid = this.api.hap.uuid.generate(device.exampleUniqueId);
// see if an accessory with the same uuid has already been registered and restored from
// the cached devices we stored in the `configureAccessory` method above
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
// see if an accessory with the same uuid has already been registered and restored from
// the cached devices we stored in the `configureAccessory` method above
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory) {
// the accessory already exists
this.log.info('Restoring existing accessory from cache:', existingAccessory.displayName);
if (existingAccessory) {
// the accessory already exists
this.log.info('Restoring existing accessory from cache:', existingAccessory.displayName);
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
// existingAccessory.context.device = device;
// this.api.updatePlatformAccessories([existingAccessory]);
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
// existingAccessory.context.device = device;
// this.api.updatePlatformAccessories([existingAccessory]);
// create the accessory handler for the restored accessory
// this is imported from `accessoryInput.ts`
new DeviceAccessory(this, existingAccessory, this.config.numScenes);
// create the accessory handler for the restored accessory
// this is imported from `platformAccessory.ts`
new ExamplePlatformAccessory(this, existingAccessory);
// it is possible to remove platform accessories at any time using `api.unregisterPlatformAccessories`, eg.:
// remove platform accessories when no longer present
// 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.:
// remove platform accessories when no longer present
// 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
const accessory = new this.api.platformAccessory(<string>this.config.name, uuid);
// create a new accessory
const accessory = new this.api.platformAccessory(device.exampleDisplayName, uuid);
// store a copy of the device object in the `accessory.context`
// 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`
// the `context` property can be used to store any data about the accessory you may need
accessory.context.device = device;
// create the accessory handler for the newly create accessory
// this is imported from `accessoryInput.ts`
new DeviceAccessory(this, accessory, this.config.numScenes);
// create the accessory handler for the newly create accessory
// this is imported from `platformAccessory.ts`
new ExamplePlatformAccessory(this, accessory);
// link the accessory to your platform
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [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
*/
export const PLATFORM_NAME = 'ExampleHomebridgePlugin';
export const PLATFORM_NAME = 'MultiTapSwitch';
/**
* 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';