homebridge-deconz 0.0.10 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -6
- package/cli/deconz.js +12 -0
- package/config.schema.json +1 -0
- package/homebridge-ui/public/index.html +26 -0
- package/homebridge-ui/public/style.css +0 -0
- package/homebridge-ui/server.js +43 -0
- package/lib/Deconz/ApiClient.js +34 -1
- package/lib/Deconz/ApiResponse.js +1 -1
- package/lib/Deconz/Device.js +0 -7
- package/lib/Deconz/Resource.js +751 -25
- package/lib/DeconzAccessory/Contact.js +54 -0
- package/lib/DeconzAccessory/Gateway.js +102 -66
- package/lib/DeconzAccessory/Light.js +42 -37
- package/lib/DeconzAccessory/Motion.js +51 -0
- package/lib/DeconzAccessory/Sensor.js +35 -0
- package/lib/DeconzAccessory/Temperature.js +63 -0
- package/lib/DeconzAccessory/Thermostat.js +50 -0
- package/lib/DeconzAccessory/WarningDevice.js +56 -0
- package/lib/DeconzAccessory/WindowCovering.js +47 -0
- package/lib/DeconzAccessory/index.js +144 -2
- package/lib/DeconzPlatform.js +5 -2
- package/lib/DeconzService/AirPressure.js +43 -0
- package/lib/DeconzService/AirQuality.js +20 -11
- package/lib/DeconzService/Alarm.js +13 -9
- package/lib/DeconzService/Battery.js +53 -0
- package/lib/DeconzService/Button.js +9 -2
- package/lib/DeconzService/CarbonMonoxide.js +38 -0
- package/lib/DeconzService/Consumption.js +65 -0
- package/lib/DeconzService/Contact.js +60 -0
- package/lib/DeconzService/Daylight.js +132 -0
- package/lib/DeconzService/DeviceSettings.js +11 -0
- package/lib/DeconzService/Flag.js +52 -0
- package/lib/DeconzService/Humidity.js +37 -0
- package/lib/DeconzService/Leak.js +38 -0
- package/lib/DeconzService/Light.js +122 -172
- package/lib/DeconzService/LightLevel.js +54 -0
- package/lib/DeconzService/LightsResource.js +112 -0
- package/lib/DeconzService/Motion.js +101 -0
- package/lib/DeconzService/Outlet.js +76 -0
- package/lib/DeconzService/Power.js +83 -0
- package/lib/DeconzService/SensorsResource.js +96 -0
- package/lib/DeconzService/Smoke.js +38 -0
- package/lib/DeconzService/Status.js +53 -0
- package/lib/DeconzService/Switch.js +93 -0
- package/lib/DeconzService/Temperature.js +63 -0
- package/lib/DeconzService/Thermostat.js +175 -0
- package/lib/DeconzService/WarningDevice.js +68 -0
- package/lib/DeconzService/WindowCovering.js +162 -0
- package/lib/DeconzService/index.js +79 -25
- package/package.json +6 -5
- package/lib/Client/ApiError.js +0 -42
- package/lib/DeconzAccessory/Device.js +0 -69
- package/lib/DeconzService/Sensor.js +0 -61
@@ -0,0 +1,54 @@
|
|
1
|
+
// homebridge-deconz/lib/DeconzService/LightLevel.js
|
2
|
+
// Copyright © 2022 Erik Baauw. All rights reserved.
|
3
|
+
//
|
4
|
+
// Homebridge plugin for deCONZ.
|
5
|
+
|
6
|
+
'use strict'
|
7
|
+
|
8
|
+
const DeconzService = require('../DeconzService')
|
9
|
+
const Deconz = require('../Deconz')
|
10
|
+
|
11
|
+
const { lightLevelToLux } = Deconz.ApiClient
|
12
|
+
|
13
|
+
/**
|
14
|
+
* @memberof DeconzService
|
15
|
+
*/
|
16
|
+
class LightLevel extends DeconzService.SensorsResource {
|
17
|
+
constructor (accessory, resource, params = {}) {
|
18
|
+
params.Service = accessory.Services.hap.LightSensor
|
19
|
+
super(accessory, resource, params)
|
20
|
+
|
21
|
+
this.addCharacteristicDelegate({
|
22
|
+
key: 'lightlevel',
|
23
|
+
Characteristic: this.Characteristics.hap.CurrentAmbientLightLevel,
|
24
|
+
unit: ' lux'
|
25
|
+
})
|
26
|
+
|
27
|
+
this.addCharacteristicDelegate({
|
28
|
+
key: 'dark',
|
29
|
+
Characteristic: this.Characteristics.my.Dark
|
30
|
+
})
|
31
|
+
|
32
|
+
this.addCharacteristicDelegate({
|
33
|
+
key: 'daylight',
|
34
|
+
Characteristic: this.Characteristics.my.Daylight
|
35
|
+
})
|
36
|
+
|
37
|
+
this.addCharacteristicDelegates()
|
38
|
+
}
|
39
|
+
|
40
|
+
updateState (state) {
|
41
|
+
if (state.lightlevel != null) {
|
42
|
+
this.values.lightlevel = lightLevelToLux(state.lightlevel)
|
43
|
+
}
|
44
|
+
if (state.dark != null) {
|
45
|
+
this.values.dark = state.dark
|
46
|
+
}
|
47
|
+
if (state.daylight != null) {
|
48
|
+
this.values.daylight = state.daylight
|
49
|
+
}
|
50
|
+
super.updateState(state)
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
module.exports = LightLevel
|
@@ -0,0 +1,112 @@
|
|
1
|
+
// homebridge-deconz/lib/DeconzService/LightsResource.js
|
2
|
+
// Copyright © 2022 Erik Baauw. All rights reserved.
|
3
|
+
//
|
4
|
+
// Homebridge plugin for deCONZ.
|
5
|
+
|
6
|
+
'use strict'
|
7
|
+
|
8
|
+
const homebridgeLib = require('homebridge-lib')
|
9
|
+
const Deconz = require('../Deconz')
|
10
|
+
const DeconzService = require('../DeconzService')
|
11
|
+
|
12
|
+
const { HttpError } = Deconz.ApiClient
|
13
|
+
const { timeout } = homebridgeLib
|
14
|
+
|
15
|
+
class LightsResource extends DeconzService {
|
16
|
+
constructor (accessory, resource, params) {
|
17
|
+
super(accessory, resource, params)
|
18
|
+
this.rpath += resource.rtype === 'groups' ? '/action' : '/state'
|
19
|
+
|
20
|
+
this.targetState = {}
|
21
|
+
this.deferrals = []
|
22
|
+
}
|
23
|
+
|
24
|
+
addCharacteristicDelegates (params = {}) {
|
25
|
+
this.addCharacteristicDelegate({
|
26
|
+
key: 'lastSeen',
|
27
|
+
Characteristic: this.Characteristics.my.LastSeen,
|
28
|
+
silent: true
|
29
|
+
})
|
30
|
+
|
31
|
+
this.addCharacteristicDelegate({
|
32
|
+
key: 'statusFault',
|
33
|
+
Characteristic: this.Characteristics.hap.StatusFault
|
34
|
+
})
|
35
|
+
}
|
36
|
+
|
37
|
+
updateState (state) {
|
38
|
+
if (state.reachable != null) {
|
39
|
+
this.values.statusFault = state.reachable
|
40
|
+
? this.Characteristics.hap.StatusFault.NO_FAULT
|
41
|
+
: this.Characteristics.hap.StatusFault.GENERAL_FAULT
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
async identify () {
|
46
|
+
if (this.capabilities.alert) {
|
47
|
+
if (this.capabilities.breathe) {
|
48
|
+
await this.client.put(this.rpath, { alert: 'breathe' })
|
49
|
+
await timeout(1500)
|
50
|
+
await this.client.put(this.rpath, { alert: 'stop' })
|
51
|
+
}
|
52
|
+
await this.put(this.rpath, { alert: 'select' })
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
// Collect changes into a combined request.
|
57
|
+
put (state) {
|
58
|
+
for (const key in state) {
|
59
|
+
this.resource.body.state[key] = state[key]
|
60
|
+
this.targetState[key] = state[key]
|
61
|
+
}
|
62
|
+
this._put()
|
63
|
+
}
|
64
|
+
|
65
|
+
// Send the request (for the combined changes) to the gateway.
|
66
|
+
async _put () {
|
67
|
+
try {
|
68
|
+
if (this.updating) {
|
69
|
+
return
|
70
|
+
}
|
71
|
+
this.updating = true
|
72
|
+
if (this.platform.config.waitTimeUpdate > 0) {
|
73
|
+
await timeout(this.platform.config.waitTimeUpdate)
|
74
|
+
}
|
75
|
+
const targetState = this.targetState
|
76
|
+
this.targetState = {}
|
77
|
+
this.updating = false
|
78
|
+
if (
|
79
|
+
this.gateway.transitionTime !== this.gateway.defaultTransitionTime &&
|
80
|
+
targetState.transitiontime === undefined
|
81
|
+
) {
|
82
|
+
targetState.transitiontime = this.gateway.transitionTime * 10
|
83
|
+
this.gateway.resetTransitionTime()
|
84
|
+
}
|
85
|
+
if (this.capabilities.noTransition) {
|
86
|
+
if (
|
87
|
+
(
|
88
|
+
targetState.on != null || targetState.bri != null ||
|
89
|
+
targetState.bri_inc != null
|
90
|
+
) && (
|
91
|
+
targetState.xy != null || targetState.ct != null ||
|
92
|
+
targetState.hue != null || targetState.sat != null ||
|
93
|
+
targetState.effect != null
|
94
|
+
)
|
95
|
+
) {
|
96
|
+
targetState.transitiontime = 0
|
97
|
+
}
|
98
|
+
}
|
99
|
+
this.debug('PUT %s %j', this.rpath, targetState)
|
100
|
+
await this.client.put(this.rpath, targetState)
|
101
|
+
this.recentlyUpdated = true
|
102
|
+
await timeout(500)
|
103
|
+
this.recentlyUpdated = false
|
104
|
+
} catch (error) {
|
105
|
+
if (!(error instanceof HttpError)) {
|
106
|
+
this.warn(error)
|
107
|
+
}
|
108
|
+
}
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
module.exports = LightsResource
|
@@ -0,0 +1,101 @@
|
|
1
|
+
// homebridge-deconz/lib/DeconzService/Motion.js
|
2
|
+
// Copyright © 2022 Erik Baauw. All rights reserved.
|
3
|
+
//
|
4
|
+
// Homebridge plugin for deCONZ.
|
5
|
+
|
6
|
+
'use strict'
|
7
|
+
|
8
|
+
const DeconzService = require('../DeconzService')
|
9
|
+
|
10
|
+
/**
|
11
|
+
* @memberof DeconzService
|
12
|
+
*/
|
13
|
+
class Motion extends DeconzService.SensorsResource {
|
14
|
+
constructor (accessory, resource, params = {}) {
|
15
|
+
params.Service = accessory.Services.hap.MotionSensor
|
16
|
+
super(accessory, resource, params)
|
17
|
+
|
18
|
+
this.durationKey = resource.body.config.delay !== null ? 'delay' : 'duration'
|
19
|
+
this.sensitivitymax = resource.body.config.sensitivitymax
|
20
|
+
|
21
|
+
this.addCharacteristicDelegate({
|
22
|
+
key: 'motion',
|
23
|
+
Characteristic: this.Characteristics.hap.MotionDetected,
|
24
|
+
value: 0
|
25
|
+
})
|
26
|
+
|
27
|
+
this.addCharacteristicDelegate({
|
28
|
+
key: 'sensitivity',
|
29
|
+
Characteristic: this.Characteristics.eve.Sensitivity,
|
30
|
+
value: this.Characteristics.hap.TemperatureDisplayUnits.CELSIUS
|
31
|
+
}).on('didSet', async (value, fromHomeKit) => {
|
32
|
+
if (fromHomeKit) {
|
33
|
+
const sensitivity = value === this.Characteristics.eve.Sensitivity.HIGH
|
34
|
+
? this.sensitivitymax
|
35
|
+
: value === this.Characteristics.eve.Sensitivity.LOW
|
36
|
+
? 0
|
37
|
+
: Math.round(this.sensitivitymax / 2)
|
38
|
+
await this.put('/config', { sensitivity: sensitivity })
|
39
|
+
}
|
40
|
+
})
|
41
|
+
|
42
|
+
this.addCharacteristicDelegate({
|
43
|
+
key: 'duration',
|
44
|
+
Characteristic: this.Characteristics.eve.Duration,
|
45
|
+
unit: 's'
|
46
|
+
}).on('didSet', async (value, fromHomeKit) => {
|
47
|
+
if (fromHomeKit) {
|
48
|
+
const config = {}
|
49
|
+
config[this.durationKey] =
|
50
|
+
value === this.Characteristics.eve.Duration.VALID_VALUES[0] ? 0 : value
|
51
|
+
await this.put('/config', config)
|
52
|
+
}
|
53
|
+
})
|
54
|
+
|
55
|
+
this.addCharacteristicDelegate({
|
56
|
+
key: 'lastActivation',
|
57
|
+
Characteristic: this.Characteristics.eve.LastActivation,
|
58
|
+
silent: true
|
59
|
+
})
|
60
|
+
|
61
|
+
this.addCharacteristicDelegates()
|
62
|
+
|
63
|
+
this.update(resource.body)
|
64
|
+
}
|
65
|
+
|
66
|
+
updateState (state) {
|
67
|
+
if (state.presence != null) {
|
68
|
+
this.values.motion = state.presence
|
69
|
+
}
|
70
|
+
if (state.vibration != null) {
|
71
|
+
this.values.motion = state.vibration
|
72
|
+
}
|
73
|
+
if (state.tampered != null) {
|
74
|
+
this.values.tampered = state.tampered
|
75
|
+
}
|
76
|
+
super.updateState(state)
|
77
|
+
}
|
78
|
+
|
79
|
+
updateConfig (config) {
|
80
|
+
if (config[this.durationKey] != null) {
|
81
|
+
let duration
|
82
|
+
for (const value of this.Characteristics.eve.Duration.VALID_VALUES) {
|
83
|
+
duration = value
|
84
|
+
if (config[this.durationKey] <= value) {
|
85
|
+
break
|
86
|
+
}
|
87
|
+
}
|
88
|
+
this.values.duration = duration
|
89
|
+
}
|
90
|
+
if (config.sensitivity != null) {
|
91
|
+
this.values.sensitivity = config.sensitivity === this.sensitivitymax
|
92
|
+
? this.Characteristics.eve.Sensitivity.HIGH
|
93
|
+
: config.sensitivity === 0
|
94
|
+
? this.Characteristics.eve.Sensitivity.LOW
|
95
|
+
: this.Characteristics.eve.Sensitivity.MEDIUM
|
96
|
+
}
|
97
|
+
super.updateConfig(config)
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
module.exports = Motion
|
@@ -0,0 +1,76 @@
|
|
1
|
+
// homebridge-deconz/lib/DeconzService/Outlet.js
|
2
|
+
// Copyright © 2022 Erik Baauw. All rights reserved.
|
3
|
+
//
|
4
|
+
// Homebridge plugin for deCONZ.
|
5
|
+
|
6
|
+
'use strict'
|
7
|
+
|
8
|
+
const DeconzService = require('../DeconzService')
|
9
|
+
|
10
|
+
class Outlet extends DeconzService.LightsResource {
|
11
|
+
constructor (accessory, resource, params = {}) {
|
12
|
+
params.Service = accessory.Services.hap.Outlet
|
13
|
+
super(accessory, resource, params)
|
14
|
+
|
15
|
+
this.addCharacteristicDelegate({
|
16
|
+
key: 'on',
|
17
|
+
Characteristic: this.Characteristics.hap.On,
|
18
|
+
value: this.capabilities.on
|
19
|
+
? this.resource.body.state.on
|
20
|
+
: this.resource.body.state.all_on
|
21
|
+
}).on('didSet', (value, fromHomeKit) => {
|
22
|
+
if (fromHomeKit) {
|
23
|
+
this.put({ on: value })
|
24
|
+
}
|
25
|
+
})
|
26
|
+
|
27
|
+
if (!this.capabilities.on) {
|
28
|
+
this.addCharacteristicDelegate({
|
29
|
+
key: 'anyOn',
|
30
|
+
Characteristic: this.Characteristics.my.AnyOn,
|
31
|
+
value: this.resource.body.state.any_on
|
32
|
+
}).on('didSet', (value, fromHomeKit) => {
|
33
|
+
if (fromHomeKit) {
|
34
|
+
this.put({ on: value })
|
35
|
+
}
|
36
|
+
})
|
37
|
+
}
|
38
|
+
|
39
|
+
this.addCharacteristicDelegate({
|
40
|
+
key: 'outletInUse',
|
41
|
+
Characteristic: this.Characteristics.hap.OutletInUse,
|
42
|
+
value: 1
|
43
|
+
})
|
44
|
+
|
45
|
+
this.addCharacteristicDelegates()
|
46
|
+
|
47
|
+
this.settings = {
|
48
|
+
resetTimeout: this.platform.config.resetTimeout,
|
49
|
+
waitTimeUpdate: this.platform.config.waitTimeUpdate,
|
50
|
+
wallSwitch: false
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
updateState (state, rpath) {
|
55
|
+
for (const key in state) {
|
56
|
+
const value = state[key]
|
57
|
+
this.resource.body.state[key] = value
|
58
|
+
switch (key) {
|
59
|
+
case 'all_on':
|
60
|
+
this.values.on = value
|
61
|
+
break
|
62
|
+
case 'any_on':
|
63
|
+
this.values.anyOn = value
|
64
|
+
break
|
65
|
+
case 'on':
|
66
|
+
this.values.on = value
|
67
|
+
break
|
68
|
+
default:
|
69
|
+
break
|
70
|
+
}
|
71
|
+
}
|
72
|
+
super.updateState(state)
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
module.exports = Outlet
|
@@ -0,0 +1,83 @@
|
|
1
|
+
// homebridge-deconz/lib/DeconzService/Power.js
|
2
|
+
// Copyright © 2022 Erik Baauw. All rights reserved.
|
3
|
+
//
|
4
|
+
// Homebridge plugin for deCONZ.
|
5
|
+
|
6
|
+
'use strict'
|
7
|
+
|
8
|
+
const Deconz = require('../Deconz')
|
9
|
+
const DeconzService = require('../DeconzService')
|
10
|
+
|
11
|
+
const { dateToString } = Deconz.ApiClient
|
12
|
+
|
13
|
+
/**
|
14
|
+
* @memberof DeconzService
|
15
|
+
*/
|
16
|
+
class Power extends DeconzService.SensorsResource {
|
17
|
+
static addResource (service, resource) {
|
18
|
+
if (service.values.currentConsumption === undefined) {
|
19
|
+
service.addCharacteristicDelegate({
|
20
|
+
key: 'currentConsumption',
|
21
|
+
Characteristic: service.Characteristics.eve.CurrentConsumption,
|
22
|
+
unit: ' W'
|
23
|
+
})
|
24
|
+
}
|
25
|
+
|
26
|
+
if (resource.body.state.current !== undefined) {
|
27
|
+
service.addCharacteristicDelegate({
|
28
|
+
key: 'electricCurrent',
|
29
|
+
Characteristic: service.Characteristics.eve.ElectricCurrent,
|
30
|
+
unit: ' A'
|
31
|
+
})
|
32
|
+
}
|
33
|
+
|
34
|
+
if (resource.body.state.voltage !== undefined) {
|
35
|
+
service.addCharacteristicDelegate({
|
36
|
+
key: 'voltage',
|
37
|
+
Characteristic: service.Characteristics.eve.Voltage,
|
38
|
+
unit: ' V'
|
39
|
+
})
|
40
|
+
}
|
41
|
+
|
42
|
+
if (service.values.lastUpdated === undefined) {
|
43
|
+
service.addCharacteristicDelegate({
|
44
|
+
key: 'lastUpdated',
|
45
|
+
Characteristic: service.Characteristics.my.LastUpdated,
|
46
|
+
silent: true
|
47
|
+
})
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
static updateResourceState (service, state) {
|
52
|
+
if (state.power != null) {
|
53
|
+
service.values.currentConsumption = state.power
|
54
|
+
}
|
55
|
+
if (state.current != null) {
|
56
|
+
service.values.electricCurrent = state.current / 1000
|
57
|
+
}
|
58
|
+
if (state.voltage != null) {
|
59
|
+
service.values.voltage = state.voltage
|
60
|
+
}
|
61
|
+
if (state.lastupdated != null) {
|
62
|
+
service.values.lastUpdated = dateToString(state.lastupdated)
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
constructor (accessory, resource, params = {}) {
|
67
|
+
params.Service = accessory.Services.my.Resource
|
68
|
+
super(accessory, resource, params)
|
69
|
+
|
70
|
+
Power.addResource(this, resource)
|
71
|
+
|
72
|
+
super.addCharacteristicDelegates()
|
73
|
+
|
74
|
+
this.update(resource.body)
|
75
|
+
}
|
76
|
+
|
77
|
+
updateState (state) {
|
78
|
+
Power.updateResourceState(this.service, state)
|
79
|
+
super.updateState(state)
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
module.exports = Power
|
@@ -0,0 +1,96 @@
|
|
1
|
+
// homebridge-deconz/lib/DeconzService/SensorsResource.js
|
2
|
+
// Copyright © 2022 Erik Baauw. All rights reserved.
|
3
|
+
//
|
4
|
+
// Homebridge plugin for deCONZ.
|
5
|
+
|
6
|
+
'use strict'
|
7
|
+
|
8
|
+
const Deconz = require('../Deconz')
|
9
|
+
const DeconzService = require('../DeconzService')
|
10
|
+
|
11
|
+
const { dateToString, HttpError } = Deconz.ApiClient
|
12
|
+
|
13
|
+
/**
|
14
|
+
* @memberof DeconzService
|
15
|
+
*/
|
16
|
+
class SensorsResource extends DeconzService {
|
17
|
+
// constructor (accessory, resource, params) {
|
18
|
+
// super(accessory, resource, params)
|
19
|
+
// }
|
20
|
+
|
21
|
+
addCharacteristicDelegates (params = {}) {
|
22
|
+
if (!params.noLastUpdated) {
|
23
|
+
this.addCharacteristicDelegate({
|
24
|
+
key: 'lastUpdated',
|
25
|
+
Characteristic: this.Characteristics.my.LastUpdated,
|
26
|
+
silent: true
|
27
|
+
})
|
28
|
+
}
|
29
|
+
|
30
|
+
this.addCharacteristicDelegate({
|
31
|
+
key: 'enabled',
|
32
|
+
Characteristic: this.Characteristics.my.Enabled
|
33
|
+
}).on('didSet', (value) => {
|
34
|
+
this.values.statusActive = value
|
35
|
+
})
|
36
|
+
|
37
|
+
this.addCharacteristicDelegate({
|
38
|
+
key: 'statusActive',
|
39
|
+
Characteristic: this.Characteristics.hap.StatusActive
|
40
|
+
})
|
41
|
+
|
42
|
+
if (this.resource.body.config.reachable !== undefined) {
|
43
|
+
this.addCharacteristicDelegate({
|
44
|
+
key: 'statusFault',
|
45
|
+
Characteristic: this.Characteristics.hap.StatusFault
|
46
|
+
})
|
47
|
+
}
|
48
|
+
|
49
|
+
if (this.resource.body.state.tampered !== undefined && !params.noTampered) {
|
50
|
+
this.addCharacteristicDelegate({
|
51
|
+
key: 'tampered',
|
52
|
+
Characteristic: this.Characteristics.hap.StatusTampered
|
53
|
+
})
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
async identify () {
|
58
|
+
if (this.resource.body.config.alert) {
|
59
|
+
return this.put('/config', { alert: 'select' })
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
updateState (state) {
|
64
|
+
if (state.lastupdated != null) {
|
65
|
+
this.values.lastUpdated = dateToString(state.lastupdated)
|
66
|
+
}
|
67
|
+
if (state.tampered != null) {
|
68
|
+
this.values.tampered = state.tampered
|
69
|
+
? this.Characteristics.hap.StatusTampered.TAMPERED
|
70
|
+
: this.Characteristics.hap.StatusTampered.NOT_TAMPERED
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
updateConfig (config) {
|
75
|
+
if (config.on != null) {
|
76
|
+
this.values.enabled = !!config.on
|
77
|
+
}
|
78
|
+
if (config.reachable != null) {
|
79
|
+
this.values.statusFault = config.reachable
|
80
|
+
? this.Characteristics.hap.StatusFault.NO_FAULT
|
81
|
+
: this.Characteristics.hap.StatusFault.GENERAL_FAULT
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
async put (resource, body) {
|
86
|
+
try {
|
87
|
+
await this.client.put(this.rpath + resource, body)
|
88
|
+
} catch (error) {
|
89
|
+
if (!(error instanceof HttpError)) {
|
90
|
+
this.warn(error)
|
91
|
+
}
|
92
|
+
}
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
module.exports = SensorsResource
|
@@ -0,0 +1,38 @@
|
|
1
|
+
// homebridge-deconz/lib/DeconzService/Smoke.js
|
2
|
+
// Copyright © 2022 Erik Baauw. All rights reserved.
|
3
|
+
//
|
4
|
+
// Homebridge plugin for deCONZ.
|
5
|
+
|
6
|
+
'use strict'
|
7
|
+
|
8
|
+
const DeconzService = require('../DeconzService')
|
9
|
+
|
10
|
+
/**
|
11
|
+
* @memberof DeconzService
|
12
|
+
*/
|
13
|
+
class Smoke extends DeconzService.SensorsResource {
|
14
|
+
constructor (accessory, resource, params = {}) {
|
15
|
+
params.Service = accessory.Services.hap.SmokeSensor
|
16
|
+
super(accessory, resource, params)
|
17
|
+
|
18
|
+
this.addCharacteristicDelegate({
|
19
|
+
key: 'fire',
|
20
|
+
Characteristic: this.Characteristics.hap.SmokeDetected
|
21
|
+
})
|
22
|
+
|
23
|
+
super.addCharacteristicDelegates(params)
|
24
|
+
|
25
|
+
this.update(resource.body, resource.rpath)
|
26
|
+
}
|
27
|
+
|
28
|
+
updateState (state) {
|
29
|
+
if (state.fire != null || state.test != null) {
|
30
|
+
this.values.fire = state.fire || state.test
|
31
|
+
? this.Characteristics.hap.SmokeDetected.SMOKE_DETECTED
|
32
|
+
: this.Characteristics.hap.SmokeDetected.SMOKE_NOT_DETECTED
|
33
|
+
}
|
34
|
+
super.updateState(state)
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
module.exports = Smoke
|
@@ -0,0 +1,53 @@
|
|
1
|
+
// homebridge-deconz/lib/DeconzService/Status.js
|
2
|
+
// Copyright © 2022 Erik Baauw. All rights reserved.
|
3
|
+
//
|
4
|
+
// Homebridge plugin for deCONZ.
|
5
|
+
|
6
|
+
'use strict'
|
7
|
+
|
8
|
+
const DeconzService = require('../DeconzService')
|
9
|
+
|
10
|
+
/**
|
11
|
+
* @memberof DeconzService
|
12
|
+
*/
|
13
|
+
class Status extends DeconzService.SensorsResource {
|
14
|
+
constructor (accessory, resource, params = {}) {
|
15
|
+
params.Service = accessory.Services.my.Status
|
16
|
+
super(accessory, resource, params)
|
17
|
+
|
18
|
+
if (resource.capabilities.readonly) {
|
19
|
+
this.addCharacteristicDelegate({
|
20
|
+
key: 'status',
|
21
|
+
Characteristic: this.Characteristics.my.Status,
|
22
|
+
props: {
|
23
|
+
perms: [
|
24
|
+
this.Characteristic.Perms.READ, this.Characteristic.Perms.NOTIFY
|
25
|
+
]
|
26
|
+
}
|
27
|
+
})
|
28
|
+
} else {
|
29
|
+
this.addCharacteristicDelegate({
|
30
|
+
key: 'status',
|
31
|
+
Characteristic: this.Characteristics.my.Status,
|
32
|
+
props: resource.capabilities.props
|
33
|
+
}).on('didSet', async (value, fromHomeKit) => {
|
34
|
+
if (fromHomeKit) {
|
35
|
+
await this.put('/state', { status: value })
|
36
|
+
}
|
37
|
+
})
|
38
|
+
}
|
39
|
+
|
40
|
+
this.addCharacteristicDelegates()
|
41
|
+
|
42
|
+
this.update(resource.body)
|
43
|
+
}
|
44
|
+
|
45
|
+
updateState (state) {
|
46
|
+
if (state.status != null) {
|
47
|
+
this.values.status = state.status
|
48
|
+
}
|
49
|
+
super.updateState(state)
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
module.exports = Status
|
@@ -0,0 +1,93 @@
|
|
1
|
+
// homebridge-deconz/lib/DeconzService/Switch.js
|
2
|
+
// Copyright © 2022 Erik Baauw. All rights reserved.
|
3
|
+
//
|
4
|
+
// Homebridge plugin for deCONZ.
|
5
|
+
|
6
|
+
'use strict'
|
7
|
+
|
8
|
+
const DeconzService = require('../DeconzService')
|
9
|
+
|
10
|
+
/**
|
11
|
+
* @memberof DeconzService
|
12
|
+
*/
|
13
|
+
class Switch extends DeconzService.SensorsResource {
|
14
|
+
constructor (accessory, resource, params = {}) {
|
15
|
+
params.Service = accessory.Services.hap.ServiceLabel
|
16
|
+
super(accessory, resource, params)
|
17
|
+
|
18
|
+
this.addCharacteristicDelegate({
|
19
|
+
key: 'namespace',
|
20
|
+
Characteristic: this.Characteristics.hap.ServiceLabelNamespace,
|
21
|
+
value: resource.capabilities.namespace
|
22
|
+
})
|
23
|
+
|
24
|
+
this.addCharacteristicDelegates({ noLastUpdated: true })
|
25
|
+
|
26
|
+
this.buttonResources = {}
|
27
|
+
this.buttonServices = {}
|
28
|
+
this.hasRepeat = false
|
29
|
+
}
|
30
|
+
|
31
|
+
createButtonServices (resource) {
|
32
|
+
this.buttonResources[resource.rpath] = {
|
33
|
+
buttonEvent: resource.body.state.buttonevent,
|
34
|
+
lastUpdated: '',
|
35
|
+
toButtonEvent: resource.capabilities.toButtonEvent
|
36
|
+
}
|
37
|
+
for (const i in resource.capabilities.buttons) {
|
38
|
+
const { label, events, hasRepeat } = resource.capabilities.buttons[i]
|
39
|
+
if (hasRepeat) {
|
40
|
+
this.hasRepeat = hasRepeat
|
41
|
+
}
|
42
|
+
this.buttonServices[i] = new DeconzService.Button(this.accessoryDelegate, {
|
43
|
+
name: this.name + ' ' + label,
|
44
|
+
button: Number(i),
|
45
|
+
events: events,
|
46
|
+
hasRepeat: hasRepeat
|
47
|
+
})
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
updateState (state, rpath) {
|
52
|
+
const buttonResource = this.buttonResources[rpath]
|
53
|
+
if (buttonResource.lastUpdated === '') {
|
54
|
+
buttonResource.lastUpdated = state.lastupdated
|
55
|
+
} else if (
|
56
|
+
state.lastupdated != null &&
|
57
|
+
state.lastupdated !== buttonResource.lastUpdated
|
58
|
+
) {
|
59
|
+
buttonResource.lastUpdated = state.lastupdated
|
60
|
+
const oldValue = buttonResource.buttonEvent
|
61
|
+
if (state.buttonevent != null) {
|
62
|
+
buttonResource.buttonEvent = buttonResource.toButtonEvent == null
|
63
|
+
? state.buttonevent
|
64
|
+
: buttonResource.toButtonEvent(state.buttonevent)
|
65
|
+
}
|
66
|
+
// TODO handle repeat
|
67
|
+
this.updateButtonEvent(
|
68
|
+
buttonResource.buttonEvent, oldValue,
|
69
|
+
this.accessoryDelegate.settingsService.values.repeat
|
70
|
+
)
|
71
|
+
}
|
72
|
+
super.updateState(state)
|
73
|
+
}
|
74
|
+
|
75
|
+
updateConfig (config) {
|
76
|
+
// TODO handle change in devicemode
|
77
|
+
super.updateConfig(config)
|
78
|
+
}
|
79
|
+
|
80
|
+
updateButtonEvent (value, oldValue, repeat) {
|
81
|
+
const i = Math.floor(value / 1000)
|
82
|
+
if (this.buttonServices[i] != null) {
|
83
|
+
this.buttonServices[i].update(value, oldValue, repeat)
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
async identify () {
|
88
|
+
this.debug('hasRepeat: %j', this.hasRepeat)
|
89
|
+
return super.identify()
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
module.exports = Switch
|