hb-rpi-tools 0.0.2 → 0.0.3
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/GpioClient/PigpioClient.js +6 -1
- package/lib/GpioClient/RgpioClient.js +31 -17
- package/lib/GpioDhtClient.js +91 -0
- package/lib/GpioLedChain.js +14 -10
- package/lib/RpiInfo.js +2 -3
- package/lib/RpiTool.js +226 -6
- package/package.json +1 -1
|
@@ -650,12 +650,17 @@ class PigpioClient extends GpioClient {
|
|
|
650
650
|
await this.command(this.commands.WDOG, gpio, timeout)
|
|
651
651
|
}
|
|
652
652
|
|
|
653
|
-
async
|
|
653
|
+
async dhtRead (gpio) {
|
|
654
654
|
await this.write(gpio, 0)
|
|
655
655
|
await timeout(18)
|
|
656
656
|
await this.setInput(gpio, this.pudValues.up)
|
|
657
657
|
}
|
|
658
658
|
|
|
659
|
+
async read (gpio) {
|
|
660
|
+
const response = await this.command(this.commands.READ, gpio)
|
|
661
|
+
return response.status !== 0
|
|
662
|
+
}
|
|
663
|
+
|
|
659
664
|
async write (gpio, value) {
|
|
660
665
|
await this.command(this.commands.WRITE, gpio, (value ? 1 : 0))
|
|
661
666
|
}
|
|
@@ -380,12 +380,20 @@ class RgpioClient extends GpioClient {
|
|
|
380
380
|
await this.command(commands.PASSW, { string: hash.digest('hex') })
|
|
381
381
|
this.emit('message', `user ${this._params.user} logged in`)
|
|
382
382
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
383
|
+
await this.command(commands.SHARE, { longs: [42] })
|
|
384
|
+
this.gpioChipHandle = 0
|
|
385
|
+
try {
|
|
386
|
+
const result = await this.command(commands.GIC, { longs: [this.gpioChipHandle] })
|
|
387
|
+
this.emit('message', `${result.name}: ${result.label}`)
|
|
388
|
+
} catch (error) {
|
|
389
|
+
this.emit('message', `warning: ${error.message}`)
|
|
390
|
+
this.gpioChipHandle = (await (this.command(commands.GO, { longs: [0] }))).status
|
|
391
|
+
if (this.gpioChipHandle !== 0) {
|
|
392
|
+
this.emit('warning', new Error(`got GPIO chip handle ${this.gpioChipHandle}`))
|
|
393
|
+
}
|
|
394
|
+
const result = await this.command(commands.GIC, { longs: [this.gpioChipHandle] })
|
|
395
|
+
this.emit('message', `${result.name}: ${result.label}`)
|
|
386
396
|
}
|
|
387
|
-
const result = await this.command(commands.GIC, { longs: [this.gpioChipHandle] })
|
|
388
|
-
this.emit('message', `${result.name}: ${result.label}`)
|
|
389
397
|
}
|
|
390
398
|
|
|
391
399
|
/** Subscribe to notifications for changed GPIO values.
|
|
@@ -405,9 +413,9 @@ class RgpioClient extends GpioClient {
|
|
|
405
413
|
|
|
406
414
|
await super.listen()
|
|
407
415
|
|
|
408
|
-
if (this.dataHandle !== 0) {
|
|
409
|
-
|
|
410
|
-
}
|
|
416
|
+
// if (this.dataHandle !== 0) {
|
|
417
|
+
// this.emit('warning', new Error(`got data handle ${this.dataHandle}`))
|
|
418
|
+
// }
|
|
411
419
|
|
|
412
420
|
const { tick, date } = await this.command(commands.TICK)
|
|
413
421
|
this.emit('message', `tick: ${tick} (${date})`)
|
|
@@ -450,7 +458,7 @@ class RgpioClient extends GpioClient {
|
|
|
450
458
|
}
|
|
451
459
|
delete this.fileHandle
|
|
452
460
|
}
|
|
453
|
-
if (this.gpioChipHandle != null) {
|
|
461
|
+
if (this.gpioChipHandle != null && this.gpioChipHandle !== 0) {
|
|
454
462
|
try {
|
|
455
463
|
await this.command(commands.GC, { longs: [this.gpioChipHandle] })
|
|
456
464
|
} catch (error) {
|
|
@@ -644,9 +652,10 @@ class RgpioClient extends GpioClient {
|
|
|
644
652
|
value = (await this.command(this.commands.GR, { longs: [this.gpioChipHandle, gpio] })).status
|
|
645
653
|
}
|
|
646
654
|
await this.command(this.commands.GSOX, { longs: [this.gpioChipHandle, gpioModes.none, gpio, value] })
|
|
655
|
+
// this.mask |= (1 << gpio)
|
|
647
656
|
}
|
|
648
657
|
|
|
649
|
-
async
|
|
658
|
+
async dhtRead (gpio) {
|
|
650
659
|
await this.setOutput(gpio, 0)
|
|
651
660
|
await timeout(18)
|
|
652
661
|
await this.command(this.commands.GSAX, {
|
|
@@ -655,6 +664,11 @@ class RgpioClient extends GpioClient {
|
|
|
655
664
|
})
|
|
656
665
|
}
|
|
657
666
|
|
|
667
|
+
async read (gpio) {
|
|
668
|
+
const result = await this.command(this.commands.GR, { longs: [this.gpioChipHandle, gpio] })
|
|
669
|
+
return result.status === 1
|
|
670
|
+
}
|
|
671
|
+
|
|
658
672
|
async write (gpio, value) {
|
|
659
673
|
await this.command(this.commands.GW, { longs: [this.gpioChipHandle, gpio, value ? 1 : 0] })
|
|
660
674
|
this.emit('gpio' + gpio, { value, tick: 0 })
|
|
@@ -666,7 +680,7 @@ class RgpioClient extends GpioClient {
|
|
|
666
680
|
|
|
667
681
|
async writePwm (gpio, dutyCycle) {
|
|
668
682
|
await this.command(this.commands.PX, {
|
|
669
|
-
longs: [this.gpioChipHandle, gpio,
|
|
683
|
+
longs: [this.gpioChipHandle, gpio, dutyCycle === 0 ? 0 : 10000000, dutyCycle * 100, 0, 0]
|
|
670
684
|
})
|
|
671
685
|
}
|
|
672
686
|
|
|
@@ -715,9 +729,9 @@ class RgpioClient extends GpioClient {
|
|
|
715
729
|
delete this.fileHandle
|
|
716
730
|
}
|
|
717
731
|
this.fileHandle = (await this.command(commands.FO, { longs: [1], string: filename })).status
|
|
718
|
-
if (this.fileHandle !== 1) {
|
|
719
|
-
|
|
720
|
-
}
|
|
732
|
+
// if (this.fileHandle !== 1) {
|
|
733
|
+
// this.emit('warning', new Error(`got file handle ${this.fileHandle}`))
|
|
734
|
+
// }
|
|
721
735
|
let s = ''
|
|
722
736
|
let result
|
|
723
737
|
do {
|
|
@@ -746,9 +760,9 @@ class RgpioClient extends GpioClient {
|
|
|
746
760
|
delete this.fileHandle
|
|
747
761
|
}
|
|
748
762
|
this.fileHandle = (await this.command(commands.FO, { longs: [2], string: filename })).status
|
|
749
|
-
if (this.fileHandle !== 1) {
|
|
750
|
-
|
|
751
|
-
}
|
|
763
|
+
// if (this.fileHandle !== 1) {
|
|
764
|
+
// this.emit('warning', new Error(`got file handle ${this.fileHandle}`))
|
|
765
|
+
// }
|
|
752
766
|
await this.command(commands.FW, { longs: [this.fileHandle], string: text })
|
|
753
767
|
await this.command(commands.FC, { longs: [this.fileHandle] })
|
|
754
768
|
delete this.fileHandle
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// hb-rpi-tools/lib/GpioDhtClient.js
|
|
2
|
+
// Copyright © 2019-2026 Erik Baauw. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
// Homebridge RPi Tools.
|
|
5
|
+
|
|
6
|
+
import { EventEmitter, once } from 'node:events'
|
|
7
|
+
|
|
8
|
+
/** Class to read a DHTxx sensor connected to a GPIO pin.
|
|
9
|
+
*
|
|
10
|
+
* @extends EventEmitter
|
|
11
|
+
*/
|
|
12
|
+
class GpioDhtClient extends EventEmitter {
|
|
13
|
+
constructor (parent, pi, gpio) {
|
|
14
|
+
super()
|
|
15
|
+
this.debug = parent.debug.bind(parent)
|
|
16
|
+
this.vdebug = parent.vdebug.bind(parent)
|
|
17
|
+
this.pi = pi
|
|
18
|
+
this.gpio = gpio
|
|
19
|
+
|
|
20
|
+
this.pi.on('gpio' + this.gpio, (payload) => {
|
|
21
|
+
if (payload.value) {
|
|
22
|
+
const duration = payload.tick - (this._previousTick ?? 0)
|
|
23
|
+
this._previousTick = payload.tick
|
|
24
|
+
this.#update(duration)
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async read () {
|
|
30
|
+
const timeout = setTimeout(() => {
|
|
31
|
+
this.emit('error', new Error(`gpio ${this.gpio}: timeout`))
|
|
32
|
+
}, this.pi._params.timeout * 1000)
|
|
33
|
+
this.pi.dhtRead(this.gpio)
|
|
34
|
+
const a = await once(this, 'dht')
|
|
35
|
+
clearTimeout(timeout)
|
|
36
|
+
return a[0]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
#update (duration) {
|
|
40
|
+
this.vdebug('gpio %d: rise after %d µs', this.gpio, duration)
|
|
41
|
+
if (duration > 10000) {
|
|
42
|
+
this.receiving = true
|
|
43
|
+
this.bit = this.pi.port === 8888 ? -2 : 0
|
|
44
|
+
this.data = 0n
|
|
45
|
+
} else if (this.receiving) {
|
|
46
|
+
if (++this.bit >= 1) {
|
|
47
|
+
this.data <<= 1n
|
|
48
|
+
if (duration >= 60 && duration <= 100) {
|
|
49
|
+
// 0 bit
|
|
50
|
+
this.vdebug('gpio %d: bit %d: 0', this.gpio, this.bit)
|
|
51
|
+
} else if (duration > 100 && duration <= 160) {
|
|
52
|
+
this.data += 1n // 1 bit
|
|
53
|
+
this.vdebug('gpio %d: bit %d: 1', this.gpio, this.bit)
|
|
54
|
+
} else {
|
|
55
|
+
this.receiving = false // invalid
|
|
56
|
+
this.debug('gpio %d: invalid signal', this.gpio)
|
|
57
|
+
}
|
|
58
|
+
if (this.receiving && this.bit === 40) {
|
|
59
|
+
const buf = Buffer.alloc(8)
|
|
60
|
+
buf.writeBigUint64LE(this.data)
|
|
61
|
+
if (((buf[1] + buf[2] + buf[3] + buf[4]) & 0xFF) !== buf[0]) {
|
|
62
|
+
this.debug('gpio %d: bad checksum', this.gpio)
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
let ok = false
|
|
66
|
+
let sensor = 'DHTxx'
|
|
67
|
+
let temperature = buf.readInt16LE(1) / 10
|
|
68
|
+
let humidity = buf.readUint16LE(3) / 10
|
|
69
|
+
ok = temperature >= -40 && temperature <= 125 && humidity <= 100
|
|
70
|
+
if (!ok) {
|
|
71
|
+
sensor = 'DHT11'
|
|
72
|
+
temperature = buf[2]
|
|
73
|
+
humidity = buf[4]
|
|
74
|
+
ok = temperature <= 50 && humidity >= 20 && humidity <= 80
|
|
75
|
+
}
|
|
76
|
+
if (!ok) {
|
|
77
|
+
this.debug('gpio %d: invalid data', this.gpio)
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
this.debug(
|
|
81
|
+
'gpio %d: %s: temperature: %d, humidity: %d',
|
|
82
|
+
this.gpio, sensor, temperature, humidity
|
|
83
|
+
)
|
|
84
|
+
this.emit('dht', { temperature, humidity })
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export { GpioDhtClient }
|
package/lib/GpioLedChain.js
CHANGED
|
@@ -31,10 +31,14 @@ class GpioLedChain extends EventEmitter {
|
|
|
31
31
|
this._nLeds = params.nLeds ?? 8
|
|
32
32
|
|
|
33
33
|
this._leds = []
|
|
34
|
+
this._bri = 0xFF
|
|
34
35
|
|
|
35
36
|
this._initWordBuffer()
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
get bri () { return this._bri }
|
|
40
|
+
set bri (value) { this._bri = value & 0xFF }
|
|
41
|
+
|
|
38
42
|
/** Initialise GPIO pins and update all LEDs.
|
|
39
43
|
* @param {boolean} [turnOff=false] - Turn LEDs off.
|
|
40
44
|
*/
|
|
@@ -177,7 +181,7 @@ class GpioLedChain extends EventEmitter {
|
|
|
177
181
|
await once(this, 'stopped')
|
|
178
182
|
}
|
|
179
183
|
|
|
180
|
-
async colorloop (
|
|
184
|
+
async colorloop () {
|
|
181
185
|
let r = 0
|
|
182
186
|
let g = 1
|
|
183
187
|
let b = 255
|
|
@@ -196,14 +200,14 @@ class GpioLedChain extends EventEmitter {
|
|
|
196
200
|
} else if (r === 0 && g > 0 && b === 255) {
|
|
197
201
|
g--
|
|
198
202
|
}
|
|
199
|
-
this.setAllLeds(
|
|
203
|
+
this.setAllLeds(this._bri, r, g, b)
|
|
200
204
|
await this.update()
|
|
201
205
|
}
|
|
202
206
|
this.emit('stopped')
|
|
203
207
|
}
|
|
204
208
|
|
|
205
209
|
// Inspired by: https://github.com/pimoroni/blinkt/blob/master/examples/larson.py
|
|
206
|
-
async cylon (
|
|
210
|
+
async cylon () {
|
|
207
211
|
let eye = -2 // eye centre goes from -2 to nLeds + 1
|
|
208
212
|
let up = true
|
|
209
213
|
|
|
@@ -219,25 +223,25 @@ class GpioLedChain extends EventEmitter {
|
|
|
219
223
|
this._continue = true
|
|
220
224
|
while (this._continue) {
|
|
221
225
|
if (eye - 3 >= 0) {
|
|
222
|
-
this.setLed(eye - 3,
|
|
226
|
+
this.setLed(eye - 3, this._bri, 0, 0, 0)
|
|
223
227
|
}
|
|
224
228
|
if (eye - 2 >= 0) {
|
|
225
|
-
this.setLed(eye - 2,
|
|
229
|
+
this.setLed(eye - 2, this._bri, 16, 0, 0)
|
|
226
230
|
}
|
|
227
231
|
if (eye - 1 >= 0) {
|
|
228
|
-
this.setLed(eye - 1,
|
|
232
|
+
this.setLed(eye - 1, this._bri, 64, 0, 0)
|
|
229
233
|
}
|
|
230
234
|
if (eye >= 0 && eye < this._nLeds) {
|
|
231
|
-
this.setLed(eye,
|
|
235
|
+
this.setLed(eye, this._bri, 255, 0, 0)
|
|
232
236
|
}
|
|
233
237
|
if (eye + 1 < this._nLeds) {
|
|
234
|
-
this.setLed(eye + 1,
|
|
238
|
+
this.setLed(eye + 1, this._bri, 64, 0, 0)
|
|
235
239
|
}
|
|
236
240
|
if (eye + 2 < this._nLeds) {
|
|
237
|
-
this.setLed(eye + 2,
|
|
241
|
+
this.setLed(eye + 2, this._bri, 16, 0, 0)
|
|
238
242
|
}
|
|
239
243
|
if (eye + 3 < this._nLeds) {
|
|
240
|
-
this.setLed(eye + 3,
|
|
244
|
+
this.setLed(eye + 3, this._bri, 0, 0, 0)
|
|
241
245
|
}
|
|
242
246
|
await this.update()
|
|
243
247
|
const delay = (eye <= 2)
|
package/lib/RpiInfo.js
CHANGED
|
@@ -21,9 +21,8 @@ const fansPwm = [
|
|
|
21
21
|
* - Retrieve the state through spawning `vcgencmd`.
|
|
22
22
|
*
|
|
23
23
|
* For remote Rapsberry Pi computers:
|
|
24
|
-
* - Parse the contents of `/proc/cpuinfo
|
|
25
|
-
* - Parse the state as returned by the `getState` script
|
|
26
|
-
* the PigpioClient.
|
|
24
|
+
* - Parse the contents of `/proc/cpuinfo`.
|
|
25
|
+
* - Parse the state as returned by the `getState` script.
|
|
27
26
|
*
|
|
28
27
|
* @extends EventEmitter
|
|
29
28
|
* @see https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
|
package/lib/RpiTool.js
CHANGED
|
@@ -21,7 +21,11 @@ const usage = {
|
|
|
21
21
|
test: `${b('test')} [${b('-hns')}]`,
|
|
22
22
|
led: `${b('led')} [${b('-h')}] [${b('on')}|${b('off')}]`,
|
|
23
23
|
eventlog: `${b('eventlog')} [${b('-h')}] [${u('gpio')}...]`,
|
|
24
|
-
|
|
24
|
+
gpio: `${b('gpio')} [${b('-h')}] ${u('gpio')} [${b('high')}|${b('low')}]`,
|
|
25
|
+
dht: `${b('dht')} [${b('-h')}] ${u('gpio')}`,
|
|
26
|
+
ledchain: `${b('ledchain')} [${b('-h')}] [${b('-B')}|${b('-P')}] [${b('-c')} ${u('gpio')} ${b('-d')} ${u('gpio')} ${b('-n')} ${u('nLeds')}] [${b('-b')} ${u('brightness')}] [${u('mode')}]`,
|
|
27
|
+
pwm: `${b('pwm')} [${b('-h')}] ${u('gpio')} [${u('dutyCycle')}]`,
|
|
28
|
+
servo: `${b('servo')} [${b('-h')}] ${u('gpio')} [${u('pulseWidth')}]`
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
const description = {
|
|
@@ -29,8 +33,12 @@ const description = {
|
|
|
29
33
|
info: 'Get Raspberry Pi properties.',
|
|
30
34
|
state: 'Get Raspberry Pi state.',
|
|
31
35
|
test: 'Repeatedly get Raspberry Pi state.',
|
|
32
|
-
led: '
|
|
36
|
+
led: 'Read/write power LED state.',
|
|
33
37
|
eventlog: 'Monitor GPIO state changes.',
|
|
38
|
+
gpio: 'Read/write GPIO state.',
|
|
39
|
+
pwm: 'Read/write PWM duty cycle.',
|
|
40
|
+
servo: 'Read/write servo pulse width.',
|
|
41
|
+
dht: 'Read DHTxx temperature/humidity sensor.',
|
|
34
42
|
ledchain: 'Control Blinkt! or P9813 LED chain.'
|
|
35
43
|
}
|
|
36
44
|
|
|
@@ -66,7 +74,7 @@ Parameters:
|
|
|
66
74
|
${b('-P')} ${u('password')}, ${b('--password=')}${u('password')}
|
|
67
75
|
Authenticate to the ${b('rgpio')} daemon with ${u('password')}.
|
|
68
76
|
Default is ${b('')} (empty).
|
|
69
|
-
The password can also be set
|
|
77
|
+
The password can also be set through the environment variable ${b('LG_PASS')}.
|
|
70
78
|
|
|
71
79
|
Commands:
|
|
72
80
|
${usage.info}
|
|
@@ -84,6 +92,18 @@ Commands:
|
|
|
84
92
|
${usage.eventlog}
|
|
85
93
|
${description.eventlog}
|
|
86
94
|
|
|
95
|
+
${usage.gpio}
|
|
96
|
+
${description.gpio}
|
|
97
|
+
|
|
98
|
+
${usage.pwm}
|
|
99
|
+
${description.pwm}
|
|
100
|
+
|
|
101
|
+
${usage.servo}
|
|
102
|
+
${description.servo}
|
|
103
|
+
|
|
104
|
+
${usage.dht}
|
|
105
|
+
${description.dht}
|
|
106
|
+
|
|
87
107
|
${usage.ledchain}
|
|
88
108
|
${description.ledchain}
|
|
89
109
|
|
|
@@ -128,6 +148,8 @@ Parameters:
|
|
|
128
148
|
${b('-s')}, ${b('--sortKeys')}
|
|
129
149
|
Sort object key/value pairs alphabetically on key.`,
|
|
130
150
|
led: `${description.led}
|
|
151
|
+
Note that this command only works on Raspberry Pi models
|
|
152
|
+
that support controlling the power LED, as reported by ${b('rpi info')}.
|
|
131
153
|
|
|
132
154
|
Usage: ${b('rpi')} ${usage.led}
|
|
133
155
|
|
|
@@ -139,7 +161,10 @@ Parameters:
|
|
|
139
161
|
Turn power LED on.
|
|
140
162
|
|
|
141
163
|
${b('off')}
|
|
142
|
-
Turn power LED off
|
|
164
|
+
Turn power LED off.
|
|
165
|
+
|
|
166
|
+
When neither ${b('on')} nor ${b('off')} is specified,
|
|
167
|
+
the current state of the power LED is reported.`,
|
|
143
168
|
eventlog: `${description.eventlog}
|
|
144
169
|
|
|
145
170
|
Usage: ${b('rpi')} ${usage.eventlog}
|
|
@@ -150,7 +175,69 @@ Paramerers:
|
|
|
150
175
|
|
|
151
176
|
${u('gpio')}
|
|
152
177
|
Log events for GPIO ${u('gpio')}.
|
|
153
|
-
Default: all user GPIOs on the Rapberry Pi model
|
|
178
|
+
Default: all user GPIOs on the Rapberry Pi model.
|
|
179
|
+
Note that ${b('rgpio')} only report state changes to input GPIOs.`,
|
|
180
|
+
gpio: `${description.gpio}
|
|
181
|
+
|
|
182
|
+
Usage: ${b('rpi')} ${usage.gpio}
|
|
183
|
+
|
|
184
|
+
Paramerers:
|
|
185
|
+
${b('-h')}, ${b('--help')}
|
|
186
|
+
Print this help and exit.
|
|
187
|
+
|
|
188
|
+
${u('gpio')}
|
|
189
|
+
Read or control GPIO ${u('gpio')}.
|
|
190
|
+
|
|
191
|
+
${b('high')}
|
|
192
|
+
Set GPIO high.
|
|
193
|
+
|
|
194
|
+
${b('low')}
|
|
195
|
+
Set GPIO low.
|
|
196
|
+
|
|
197
|
+
When neither ${b('high')} nor ${b('low')} is specified,
|
|
198
|
+
the current state of the GPIO is reported.`,
|
|
199
|
+
pwm: `${description.pwm}
|
|
200
|
+
|
|
201
|
+
Usage: ${b('rpi')} ${usage.pwm}
|
|
202
|
+
|
|
203
|
+
Paramerers:
|
|
204
|
+
${b('-h')}, ${b('--help')}
|
|
205
|
+
Print this help and exit.
|
|
206
|
+
|
|
207
|
+
${u('gpio')}
|
|
208
|
+
Read or control GPIO ${u('gpio')}.
|
|
209
|
+
|
|
210
|
+
${u('dutyCycle')}
|
|
211
|
+
Set PWM duty cycle to ${u('dutyCycle')} (between 0% and 100%).
|
|
212
|
+
|
|
213
|
+
When no duty cycle is specified, the current duty clycle of the GPIO is reported.
|
|
214
|
+
Note that ${b('rgpio')} doesn't support reading the duty cycle.`,
|
|
215
|
+
servo: `${description.servo}
|
|
216
|
+
|
|
217
|
+
Usage: ${b('rpi')} ${usage.servo}
|
|
218
|
+
|
|
219
|
+
Paramerers:
|
|
220
|
+
${b('-h')}, ${b('--help')}
|
|
221
|
+
Print this help and exit.
|
|
222
|
+
|
|
223
|
+
${u('gpio')}
|
|
224
|
+
Read or control GPIO ${u('gpio')}.
|
|
225
|
+
|
|
226
|
+
${u('pulseWidth')}
|
|
227
|
+
Set servo pulse width to ${u('pulseWidth')} (between 500 and 2500, or 0 for off).
|
|
228
|
+
|
|
229
|
+
When no pulse width is specified, the current pulse width of the GPIO is reported.
|
|
230
|
+
Note that ${b('rgpio')} doesn't support reading the pulse width.`,
|
|
231
|
+
dht: `${description.dht}
|
|
232
|
+
|
|
233
|
+
Usage: ${b('rpi')} ${usage.dht}
|
|
234
|
+
|
|
235
|
+
Paramerers:
|
|
236
|
+
${b('-h')}, ${b('--help')}
|
|
237
|
+
Print this help and exit.
|
|
238
|
+
|
|
239
|
+
${u('gpio')}
|
|
240
|
+
GPIO pin for DHTxx sensor.`,
|
|
154
241
|
ledchain: `${description.ledchain}
|
|
155
242
|
|
|
156
243
|
Usage: ${b('rpi')} ${usage.ledchain}
|
|
@@ -455,10 +542,143 @@ class RpiTool extends CommandLineTool {
|
|
|
455
542
|
)
|
|
456
543
|
})
|
|
457
544
|
}
|
|
458
|
-
|
|
545
|
+
this.pi.mask = mask === 0 ? gpioMask : mask
|
|
546
|
+
await this.pi.listen()
|
|
459
547
|
await new Promise(() => {})
|
|
460
548
|
}
|
|
461
549
|
|
|
550
|
+
async gpio (...args) {
|
|
551
|
+
const clargs = {}
|
|
552
|
+
const parser = new CommandLineParser(this.pkgJson)
|
|
553
|
+
parser
|
|
554
|
+
.help('h', 'help', this.help)
|
|
555
|
+
.parameter('gpio', (value) => {
|
|
556
|
+
clargs.gpio = OptionParser.toInt('gpio', value)
|
|
557
|
+
})
|
|
558
|
+
.remaining((value) => {
|
|
559
|
+
if (value.length > 1) {
|
|
560
|
+
throw new UsageError('too many parameters')
|
|
561
|
+
}
|
|
562
|
+
if (value.length === 1) {
|
|
563
|
+
if (value[0] !== 'high' && value[0] !== 'low') {
|
|
564
|
+
throw new UsageError(`${value[0]}: unknown state`)
|
|
565
|
+
}
|
|
566
|
+
clargs.value = value[0] === 'high' ? 1 : 0
|
|
567
|
+
}
|
|
568
|
+
})
|
|
569
|
+
.parse(...args)
|
|
570
|
+
const { gpioMask, model } = await this._getInfo()
|
|
571
|
+
const bit = 1 << clargs.gpio
|
|
572
|
+
if ((bit & gpioMask) === 0) {
|
|
573
|
+
throw new UsageError(`gpio: GPIO ${clargs.gpio}: not available on Raspberry Pi ${model}`)
|
|
574
|
+
}
|
|
575
|
+
if (clargs.value != null) {
|
|
576
|
+
await this.pi.write(clargs.gpio, clargs.value)
|
|
577
|
+
}
|
|
578
|
+
const value = await this.pi.read(clargs.gpio)
|
|
579
|
+
this.print(value ? 'high' : 'low')
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
async pwm (...args) {
|
|
583
|
+
const clargs = {}
|
|
584
|
+
const parser = new CommandLineParser(this.pkgJson)
|
|
585
|
+
parser
|
|
586
|
+
.help('h', 'help', this.help)
|
|
587
|
+
.parameter('gpio', (value) => {
|
|
588
|
+
clargs.gpio = OptionParser.toInt('gpio', value)
|
|
589
|
+
})
|
|
590
|
+
.remaining((value) => {
|
|
591
|
+
if (value.length > 1) {
|
|
592
|
+
throw new UsageError('too many parameters')
|
|
593
|
+
}
|
|
594
|
+
if (value.length === 1) {
|
|
595
|
+
clargs.value = OptionParser.toInt('dutyCycle', value[0], 0, 100)
|
|
596
|
+
}
|
|
597
|
+
})
|
|
598
|
+
.parse(...args)
|
|
599
|
+
const { gpioMask, model } = await this._getInfo()
|
|
600
|
+
const bit = 1 << clargs.gpio
|
|
601
|
+
if ((bit & gpioMask) === 0) {
|
|
602
|
+
throw new UsageError(`gpio: GPIO ${clargs.gpio}: not available on Raspberry Pi ${model}`)
|
|
603
|
+
}
|
|
604
|
+
if (clargs.value != null) {
|
|
605
|
+
await this.pi.writePwm(clargs.gpio, clargs.value)
|
|
606
|
+
}
|
|
607
|
+
if (this.pi.port === 8888) {
|
|
608
|
+
const value = Math.round((await this.pi.command(
|
|
609
|
+
this.pi.commands.GDC, clargs.gpio
|
|
610
|
+
)).status / 2.55)
|
|
611
|
+
this.print(value)
|
|
612
|
+
} else if (clargs.value == null) {
|
|
613
|
+
this.warn('reading of duty cycle not supported by rgpio')
|
|
614
|
+
} else {
|
|
615
|
+
this.print(clargs.value)
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
async servo (...args) {
|
|
620
|
+
const clargs = {}
|
|
621
|
+
const parser = new CommandLineParser(this.pkgJson)
|
|
622
|
+
parser
|
|
623
|
+
.help('h', 'help', this.help)
|
|
624
|
+
.parameter('gpio', (value) => {
|
|
625
|
+
clargs.gpio = OptionParser.toInt('gpio', value)
|
|
626
|
+
})
|
|
627
|
+
.remaining((value) => {
|
|
628
|
+
if (value.length > 1) {
|
|
629
|
+
throw new UsageError('too many parameters')
|
|
630
|
+
}
|
|
631
|
+
if (value.length === 1) {
|
|
632
|
+
clargs.value = OptionParser.toInt('pulseWidth', value[0], 0)
|
|
633
|
+
if (clargs.value !== 0) {
|
|
634
|
+
clargs.value = OptionParser.toInt('pulseWidth', value[0], 500, 2500)
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
})
|
|
638
|
+
.parse(...args)
|
|
639
|
+
const { gpioMask, model } = await this._getInfo()
|
|
640
|
+
const bit = 1 << clargs.gpio
|
|
641
|
+
if ((bit & gpioMask) === 0) {
|
|
642
|
+
throw new UsageError(`gpio: GPIO ${clargs.gpio}: not available on Raspberry Pi ${model}`)
|
|
643
|
+
}
|
|
644
|
+
if (clargs.value != null) {
|
|
645
|
+
await this.pi.writeServo(clargs.gpio, clargs.value)
|
|
646
|
+
}
|
|
647
|
+
if (this.pi.port === 8888) {
|
|
648
|
+
const value = (await this.pi.command(this.pi.commands.GPW, clargs.gpio)).status
|
|
649
|
+
this.print(value)
|
|
650
|
+
} else if (clargs.value == null) {
|
|
651
|
+
this.warn('reading of pulse width not supported by rgpio')
|
|
652
|
+
} else {
|
|
653
|
+
this.print(clargs.value)
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
async dht (...args) {
|
|
658
|
+
const clargs = {}
|
|
659
|
+
const parser = new CommandLineParser(this.pkgJson)
|
|
660
|
+
parser
|
|
661
|
+
.help('h', 'help', this.help)
|
|
662
|
+
.parameter('gpio', (value) => {
|
|
663
|
+
clargs.gpio = OptionParser.toInt('gpio', value)
|
|
664
|
+
})
|
|
665
|
+
.parse(...args)
|
|
666
|
+
const { gpioMask, model } = await this._getInfo()
|
|
667
|
+
const bit = 1 << clargs.gpio
|
|
668
|
+
if ((bit & gpioMask) === 0) {
|
|
669
|
+
throw new UsageError(`gpio: GPIO ${clargs.gpio}: not available on Raspberry Pi ${model}`)
|
|
670
|
+
}
|
|
671
|
+
this.pi
|
|
672
|
+
.on('listen', (mask) => { this.debug('listening for %s', this.pi.vmap(mask)) })
|
|
673
|
+
const { GpioDhtClient } = await import('../lib/GpioDhtClient.js')
|
|
674
|
+
const dht = new GpioDhtClient(this, this.pi, clargs.gpio)
|
|
675
|
+
this.pi.mask = 1 << clargs.gpio
|
|
676
|
+
await this.pi.listen()
|
|
677
|
+
const { temperature, humidity } = await dht.read()
|
|
678
|
+
this.print('temperature: %dº', temperature)
|
|
679
|
+
this.print('humidity: %d%%', humidity)
|
|
680
|
+
}
|
|
681
|
+
|
|
462
682
|
async ledchain (...args) {
|
|
463
683
|
const clargs = {
|
|
464
684
|
mode: 'cylon',
|