🚧 WIP
This commit is contained in:
@@ -99,9 +99,44 @@ diagnosis.
|
||||
| D13 | Frozen value | `expect_change: true` tag with unchanged value+timestamp for `max_age_s` | WARN |
|
||||
| D14 | Mass quality degradation | ≥ 50% of monitored tags BAD simultaneously while connection OK | CRITICAL (`CONTROL_LINK_DEGRADED` — points at OPC-server↔device link, not DCOM) |
|
||||
| D15 | Heartbeat / summary | Periodic stats snapshot every `heartbeat_s` (300) | INFO |
|
||||
| D16 | Device link down | A configured device-indicator tag reads `false`, or any quality other than GOOD, or a read error | CRITICAL per device (`DEVICE_LINK_DOWN`); D1/D2 do **not** imply device-link state |
|
||||
|
||||
All thresholds are configurable; severities are INFO / WARN / CRITICAL.
|
||||
|
||||
### 6.1 Device connection-indicator tags (D16)
|
||||
|
||||
The config names one or more tags as **device-link indicators**: values the
|
||||
control system maintains that say whether the OPC server can reach the device.
|
||||
The **normal (connected) reading is configurable per indicator** — conventions
|
||||
differ per control system, so it is never hardcoded:
|
||||
|
||||
```yaml
|
||||
devices:
|
||||
- { name: "Conveyor 3", tag: "...Connected" } # any truthy: true/1
|
||||
- { name: "Pump A", tag: "...PumpAFault", ok_values: [false, 0] } # inverted fault flag
|
||||
- { name: "Boiler 2", tag: "...State", ok_values: ["RUN"] } # enum/string state
|
||||
```
|
||||
|
||||
Default `ok_values: [true]` (boolean connected-flags are the common case).
|
||||
Value comparison is by **string equality** on the read value rendered as text
|
||||
(`"True"`, `"1"`, `"RUN"`), so type quirks across systems cannot cause false
|
||||
positives; quality must also be GOOD. Semantics (all DOWN cases are logged as
|
||||
`DEVICE_LINK_DOWN`):
|
||||
|
||||
| Indicator reading | Interpretation |
|
||||
|-------------------|------------------|
|
||||
| GOOD + value ∈ `ok_values` | Device connected — normal |
|
||||
| GOOD + value ∉ `ok_values` | **Device link down / fault** — CRITICAL (works for inverted fault-flags: a fault `1` is not in `[false, 0]`) |
|
||||
| Any quality other than GOOD (BAD/UNCERTAIN) | **Something is wrong with the device link** — CRITICAL |
|
||||
| Read error (tag unreadable) | **Something is wrong with the device link** — CRITICAL |
|
||||
|
||||
Device-link state is per indicator tag: the config maps each indicator to a
|
||||
human-readable device name for the log lines (see `config.example.yaml`).
|
||||
Recovery (`DEVICE_LINK_UP`) is logged when the same indicator reads GOOD with
|
||||
an ok value again. A value that is neither in `ok_values` nor a recognized
|
||||
fault shape still logs DOWN — the normal state is explicit, and everything
|
||||
else is "not normal" by definition.
|
||||
|
||||
## 7. OPC DA quality codes (reference)
|
||||
|
||||
OPC DA quality is a 16-bit field. Bits 7–6 of the low byte give the class:
|
||||
@@ -126,6 +161,13 @@ decodes and names:
|
||||
Remaining UNCERTAIN subcodes (DA 2.05a) are decoded by the same table in `quality.py`.
|
||||
Every quality event carries the raw hex code **and** the decoded name.
|
||||
|
||||
**Clear-text status rule:** wherever a status or quality is reported — JSONL
|
||||
fields, the text log, Event Log, console — it is written in clear text with
|
||||
the raw code in parentheses: `BAD / communication failure (0x18)`,
|
||||
`GOOD (0xC0)`. Nobody should have to decode hex codes by hand, but the raw
|
||||
code stays for unambiguous correlation with vendor documentation and the
|
||||
HRESULT table.
|
||||
|
||||
## 8. Event model
|
||||
|
||||
Every event is a structured record:
|
||||
@@ -163,12 +205,36 @@ alongside and clearly labeled.
|
||||
| Reporter | Purpose | Notes |
|
||||
|----------|---------|-------|
|
||||
| JSONL rotating file | Primary evidence trail | One JSON event per line; rotation by size; default dir `%ProgramData%\OPCDA-Diagnozer\logs` |
|
||||
| **Plain-text anomaly log** | Human-readable evidence | One line per **detected anomaly** (not heartbeats): timestamp, kind, tag/device, message with clear-text status `NAME (0xNN)`; same rotation scheme as JSONL. See §9.1 for the line format |
|
||||
| Windows Event Log | Ops visibility | WARN+ only; source `OPCDA-Diagnozer` |
|
||||
| Console | Foreground/debug runs | Human-readable |
|
||||
| HTTP webhook (optional) | Alert integration | POST one JSON event per request, optional bearer token |
|
||||
|
||||
Reporters are pluggable (`Reporter.emit(event)`); a heartbeat event every 5 minutes
|
||||
proves liveness and enables baseline graphs even when everything is healthy.
|
||||
The JSONL file stays the machine-readable source of truth; the text log is a
|
||||
human-first convenience view of the same events — every text line corresponds
|
||||
to a JSONL record.
|
||||
|
||||
### 9.1 Plain-text anomaly log format
|
||||
|
||||
File `anomalies-YYYYMMDD.log` (daily rotation, size-capped) in the same log
|
||||
directory. One line per detected anomaly — anomalies only; heartbeats and
|
||||
reconnect-OK events do not appear here. Clear text first, codes in parentheses:
|
||||
|
||||
```
|
||||
2026-10-07 14:23:01.123 UTC WARN QUALITY_BAD tag 'Channel1.Device1.Counter' changed GOOD (0xC0) -> BAD / communication failure (0x18)
|
||||
2026-10-07 14:24:31.500 UTC CRITICAL DEVICE_LINK_DOWN device 'Conveyor 3': link indicator 'Channel1.Device3.Connected' read false (GOOD)
|
||||
2026-10-07 14:26:02.780 UTC CRITICAL DEVICE_LINK_DOWN device 'Conveyor 3': link indicator 'Channel1.Device3.Connected' quality BAD / not connected (0x08)
|
||||
2026-10-07 14:27:10.001 UTC CRITICAL POLL_HANG read call hung > 5000 ms; COM thread abandoned and rebuilt
|
||||
2026-10-07 14:30:00.000 UTC CRITICAL CONTROL_LINK_DEGRADED 12 of 14 monitored tags BAD while connection OK
|
||||
```
|
||||
|
||||
Fields (pipe-free, fixed order): `timestamp SEVERITY KIND message`.
|
||||
Timestamps are the local receive time in UTC (§8). The message carries the
|
||||
clear-text status with the code between parentheses per §7. A matching
|
||||
recovery (link back up, quality back to GOOD) is also logged as an anomaly
|
||||
line, so the log reads as a continuous incident narrative.
|
||||
|
||||
## 10. Operational behavior
|
||||
|
||||
|
||||
Reference in New Issue
Block a user