Nut - v1.0.0
    Preparing search index...

    Nut - v1.0.0

    nut-client

    NPM version CI Coverage Downloads License Known Vulnerabilities nut-client-snyk Donate GitHub stars Package Quality

    Bugs Code Smells Duplicated Lines (%) Lines of Code Maintainability Rating Quality Gate Status Reliability Rating Security Rating Technical Debt Vulnerabilities

    Dependencies update - renovate NPM

    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-client

    Supported 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-client manages 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 UPS object 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 Monitor module reads variables at regular intervals, emitting UPS events similar to upsmon (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 emits NOCOMM.

      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-client is 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.js
    

    Contributions 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

    MIT