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

@csllc/cs1816

v3.3.0

Published

Package used to communicate with CS1816-type BLE and USB Dongles

Downloads

172

Readme

@csllc/cs1816

TypeScript package for communicating with CS181x BLE/USB dongles — small hardware devices that provide wireless access to an attached local device or system over Bluetooth Low Energy or USB.

Installation

npm install @csllc/cs1816

Overview

The CS181x dongle acts as a BLE peripheral and connects by wire to a motor controller or other local device. This package runs on the BLE central side (mobile app, Node.js desktop, etc.) and handles:

  • Inspecting and reading dongle device information
  • Reading and writing device memory and objects
  • Configuring the dongle's hardware interface (I2C, serial, CAN)
  • Monitoring variables via watchers and the super watcher
  • Sending commands such as keyswitch control and device reset

Two concrete dongle implementations are provided:

  • BleDongle — for BLE connections. Requires a Ble-compatible adapter such as @csllc/noble-ble or @csllc/mb-conn-noble-mac.
  • UsbDongle — for USB/serial connections. Requires a Connection from @csllc/mb-conn-node-serial.

Both follow the same lifecycle: construct, then call initialize() to open the connection, create the MODBUS Master, and inspect device objects.

The exported serviceUuid string is the BLE service UUID that CS181x dongles advertise. Use it with your BLE manager's scan function to discover dongles.

Usage

BLE dongle

import { BleDongle, serviceUuid } from '@csllc/cs1816';
import { NobleMacBleManager } from '@csllc/mb-conn-noble-mac';

await NobleMacBleManager.initialize();

// Scan for a dongle advertising serviceUuid
await NobleMacBleManager.startScan([serviceUuid], (peripheral) => {
  console.log('Found dongle:', peripheral.name);
});
// ... stop scan, get peripheral reference ...

// Construct and initialize — BleDongle handles BLE connect, UART discovery,
// and Master creation internally
const dongle = new BleDongle(NobleMacBleManager, peripheral, {
  logger: myLogger,
});
await dongle.initialize();

const info = await dongle.readDongleInfo();
console.log('Model:', info.model, 'SW:', info.sw);

USB dongle

import { UsbDongle } from '@csllc/cs1816';
import { SerialConnection } from '@csllc/mb-conn-node-serial';

const connection = new SerialConnection(
  { id: '/dev/ttyUSB0', type: 'serial', path: '/dev/ttyUSB0' },
  { baudRate: 9600 },
);

// Construct and initialize — UsbDongle opens the serial port and creates
// the MODBUS Master internally
const dongle = new UsbDongle(connection, { logger: myLogger });
await dongle.initialize();

const info = await dongle.readDongleInfo();
console.log('Model:', info.model, 'SW:', info.sw);

Reading dongle info

const info = await dongle.readDongleInfo();
// info: { model, serial, fw, hw, sw, mfr, product }

// After readDongleInfo(), softwareRevision is also available in multiple formats:
console.log(dongle.softwareRevision.string); // "1.10.0"
console.log(dongle.softwareRevision.scalar); // 0x010A00
console.log(dongle.softwareRevision.bytes); // { major: 1, minor: 10, patch: 0 }

Reading and writing memory

// Read 128 bytes starting at address 0x0300 from unit 1
const data = await dongle.readMemory(1, 0x0300, 128);

// Write bytes to unit 1 at address 0x0310
await dongle.writeMemory(1, 0x0310, [0x01, 0x02, 0x03]);

// Write with readback verification
await dongle.writeVerifyMemory(1, 0x0310, [0x01, 0x02, 0x03]);

Reading and writing objects

// Read object 0 from the dongle itself (unit ID is dongle.ID = 0xFE)
const config = await dongle.readObject(dongle.ID, 0);

// Write bytes to object 5 on unit 1
await dongle.writeObject(1, 5, [0xab, 0xcd]);

Access key

// Read the 128-byte cloud access key (object 0 on the dongle)
const key = await dongle.readAccessKey();

// Write a new access key
await dongle.writeAccessKey([...Array(128).keys()]);

Configuration and keyswitch

// Configure I2C interface
await dongle.configureI2c();

// Enable the keyswitch output
await dongle.keyswitch(true);

// Monitor interface status changes
await dongle.onInterfaceUpdate((iface, dongle) => {
  console.log('Interface status changed:', iface);
});

Watchers

// Watch 1 byte at address 0x0086 on unit 1
const slot = await dongle.watch(
  1,
  0x0086,
  1,
  undefined,
  (data, address, unit) => {
    console.log('Variable changed:', data[0]);
  },
);

// Cancel the watcher
dongle.unwatch(slot);

// Cancel all watchers
await dongle.unwatchAll();

Super watcher

The super watcher monitors a larger number of single-byte variables. Register all variables before calling updateSuperWatcher().

