Data & simulation: - simulation_tags.json: re-prioritize 10 tags to Medium so all four priorities appear in live data (backfilled journal history to match) - SimHarness probe P2: ack-user/includeData ground truth + filtered-bundle verification against the live journal Data layer (PrimeControls.calc/alarms): - filters now drive every metric: queryStatus rows (Active Now/Unacked/ Standing) filtered via calc.apply_status_filters; event_count counts only filtered instances (per-instance n_events); dropdown options enumerate unfiltered data so choices never collapse - build_bundle refactored into _assemble(); when filters are active an unfiltered mirror is attached as bundle.overview - the Overview tab stays a plant-wide summary while all other consumers bind filtered sections - _fetch_journal now honors includeData (required for ackUserName; without it ack attribution is always None); enabled for journal rows + source detail so Top Ack Users and the Ack By column populate FilterBar/Dashboard: - root-cause fix: bidirectional bindings never wrote dropdown selections back to session props, so filters silently did nothing; Apply now pulls values directly from the sibling controls, Clear resets both - multi-select dropdowns cap at 280px and wrap chips; filter bar row is auto-height so wrapped chips push tabs down instead of overlapping - filter bar hidden on the Overview tab (not applicable there) UI scaling: - Header: Prime logo added; KpiCard compacted to fit the 71px KPI row (basis-95% overflow fix, chip hugs text, embeds clipped) - no scrollbars - Overview timeline: thinned x labels (minDistance 140), labels anchored below the axis, smaller legend markers - Bad Actors focus chip shows the full source string with the clear X - popup repeaters (Daily Activity, ScoreBars) no longer overflow (useDefaultViewWidth/Height off, taller strip); 5px table cell padding Tooling/tests: - lint_project.py: accept propConfig params.* as param declarations (Designer saves strip null params entries) - tests: 31 -> 34 (status-filter semantics, overview mirror, filtered event counts) - .gitignore: runtime churn (valueStore.idb, local-system-properties, migration logs, thumbnails, .schemas) New project: AlarmAnalysis - submission copy of PrimeBAT with client-visible Prime Controls branding removed (logo, subtitle, project title, shift report heading); PrimeControls organizational namespaces retained per spec. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Test Data — Simulated Alarm Activity
Generates realistic alarm journal data for building/testing the alarm analysis dashboard. Everything here uses native Ignition features only (memory tags + tag alarms + Jython).
Files
simulation_tags.json— Ignition 8.3 tag export: aBuildathonSimfolder with 49 Boolean memory tags across 5 plant areas (Intake,BoilerHouse,Packaging,Utilities,TankFarm). Every tag has one Equality alarm (active when the tag istrue) with priorities spread across Low / High / Critical.alarm_simulator.py— Jython script that drives those tags. Full usage instructions are in the header comment.
Setup (after the gateway + journal are configured per the main README)
1. Import the tags
Already done if you ran python3 tools/provision.py provision (it imports this file
through the REST API; re-run python3 tools/provision.py import-tags after editing it).
Manual alternative: Designer → Tag Browser → select the default tag provider root →
right-click → Import Tags → choose simulation_tags.json. Either way you should see
BuildathonSim/<Area>/<Tag> folders appear.
2. Install the simulator (gateway timer script — recommended)
- Designer → Project Library → new script named
alarmsim→ paste the contents ofalarm_simulator.py. - Project → Gateway Events → Timer → add a script:
- Delay:
5000ms, Fixed Delay, Dedicated thread - Body:
alarmsim.tick()
- Delay:
- Save the project. Alarm events start flowing into the journal immediately and keep running as long as the gateway is up (no Designer needed).
Alternative: paste the whole file into the Designer Script Console and call
run_console(minutes=30) — simpler, but it blocks the console and stops when you close it.
3. Let it run
Give it 30-60 minutes for meaningful analytics. Roughly every 30-60 minutes one area gets
a flood burst; to force one for a demo, call alarmsim.force_flood() (e.g. temporarily
from the timer script, or from the console if using console mode). alarmsim.reset()
clears all sim tags and state.
Patterns generated (what your analytics should detect)
| Pattern | Tags | Behavior |
|---|---|---|
| Baseline | 40 tags, all areas | Random activations, active 30 s–5 min, ~3-4/min plant-wide |
| Chattering | *_Chatter (3) |
Re-trigger every 30–60 s, active 5–15 s each cycle |
| Standing | *_Standing (2) |
Active from first tick, never clear |
| Fleeting | *_Fleeting (4) |
Active < 10 s (2–8 s), ~1/min |
| Flood | one random area | 15+ activations within 10 min in a single area |
Querying the journal
Events land in MariaDB tables PrimeControls_alarm_events / PrimeControls_alarm_event_data
(created automatically on first event). The plant area is the folder in the alarm's
source path — e.g. prov:default:/tag:BuildathonSim/TankFarm/T101_LevelHigh:/alm:... —
so area analytics can group on the path segment after BuildathonSim/. Priority is stored
on the event; eventtype 0/1/2 = active/clear/ack.
Quick sanity check from your SQL client (localhost:3306, user ignition/ignition):
SELECT source, displaypath, priority, eventtype, eventtime
FROM PrimeControls_alarm_events
ORDER BY eventtime DESC LIMIT 20;