wrps-demo-kit/04-scada/QUICKLOAD.md
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

119 lines
4.7 KiB
Markdown

# Quickload — moving configuration in and out of CI Server
`dssqld` is CI Server's quickload utility. It exports and imports **configuration
datasets** as `.qli` files: sections, items, Modbus points, historian groups.
> [!IMPORTANT]
> **Quickload is for configuration only. It is not how displays are deployed.**
> HMI displays are plain file copy/replace into the deployment's `displays`
> directory — see `hmi/DEPLOY.md`. Do not look for a `dssqld` command for them;
> there isn't one.
## The two commands
**Export** — writes every record of one class to a file:
```bash
dssqld -d MODBUS_POINT_DF -e modbus-points.qli
```
`-d` names the class, `-e` the output file.
**Import** — loads a file back in:
```bash
dssqld -i modbus-points.qli
```
The class is read from the file's own `@` header, so import takes no `-d`.
> Other classes may need different flags. These two forms are the ones proven on
> this project. **If a command fails, ask** — do not guess at flags against a live
> configuration.
## The classes this project uses
| Class | File | Holds | Generated? |
|---|---|---|---|
| `SECTION_DF` | `modbus_points/wrps_section_df.qli` | the 6 `AID.WRPS.*` sections | ✅ `gen_ciserver_qli.py` |
| `MODBUS_POINT_DF` | `modbus_points/wrps_modbus_point_df.qli` | 49 Modbus point definitions | ✅ |
| `ITEM_DF` | `modbus_points/wrps_item_df.qli` | 49 items, bound to those points | ✅ |
| `HIS_GROUP_DF` | `modbus_points/historian/his_group.qli` | 3 collection groups | ❌ hand-made |
| `ITEM_HIS_DF` | `modbus_points/historian/item_his.qli` | 49 item→group bindings | ❌ hand-made |
## Import order — it matters
```bash
dssqld -i wrps_section_df.qli # 1. sections
dssqld -i wrps_modbus_point_df.qli # 2. points
dssqld -i wrps_item_df.qli # 3. items
dssqld -i historian/his_group.qli # 4. collection groups
dssqld -i historian/item_his.qli # 5. item -> group bindings
```
Each step depends on the one before it:
- **Sections first.** CI Server derives its hierarchy from the dots in a name, and
a section must exist before an item can be created inside it.
- **Points before items**, because an item binds to a point.
- **Groups before bindings**, because `ITEM_HIS_DF` names both an item and a group
and needs both to exist.
## ⚠️ After importing items, every display goes dead
**An item import renumbers every item.** Proven on 2026-08-14: items were
re-imported to change engineering units, keeping every `NAME`, `NSID` and
`ID_NUMBER` byte-identical — and every itemId still moved. CI Server recreates
items on import rather than updating them in place.
Displays bind by **itemId** at runtime, so every value on every screen dies at
once.
**The fix is one action, and it is not a rebuild:**
> **Open each display in CI Server's Editor Module and validate it.**
Validation resolves every connection by name and rewrites the ids. Then re-harvest
so the next build ships the current ids:
```bash
python hmi/build_display.py --harvest <the saved display>.xml
```
`WRPS_TagTest` binds every project item, so harvesting that one display measures
all 49 in a single pass.
**Moving displays to a different CI Server** needs no rebuild and no re-harvest:
importing a display into the target resolves its connections by name on the way
in. **Import, then validate.** The files built for one server are the files you
ship to the next — provided the item names are identical, which means `ROOT`,
`INSTALL` and `STATION` in `gen_ciserver_qli.py` must match on both.
## Exporting, to check what the server actually holds
The repo cannot see `cicore1`, so the only way to confirm the server agrees with
this folder is to export and diff:
```bash
dssqld -d SECTION_DF -e check_section_df.qli
dssqld -d MODBUS_POINT_DF -e check_modbus_point_df.qli
dssqld -d ITEM_DF -e check_item_df.qli
dssqld -d HIS_GROUP_DF -e check_his_group.qli
dssqld -d ITEM_HIS_DF -e check_item_his_df.qli
```
An export contains **every** record of that class, not just this project's — the
2026-08 export in `ciserver-backup-2026-08/` holds 147 WRPS item records among
others. Filter on `AID.WRPS` when comparing.
**This has already caught a real drift.** The 2026-08 export shows historian
groups (`WRPS_THIRTY_SEC`, `FIVE_SECONDS`) that
`modbus_points/historian/his_group.qli` does not define. One of the two is stale
and nobody currently knows which.
## Format reference
CI Server publishes no documentation for the `.qli` format. Ten real exports are
kept in `99-reference/ciserver-qli-exports/` — every field layout and constant in
`gen_ciserver_qli.py` was copied from them. If you need a class this project does
not use, export one record of it and read the header.