await dongle.clearSuperWatcher();

await dongle.superWatch(1, 0x0086, (data, address, unit) => {
  console.log(`Address ${address} on unit ${unit} changed:`, data);
});
await dongle.superWatch(1, 0x0087, (data, address, unit) => {
  console.log(`Address ${address} changed:`, data);
});

await dongle.updateSuperWatcher();

Batch registration

registerWatchers() and registerSuperWatchers() provide a simpler way to set up multiple watchers at once, without needing to handle BLE vs USB differences — the dongle subclass manages the transport-specific details internally.

import type { WatcherRegistration, SuperWatcherRegistration } from '@csllc/cs1816';

const watchers: WatcherRegistration[] = [
  { unit: 1, address: 0x0064, length: 2, cb: (value) => console.log('Voltage:', value) },
  { unit: 1, address: 0x0038, length: 1, cb: (value) => console.log('Fault:', value) },
];

const slots = await dongle.registerWatchers(watchers);
console.log('Registered in slots:', slots);

// Tear down all watchers (e.g. when the device interface goes down)
dongle.teardownWatchers();

Resetting a device

await dongle.reset(1);

API Reference

Exported symbols

| Symbol | Type | Description | | ---------------------- | ---------------------- | ------------------------------------------------------------ | | Dongle | abstract class | Abstract base class for all dongle types. | | UsbDongle | class extends Dongle | USB/serial dongle. Creates RTU Master internally. | | BleDongle | class extends Dongle | BLE dongle. Creates IP Master internally. | | DeviceInterface | class | Decoded hardware interface status (mode, protocol, up/down). | | Watcher | class | Represents a registered watcher slot. | | serviceUuid | string | BLE service UUID advertised by CS181x dongles. | | DONGLE_UUIDS | object | All BLE service and characteristic UUIDs for CS181x. | | ConfigureCommand | class | Configure dongle hardware interface (mode, protocol). | | DongleMode | enum | Hardware interface mode values. | | DongleProtocol | enum | Protocol values. | | KeySwitchCommand | class | Set keyswitch output state. | | WatchCommand | class | Set watcher slots on the device. | | WatchMaskedCommand | class | Set watcher slots with per-bit change masks. | | UnwatchCommand | class | Cancel specific watcher slots. | | UnwatchAllCommand | class | Cancel all watcher slots. | | SuperWatchCommand | class | Set superwatcher addresses. | | GetWatcherCommand | class | Query the device's watcher table. | | WatcherType | enum | Watcher query type. | | ResetCommand | class | Send a reset command to a device. | | DongleSlaveIdRequest | class | Report slave ID request. | | WatcherRegistration | interface | Configuration for registering a watcher. | | SuperWatcherRegistration | interface | Configuration for registering a superwatcher. | | WatcherCallback | type | Callback type for watcher/superwatcher updates. |


abstract class Dongle

Abstract base class managing MODBUS commands, watcher registry, and high-level dongle operations. All MODBUS operations use Master.requestAsync() with typed Request/Response classes.

Constructor

new Dongle(options: DongleOptions)

The constructor is lightweight — it stores options and initializes watcher arrays. The Master and connection are created by subclasses during initialize().

DongleOptions

| Property | Type | Default | Description | | ----------------------- | -------------- | -------------------------- | ------------------------------------------------ | | logger | DongleLogger | (stub) | Winston/pino-compatible logger for debug output. | | maxConcurrentRequests | number | 2 | Maximum simultaneous in-flight requests. | | defaultMaxRetries | number | 2 | Default retry count per transaction. | | defaultTimeout | number | 6500 | Default response timeout in milliseconds. | | retryOnException | number[] | [0x04, 0x06, 0x0A, 0x0B] | Exception codes that trigger a retry. |

Properties

| Property | Type | Description | | ------------------ | ----------------- | ------------------------------------------------------- | | ID | number | The dongle's Modbus unit address (0xFE). | | master | Master | The MODBUS Master instance (set during initialize()). | | peripheral | Connection | The underlying connection (set during initialize()). | | softwareRevision | DongleSwVersion | Software version (set after readDongleInfo()). | | watchers | Watcher[] | Array of registered watcher slots (max 15). | | superWatchers | Watcher[] | Array of super watcher slots (max 25). |

Methods

