npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@oahl/adapter-arduino

v0.1.1

Published

OAHL adapter for Arduino Uno — digital I/O, analog read, PWM, servo, I2C, SPI, EEPROM, and serial messaging over USB.

Readme

@oahl/adapter-arduino

OAHL adapter for Arduino Uno. Exposes digital I/O, analog reading, PWM output, servo control, I2C, SPI, EEPROM, and raw serial messaging to AI agents — over USB via Serial or Firmata protocol.


Prerequisites

  • Node.js >= 18
  • Arduino Uno connected via USB
  • Either:
    • A custom sketch uploaded that handles serial commands (for Serial mode)
    • StandardFirmata uploaded (for Firmata mode — Tools → Manage Libraries → search "Firmata" → upload StandardFirmata example)

Installation

npm install @oahl/adapter-arduino

Communication Modes

Every capability has a mode argument: "serial" or "firmata".

| Mode | How it works | Requires | |---|---|---| | firmata | Structured Firmata protocol via johnny-five | StandardFirmata sketch on the board | | serial | Raw string commands over serial | Custom sketch that parses the command format below |

Firmata is the default and recommended for most use cases — no custom sketch needed.

Serial Command Format (for custom sketches)

When using mode: "serial", commands follow this pattern:

| Command | Meaning | |---|---| | DW:<pin>:<0\|1> | Digital write | | DR:<pin> | Digital read | | AR:<pin> | Analog read | | PW:<pin>:<0-255> | PWM write | | SV:<pin>:<angle> | Servo write | | PM:<pin>:<mode> | Set pin mode | | I2C:SCAN | Scan I2C bus | | I2C:W:<addr>:<reg>:<bytes> | I2C write | | I2C:R:<addr>:<reg>:<len> | I2C read | | SPI:<cs>:<bytes> | SPI transfer | | EE:R:<addr>:<len> | EEPROM read | | EE:W:<addr>:<bytes> | EEPROM write |


Usage

Register in oahl-config.json

{
  "adapters": [
    {
      "id": "arduino-adapter",
      "module": "@oahl/adapter-arduino"
    }
  ]
}

Use directly in code

import ArduinoAdapter from '@oahl/adapter-arduino';

const adapter = new ArduinoAdapter({ baudRate: 9600 });
await adapter.initialize();

const devices = await adapter.getDevices();
// [{ id: '/dev/ttyACM0', type: 'arduino-uno', name: 'Arduino Uno @ /dev/ttyACM0' }]

const deviceId = devices[0].id;

// Blink the built-in LED (pin 13) 3 times
await adapter.execute(deviceId, 'digital.blink', { pin: 13, times: 3, onMs: 500 });

// Read a potentiometer on A0
const reading = await adapter.execute(deviceId, 'analog.read', { pin: 0 });
console.log(reading.voltage); // e.g. 2.47

// Set a servo to 90 degrees
await adapter.execute(deviceId, 'servo.write', { pin: 9, angle: 90 });

Capabilities

Connection

serial.connect

Open the serial port. Called automatically by all other capabilities, but useful to pre-warm the connection.

| Arg | Type | Default | Description | |---|---|---|---| | baudRate | integer | 9600 | Serial baud rate | | waitMs | integer | 2000 | Wait after open (for Arduino reset) |

serial.disconnect

Close the serial port.

firmata.connect

Connect via Firmata protocol. Requires StandardFirmata on the board.


Serial Messaging

serial.send

Send a raw string to the Arduino.

| Arg | Type | Default | Description | |---|---|---|---| | message | string | — | String to send | | awaitResponse | boolean | false | Wait for a response line | | responseTimeoutMs | integer | 3000 | — |

serial.read

Read buffered lines from the Arduino's serial output.

| Arg | Type | Default | Description | |---|---|---|---| | lines | integer | 10 | Max lines to return | | waitMs | integer | 200 | Wait time before reading | | flush | boolean | false | Clear buffer after read |

serial.flush

Clear the receive buffer.

serial.send_command

Send a command and collect response lines.

| Arg | Type | Description | |---|---|---| | command | string | Command string | | responseLines | integer | Lines to collect (default 1) | | responseTimeoutMs | integer | Timeout (default 3000ms) |


Digital I/O

digital.write

Set a pin HIGH or LOW.

await adapter.execute(deviceId, 'digital.write', { pin: 13, value: 1 });

