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

abb-rws-client

v0.5.0

Published

A typed TypeScript/Node.js HTTP and WebSocket client for **ABB IRC5 robot controllers** using [Robot Web Services (RWS) 1.0](https://developercenter.robotstudio.com/api/rwsApi/).

Readme

abb-rws-client

A typed TypeScript/Node.js HTTP and WebSocket client for ABB IRC5 robot controllers using Robot Web Services (RWS) 1.0.

Compatibility: RWS 1.0 / RobotWare 6.x only.
Not compatible with OmniCore, RobotWare 7.x, or RWS 2.0.


VS Code Extension

Prefer a GUI? The companion VS Code extension gives you live status, motion data, RAPID control, I/O signals, event log, and file management directly from the sidebar — no code required.

ABB Robot (RWS) — VS Code Marketplace


Features

  • HTTP Digest Authentication (RFC 2617) — no external auth libraries
  • Session cookie management (ABBCX, -http-session-) with automatic reuse
  • Request rate limiting (< 20 req/sec, configurable)
  • Automatic re-authentication after session expiry
  • WebSocket subscriptions for real-time events
  • Auto-reconnect on WebSocket disconnect (3 retries, exponential backoff)
  • Fully typed public API — every method throws RwsError with a typed code
  • Zero runtime dependencies — Node.js built-ins only

Installation

npm install abb-rws-client

Requirements: Node.js 18+ (WebSocket subscriptions require Node 21+ or Node 18 with --experimental-websocket).


Quick Start

import { RwsClient, RwsError } from 'abb-rws-client';

const client = new RwsClient({
  host: '192.168.125.1',
  username: 'Default User',
  password: 'robotics',
});

await client.connect();

// Controller state
const state = await client.getControllerState(); // 'motoron' | 'motoroff' | ...
const mode  = await client.getOperationMode();   // 'AUTO' | 'MANR' | 'MANF'

// Motion
const joints    = await client.getJointPositions();    // rax_1..rax_6 in degrees
const tcp       = await client.getCartesianPosition(); // x/y/z mm + quaternion
const tcpConfig = await client.getCartesianFull();     // + j1/j4/j6/jx config flags

// RAPID
await client.startRapid();
await client.stopRapid();
await client.resetRapid(); // PP to Main

// Variables
const val = await client.getRapidVariable('T_ROB1', 'user', 'reg1');
await client.setRapidVariable('T_ROB1', 'user', 'reg1', '42');

// I/O signals
const signals = await client.listAllSignals();
await client.writeSignal('Local', 'DRV_1', 'DO_1', '1');

// Real-time subscriptions
const unsubscribe = await client.subscribe(
  ['execution', 'controllerstate', { type: 'signal', name: 'Local/DRV_1/DI_1' }],
  (event) => console.log(event.resource, '=', event.value),
);
await unsubscribe();

await client.disconnect();

API Reference

Constructor

new RwsClient(options: RwsClientOptions)

| Option | Type | Default | Description | |--------|------|---------|-------------| | host | string | — | Controller IP or hostname | | port | number | 80 | HTTP port | | username | string | 'Default User' | RWS username | | password | string | 'robotics' | RWS password | | requestIntervalMs | number | 55 | Min ms between requests (enforces < 20 req/sec) | | timeout | number | 5000 | Request timeout in ms | | sessionCookie | string | — | Saved cookie to reuse an existing session slot |


Connection

| Method | Returns | Description | |--------|---------|-------------| | connect() | void | Establish session and authenticate | | disconnect() | void | Close WebSocket subscriptions and clear session | | getSessionCookie() | string \| null | Current session cookie — persist to avoid 70-session limit |


Controller State & Panel

| Method | Returns | Description | |--------|---------|-------------| | getControllerState() | ControllerState | Motor state: motoron / motoroff / guardstop / emergencystop / … | | setControllerState(state) | void | Set motor state — requires mastership | | getOperationMode() | OperationMode | AUTO / MANR / MANF | | lockOperationMode(pin, permanent?) | void | Lock FlexPendant key switch with PIN | | unlockOperationMode() | void | Unlock FlexPendant key switch | | getSpeedRatio() | number | Speed override 0–100 | | setSpeedRatio(ratio) | void | Set speed override — AUTO mode only | | getCollisionDetectionState() | CollisionDetectionState | INIT / TRIGGERED / CONFIRMED / TRIGGERED_ACK | | restartController(mode?) | void | restart / istart / pstart / bstart | | getControllerIdentity() | ControllerIdentity | Name, ID, type, MAC address | | getSystemInfo() | SystemInfo | RobotWare version, options, system ID | | getControllerClock() | ControllerClock | Current date/time (UTC) | | setControllerClock(y,mo,d,h,mi,s) | void | Set controller date/time (UTC) |


RAPID Execution

| Method | Returns | Description | |--------|---------|-------------| | getRapidExecutionState() | ExecutionState | 'running' | 'stopped' | | getRapidExecutionInfo() | ExecutionInfo | State + current cycle mode | | getRapidTasks() | RapidTask[] | All tasks with name, type, state, active flag | | startRapid() | void | Start execution (AUTO + motors on required) | | stopRapid() | void | Stop execution | | resetRapid() | void | Reset program pointer to Main | | setExecutionCycle(cycle) | void | 'once' | 'forever' | 'asis' | | activateRapidTask(task) | void | Activate a task (multitasking) | | deactivateRapidTask(task) | void | Deactivate a task | | activateAllRapidTasks() | void | Activate all tasks | | deactivateAllRapidTasks() | void | Deactivate all tasks |


RAPID Variables & Symbols

| Method | Returns | Description | |--------|---------|-------------| | getRapidVariable(task, module, symbol) | string | Read variable as RAPID-syntax string | | setRapidVariable(task, module, symbol, value) | void | Write variable (RAPID syntax: '42', '"hello"', '[1,0,0,0]') | | validateRapidValue(task, value, datatype) | boolean | Validate value against datatype before writing | | getRapidSymbolProperties(task, module, symbol) | RapidSymbolProperties | Type, dims, storage class, flags | | searchRapidSymbols(params) | RapidSymbolInfo[] | Search by task, type, datatype, or regex | | getActiveUiInstruction() | UiInstruction \| null | Detect if RAPID is waiting for operator input | | setUiInstructionParam(stackurl, param, value) | void | Respond to a UI instruction (TPReadNum, TPReadFK…) |


RAPID Modules

| Method | Returns | Description | |--------|---------|-------------| | listModules(taskName) | string[] | Names of all loaded modules in a task | | loadModule(task, modulePath, replace?) | void | Load module from controller filesystem into task | | unloadModule(task, moduleName) | void | Unload module from task (RAPID must be stopped) |


Motion

| Method | Returns | Description | |--------|---------|-------------| | getJointPositions(mechunit?) | JointTarget | rax_1–rax_6 in degrees (default mechunit: ROB_1) | | getCartesianPosition(mechunit?, tool?, wobj?) | RobTarget | TCP x/y/z (mm) + q1–q4 quaternion | | getCartesianFull(mechunit?) | CartesianFull | TCP pose + j1/j4/j6/jx configuration flags |


File System

| Method | Returns | Description | |--------|---------|-------------| | listDirectory(remotePath) | FileEntry[] | Browse a directory ($HOME, $TEMP, …) | | readFile(remotePath) | string | Download file as UTF-8 string | | uploadModule(remotePath, content) | void | Upload file content (max 800 MB) | | deleteFile(remotePath) | void | Delete file | | createDirectory(parentPath, dirName) | void | Create directory | | copyFile(sourcePath, destPath) | void | Copy file on controller |


I/O Signals

| Method | Returns | Description | |--------|---------|-------------| | listAllSignals(start?, limit?) | Signal[] | Paginated flat list of all signals | | readSignal(network, device, name) | Signal | Read a specific signal by address | | writeSignal(network, device, name, value) | void | Write DO/AO/GO — value as string: '1', '0', '3.14' | | listNetworks() | IoNetwork[] | All I/O networks | | listDevices(network) | IoDevice[] | Devices on a network |

Pass '' for network and device to use the flat signal path (works by signal name alone).


Event Log

| Method | Returns | Description | |--------|---------|-------------| | getEventLog(domain?, lang?) | ElogMessage[] | Read log messages (domain 0 = main, newest first) | | clearEventLog(domain?) | void | Clear messages in one domain | | clearAllEventLogs() | void | Clear all domains |


Mastership

Required before modifying motor state, speed ratio, or certain RAPID operations.

| Method | Returns | Description | |--------|---------|-------------| | requestMastership(domain) | void | Take control — 'cfg' | 'motion' | 'rapid' | | releaseMastership(domain) | void | Release control — always call in finally |

await client.requestMastership('rapid');
try {
  await client.setControllerState('motoron');
} finally {
  await client.releaseMastership('rapid');
}

WebSocket Subscriptions

const unsubscribe = await client.subscribe(resources, handler);
// ...
await unsubscribe();

| Resource | Type | Description | |----------|------|-------------| | 'execution' | string | RAPID execution state changes | | 'controllerstate' | string | Motor state changes | | 'operationmode' | string | Operation mode changes | | 'speedratio' | string | Speed ratio changes | | 'coldetstate' | string | Collision detection state | | 'uiinstr' | string | Active UI instruction changes | | { type: 'execycle' } | object | Execution cycle mode changes | | { type: 'taskchange', task } | object | Task state changes | | { type: 'signal', name } | object | I/O signal value changes | | { type: 'persvar', name } | object | RAPID persistent variable changes | | { type: 'elog', domain } | object | New event log entries |

SubscriptionEvent: { resource: string, value: string, timestamp: Date }


Error Handling

All public methods throw RwsError — never a plain Error.

| Code | Meaning | |------|---------| | 'AUTH_FAILED' | Wrong credentials or session rejected | | 'SESSION_EXPIRED' | Session timed out | | 'MOTORS_OFF' | Action requires motors on | | 'MODULE_NOT_FOUND' | Module file not found on controller | | 'CONTROLLER_BUSY' | Controller returned 503 — retry later | | 'RATE_LIMITED' | Too many requests (429) | | 'NETWORK_ERROR' | TCP / timeout / WebSocket error | | 'PARSE_ERROR' | Unexpected XML response format | | 'UNKNOWN' | Unmapped error — check httpStatus and rwsDetail |

try {
  await client.startRapid();
} catch (e) {
  if (e instanceof RwsError) {
    if (e.code === 'MOTORS_OFF') console.error('Enable motors first');
    else throw e;
  }
}

Session Persistence

The IRC5 controller allows a maximum of 70 concurrent RWS sessions. Persist the session cookie across restarts to always reuse the same slot:

import fs from 'fs';

// Save after connecting
const cookie = client.getSessionCookie();
if (cookie) fs.writeFileSync('.rws-session', cookie, 'utf8');

// Restore on next start
let sessionCookie: string | undefined;
try { sessionCookie = fs.readFileSync('.rws-session', 'utf8'); } catch {}

const client = new RwsClient({ host, username, password, sessionCookie });
await client.connect(); // reuses the existing session slot

Rate Limits

| Constraint | Value | |------------|-------| | Max request rate | 20 req/sec | | Client enforced interval | 55 ms between requests | | Max concurrent sessions | 70 | | Session inactivity timeout | 5 minutes | | Max session lifetime | 25 minutes | | Max file upload | 800 MB |


Compatibility

| | RobotWare 6.x (RWS 1.0) | RobotWare 7.x (RWS 2.0) | |--|--|--| | This package | ✅ Supported | ❌ Not compatible | | IRC5 controller | ✅ | n/a | | OmniCore controller | n/a | ❌ | | RobotStudio virtual | ✅ (127.0.0.1) | ❌ |


Resources


License

MIT — see LICENSE