homebridge-lib 6.3.6 → 6.3.7

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/hap.js CHANGED
@@ -9,84 +9,6 @@
9
9
 
10
10
  'use strict'
11
11
 
12
- const homebridgeLib = require('../index')
12
+ const { HapTool } = require('../index')
13
13
 
14
- const Bonjour = require('bonjour-hap')
15
-
16
- const { b, u } = homebridgeLib.CommandLineTool
17
-
18
- const usage = `${b('hap')} [${b('-hVlrs')}] [${b('-t')} ${u('timeout')}]`
19
- const help = `Logger for HomeKit accessory announcements.
20
-
21
- Usage: ${usage}
22
-
23
- Search for HomeKit accessory announcements
24
- Parameters:
25
- ${b('-h')} Print this help and exit.
26
- ${b('-V')} Print version and exit.
27
- ${b('-d')} Listen for Bonjour alive broadcasts instead of searching.
28
- ${b('-s')} Do not output timestamps (useful when running as service).
29
- ${b('-t')} ${u('timeout')} Search for ${u('timeout')} seconds instead of default ${b('5')}.`
30
-
31
- class Main extends homebridgeLib.CommandLineTool {
32
- constructor () {
33
- super()
34
- this.usage = usage
35
- this.options = { timeout: 15 }
36
- }
37
-
38
- parseArguments () {
39
- const parser = new homebridgeLib.CommandLineParser()
40
- parser
41
- .help('h', 'help', help)
42
- .version('V', 'version')
43
- .flag('l', 'listen', (key) => { this.options.mode = 'daemon' })
44
- .flag('s', 'service', (key) => { this.options.mode = 'service' })
45
- .option('t', 'timeout', (value, key) => {
46
- this.options.timeout = homebridgeLib.OptionParser.toInt(
47
- 'timeout', value, 1, 60, true
48
- )
49
- })
50
- .parse()
51
- }
52
-
53
- onUp (obj) {
54
- delete obj.rawTxt
55
- this.log('found accessory: %s', obj.name, this.jsonFormatter.stringify(obj))
56
- }
57
-
58
- async main () {
59
- try {
60
- this.parseArguments()
61
- this.jsonFormatter = new homebridgeLib.JsonFormatter(
62
- this.options.mode === 'service'
63
- ? { noWhiteSpace: true, sortKeys: true }
64
- : { sortKeys: true }
65
- )
66
- if (this.options.mode) {
67
- this.setOptions({ mode: this.options.mode })
68
- } else {
69
- setTimeout(() => {
70
- this.log('search done')
71
- bonjour4.destroy()
72
- // bonjour6.destroy()
73
- }, this.options.timeout * 1000)
74
- }
75
- this.log('searching for HomeKit accessories')
76
- const bonjour4 = new Bonjour()
77
- const browser4 = bonjour4.find({ type: 'hap' })
78
- browser4.on('up', this.onUp.bind(this))
79
- // const bonjour6 = new Bonjour({
80
- // type: 'udp6',
81
- // interface: '::%en0', // TODO: how to determine the interface?!
82
- // ip: 'ff02::fb'
83
- // })
84
- // const browser6 = bonjour6.find({ type: 'hap' })
85
- // browser6.on('up', this.onUp.bind(this))
86
- } catch (error) {
87
- await this.fatal(error)
88
- }
89
- }
90
- }
91
-
92
- new Main().main()
14
+ new HapTool().main()
package/cli/json.js CHANGED
@@ -9,158 +9,6 @@
9
9
 
10
10
  'use strict'
11
11
 
12
- const homebridgeLib = require('../index')
12
+ const { JsonTool } = require('../index')
13
13
 
