Doorbell refinement, working on README

This commit is contained in:
Serge Wagener 2022-02-10 12:01:24 +01:00
parent a8c5b1b9e6
commit b95352b05b
6 changed files with 320 additions and 120 deletions

290
README.md
View File

@ -1,48 +1,41 @@
# homebridge-smarthomeng # homebridge-smarthomeng
Homebridge plugin for SmartHomeNG. This is work in progress and not all devices are supported yet.
**Version v2 is a complete rewrite from scratch and a breaking update.**
You need to adapt your `config.json` !
## Currently supported ## Currently supported
This plugin currently supports the following services (and characteristics): This plugin currently supports the following services (and characteristics):
* LightBulb (on/off, brightness, hue, saturation) * LightBulb (on/off, brightness, hue, saturation, r, g, b, w)
* Fan (on/off) * Fan (active)
* Temperature sensor (current temperature) * TemperatureSensor (current temperature)
* Thermostat (current- / target temperature) * Thermostat (current- / target temperature, currentheatingcoolingstate)
* Window (current- / target position) * MotionSensor (motion detected)
* Window Covering (current- / target position) * OccupancySensor (presence detected)
* Motion sensor (motion detected) * ContactSensor (contact state)
* Occupancy sensor (motion detected)
* Contact Sensor (contact state)
* Switch (on/off) * Switch (on/off)
* Outlet (on/off)
* WindowCovering (CurrentPosition, TargetPosition).
Other accessories are being worked on and will be added as soon as ready.
## Requirements ## Requirements
* [SmartHomeNG](https://github.com/smarthomeNG/smarthome) * [SmartHomeNG](https://github.com/smarthomeNG/smarthome)
* [homebridge](https://www.npmjs.com/package/homebridge) * [homebridge](https://www.npmjs.com/package/homebridge)
## Installation ## Installation
### Install nodejs >= 0.12. ### Install nodejs >=14.18.1
You have to find out the right way for your OS. See [NodeJS](https://nodejs.org/en/) website for details depending on your OS.
Debian Jessie:
curl -sL https://deb.nodesource.com/setup_4.x | sudo bash -
sudo apt-get install -y nodejs
Alpine Linux: (--no-cache example is for building a docker image)
apk --no-cache add nodejs
### Install libavahi-compat-libdnssd-dev lib ### Install libavahi-compat-libdnssd-dev lib
Debian Jessie: For me i needed these libraries to be installed for my homebridge to work. See their [Homepage](https://homebridge.io) for installation instructions.
Below is what i did on my Debian Bullseye installation:
sudo apt-get install libavahi-compat-libdnssd-dev
Alpine Linux: (--no-cache example is for building a docker image) sudo apt install libavahi-compat-libdnssd-dev
apk --no-cache add dbus nodejs avahi avahi-compat-libdns_sd avahi-dev
### Install homebridge from NPM repository ### Install homebridge >=1.3.5 from NPM repository
npm install -g homebridge --unsafe-perm npm install -g homebridge --unsafe-perm
@ -53,104 +46,183 @@ Alpine Linux: (--no-cache example is for building a docker image)
## Configuration ## Configuration
You have to create a config.json in .homebridge directory. You'll find that directory in your home folder. This is an example config file which just uses this plugin and some example SmartHomeNG items. If you already have a working homebridge installation just add the platform section into your existing config. If you are a new homebridge user you have to create a `config.json` file in the `.homebridge` directory. You'll find that directory in your home folder.
### Common characteristics
The following characteristics are valid for all accessories.
Mandatory:
```json
{
"type": "OccupancySensor",
"name": "Presence kitchen",
}
```
Optional:
```json
{
"manufacturer": "Preussen",
"model": "Motion 360 KNX",
}
```
### Doorbell
TODO
### Fan
TODO
### LightBulb
TODO
### Occupancy sensor
TODO
### Motion sensor
TODO
### Contact sensor
TODO
### Switch
TODO
### Outlet
TODO
### Temperature sensor
TODO
### Thermostat
TODO
### WindowCovering
In addition to the common characteristics the following are available.
Mandatory:
```json
{
"CurrentPosition": "EG.Buero.Rolladen.Position",
"TargetPosition": "EG.Buero.Rolladen.ZielPosition",
}
```
The current moving state and direction is automatically derived from the difference between the current and target position.
Optional:
```json
{
"CurrentPositionMin": 0,
"CurrentPositionMax": 255,
"CurrentPositionInverted": true,
"TargetPositionMin": 0,
"TargetPositionMax": 255,
"TargetPositionInverted": true
}
```
HomeKit works with values between 0 and 100 where 0 is completely closed and 100 is open.
My KNX installation, as example, needs values between 0 and 255 where 255 is completely closed and 0 is open.
The above optional parameters allow you to specify the neede range for your device. If needed the values can be inverted at the same time. The plugin then transposes the values in both directions.
### Example configuration file
This is an example config file which just uses this plugin and some example SmartHomeNG items.
```json
{ {
"bridge": { "bridge": {
"name": "HBDEV", "name": "SmartHomeNG",
"username": "CC:22:3D:E3:DE:37", "username": "CC:22:3D:E3:DE:37",
"port": 51826, "port": 51138,
"pin": "031-45-154" "pin": "655-59-9284"
}, },
"platforms": [ "platforms": [
{ {
"platform": "SmartHomeNG", "platform": "SmartHomeNG",
"name": "SmartHomeNG", "name": "SmartHomeNG",
"host": "srvsmarthome.ha.swa.lu", "host": "smarthome.iot.wagener.family",
"accessories": [ "accessories": [
{ {
"name": "Temperatur Stube",
"type": "TemperatureSensor",
"currenttemperature": "EG.Stube.Temperatur"
},
{
"name": "Heizung Bad",
"type": "Thermostat",
"currenttemperature": "OG.Bad.Temperatur",
"targettemperature": "OG.Bad.Temperatur.Sollwert",
"targettemperatureminimum": 18,
"targettemperaturemaximum": 25
},
{
"name": "Ventilator Bad",
"type": "Fan",
"onoff": "OG.Bad.Ventilator"
},
{
"name": "Lüftung",
"type": "Fan",
"onoff": "EG.Lüftung"
"rotationSpeed": "EG.LüftungSpeed"
},
{
"name": "Schalter",
"type": "Switch",
"onoff": "EG.Esszimmer.Schalter"
},
{
"name": "Schaltsteckdose",
"type": "Outlet", "type": "Outlet",
"onoff": "EG.Esszimmer.Steckdose" "name": "Steckdose Esszimmer",
"On": "EG.Esszimmer.Steckdose"
}, },
{ {
"name": "Bürolicht",
"type": "Lightbulb",
"onoff": "EG.Buero.Licht"
},
{
"name": "Stubenlicht",
"type": "Lightbulb",
"onoff": "EG.Stube.Licht"
},
{
"name": "Schlafzimmerlicht",
"type": "Lightbulb",
"onoff": "OG.SZSS.Licht",
"brightness": "OG.SZSS.Licht.dimmen"
},
{
"name": "Rolladen Büro",
"type": "WindowCovering",
"updown": "EG.Buero.Rolladen.AufAb",
"currentposition": "EG.Buero.Rolladen.Position",
"targetposition": "EG.Buero.Rolladen.Position",
"inverted": true
},
{
"name": "Bewegungsmelder Küche",
"type": "MotionSensor",
"motionstate": "EG.Kueche.Praesenz"
},
{
"name": "Terassentür Küche",
"type": "ContactSensor",
"contactsensorstate": "EG.Kueche.Tuer",
"inverted": true
},
{
"name": "Fenster Esszimmer",
"type": "ContactSensor",
"contactsensorstate": "EG.Esszimmer.Fenster",
"inverted": true
},
{
"name": "Präsenzsmelder Esszimmer",
"type": "OccupancySensor", "type": "OccupancySensor",
"motiondetected": "EG.Esszimmer.Praesenz" "name": "Präsenz Büro",
"manufacturer": "Preussen",
"model": "Motion 360 KNX",
"OccupancyDetected": "EG.Buero.Praesenz"
},
{
"type": "MotionSensor",
"name": "Bewegung Flur",
"manufacturer": "Preussen",
"model": "Motion 360 KNX",
"MotionDetected": "EG.Flur.Praesenz"
},
{
"type": "ContactSensor",
"name": "Fenster Büro",
"ContactState": "EG.Buero.Fenster"
},
{
"type": "Doorbell",
"name": "Haustür",
"SinglePress": "Technik.Asterisk.Klingel"
},
{
"type": "Lightbulb",
"name": "Licht Büro",
"On": "EG.Buero.Deckenspots",
"Brightness": "EG.Buero.Deckenspots.dimmen",
"BrightnessMin": 0,
"BrightnessMax": 255
}
{
"type": "Lightbulb",
"name": "RGB Leiste Stube",
"On": "EG.Stube.Ledleiste",
"Brightness": "EG.Stube.Ledleiste.dimmen",
"BrightnessMin": 0,
"BrightnessMax": 255,
"R": "EG.Stube.Ledleiste.R.dimmen",
"RMin": 0,
"RMax": 255,
"G": "EG.Stube.Ledleiste.G.dimmen",
"GMin": 0,
"GMax": 255,
"B": "EG.Stube.Ledleiste.B.dimmen",
"BMin": 0,
"BMax": 255,
"W": "EG.Stube.Ledleiste.W.dimmen",
"WMin": 0,
"WMax": 255
},
{
"type": "Fan",
"name": "Ventilator Bad",
"Active": "OG.Bad.Ventilator"
},
{
"type": "Thermostat",
"name": "Temperatur Büro",
"CurrentTemperature": "EG.Buero.Temperatur",
"TargetTemperature": "EG.Buero.Temperatur.Sollwert",
"CurrentHeatingCoolingState": "EG.Buero.Temperatur.Modus"
},
{
"type": "WindowCovering",
"name": "Shutters office",
"CurrentPosition": "EG.Buero.Rolladen.Position",
"CurrentPositionMin": 0,
"CurrentPositionMax": 255,
"CurrentPositionInverted": true,
"TargetPosition": "EG.Buero.Rolladen.ZielPosition",
"TargetPositionMin": 0,
"TargetPositionMax": 255,
"TargetPositionInverted": true
} }
] ]
} }
], ],
@ -158,3 +230,5 @@ You have to create a config.json in .homebridge directory. You'll find that dire
"description": "This is my development config file." "description": "This is my development config file."
} }
```

11
package-lock.json generated
View File

@ -9,7 +9,6 @@
"version": "2.0.0", "version": "2.0.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"lodash": "^4.17.21",
"ws": "^8.4.2" "ws": "^8.4.2"
}, },
"devDependencies": { "devDependencies": {
@ -2336,11 +2335,6 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash.merge": { "node_modules/lodash.merge": {
"version": "4.6.2", "version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@ -5407,11 +5401,6 @@
"type-check": "~0.4.0" "type-check": "~0.4.0"
} }
}, },
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lodash.merge": { "lodash.merge": {
"version": "4.6.2", "version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",

