---
module: agent.nh-tcr-events
title: NH TCR Events — cassette + firmware monitoring for Nautilus Hyosung / Glory BRM30 recyclers
tab: Claude
order: 40
audience: dev
---

> **Internal · agent reference.** Terse. Confirmed against `hiveops-module-nh-tcr-events` source 2026-07-01.

## Identity
- Maven artifact: **`hiveops-module-nh-tcr-events`** (`com.hiveops`, version `1.0.0`, packaged as a standalone `jar`, parent `hiveops-agent-parent` `4.4.3`).
- Agent module id (`getName()`, and the string for **`modules.disabled`**): **`nh-tcr-events`**.
- `getVersion()` = `1.0.0`; `getLogPackage()` = `com.hiveops.nhtcr`.
- Entry class: `com.hiveops.nhtcr.NhTcrEventsModule`, registered via `META-INF/services/com.hiveops.core.module.AgentModule`.
- Vendor target: Nautilus Hyosung TCR + Glory BRM30 external processor (EP).
- Activation gate: `device.type` must equal **`NH_TCR`** exactly (uppercased/trimmed). No legacy alias. Any other value → module inert, `isEnabled()` = `false`.
- Platform: Windows-only in practice (no runtime OS check in code — enforced by deployment convention).

## Config properties (exact keys)
| Key | Default | Required | Notes |
|---|---|---|---|
| `device.type` | *(none)* | **yes** | must be `NH_TCR` or module disables |
| `nh.tcr.ap.log.dir` | *(none)* | one of ap/fw | MoniPlus2S APLog root; date subfolders under it. Not-a-dir → APLog monitor off (warn) |
| `nh.tcr.fw.log.dir` | *(none)* | one of ap/fw | Glory FWLogSave dir. Not-a-dir → FW monitor off (warn) |
| `nh.tcr.events.poll.interval.sec` | `30` | no | **applied** here (unlike sibling `atec-tcr-events`, where it's a no-op) |

- If **both** `nh.tcr.ap.log.dir` and `nh.tcr.fw.log.dir` are unset → module disabled. Neither dir existing → module disabled.
- Shared (not module-specific): `agent.endpoint` / `incident.endpoint` (prefix = `agent` if `agent.endpoint` set, else `incident`; if neither → disabled), `agent.auth.token`, `agent.institution.key` / `incident.institution.key`.

## Event types emitted (exact strings)
| Event type | Source | Trigger |
|---|---|---|
| `CASSETTE_INVENTORY` | APLog | **any** slot status change (emitted first, always) |
| `CASSETTE_LOW` | APLog | slot status → `LOW` |
| `CASSETTE_EMPTY` | APLog | slot status → `EMPTY` |
| `TCR_CASSETTE_MISSING` | APLog | slot status → `MISSING` |
| `TCR_CASSETTE_MANIP` | APLog | slot status → `MANIP` (suspect bills) |
| `TCR_EP_RESTART` | FWEvent | line matches `LogManager_StartUp()` |

- Status `OK` (recovery) → **no event**, agent-log-only (`slot {} recovered`).
- `eventType` is a free-form `String` on `CreateJournalEventRequest` (`hiveops-agent-journal` DTO) — **not validated client-side**. Recognition/labeling is server-side via hiveops-incident's DB `event_type` table.
- `eventSource` sent: **`NH_TCR_APLOG`** (cassette) or **`NH_TCR_FWEVENT`** (EP restart).
- Cassette events also set `cassettePosition` (slot, e.g. `CST_C`), `cassetteDenomination` (int), `cassetteBillCount` (int), `cassetteType` (`RECYCLING`/`REJECT`/`REPCONTAINER`), `cassetteCurrency="USD"` (hardcoded). FW events set none of these.
- Transport: `IncidentEventClient.sendEvent()` → `POST {endpoint}/api/journal-events`.
- Separate path — firmware inventory: `client.syncHardware()` → `POST {endpoint}/api/atms/hardware/sync`, fired **once per daily APLog file** from the header block (`peripheralVersions` map).

## Files monitored
- APLog: `{nh.tcr.ap.log.dir}/{YYYYMMDD}/APLog{YYYYMMDD}.log` — **date subfolder**, daily rotation. Tail-by-offset; offset/`slotStatus` reset on rollover or truncation.
- FWEvent: `{nh.tcr.fw.log.dir}/00FWEvent00.log` … `00FWEvent09.log` — 10-file **circular buffer**. Per-file offset; first poll seeks all to EOF (only NEW entries emit).

## Deployment
- Delivered fleet-wide via **`INSTALL_MODULE`** fleet task (drops JAR into agent's `modules/` dir, restarts agent — `ProcessInstallModule` in `hiveops-file-collection`).
- Disable without uninstalling: add `nh-tcr-events` to `modules.disabled`, push `CONFIG_UPDATE`.
- Emitted event types must be registered in hiveops-incident → Settings → Event Types (DB `event_type` table) to be recognized/labeled.

## Do NOT
- Do NOT run this on non-`NH_TCR` device types — it's a no-op by design elsewhere, not a bug to chase.
- Do NOT use anything but **`nh-tcr-events`** as the `modules.disabled` / module id string.
- Do NOT expect `TCR_EP_RESTART` for restarts that happened **before** the agent came up — the FW monitor seeks to EOF on first poll; only post-start `LogManager_StartUp()` lines emit.
- Do NOT assume firmware versions refresh continuously — the header sync runs **once per daily APLog file** and sets `headerParsed=true` even on partial failure (no same-day retry).
- Do NOT expect retry/queueing on send/sync failure — a failed `sendEvent()` / `syncHardware()` is logged and dropped.
- Do NOT assume `cassetteCurrency` reflects the real currency — it's hardcoded `"USD"`.
- Do NOT trust `NhTcrEventsModule`'s class Javadoc emit list — it's stale (omits `CASSETTE_INVENTORY` and `TCR_CASSETTE_MANIP`). Use the table above / the monitor code.
- Do NOT confuse with `hiveops-module-atec-tcr-events` (`tcr-events`, LG/ATEC vendor) or `hiveops-module-nh-tcr-journal` — separate modules, different log formats and event pipelines.