digital.read

Read a pin's current value.

const { value } = await adapter.execute(deviceId, 'digital.read', { pin: 7 });

digital.write_bulk

Write multiple pins at once.

await adapter.execute(deviceId, 'digital.write_bulk', {
  pins: [{ pin: 8, value: 1 }, { pin: 9, value: 0 }]
});

digital.read_all

Read all 14 digital pins simultaneously.

digital.pulse

Pulse a pin HIGH for a duration then back LOW.

| Arg | Type | Default | |---|---|---| | pin | integer | — | | durationMs | integer | 100 |

digital.blink

Blink a pin N times.

| Arg | Type | Default | |---|---|---| | pin | integer | — | | times | integer | 3 | | onMs | integer | 500 | | offMs | integer | 500 |


Analog Read

analog.read

Read an analog pin. Returns raw (0-1023) and voltage (0-5V).

const { raw, voltage } = await adapter.execute(deviceId, 'analog.read', { pin: 0, samples: 5 });

| Arg | Type | Default | Description | |---|---|---|---| | pin | integer | — | Analog pin 0-5 (A0-A5) | | samples | integer | 1 | Readings to average | | intervalMs | integer | 50 | Between samples |

analog.read_all

Read all 6 analog pins at once.

analog.read_stream

Sample a pin continuously for a duration and return all readings with timestamps.

| Arg | Type | Default | |---|---|---| | pin | integer | — | | durationMs | integer | 1000 | | intervalMs | integer | 100 |


PWM Output

PWM-capable pins on the Uno: 3, 5, 6, 9, 10, 11

pwm.write

Write a duty cycle value (0–255).

await adapter.execute(deviceId, 'pwm.write', { pin: 6, value: 128 }); // 50% duty cycle

pwm.fade

Fade from one value to another over a duration.

| Arg | Type | Default | |---|---|---| | pin | integer | — | | from | integer | 0 | | to | integer | 255 | | durationMs | integer | 1000 | | steps | integer | 50 |

servo.write

Set a servo angle (0–180°).

await adapter.execute(deviceId, 'servo.write', { pin: 9, angle: 90 });

servo.sweep

Sweep a servo back and forth between two angles.

| Arg | Type | Default | |---|---|---| | pin | integer | — | | from | integer | 0 | | to | integer | 180 | | sweeps | integer | 1 | | stepMs | integer | 15 |


I2C

I2C uses pins A4 (SDA) and A5 (SCL) on the Uno.

i2c.scan

Scan bus and return all responding addresses.

const { addresses, hex } = await adapter.execute(deviceId, 'i2c.scan', {});
// { addresses: [60], hex: ['0x3c'] }

i2c.write

Write bytes to a device.

await adapter.execute(deviceId, 'i2c.write', {
  address: 0x3C, register: 0x00, bytes: [0xAE]
});

i2c.read

Read bytes from a device.

const { bytes } = await adapter.execute(deviceId, 'i2c.read', {
  address: 0x68, register: 0x3B, length: 6
});

SPI

SPI pins on Uno: 10 (SS), 11 (MOSI), 12 (MISO), 13 (SCK)

spi.transfer

Send bytes and receive simultaneously. Requires a sketch that handles SPI:<cs>:<bytes> commands.

const { received } = await adapter.execute(deviceId, 'spi.transfer', {
  bytes: [0x9F], csPin: 10
});

EEPROM

The Uno has 1024 bytes of EEPROM (addresses 0–1023).

eeprom.read

const { bytes } = await adapter.execute(deviceId, 'eeprom.read', { address: 0, length: 4 });

eeprom.write

await adapter.execute(deviceId, 'eeprom.write', { address: 0, bytes: [72, 101, 108, 108] });

eeprom.clear

Writes 0xFF to all 1024 bytes.


Pin Management

pin.mode

Set a pin mode: INPUT, OUTPUT, INPUT_PULLUP, ANALOG, PWM.

pin.info

Return capabilities for a specific pin.

pin.list

Return all pins with their labels and capability flags.


Board

board.reset

Toggle DTR to trigger a hardware reset.

board.info

Return port, baud rate, connection mode, Firmata version, and pin counts.

board.ping

Send a message and wait for the echo. Useful to confirm the sketch is running.


Build

npm install
npm run build

Publish

npm publish --access public

License

Apache-2.0