homebridge-nb 1.3.4 → 1.4.1
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/cli/nb.js +5 -647
- package/lib/NbAccessory.js +17 -2
- package/lib/NbPlatform.js +1 -3
- package/lib/NbService.js +1 -1
- package/package.json +5 -3
- package/lib/NbClient.js +0 -201
- package/lib/NbDiscovery.js +0 -56
- package/lib/NbListener.js +0 -105
package/cli/nb.js
CHANGED
|
@@ -1,654 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
// Copyright © 2020-2023 Erik Baauw. All rights reserved.
|
|
3
|
+
// nb.js
|
|
5
4
|
//
|
|
6
|
-
// Homebridge
|
|
5
|
+
// Homebridge NB Tools.
|
|
6
|
+
// Copyright © 2018-2023 Erik Baauw. All rights reserved.
|
|
7
7
|
|
|
8
8
|
'use strict'
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
const NbClient = require('../lib/NbClient')
|
|
12
|
-
const NbDiscovery = require('../lib/NbDiscovery')
|
|
13
|
-
const NbListener = require('../lib/NbListener')
|
|
14
|
-
const homebridgeLib = require('homebridge-lib')
|
|
15
|
-
const packageJson = require('../package.json')
|
|
10
|
+
const { NbTool } = require('hb-nb-tools')
|
|
16
11
|
|
|
17
|
-
|
|
18
|
-
const { UsageError } = homebridgeLib.CommandLineParser
|
|
19
|
-
|
|
20
|
-
const usage = {
|
|
21
|
-
nb: `${b('nb')} [${b('-hVD')}] [${b('-H')} ${u('hostname')}[${b(':')}${u('port')}]] [${b('-T')} ${u('token')}] [${b('-t')} ${u('timeout')}] ${u('command')} [${u('argument')} ...]`,
|
|
22
|
-
|
|
23
|
-
discover: `${b('discover')} [${b('-h')}] [${b('-t')} ${u('timeout')}]`,
|
|
24
|
-
|
|
25
|
-
auth: `${b('auth')} [${b('-h')}]`,
|
|
26
|
-
info: `${b('info')} [${b('-h')}]`,
|
|
27
|
-
getlog: `${b('getlog')} [${b('-h')}]`,
|
|
28
|
-
clearlog: `${b('clearlog')} [${b('-h')}]`,
|
|
29
|
-
reboot: `${b('reboot')} [${b('-h')}]`,
|
|
30
|
-
fwupdate: `${b('fwupdate')} [${b('-h')}]`,
|
|
31
|
-
list: `${b('list')} [${b('-h')}]`,
|
|
32
|
-
|
|
33
|
-
lockState: `${b('lockState')} [${b('-h')}] ${u('nukiId')} ${u('deviceType')}`,
|
|
34
|
-
lock: `${b('lock')} [${b('-h')}] ${u('nukiId')} ${u('deviceType')}`,
|
|
35
|
-
unlock: `${b('unlock')} [${b('-h')}] ${u('nukiId')} ${u('deviceType')}`,
|
|
36
|
-
lockAction: `${b('lockAction')} [${b('-h')}] ${u('nukiId')} ${u('deviceType')} ${u('action')}`,
|
|
37
|
-
|
|
38
|
-
eventlog: `${b('eventlog')} [${b('-hns')}]`,
|
|
39
|
-
callbackList: `${b('callbackList')} [${b('-h')}]`,
|
|
40
|
-
callbackRemove: `${b('callbackRemove')} [${b('-h')}] ${u('id')}`
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const description = {
|
|
44
|
-
nb: 'Command line interface to Nuki bridge HTTP API.',
|
|
45
|
-
|
|
46
|
-
discover: 'Discover Nuki bridges.',
|
|
47
|
-
|
|
48
|
-
auth: 'Obtain Nuki bridge token.',
|
|
49
|
-
info: 'Get Nuki bridge info.',
|
|
50
|
-
getlog: 'Get Nuki bridge log.',
|
|
51
|
-
clearlog: 'Clear Nuki bridge log.',
|
|
52
|
-
reboot: 'Reboot Nuki bridge.',
|
|
53
|
-
fwupdate: 'Trigger a firmware update of the bridge and connected devices.',
|
|
54
|
-
list: 'Get list of paired Nuki devices.',
|
|
55
|
-
|
|
56
|
-
lockState: 'Refresh state from paired Nuki device.',
|
|
57
|
-
lock: 'Lock paired Nuki device.',
|
|
58
|
-
unlock: 'Unlock paired Nuki device.',
|
|
59
|
-
lockAction: 'Send action to paired Nuki device.',
|
|
60
|
-
|
|
61
|
-
eventlog: 'Add Nuki bridge subscription and listen for events.',
|
|
62
|
-
callbackList: 'List Nuki bridge subscriptions.',
|
|
63
|
-
callbackRemove: 'Remove Nuki bridge subscription.'
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const help = {
|
|
67
|
-
nb: `${description.nb}
|
|
68
|
-
|
|
69
|
-
Usage: ${usage.nb}
|
|
70
|
-
|
|
71
|
-
Parameters:
|
|
72
|
-
${b('-h')}, ${b('--help')}
|
|
73
|
-
Print this help and exit.
|
|
74
|
-
|
|
75
|
-
${b('-V')}, ${b('--version')}
|
|
76
|
-
Print version and exit.
|
|
77
|
-
|
|
78
|
-
${b('-D')}, ${b('--debug')}
|
|
79
|
-
Print debug messages for communication with Nuki bridge.
|
|
80
|
-
|
|
81
|
-
${b('-H')} ${u('hostname')}[${b(':')}${u('port')}], ${b('--host=')}${u('hostname')}[${b(':')}${u('port')}]
|
|
82
|
-
Connect to Nuki bridge at ${u('hostname')}${b(':8080')} or ${u('hostname')}${b(':')}${u('port')}.
|
|
83
|
-
You can also specify the hostname and port in the ${b('NB_HOST')} environment variable.
|
|
84
|
-
|
|
85
|
-
${b('-T')} ${u('token')}, ${b('--token=')}${u('token')}
|
|
86
|
-
Use token ${u('token')} to connect to the Nuki bridge.
|
|
87
|
-
You can also specify the token in the ${b('NB_TOKEN')} environment variable.
|
|
88
|
-
|
|
89
|
-
Commands:
|
|
90
|
-
${usage.discover}
|
|
91
|
-
${description.discover}
|
|
92
|
-
|
|
93
|
-
${usage.auth}
|
|
94
|
-
${description.auth}
|
|
95
|
-
|
|
96
|
-
${usage.info}
|
|
97
|
-
${description.info}
|
|
98
|
-
|
|
99
|
-
${usage.getlog}
|
|
100
|
-
${description.getlog}
|
|
101
|
-
|
|
102
|
-
${usage.clearlog}
|
|
103
|
-
${description.clearlog}
|
|
104
|
-
|
|
105
|
-
${usage.reboot}
|
|
106
|
-
${description.reboot}
|
|
107
|
-
|
|
108
|
-
${usage.fwupdate}
|
|
109
|
-
${description.fwupdate}
|
|
110
|
-
|
|
111
|
-
${usage.list}
|
|
112
|
-
${description.list}
|
|
113
|
-
|
|
114
|
-
${usage.lockState}
|
|
115
|
-
${description.lockState}
|
|
116
|
-
|
|
117
|
-
${usage.lock}
|
|
118
|
-
${description.lock}
|
|
119
|
-
|
|
120
|
-
${usage.unlock}
|
|
121
|
-
${description.unlock}
|
|
122
|
-
|
|
123
|
-
${usage.lockAction}
|
|
124
|
-
${description.lockAction}
|
|
125
|
-
|
|
126
|
-
${usage.eventlog}
|
|
127
|
-
${description.eventlog}
|
|
128
|
-
|
|
129
|
-
${usage.callbackList}
|
|
130
|
-
${description.callbackList}
|
|
131
|
-
|
|
132
|
-
${usage.callbackRemove}
|
|
133
|
-
${description.callbackRemove}
|
|
134
|
-
|
|
135
|
-
For more help, issue: ${b('nb')} ${u('command')} ${b('-h')}`,
|
|
136
|
-
discover: `${description.discover}
|
|
137
|
-
|
|
138
|
-
Usage: ${usage.discover}
|
|
139
|
-
|
|
140
|
-
Parameters:
|
|
141
|
-
${b('-h')}, ${b('--help')}
|
|
142
|
-
Print this help and exit.`,
|
|
143
|
-
auth: `${description.auth}
|
|
144
|
-
|
|
145
|
-
Usage: ${usage.auth}
|
|
146
|
-
|
|
147
|
-
Parameters:
|
|
148
|
-
${b('-h')}, ${b('--help')}
|
|
149
|
-
Print this help and exit.`,
|
|
150
|
-
info: `${description.info}
|
|
151
|
-
|
|
152
|
-
Usage: ${usage.info}
|
|
153
|
-
|
|
154
|
-
Parameters:
|
|
155
|
-
${b('-h')}, ${b('--help')}
|
|
156
|
-
Print this help and exit.`,
|
|
157
|
-
getlog: `${description.getlog}
|
|
158
|
-
|
|
159
|
-
Usage: ${usage.getlog}
|
|
160
|
-
|
|
161
|
-
Parameters:
|
|
162
|
-
${b('-h')}, ${b('--help')}
|
|
163
|
-
Print this help and exit.`,
|
|
164
|
-
clearlog: `${description.clearlog}
|
|
165
|
-
|
|
166
|
-
Usage: ${usage.clearlog}
|
|
167
|
-
|
|
168
|
-
Parameters:
|
|
169
|
-
${b('-h')}, ${b('--help')}
|
|
170
|
-
Print this help and exit.`,
|
|
171
|
-
reboot: `${description.reboot}
|
|
172
|
-
|
|
173
|
-
Usage: ${usage.reboot}
|
|
174
|
-
|
|
175
|
-
Parameters:
|
|
176
|
-
${b('-h')}, ${b('--help')}
|
|
177
|
-
Print this help and exit.`,
|
|
178
|
-
fwupdate: `${description.fwupdate}
|
|
179
|
-
|
|
180
|
-
Usage: ${usage.fwupdate}
|
|
181
|
-
|
|
182
|
-
Parameters:
|
|
183
|
-
${b('-h')}, ${b('--help')}
|
|
184
|
-
Print this help and exit.`,
|
|
185
|
-
list: `${description.list}
|
|
186
|
-
|
|
187
|
-
Usage: ${usage.list}
|
|
188
|
-
|
|
189
|
-
Parameters:
|
|
190
|
-
${b('-h')}, ${b('--help')}
|
|
191
|
-
Print this help and exit.`,
|
|
192
|
-
lockState: `${description.lockState}
|
|
193
|
-
|
|
194
|
-
Usage: ${usage.lockState}
|
|
195
|
-
|
|
196
|
-
Parameters:
|
|
197
|
-
${b('-h')}, ${b('--help')}
|
|
198
|
-
Print this help and exit.
|
|
199
|
-
|
|
200
|
-
${u('nukiId')}
|
|
201
|
-
The ID of the Nuki device (from ${b('nb list')}).
|
|
202
|
-
|
|
203
|
-
${u('deviceType')}
|
|
204
|
-
The type of the Nuki device (from ${b('nb list')}):
|
|
205
|
-
0: Smart Lock 1.0 or 2.0
|
|
206
|
-
2: Opener
|
|
207
|
-
3: Smart Door
|
|
208
|
-
4: Smart Lock 3.0`,
|
|
209
|
-
lock: `${description.lock}
|
|
210
|
-
|
|
211
|
-
Usage: ${usage.lock}
|
|
212
|
-
|
|
213
|
-
Parameters:
|
|
214
|
-
${b('-h')}, ${b('--help')}
|
|
215
|
-
Print this help and exit.
|
|
216
|
-
|
|
217
|
-
${u('nukiId')}
|
|
218
|
-
The ID of the Nuki device (from ${b('nb list')}).
|
|
219
|
-
|
|
220
|
-
${u('deviceType')}
|
|
221
|
-
The type of the Nuki device (from ${b('nb list')}):
|
|
222
|
-
0: Smart Lock 1.0 or 2.0
|
|
223
|
-
2: Opener
|
|
224
|
-
3: Smart Door
|
|
225
|
-
4: Smart Lock 3.0`,
|
|
226
|
-
unlock: `${description.unlock}
|
|
227
|
-
|
|
228
|
-
Usage: ${usage.unlock}
|
|
229
|
-
|
|
230
|
-
Parameters:
|
|
231
|
-
${b('-h')}, ${b('--help')}
|
|
232
|
-
Print this help and exit.
|
|
233
|
-
|
|
234
|
-
${u('nukiId')}
|
|
235
|
-
The ID of the Nuki device (from ${b('nb list')}).
|
|
236
|
-
|
|
237
|
-
${u('deviceType')}
|
|
238
|
-
The type of the Nuki device (from ${b('nb list')}):
|
|
239
|
-
0: Smart Lock 1.0 or 2.0
|
|
240
|
-
2: Opener
|
|
241
|
-
3: Smart Door
|
|
242
|
-
4: Smart Lock 3.0`,
|
|
243
|
-
lockAction: `${description.lockAction}
|
|
244
|
-
|
|
245
|
-
Usage: ${usage.lockAction}
|
|
246
|
-
|
|
247
|
-
Parameters:
|
|
248
|
-
${b('-h')}, ${b('--help')}
|
|
249
|
-
Print this help and exit.
|
|
250
|
-
|
|
251
|
-
${u('nukiId')}
|
|
252
|
-
The ID of the Nuki device (from ${b('nb list')}).
|
|
253
|
-
|
|
254
|
-
${u('deviceType')}
|
|
255
|
-
The type of the Nuki device (from ${b('nb list')}):
|
|
256
|
-
0: Smart Lock 1.0 or 2.0
|
|
257
|
-
2: Opener
|
|
258
|
-
3: Smart Door
|
|
259
|
-
4: Smart Lock 3.0
|
|
260
|
-
|
|
261
|
-
${u('action')}
|
|
262
|
-
The action to send to the Nuki device:
|
|
263
|
-
Smart Lock, Smart Door Opener
|
|
264
|
-
- ------------------------ -------------------------
|
|
265
|
-
1 unlock activate rto
|
|
266
|
-
2 lock deactivate rto
|
|
267
|
-
3 unlatch electric strike actuation
|
|
268
|
-
4 lock ‘n’ go activate continuous mode
|
|
269
|
-
5 lock ‘n’ go with unlatch deactivate continuous mode`,
|
|
270
|
-
eventlog: `${description.eventlog}
|
|
271
|
-
|
|
272
|
-
Usage: ${usage.eventlog}
|
|
273
|
-
|
|
274
|
-
Parameters:
|
|
275
|
-
${b('-h')}, ${b('--help')}
|
|
276
|
-
Print this help and exit.
|
|
277
|
-
|
|
278
|
-
${b('-n')}, ${b('--noWhiteSpace')}
|
|
279
|
-
Do not include spaces nor newlines in JSON output.
|
|
280
|
-
|
|
281
|
-
${b('-s')}, ${b('--service')}
|
|
282
|
-
Do not output timestamps (useful when running as service).`,
|
|
283
|
-
callbackList: `${description.callbackList}
|
|
284
|
-
|
|
285
|
-
Usage: ${usage.callbackList}
|
|
286
|
-
|
|
287
|
-
Parameters:
|
|
288
|
-
${b('-h')}, ${b('--help')}
|
|
289
|
-
Print this help and exit.`,
|
|
290
|
-
callbackRemove: `${description.callbackRemove}
|
|
291
|
-
|
|
292
|
-
Usage: ${usage.callbackRemove}
|
|
293
|
-
|
|
294
|
-
Parameters:
|
|
295
|
-
${b('-h')}, ${b('--help')}
|
|
296
|
-
Print this help and exit.
|
|
297
|
-
|
|
298
|
-
${u('id')}
|
|
299
|
-
Remove callback with ID ${u('id')} (from ${b('nb callbackList')}).`
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
class Main extends homebridgeLib.CommandLineTool {
|
|
303
|
-
constructor () {
|
|
304
|
-
super({ mode: 'command', debug: false })
|
|
305
|
-
this.usage = usage.ph
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
parseArguments () {
|
|
309
|
-
const parser = new homebridgeLib.CommandLineParser(packageJson)
|
|
310
|
-
const clargs = {
|
|
311
|
-
options: {
|
|
312
|
-
host: process.env.NB_HOST,
|
|
313
|
-
token: process.env.NB_TOKEN
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
parser
|
|
317
|
-
.help('h', 'help', help.nb)
|
|
318
|
-
.version('V', 'version')
|
|
319
|
-
.flag('D', 'debug', () => {
|
|
320
|
-
if (this.debugEnabled) {
|
|
321
|
-
this.setOptions({ vdebug: true })
|
|
322
|
-
} else {
|
|
323
|
-
this.setOptions({ debug: true, chalk: true })
|
|
324
|
-
}
|
|
325
|
-
})
|
|
326
|
-
.option('H', 'host', (value) => {
|
|
327
|
-
homebridgeLib.OptionParser.toHost('host', value, false, true)
|
|
328
|
-
clargs.options.host = value
|
|
329
|
-
})
|
|
330
|
-
.option('t', 'timeout', (value) => {
|
|
331
|
-
clargs.options.timeout = homebridgeLib.OptionParser.toInt(
|
|
332
|
-
'timeout', value, 1, 60, true
|
|
333
|
-
)
|
|
334
|
-
})
|
|
335
|
-
.option('T', 'token', (value) => {
|
|
336
|
-
clargs.options.token = homebridgeLib.OptionParser.toString(
|
|
337
|
-
'token', value, true, true
|
|
338
|
-
)
|
|
339
|
-
})
|
|
340
|
-
.parameter('command', (value) => {
|
|
341
|
-
if (usage[value] == null || typeof this[value] !== 'function') {
|
|
342
|
-
throw new UsageError(`${value}: unknown command`)
|
|
343
|
-
}
|
|
344
|
-
clargs.command = value
|
|
345
|
-
})
|
|
346
|
-
.remaining((list) => { clargs.args = list })
|
|
347
|
-
.parse()
|
|
348
|
-
return clargs
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
async main () {
|
|
352
|
-
try {
|
|
353
|
-
this.usage = usage.nb
|
|
354
|
-
const clargs = this.parseArguments()
|
|
355
|
-
this.jsonFormatter = new homebridgeLib.JsonFormatter({ sortKeys: true })
|
|
356
|
-
if (clargs.command !== 'discover') {
|
|
357
|
-
if (clargs.options.host == null) {
|
|
358
|
-
await this.fatal(`Missing host. Set ${b('NB_HOST')} or specify ${b('-H')}.`)
|
|
359
|
-
}
|
|
360
|
-
if (clargs.command === 'auth') {
|
|
361
|
-
clargs.options.timeout = 60
|
|
362
|
-
}
|
|
363
|
-
const name = clargs.options.host
|
|
364
|
-
this.client = new NbClient(clargs.options)
|
|
365
|
-
this.client
|
|
366
|
-
.on('error', (error) => {
|
|
367
|
-
this.log(
|
|
368
|
-
'%s: request %d: %s %s', name, error.request.id,
|
|
369
|
-
error.request.method, error.request.resource
|
|
370
|
-
)
|
|
371
|
-
this.warn(
|
|
372
|
-
'%s: request %d: error: %s', name, error.request.id, error
|
|
373
|
-
)
|
|
374
|
-
})
|
|
375
|
-
.on('request', (request) => {
|
|
376
|
-
this.debug(
|
|
377
|
-
'%s: request %d: %s %s', name, request.id,
|
|
378
|
-
request.method, request.resource
|
|
379
|
-
)
|
|
380
|
-
this.vdebug(
|
|
381
|
-
'%s: request %d: %s %s', name, request.id,
|
|
382
|
-
request.method, request.url
|
|
383
|
-
)
|
|
384
|
-
})
|
|
385
|
-
.on('response', (response) => {
|
|
386
|
-
this.vdebug(
|
|
387
|
-
'%s: request %d: response: %j', name, response.request.id,
|
|
388
|
-
response.body
|
|
389
|
-
)
|
|
390
|
-
this.debug(
|
|
391
|
-
'%s: request %d: %d %s', name, response.request.id,
|
|
392
|
-
response.statusCode, response.statusMessage
|
|
393
|
-
)
|
|
394
|
-
})
|
|
395
|
-
if (clargs.options.token == null && clargs.command !== 'auth') {
|
|
396
|
-
let args = ''
|
|
397
|
-
if (clargs.options.host !== process.env.NB_HOST) {
|
|
398
|
-
args += ' -H ' + clargs.options.host
|
|
399
|
-
}
|
|
400
|
-
await this.fatal(
|
|
401
|
-
`Missing token. Set ${b('NB_TOKEN')} or specify ${b('-T')}. Run ${b('nb' + args + ' auth')} to obtain the token.`
|
|
402
|
-
)
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
this.name = 'nb ' + clargs.command
|
|
406
|
-
this.usage = `${b('nb')} ${usage[clargs.command]}`
|
|
407
|
-
this.parser = new homebridgeLib.CommandLineParser(packageJson)
|
|
408
|
-
this.parser.help('h', 'help', help[clargs.command])
|
|
409
|
-
await this[clargs.command](clargs.args)
|
|
410
|
-
} catch (error) {
|
|
411
|
-
await this.fatal(error)
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
async discover (...args) {
|
|
416
|
-
const options = {}
|
|
417
|
-
this.parser
|
|
418
|
-
.option('t', 'timeout', (value, key) => {
|
|
419
|
-
options.timeout = homebridgeLib.OptionParser.toInt(
|
|
420
|
-
'timeout', value, 1, 60, true
|
|
421
|
-
)
|
|
422
|
-
})
|
|
423
|
-
.parse(...args)
|
|
424
|
-
const nbDiscovery = new NbDiscovery(options)
|
|
425
|
-
nbDiscovery
|
|
426
|
-
.on('error', (error) => {
|
|
427
|
-
this.log(
|
|
428
|
-
'%s: request %d: %s %s', error.request.name, error.request.id,
|
|
429
|
-
error.request.method, error.request.resource
|
|
430
|
-
)
|
|
431
|
-
this.warn(
|
|
432
|
-
'%s: request %d: error: %s', error.request.name, error.request.id, error
|
|
433
|
-
)
|
|
434
|
-
})
|
|
435
|
-
.on('request', (request) => {
|
|
436
|
-
this.debug(
|
|
437
|
-
'%s: request %d: %s %s', request.name, request.id,
|
|
438
|
-
request.method, request.resource
|
|
439
|
-
)
|
|
440
|
-
this.vdebug(
|
|
441
|
-
'%s: request %d: %s %s', request.name, request.id,
|
|
442
|
-
request.method, request.url
|
|
443
|
-
)
|
|
444
|
-
})
|
|
445
|
-
.on('response', (response) => {
|
|
446
|
-
this.vdebug(
|
|
447
|
-
'%s: request %d: response: %j', response.request.name, response.request.id,
|
|
448
|
-
response.body
|
|
449
|
-
)
|
|
450
|
-
this.debug(
|
|
451
|
-
'%s: request %d: %d %s', response.request.name, response.request.id,
|
|
452
|
-
response.statusCode, response.statusMessage
|
|
453
|
-
)
|
|
454
|
-
})
|
|
455
|
-
const bridges = await nbDiscovery.discover()
|
|
456
|
-
this.print(this.jsonFormatter.stringify(bridges))
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
async auth (...args) {
|
|
460
|
-
this.parser.parse(...args)
|
|
461
|
-
this.log('press button on Nuki bridge to obtain token')
|
|
462
|
-
const token = await this.client.auth()
|
|
463
|
-
this.print(token)
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
async info (...args) {
|
|
467
|
-
this.parser.parse(...args)
|
|
468
|
-
const response = await this.client.info()
|
|
469
|
-
this.print(this.jsonFormatter.stringify(response.body))
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
async getlog (...args) {
|
|
473
|
-
this.parser.parse(...args)
|
|
474
|
-
const response = await this.client.log()
|
|
475
|
-
this.print(this.jsonFormatter.stringify(response.body))
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
async clearlog (...args) {
|
|
479
|
-
this.parser.parse(...args)
|
|
480
|
-
const response = await this.client.clearlog()
|
|
481
|
-
this.print(this.jsonFormatter.stringify(response.body))
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
async reboot (...args) {
|
|
485
|
-
this.parser.parse(...args)
|
|
486
|
-
const response = await this.client.reboot()
|
|
487
|
-
this.print(this.jsonFormatter.stringify(response.body))
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
async fwupdate (...args) {
|
|
491
|
-
this.parser.parse(...args)
|
|
492
|
-
const response = await this.client.fwupdate()
|
|
493
|
-
this.print(this.jsonFormatter.stringify(response.body))
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
async list (...args) {
|
|
497
|
-
this.parser.parse(...args)
|
|
498
|
-
const response = await this.client.list()
|
|
499
|
-
this.print(this.jsonFormatter.stringify(response.body))
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
async lockState (...args) {
|
|
503
|
-
let nukiId
|
|
504
|
-
let deviceType
|
|
505
|
-
this.parser
|
|
506
|
-
.parameter('nukiId', (value) => {
|
|
507
|
-
nukiId = homebridgeLib.OptionParser.toInt(
|
|
508
|
-
'nukiId', value, 0, Infinity, true
|
|
509
|
-
)
|
|
510
|
-
})
|
|
511
|
-
.parameter('deviceType', (value) => {
|
|
512
|
-
deviceType = homebridgeLib.OptionParser.toInt(
|
|
513
|
-
'deviceType', value, 0, 2, true
|
|
514
|
-
)
|
|
515
|
-
})
|
|
516
|
-
.parse(...args)
|
|
517
|
-
const response = await this.client.lockState(nukiId, deviceType)
|
|
518
|
-
this.print(this.jsonFormatter.stringify(response.body))
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
async lock (...args) {
|
|
522
|
-
let nukiId
|
|
523
|
-
let deviceType
|
|
524
|
-
this.parser
|
|
525
|
-
.parameter('nukiId', (value) => {
|
|
526
|
-
nukiId = homebridgeLib.OptionParser.toInt(
|
|
527
|
-
'nukiId', value, 0, Infinity, true
|
|
528
|
-
)
|
|
529
|
-
})
|
|
530
|
-
.parameter('deviceType', (value) => {
|
|
531
|
-
deviceType = homebridgeLib.OptionParser.toInt(
|
|
532
|
-
'deviceType', value, 0, 2, true
|
|
533
|
-
)
|
|
534
|
-
})
|
|
535
|
-
.parse(...args)
|
|
536
|
-
const response = await this.client.lock(nukiId, deviceType)
|
|
537
|
-
this.print(this.jsonFormatter.stringify(response.body))
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
async unlock (...args) {
|
|
541
|
-
let nukiId
|
|
542
|
-
let deviceType
|
|
543
|
-
this.parser
|
|
544
|
-
.parameter('nukiId', (value) => {
|
|
545
|
-
nukiId = homebridgeLib.OptionParser.toInt(
|
|
546
|
-
'nukiId', value, 0, Infinity, true
|
|
547
|
-
)
|
|
548
|
-
})
|
|
549
|
-
.parameter('deviceType', (value) => {
|
|
550
|
-
deviceType = homebridgeLib.OptionParser.toInt(
|
|
551
|
-
'deviceType', value, 0, 2, true
|
|
552
|
-
)
|
|
553
|
-
})
|
|
554
|
-
.parse(...args)
|
|
555
|
-
const response = await this.client.unlock(nukiId, deviceType)
|
|
556
|
-
this.print(this.jsonFormatter.stringify(response.body))
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
async lockAction (...args) {
|
|
560
|
-
let nukiId
|
|
561
|
-
let deviceType
|
|
562
|
-
let action
|
|
563
|
-
this.parser
|
|
564
|
-
.parameter('nukiId', (value) => {
|
|
565
|
-
nukiId = homebridgeLib.OptionParser.toInt(
|
|
566
|
-
'nukiId', value, 0, Infinity, true
|
|
567
|
-
)
|
|
568
|
-
})
|
|
569
|
-
.parameter('deviceType', (value) => {
|
|
570
|
-
deviceType = homebridgeLib.OptionParser.toInt(
|
|
571
|
-
'deviceType', value, 0, 2, true
|
|
572
|
-
)
|
|
573
|
-
})
|
|
574
|
-
.parameter('action', (value) => {
|
|
575
|
-
action = homebridgeLib.OptionParser.toInt('action', value, 1, 5, true)
|
|
576
|
-
})
|
|
577
|
-
.parse(...args)
|
|
578
|
-
const response = await this.client.lockAction(nukiId, deviceType, action)
|
|
579
|
-
this.print(this.jsonFormatter.stringify(response.body))
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
async destroy () {
|
|
583
|
-
if (this.listener != null) {
|
|
584
|
-
const response = await this.client.callbackList()
|
|
585
|
-
for (const callback of response.body.callbacks) {
|
|
586
|
-
if (callback.url === this._callbackUrl) {
|
|
587
|
-
this.log(
|
|
588
|
-
'Removing subscription %s for %s', callback.id, callback.url
|
|
589
|
-
)
|
|
590
|
-
try {
|
|
591
|
-
await this.client.callbackRemove(callback.id)
|
|
592
|
-
} catch (error) {
|
|
593
|
-
this.error(error)
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
this.listener.removeClient(this.client)
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
async eventlog (...args) {
|
|
602
|
-
let noWhiteSpace = false
|
|
603
|
-
let mode = 'daemon'
|
|
604
|
-
this.parser
|
|
605
|
-
.flag('n', 'noWhiteSpace', () => { noWhiteSpace = true })
|
|
606
|
-
.flag('s', 'service', () => { mode = 'service' })
|
|
607
|
-
.parse(...args)
|
|
608
|
-
this.setOptions({ mode })
|
|
609
|
-
const jsonFormatter = new homebridgeLib.JsonFormatter({
|
|
610
|
-
sortKeys: true,
|
|
611
|
-
noWhiteSpace
|
|
612
|
-
})
|
|
613
|
-
|
|
614
|
-
this.listener = new NbListener()
|
|
615
|
-
this.listener
|
|
616
|
-
.on('error', (error) => { this.error(error) })
|
|
617
|
-
.on('listening', (url) => {
|
|
618
|
-
this.log('listening on %s', url)
|
|
619
|
-
})
|
|
620
|
-
.on('close', (url) => {
|
|
621
|
-
this.log('closed %s', url)
|
|
622
|
-
})
|
|
623
|
-
this.client.on('event', (event) => {
|
|
624
|
-
this.log('%s', jsonFormatter.stringify(event))
|
|
625
|
-
})
|
|
626
|
-
|
|
627
|
-
await this.client.init()
|
|
628
|
-
this._callbackUrl = await this.listener.addClient(this.client)
|
|
629
|
-
const response = await this.client.callbackAdd(this._callbackUrl)
|
|
630
|
-
if (!response.body.success) {
|
|
631
|
-
this.listener.removeClient(this.client)
|
|
632
|
-
this.error(response.body.message)
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
async callbackList (...args) {
|
|
637
|
-
this.parser.parse(...args)
|
|
638
|
-
const response = await this.client.callbackList()
|
|
639
|
-
this.print(this.jsonFormatter.stringify(response.body))
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
async callbackRemove (...args) {
|
|
643
|
-
let id
|
|
644
|
-
this.parser
|
|
645
|
-
.parameter('id', (value) => {
|
|
646
|
-
id = homebridgeLib.OptionParser.toInt('id', value, 0, Infinity, true)
|
|
647
|
-
})
|
|
648
|
-
.parse(...args)
|
|
649
|
-
const response = await this.client.callbackRemove(id)
|
|
650
|
-
this.print(this.jsonFormatter.stringify(response.body))
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
new Main().main()
|
|
12
|
+
new NbTool(require('../package.json')).main()
|
package/lib/NbAccessory.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const homebridgeLib = require('homebridge-lib')
|
|
9
9
|
const NbService = require('./NbService')
|
|
10
|
-
const NbClient = require('
|
|
10
|
+
const { NbClient } = require('hb-nb-tools')
|
|
11
11
|
|
|
12
12
|
class NbAccessory extends homebridgeLib.AccessoryDelegate {
|
|
13
13
|
constructor (bridge, params) {
|
|
@@ -136,7 +136,22 @@ class Bridge extends homebridgeLib.AccessoryDelegate {
|
|
|
136
136
|
await this.client.init()
|
|
137
137
|
this.values.firmware = this.client.firmware
|
|
138
138
|
this.context.firmware = this.values.firmware
|
|
139
|
-
|
|
139
|
+
if (this.values.firmware !== this.platform.packageJson.engines.nuki) {
|
|
140
|
+
this.warn(
|
|
141
|
+
'recommended version: Nuki Bridge v%s',
|
|
142
|
+
this.platform.packageJson.engines.nuki
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
switch (this.client.encryption) {
|
|
146
|
+
case 'none':
|
|
147
|
+
this.warn('using plain-text tokens')
|
|
148
|
+
break
|
|
149
|
+
case 'hashedToken':
|
|
150
|
+
this.warn('using deprecated hashed tokens')
|
|
151
|
+
break
|
|
152
|
+
default:
|
|
153
|
+
break
|
|
154
|
+
}
|
|
140
155
|
} catch (error) {
|
|
141
156
|
return
|
|
142
157
|
}
|
package/lib/NbPlatform.js
CHANGED
|
@@ -8,9 +8,7 @@
|
|
|
8
8
|
const events = require('events')
|
|
9
9
|
const homebridgeLib = require('homebridge-lib')
|
|
10
10
|
const NbAccessory = require('./NbAccessory')
|
|
11
|
-
const NbClient = require('
|
|
12
|
-
const NbDiscovery = require('./NbDiscovery')
|
|
13
|
-
const NbListener = require('./NbListener')
|
|
11
|
+
const { NbClient, NbDiscovery, NbListener } = require('hb-nb-tools')
|
|
14
12
|
|
|
15
13
|
class NbPlatform extends homebridgeLib.Platform {
|
|
16
14
|
constructor (log, configJson, homebridge) {
|
package/lib/NbService.js
CHANGED
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"displayName": "Homebridge NB",
|
|
5
5
|
"author": "Erik Baauw",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
|
-
"version": "1.
|
|
7
|
+
"version": "1.4.1",
|
|
8
8
|
"keywords": [
|
|
9
9
|
"homebridge-plugin",
|
|
10
10
|
"homekit",
|
|
@@ -19,10 +19,12 @@
|
|
|
19
19
|
},
|
|
20
20
|
"engines": {
|
|
21
21
|
"homebridge": "^1.6.0",
|
|
22
|
-
"node": "^18.
|
|
22
|
+
"node": "^18.16.0",
|
|
23
|
+
"nuki": "2.15.0"
|
|
23
24
|
},
|
|
24
25
|
"dependencies": {
|
|
25
|
-
"homebridge-lib": "~6.3.
|
|
26
|
+
"homebridge-lib": "~6.3.14",
|
|
27
|
+
"hb-nb-tools": "~1.0.1"
|
|
26
28
|
},
|
|
27
29
|
"scripts": {
|
|
28
30
|
"prepare": "standard",
|
package/lib/NbClient.js
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
// homebridge-nb/lib/NbClient.js
|
|
2
|
-
// Copyright © 2020-2023 Erik Baauw. All rights reserved.
|
|
3
|
-
//
|
|
4
|
-
// Homebridge plug-in for Nuki Bridge.
|
|
5
|
-
|
|
6
|
-
'use strict'
|
|
7
|
-
|
|
8
|
-
const crypto = require('crypto')
|
|
9
|
-
const homebridgeLib = require('homebridge-lib')
|
|
10
|
-
|
|
11
|
-
class NbClient extends homebridgeLib.HttpClient {
|
|
12
|
-
static get DeviceTypes () {
|
|
13
|
-
return {
|
|
14
|
-
SMARTLOCK: 0,
|
|
15
|
-
OPENER: 2,
|
|
16
|
-
SMARTDOOR: 3,
|
|
17
|
-
SMARTLOCK3: 4
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
static get LockStates () {
|
|
22
|
-
return {
|
|
23
|
-
UNCALIBRATED: 0,
|
|
24
|
-
LOCKED: 1,
|
|
25
|
-
UNLOCKING: 2,
|
|
26
|
-
UNLOCKED: 3,
|
|
27
|
-
LOCKING: 4,
|
|
28
|
-
UNLATCHED: 5,
|
|
29
|
-
UNLOCKED_LOCK_N_GO: 6,
|
|
30
|
-
UNLATCHING: 7,
|
|
31
|
-
MOTOR_BLOCKED: 254,
|
|
32
|
-
UNDEFINED: 255
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
static get DoorSensorStates () {
|
|
37
|
-
return {
|
|
38
|
-
DEACTIVATED: 0,
|
|
39
|
-
CLOSED: 2,
|
|
40
|
-
OPEN: 3,
|
|
41
|
-
UNKNOWN: 4,
|
|
42
|
-
CALIBRATING: 5
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
static get LockActions () {
|
|
47
|
-
return {
|
|
48
|
-
UNLOCK: 1,
|
|
49
|
-
LOCK: 2,
|
|
50
|
-
UNLATCH: 3,
|
|
51
|
-
LOCK_N_GO: 4,
|
|
52
|
-
LOCK_N_GO_WITH_UNLATCH: 5
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
static get OpenerModes () {
|
|
57
|
-
return {
|
|
58
|
-
DOOR_MODE: 2,
|
|
59
|
-
CONTINUOUS_MODE: 3
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
static get OpenerStates () {
|
|
64
|
-
return {
|
|
65
|
-
UNTRAINED: 0,
|
|
66
|
-
ONLINE: 1,
|
|
67
|
-
RTO_ACTIVE: 3,
|
|
68
|
-
OPEN: 5,
|
|
69
|
-
OPENING: 7,
|
|
70
|
-
BOOT_RUN: 253,
|
|
71
|
-
UNDEFINED: 255
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
static get OpenerActions () {
|
|
76
|
-
return {
|
|
77
|
-
ACTIVATE_RTO: 1,
|
|
78
|
-
DEACTIVATE_RTO: 2,
|
|
79
|
-
OPEN: 3,
|
|
80
|
-
ACTIVATE_CM: 4,
|
|
81
|
-
DEACTIVATE_CM: 5
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
static modelName (deviceType, firmware) {
|
|
86
|
-
switch (deviceType) {
|
|
87
|
-
case NbClient.DeviceTypes.SMARTLOCK:
|
|
88
|
-
if (firmware[0] === '1') {
|
|
89
|
-
return 'Smart Lock 1.0'
|
|
90
|
-
}
|
|
91
|
-
return 'Smart Lock 2.0'
|
|
92
|
-
case NbClient.DeviceTypes.OPENER:
|
|
93
|
-
return 'Opener'
|
|
94
|
-
case NbClient.DeviceTypes.SMARTDOOR:
|
|
95
|
-
return 'Smart Door'
|
|
96
|
-
case NbClient.DeviceTypes.SMARTLOCK3:
|
|
97
|
-
return 'Smart Lock 3.0'
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
constructor (params = {}) {
|
|
102
|
-
const _params = {
|
|
103
|
-
hashedToken: true,
|
|
104
|
-
port: 8080,
|
|
105
|
-
timeout: 5
|
|
106
|
-
}
|
|
107
|
-
const optionParser = new homebridgeLib.OptionParser(_params)
|
|
108
|
-
optionParser
|
|
109
|
-
.hostKey('host')
|
|
110
|
-
.intKey('timeout', 1, 60)
|
|
111
|
-
.stringKey('token')
|
|
112
|
-
.parse(params)
|
|
113
|
-
super({
|
|
114
|
-
host: _params.hostname + ':' + _params.port,
|
|
115
|
-
json: true,
|
|
116
|
-
keepAlive: true,
|
|
117
|
-
maxSockets: 1,
|
|
118
|
-
timeout: _params.timeout
|
|
119
|
-
})
|
|
120
|
-
this._params = _params
|
|
121
|
-
this._jsonFormatter = new homebridgeLib.JsonFormatter()
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
get id () { return this._params.id }
|
|
125
|
-
get name () { return 'Nuki_Bridge_' + this._params.id }
|
|
126
|
-
get firmware () { return this._params.firmware }
|
|
127
|
-
get token () { return this._params.token }
|
|
128
|
-
|
|
129
|
-
async auth () {
|
|
130
|
-
const response = await this._get('/auth')
|
|
131
|
-
if (response.body.success) {
|
|
132
|
-
this._params.token = response.body.token
|
|
133
|
-
return response.body.token
|
|
134
|
-
}
|
|
135
|
-
throw new Error('Nuki bridge button not pressed')
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async info () { return this._get('/info') }
|
|
139
|
-
async list () { return this._get('/list') }
|
|
140
|
-
async log () { return this._get('/log') }
|
|
141
|
-
async reboot () { return this._get('/reboot') }
|
|
142
|
-
async fwupdate () { return this._get('/fwupdate') }
|
|
143
|
-
|
|
144
|
-
async lockState (nukiId, deviceType) {
|
|
145
|
-
return this._get('/lockState', { nukiId, deviceType })
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async lock (nukiId, deviceType) {
|
|
149
|
-
return this._get('/lock', { nukiId, deviceType })
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async unlock (nukiId, deviceType) {
|
|
153
|
-
return this._get('/unlock', { nukiId, deviceType })
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
async lockAction (nukiId, deviceType, action) {
|
|
157
|
-
return this._get(
|
|
158
|
-
'/lockAction', { nukiId, deviceType, action }
|
|
159
|
-
)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
async init () {
|
|
163
|
-
const response = await this.info()
|
|
164
|
-
this._params.id = response.body.ids.serverId.toString(16).toUpperCase()
|
|
165
|
-
this._params.firmware = response.body.versions.firmwareVersion
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
async callbackAdd (url) {
|
|
169
|
-
return this._get('/callback/add', { url: encodeURIComponent(url) })
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
async callbackList () { return this._get('/callback/list') }
|
|
173
|
-
async callbackRemove (id) { return this._get('/callback/remove', { id }) }
|
|
174
|
-
|
|
175
|
-
async _get (resource, params = {}) {
|
|
176
|
-
// Append parameters
|
|
177
|
-
let separator = '?'
|
|
178
|
-
for (const param in params) {
|
|
179
|
-
resource += separator + param + '=' + params[param]
|
|
180
|
-
separator = '&'
|
|
181
|
-
}
|
|
182
|
-
let suffix = ''
|
|
183
|
-
if (resource !== '/auth') {
|
|
184
|
-
if (this._params.hashedToken) {
|
|
185
|
-
// Append hashed token
|
|
186
|
-
const hash = crypto.createHash('sha256')
|
|
187
|
-
const date = new Date().toISOString()
|
|
188
|
-
const ts = date.slice(0, 19) + 'Z'
|
|
189
|
-
const rnr = '1' + date.slice(20, 23)
|
|
190
|
-
hash.update([ts, rnr, this._params.token].join(','))
|
|
191
|
-
suffix = separator + 'ts=' + ts + '&rnr=' + rnr +
|
|
192
|
-
'&hash=' + hash.digest('hex')
|
|
193
|
-
} else {
|
|
194
|
-
suffix = separator + 'token=' + this._params.token
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return super.get(resource, undefined, suffix)
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
module.exports = NbClient
|
package/lib/NbDiscovery.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// homebridge-nb/lib/NbDiscovery.js
|
|
2
|
-
// Copyright © 2020-2023 Erik Baauw. All rights reserved.
|
|
3
|
-
//
|
|
4
|
-
// Homebridge plug-in for Nuki Bridge.
|
|
5
|
-
|
|
6
|
-
'use strict'
|
|
7
|
-
|
|
8
|
-
const homebridgeLib = require('homebridge-lib')
|
|
9
|
-
|
|
10
|
-
class NbDiscovery extends homebridgeLib.HttpClient {
|
|
11
|
-
constructor (params = {}) {
|
|
12
|
-
const config = {
|
|
13
|
-
timeout: 5
|
|
14
|
-
}
|
|
15
|
-
const optionParser = new homebridgeLib.OptionParser(config)
|
|
16
|
-
optionParser.intKey('timeout', 1, 60)
|
|
17
|
-
optionParser.parse(params)
|
|
18
|
-
super({
|
|
19
|
-
https: true,
|
|
20
|
-
host: 'api.nuki.io',
|
|
21
|
-
json: true,
|
|
22
|
-
keepAlive: false,
|
|
23
|
-
name: 'nuki server',
|
|
24
|
-
path: '/discover',
|
|
25
|
-
timeout: config.timeout
|
|
26
|
-
})
|
|
27
|
-
this.config = config
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async discover () {
|
|
31
|
-
const bridges = []
|
|
32
|
-
const response = await super.get('/bridges')
|
|
33
|
-
if (response == null) {
|
|
34
|
-
return bridges
|
|
35
|
-
}
|
|
36
|
-
for (const bridge of response.body.bridges) {
|
|
37
|
-
const client = new homebridgeLib.HttpClient({
|
|
38
|
-
host: bridge.ip + ':' + bridge.port,
|
|
39
|
-
path: '',
|
|
40
|
-
timeout: this.config.timeout,
|
|
41
|
-
validStatusCodes: [200, 401]
|
|
42
|
-
})
|
|
43
|
-
client
|
|
44
|
-
.on('error', (error) => { this.emit('error', error) })
|
|
45
|
-
.on('request', (request) => { this.emit('request', request) })
|
|
46
|
-
.on('response', (response) => { this.emit('response', response) })
|
|
47
|
-
try {
|
|
48
|
-
await client.get('/info')
|
|
49
|
-
bridges.push(bridge)
|
|
50
|
-
} catch (error) {}
|
|
51
|
-
}
|
|
52
|
-
return bridges
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
module.exports = NbDiscovery
|
package/lib/NbListener.js
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
// homebridge-nb/lib/NbListener.js
|
|
2
|
-
// Copyright © 2020-2023 Erik Baauw. All rights reserved.
|
|
3
|
-
//
|
|
4
|
-
// Homebridge plug-in for Nuki Bridge.
|
|
5
|
-
|
|
6
|
-
'use strict'
|
|
7
|
-
|
|
8
|
-
const events = require('events')
|
|
9
|
-
const http = require('http')
|
|
10
|
-
|
|
11
|
-
class NbListener extends events.EventEmitter {
|
|
12
|
-
constructor (port = 0) {
|
|
13
|
-
super()
|
|
14
|
-
this._myPort = port
|
|
15
|
-
this._clients = {}
|
|
16
|
-
this._clientsByName = {}
|
|
17
|
-
this._server = http.createServer((request, response) => {
|
|
18
|
-
let buffer = ''
|
|
19
|
-
request.on('data', (data) => {
|
|
20
|
-
buffer += data
|
|
21
|
-
})
|
|
22
|
-
request.on('end', async () => {
|
|
23
|
-
try {
|
|
24
|
-
request.body = buffer
|
|
25
|
-
if (request.method === 'GET' && request.url === '/notify') {
|
|
26
|
-
// Provide an easy way to check that listener is reachable.
|
|
27
|
-
response.writeHead(200, { 'Content-Type': 'text/html' })
|
|
28
|
-
response.write('<table>')
|
|
29
|
-
response.write(`<caption><h3>Listening to ${Object.keys(this._clients).length} clients</h3></caption>`)
|
|
30
|
-
response.write('<tr><th scope="col">Nuki Bridge</th>')
|
|
31
|
-
response.write('<th scope="col">IP Address</th>')
|
|
32
|
-
response.write('<th scope="col">Local IP Address</th>')
|
|
33
|
-
for (const name of Object.keys(this._clientsByName).sort()) {
|
|
34
|
-
const client = this._clientsByName[name]
|
|
35
|
-
response.write(`<tr><td>${name}</td><td>${client.address}</td>`)
|
|
36
|
-
response.write(`<td>${client.localAddress}</td></tr>`)
|
|
37
|
-
}
|
|
38
|
-
response.write('</table>')
|
|
39
|
-
} else if (request.method === 'POST') {
|
|
40
|
-
const array = request.url.split('/')
|
|
41
|
-
const client = this._clients[array[2]]
|
|
42
|
-
if (array[1] === 'notify' && client !== null) {
|
|
43
|
-
const obj = JSON.parse(request.body)
|
|
44
|
-
client.emit('event', obj)
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
response.end()
|
|
48
|
-
} catch (error) {
|
|
49
|
-
this.emit('error', error)
|
|
50
|
-
}
|
|
51
|
-
})
|
|
52
|
-
})
|
|
53
|
-
this._server
|
|
54
|
-
.on('error', (error) => { this.emit('error', error) })
|
|
55
|
-
.on('close', () => {
|
|
56
|
-
this.emit('close', this._callbackUrl)
|
|
57
|
-
delete this._callbackUrl
|
|
58
|
-
})
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async _listen () {
|
|
62
|
-
if (this._server.listening) {
|
|
63
|
-
return
|
|
64
|
-
}
|
|
65
|
-
return new Promise((resolve, reject) => {
|
|
66
|
-
try {
|
|
67
|
-
this._server.listen(this._myPort, '0.0.0.0', () => {
|
|
68
|
-
const address = this._server.address()
|
|
69
|
-
this._myIp = address.address
|
|
70
|
-
this._myPort = address.port
|
|
71
|
-
this._callbackUrl =
|
|
72
|
-
'http://' + this._myIp + ':' + this._myPort + '/notify'
|
|
73
|
-
/** Emitted when the web server has started.
|
|
74
|
-
* @event NbListener#listening
|
|
75
|
-
* @param {string} url - The url the web server is listening on.
|
|
76
|
-
*/
|
|
77
|
-
this.emit('listening', this._callbackUrl)
|
|
78
|
-
return resolve()
|
|
79
|
-
})
|
|
80
|
-
} catch (error) {
|
|
81
|
-
return reject(error)
|
|
82
|
-
}
|
|
83
|
-
})
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
async addClient (nbClient) {
|
|
87
|
-
this._clients[nbClient.id] = nbClient
|
|
88
|
-
this._clientsByName[nbClient.name] = nbClient
|
|
89
|
-
await this._listen()
|
|
90
|
-
const callbackUrl = 'http://' + nbClient.localAddress + ':' + this._myPort +
|
|
91
|
-
'/notify/' + nbClient.id
|
|
92
|
-
return callbackUrl
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async removeClient (nbClient) {
|
|
96
|
-
this.removeAllListeners(nbClient.id)
|
|
97
|
-
delete this._clientsByName[nbClient.name]
|
|
98
|
-
delete this._clients[nbClient.id]
|
|
99
|
-
if (Object.keys(this._clients).length === 0) {
|
|
100
|
-
await this._server.close()
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
module.exports = NbListener
|