homebridge-deconz 1.0.15 → 1.0.18
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/lib/Deconz/Resource.js +3 -0
- package/lib/DeconzAccessory/Gateway.js +61 -3
- package/lib/DeconzAccessory/Light.js +2 -0
- package/lib/DeconzAccessory/index.js +3 -4
- package/lib/DeconzService/LightsResource.js +0 -1
- package/lib/DeconzService/Motion.js +44 -0
- package/lib/DeconzService/SensorsResource.js +36 -3
- package/package.json +3 -3
package/lib/Deconz/Resource.js
CHANGED
@@ -665,9 +665,12 @@ class Gateway extends AccessoryDelegate {
|
|
665
665
|
let { serviceName } = device.resource
|
666
666
|
await this.importAccessoryType(serviceName)
|
667
667
|
if (DeconzAccessory[serviceName] == null) {
|
668
|
-
// this.warn('%s: %s:
|
668
|
+
// this.warn('%s: %s: accessory type not available', body.name, serviceName)
|
669
669
|
serviceName = 'Sensor'
|
670
670
|
}
|
671
|
+
if (this.context.settingsById[id]?.serviceName != null) {
|
672
|
+
await this.importServiceType(this.context.settingsById[id].serviceName)
|
673
|
+
}
|
671
674
|
for (const resourceServiceName of Object.keys(device.subtypesByServiceName)) {
|
672
675
|
await this.importServiceType(resourceServiceName)
|
673
676
|
}
|
@@ -1007,6 +1010,7 @@ class Gateway extends AccessoryDelegate {
|
|
1007
1010
|
this.context.fullState.config = config
|
1008
1011
|
this.context.fullState.lights = await this.client.get('/lights')
|
1009
1012
|
this.context.fullState.sensors = await this.client.get('/sensors')
|
1013
|
+
this.context.fullState.resourcelinks = await this.client.get('/resourcelinks')
|
1010
1014
|
if (this.nDevicesByRtype.groups > 0) {
|
1011
1015
|
this.context.fullState.groups = await this.client.get('/groups')
|
1012
1016
|
this.context.fullState.groups[0] = await this.client.get('/groups/0')
|
@@ -1030,6 +1034,54 @@ class Gateway extends AccessoryDelegate {
|
|
1030
1034
|
}
|
1031
1035
|
}
|
1032
1036
|
|
1037
|
+
/* Analyse blacklist resourcelinks.
|
1038
|
+
*/
|
1039
|
+
analyseResourcelinks (logUnsupported = false) {
|
1040
|
+
const warn = (logUnsupported ? this.warn : this.vdebug).bind(this)
|
1041
|
+
/** Blacklisted resources.
|
1042
|
+
*
|
1043
|
+
* Updated by
|
1044
|
+
* {@link DeconzAccessory.Gateway#analyseBlacklist analyseBlacklist()}.
|
1045
|
+
* @type {Object<string, boolean>}
|
1046
|
+
*/
|
1047
|
+
this.blacklist = {
|
1048
|
+
lights: {},
|
1049
|
+
sensors: {}
|
1050
|
+
}
|
1051
|
+
this.splitdevice = {
|
1052
|
+
lights: {},
|
1053
|
+
sensors: {}
|
1054
|
+
}
|
1055
|
+
for (const key in this.context.fullState.resourcelinks) {
|
1056
|
+
const link = this.context.fullState.resourcelinks[key]
|
1057
|
+
if (
|
1058
|
+
link.name === 'homebridge-deconz' && link.links != null &&
|
1059
|
+
link.description != null
|
1060
|
+
) {
|
1061
|
+
const type = link.description.toLowerCase()
|
1062
|
+
switch (type) {
|
1063
|
+
case 'migration':
|
1064
|
+
break
|
1065
|
+
case 'splitdevice':
|
1066
|
+
case 'blacklist':
|
1067
|
+
this.debug('/resourcelinks/%d: %d %s entries', key, link.links.length, type)
|
1068
|
+
for (const resource of link.links) {
|
1069
|
+
const rtype = resource.split('/')[1]
|
1070
|
+
const rid = resource.split('/')[2]
|
1071
|
+
if (this[type][rtype] == null) {
|
1072
|
+
warn('/resourcelinks/%d: %s: ignoring unsupported %s resource', key, resource, type)
|
1073
|
+
continue
|
1074
|
+
}
|
1075
|
+
this[type][rtype][rid] = true
|
1076
|
+
}
|
1077
|
+
break
|
1078
|
+
default:
|
1079
|
+
warn('/resourcelinks/%d: %s: ignoring unsupported resourcelink', key, type)
|
1080
|
+
}
|
1081
|
+
}
|
1082
|
+
}
|
1083
|
+
}
|
1084
|
+
|
1033
1085
|
/** Analyse the peristed full state of the gateway,
|
1034
1086
|
* adding, re-configuring, and deleting delegates for corresponding HomeKit
|
1035
1087
|
* accessories and services.
|
@@ -1094,6 +1146,7 @@ class Gateway extends AccessoryDelegate {
|
|
1094
1146
|
this.nDevicesByRtype = {}
|
1095
1147
|
|
1096
1148
|
this.vdebug('analysing resources...')
|
1149
|
+
this.analyseResourcelinks(params.logUnsupported)
|
1097
1150
|
for (const rtype of rtypes) {
|
1098
1151
|
this.deviceByRidByRtype[rtype] = {}
|
1099
1152
|
for (const rid in fullState[rtype]) {
|
@@ -1251,10 +1304,16 @@ class Gateway extends AccessoryDelegate {
|
|
1251
1304
|
* unsupported resources.
|
1252
1305
|
*/
|
1253
1306
|
analyseResource (rtype, rid, body, logUnsupported) {
|
1307
|
+
const warn = (logUnsupported ? this.warn : this.vdebug).bind(this)
|
1308
|
+
const debug = (logUnsupported ? this.debug : this.vdebug).bind(this)
|
1309
|
+
|
1254
1310
|
const resource = new Deconz.Resource(this, rtype, rid, body)
|
1255
1311
|
const { id, serviceName } = resource
|
1312
|
+
if (this.blacklist[rtype]?.[rid]) {
|
1313
|
+
debug('%s: /%s/%d: ignoring blacklisted resource', id, rtype, rid)
|
1314
|
+
return
|
1315
|
+
}
|
1256
1316
|
if (id === this.id || serviceName === '') {
|
1257
|
-
const debug = (logUnsupported ? this.debug : this.vdebug).bind(this)
|
1258
1317
|
debug(
|
1259
1318
|
'%s: /%s/%d: %s: ignoring unsupported %s type',
|
1260
1319
|
id, rtype, rid, body.type, rtype
|
@@ -1262,7 +1321,6 @@ class Gateway extends AccessoryDelegate {
|
|
1262
1321
|
return
|
1263
1322
|
}
|
1264
1323
|
if (serviceName == null) {
|
1265
|
-
const warn = (logUnsupported ? this.warn : this.vdebug).bind(this)
|
1266
1324
|
warn(
|
1267
1325
|
'%s: /%s/%d: %s: ignoring unknown %s type',
|
1268
1326
|
id, rtype, rid, body.type, rtype
|
@@ -26,6 +26,8 @@ class Light extends DeconzAccessory {
|
|
26
26
|
this.addPropertyDelegate({
|
27
27
|
key: 'serviceName',
|
28
28
|
value: device.resource.serviceName
|
29
|
+
}).on('didSet', (value) => {
|
30
|
+
gateway.context.settingsById[device.id].serviceName = value
|
29
31
|
})
|
30
32
|
|
31
33
|
this.service = this.createService(device.resource, {
|
@@ -139,8 +139,8 @@ class DeconzAccessory extends AccessoryDelegate {
|
|
139
139
|
}
|
140
140
|
if (DeconzService[params.serviceName] == null) {
|
141
141
|
this.warn(
|
142
|
-
'%s: %s:
|
143
|
-
resource.rpath,
|
142
|
+
'%s: %s: service type not available',
|
143
|
+
resource.rpath, params.serviceName
|
144
144
|
)
|
145
145
|
return
|
146
146
|
}
|
@@ -236,7 +236,6 @@ class DeconzAccessory extends AccessoryDelegate {
|
|
236
236
|
lowBatteryThreshold: this.servicesByServiceName?.Battery?.[0].values.lowBatteryThreshold,
|
237
237
|
// offset: this.servicesByServiceName?.Temperature?.[0].values.offset,
|
238
238
|
serviceName: this.values.serviceName,
|
239
|
-
splitLight: undefined,
|
240
239
|
venetianBlind: this.service.values.venetianBlind,
|
241
240
|
useExternalTemperature: this.service.values.useExternalTemperature,
|
242
241
|
wallSwitch: this.service.values.wallSwitch
|
@@ -293,7 +292,7 @@ class DeconzAccessory extends AccessoryDelegate {
|
|
293
292
|
case 'serviceName':
|
294
293
|
if (this.values.serviceName != null) {
|
295
294
|
value = OptionParser.toString(key, body[key])
|
296
|
-
if (
|
295
|
+
if (['Light', 'Outlet', 'Switch', 'Valve'].includes(value) == null) {
|
297
296
|
throw new Error(`${value}: illegal serviceName`)
|
298
297
|
}
|
299
298
|
this.values.serviceName = value
|
@@ -23,6 +23,15 @@ class Motion extends DeconzService.SensorsResource {
|
|
23
23
|
value: false
|
24
24
|
})
|
25
25
|
|
26
|
+
if (resource.body.state.distance !== undefined) {
|
27
|
+
this.addCharacteristicDelegate({
|
28
|
+
key: 'distance',
|
29
|
+
Characteristic: this.Characteristics.my.Distance,
|
30
|
+
unit: ' cm',
|
31
|
+
value: 0
|
32
|
+
})
|
33
|
+
}
|
34
|
+
|
26
35
|
this.addCharacteristicDelegate({
|
27
36
|
key: 'sensitivity',
|
28
37
|
Characteristic: this.Characteristics.eve.Sensitivity
|
@@ -50,6 +59,32 @@ class Motion extends DeconzService.SensorsResource {
|
|
50
59
|
}
|
51
60
|
})
|
52
61
|
|
62
|
+
if (resource.body.config.detectionrange !== undefined) {
|
63
|
+
this.addCharacteristicDelegate({
|
64
|
+
key: 'detectionRange',
|
65
|
+
Characteristic: this.Characteristics.my.DetectionRange,
|
66
|
+
unit: ' cm',
|
67
|
+
value: 600
|
68
|
+
}).on('didSet', async (value, fromHomeKit) => {
|
69
|
+
if (fromHomeKit) {
|
70
|
+
const detectionrange = Math.max(0, Math.min(value, 600))
|
71
|
+
await this.putConfig({ detectionrange })
|
72
|
+
}
|
73
|
+
})
|
74
|
+
}
|
75
|
+
|
76
|
+
if (resource.body.config.resetpresence !== undefined) {
|
77
|
+
this.addCharacteristicDelegate({
|
78
|
+
key: 'reset',
|
79
|
+
Characteristic: this.Characteristics.my.Reset,
|
80
|
+
value: false
|
81
|
+
}).on('didSet', async (value, fromHomeKit) => {
|
82
|
+
if (fromHomeKit) {
|
83
|
+
await this.put('/config', { resetpresence: value })
|
84
|
+
}
|
85
|
+
})
|
86
|
+
}
|
87
|
+
|
53
88
|
this.addCharacteristicDelegates()
|
54
89
|
|
55
90
|
this.update(resource.body, resource.rpath)
|
@@ -59,6 +94,9 @@ class Motion extends DeconzService.SensorsResource {
|
|
59
94
|
if (state.presence != null) {
|
60
95
|
this.values.motion = state.presence
|
61
96
|
}
|
97
|
+
if (state.distance != null) {
|
98
|
+
this.values.distance = state.distance
|
99
|
+
}
|
62
100
|
if (state.vibration != null) {
|
63
101
|
this.values.motion = state.vibration
|
64
102
|
}
|
@@ -83,6 +121,12 @@ class Motion extends DeconzService.SensorsResource {
|
|
83
121
|
? this.Characteristics.eve.Sensitivity.LOW
|
84
122
|
: this.Characteristics.eve.Sensitivity.MEDIUM
|
85
123
|
}
|
124
|
+
if (config.detectionrange != null) {
|
125
|
+
this.values.detectionRange = config.detectionrange
|
126
|
+
}
|
127
|
+
if (config.resetpresence != null) {
|
128
|
+
this.values.reset = config.resetpresence
|
129
|
+
}
|
86
130
|
super.updateConfig(config)
|
87
131
|
}
|
88
132
|
}
|
@@ -3,6 +3,8 @@
|
|
3
3
|
//
|
4
4
|
// Homebridge plugin for deCONZ.
|
5
5
|
|
6
|
+
import { timeout } from 'homebridge-lib'
|
7
|
+
|
6
8
|
import { ApiClient } from 'hb-deconz-tools/ApiClient'
|
7
9
|
|
8
10
|
import { DeconzService } from '../DeconzService/index.js'
|
@@ -13,9 +15,12 @@ const { dateToString } = ApiClient
|
|
13
15
|
* @memberof DeconzService
|
14
16
|
*/
|
15
17
|
class SensorsResource extends DeconzService {
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
constructor (accessory, resource, params) {
|
19
|
+
super(accessory, resource, params)
|
20
|
+
|
21
|
+
this.updating = 0
|
22
|
+
this.targetConfig = {}
|
23
|
+
}
|
19
24
|
|
20
25
|
addCharacteristicDelegates (params = {}) {
|
21
26
|
if (!params.noLastUpdated) {
|
@@ -83,6 +88,34 @@ class SensorsResource extends DeconzService {
|
|
83
88
|
return this.put('/config', { alert: 'select' })
|
84
89
|
}
|
85
90
|
}
|
91
|
+
|
92
|
+
// Collect config changes into a combined request.
|
93
|
+
async putConfig (config) {
|
94
|
+
for (const key in config) {
|
95
|
+
this.resource.body.config[key] = config[key]
|
96
|
+
this.targetConfig[key] = config[key]
|
97
|
+
}
|
98
|
+
return this._putConfig()
|
99
|
+
}
|
100
|
+
|
101
|
+
// Send the request (for the combined state changes) to the gateway.
|
102
|
+
async _putConfig () {
|
103
|
+
try {
|
104
|
+
if (this.platform.config.waitTimeUpdate > 0) {
|
105
|
+
this.updating++
|
106
|
+
await timeout(this.platform.config.waitTimeUpdate)
|
107
|
+
if (--this.updating > 0) {
|
108
|
+
return
|
109
|
+
}
|
110
|
+
}
|
111
|
+
const targetConfig = this.targetConfig
|
112
|
+
this.targetConfig = {}
|
113
|
+
await this.put('/config', targetConfig)
|
114
|
+
// this.recentlyUpdated = true
|
115
|
+
// await timeout(500)
|
116
|
+
// this.recentlyUpdated = false
|
117
|
+
} catch (error) { this.warn(error) }
|
118
|
+
}
|
86
119
|
}
|
87
120
|
|
88
121
|
DeconzService.SensorsResource = SensorsResource
|
package/package.json
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
"ebaauw"
|
8
8
|
],
|
9
9
|
"license": "Apache-2.0",
|
10
|
-
"version": "1.0.
|
10
|
+
"version": "1.0.18",
|
11
11
|
"keywords": [
|
12
12
|
"homebridge-plugin",
|
13
13
|
"homekit",
|
@@ -26,13 +26,13 @@
|
|
26
26
|
"ui": "cli/ui.js"
|
27
27
|
},
|
28
28
|
"engines": {
|
29
|
-
"deCONZ": "2.
|
29
|
+
"deCONZ": "2.28.1",
|
30
30
|
"homebridge": "^1.8.4||^2.0.0-beta",
|
31
31
|
"node": "^20||^18"
|
32
32
|
},
|
33
33
|
"dependencies": {
|
34
34
|
"hb-deconz-tools": "~2.0.3",
|
35
|
-
"homebridge-lib": "~7.0.
|
35
|
+
"homebridge-lib": "~7.0.8"
|
36
36
|
},
|
37
37
|
"scripts": {
|
38
38
|
"prepare": "standard && rm -rf out && jsdoc -c jsdoc.json",
|