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

@rejaul/react-native-usb-serial

v0.0.1

Published

Production-ready React Native USB serial communication module for Android with Modbus RTU soil sensor support

Readme

React-native-usb-serial

A professional-grade React Native module providing seamless USB serial communication for Android devices only. Built with Kotlin and supporting USB CDC devices, modbus sensors, and high-performance serial data streaming.

Important: This library is exclusively for Android. iOS is not supported due to platform limitations. For iOS projects, consider alternative solutions.

npm version license Platform - Android Only Kotlin TypeScript

Features

  • Full USB Device Control - Enumerate, connect, and manage USB devices
  • Real-time Data Streaming - Configurable interval-based serial data reading
  • Modbus Soil Sensors - Native support for 8-in-1 modbus soil sensors
  • Configurable Parameters - Custom baud rates, buffer sizes, and timeouts
  • Permission Handling - Integrated USB permission request management
  • Type-Safe - Full TypeScript support with comprehensive type definitions
  • High Performance - Native Android implementation for optimal throughput

Platform Support

| Platform | Status | Details | |----------|--------|---------| | Android | Fully Supported | API Level 24+ required | | iOS | Not Supported | iOS does not allow direct USB serial access | | Web | Not Supported | Web platform not compatible |

Why Android Only?

  • iOS Limitation: Apple's iOS sandboxing prevents direct USB serial device access without specific MFi (Made for iPhone) certification
  • Platform Design: This library uses Android's native USB Host API which is Android-specific
  • Alternative for iOS: Consider using Bluetooth/BLE modules instead

Important: If you have an iOS requirement, you must use a different architecture (e.g., Bluetooth serial modules with a compatible React Native Bluetooth library).

Minimum Requirements

  • React Native >= 0.71.0
  • Android API Level >= 24 (Android 7.0+)
  • Java 8+ (OpenJDK or Oracle JDK)
  • Kotlin 2.0.21+ (included in build system)

Installation

Android Only: This package only works on Android devices. It will not function on iOS.

npm install @rejaul/react-native-usb-serial
# or
yarn add @rejaul/react-native-usb-serial

Android Configuration

Add USB permissions to your AndroidManifest.xml:

<uses-permission android:name="android.permission.USB_PERMISSION" />
<uses-feature android:name="android.hardware.usb.host" />

Quick Start

Basic Device Enumeration

import {
  getDeviceList,
  type UsbDevice,
} from '@rejaul/react-native-usb-serial';

// Get all connected USB devices
const devices: UsbDevice[] = getDeviceList();

devices.forEach(device => {
  console.log(`Device: ${device.productName}`);
  console.log(`Vendor ID: ${device.vendorId}`);
  console.log(`Product ID: ${device.productId}`);
});

Device Connection with Permission Handling

import {
  hasPermission,
  requestUsbPermission,
  connect,
  disconnect,
} from '@rejaul/react-native-usb-serial';

async function connectToDevice(device: UsbDevice): Promise<void> {
  try {
    // Check existing permission
    let hasAccess = await hasPermission(device);

    // Request permission if needed
    if (!hasAccess) {
      hasAccess = await requestUsbPermission(device);
      if (!hasAccess) {
        throw new Error('USB permission denied');
      }
    }

    // Connect with custom baud rate (9600 is default)
    const connected = await connect(device, 115200);

    if (connected) {
      console.log('Connected successfully');
    }
  } catch (error) {
    console.error('Connection failed:', error);
  }
}

// Disconnect when done
await disconnect();

Real-time Serial Data Streaming

import {
  onReadInterval,
  offReadInterval,
  type RawReadConfig,
  NativeEventEmitter,
} from '@rejaul/react-native-usb-serial';

// Configure reading parameters
const readConfig: RawReadConfig = {
  bufferSize: 2048,    // Buffer size in bytes
  timeout: 1000,       // Read timeout in milliseconds
};

// Start listening for data every 100ms
await onReadInterval(100, readConfig);

// Listen to serial data events
const eventEmitter = new NativeEventEmitter();
const subscription = eventEmitter.addListener(
  'USB_SERIAL_DATA',
  (event: { data: string }) => {
    console.log('Received:', event.data);
  }
);

// Stop listening when done
await offReadInterval();

// Clean up
subscription.remove();

Writing Data to Serial Port

import { write, isConnected } from '@rejaul/react-native-usb-serial';

async function sendCommand(command: string): Promise<void> {
  try {
    const connected = await isConnected();
    if (!connected) {
      throw new Error('Device not connected');
    }

    await write(command);
    console.log('Data sent:', command);
  } catch (error) {
    console.error('Write failed:', error);
  }
}

// Send AT commands
await sendCommand('AT+RST\r\n');

Manual Serial Reading

import { read } from '@rejaul/react-native-usb-serial';

async function readSerialData(): Promise<void> {
  try {
    // Read with default buffer (1024 bytes) and timeout (1000ms)
    let data = await read();

    // Or with custom parameters
    data = await read(4096, 2000);

    console.log('Received:', data);
  } catch (error) {
    console.error('Read failed:', error);
  }
}

Advanced Usage

Soil Sensor Integration

import {
  readSoilData,
  onReadSoilDataInterval,
  offReadSoilDataInterval,
  type SoilSensorConfig,
  type SoilData,
  NativeEventEmitter,
} from '@rejaul/react-native-usb-serial';

// Configure modbus soil sensor
const soilConfig: SoilSensorConfig = {
  slaveId: 1,           // Modbus slave ID
  startAddress: 0x0000, // Register start address
  registerCount: 8,     // Number of registers to read
  responseDelayMs: 300, // Response wait time
};

