# 03 — Device Integration (End-to-End)

How to take a real analyzer from "in the box" to "results landing in the
cloud UI". Walk through the Abaxis VetScan VS2 example first; vendor and
connection-type variations follow.

## Big picture

```
Analyzer ──(local TCP or RS-232)──> LabBridge Agent ──(HTTPS)──> Cloud LabCore
   on clinic LAN                       on clinic PC                  on internet
```

Three things must agree on **address**:
1. The **analyzer** is told where to send results (an IP+port or a serial cable).
2. The **agent** listens on that exact address.
3. The **cloud** has a device row whose `host`/`port` (or `com_port`) matches.

The cloud device row is what tells the agent *what* to listen on when it
calls `register`. So getting the cloud config right is the source of truth.

## Walkthrough: Abaxis VetScan VS2 over TCP

Assumes you've already done [01 Installation](01-installation.md) and
[02 Agent installation](02-agent-installation.md) — agent is online.

### Step 1 — pick a port

Choose any free TCP port on the clinic PC, say **9600**. Open it in the
Windows Firewall **inbound** for the clinic LAN:

```bat
netsh advfirewall firewall add rule name="LabBridge ASTM 9600" ^
    dir=in action=allow protocol=TCP localport=9600
```

### Step 2 — create the device in the cloud UI

1. Go to **Lab → Devices** → **Add Analyzer** (left card).
2. Fill in:
   - **Name:** `VetScan VS2 - Bench 1`
   - **Vendor:** `Abaxis VetScan`
   - **Model:** `VS2`
   - **Agent:** the agent you created (e.g. *Main Clinic*)
   - **Connection Type:** `TCP/IP (network)`
   - **Comm Protocol:** `astm-e1394`
   - **Host / IP:** the analyzer's IP (e.g. `192.168.1.50`) — used for
     reverse-identification when it connects in
   - **Port:** `9600`
   - **Status:** Offline (the agent will flip it to Online on first contact)
3. Click **Add Device**.

### Step 3 — restart the agent

The agent picks up the device list on startup. After adding the first
device:

```bat
labbridge.exe restart
```

The Event Viewer (or stdout if running in `run` mode) should show:

```
listener: device 5 "VetScan VS2 - Bench 1" TCP on :9600 (abaxis)
```

### Step 4 — configure the analyzer

On the VetScan VS2 itself:

1. Open the analyzer's Settings → **Data Transfer** (menu wording varies by
   firmware).
2. Set the destination IP to the **clinic PC's** IP (where the agent runs).
3. Set the destination port to **9600**.
4. Set protocol to **ASTM** / **LIS**.
5. Save and exit.

For other Abaxis models the menus differ slightly; the principle is
identical — point the analyzer at the agent's IP + port.

### Step 5 — run a sample

Run any sample on the VetScan. When the run finishes the analyzer pushes
the result; the flow is:

1. Analyzer opens TCP to `192.168.1.10:9600` (agent's IP).
2. Agent runs ASTM E1381 handshake — ENQ/ACK, frames, EOT.
3. Agent queues the assembled message (SQLite) and triggers an immediate
   sync sweep.
4. Sweep POSTs to `https://erp.example.com/api/lab/results` with the
   message + a UUID.
5. Cloud parses ASTM E1394, normalizes via `AbaxisDriver`, stores
   `LabTestSession` + `LabTestResult` rows.
6. Result appears in **Lab → Results** (canonical names, abnormal flags,
   reference ranges all populated).

End-to-end latency on a healthy network: a few seconds.

## Connection types — when to use which

| Type | When to use | Cloud device fields | Agent listens on |
|---|---|---|---|
| `tcp` | Networked analyzer (VetScan with Ethernet, IDEXX VLS) | `host`, `port` | `:port` |
| `serial2eth` | Analyzer with only RS-232, bridged via a Moxa / USR adapter | `host`, `port` | `:port` (same as tcp) |
| `serial` | Direct RS-232 from analyzer to clinic PC (VetScan VS2 with cable) | `com_port`, `baud`, `parity`, `data_bits`, `stop_bits` | the COM port |

Serial-to-Ethernet adapters are the **recommended** path for serial-only
analyzers — more reliable than a USB-serial adapter, and the agent sees
them as plain TCP.

## Direct serial (RS-232) example

If you wire the VetScan straight to a USB-serial dongle on the clinic PC:

1. Note the COM port assigned (Device Manager → Ports). Say `COM3`.
2. In the cloud device row: Connection Type = `serial`, COM Port = `COM3`,
   Baud = `9600`, Data Bits = `8`, Stop Bits = `1`, Parity = (leave blank
   for "None").
3. Restart the agent. Logs should show:

   ```
   listener: device 6 "VetScan HM5" serial COM3 @ 9600 (abaxis)
   ```

Serial defaults if you leave fields blank: 9600 8-N-1, no flow control.

## Vendor-specific notes

### Abaxis / Zoetis VetScan family

Models covered by the AbaxisLab module:

| Model | Type | Typical connection |
|---|---|---|
| VetScan VS2 | Chemistry | Serial (direct or via Moxa) |
| VetScan HM5 / HM2 | Hematology | Serial |
| VetScan VSpro | Coagulation | Serial |
| VetScan i-STAT Alinity v | Blood gas | Ethernet |
| VetScan UA / SA | Urinalysis / sediment | Serial |

ASTM field positions in `AbaxisDriver` follow the **standard E1394**
positions. Individual VetScan firmware revisions can place fields (species
especially) slightly differently. After the first real run, eyeball the
result in **Lab → Results** — if species or patient name comes back empty
or in the wrong column, capture the raw message from
`lab_communication_logs` and adjust `Modules/AbaxisLab/Entities/Drivers/AbaxisDriver.php`
(`normalize()` method).

### NX600

The NX600Lab module keeps its existing standalone listeners
(`nx600lab:tcp-server`, `nx600lab:hl7-server`). NX600 isn't yet routed
through the LabBridge Agent — the driver is registered with LabCore so
NX600 devices show up in the unified Devices screen and the agent's API
*could* relay it, but the agent's transport layer is ASTM E1381 and NX600
uses a different (vendor-proprietary) protocol. NX600 migration onto the
agent is future work.

For NX600 today: install the NX600Lab module, run its console servers as
documented in `Modules/NX600Lab/`.

### IDEXX

The IdexxLab module is not yet built; it's gated on an IDEXX agreement
(VetConnect PLUS API access or VetLab Station interface enablement).
Contact your IDEXX rep — the architecture is ready; only the driver +
module wrapper need to be written. See
[08 Developer guide](08-developer-guide.md) for what that looks like.

## Testing with the simulator

You can prove the full pipeline without a real analyzer by running
[`abaxis:simulate`](../../Modules/AbaxisLab/Console/AbaxisSimulator.php).

### Mode `print` — see what gets sent

```bash
php artisan abaxis:simulate --mode=print --scenario=abnormal
```

Prints the synthetic VetScan ASTM message to the terminal.

### Mode `api` — bypass the agent, post directly to the cloud

```bash
php artisan abaxis:simulate --mode=api --scenario=abnormal --patient="Rex" --species=Canine
```

POSTs to `/api/lab/results`. Auto-provisions a `simulator` agent. Result
appears in Lab → Results immediately. Good for verifying the cloud
pipeline (parser, ingestion, UI).

### Mode `tcp` — talk to a real agent over the network

```bash
php artisan abaxis:simulate --mode=tcp --host=<agent-ip> --port=9600 --scenario=chemistry
```

Runs the full ASTM E1381 client handshake against the agent. Use this from
any machine to verify the agent's listener path before you connect the
real analyzer.

## Common first-time checks

After Step 5, if nothing appears:

| Symptom | Check |
|---|---|
| No connection in agent logs when analyzer fires | Analyzer's destination IP/port; clinic-PC firewall |
| Connection logged but "ASTM error" | Check `lab_communication_logs` for the raw bytes; mismatched protocol (HL7 vs ASTM) is the usual cause |
| Stored in queue but nothing in cloud | Agent can't reach cloud — see [07 Troubleshooting § Agent isn't reaching the cloud](07-troubleshooting.md#agent-isnt-reaching-the-cloud) |
| Cloud `{status: stored}` but UI is empty | Wrong business filter — see [07 § Results aren't showing](07-troubleshooting.md#results-arent-showing-in-the-ui) |

Full troubleshooting matrix in [07 Troubleshooting](07-troubleshooting.md).
