npm package: @jaarnio/tripplite-poweralert
Description: Enterprise-grade Tripplite PDU SDK with singleton connection management and WebSocket real-time monitoring
Author: jaarnio
Latest version: 3.0.1

# @jaarnio/tripplite-poweralert

Enterprise-grade Node.js SDK for Tripplite PDU management with real-time WebSocket monitoring and automatic session management.

## Installation

```bash
npm install @jaarnio/tripplite-poweralert
```

## Quick Start

```javascript
const { TripplitePDUSDK } = require('@jaarnio/tripplite-poweralert');

const sdk = new TripplitePDUSDK({
  ip: '192.168.1.100',
  username: 'admin',
  password: 'password'
});

// Start WebSocket server and connect to PDU
await sdk.startWebSocketService();

// Get all outlets
const outlets = await sdk.getAllOutlets();

// Control an outlet
await sdk.controlOutlet(1, 'on');
```

## Features

- **Singleton Connection Management** - Prevents session stacking on PDU hardware
- **Automatic Token Management** - Persists and reuses authentication tokens across restarts
- **Real-time WebSocket Server** - Monitor and control outlets via WebSocket
- **REST API Wrapper** - Simple methods for all PDU operations
- **Automatic Session Refresh** - Tokens refresh before expiry
- **Built-in Caching** - Reduces API calls with intelligent caching

## API Reference

### Constructor

```javascript
new TripplitePDUSDK(config)
```

**Config Options:**

| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| `ip` | string | Yes | - | PDU IP address |
| `username` | string | Yes | - | PDU username |
| `password` | string | Yes | - | PDU password |
| `port` | number | No | 443 | PDU HTTPS port |
| `wsPort` | number | No | 8080 | WebSocket server port |
| `pollInterval` | number | No | 5000 | State polling interval (ms) |
| `persistTokens` | boolean | No | true | Save tokens to disk |
| `tokenStorePath` | string | No | `~/.tripplite-pdu-tokens/{ip}.json` | Token storage location |

### Methods

#### `startWebSocketService(port?: number): Promise<void>`
Start the WebSocket server and connect to PDU.

```javascript
await sdk.startWebSocketService(8080);
```

#### `getAllOutlets(): Promise<Outlet[]>`
Get all outlet states.

```javascript
const outlets = await sdk.getAllOutlets();
// Returns: [{ id: 1, name: "Server", state: "on", description: "Main Server" }]
```

#### `getOutlet(outletId: number): Promise<Outlet>`
Get specific outlet state.

```javascript
const outlet = await sdk.getOutlet(1);
```

#### `controlOutlet(outletId: number, action: 'on' | 'off' | 'cycle'): Promise<boolean>`
Control outlet power state.

```javascript
await sdk.controlOutlet(1, 'on');   // Turn on
await sdk.controlOutlet(1, 'off');  // Turn off
await sdk.controlOutlet(1, 'cycle'); // Power cycle
```

#### `renameOutlet(outletId: number, newName: string, description?: string): Promise<Outlet>`
Rename an outlet and optionally update its description.

```javascript
await sdk.renameOutlet(1, 'Database Server');
// Or with description
await sdk.renameOutlet(1, 'Database Server', 'Primary PostgreSQL instance');
```

#### `getDeviceInfo(): Promise<PDUDevice>`
Get PDU device information.

```javascript
const info = await sdk.getDeviceInfo();
// Returns: { model: "PDUMH15NET", name: "PDU-01", ... }
```

#### `stop(): Promise<void>`
Stop the SDK and clean up connections.

```javascript
await sdk.stop();
```

#### `getStats(): object`
Get WebSocket server and cache statistics.

```javascript
const stats = sdk.getStats();
// Returns: {
//   running: true,
//   clients: 2,
//   outlets: 8,
//   cacheStats: {
//     hits: 45,
//     misses: 12,
//     size: 8
//   }
// }
```

## WebSocket Protocol

Connect to the WebSocket server to receive real-time updates:

```javascript
const ws = new WebSocket('ws://localhost:8080');

// Subscribe to updates
ws.send(JSON.stringify({
  action: 'subscribe',
  type: 'full'  // or 'outlet' with outletIds: [1, 2, 3]
}));
```

### Message Types

#### Connection
```json
{
  "type": "connection",
  "status": "connected",
  "version": "1.0.0",
  "timestamp": "2024-01-01T12:00:00Z"
}
```

#### Initial State
```json
{
  "type": "initial_state",
  "data": {
    "device": { "model": "PDUMH15NET", "name": "PDU-01" },
    "outlets": [
      { "id": 1, "name": "Server", "state": "on", "description": "Main Server" }
    ]
  }
}
```

#### State Update
```json
{
  "type": "update",
  "changes": [
    {
      "outlet": 1,
      "field": "state",
      "oldValue": "off",
      "newValue": "on"
    }
  ]
}
```

#### Control Outlet
```json
{
  "action": "action",
  "outletId": 1,
  "operation": "on"
}
```

#### Rename Outlet
```json
{
  "action": "rename",
  "outletId": 1,
  "name": "New Name",
  "description": "New Description"
}
```

## Token Persistence

The SDK automatically saves authentication tokens to prevent session stacking. Tokens are stored at:
- **Linux/Mac**: `~/.tripplite-pdu-tokens/{ip}.json`
- **Windows**: `%USERPROFILE%\.tripplite-pdu-tokens\{ip}.json`

To disable token persistence:
```javascript
const sdk = new TripplitePDUSDK({
  ip: '192.168.1.100',
  username: 'admin',
  password: 'password',
  persistTokens: false
});
```

## Examples

### Basic Server
```javascript
const { TripplitePDUSDK } = require('@jaarnio/tripplite-poweralert');

async function main() {
  const sdk = new TripplitePDUSDK({
    ip: process.env.PDU_IP,
    username: process.env.PDU_USER,
    password: process.env.PDU_PASS
  });

  await sdk.startWebSocketService();
  
  const outlets = await sdk.getAllOutlets();
  outlets.forEach(outlet => {
    console.log(`Outlet ${outlet.id}: ${outlet.state}`);
  });

  // Handle shutdown
  process.on('SIGINT', async () => {
    await sdk.stop();
    process.exit(0);
  });
}

main().catch(console.error);
```

### WebSocket Client
```javascript
const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:8080');

ws.on('open', () => {
  // Subscribe to all outlets
  ws.send(JSON.stringify({
    action: 'subscribe',
    type: 'full'
  }));
});

ws.on('message', (data) => {
  const message = JSON.parse(data);
  console.log('Received:', message.type);
  
  if (message.type === 'update') {
    message.changes.forEach(change => {
      console.log(`Outlet ${change.outlet}: ${change.field} = ${change.newValue}`);
    });
  }
});
```

## Error Handling

The SDK throws errors for connection and authentication issues:

```javascript
try {
  await sdk.startWebSocketService();
} catch (error) {
  if (error.code === 'AUTH_FAILED') {
    console.error('Authentication failed:', error.message);
  } else if (error.code === 'PDU_UNREACHABLE') {
    console.error('Cannot connect to PDU:', error.message);
  }
}
```

## Environment Variables

Create a `.env` file for configuration:

```env
PDU_IP=192.168.1.100
PDU_USER=admin
PDU_PASS=password
```

## Requirements

- Node.js >= 16.0.0
- Network access to Tripplite PDU
- PDU credentials with API access

## License

MIT

## Support

For issues and questions, visit: https://github.com/jaarnio/tripplite-poweralert/issues