Git Product home page Git Product logo

node-libgpiod's Introduction

Native nodejs bindings for libgpiod

npm Build Status MIT

Requirements / Dependencies

  • libgpiod 1.x (and devel headers)
  • nodejs (and devel headers)
  • linux (tested on fedora 33 running on raspberry pi model 3 B+ and rasp pi os on zero w)
  • c/c++ development tools

How to use into your project

First install libgpiod and node development packages, if not installed yet:

RPM based

# fedora
sudo dnf install libgpiod libgpiod-devel libgpiod-utils nodejs-devel
# openSUSE
sudo zypper in libgpiod libgpiod-devel libgpiod-utils nodejs-devel

DEB based

# debian and its variants
sudo apt install gpiod libgpiod2 libgpiod-dev libnode-dev

Then just add it as a regular nodejs dependency:

npm i node-libgpiod

node-gyp will do the rest for you.

Tested platforms

Technically speaking it should work with any modern vanilla kernel and libgpiod 1.x.

What about libgpiod 2.x?

We're still working on libgpiod 2.x

Status

We already are able to read and write pins!

Here goes the sample blink led hello-world.js:

const { version, Chip, Line } = require("node-libgpiod");

global.chip = new Chip(0);
global.line = new Line(chip, 17); // led on GPIO17
let count = 10;

console.log(version());
line.requestOutputMode();

const blink = () => {
  if(count){
    line.setValue(count-- % 2);
    setTimeout(blink,1000);
  } // else line.release(); 
  // not needed, libgpiod releases resources on process exit  
};

setTimeout(blink,1000);

Another example:

const { version, Chip, Line } = require("node-libgpiod");
const express = require("express");

const app = express();
// avoid chip and line being gc-collected
app.chip = new Chip(0);
app.line = new Line(app.chip, 17); // led on GPIO17

console.log(version());
app.line.requestOutputMode();

app.get("/on", (req,res) => {
  app.line.setValue(1);
  res.send("it's on");
});

app.get("/off", (req,res) => {
  app.line.setValue(0);
  res.send("it's off");
});

app.listen(3000);
console.log("running");

See our testcases for more information

See node-libgpiod-examples for more sample code

known issues

  • libgpiod 2.x series is around the corner, and its API is incompatible with 1.x the 2.x branch (under development) will handle 2.x while 0.x and 1.x will support libgpiod 1.x series.

  • gpio character device needs special udev rules in order to belong to a special group so non-root users could access it freely

    # /etc/udev/rules.d/85-gpiochip.rules 
    KERNEL=="gpiochip*", SUBSYSTEM=="gpio", MODE="0660", GROUP="wheel"
  • libgpiod must be installed in the system correctly with development headers otherwise npm install will fail.

  • inside libgpiod 1.x series there is a set of new flags created on 1.5.x version around 2019 and they where no back ported to previous ones libgpiod releases. Your build might break because of this, we're working on solve this.

  • node will garbage collect Chip and Line too early on certain cases. When writing the samples, the following error kept being thrown:

    /home/sombriks/git/sample-node-libgpiod/index2.js:12
        line.setValue(count-- % 2);
            ^
    
    Error: Unable to set value for this line
        at Timeout.blink [as _onTimeout] (/home/sombriks/git/sample-node-libgpiod/index2.js:12:10)
        at listOnTimeout (internal/timers.js:554:17)
        at processTimers (internal/timers.js:497:7)

    It occurs because main module body was already evaluated and finished while interval/timeout function still active, but has no local reference for Chip or Line instances. Therefore, v8 thinks that those objects can be garbage-collected releasing the underlying resources, giving us the error. To avoid this, make sure your objects will be present on function scope:

    const { version, Chip, Line } = require("node-libgpiod");
    
    const chip = new Chip(0);
    const line = new Line(chip, 17); // led on GPIO17
    let count = 20;
    
    console.log(version());
    line.requestOutputMode();
    
    const blink = function () {
      // avoid early gc
      this.chip = chip
      this.line = line
      if(count){
        line.setValue(count-- % 2);
        setTimeout(blink,500);
      }
    };
    
    setTimeout(blink,500);

    Or, probably it is even better to create you chip and line instances globally:

    global.mychip = new Chip(0);
    global.line1 = new Line(chip, 17);

Roadmap

  • basic read/write
  • basic instant read/write
  • Chip/Line abstractions
  • GPIO monitoring callbacks
  • Bulk read/write
  • Complete API parity with underlying C/C++ library

All features present on libgpiod eventually will be added to node bindings, then the node package will finally enter in 1.x series.

Also see our changelog and project updates for details.

Functionality parity

This is the api parity table:

Description Scope C/C++ Node
get line's instant value Miscellaneous gpiod_ctxless_get_value getInstantLineValue
set line's instant value Miscellaneous gpiod_ctxless_set_value setInstantLineValue
get number of lines in a chip Chip gpiod_chip_num_lines getNumberOfLines
get chip name Chip gpiod_chip_name getChipName
get chip label Chip gpiod_chip_label getChipLabel
get line/pin offset number Line gpiod_line_offset getLineOffset
get line/pin name Line gpiod_line_name getLineName
get line/pin value Line gpiod_line_get_value getValue
set line/pin value Line gpiod_line_set_value setValue
get line consumer Line gpiod_line_consumer getLineConsumer
set line for input (read) Line gpiod_line_request_input requestInputMode
set line for input with flags Line gpiod_line_request_input_flags requestInputModeFlags
set line for output (write) Line gpiod_line_request_output requestOutputMode
release the line Line gpiod_line_release release