14
- const fs = require('fs')
15
- const util = require('util')
16
- const zlib = require('zlib')
17
-
18
- const gunzip = util.promisify(zlib.unzip)
19
-
20
- const { b, u } = homebridgeLib.CommandLineTool
21
-
22
- const usage = `${b('json')} [${b('-hVsnjuatlkv')}] [${b('-p')} path] [${b('-d')} depth] [${b('-c')} ${u('string')}]... [${u('file')}]...`
23
- const help = `JSON formatter.
24
-
25
- Usage: ${usage}
26
-
27
- By default, ${b('json')} reads JSON from stdin, formats it, and prints it to stdout.
28
-
29
- Parameters:
30
- ${b('-h')}, ${b('--help')}
31
- Print this help and exit.
32
-
33
- ${b('-V')}, ${b('--version')}
34
- Print version and exit.
35
-
36
- ${b('-s')}, ${b('--sortKeys')}
37
- Sort object key/value pairs alphabetically on key.
38
-
39
- ${b('-n')}, ${b('--noWhiteSpace')}
40
- Do not include spaces nor newlines in output.
41
-
42
- ${b('-j')}, ${b('--jsonArray')}
43
- Output JSON array of objects for each key/value pair.
44
- Each object contains two key/value pairs:
45
- - key ${b('keys')} with an array of keys as value;
46
- - key ${b('value')} with the value as value.
47
-
48
- ${b('-u')}, ${b('--joinKeys')}
49
- Output JSON array of objects for each key/value pair.
50
- Each object contains one key/value pair:
51
- the path (concatenated keys separated by ${b('/')} as key and the value as value.
52
-
53
- ${b('-a')}, ${b('--ascii')}
54
- Output ${u('path')}${b(':')}${u('value')} in plain text instead of JSON.
55
-
56
- ${b('-t')}, ${b('--topOnly')}
57
- Limit output to top-level key/values.
58
-
59
- ${b('-p')} ${u('path')}, ${b('--fromPath=')}${u('path')}
60
- Limit output to key/values under ${u('path')}. Set top level below ${u('path')}.
61
-
62
- ${b('-d')} ${u('depth')}, ${b('--maxDepth=')}${u('depth')}
63
- Limit output to levels above ${u('depth')}.
64
-
65
- ${b('-l')}, ${b('--leavesOnly')}
66
- Limit output to leaf (non-array, non-object) key/values.
67
-
68
- ${b('-k')}, ${b('--keysOnly')}
69
- Limit output to keys. With ${b('-u')} output JSON array of paths.
70
-
71
- ${b('-v')}, ${b('--valuesOnly')}
72
- Limit output to values. With ${b('-u')} output JSON array of values.
73
-
74
- ${b('-c')} ${u('string')}, ${b('--string=')}${u('string')}
75
- Read JSON from ${u('string')} instead of from stdin.
76
-
77
- ${u('file')}
78
- Read JSON from ${u('file')} instead of from stdin.
79
- When the file name ends in ${b('.gz')}, it is assumed to be a gzip file and
80
- uncompressed automatically.`
81
-
82
- class Main extends homebridgeLib.CommandLineTool {
83
- constructor () {
84
- super()
85
- this.usage = usage
86
- this.options = {}
87
- this.stringList = []
88
- this.fileList = []
89
- }
90
-
91
- parseArguments () {
92
- const parser = new homebridgeLib.CommandLineParser()
93
- parser
94
- .help('h', 'help', help)
95
- .version('V', 'version')
96
- .flag('s', 'sortKeys', () => { this.options.sortKeys = true })
97
- .flag('n', 'noWhiteSpace', () => { this.options.noWhiteSpace = true })
98
- .flag('j', 'jsonArray', () => { this.options.jsonArray = true })
99
- .flag('u', 'joinKeys', () => { this.options.joinKeys = true })
100
- .flag('a', 'ascii', () => { this.options.ascii = true })
101
- .flag('t', 'topOnly', () => { this.options.topOnly = true })
102
- .option('d', 'maxDepth', (value, option) => {
103
- this.options.maxDepth = homebridgeLib.OptionParser.toInt(
104
- 'maxDepth', value, 0, undefined, true)
105
- })
106
- .option('p', 'fromPath', (value, option) => {
107
- this.options.fromPath = homebridgeLib.OptionParser.toPath(
108
- 'fromPath', value, true
109
- )
110
- })
111
- .flag('l', 'leavesOnly', () => { this.options.leavesOnly = true })
112
- .flag('k', 'keysOnly', () => { this.options.keysOnly = true })
113
- .flag('v', 'valuesOnly', () => { this.options.valuesOnly = true })
114
- .option('c', 'string', (value) => { this.stringList.push(value) })
115
- .remaining((list) => { this.fileList = list })
116
- .parse()
117
- }
118
-
119
- processString (s) {
120
- let value
121
- try {
122
- value = JSON.parse(s)
123
- } catch (error) {
124
- throw new Error(error.message) // Convert SyntaxError to Error.
125
- }
126
- const output = this.jsonFormatter.stringify(value)
127
- if (this.n++ > 0) {
128
- this.print('------')
129
- }
130
- if (output !== '') {
131
- this.print(output)
132
- }
133
- }
134
-
135
- async main () {
136
- try {
137
- this.parseArguments()
138
- this.jsonFormatter = new homebridgeLib.JsonFormatter(this.options)
139
- if (this.fileList.length === 0 && this.stringList.length === 0) {
140
- this.fileList = ['-']
141
- }
142
- this.n = 0
143
- this.stringList.forEach((s) => {
144
- try {
145
- this.processString(s)
146
- } catch (error) {
147
- this.error(error)
148
- }
149
- })
150
- this.fileList.forEach(async (file) => {
151
- try {
152
- const s = file.endsWith('.gz')
153
- ? await gunzip(fs.readFileSync(file))
154
- : fs.readFileSync(file === '-' ? 0 : file, 'utf8')
155
- this.processString(s)
156
- } catch (error) {
157
- this.error(error)
158
- }
159
- })
160
- } catch (error) {
161
- await this.fatal(error)
162
- }
163
- }
164
- }
165
-
166
- new Main().main()
14
+ new JsonTool().main()
package/cli/sysinfo.js CHANGED
@@ -9,73 +9,6 @@
9
9
 
