# Node-RED PgTg Bridge Control Flow

## Overview

A complete Node-RED flow for controlling the PgTg Bridge service and displaying real-time amplifier/tuner telemetry. Uses the WebSocket API documented in [WebSocket-API-Reference.md](WebSocket-API-Reference.md).

## Prerequisites

- **Node-RED** installed and running
- **node-red-dashboard** (`node-red-contrib-dashboard`) installed for UI widgets
- **PgTg Bridge service** running on `ws://YourPcIp:4990`

Note: When PgTgController starts, if port 4990 is already in use, it will decrement port number 
until successfully able to bind to a port. Range 4980-4990

Install the dashboard if not already present:
```
cd ~/.node-red
npm install node-red-dashboard
```

## Import the Flow

1. Open Node-RED editor (typically `http://YourNodeRedInstanceIp:1880`)
2. Menu (hamburger) → Import → Clipboard
3. Paste the contents of [NodeRed-PgTg-Bridge.json](NodeRed-PgTg-Bridge.json)
4. Click Import → Deploy

The dashboard UI is available at `http://YourNodeRedInstanceIp:1880/ui`

## Flow Architecture

```
┌─────────────────────────── /command endpoint ───────────────────────────┐
│                                                                         │
│  [Start] ──┐                                                            │
│  [Stop]  ──┼──► [Build Command] ──► [WS Command Out]                    │
│  [Restart]─┤         ▲                                                  │
│  [Status] ─┘         │                                                  │
│                       │                                                  │
│  [WS Command In] ──► [Parse Command Response] ──► [Bridge State]        │
│                              │                 ──► [Status Light]        │
│                              └────────────────────► [Debug]              │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────── /data endpoint ──────────────────────────────┐
│                                                                         │
│  [WS Data In] ──► [Parse Data Messages] ──► [Meter Router] ──► Gauges  │
│                          │                                              │
│                          ├──► [TX Frequency]                            │
│                          └──► [Debug]                                   │
└─────────────────────────────────────────────────────────────────────────┘
```

## Function Nodes

### Build Command

Converts a button payload into a WebSocket command JSON message.

**Input:** `msg.payload` = command string (e.g., `"RequestStart"`)
**Output:** `msg.payload` = JSON string

```javascript
msg.payload = JSON.stringify({
    type: "command",
    command: msg.payload
});
return msg;
```

### Parse Command Response

Handles both direct command responses and unsolicited status change pushes. Maps bridge state to UI-friendly colors.

**Input:** `msg.payload` = raw JSON from WebSocket
**Outputs:**
- `[0]` → Status text for display (e.g., "Running")
- `[1]` → Status color hex (e.g., "#4CAF50" for green)
- `[2]` → Debug log string

**State → Color mapping:**

| State | Color | Hex |
|-------|-------|-----|
| Running | Green | `#4CAF50` |
| Starting / Restarting / Stopping | Orange | `#FF9800` |
| ReadyToStart | Blue | `#2196F3` |
| Error / TrialExpired | Red | `#F44336` |
| Initializing / NotDetected | Grey | `#9E9E9E` |

### Parse Data Messages

Parses the three message types from the `/data` endpoint.

**Input:** `msg.payload` = raw JSON from WebSocket
**Outputs:**
- `[0]` → Meter readings (array of messages, one per meter, `msg.topic` = meter name)
- `[1]` → Frequency display text (e.g., "14.200 MHz - 20m")
- `[2]` → Debug log

On `meterConfig`: stores configuration in `flow.meterConfig` for reference by subsequent `meterData` messages.

On `meterData`: emits one message per meter with `msg.topic`, `msg.payload` (value), `msg.units`, `msg.min`, `msg.max`.

### Meter Router

Splits meter messages by name to dedicated gauge outputs.

**Input:** `msg.topic` = meter name, `msg.payload` = value
**Outputs (5):**

| Output | Meter | Widget |
|--------|-------|--------|
| 0 | AMP_FWD | Forward Power gauge (Watts) |
| 1 | AMP_RL | SWR gauge |
| 2 | AMP_TEMP | Temperature gauge (°C) |
| 3 | TUNER_FWD | Tuner Forward Power gauge (Watts) |
| 4 | TUNER_RL | Tuner SWR gauge |

## Dashboard UI

The dashboard provides:

- **Bridge Control** group: Start (green), Stop (red), Restart (orange), Status (blue) buttons
- **Bridge Status** group: Current state text + colored status indicator dot + TX frequency
- **Meters** group: Five gauges with color-coded thresholds matching the PgTg Controller:
  - **Power gauges**: Green → Yellow → Red by fraction of max
  - **SWR gauges**: Green < 1.5, Yellow 1.5–2.5, Red ≥ 2.5
  - **Temp gauge**: Blue < 40°C, Green 40–75°C, Red ≥ 75°C

## Configuration

### Changing the WebSocket Port

If your PgTg service uses a different port than 4990:

1. Double-click the **WS Command Out** node
2. Click the pencil icon next to the WebSocket client config
3. Change the URL from `ws://127.0.0.1:4990/command` to your port
4. Repeat for the **WS Data In** node (`ws://127.0.0.1:{port}/data`)
5. Deploy

### Adjusting Gauge Ranges

The gauge max values default to:
- AMP FWD: 1500W (KPA1500). Change to 600 for KPA500.
- TUNER FWD: 600W (KAT500)
- AMP TEMP: 100°C
- SWR: 1.0–3.0

To auto-adjust from server config, wire the `meterConfig` message to update gauge properties dynamically, or manually set them in the gauge node properties.

## Standalone Function Node (No Dashboard)

If you only need the command/control logic without `node-red-dashboard`, use this self-contained function node wired to WebSocket in/out nodes:

```javascript
// Function node: PgTg Bridge Controller
// Wire input from inject nodes with msg.payload = "RequestStart" / "RequestStop" / "RequestRestart"
// Wire output to a websocket-out node pointed at ws://127.0.0.1:4990/command

// --- SEND COMMAND ---
if (msg.topic === "send" || !msg.topic) {
    // Build and forward the command
    msg.payload = JSON.stringify({
        type: "command",
        command: msg.payload
    });
    return msg;
}

// --- RECEIVE RESPONSE ---
// (wire websocket-in to this node with msg.topic = "receive")
if (msg.topic === "receive") {
    let data;
    try {
        data = JSON.parse(msg.payload);
    } catch (e) {
        node.warn("Failed to parse: " + msg.payload);
        return null;
    }

    if (data.type === "response") {
        node.status({ fill: "blue", shape: "dot", text: data.command + " → " + data.state });
        msg.payload = { command: data.command, state: data.state, data: data.data };
        return msg;
    }

    if (data.type === "statusChange") {
        let colors = {
            Running: "green", Starting: "yellow", Restarting: "yellow",
            Stopping: "yellow", ReadyToStart: "blue", Error: "red",
            TrialExpired: "red"
        };
        node.status({ fill: colors[data.state] || "grey", shape: "ring", text: data.state });
        msg.payload = { state: data.state };
        return msg;
    }

    return null;
}
```

### Wiring the Standalone Node

```
[Inject: RequestStart] ──► [PgTg Controller] ──► [WS Out: /command]
[Inject: RequestStop]  ──┘        ▲
[Inject: RequestRestart]──┘       │
                                  │
[WS In: /command] ──(topic:receive)──┘
```

Use a **Change** node to set `msg.topic = "receive"` on the websocket-in output before routing it back to the function node, or use two separate function nodes (one for send, one for receive).