Other implementations

Those are other notable libgpiod wrapper implementations:

Official C++ binding

Official Python binding

Golang binding

Rust binding

Contributing

This is open source, i am willing to evaluate PR's 😎

node-libgpiod's People

Contributors

alessandromrc avatar d-beamon avatar dependabot[bot] avatar dmitrydvorkin avatar khill-fbmc avatar noctarius avatar sombriks avatar splitice avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

node-libgpiod's Issues

support for gpioinfo

as post in #9 , implement calls to grab information about the chip, lines and so on. they can be quite useful at runtime.

Double defined line object, cannot call getValue or setValue funciton.

Hi, Leonardo
I defined line twice, then it occured "Error: Unable to get value for this line".
Is there some way to this error.
I make a nodered node which based on your node-libgpiod library. The first time is good,then move debug node and deploy again, error occurs. I think the reason it i double defined line object.

image
image

No longer compatible with libgpiod < 1.6.x

The documentation states in the requirements that this should be compatible with libgpiod 1.x. However, since version 0.4 it's no longer compatible with libgpiod versions lower than 1.6.0

image

It would be nice its compatibility could be maintained since LTS versions of many distros, like Ubuntu 20.04, are still shipped with libgpiod 1.4.

If not possible, I recommend updating the documentation and clarify the minimum requirements.

Attempting to test with Vitest

I decided to take a stab at getting your tests you wrote to work with Vitest since it is the new hotness.

I am getting close but getting this weird error, and since I don't know C++ I don't know what it means heh

image

When importing mysql2 and setting the value of lines in a setInterval it gives an EPERM error

This is a very strange issue, see below a piece of code that works, but when you require('mysql2') it stops working and gives the following error:

Error: EPERM, Operation not permitted
    at Timeout.main [as _onTimeout] (test.js:9:7)
    at listOnTimeout (node:internal/timers:573:17)
    at process.processTimers (node:internal/timers:514:7) {
  errno: 1,
  code: 'EPERM',
  syscall: '::setValue'
}

Also worth to mention is that this error only occurs when requiring mysql2 and calling the setValue in a setTimeout or setInterval

Code:

const lib = require('node-libgpiod');
const mysql2 = require('mysql2'); // when commenting this line everything works fine
const chip = new lib.Chip(4);
const line = new lib.Line(chip, 26);
line.requestOutputMode(0);

function main() {
        line.setValue(1);
}

setTimeout(main, 1000 * 30);

Versions:
Node: v20.13.1
mysql2: 3.9.8
node-libgpiod: 0.4.3
ubuntu: Ubuntu 24.04 LTS
Raspberry Pi 5B rev 1.0

Support for GPIO monitoring callbacks

I know that GPIO monitoring callbacks is in the roadmap but it would be really great addition. I have tried node-libgpiod with Raspberry Pi 5 4GB (I just needed to change new Chip(0) to new Chip(4)) and it works great for setting the outputs but don't know how to do the "monitoring" (like detecting push buttons connected to some GPIO). I am willing to sponsor the addition of the callbacks to the library.

input debounce?

Hi, first off, I'm trying to learn nodejs and gpio, and your module is the most platform independent I could find.
Almost all of gpio module for nodejs is geared toward raspberry pi, I'm on an Alwinner (nanopi neo) SOC.
The module works as demoed, but I'm using buttons and sometimes I'm getting more than one result on a single press,
Do you know of a workaround for it?

Missing gpiod_line_request_input_flags

Without support for gpiod_line_request_input_flags (which perhaps should be an additional argument in the requestInputMode) its not possible to set a pull up or pull down on the line.

This is the only thing preventing this library from being almost a drop-in replacement (that I have noticed) for the capabilities offered by most sysfs based APIs.

Required version of libgpiod?

Potential min libgpiod version or ifdefs required.

../src/line.cc:24:99: error: ‘GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE’ was not declared in this scope; did you mean ‘GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN’?
   24 |   Nan::Set(lineFlags, Nan::New("GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE").ToLocalChecked(), Nan::New(GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE));
      |                                                                                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                                                                   GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN
../src/line.cc:25:101: error: ‘GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN’ was not declared in this scope; did you mean ‘GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW’?
   25 |   Nan::Set(lineFlags, Nan::New("GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN").ToLocalChecked(), Nan::New(GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN));
      |                                                                                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                                                                     GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW
../src/line.cc:26:99: error: ‘GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP’ was not declared in this scope; did you mean ‘GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW’?
   26 |   Nan::Set(lineFlags, Nan::New("GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP").ToLocalChecked(), Nan::New(GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP));
      |                                                                                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                                                                   GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW

Havent yet dug into libgpiod to work out the required version.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.