10
10
  'use strict'
11
11
 
12
- const homebridgeLib = require('../index')
12
+ const { SysinfoTool } = require('../index')
13
13
 
14
- const { b } = homebridgeLib.CommandLineTool
15
-
16
- const usage = `${b('sysinfo')} [${b('-hVDj')}]`
17
- const help = `System information tool.
18
-
19
- Print Hardware and Operating System information.
20
-
21
- Usage: ${usage}
22
-
23
- Parameters:
24
- ${b('-h')}, ${b('--help')}
25
- Print this help and exit.
26
-
27
- ${b('-V')}, ${b('--version')}
28
- Print version and exit.
29
-
30
- ${b('-D')}, ${b('--debug')}
31
- Print debug messages.
32
-
33
- ${b('-j')}, ${b('--json')}
34
- Print full info in json.`
35
-
36
- class Main extends homebridgeLib.CommandLineTool {
37
- constructor () {
38
- super()
39
- this.usage = usage
40
- this.options = {
41
- noWhiteSpace: false
42
- }
43
- this.upnp = {}
44
- }
45
-
46
- parseArguments () {
47
- const parser = new homebridgeLib.CommandLineParser()
48
- parser
49
- .help('h', 'help', help)
50
- .version('V', 'version')
51
- .flag('D', 'debug', () => { this.setOptions({ debug: true }) })
52
- .flag('j', 'json', () => { this.json = true })
53
- .parse()
54
- }
55
-
56
- async main () {
57
- try {
58
- this.parseArguments()
59
- this.systemInfo = new homebridgeLib.SystemInfo()
60
- this.systemInfo
61
- .on('error', (error) => { this.error(error) })
62
- .on('exec', (command) => { this.debug('exec: %s', command) })
63
- .on('readFile', (fileName) => { this.debug('read file: %s', fileName) })
64
- await this.systemInfo.init()
65
- if (this.json) {
66
- const jsonFormatter = new homebridgeLib.JsonFormatter(this.options)
67
- this.print(jsonFormatter.stringify({
68
- hardware: this.systemInfo.hwInfo,
69
- os: this.systemInfo.osInfo
70
- }))
71
- } else {
72
- this.print(this.systemInfo.hwInfo.prettyName)
73
- this.print(this.systemInfo.osInfo.prettyName)
74
- }
75
- } catch (error) {
76
- await this.fatal(error)
77
- }
78
- }
79
- }
80
-
81
- new Main().main()
14
+ new SysinfoTool().main()
package/cli/upnp.js CHANGED
@@ -9,142 +9,6 @@
9
9
 
10
10
  'use strict'
11
11
 
12
- const homebridgeLib = require('../index')
12
+ const { UpnpTool } = require('../index')
13
13
 