// Read once
const soilData: SoilData | null = await readSoilData(soilConfig);
if (soilData) {
  console.log('Soil Moisture:', soilData.moisture);
  console.log('Soil Temperature:', soilData.temperature);
}

// Start continuous monitoring (every 500ms)
await onReadSoilDataInterval(500, soilConfig);

// Listen to soil sensor events
const eventEmitter = new NativeEventEmitter();
const subscription = eventEmitter.addListener(
  'USB_SOIL_DATA',
  (event: SoilData) => {
    console.log('Soil Data:', {
      moisture: event.moisture,
      temperature: event.temperature,
      ec: event.ec,
    });
  }
);

// Stop monitoring
await offReadSoilDataInterval();
subscription.remove();

Get Currently Connected Device

import { getConnectedDevice } from '@rejaul/react-native-usb-serial';

const device = await getConnectedDevice();
if (device) {
  console.log('Connected to:', device.productName);
  console.log('Serial Number:', device.serialNumber);
} else {
  console.log('No device connected');
}

Event Listening

Use NativeEventEmitter to listen to real-time data:

import { NativeEventEmitter } from 'react-native';

const eventEmitter = new NativeEventEmitter();

// Serial data events
const serialSub = eventEmitter.addListener('USB_SERIAL_DATA', (event) => {
  console.log('Serial:', event.data);
});

// Soil sensor events
const soilSub = eventEmitter.addListener('USB_SOIL_DATA', (event) => {
  console.log('Soil:', event);
});

// Clean up
serialSub.remove();
soilSub.remove();

Error Handling

import { connect, type UsbDevice } from '@rejaul/react-native-usb-serial';

async function safeConnect(device: UsbDevice): Promise<void> {
  try {
    const success = await connect(device);
    if (!success) {
      console.error('Connection failed');
    }
  } catch (error) {
    if (error instanceof Error) {
      console.error('Error:', error.message);
    }
  }
}

Type Definitions

UsbDevice

type UsbDevice = {
  deviceName: string;
  vendorId: number;
  productId: number;
  manufacturer?: string | null;
  productName?: string | null;
  serialNumber?: string | null;
};

RawReadConfig

type RawReadConfig = {
  bufferSize?: number;  // Default: 1024 bytes
  timeout?: number;     // Default: 1000 ms
};

SoilSensorConfig

type SoilSensorConfig = {
  slaveId?: number;        // Default: 1
  startAddress?: number;   // Default: 0x0000
  registerCount?: number;  // Default: 8
  responseDelayMs?: number; // Default: 300 ms
};

SoilData

type SoilData = {
  [key: string]: number;
  // Typical keys: moisture, temperature, ec, ph, etc.
};

API Reference

Device Management

getDeviceList(): UsbDevice[]

Get all connected USB devices synchronously.

hasPermission(device: UsbDevice): Promise<boolean>

Check if app has USB permission for a device.

requestUsbPermission(device: UsbDevice): Promise<boolean>

Request USB permission from user. Returns true if granted.

connect(device: UsbDevice, baudRate?: number): Promise<boolean>

Connect to a USB device. Default baud rate: 9600.

disconnect(): Promise<void>

Disconnect from current device.

isConnected(): Promise<boolean>

Check if currently connected to a device.

getConnectedDevice(): Promise<UsbDevice | null>

Get the currently connected device information.

Serial Communication

write(data: string): Promise<void>

Write data to the serial port.

read(bufferSize?: number, timeout?: number): Promise<string>

Read data from serial port. Useful for one-off reads.

onReadInterval(intervalMs: number, config?: RawReadConfig): Promise<void>

Start streaming serial data at specified interval. Emits USB_SERIAL_DATA events.

offReadInterval(): Promise<void>

Stop streaming serial data.

Soil Sensor

readSoilData(config?: SoilSensorConfig): Promise<SoilData | null>

Read modbus soil sensor data once.

onReadSoilDataInterval(intervalMs: number, config?: SoilSensorConfig): Promise<void>

Start reading soil sensor data periodically. Emits USB_SOIL_DATA events.

offReadSoilDataInterval(): Promise<void>

Stop reading soil sensor data.

Best Practices

  1. Always check connection status before writing/reading
  2. Handle permissions gracefully - Some devices may refuse access
  3. Use appropriate timeouts for different devices
  4. Clean up listeners to prevent memory leaks
  5. Validate device IDs before connecting
  6. Buffer large data properly with adequate buffer sizes
  7. Test with real devices - Emulator USB support is limited

Example Application

See the example directory for a complete React Native application demonstrating:

  • Device enumeration and listing
  • Permission management
  • Connection lifecycle
  • Real-time data streaming
  • Error handling
cd example
yarn install
yarn android

Troubleshooting

Device Not Detected

  • Ensure USB debugging is enabled
  • Check USB cable connection
  • Verify device is recognized by adb devices

Permission Denied

  • Grant USB permission when prompted
  • Check AndroidManifest.xml permissions
  • Restart app if permission prompt was dismissed

No Data Received

  • Verify baud rate matches device
  • Check serial cable quality
  • Increase read timeout value
  • Ensure device is sending data

Connection Drops

  • Check USB cable stability
  • Reduce read interval if too frequent
  • Monitor system resources
  • Check device firmware

Performance Tips

  • Use appropriate buffer sizes (1024-4096 for most cases)
  • Adjust read intervals based on data volume
  • Unsubscribe from events when not needed
  • Handle large data streams with chunking
  • Monitor memory usage with large buffers

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

Code of Conduct

This project adheres to the Code of Conduct.

License

MIT - See LICENSE file for details.

Support

For issues, questions, or suggestions, please open an issue on GitHub.


Made with ❤️ for the React Native community