wrps-demo-kit/04-scada/modbus_points/historian/README.md
Clio Liu 0927323e13 fix(scada): PS_* placeholder tags out, CI Server item names in
scada-points.csv led with a scada_tag column of PS_* names derived from
the PLC register map - PS_STN_WET_WELL_LEVEL and the like. CI Server never
adopted them. They named nothing that exists, nothing in this repo read
them, and read as if authoritative they have already caused a real defect
in a downstream project.

Replaced with ci-server-points.csv, the as-built delivery from the CI
Server side (copied from yau-plant-assistant, not re-derived). It is keyed
on the CI Server item, with the station and point name beside it:

    ci_item,ci_station,ci_point,description,poll_group,...

gen_scada_points.py now reproduces that file byte-identically, taking the
names from the LEAF table in gen_ciserver_qli.py so the CSV and the .qli
cannot disagree. tag_for() is gone. Verified: the CSV and all three .qli
regenerate unchanged, and all six displays still build.

The four poll groups keep their PS_ names - PS_STATUS_BITS, PS_PUBLISHED,
PS_SETPOINTS, PS_SIM_CONTROL. Those are live configuration, and are the
only legitimate PS_ names.

modbus_points/README.md gains a 'four namespaces' section - instrument tag,
PLC address, CI Server point, CI Server item - since confusing them is what
produced the placeholder column in the first place.

Also settles the historian drift left open in the previous commit. The
live export is the authority: the server runs WRPS_ONE_SEC at 5 SECONDS,
not 1, and WRPS_THIRTY_SEC at 30 seconds rather than a 60 second
WRPS_ONE_MIN. Code assuming 60 s was wrong by twelvefold. Recorded in
historian/README.md with a caution never to hardcode a sample interval.

Every .qli in the delivery was byte-identical to ours - only the CSV
differed.
2026-09-02 17:21:57 +10:00

3.1 KiB

historian — collection groups and item bindings

Hand-made. There is no generator for this. Everything else under modbus_points/ is generated from 03-plc/register-map.csv; these two files are not, and that is the reason they have drifted from the server.

File Class Holds
his_group.qli @HIS_GROUP_DF 3 collection groups
item_his.qli @ITEM_HIS_DF 49 item → group bindings

⚠️ These files are the INTENDED rates. The server runs different ones.

Resolved 2026-09-02. The question of which was correct is now answered: ../../ciserver-backup-2026-08/export_his_group.qli, taken from the running server, is what the historian actually did. The live export wins.

his_group.qli says The running server does
Fast group WRPS_ONE_SEC at 1 second WRPS_ONE_SEC at 5 seconds
Second group WRPS_ONE_MIN at 60 seconds WRPS_THIRTY_SEC at 30 seconds
Event group WRPS_EVENT, on change WRPS_EVENT, on change

Caution

Never hardcode a sample interval from these files. Anything assuming WRPS_ONE_MIN at 60 seconds is wrong by twelvefold against a group that is actually running at 5 seconds. This has already produced a real defect in a downstream project. Read the interval from the item's own configuration.

The three groups as written here (intended, not live)

Group Items Intended collection
WRPS_ONE_SEC 5 1 s — the fast analogues: level, inflow, discharge
WRPS_ONE_MIN 4 1 min — slower trends
WRPS_EVENT 40 on change — states, commands, alarms, trips

Written 2026-08-21.

Why this matters more than it looks

The demo this project exists to support is built on historical grounding. From 01-design/00-origin/:

"Are you sure? What did inflow actually do last time we had rain like this?"

The answer to that question comes from the historian. Layer 1 of the demo — risk and headroom — works from live values alone. The push-back that earns trust does not. Without these two files there is no historian, and the demo loses the layer it was designed around.

Why they disagree

These files are the source project's intent. The server was tuned afterwards and nobody brought the change back. That is the predictable cost of the one link in this chain with no generator: the points and items cannot drift because they are regenerated; the historian can, and did.

Before importing these onto a working server, export what is there first (../../QUICKLOAD.md) and compare. Importing blind may remove a group something depends on.

Worth doing: generate these too

The points and items chain is generated end to end, which is what keeps the PLC and SCADA from drifting apart. The historian stops short of that, is maintained by hand, and has drifted — exactly the failure the generated chain exists to prevent.

Extending ../gen_ciserver_qli.py to emit @HIS_GROUP_DF and @ITEM_HIS_DF would close the gap. The item list is already there; what it needs is a table saying which item belongs to which group at what rate. Not done in this audit.