14
- const { b, u } = homebridgeLib.CommandLineTool
15
-
16
- const usage = `${b('upnp')} [${b('-hVDadnprsz')}] [${b('-c')} ${u('class')}] [${b('-t')} ${u('timeout')}]`
17
- const help = `UPnP tool.
18
-
19
- Search for UPnP devices and print found devices as JSON.
20
- When running as daemon or service, log UPnP alive broadcasts as JSON.
21
-
22
- Usage: ${usage}
23
-
24
- Parameters:
25
- ${b('-h')}, ${b('--help')}
26
- Print this help and exit.
27
-
28
- ${b('-V')}, ${b('--version')}
29
- Print version and exit.
30
-
31
- ${b('-D')}, ${b('--debug')}
32
- Print debug messages.
33
-
34
- ${b('-a')}, ${b('--all')}
35
- Short for ${b('-c ssdp:all')}.
36
-
37
- ${b('-c')} ${u('class')}, ${b('--class=')}${u('class')}
38
- Search for ${u('class')} instead of default ${b('ssdp:rootdevice')}.
39
-
40
- ${b('-d')}, ${b('--daemon')}
41
- Run as daemon. Listen for UPnP alive broadcasts instead of searching.
42
-
43
- ${b('-n')}, ${b('--noWhiteSpace')}
44
- Do not include spaces nor newlines in JSON output.
45
-
46
- ${b('-p')}, ${b('--hue')}
47
- Search for Philips Hue bridges and/or deCONZ gateways.
48
-
49
- ${b('-r')}, ${b('--raw')}
50
- Do not parse messages, output raw message data instead of JSON.
51
-
52
- ${b('-s')}, ${b('--service')}
53
- Run as daemon. Listen for UPnP alive broadcasts instead of searching.
54
-
55
- ${b('-t')} ${u('timeout')}, ${b('--timeout=')}${u('timeout')}
56
- Search for ${u('timeout')} seconds instead of default ${b('5')}.
57
-
58
- ${b('-z')}, ${b('--sonos')}
59
- Search for Sonos Zone Players.`
60
-
61
- class Main extends homebridgeLib.CommandLineTool {
62
- constructor () {
63
- super()
64
- this.usage = usage
65
- this.options = {
66
- noWhiteSpace: false
67
- }
68
- this.upnp = {}
69
- }
70
-
71
- parseArguments () {
72
- const parser = new homebridgeLib.CommandLineParser()
73
- parser
74
- .help('h', 'help', help)
75
- .version('V', 'version')
76
- .flag('D', 'debug', () => { this.setOptions({ debug: true }) })
77
- .flag('a', 'all', (key) => { this.upnp.class = 'ssdp:all' })
78
- .option('c', 'class', (value, key) => { this.upnp.class = value })
79
- .flag('d', 'daemon', (key) => { this.options.mode = 'daemon' })
80
- .flag('n', 'noWhiteSpace', () => { this.options.noWhiteSpace = true })
81
- .flag('r', 'raw', (key) => { this.options.raw = true })
82
- .flag('s', 'service', (key) => { this.options.mode = 'service' })
83
- .option('t', 'timeout', (value, key) => {
84
- this.upnp.timeout = homebridgeLib.OptionParser.toInt(
85
- 'timeout', value, 1, 60, true
86
- )
87
- })
88
- .flag('p', 'hue', (key) => {
89
- this.upnp.filter = (message) => {
90
- return /^[0-9A-F]{16}$/.test(message['hue-bridgeid'])
91
- }
92
- })
93
- .flag('z', 'sonos', (key) => {
94
- this.upnp.class = 'urn:schemas-upnp-org:device:ZonePlayer:1'
95
- })
96
- .parse()
97
- }
98
-
99
- async destroy () {
100
- if (this.upnpClient == null) {
101
- return
102
- }
103
- return this.upnpClient.stopListen()
104
- }
105
-
106
- async main () {
107
- try {
108
- this.parseArguments()
109
- const jsonFormatter = new homebridgeLib.JsonFormatter({
110
- noWhiteSpace: this.options.noWhiteSpace
111
- })
112
- this.upnpClient = new homebridgeLib.UpnpClient(this.upnp)
113
- this.upnpClient
114
- .on('error', (error) => { this.error(error) })
115
- .on('listening', (host) => { this.debug('listening on %s', host) })
116
- .on('stopListening', (host) => { this.debug('stopped listening on %s', host) })
117
- .on('deviceAlive', (address, obj, message) => {
118
- if (!this.options.raw) {
119
- message = jsonFormatter.stringify(obj)
120
- }
121
- this.log('%s: %s', address, message)
122
- })
123
- .on('searching', (host) => { this.debug('listening on %s', host) })
124
- .on('request', (request) => {
125
- this.debug(
126
- '%s: request %d: %s %s', request.host, request.id,
127
- request.method, request.resource
128
- )
129
- })
130
- .on('searchDone', (host) => { this.debug('search done') })
131
- .on('deviceFound', (address, obj, message) => {
132
- if (!this.options.raw) {
133
- message = jsonFormatter.stringify(obj)
134
- }
135
- this.print('%s: %s', address, message)
136
- })
137
-
138
- if (this.options.mode) {
139
- this.setOptions({ mode: this.options.mode })
140
- this.upnpClient.listen()
141
- } else {
142
- this.upnpClient.search()
143
- }
144
- } catch (error) {
145
- await this.fatal(error)
146
- }
147
- }
148
- }
149
-
150
- new Main().main()
14
+ new UpnpTool().main()
package/index.js CHANGED
@@ -210,6 +210,12 @@ class homebridgeLib {
210
210
  */
211
211
  static get UpnpClient () { return require('./lib/UpnpClient') }
212
212
 
213
+ // Command-line tools.
214
+ static get HapTool () { return require('./lib/HapTool') }
215
+ static get JsonTool () { return require('./lib/JsonTool') }
216
+ static get SysinfoTool () { return require('./lib/SysinfoTool') }
217
+ static get UpnpTool () { return require('./lib/UpnpTool') }
218
+
213
219
  /** Resolve after given period, delaying execution.
214
220
  *
215
221
  * E.g. to delay execution for 1.5 seconds, issue:
package/lib/HapTool.js ADDED
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+
3
+ // homebridge-lib/lib/HapTool.js
4
+ //
5
+ // Library for Homebridge plugins.
6
+ // Copyright © 2018-2023 Erik Baauw. All rights reserved.
7
+ //
8
+ // Logger for HomeKit accessory announcements.
9
+
10
+ 'use strict'
11
+
12
+ const homebridgeLib = require('../index')
13
+
14
+ const Bonjour = require('bonjour-hap')
15
+
16
+ const { b, u } = homebridgeLib.CommandLineTool
17
+
18
+ const usage = `${b('hap')} [${b('-hVlrs')}] [${b('-t')} ${u('timeout')}]`
19
+ const help = `Logger for HomeKit accessory announcements.
20
+
21
+ Usage: ${usage}
22
+
23
+ Search for HomeKit accessory announcements
24
+ Parameters:
25
+ ${b('-h')} Print this help and exit.
26
+ ${b('-V')} Print version and exit.
27
+ ${b('-d')} Listen for Bonjour alive broadcasts instead of searching.
28
+ ${b('-s')} Do not output timestamps (useful when running as service).
29
+ ${b('-t')} ${u('timeout')} Search for ${u('timeout')} seconds instead of default ${b('5')}.`
30
+
31
+ class HapTool extends homebridgeLib.CommandLineTool {
32
+ constructor () {
33
+ super()
34
+ this.usage = usage
35
+ this.options = { timeout: 15 }
36
+ }
37
+
38
+ parseArguments () {
39
+ const parser = new homebridgeLib.CommandLineParser()
40
+ parser
41
+ .help('h', 'help', help)
42
+ .version('V', 'version')
43
+ .flag('l', 'listen', (key) => { this.options.mode = 'daemon' })
44
+ .flag('s', 'service', (key) => { this.options.mode = 'service' })
45
+ .option('t', 'timeout', (value, key) => {
46
+ this.options.timeout = homebridgeLib.OptionParser.toInt(
47
+ 'timeout', value, 1, 60, true
48
+ )
49
+ })
50
+ .parse()
51
+ }
52
+
53
+ onUp (obj) {
54
+ delete obj.rawTxt
55
+ this.log('found accessory: %s', obj.name, this.jsonFormatter.stringify(obj))
56
+ }
57
+
58
+ async main () {
59
+ try {
60
+ this.parseArguments()
61
+ this.jsonFormatter = new homebridgeLib.JsonFormatter(
62
+ this.options.mode === 'service'
63
+ ? { noWhiteSpace: true, sortKeys: true }
64
+ : { sortKeys: true }
65
+ )
66
+ if (this.options.mode) {
67
+ this.setOptions({ mode: this.options.mode })
68
+ } else {
69
+ setTimeout(() => {
70
+ this.log('search done')
71
+ bonjour4.destroy()
72
+ // bonjour6.destroy()
73
+ }, this.options.timeout * 1000)
74
+ }
75
+ this.log('searching for HomeKit accessories')
76
+ const bonjour4 = new Bonjour()
77
+ const browser4 = bonjour4.find({ type: 'hap' })
78
+ browser4.on('up', this.onUp.bind(this))
79
+ // const bonjour6 = new Bonjour({
80
+ // type: 'udp6',
81
+ // interface: '::%en0', // TODO: how to determine the interface?!
82
+ // ip: 'ff02::fb'
83
+ // })
84
+ // const browser6 = bonjour6.find({ type: 'hap' })
85
+ // browser6.on('up', this.onUp.bind(this))
86
+ } catch (error) {
87
+ await this.fatal(error)
88
+ }
89
+ }
90
+ }
91
+
92
+ module.exports = HapTool
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env node
2
+
3
+ // homebridge-lib/lib/JsonTool.js
4
+ //
5
+ // Library for Homebridge plugins.
6
+ // Copyright © 2018-2023 Erik Baauw. All rights reserved.
7
+ //
8
+ // JSON formatter.
9
+
10
+ 'use strict'
11
+
12
+ const homebridgeLib = require('../index')
13
+
14
+ const fs = require('fs')
15
+ const util = require('util')
16
+ const zlib = require('zlib')
17
+
18
+ const gunzip = util.promisify(zlib.unzip)
19
+
20
+ const { b, u } = homebridgeLib.CommandLineTool
21
+
22
+ const usage = `${b('json')} [${b('-hVsnjuatlkv')}] [${b('-p')} path] [${b('-d')} depth] [${b('-c')} ${u('string')}]... [${u('file')}]...`
23
+ const help = `JSON formatter.
24
+
25
+ Usage: ${usage}
26
+
27
+ By default, ${b('json')} reads JSON from stdin, formats it, and prints it to stdout.
28
+
29
+ Parameters:
30
+ ${b('-h')}, ${b('--help')}
31
+ Print this help and exit.
32
+
33
+ ${b('-V')}, ${b('--version')}
34
+ Print version and exit.
35
+
36
+ ${b('-s')}, ${b('--sortKeys')}
37
+ Sort object key/value pairs alphabetically on key.
38
+
39
+ ${b('-n')}, ${b('--noWhiteSpace')}
40
+ Do not include spaces nor newlines in output.
41
+
42
+ ${b('-j')}, ${b('--jsonArray')}
43
+ Output JSON array of objects for each key/value pair.
44
+ Each object contains two key/value pairs:
45
+ - key ${b('keys')} with an array of keys as value;
46
+ - key ${b('value')} with the value as value.
47
+
48
+ ${b('-u')}, ${b('--joinKeys')}
49
+ Output JSON array of objects for each key/value pair.
50
+ Each object contains one key/value pair:
51
+ the path (concatenated keys separated by ${b('/')} as key and the value as value.
52
+
53
+ ${b('-a')}, ${b('--ascii')}
54
+ Output ${u('path')}${b(':')}${u('value')} in plain text instead of JSON.
55
+
56
+ ${b('-t')}, ${b('--topOnly')}
57
+ Limit output to top-level key/values.
58
+
59
+ ${b('-p')} ${u('path')}, ${b('--fromPath=')}${u('path')}
60
+ Limit output to key/values under ${u('path')}. Set top level below ${u('path')}.
61
+
62
+ ${b('-d')} ${u('depth')}, ${b('--maxDepth=')}${u('depth')}
63
+ Limit output to levels above ${u('depth')}.
64
+
65
+ ${b('-l')}, ${b('--leavesOnly')}
66
+ Limit output to leaf (non-array, non-object) key/values.
67
+
68
+ ${b('-k')}, ${b('--keysOnly')}
69
+ Limit output to keys. With ${b('-u')} output JSON array of paths.
70
+
71
+ ${b('-v')}, ${b('--valuesOnly')}
72
+ Limit output to values. With ${b('-u')} output JSON array of values.
73
+
74
+ ${b('-c')} ${u('string')}, ${b('--string=')}${u('string')}
75
+ Read JSON from ${u('string')} instead of from stdin.
76
+
77
+ ${u('file')}
78
+ Read JSON from ${u('file')} instead of from stdin.
79
+ When the file name ends in ${b('.gz')}, it is assumed to be a gzip file and
80
+ uncompressed automatically.`
81
+
82
+ class JsonTool extends homebridgeLib.CommandLineTool {
83
+ constructor () {
84
+ super()
85
+ this.usage = usage
86
+ this.options = {}
87
+ this.stringList = []
88
+ this.fileList = []
89
+ }
90
+
91
+ parseArguments () {
92
+ const parser = new homebridgeLib.CommandLineParser()
93
+ parser
94
+ .help('h', 'help', help)
95
+ .version('V', 'version')
96
+ .flag('s', 'sortKeys', () => { this.options.sortKeys = true })
97
+ .flag('n', 'noWhiteSpace', () => { this.options.noWhiteSpace = true })
98
+ .flag('j', 'jsonArray', () => { this.options.jsonArray = true })
99
+ .flag('u', 'joinKeys', () => { this.options.joinKeys = true })
100
+ .flag('a', 'ascii', () => { this.options.ascii = true })
101
+ .flag('t', 'topOnly', () => { this.options.topOnly = true })
102
+ .option('d', 'maxDepth', (value, option) => {
103
+ this.options.maxDepth = homebridgeLib.OptionParser.toInt(
104
+ 'maxDepth', value, 0, undefined, true)
105
+ })
106
+ .option('p', 'fromPath', (value, option) => {
107
+ this.options.fromPath = homebridgeLib.OptionParser.toPath(
108
+ 'fromPath', value, true
109
+ )
110
+ })
111
+ .flag('l', 'leavesOnly', () => { this.options.leavesOnly = true })
112
+ .flag('k', 'keysOnly', () => { this.options.keysOnly = true })
113
+ .flag('v', 'valuesOnly', () => { this.options.valuesOnly = true })
114
+ .option('c', 'string', (value) => { this.stringList.push(value) })
115
+ .remaining((list) => { this.fileList = list })
116
+ .parse()
117
+ }
118
+
119
+ processString (s) {
120
+ let value
121
+ try {
122
+ value = JSON.parse(s)
123
+ } catch (error) {
124
+ throw new Error(error.message) // Convert SyntaxError to Error.
125
+ }
126
+ const output = this.jsonFormatter.stringify(value)
127
+ if (this.n++ > 0) {
128
+ this.print('------')
129
+ }
130
+ if (output !== '') {
131
+ this.print(output)
132
+ }
133
+ }
134
+
135
+ async main () {
136
+ try {
137
+ this.parseArguments()
138
+ this.jsonFormatter = new homebridgeLib.JsonFormatter(this.options)
139
+ if (this.fileList.length === 0 && this.stringList.length === 0) {
140
+ this.fileList = ['-']
141
+ }
142
+ this.n = 0
143
+ this.stringList.forEach((s) => {
144
+ try {
145
+ this.processString(s)
146
+ } catch (error) {
147
+ this.error(error)
148
+ }
149
+ })
150
+ this.fileList.forEach(async (file) => {
151
+ try {
152
+ const s = file.endsWith('.gz')
153
+ ? await gunzip(fs.readFileSync(file))
154
+ : fs.readFileSync(file === '-' ? 0 : file, 'utf8')
155
+ this.processString(s)
156
+ } catch (error) {
157
+ this.error(error)
158
+ }
159
+ })
160
+ } catch (error) {
161
+ await this.fatal(error)
162
+ }
163
+ }
164
+ }
165
+
166
+ module.exports = JsonTool
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+
3
+ // homebridge-lib/lib/SysinfoTool.js
4
+ //
5
+ // Show system info.
6
+ // Copyright © 2021-2023 Erik Baauw. All rights reserved.
7
+
8
+ 'use strict'
9
+
10
+ const homebridgeLib = require('../index')
11
+
12
+ const { b } = homebridgeLib.CommandLineTool
13
+
14
+ const usage = `${b('sysinfo')} [${b('-hVDj')}]`
15
+ const help = `System information tool.
16
+
17
+ Print Hardware and Operating System information.
18
+
19
+ Usage: ${usage}
20
+
21
+ Parameters:
22
+ ${b('-h')}, ${b('--help')}
23
+ Print this help and exit.
24
+
25
+ ${b('-V')}, ${b('--version')}
26
+ Print version and exit.
27
+
28
+ ${b('-D')}, ${b('--debug')}
29
+ Print debug messages.
30
+
31
+ ${b('-j')}, ${b('--json')}
32
+ Print full info in json.`
33
+
34
+ class SysinfoTool extends homebridgeLib.CommandLineTool {
35
+ constructor () {
36
+ super()
37
+ this.usage = usage
38
+ this.options = {
39
+ noWhiteSpace: false
40
+ }
41
+ this.upnp = {}
42
+ }
43
+
44
+ parseArguments () {
45
+ const parser = new homebridgeLib.CommandLineParser()
46
+ parser
47
+ .help('h', 'help', help)
48
+ .version('V', 'version')
49
+ .flag('D', 'debug', () => { this.setOptions({ debug: true }) })
50
+ .flag('j', 'json', () => { this.json = true })
51
+ .parse()
52
+ }
53
+
54
+ async main () {
55
+ try {
56
+ this.parseArguments()
57
+ this.systemInfo = new homebridgeLib.SystemInfo()
58
+ this.systemInfo
59
+ .on('error', (error) => { this.error(error) })
60
+ .on('exec', (command) => { this.debug('exec: %s', command) })
61
+ .on('readFile', (fileName) => { this.debug('read file: %s', fileName) })
62
+ await this.systemInfo.init()
63
+ if (this.json) {
64
+ const jsonFormatter = new homebridgeLib.JsonFormatter(this.options)
65
+ this.print(jsonFormatter.stringify({
66
+ hardware: this.systemInfo.hwInfo,
67
+ os: this.systemInfo.osInfo
68
+ }))
69
+ } else {
70
+ this.print(this.systemInfo.hwInfo.prettyName)
71
+ this.print(this.systemInfo.osInfo.prettyName)
72
+ }
73
+ } catch (error) {
74
+ await this.fatal(error)
75
+ }
76
+ }
77
+ }
78
+
79
+ module.exports = SysinfoTool
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env node
2
+
3
+ // homebridge-lib/cli/upnp.js
4
+ //
5
+ // Logger for UPnP device announcements.
6
+ // Copyright © 2018-2023 Erik Baauw. All rights reserved.
7
+
8
+ 'use strict'
9
+
10
+ const homebridgeLib = require('../index')
11
+
12
+ const { b, u } = homebridgeLib.CommandLineTool
13
+
14
+ const usage = `${b('upnp')} [${b('-hVDadnprsz')}] [${b('-c')} ${u('class')}] [${b('-t')} ${u('timeout')}]`
15
+ const help = `UPnP tool.
16
+
17
+ Search for UPnP devices and print found devices as JSON.
18
+ When running as daemon or service, log UPnP alive broadcasts as JSON.
19
+
20
+ Usage: ${usage}
21
+
22
+ Parameters:
23
+ ${b('-h')}, ${b('--help')}
24
+ Print this help and exit.
25
+
26
+ ${b('-V')}, ${b('--version')}
27
+ Print version and exit.
28
+
29
+ ${b('-D')}, ${b('--debug')}
30
+ Print debug messages.
31
+
32
+ ${b('-a')}, ${b('--all')}
33
+ Short for ${b('-c ssdp:all')}.
34
+
35
+ ${b('-c')} ${u('class')}, ${b('--class=')}${u('class')}
36
+ Search for ${u('class')} instead of default ${b('ssdp:rootdevice')}.
37
+
38
+ ${b('-d')}, ${b('--daemon')}
39
+ Run as daemon. Listen for UPnP alive broadcasts instead of searching.
40
+
41
+ ${b('-n')}, ${b('--noWhiteSpace')}
42
+ Do not include spaces nor newlines in JSON output.
43
+
44
+ ${b('-p')}, ${b('--hue')}
45
+ Search for Philips Hue bridges and/or deCONZ gateways.
46
+
47
+ ${b('-r')}, ${b('--raw')}
48
+ Do not parse messages, output raw message data instead of JSON.
49
+
50
+ ${b('-s')}, ${b('--service')}
51
+ Run as daemon. Listen for UPnP alive broadcasts instead of searching.
52
+
53
+ ${b('-t')} ${u('timeout')}, ${b('--timeout=')}${u('timeout')}
54
+ Search for ${u('timeout')} seconds instead of default ${b('5')}.
55
+
56
+ ${b('-z')}, ${b('--sonos')}
57
+ Search for Sonos Zone Players.`
58
+
59
+ class UpnpTool extends homebridgeLib.CommandLineTool {
60
+ constructor () {
61
+ super()
62
+ this.usage = usage
63
+ this.options = {
64
+ noWhiteSpace: false
65
+ }
66
+ this.upnp = {}
67
+ }
68
+
69
+ parseArguments () {
70
+ const parser = new homebridgeLib.CommandLineParser()
71
+ parser
72
+ .help('h', 'help', help)
73
+ .version('V', 'version')
74
+ .flag('D', 'debug', () => { this.setOptions({ debug: true }) })
75
+ .flag('a', 'all', (key) => { this.upnp.class = 'ssdp:all' })
76
+ .option('c', 'class', (value, key) => { this.upnp.class = value })
77
+ .flag('d', 'daemon', (key) => { this.options.mode = 'daemon' })
78
+ .flag('n', 'noWhiteSpace', () => { this.options.noWhiteSpace = true })
79
+ .flag('r', 'raw', (key) => { this.options.raw = true })
80
+ .flag('s', 'service', (key) => { this.options.mode = 'service' })
81
+ .option('t', 'timeout', (value, key) => {
82
+ this.upnp.timeout = homebridgeLib.OptionParser.toInt(
83
+ 'timeout', value, 1, 60, true
84
+ )
85
+ })
86
+ .flag('p', 'hue', (key) => {
87
+ this.upnp.filter = (message) => {
88
+ return /^[0-9A-F]{16}$/.test(message['hue-bridgeid'])
89
+ }
90
+ })
91
+ .flag('z', 'sonos', (key) => {
92
+ this.upnp.class = 'urn:schemas-upnp-org:device:ZonePlayer:1'
93
+ })
94
+ .parse()
95
+ }
96
+
97
+ async destroy () {
98
+ if (this.upnpClient == null) {
99
+ return
100
+ }
101
+ return this.upnpClient.stopListen()
102
+ }
103
+
104
+ async main () {
105
+ try {
106
+ this.parseArguments()
107
+ const jsonFormatter = new homebridgeLib.JsonFormatter({
108
+ noWhiteSpace: this.options.noWhiteSpace
109
+ })
110
+ this.upnpClient = new homebridgeLib.UpnpClient(this.upnp)
111
+ this.upnpClient
112
+ .on('error', (error) => { this.error(error) })
113
+ .on('listening', (host) => { this.debug('listening on %s', host) })
114
+ .on('stopListening', (host) => { this.debug('stopped listening on %s', host) })
115
+ .on('deviceAlive', (address, obj, message) => {
116
+ if (!this.options.raw) {
117
+ message = jsonFormatter.stringify(obj)
118
+ }
119
+ this.log('%s: %s', address, message)
120
+ })
121
+ .on('searching', (host) => { this.debug('listening on %s', host) })
122
+ .on('request', (request) => {
123
+ this.debug(
124
+ '%s: request %d: %s %s', request.host, request.id,
125
+ request.method, request.resource
126
+ )
127
+ })
128
+ .on('searchDone', (host) => { this.debug('search done') })
129
+ .on('deviceFound', (address, obj, message) => {
130
+ if (!this.options.raw) {
131
+ message = jsonFormatter.stringify(obj)
132
+ }
133
+ this.print('%s: %s', address, message)
134
+ })
135
+
136
+ if (this.options.mode) {
137
+ this.setOptions({ mode: this.options.mode })
138
+ this.upnpClient.listen()
139
+ } else {
140
+ this.upnpClient.search()
141
+ }
142
+ } catch (error) {
143
+ await this.fatal(error)
144
+ }
145
+ }
146
+ }
147
+
148
+ module.exports = UpnpTool
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Library for homebridge plugins",
4
4
  "author": "Erik Baauw",
5
5
  "license": "Apache-2.0",
6
- "version": "6.3.6",
6
+ "version": "6.3.7",
7
7
  "keywords": [
8
8
  "homekit",
9
9
  "homebridge"