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>
Build-a-Thon — Alarm Analysis Dashboard (Ignition 8.3.7 + Perspective)
Local development environment for the Inductive Automation Build-a-Thon. Native Ignition features only — no third-party modules (contest rule).
Quickstart
docker compose up -d
- Gateway: http://localhost:8088 — login
admin/password - MariaDB:
localhost:3306— dbignition, userignition/ignition(root password:password)
First start takes a minute or two while the gateway commissions itself (EULA, edition, and admin credentials are seeded by env vars, so there is no commissioning wizard). Watch with:
docker compose logs -f ignition
The gateway is ready when curl http://localhost:8088/StatusPing returns {"state":"RUNNING"}.
Gateway state lives in this repo (gateway-as-files)
The gateway's durable state is bind-mounted from the repo (primebench/TestingPlatform pattern) — a container recreate can never wipe it, and the gateway never re-commissions:
| Repo path | In container (data/) |
What's in it |
|---|---|---|
ignition/gateway/commission/commissioning.json |
commissioning.json |
Commissioning marker (committed) |
ignition/gateway/config/ |
config/ |
All config resources: DB connection, journal, API token, tags, secrets |
ignition/gateway/projects/ |
projects/ |
Project files: Perspective views, scripts, timers |
Everything else (internal db, logs, certs) stays ephemeral in the container. The gateway
runs as your host uid/gid (IGNITION_UID/IGNITION_GID, default 1000), so files stay
owned by you.
Edit-files workflow: change files under ignition/gateway/, then tell the gateway to
reload — python3 tools/provision.py scan-config (config/tags) or scan-projects
(project resources). Changes made in the Designer/gateway UI land back in these files,
ready to diff.
Automated provisioning (REST API)
Gateway config is provisioned through the Ignition 8.3 HTTP API using tools/provision.py (stdlib only, no pip installs). On a fresh gateway:
python3 tools/provision.py mint-token # API token file-drops + gateway restart; updates .env
python3 tools/provision.py provision # secret provider + DB connection + alarm journal + sim tags
mint-tokenwrites anapi-tokenconfig resource underignition/gateway/config/, patches theAuthenticated > APIsecurity levels into gateway read/write permissions, restarts the gateway (if running; otherwise the token loads on next boot), and savesIGN_API=Buildathon:<secret>to.env(gitignored). Only the SHA-256 hash of the secret is stored in the config files.provisionis idempotent — it skips resources that already exist. It creates:- file secret provider
local(MariaDB password lives in the gitignored fileignition/gateway/config/secrets/mariadb_password, referenced by the connection — the 8.3 API only accepts encrypted or referenced secrets) - database connection
Buildathon_DB→jdbc:mariadb://db:3306/ignition - alarm journal
Journal→ tablesPrimeControls_alarm_events/PrimeControls_alarm_event_data - imports
test-data/simulation_tags.jsoninto thedefaulttag provider
- file secret provider
Ad-hoc API calls use one header: curl -H "X-Ignition-API-Token: $IGN_API" $GATEWAY_URL/openapi.json
(source .env first).
Two steps remain manual (Designer-only): creating the Buildathon Perspective project
(step 3 below) and installing the simulator timer script (test-data/README.md).
Manual setup reference (what provision.py does, plus the Designer steps)
1. Database connection (MariaDB) — automated
Gateway web UI → Config → Databases → Connections → Create new Database Connection
| Setting | Value |
|---|---|
| Name | Buildathon_DB |
| Driver | MariaDB |
| Connect URL | jdbc:mariadb://db:3306/ignition |
| Username | ignition |
| Password | ignition |
Note the host is db (the compose service name), not localhost — the gateway reaches
MariaDB over the compose network. Save and confirm the status shows Valid.
Ignition 8.3 ships the MariaDB JDBC driver, so no driver install is needed.
2. Alarm journal profile — automated
Gateway web UI → Config → Alarming → Journal → Create new Alarm Journal Profile
| Setting | Value |
|---|---|
| Name | Journal (any name works) |
| Type | Database |
| Datasource | Buildathon_DB |
| Table prefix | PrimeControls_ |
Leave the event filters at defaults (store everything) so the analytics have full data.
The journal auto-creates PrimeControls_alarm_events and PrimeControls_alarm_event_data
in MariaDB the first time an alarm event occurs.
3. Perspective project — manual
- Gateway web UI → Config → Projects → Create new Project (or Designer → File → New Project)
- Name:
Buildathon
- Name:
- Open it in the Designer (launch from http://localhost:8088 → Designer launcher),
then set the project default database: Project → Project Properties → General →
Default Database →
Buildathon_DB. Save the project.
Named queries and bindings that use the "default" database now hit MariaDB.
Test data
See test-data/README.md — imports simulation memory tags with alarm configs and a Jython script that generates realistic alarm activity (baseline alarms across 5 plant areas / 3 priorities, chattering, standing, fleeting, and flood-burst patterns).
Reset to a completely fresh gateway
Gateway state is repo files now, so docker compose down -v alone no longer wipes the
gateway — it only removes the containers and the MariaDB volume. To verify the project
export imports cleanly on a fresh install (the contest judging scenario), set the gateway
files aside and rebuild:
docker compose down -v # containers + MariaDB volume
mv ignition/gateway ignition/gateway.bak # keep your current state for rollback
mkdir -p ignition/gateway/commission ignition/gateway/config ignition/gateway/projects
cp ignition/gateway.bak/commission/commissioning.json ignition/gateway/commission/
docker compose up -d # boots factory-fresh, auto-commissions
python3 tools/provision.py mint-token # old token lived in gateway.bak
python3 tools/provision.py provision
Then import your project export to prove it stands alone. Roll back to your working
state with docker compose down && rm -rf ignition/gateway && mv ignition/gateway.bak ignition/gateway && docker compose up -d (MariaDB journal data is gone either way after
-v — the sim regenerates it).
A plain docker compose down / up -d restarts with everything intact.
Notes
- Max JVM heap is 2 GB (
-m 2048runtime arg in the composecommand). - The 8.3 image's data dir is
/usr/local/bin/ignition/data; onlycommissioning.json,config/, andprojects/are bind-mounted fromignition/gateway/(see the gateway-as-files section above). ignitionwaits on the MariaDB healthcheck before starting, so the datasource is reachable as soon as the gateway is up.