---
module: agent.tcr-events
title: TCR Events — cassette + sensor + process monitoring for Teller Cash Recyclers
tab: Internal
order: 20
audience: dev
---

> **Internal · ops/support.** Written 2026-07-01 from the compiled `hiveops-module-tcr-events` artifact (v4.3.5). The `.java` sources are not in the working tree — facts below were read from the module bytecode in `target/classes` plus the core `IncidentEventClient` / `HttpClientHelper` sources. Verify against code before relying on specifics.

## What this module is

`hiveops-module-tcr-events` (Maven artifact `hiveops-module-tcr-events`, agent module id **`tcr-events`**, reported module version `1.0.0`) is an **agent drop-in module**, not a backend service. It runs inside the HiveIQ Agent process on **TCR (Teller Cash Recycler) devices only**. It self-disables unless the ATM's `device.type` is `ATEC_TCR` (or the legacy alias `TCR`).

It tails **three** log files that the LG/ATEC TCR software already writes to disk and turns specific lines into HiveIQ journal events, which it POSTs into the incident pipeline. The module does **not** talk to the recycler hardware directly and does not reconcile cash totals — it only reads logs and forwards structured events.

> Note: this module shares the agent module id `tcr-events` with `hiveops-module-atec-tcr-events`. This variant is the superset — it adds the JSON cassette-inventory monitor (`TcrCassetteMonitor`) on top of the access-log and sensor-log monitors. Do not install both on the same device.

## What it monitors

Three independent pollers, all driven by one scheduler tick (default every 30s), each reading a daily-rotated file (`MMdd` = month+day) from `tcr.log.dir`:

| Poller class | File pattern | Watches for |
|---|---|---|
| `TcrAccessLogMonitor` | `ACESSLog<MMdd>.txt` *(sic — misspelled in the vendor logs)* | abnormal process restarts, operator/reboot shutdowns |
| `CstSnsLogMonitor` | `CST_SNR_<MMdd>.log` | cassette sensor state (empty / fault / manual-required) and SNR deposit-count mismatches |
| `TcrCassetteMonitor` | `JsonLog_<MMdd>.json` | per-slot cassette inventory (`"Command":"RU"` recycler-unit status lines) |

Each poller tracks a byte offset into its current file (opened read-only) and only processes newly appended lines each tick.

## Events it emits

All events are sent as HiveIQ journal events (`POST {endpoint}/api/journal-events`). Event types by source:

| `eventSource` | `eventType` | Trigger |
|---|---|---|
| `TCR_ACESS_LOG` | `TCR_PROCESS_RESTART` | log line "Process restarted from abnormal termination" |
| `TCR_ACESS_LOG` | `TCR_SHUTDOWN` | "## Shutdown ##" / "## Shutdown for reboot ##" (reboot vs operator shutdown in details) |
| `TCR_CST_SNR` | `CASSETTE_EMPTY` | sensor state `EMPT` |
| `TCR_CST_SNR` | `TCR_SENSOR_FAULT` | sensor state `SNRF` |
| `TCR_CST_SNR` | `TCR_MANUAL_REQUIRED` | sensor state `TMAN` |
| `TCR_CST_SNR` | `TCR_SENSOR_MISMATCH` | SNR deposit-count mismatch line |
| `TCR_CASSETTE` | `CASSETTE_INVENTORY` | one per slot from each `RU` status snapshot |

Sensor state `NORM` is treated as **recovery** — it is logged (`slot {} recovered`) but emits **no** event.

## Config properties it registers

Read from the agent's main properties (`hiveops.properties`) during `initialize()`:

| Property | Default | Effect |
|---|---|---|
| `device.type` | `ATM` | Gate — module runs only when this is `ATEC_TCR` or `TCR` (upper-cased). Anything else: module disabled. |
| `tcr.events.enabled` | `true` | Master on/off. Any value other than `true` (case-insensitive): module disabled. |
| `tcr.log.dir` | *(none — required)* | Directory holding the three TCR log files. If unset: module disabled. If set but missing on disk: warns and retries each poll. |
| `tcr.events.poll.interval.sec` | `30` | Scheduler period in seconds. |
| `agent.endpoint` | *(none)* | If present, HTTP settings load from the `agent.*` prefix (agent-proxy); if absent, they fall back to the `incident.*` prefix. |

Transport credentials are **not** module-specific: the bearer token always comes from `agent.auth.token`, and the institution key resolves `<{prefix}>.institution.key` → `agent.institution.key` → `incident.institution.key` (see `HttpClientHelper.loadSettingsFromProperties`).

## How it's enabled / deployed

1. Device must be flagged `device.type=ATEC_TCR` (or `TCR`) and have `tcr.log.dir` pointed at the vendor log directory.
2. Deliver the module JAR like any other agent module: upload to the fleet artifact store, then push a fleet **`INSTALL_MODULE`** task, which drops the JAR into the agent's `modules/` directory and restarts the agent (`ProcessInstallModule` in `hiveops-file-collection`). It can also ship as part of a full standard-set agent update.
3. Standard rollout order applies: lab TCR → pilot device → fleet.

On successful init the agent logs `tcr-events initialized (log.dir={}, poll={}s)` and, once started, `tcr-events started`.

## Common failure modes / what to check

- **Module silently absent from a device.** Check `device.type` — if it is not `ATEC_TCR`/`TCR` the agent logs `tcr-events: device.type is '{}', not ATEC_TCR — module disabled` and never starts. This is the most common cause.
- **No events at all.** Confirm `tcr.events.enabled` is not set to `false` (`tcr-events: disabled via tcr.events.enabled=false`) and `tcr.log.dir` is configured (`tcr.log.dir not configured — module disabled`).
- **Log dir warning on every poll.** `log dir '{}' does not exist yet — will retry each poll` means the module initialized but the directory is missing/misnamed — the vendor software may not have created that day's folder yet.
- **Events built but not arriving in incident.** Look for `tcr-events: failed to send {}: {}` (HTTP error from `/api/journal-events`) — usually an endpoint/token/institution-key problem, or the wrong prefix (`agent.endpoint` present but `agent.*` settings wrong).
- **Read errors.** `tcr-events: failed to read {}` / `cassette monitor failed to read {}` — permissions or a locked/rotating vendor file.
- **Wrong day / nothing new.** All three files are day-stamped (`MMdd`); at midnight rollover the pollers switch to the new filename automatically.

> Gotcha: emitted events do **not** set `deviceType` on the request, so the incident backend records them under its default device type (ATM), even though the module only runs on TCR devices. See [architect.tcr-events].
