exchange work

This commit is contained in:
2026-09-15 13:06:45 -05:00
parent 8a3a0acb75
commit 58610c1e1a
265 changed files with 33534 additions and 69 deletions

View File

@@ -0,0 +1,118 @@
# Alarm Analysis Dashboard
A drop-in Ignition Perspective dashboard that turns the **alarm journal** into
actionable alarm-management metrics: alarm rate, MTTA/MTTR, flood episodes,
chattering and standing alarms, a Pareto of bad actors, a day/hour heatmap, and
an overall alarm-health score graded AF against ISA-18.2 style targets.
It reads the journal through `system.alarm.queryJournal` / `system.alarm.queryStatus`
only. There are **no tags, no named queries, no SQL and no database connection**
if the gateway has an alarm journal profile with data in it, the dashboard works.
---
## Requirements
* Ignition **8.1.20+** with the **Perspective** module.
* An **alarm journal profile** that is receiving data (Gateway → Config → Alarming →
Journal). Any journal store works; the resource never talks to the database directly.
* No third-party modules, no Python packages, no gateway scripting configuration.
## Install
1. In the Designer, open the project you want the resource in and choose
**File → Import…**, or use **Config → Projects → Import** on the Gateway
web page to bring the download in as its own project.
2. Import the resource. Everything lands under namespaced folders, so nothing in
an existing project is overwritten:
| Resource | Location |
|---|---|
| Views | `Exchange/AlarmAnalysis/…` |
| Style classes | `exchange/alarm-analysis/…` |
| Project library | `exchange/alarmAnalysis/{alarms, calc, fmt}` |
| Page | `/alarm-analysis``Exchange/AlarmAnalysis/Dashboard` |
3. **Save** the project.
4. Open a Perspective session and browse to **`/alarm-analysis`**.
That is the whole installation. The dashboard holds all of its own state on the
`Dashboard` view, so importing it does **not** add session custom properties,
client tags or global variables to your project.
### If you imported into an existing project
* The page URL `/alarm-analysis` is added to your project's page configuration.
If that URL is already taken, change it in **Project Browser → Perspective →
Page Configuration**; the view path it should point at is
`Exchange/AlarmAnalysis/Dashboard`.
* Nothing else in your project is touched — every resource is namespaced.
### If you want it on its own page shell
Embed `Exchange/AlarmAnalysis/Dashboard` in any view or dock. It takes no
parameters and sizes itself to its container (design size 1600×900).
## Using it
| Tab | What it shows |
|---|---|
| **Overview** | Headline KPIs vs the previous equal-length period, alarm-rate chart, priority mix, top sources, and plain-language insights. |
| **Analysis** | Day/hour heatmap, flood episodes, MTTA/MTTR trend, and priority distribution against the ISA 80/15/5 target. |
| **Bad Actors** | Pareto of the worst offenders plus chattering, standing and fleeting alarm tables. Click a row for the per-source drill-down. |
| **Journal** | Paged, filtered journal browser with CSV export and a per-event detail popup. |
* The **range selector** and **Refresh** in the header set the analysis window.
* The **filter bar** (Priority / Area / State / Search) applies to every tab except
Overview, which deliberately stays a plant-wide summary.
* **Shift Report** renders a plain-text handover summary for the previous shift,
ready to copy into a log.
* Clicking a source anywhere drills through to that source in **Bad Actors**;
clicking a Bad Actors row opens the per-source history popup.
## Tuning
All thresholds live in one place — `exchange.alarmAnalysis.calc.DEFAULTS`:
| Key | Default | Meaning |
|---|---|---|
| `target_per_hr` | `6.0` | ISA target alarm rate per operator per hour |
| `flood_per_10min` | `10` | Activations per 10 min that start a flood episode |
| `chatter_per_hr` | `10.0` | Re-triggers per hour that mark a source as chattering |
| `chatter_gap_s` | `120` | Median gap below which re-triggers count as chatter |
| `fleeting_s` | `10` | Active duration below which an alarm counts as fleeting |
| `standing_hours` | `24` | Age above which an active alarm counts as standing |
| `priority_target` | `80/15/5` | ISA low/medium/high priority mix |
| `health_weights` | see source | Weighting of the five health sub-scores |
| `max_events` | `50000` | Hard cap on journal rows read per query |
Edit the dict in the Designer's script library, or pass an override dict as the
`opts` argument of any `calc` function.
## Script library
| Module | Responsibility |
|---|---|
| `exchange.alarmAnalysis.alarms` | Talks to `system.alarm`; the only module that does I/O. Entry points used by the views: `getDashboardBundle`, `getJournalPage`, `journalCsv`, `getSourceDetail`, `getEventData`, `getShiftReportText`. |
| `exchange.alarmAnalysis.calc` | Pure analytics — correlation, binning, floods, chatter, MTTA/MTTR, Pareto, health score. No Ignition API calls, so it is unit-testable. |
| `exchange.alarmAnalysis.fmt` | Display formatting and the natural-language insight/shift-report text. |
Every public function carries a docstring, so the Designer's autocomplete
documents the API.
## Notes and limits
* The journal is queried for **twice** the selected window (current plus the
equal-length prior period) so every KPI can show a delta. A very wide range over
a busy plant is bounded by `max_events`; when that cap is hit the header shows a
*truncated* chip.
* Alarm instances are correlated by journal event id when the journal supplies
one, and by a per-source active/clear state machine otherwise. The mode in use
is reported in `bundle.meta.correlation_mode`.
* "Active now", unacked and shelved counts come from live alarm status, so they
reflect the present moment rather than the selected window.
* Scripts are Jython 2.7 compatible (no f-strings, no `typing`, no `statistics`).
## License
Provided as-is under the terms of the Ignition Exchange.