View File

@ -27,7 +27,6 @@
"homebridge-plugin" "homebridge-plugin"
], ],
"dependencies": { "dependencies": {
"lodash": "^4.17.21",
"ws": "^8.4.2" "ws": "^8.4.2"
}, },
"devDependencies": { "devDependencies": {

View File

@ -0,0 +1,66 @@
import {
AccessoryPlugin,
CharacteristicValue,
Service,
Nullable,
} from 'homebridge';
import { SmartHomeNGPlatform } from '../platform';
export class Doorbell implements AccessoryPlugin {
private readonly deviceService: Service;
private readonly informationService: Service;
public name: string;
//private event = this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS;
constructor(private readonly platform: SmartHomeNGPlatform, private readonly accessory) {
this.name = accessory.name;
this.deviceService = new this.platform.Service.Doorbell(accessory.name);
// create handlers for required characteristics
this.deviceService.getCharacteristic(this.platform.Characteristic.ProgrammableSwitchEvent)
.onGet(this.handleProgrammableSwitchEventGet.bind(this));
this.informationService =
new this.platform.Service.AccessoryInformation()
.setCharacteristic(this.platform.Characteristic.Manufacturer, accessory.manufacturer)
.setCharacteristic(this.platform.Characteristic.Model, accessory.model)
.setCharacteristic(this.platform.Characteristic.SerialNumber, accessory.singlepress);
this.platform.shng.addMonitor(accessory.singlepress, this.shngSinglePressCallback.bind(this));
this.platform.log.info('Doorbell', accessory.name, 'created!');
}
identify(): void {
this.platform.log.info('Identify!');
}
getServices(): Service[] {
return [this.informationService, this.deviceService];
}
handleProgrammableSwitchEventGet(): Nullable<CharacteristicValue> {
this.platform.log.error(
'handleProgrammableSwitchEventGet:',
this.accessory.name, '=',
0,
);
return 0;
}
shngSinglePressCallback(value: unknown): void {
this.platform.log.debug('shngSinglePressCallback:', this.accessory.name, '=', value, '(' + typeof value + ')');
if (typeof value === 'boolean') {
if (value) {
this.deviceService.updateCharacteristic(
this.platform.Characteristic.ProgrammableSwitchEvent,
this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
);
}
} else {
this.platform.log.warn('Unknown type', typeof value, 'received for', this.accessory.name + ':', value);
}
}
}

View File

@ -0,0 +1,66 @@
import {
AccessoryPlugin,
CharacteristicValue,
Service,
Nullable,
} from 'homebridge';
import { SmartHomeNGPlatform } from '../platform';
export class Doorbell implements AccessoryPlugin {
private readonly deviceService: Service;
private readonly informationService: Service;
public name: string;
//private event = this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS;
constructor(private readonly platform: SmartHomeNGPlatform, private readonly accessory) {
this.name = accessory.name;
this.deviceService = new this.platform.Service.Doorbell(accessory.name);
// create handlers for required characteristics
this.deviceService.getCharacteristic(this.platform.Characteristic.ProgrammableSwitchEvent)
.onGet(this.handleProgrammableSwitchEventGet.bind(this));
this.informationService =
new this.platform.Service.AccessoryInformation()
.setCharacteristic(this.platform.Characteristic.Manufacturer, accessory.manufacturer)
.setCharacteristic(this.platform.Characteristic.Model, accessory.model)
.setCharacteristic(this.platform.Characteristic.SerialNumber, accessory.singlepress);
this.platform.shng.addMonitor(accessory.contactstate, this.shngCallback.bind(this));
this.platform.log.info('ContactSensor', accessory.name, 'created!');
}
identify(): void {
this.platform.log.info('Identify!');
}
getServices(): Service[] {
return [this.informationService, this.deviceService];
}
handleProgrammableSwitchEventGet(): Nullable<CharacteristicValue> {
this.platform.log.debug(
'handleProgrammableSwitchEventGet:',
this.accessory.name, '=',
0,
);
return this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS;
}
shngCallback(value: unknown): void {
this.platform.log.debug('shngCallback:', this.accessory.name, '=', value, '(' + typeof value + ')');
if (typeof value === 'boolean') {
if (value) {
this.deviceService.updateCharacteristic(
this.platform.Characteristic.ProgrammableSwitchEvent,
this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
);
}
} else {
this.platform.log.warn('Unknown type', typeof value, 'received for', this.accessory.name + ':', value);
}
}
}

View File

@ -19,6 +19,7 @@ import { TemperatureSensor } from './Accessories/TemperatureSensor';
import { Thermostat } from './Accessories/Thermostat'; import { Thermostat } from './Accessories/Thermostat';
import { WindowCovering } from './Accessories/WindowCovering'; import { WindowCovering } from './Accessories/WindowCovering';
import { ContactSensor } from './Accessories/ContactSensor'; import { ContactSensor } from './Accessories/ContactSensor';
import { Doorbell } from './Accessories/DoorBell';
function uncapitalizeKeys(obj): Record<string, unknown> { function uncapitalizeKeys(obj): Record<string, unknown> {
function isObject(o: unknown): boolean { function isObject(o: unknown): boolean {
@ -95,6 +96,11 @@ export class SmartHomeNGPlatform implements StaticPlatformPlugin {
devices.push(new ContactSensor(this, accessory)); devices.push(new ContactSensor(this, accessory));
break; break;
// Doorbell
case 'doorbell':
devices.push(new Doorbell(this, accessory));
break;
// Switch // Switch
case 'switch': case 'switch':
devices.push(new Switch(this, accessory)); devices.push(new Switch(this, accessory));