JavaScript binding for I²C with support for multiple drivers

npm install @burgrp/i2c@1.0.6



JavaScript binding for I²C with support for multiple drivers.

To support auxiliary signals (such as interrupts), the library allows GPIO configuration, reading and writing.


const I2C = require("@burgrp/i2c");

 * This example reads temperature from LM75A sensor.
 * Please check the address - 0x4F means all address pins are pulled up.
 * Furthermore we configure output pin 5 connected to LED 
 * and we turn on the LED if the temperature is above 25°C.

async function start() {
    let i2c = await I2C("drake,gpioLED=5.out");
    try {

        let data = await i2c.i2cRead(0x4F, 2);
        let temperature = data.readInt16BE(0) / 256;

        console.info(`It is ${temperature}°C`);

        await i2c.setLED(temperature > 25);

    } finally {
        await i2c.close();

start().catch(e => console.error(e));


The library uses a connection string to select and configure the hardware I²C interface and GPIO.

The connection string selects the proper driver and further configures the driver if necessary.

Format of the connection string is:


Implemented drivers

driver sys


driver drake

There is a driver for Drake USB-I2C bridge, which is handy while developing or debugging on host computer. If not specified otherwise, the driver looks up for device 1209:7070.

Driver options
  • vid - VID of the device, optional, defaults to "1209"
  • pid - PID of the device, optional, defaults to "7070"
  • serial - Serial number of the device, optional

This selects the Drake USB-I2C bridge by given serial number (thus allows to distinguish between multiple connected bridges) and configures pin 5 as pull-up input rising interrupts on falling edge.

GPIO configuration

There is a generic, driver unified, way to configure GPIO pins.

On library API, pins are referred by pin names rather than physical pin numbers. This allows higher level of abstraction. Properties of the connection string starting with gpio prefix are treated as GPIO configuration. The connection string can contain multiple GPIO configurations.

Part of the property key after gpio prefix is the GPIO name.

Value of the gpio? property is a string with options. First two mandatory fields are pin number and direction. There are other options, which depends on pin direction.

This is an example of USB interface configured with two pins, first one called "Trigger" mapped to pin 6, which is open drain output with internal pull-up enabled and the second pin is called "Irq" mapped to pin 5 which is input with internal pull-up and firing interrupt on falling edge.


options of output pins

  • openDrain - configure pin for open drain mode, if not set pin is configured as push-pull
  • pullUp - enable internal pull-up resistor; this option is valid only in open-drain mode

options of input pins

  • pullDown - enable internal pull-down resistor
  • pullUp - enable internal pull-up resistor
  • irqRisingEdge - fire interrupt on rising edge
  • irqFallingEdge - fire interrupt on falling edge

Options pullDown and pullUp can not be set simultaneously.

Options irqRisingEdge and irqFallingEdge can be set simultaneously, in which case the interrupt is fired on any edge.


Library main module returns factory function which takes connection string as argument:

const I2C = require("@burgrp/i2c");
let i2c = await I2C("drake,gpioLED=5.out");
// now we have the i2c bus

I2C operations

I2C read and write operations are straightforward:

let buffer = await i2c.i2cRead(address, length);
await i2c.i2cWrite(address, buffer);

GPIO operations

Although there are two generic R/W functions available (async gpioRead(pinNumber) and async gpio(pinNumber, value)), preferred way is to use dynamically generated getters and setters named after pins:

With connection string as follows:

const I2C = require("@burgrp/i2c");
let i2c = await I2C("drake,gpioLED=5.out,gpioSignal=4.in.irqFallingEdge");

we have two pins: output called LED and input called Signal.

Then there is dynamically generated setter for LED pin:

await i2c.setLED(true); // turn the LED on
await i2c.setLED(false); // turn the LED on

And there is dynamically generated getter and interrupt handler registration for Signal pin:

let signalValue = await i2c.getSignal();
i2c.onSignal(async () => {
    console.info("Signal received!");

Closing the device

Always call close asynchronously. It may take some time to close the device due to pending IRQ event listener.

await i2c.close();


I2C-JS comes with simple command line tool i2c:

Usage: cli [options] [command]

  -V, --version             output the version number
  -c, --connection <value>  connection string, defaults to I2C environment variable
  -h, --help                display help for command

  read <address> <length>   Read data from I²C device
  write <address> <data>    Write data to I²C device
  scan                      Scan I²C bus for devices
  get <pin>                 Get value of the named GPIO pin
  set <pin> <value>         Set value of the named GPIO pin
  wait <pin>                Wait for interrupt on the named GPIO pin
  help [command]            display help for command

CLI can be installed globally as follows:

sudo npm install --unsafe-perm --global @burgrp/i2c