| Method | Returns | Description | | -------------------------------------------------- | -------------------------- | --------------------------------------------------------------------------------------------- | | initialize() | Promise<void> | Opens connection, creates Master, inspects device objects. Must be called after construction. | | destroy() | void | Destroys the master and clears watcher state. | | readDongleInfo() | Promise<DongleInfo> | Reads model, serial, firmware, hardware, software revision, and manufacturer. | | readInterface() | Promise<DeviceInterface> | Reads the current interface status object. | | readMemory(unit, address, length, options?) | Promise<number[]> | Reads bytes from device memory. | | writeMemory(unit, address, data, options?) | Promise<any> | Writes bytes to device memory. | | writeVerifyMemory(unit, address, data, options?) | Promise<any> | Writes and verifies bytes at device memory. | | readObject(unit, objectId, options?) | Promise<number[]> | Reads a MODBUS object by ID. | | writeObject(unit, objectId, data, options?) | Promise<number> | Writes data to an object. Returns status. | | readAccessKey() | Promise<number[]> | Reads the dongle's 128-byte cloud access key (object 0). | | writeAccessKey(data) | Promise<any> | Writes the dongle's cloud access key. | | command(unit, opcode, data?) | Promise<any> | Sends an FN_COMMAND with opcode and optional data. | | configure(options?) | Promise<any> | Sends the configuration command. | | configureI2c(options?) | Promise<void> | Configures I2C hardware interface. | | keyswitch(isEnabled, options?) | Promise<any> | Sets the keyswitch output state. | | onInterfaceUpdate(cb) | Promise<void> | Registers a callback for interface status changes. | | watch(unit, address, length, mask?, cb) | Promise<number> | Sets up a watcher. Returns the slot number. | | unwatch(slot) | void | Removes watcher at slot. | | unwatchAll(options?) | Promise<any> | Removes all watchers. | | superWatch(unit, address, cb) | Promise<number> | Registers a super watcher address. Returns slot. | | updateSuperWatcher(options?) | Promise<void> | Activates all registered super watchers. | | clearSuperWatcher(options?) | Promise<any> | Disables and clears super watcher slots. | | registerWatchers(registrations) | Promise<number[]> | Registers watchers from an array of configs. Returns slot indices. | | registerSuperWatchers(registrations) | Promise<number[]> | Registers superwatchers from an array of configs. Returns slot indices. | | teardownWatchers() | void | Resets all watcher and superwatcher slots to empty. | | reset(unit, options?) | Promise<number> | Sends a reset command. |


class UsbDongle extends Dongle

USB/serial dongle implementation. Creates a MODBUS Master with RTU transport over the supplied Connection.

Constructor

new UsbDongle(connection: Connection, options: DongleOptions)

The connection is a SerialConnection (or any Connection subclass). The Master is created during initialize(), not in the constructor.


class BleDongle extends Dongle

BLE dongle implementation. Connects to the BLE peripheral, discovers UART characteristics, creates an internal BLE UART connection, and creates a MODBUS Master with IP transport.

Constructor

new BleDongle(ble: Ble, blePeripheral: BlePeripheral, options: DongleOptions)
  • ble — a Ble-compatible adapter (e.g. NobleBleManager, NobleMacBleManager)
  • blePeripheral — the discovered BlePeripheral from scanning

initialize() handles BLE connect, characteristic discovery, UART connection setup, and Master creation.


DONGLE_UUIDS

Object containing all BLE service and characteristic UUIDs for CS181x dongles:

import { DONGLE_UUIDS } from '@csllc/cs1816';

DONGLE_UUIDS.uuidUartService; // '49535343-FE7D-4AE5-8FA9-9FAFD205E455'
DONGLE_UUIDS.uuidRx; // UART RX characteristic
DONGLE_UUIDS.uuidTx; // UART TX characteristic
DONGLE_UUIDS.uuidControllerService; // '6765ED1F-4DE1-49E1-4771-A14380C90000'
DONGLE_UUIDS.uuidDeviceInformation; // '180A'
// ... and more

class Watcher

Represents a single registered watcher slot. Normally constructed internally by Dongle.watch().

Properties

| Property | Type | Description | | --------- | ---------- | -------------------------------------------------------------------- | | unit | number | Slave unit being watched. | | address | number | Memory address being watched. | | length | number | Number of bytes being watched. | | hasMask | boolean | Whether a change mask is active. | | cb | function | Callback: (value: number[], address: number, unit: number) => void |


interface DongleInfo

Returned by readDongleInfo().

interface DongleInfo {
  model: string;
  serial: string;
  fw: string;
  hw: string;
  sw: string | undefined;
  mfr: string;
  product: string;
}

interface DongleLogger

interface DongleLogger {
  log(level: string, message: string, ...args: any[]): void;
  child(context: Record<string, any>): DongleLogger;
}

Message Classes

All message classes extend CommandRequest from @csllc/modbus-types:

  • ConfigureCommand — Configure hardware interface
  • KeySwitchCommand — Set keyswitch state
  • WatchCommand / WatchMaskedCommand — Set watchers
  • UnwatchCommand / UnwatchAllCommand — Cancel watchers
  • SuperWatchCommand — Set super watcher addresses
  • GetWatcherCommand — Query watcher table
  • ResetCommand — Reset device
  • DongleSlaveIdRequest — Report slave ID