nut-client is a Node.js client for Network UPS Tools (NUT), enabling advanced communication with NUT servers for UPS management. It is built to be robust, performant, and easy to integrate, supporting parallel requests, automatic reconnection, and event-based monitoring via Promises.
npm install nut-client
# or
pnpm add nut-client
# or
yarn add nut-clientSupported Node.js versions: >=18
-
NUT Command Support : Most NUT commands are supported, with automatic parsing of responses to simplify integration. Additionally, a manual mode is available for full control.
import { NUTClient } from 'nut-client' const client = new NUTClient('127.0.0.1', 3493); console.log(await client.listUPS()); console.log(await client.listVariables('ups')); // Run an instant command with optional parameter await client.runCommand('myups', 'shutdown.return', '60'); // Manual command console.log(await client.send(['LIST', 'VAR', 'myups']));
-
Parallel Request Handling : Unlike other NUT libraries,
nut-clientmanages an internal queue to handle parallel requests without conflicts, using Promises for efficient request handling.import { NUTClient } from 'nut-client' const client = new NUTClient('127.0.0.1', 3493); const [ups1, ups2, ups3] = await Promise.all([ client.getUPS('ups1'), client.getUPS('ups2'), client.getUPS('ups3'), ])
-
Auto-Reconnect : The client can automatically reconnect on connection loss with exponential backoff, jitter, and configurable limits. Credentials and TLS state are restored automatically.
import { NUTClient } from 'nut-client' const client = new NUTClient('127.0.0.1', 3493, { autoReconnect: true, username: 'admin', password: 'secret', reconnectDelay: 1000, // initial delay (ms) maxReconnectDelay: 30000, // cap for exponential backoff reconnectBackoff: 2, // multiplier maxReconnectAttempts: 10, // give up after N attempts }); client.on('reconnected', () => console.log('Reconnected!')); client.on('reconnectExhausted', () => console.log('No more retries')); // Or use the static factory for connect + auth in one call const client2 = await NUTClient.create('127.0.0.1', 3493, { username: 'admin', password: 'secret', autoReconnect: true, });
-
StartTLS Support : Communicate securely with the NUT server using StartTLS for encryption. TLS state is automatically restored on reconnect.
import { NUTClient } from 'nut-client' const client = new NUTClient('127.0.0.1', 3493); // Use clear TCP connection console.log(await client.version()); await client.startTLS({ // Allow self-signed certificate rejectUnauthorized: false }); // Use encrypted TCP connection console.log(await client.version());
-
UPS Object with Convenience Methods : Get a typed
UPSobject with high-level helpers for status, battery, load, and more.const client = new NUTClient('127.0.0.1', 3493); const ups = await client.getUPS('myups'); if (ups) { console.log('Description:', ups.description); const status = await ups.getStatus(); // ENUTStatus[] (e.g. ['OL', 'CHRG']) console.log('Online:', await ups.isOnline()); console.log('On battery:', await ups.isOnBattery()); console.log('Battery charge:', await ups.getBatteryCharge()); // 0-100 or NaN console.log('Runtime:', await ups.getBatteryRuntime()); // seconds or NaN console.log('Load:', await ups.getLoad()); // 0-100 or NaN console.log('Model:', await ups.getModel()); console.log('Manufacturer:', await ups.getManufacturer()); console.log('Serial:', await ups.getSerial()); console.log('Input voltage:', await ups.getInputVoltage()); console.log('Output voltage:', await ups.getOutputVoltage()); }
-
Built-in Monitor : A
Monitormodule reads variables at regular intervals, emitting UPS events similar toupsmon(plus additional "NOT" events and variable change tracking). It integrates with the auto-reconnect system — when the client reconnects, the Monitor resumes automatically; when reconnect is exhausted, it emitsNOCOMM.import { NUTClient, Monitor } from 'nut-client' const client = new NUTClient('127.0.0.1', 3493); const monitor = new Monitor(client, 'myUps'); // Status events (when a flag appears) monitor.on('ONLINE', () => console.log('UPS back online')); monitor.on('ONBATT', () => console.log('UPS on battery')); monitor.on('LOWBATT', () => console.log('Battery low')); // "NOT" events (when a flag disappears) monitor.on('NOTOL', () => console.log('No longer online')); monitor.on('NOTOB', () => console.log('No longer on battery')); monitor.on('NOTLB', () => console.log('Battery no longer low')); monitor.on('NOTFSD', () => console.log('FSD cleared')); monitor.on('NOTRB', () => console.log('Battery replacement cleared')); monitor.on('NOTCAL', () => console.log('Calibration finished')); monitor.on('NOTOFF', () => console.log('UPS no longer off')); monitor.on('NOTBYPASS', () => console.log('No longer on bypass')); // Communication events monitor.on('COMMOK', () => console.log('Communication restored')); monitor.on('COMMBAD', () => console.log('Communication lost')); monitor.on('NOCOMM', () => console.log('Reconnect exhausted')); // Variable change events monitor.on('VARIABLE_CHANGED', (key, oldValue, newValue, oldVars, newVars) => { console.log(`${key}: ${oldValue} → ${newValue}`); }); // Fired when any variable changed in a poll cycle monitor.on('VARIABLES_CHANGED', (oldVars, newVars) => { console.log('Variables updated'); }); monitor.on('BATTERY_CHARGE', (charge, raw) => { console.log(`Battery: ${charge}%`); }); // Wildcard listener for debugging monitor.on('*', (event, ...args) => { console.log(`Event: ${event}`, args); }); await monitor.start(); // Pause/resume without full restart monitor.pause(); monitor.isPaused(); // check if paused monitor.resume(); // Check lifecycle state monitor.isDestroyed(); // Cleanup monitor.destroy();
Full event list available in the TypeDoc documentation.
-
Command Tracking : For long-running write operations, enable tracking to get a UUID per command and poll for completion. Only write commands (SET VAR, INSTCMD) are tracked; reads are unaffected. Requires NUT 2.8.0+ (protocol v1.3).
Manual polling:
import { NUTClient } from 'nut-client'; const client = new NUTClient('127.0.0.1', 3493); await client.connect('user', 'secret'); // Enable tracking await client.setTracking(true); // Long-running command returns immediately with a tracking UUID const result = await client.runCommand('myups', 'shutdown.return', '60'); // result = { tracked: true, trackingUid: 'abc-123-def' } if (result.tracked && 'trackingUid' in result) { // Poll until the command completes let status; do { await new Promise((resolve) => setTimeout(resolve, 5000)); status = await client.getTracking(result.trackingUid); console.log('Status:', status); } while (status === 'PENDING'); if (status === 'SUCCESS') { console.log('Shutdown completed'); } else { console.log('Shutdown failed'); } } // Disable tracking when done await client.setTracking(false);
Automatic polling with
followTracking:// Enable tracking await client.setTracking(true); // Command with automatic polling — resolves when complete const result = await client.runCommand('myups', 'shutdown.return', '60', { followTracking: true, trackingTimeout: 60000, // max wait time (default: 30s) trackingPollInterval: 5000 // poll interval (default: 1s) }); // result = { tracked: true, status: 'SUCCESS' } | { tracked: true, status: 'ERR' } if (result.tracked && result.status === 'SUCCESS') { console.log('Shutdown completed'); }
See the NUT network protocol documentation for details on the tracking protocol.
-
UPS Management Commands : Additional server-side operations like getting descriptions and forcing shutdowns.
const client = new NUTClient('127.0.0.1', 3493); // Get the UPS description (from ups.conf desc= field) const desc = await client.getUPSDescription('myups'); // Force a shutdown (sets the FSD flag — requires master/FSD permission) await client.forceShutdown('myups');
-
Fully Typed with TypeScript (ESM + CJS) : Built with TypeScript,
nut-clientis distributed in both ESM and CommonJS modules for maximum compatibility.
| Class | Description |
|---|---|
NUTClient |
High-level client facade with auto-reconnect, tracking, and typed parsing |
RawNUTClient |
Low-level TCP client for raw NUT protocol access (advanced use) |
UPS |
Typed representation of a UPS device with convenience methods |
Monitor |
Event-based UPS monitoring with status, variable change, and communication events |
// Create and authenticate in one call
const client = await NUTClient.create('127.0.0.1', 3493, {
username: 'admin',
password: 'secret',
autoReconnect: true,
});client.on('disconnected', () => {});
client.on('reconnecting', (attempt, delay) => {});
client.on('reconnected', () => {});
client.on('reconnectFailed', (attempt) => {});
client.on('reconnectExhausted', () => {});
client.on('destroyed', () => {});nut-client throws typed errors that map to NUT protocol error codes. All errors extend NUTProtocolError:
import { AccessDeniedError, UnknownUPSError, ConnectionLostError } from 'nut-client';
try {
await client.getVariable('myups', 'battery.charge');
} catch (e) {
if (e instanceof AccessDeniedError) {
console.log('Authentication required');
} else if (e instanceof UnknownUPSError) {
console.log('UPS not found');
} else if (e instanceof ConnectionLostError) {
console.log('Connection lost');
}
}// Destroy the client (releases TCP socket, clears timers, removes listeners)
client.destroy();
// Destroy a monitor
monitor.destroy();This library includes debug. To enable debug logging:
DEBUG=nut-client:* node my-script.jsContributions are welcome! If you have suggestions, feel free to open an issue or a pull request.
git clone https://github.com/thib3113/nut.git
cd nut
pnpm install
pnpm run build
pnpm run test