rpi-io 1.1.5 → 1.2.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/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # rpi-io
2
- ![Static Badge](https://img.shields.io/badge/rpi--io-_1.1.4_-FF5500?style=flat) ![Static Badge](https://img.shields.io/badge/Nodejs-%3E_23-66cc33?logo=nodedotjs&logoColor=white) ![Static Badge](https://img.shields.io/badge/NPM-%3E_10-CC3534?logo=npm&logoColor=white) ![Static Badge](https://img.shields.io/badge/Raspberry_Pi-Zero2_4B_5B-C51A4A?logo=raspberrypi&logoColor=white) ![Static Badge](https://img.shields.io/badge/OS-Bookworm_Trixie-0D7AB9?style=flat)
2
+ ![Static Badge](https://img.shields.io/badge/rpi--io-_1.2.x_-FF5500?style=flat) ![Static Badge](https://img.shields.io/badge/Nodejs-%3E_23-66cc33?logo=nodedotjs&logoColor=white) ![Static Badge](https://img.shields.io/badge/NPM-%3E_10-CC3534?logo=npm&logoColor=white) ![Static Badge](https://img.shields.io/badge/Raspberry_Pi-Zero2_4B_5B-C51A4A?logo=raspberrypi&logoColor=white) ![Static Badge](https://img.shields.io/badge/OS-Bookworm_Trixie-0D7AB9?style=flat)
3
3
 
4
4
 
5
5
  **rpi-io** is a lite [ESM](https://nodejs.org/api/esm.html#modules-ecmascript-modules) module for **Node.js** to control **Raspberry Pi** GPIO: access (in, out), input event detection and [PWM](https://en.wikipedia.org/wiki/Pulse-width_modulation) peripheral control.
@@ -228,7 +228,7 @@ let currentValue = myInput.get();
228
228
 
229
229
 
230
230
 
231
- #### monitor(edge, callback)
231
+ #### monitor(edge, callback, options)
232
232
 
233
233
  To monitor activities on some *in* GPIO and receive events in a callback function.
234
234
 
@@ -246,6 +246,9 @@ myButton.monitor("both", event => {
246
246
 
247
247
  - **edge** *{String}* 'rising', 'falling' or 'both'. Any other value stops instance monitoring.
248
248
  - **callback** *{Function}* Callback function with one Object parameter for input events on instance e.g. `event = {edge: 'rising,' time: 'Thu Oct 30 2025 18:12:35 GMT+0100'}`
249
+ - **options** *{Object}* Default value is `{bias: 'disable', bounce: 0}`
250
+ - `bias` To configure according your input connection. Supported value ares 'disable', 'pull-down' and 'pull-up'.
251
+ - `bounce` Delay in ms to filter callback on rebounce. Value between 0 and 1000. 0 means no filter.
249
252
 
250
253
  ##### Detected errors
251
254
 
@@ -403,7 +406,7 @@ console.log(Rio.os())
403
406
 
404
407
  To check if device is supported by **rpi-io** (device, model, os, middleware). It returns *true/false* and displays details in console.
405
408
 
406
- #### Rio.log(level)
409
+ #### Rio.logCfg(level)
407
410
  To set the level of console used in the module:
408
411
 
409
412
  - 0: no console
@@ -414,9 +417,9 @@ To set the level of console used in the module:
414
417
 
415
418
  ```javascript
416
419
  import {Rio} from "rpi-io";
417
- Rio.log(0)
420
+ Rio.logCfg(0)
418
421
  Rio.isSystemSupported() // Nothing displayed in console
419
- Rio.log(2)
422
+ Rio.logCfg(2)
420
423
  Rio.isSystemSupported() // See console below
421
424
  // 08:15:16.506 🔎 👍 Hardware is Raspberry Pi
422
425
  // 08:15:16.539 🔎 👍 Raspberry Pi 5 Model B Rev 1.0 is supported
@@ -430,9 +433,13 @@ Rio.isSystemSupported() // See console below
430
433
 
431
434
  The following table summarizes GPIO *set* average times with rpi-io v1.1.0 and various hardware and OS.
432
435
 
433
- | | RPi 5B | RPi 4B | RPi Zero2 |
434
- |----------|---------|------------|------------|
435
- | Bookworm | 1.37 ms | 4.56 ms | 9.07 ms |
436
- | Trixie | 3.82 ms | not tested | not tested |
436
+ 💡 If you can, stick to *Bookworm*: **rpi-io** has stability and performance issues with Trixie and libgpiod v2.2.1. I did not test libgpiod v1.6.3 on Trixie.
437
+
438
+ | | RPi 5B | RPi 4B | RPi Zero2 |
439
+ |----------|---------|----------|------------|
440
+ | Bookworm | 1.37 ms | 4.56 ms | 9.07 ms |
441
+ | Trixie | 3.82 ms | 11.29 ms | not tested |
442
+
443
+
437
444
  ---
438
445
 
package/esm/dev.mjs CHANGED
@@ -9,11 +9,11 @@ let debug = {
9
9
  // -------------------------------------------------------------------
10
10
  // FUNCTIONS
11
11
  /** ------------------------------------------------------------------
12
- * @function now
12
+ * @function nowStr
13
13
  * @description Return timestamp as formatted string
14
14
  * @return {String}
15
15
  */
16
- export const now = () => {
16
+ export const nowStr = () => {
17
17
  const date = new Date()
18
18
  return date.toLocaleTimeString() + "." + date.getMilliseconds().toLocaleString('en', {
19
19
  minimumIntegerDigits: 3,
@@ -29,7 +29,7 @@ export const now = () => {
29
29
  */
30
30
  export const log = function () {
31
31
  if (debug.log)
32
- console.log.apply(console, Array.prototype.concat.apply([now(), "🔎 "], arguments))
32
+ console.log.apply(console, Array.prototype.concat.apply([nowStr(), "🔎 "], arguments))
33
33
  }
34
34
 
35
35
  /** ------------------------------------------------------------------
@@ -38,15 +38,15 @@ export const log = function () {
38
38
  */
39
39
  export const trap = function () {
40
40
  if (debug.trap)
41
- console.log.apply(console, Array.prototype.concat.apply([now(), "⚠️", "\x1b[38;2;255;80;0m", ...arguments, "\x1b[0m"]))
41
+ console.log.apply(console, Array.prototype.concat.apply([nowStr(), "⚠️", "\x1b[38;2;255;80;0m", ...arguments, "\x1b[0m"]))
42
42
  }
43
43
 
44
44
  /** ------------------------------------------------------------------
45
- * @function cfgLog
45
+ * @function logCfg
46
46
  * @description Set log configuration
47
47
  * @param {Number} level 0: no log, 1: trap only, 2: trap and log
48
48
  */
49
- export const cfgLog = level => {
49
+ export const logCfg = level => {
50
50
  debug = {
51
51
  log: false,
52
52
  trap: false
package/esm/rio.mjs CHANGED
@@ -6,7 +6,7 @@
6
6
  import {spawn} from "child_process";
7
7
  import {writeFileSync, readFileSync} from "fs"
8
8
  import {exeFile, exeShell, wait} from "./utl.mjs"
9
- import {cfgLog, log, trap} from "./dev.mjs"
9
+ import {logCfg, log, trap} from "./dev.mjs"
10
10
 
11
11
  // -------------------------------------------------------------------
12
12
  // CLASS RIO AND FURTHER
@@ -33,12 +33,8 @@ export class Rio {
33
33
  static PWM_CHIP = "pwmchip0"
34
34
  static TYPES = ["in", "out", "pwm"]
35
35
 
36
- // List of used GPIOs
37
- static used_gpios = []
38
- // Object list of monitored inputs
39
- static monitored = {}
40
- // Current monitoring process
41
- static monitoringProcess = null
36
+ // Map of instances
37
+ static instances = new Map()
42
38
 
43
39
  // ---------------------------------------------------------------
44
40
  // GENERIC METHODS: constructor, disable
@@ -51,13 +47,18 @@ export class Rio {
51
47
  */
52
48
  constructor(gpio, type) {
53
49
 
54
- this.chip = Rio.RPI_CHIP
55
50
  this.gpio = gpio
56
51
  this.gpioStr = this.gpio.toString()
57
52
  this.gpioName = "GPIO" + this.gpioStr
58
53
  this.type = type
59
54
  this.os = Rio.os().name
60
55
  this.versionLib = Rio.version().substring(0, 4)
56
+ // Monitoring properties
57
+ this.watch = {
58
+ edge: "stop",
59
+ callback: false,
60
+ process: null
61
+ }
61
62
 
62
63
  // OS is not supported
63
64
  if (Rio.TESTED_OS.indexOf(this.os) === -1)
@@ -78,34 +79,19 @@ export class Rio {
78
79
  if (Rio.RPI_GPIOS.indexOf(gpio) === -1)
79
80
  throw new Error("This gpio is not supported: " + gpio)
80
81
 
81
- // gpio is already used
82
- if (Rio.used_gpios.indexOf(gpio) !== -1)
83
- throw new Error("This gpio is already used: " + gpio)
82
+ // gpio is already defined
83
+ if (Rio.instances.has(gpio))
84
+ throw new Error("This gpio is already defined: " + gpio)
84
85
 
85
86
  // this.read, this.write, monArgs depending on gpiolib version
86
87
  switch (this.versionLib) {
87
88
  case "v1.6":
88
- this.write = (value, time = 0) => {
89
+ this.write = (value) => {
89
90
  exeFile("gpioset", [Rio.RPI_CHIP, this.gpioStr + "=" + value])
90
91
  }
91
92
  this.read = () => {
92
93
  return exeFile("gpioget", [Rio.RPI_CHIP, this.gpioStr])
93
94
  }
94
- this.monArgs = gpios => {
95
- let args = []
96
- args.push("-b") // line-buffered: output is flushed after every line
97
- args.push("--format=%o %e") // gpio, edge. Others: seconds(%s) and nanoseconds (%n)
98
- args.push(Rio.RPI_CHIP)
99
- args = args.concat(gpios)
100
- return args
101
- }
102
- this.monData = data => {
103
- const [gpio, edge] = data.toString().trim().split(/\s+/)
104
- return {
105
- gpio: gpio,
106
- edge: edge
107
- }
108
- }
109
95
  break
110
96
  case "v2.2":
111
97
  this.write = (value, time = 0) => {
@@ -114,19 +100,6 @@ export class Rio {
114
100
  this.read = () => {
115
101
  return exeFile("gpioget", ["--numeric", this.gpioName])
116
102
  }
117
- this.monArgs = gpios => {
118
- gpios = gpios.map(gpio => "GPIO" + gpio)
119
- let args = []
120
- args = args.concat(gpios)
121
- return args
122
- }
123
- this.monData = data => {
124
- const [time, edge, gpio] = data.toString().trim().split(/\s+/)
125
- return {
126
- gpio: gpio.substring(5,7),
127
- edge: edge
128
- }
129
- }
130
103
  break
131
104
  }
132
105
 
@@ -148,21 +121,26 @@ export class Rio {
148
121
  this.pathPwm = "/sys/class/pwm/" + this.pwm + "/"
149
122
  this.pathChannel = this.pathPwm + "pwm" + this.channel + "/"
150
123
  }
124
+ // Everything OK => Add this to instance list
125
+ Rio.instances.set(gpio, this)
126
+ log("new gpio instance created:", this.gpio)
151
127
  }
152
128
 
153
129
  /** --------------------------------------------------------------
154
130
  * @function disable
155
- * @description Remove instance from Rio.used_gpios
131
+ * @description Remove instance from Rio.instances
156
132
  * Set this.gpio = -1
157
133
  */
158
134
  disable() {
159
- const i = Rio.used_gpios.indexOf(this.gpio)
160
- if (this.gpio === -1 || i === -1) {
161
- log("gpio", this.gpio, "is already disabled")
162
- } else {
163
- Rio.used_gpios.splice(i, 1)
164
- log("gpio", this.gpio, "has been disabled")
135
+ if (Rio.instances.has(this.gpio)) {
165
136
  this.gpio = -1
137
+ this.watch.edge = "stop"
138
+ this.watch.callback = false
139
+ this.watch.process !== null ? this.watch.process.kill("SIGTERM") : false
140
+ Rio.instances.delete(this.gpio)
141
+ log("gpio", this.gpio, "has been disabled")
142
+ } else {
143
+ log("gpio", this.gpio, "is already disabled")
166
144
  }
167
145
  }
168
146
 
@@ -223,13 +201,112 @@ export class Rio {
223
201
  return result
224
202
  }
225
203
 
204
+ /** --------------------------------------------------------------
205
+ * @function monArgs
206
+ * @description Utility to take care gpiomon arguments according to libgpiod version
207
+ * @param {Array} gpios
208
+ * @param {Object} opt
209
+ * @return {Array}
210
+ */
211
+ #monArgs = (gpios, opt) => {
212
+ let args = []
213
+ switch (this.versionLib) {
214
+ case "v1.6":
215
+ args.push("-b") // line-buffered: output is flushed after every line
216
+ args.push("--bias=" + opt.bias)
217
+ args.push("--format=%o %e") // gpio, edge. Others: seconds(%s) and nanoseconds (%n)
218
+ args.push(Rio.RPI_CHIP)
219
+ return args.concat(gpios)
220
+ case "v2.2":
221
+ opt.bias === "disable" ? opt.bias = "disabled" : false
222
+ gpios = gpios.map(gpio => "GPIO" + gpio)
223
+ args.push("--bias")
224
+ args.push(opt.bias)
225
+ return args.concat(gpios)
226
+ }
227
+ }
228
+
229
+ /** --------------------------------------------------------------
230
+ * @function monData
231
+ * @description Utility to take care of gpiomon stdout data
232
+ * @param {String} data
233
+ * @return {Object}
234
+ */
235
+ #monData = data => {
236
+ switch (this.versionLib) {
237
+ case "v1.6":
238
+ const [gpioV1, edgeV1] = data.toString().trim().split(/\s+/)
239
+ return {
240
+ gpio: gpioV1,
241
+ edge: edgeV1
242
+ }
243
+ case "v2.2":
244
+ const [timeV2, edgeV2, gpioV2] = data.toString().trim().split(/\s+/)
245
+ return {
246
+ time: timeV2,
247
+ gpio: gpioV2.substring(5, 7),
248
+ edge: edgeV2
249
+ }
250
+ }
251
+ }
252
+ /** --------------------------------------------------------------
253
+ * @function monCallback
254
+ * @description Utility to trigger callback from gpiomon stdout data
255
+ * @param {String} data
256
+ */
257
+ #monCallback = data => {
258
+ const eventData = this.#monData(data)
259
+ const now = new Date()
260
+ const delta = Math.max(1, now - this.monitoredEvent.latest) // delta is always > 0ms
261
+ const edge = eventData.edge === "1" ? "rising" : "falling"
262
+
263
+ // Bounce detected
264
+ if (delta <= this.bounceTime && edge === this.monitoredEvent.edge) {
265
+ log("bounce detected on gpio", this.gpio, edge, delta + "ms")
266
+ }
267
+ // Trigger callback according to edge requirement
268
+ else {
269
+ if (this.watch.enabled.indexOf(edge) !== -1)
270
+ this.watch.callback(edge, now)
271
+ // log("monitored event on gpio", this.gpio, edge,)
272
+ }
273
+
274
+ // Update latest monitored event
275
+ this.monitoredEvent.latest = now
276
+ this.monitoredEvent.edge = edge
277
+ }
278
+
226
279
  /** --------------------------------------------------------------
227
280
  * @function monitor
228
281
  * @description Wait for edge events
229
282
  * @param {String} edge {'stop', 'rising', 'falling' 'both'}
230
283
  * @param {Function} callback (edge, time)
284
+ * @param {Object} opt - opt.bias {'disable','pull-up','pull-down'}
285
+ * - opt.bounce 0-1000
231
286
  */
232
- monitor(edge, callback) {
287
+ monitor(edge, callback, opt) {
288
+
289
+ // Default and clean parameters
290
+ const defaultCallback = (edge, time) => {
291
+ log("gpio", this.gpio, "event:", edge, time)
292
+ }
293
+ const defopt = {
294
+ bias: "disable",
295
+ bounce: 0
296
+ }
297
+
298
+ callback === undefined ? callback = defaultCallback : false
299
+ opt = {...defopt, ...opt}
300
+ opt.bounce < 0 ? opt.bounce = 0 : false
301
+ opt.bounce > 1000 ? opt.bounce = 1000 : false
302
+ this.bounceTime = opt.bounce
303
+ this.monitoredEvent = {
304
+ latest: new Date(null),
305
+ edge: "none"
306
+ }
307
+
308
+ const biases = ["disable", "pull-up", "pull-down"]
309
+ biases.indexOf(opt.bias) === -1 ? opt.bias = "disable" : false
233
310
 
234
311
  if (this.gpio === -1)
235
312
  throw new Error("This instance is disabled")
@@ -237,47 +314,51 @@ export class Rio {
237
314
  if (this.type !== "in")
238
315
  throw new Error("Monitor is dedicated to 'in' instances")
239
316
 
240
- // Update monitoring list
241
- Rio.monitored[this.gpio] = {
242
- edge: edge,
243
- callback: callback
244
- }
317
+ if (["stop", "rising", "falling", "both"].indexOf(edge) === -1)
318
+ throw new Error("Edge " + edge + "is not supported")
245
319
 
246
- // Suspend current monitoring if any
247
- if (Rio.monitoringProcess !== null) {
248
- Rio.monitoringProcess.kill("SIGTERM")
249
- Rio.monitoringProcess = null
250
- }
320
+ if (typeof callback !== "function")
321
+ throw new Error("Callback is not a function")
251
322
 
252
- // Default stop command => Remove current gpio from monitoring list
253
- if (["rising", "falling", "both"].indexOf(edge) === -1) {
254
- delete Rio.monitored[this.gpio]
255
- log("gpio", this.gpio, "is no longer being monitored")
256
- }
323
+ // First time the instance is monitored or has been stopped
324
+ if (this.watch === "stop") {
257
325
 
258
- // If monitored list is not empty => relaunch gpiomon
259
- const list = Object.keys(Rio.monitored)
260
- if (list.length > 0) {
261
- Rio.monitoringProcess = spawn("gpiomon", this.monArgs(list))
262
- Rio.monitoringProcess.stdout.on("data", data => {
263
- // Retrieve event data
264
- const evd = this.monData(data)
265
- const that = Rio.monitored[parseInt(evd.gpio)]
266
- if (typeof that.callback === "function") {
267
- if (evd.edge === "1") {
268
- if (that.edge === "rising" || that.edge === "both")
269
- that.callback("rising", new Date())
270
- } else {
271
- if (that.edge === "falling" || that.edge === "both")
272
- that.callback("falling", new Date())
273
- }
326
+ if (edge === "stop") {
327
+ trap("cannot stop an unstarted monitoring on gpio", this.gpio)
328
+ }
329
+ // Edge is in ["rising", "falling", "both"]
330
+ else {
331
+ this.watch = {
332
+ edge: edge,
333
+ enabled: edge === "both" ? ["rising", "falling"] : [edge],
334
+ callback: callback,
335
+ process: spawn("gpiomon", this.#monArgs([this.gpio], opt))
274
336
  }
275
- })
276
- Rio.monitoringProcess.stderr.on("data", data => {
277
- trap("gpiomon stderr:", Buffer.from(data).toString())
278
- })
279
- } else {
280
- log("no more gpio to monitor")
337
+ this.watch.process.stdout.on("data", this.#monCallback)
338
+ }
339
+ }
340
+ // Instance is already monitored
341
+ else {
342
+ // Stop: Kill process and delete monitored data
343
+ if (edge === "stop") {
344
+ this.watch.process !== null ? this.watch.process.kill("SIGTERM") : false
345
+ this.watch.edge = "stop"
346
+ this.watch.enabled = []
347
+ this.watch.callback = false
348
+ this.watch.process = null
349
+ Rio.instances.set(this.gpio, this)
350
+ log("monitoring of gpio", this.gpio, "has been stopped")
351
+ }
352
+
353
+ // Kill process, update edge and callback, define new process
354
+ else {
355
+ this.watch.process !== null ? this.watch.process.kill("SIGTERM") : false
356
+ this.watch.edge = edge
357
+ this.watch.enabled = edge === "both" ? ["rising", "falling"] : [edge]
358
+ this.watch.callback = callback
359
+ this.watch.process = spawn("gpiomon", this.#monArgs([this.gpio], opt))
360
+ this.watch.process.stdout.on("data", this.#monCallback)
361
+ }
281
362
  }
282
363
  }
283
364
 
@@ -321,9 +402,9 @@ export class Rio {
321
402
 
322
403
  // Check duty cycle
323
404
  if (duty < this.dutyMin)
324
- throw new Error("PWM duty", duty, " is lower than duty min", this.dutyMin)
405
+ throw new Error("PWM duty " + duty + " is lower than duty min " + this.dutyMin)
325
406
  if (duty > this.dutyMax)
326
- throw new Error("PWM duty", duty, " is upper than duty max", this.dutyMax)
407
+ throw new Error("PWM duty" + duty + " is upper than duty max" + this.dutyMax)
327
408
 
328
409
  log("channel", this.channel, "normalized PWM data (period, duty, duty min, duty max):", this.period, this.duty, this.dutyMin, this.dutyMax)
329
410
 
@@ -450,10 +531,15 @@ Rio.version = () => {
450
531
  * @description Stop monitoring of all inputs
451
532
  */
452
533
  Rio.stopMonitoring = () => {
453
- Rio.monitoringProcess !== null ? Rio.monitoringProcess.kill("SIGTERM") : false
454
- Rio.monitored = {}
455
- Rio.monitoringProcess = null
456
- log("gpio monitoring stopped")
534
+ Rio.instances.forEach((that) => {
535
+ if (that.watch.process !== null) {
536
+ that.watch.process.kill("SIGTERM")
537
+ that.watch.edge = "stop"
538
+ that.watch.callback = false
539
+ that.watch.process = null
540
+ log("monitoring of gpio", that.gpio, "has been stopped")
541
+ }
542
+ })
457
543
  }
458
544
 
459
545
  /** ------------------------------------------------------------------
@@ -505,8 +591,6 @@ Rio.os = () => {
505
591
  */
506
592
  Rio.isSystemSupported = () => {
507
593
 
508
- const info = Rio.cpuInfo()
509
-
510
594
  // Test hardware
511
595
  if (/Raspberry Pi/i.test(Rio.cpuInfo()) === false) {
512
596
  trap("not a Raspberry Pi hardware")
@@ -544,10 +628,14 @@ Rio.isSystemSupported = () => {
544
628
  log("👍 Systems requirements for rpi-io are met")
545
629
  return true
546
630
  }
631
+ /** ------------------------------------------------------------------
632
+ * @function Rio.logCfg
633
+ */
634
+ Rio.logCfg = logCfg
547
635
  /** ------------------------------------------------------------------
548
636
  * @function Rio.log
549
637
  */
550
- Rio.log = cfgLog
638
+ Rio.log = log
551
639
  // -------------------------------------------------------------------
552
640
  // EoF
553
641
  // -------------------------------------------------------------------
package/esm/utl.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  // -------------------------------------------------------------------
2
2
  // RPi GPIO CONTROL - UTILITIES
3
3
  // -------------------------------------------------------------------
4
- import {log,trap} from "./dev.mjs"
4
+ import {log, trap} from "./dev.mjs"
5
5
  import {execSync, execFileSync, spawnSync} from "child_process"
6
6
 
7
7
  // -------------------------------------------------------------------
@@ -64,7 +64,7 @@ export const exeShell = cmd => {
64
64
  * @param {Array} args
65
65
  * @return {String} stdout or ""
66
66
  */
67
- export const exeFile = (file, args) => {
67
+ export const exeFile = (file, args = []) => {
68
68
  try {
69
69
  return execFileSync(file, args, {
70
70
  stdio: "pipe",
package/history.md CHANGED
@@ -1,8 +1,17 @@
1
- 1.0.0 - Oct 23 2025
1
+ 1.2.1 - Nov 10, 2025
2
2
  ===================
3
- Initial release: *Bookworm*, libgpiod 1.63
3
+ * Change utility API function name from `Rio.log` to `Rio.logCfg`.
4
4
 
5
- 1.1.0 - Oct 31 2025
5
+ 1.2.0 - Nov 07, 2025
6
+ ===================
7
+ * New option parameter for method `monitor` to take care of bias and bounces.
8
+ * Fixes and optimization
9
+
10
+ 1.1.0 - Oct 31, 2025
6
11
  ===================
7
12
  * Added support libgpiod 2.2.1
8
- * Tested with *Trixie*
13
+ * Tested with *Trixie*
14
+
15
+ 1.0.0 - Oct 23, 2025
16
+ ===================
17
+ Initial release: *Bookworm*, libgpiod 1.63
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rpi-io",
3
- "version": "1.1.5",
3
+ "version": "1.2.1",
4
4
  "description": "Nodejs module to control Raspberry Pi GPIO",
5
5
  "keywords": [
6
6
  "raspberry",
@@ -8,6 +8,9 @@
8
8
  "libgpiod",
9
9
  "nodejs",
10
10
  "esm",
11
+ "output",
12
+ "input",
13
+ "monitor",
11
14
  "pwm",
12
15
  "bookworm",
13
16
  "trixie"
package/scr/test.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // -------------------------------------------------------------------
2
2
  // RPi GPIO CONTROL TEST SCRIPT
3
3
  // -------------------------------------------------------------------
4
- import {log, trap, now} from "../esm/dev.mjs"
4
+ import {log, trap, nowStr} from "../esm/dev.mjs"
5
5
  import {ctrlC} from "../esm/utl.mjs"
6
6
  import {Rio} from "../esm/rio.mjs"
7
7
 
@@ -12,7 +12,7 @@ import {Rio} from "../esm/rio.mjs"
12
12
  * @param {String} txt
13
13
  */
14
14
  function info(cmd, txt) {
15
- console.log(now(), "🔎", "\x1b[38;2;0;160;16m", cmd, "\x1b[0m", txt)
15
+ console.log(nowStr(), "🔎", "\x1b[38;2;0;160;16m", cmd, "\x1b[0m", txt)
16
16
  }
17
17
 
18
18
  /** ------------------------------------------------------------------
@@ -35,7 +35,7 @@ function isNumber(str) {
35
35
  // TOP LEVEL TEST
36
36
  // -------------------------------------------------------------------
37
37
  (function () {
38
- Rio.log(2)
38
+ Rio.logCfg(2)
39
39
  ctrlC(Rio.stopMonitoring)
40
40
 
41
41
  if (process.argv.length < 3) {
@@ -84,19 +84,25 @@ function isNumber(str) {
84
84
  if (gpio > 0) {
85
85
  const btn = new Rio(gpio, "in")
86
86
  btn.get()
87
- /* btn.monitor("both", (event, time) => {
88
- log("event", event)
89
- }) */
90
87
  }
91
88
  break
92
89
  case "monitor":
93
- gpio = isNumber(process.argv[3])
94
- if (gpio > 0) {
95
- const btn = new Rio(gpio, "in")
96
- btn.monitor("both", (event) => {
97
- log("event", event)
98
- })
90
+ const gpio1 = isNumber(process.argv[3])
91
+ const gpio2 = isNumber(process.argv[4])
92
+ let btn1, btn2
93
+ if (gpio1 > 0) {
94
+ btn1 = new Rio(gpio1, "in")
95
+ btn1.monitor("rising")
99
96
  }
97
+ if (gpio2 > 0) {
98
+ btn2 = new Rio(gpio2, "in")
99
+ btn2.monitor("falling", () => {
100
+ log(gpio2, "falling")
101
+ }, {bias: "pull-down"})
102
+ }
103
+ setTimeout(() => {
104
+ btn1.monitor("stop")
105
+ }, 6000)
100
106
  break
101
107
  case "benchmark":
102
108
  const gpioOut = isNumber(process.argv[3])
@@ -138,7 +144,7 @@ function isNumber(str) {
138
144
  setTimeout(() => {
139
145
  servo.pwmDuty(1500000)
140
146
  log("servo position = 90°")
141
- },2000)
147
+ }, 2000)
142
148
 
143
149
  // after 4s -> duty=1.5 ms
144
150
  setTimeout(() => {