wrps-demo-kit/04-scada
Clio Liu 947f632d7f feat(scada): CI Server tag database, historian, displays
The old 05-scada/, restructured around the distinction its README never
drew: configuration is deployed with dssqld, displays are deployed by
file copy. Conflating the two is what made the folder confusing.

  modbus_points/          the tag database - named for the protocol,
                          since CI Server configures others differently
  modbus_points/historian/  3 groups, 49 bindings - HAND-MADE, no
                          generator, and drifted from the server
  hmi/                    displays and their generator
  ciserver-backup-2026-08/  outdated exports, evidence only, never import
  QUICKLOAD.md            dssqld export/import, the 5 classes, the import
                          order, and why an item import kills every display
  README.md               the chain end to end, and the not-updating triage

Verified during the move - the whole chain is reproducible:
  scada-points.csv and all three .qli regenerate byte-identically
  all six displays build clean

Removed the K offset machinery from build_display.py, item-ids.meta.json
and DEPLOY.md. K was a consistency check on measured ids, not a source of
them, and diagnosing a dead screen by arithmetic is wasted effort when
validating the display in CI Server's Editor Module fixes it outright.
The guidance now leads with that one action.

Recorded, not fixed: the repo's historian config disagrees with the
2026-08 CI Server export - WRPS_THIRTY_SEC and a FIVE_SECONDS group exist
on the server and not here. cicore1 was unreachable during this audit, so
which is correct is unknown.

Not carried across: __pycache__, out/*.xml, and the top-level
WRPS_Overview.xml that was tracked despite .gitignore declaring the
display XMLs to be build output.
2026-09-02 17:16:18 +10:00
..
ciserver-backup-2026-08 feat(scada): CI Server tag database, historian, displays 2026-09-02 17:16:18 +10:00
hmi feat(scada): CI Server tag database, historian, displays 2026-09-02 17:16:18 +10:00
modbus_points feat(scada): CI Server tag database, historian, displays 2026-09-02 17:16:18 +10:00
QUICKLOAD.md feat(scada): CI Server tag database, historian, displays 2026-09-02 17:16:18 +10:00
README.md feat(scada): CI Server tag database, historian, displays 2026-09-02 17:16:18 +10:00

04-scada — the CI Server side

Everything that lives on yau-poc-cicore1 (10.0.0.21): the tag database that reads the PLC, and the displays an operator looks at.

Two halves, two deployment mechanisms

This is the distinction to get straight before anything else. Conflating them is what makes this folder confusing.

Configuration Displays
What sections, items, Modbus points, historian groups the .xml screens
Lives in modbus_points/ hmi/
Deployed by dssqld — the quickload utility file copy into the displays directory
Generated from 03-plc/register-map.csv build_display.py
Binds by NSID / ID_NUMBER itemId — healed by name on import

dssqld is for configuration only. It has nothing to do with displays. See QUICKLOAD.md.

The chain

Everything derives from the PLC. The PLC side leads, always.

03-plc/src/*.st
      │ build.py
      ▼
03-plc/register-map.csv          the contract - 69 points
      │ gen_scada_points.py
      ▼
modbus_points/scada-points.csv   the SCADA view - 49 points, poll groups, units
      │ gen_ciserver_qli.py
      ▼
modbus_points/*.qli              6 sections · 49 Modbus points · 49 items
      │ dssqld -i
      ▼
   CI SERVER  ◄──── Modbus TCP ────  the PLC on 10.0.0.17:502
      ▲
      │ file copy
      │
hmi/out/*.xml                    6 displays
      ▲ build_display.py
      │
hmi/item-ids.csv                 49 itemIds, MEASURED from CI Server

Nothing in this chain is hand-edited. Change a register in 03-plc/build.py, rebuild, then re-run both generators. If CI Server needs a field the generators do not emit, it goes in the generator.

One exception: the historian has no generator. See modbus_points/historian/README.md.

Layout

QUICKLOAD.md            dssqld - export and import configuration
modbus_points/          the tag database (named for the protocol: CI Server
                        configures other protocols differently)
    historian/          collection groups and item bindings - HAND-MADE
hmi/                    displays, and the generator that builds them
ciserver-backup-2026-08/  ⚠️ outdated exports, evidence only - never import

⚠️ "The values on my display are not updating"

First, and before any other investigation:

Open the display in CI Server's Editor Module and validate it. Then report what happened.

Validation resolves every connection by name and repairs the file. It fixes the overwhelmingly common cause in seconds — an itemId that no longer matches, which happens every time the items are re-imported. CI Server recreates items on import rather than updating them in place, so every id in every display moves at once, and every value goes dead together.

That simultaneity is the signature: everything dying at the same moment is ids, not communications.

Only once validation has been ruled out, work down these:

Symptom Cause
Some values dead, others fine Those items were never measured. Harvest the ids — see hmi/DEPLOY.md.
Every analogue reads 0, always You are polling %IW/%IX (FC04/FC02). Those are field inputs; in the simulation build nothing writes them. Live values are in the %QW block (FC03).
Values frozen at a plausible number Communications stopped. Is the container up? Is a program running? The runtime opens its Modbus slave only while a program runs — a stopped program means port 502 refuses.
Values moving but wrong Addressing. %MW starts at holding register 1024, not 0. A wrong-by-1024 read succeeds and returns plausible nonsense.
Alarm word goes negative %QW17 must be read unsigned. Bit 15 does not fit a signed INT.

What this repo cannot tell you: whether CI Server's own poll groups are actually scanning. That lives on cicore1. If the PLC polls correctly with 05-tests/verify_modbus.py and the ids are good, that is the remaining place to look.

Status

Points and items Imported and reading live PLC values (2026-08-14), verified against a direct Modbus read
Generators Verified reproducible 2026-09-02 — scada-points.csv and all three .qli regenerate byte-identically
Displays Six built; build_display.py runs clean
Historian 3 groups, 49 bindings — hand-made, and drifted from the server
CI Server state ⚠️ Unverified. No access to cicore1 during this audit. Everything here is what the repo believes, not what the server holds.

Two things left for you

  • Alarm and trend limits. Every item imports with alarming off and limits at 0. Which points alarm, at what threshold and priority, is engineering judgement about the plant — not something to derive from a register map.
  • Re-export the configuration from cicore1 and diff it against this folder. Until then, ciserver-backup-2026-08/ is the only record of the server's own state, and it is known to disagree with modbus_points/historian/.