nut_client

A pure Dart client library for the NUT (Network UPS Tools) protocol.

Dart License: MIT

Features

  • Connect to NUT servers via TCP
  • Optional TLS/STARTTLS encryption
  • Authenticate with username/password
  • List and monitor UPS devices
  • Get and set UPS variables
  • Execute instant commands
  • Built-in polling via Streams
  • Clean architecture with SOLID principles
  • Fully testable and mockable
  • Pure Dart - no platform dependencies

Installation

Add nut_client to your pubspec.yaml:

dependencies:
  nut_client: ^0.1.0

Or install via command line:

dart pub add nut_client

Usage

Basic Usage

import 'package:nut_client/nut_client.dart';

void main() async {
  // Create a client
  final client = NutTcpClient.simple('192.168.1.10');

  try {
    // Connect to the NUT server
    await client.connect();

    // List all UPS devices
    final devices = await client.listUps();
    for (final device in devices) {
      print('${device.name}: ${device.description}');
    }

    // Get variables for a UPS
    final variables = await client.listVariables('ups1');
    for (final variable in variables) {
      print('${variable.name} = ${variable.value}');
    }

    // Get a specific variable
    final status = await client.getVariable('ups1', 'ups.status');
    print('UPS Status: ${status.value}');

    final charge = await client.getVariable('ups1', 'battery.charge');
    print('Battery: ${charge.intValue}%');
  } finally {
    await client.dispose();
  }
}

With TLS and Authentication

final client = NutTcpClient(
  NutClientConfig(
    host: '192.168.1.10',
    port: 3493,
    useTls: true,
    credentials: Credentials(
      username: 'admin',
      password: 'secret',
    ),
  ),
);

await client.connect();
// Client will automatically use TLS and authenticate

// Now you can use privileged commands
await client.setVariable('ups1', 'ups.delay.shutdown', '120');
await client.runCommand('ups1', 'beeper.toggle');

Polling for Updates

// Watch a single variable
final subscription = client.watchVariable(
  'ups1',
  'battery.charge',
  interval: Duration(seconds: 5),
).listen((variable) {
  print('Battery: ${variable.value}%');
});

// Later: stop watching
await subscription.cancel();

// Watch all variables
client.watchVariables(
  'ups1',
  interval: Duration(seconds: 10),
).listen((variables) {
  for (final v in variables) {
    print('${v.name}: ${v.value}');
  }
});

Error Handling

try {
  await client.connect();
  final status = await client.getVariable('ups1', 'ups.status');
} on ConnectionException catch (e) {
  print('Connection failed: ${e.userMessage}');
} on AuthenticationException catch (e) {
  print('Authentication failed: ${e.userMessage}');
} on CommandException catch (e) {
  print('Command failed: ${e.userMessage}');
  print('Error code: ${e.errorCode}');
} on NutTimeoutException catch (e) {
  print('Timeout: ${e.userMessage}');
}

API Reference

NutClient

The main interface for interacting with NUT servers.

Method Description
connect() Connect to the NUT server
disconnect() Disconnect from the server
authenticate(credentials) Authenticate with username/password
startTls() Upgrade to TLS encryption
listUps() List all UPS devices
listVariables(upsName) List all variables for a UPS
getVariable(upsName, varName) Get a specific variable
setVariable(upsName, varName, value) Set a variable value
listCommands(upsName) List available instant commands
listWritableVariables(upsName) List writable variables
runCommand(upsName, cmdName) Execute an instant command
watchVariable(...) Watch a variable with polling
watchVariables(...) Watch all variables with polling
dispose() Clean up resources

Common UPS Variables

Variable Description Type
ups.status UPS status flags (OL, OB, LB, etc.) String
battery.charge Battery charge percentage Integer (0-100)
battery.runtime Estimated runtime in seconds Integer
input.voltage Input voltage Double
ups.load Load percentage Integer (0-100)
ups.temperature UPS temperature Double

UPS Status Flags

Flag Meaning
OL Online (on utility power)
OB On Battery
LB Low Battery
RB Replace Battery
CHRG Charging
DISCHRG Discharging
ALARM UPS alarm

Architecture

The library follows clean architecture principles:

nut_client/
├── lib/
│   └── src/
│       ├── client/       # High-level client interface
│       ├── connection/   # TCP/TLS connection layer
│       ├── protocol/     # NUT protocol parser/builder
│       ├── models/       # Data models
│       ├── exceptions/   # Typed exceptions
│       └── utils/        # Utilities

Testing

The library is designed for testability. Use the NutTcpClient.withConnection() constructor to inject mock connections:

import 'package:mocktail/mocktail.dart';

class MockConnection extends Mock implements NutConnection {}

void main() {
  test('lists UPS devices', () async {
    final mockConnection = MockConnection();
    final client = NutTcpClient.withConnection(mockConnection);

    when(() => mockConnection.isConnected).thenReturn(true);
    when(() => mockConnection.send(any())).thenAnswer((_) async {});
    when(() => mockConnection.readMultiLine()).thenAnswer(
      (_) async => [
        'BEGIN LIST UPS',
        'UPS myups "My UPS"',
        'END LIST UPS',
      ],
    );

    final devices = await client.listUps();
    expect(devices.length, equals(1));
    expect(devices.first.name, equals('myups'));
  });
}

Requirements

  • Dart SDK >= 3.0.0
  • NUT server (tested with NUT 2.8.0+)

License

MIT License - see LICENSE for details.

Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

Libraries

nut_client
A pure Dart client library for the NUT (Network UPS Tools) protocol.