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.
This commit is contained in:
Clio Liu 2026-09-02 17:21:57 +10:00
parent 947f632d7f
commit 0927323e13
11 changed files with 169 additions and 102 deletions

View file

@ -30,7 +30,7 @@ Everything derives from the PLC. The PLC side leads, always.
03-plc/register-map.csv the contract - 69 points 03-plc/register-map.csv the contract - 69 points
│ gen_scada_points.py │ gen_scada_points.py
modbus_points/scada-points.csv the SCADA view - 49 points, poll groups, units modbus_points/ci-server-points.csv the SCADA view - 49 points, poll groups, units
│ gen_ciserver_qli.py │ gen_ciserver_qli.py
modbus_points/*.qli 6 sections · 49 Modbus points · 49 items modbus_points/*.qli 6 sections · 49 Modbus points · 49 items
@ -100,9 +100,9 @@ look.
| | | | | |
|---|---| |---|---|
| Points and items | **Imported and reading live PLC values** (2026-08-14), verified against a direct Modbus read | | 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 | | Generators | Verified reproducible 2026-09-02 — `ci-server-points.csv` and all three `.qli` regenerate byte-identically |
| Displays | Six built; `build_display.py` runs clean | | Displays | Six built; `build_display.py` runs clean |
| Historian | 3 groups, 49 bindings — **hand-made, and drifted from the server** | | Historian | 3 groups, 49 bindings — **hand-made, and the live rates differ from these files.** The server runs `WRPS_ONE_SEC` at 5 s and `WRPS_THIRTY_SEC` at 30 s. See `modbus_points/historian/README.md`. |
| CI Server state | ⚠️ **Unverified.** No access to `cicore1` during this audit. Everything here is what the repo believes, not what the server holds. | | 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 ### Two things left for you

View file

@ -21,9 +21,11 @@ as opposed to what the repo believes was configured.
An export holds **every** record of its class, not only this project's. Filter on An export holds **every** record of its class, not only this project's. Filter on
`AID.WRPS` when comparing. `AID.WRPS` when comparing.
## The drift they revealed ## The drift they revealed — and settled
Comparing these against `../modbus_points/historian/` shows the two do not agree: Comparing these against `../modbus_points/historian/` shows the two do not agree.
**These exports are the authority**: they record what the running server actually
did, whereas `his_group.qli` records what the source project intended.
| In this export | In the repo's source | | In this export | In the repo's source |
|---|---| |---|---|
@ -34,6 +36,11 @@ Comparing these against `../modbus_points/historian/` shows the two do not agree
That is the whole reason this folder exists rather than being deleted. That is the whole reason this folder exists rather than being deleted.
**The rates matter more than the names.** The live `WRPS_ONE_SEC` runs at **5
seconds**, not 1, and the second group is `WRPS_THIRTY_SEC` at **30 seconds**, not
a 60 second `WRPS_ONE_MIN`. Code that assumed 60 seconds was wrong by twelvefold.
Never hardcode a sample interval — read it from the item.
## Replacing it ## Replacing it
When `cicore1` is reachable, re-export the five classes (`../../QUICKLOAD.md`), When `cicore1` is reachable, re-export the five classes (`../../QUICKLOAD.md`),

View file

@ -252,7 +252,7 @@ of the spill weir resolves to 0.017% because the register underneath is mm, and
a flow in m³/h to 0.1 — so both get one decimal, and a second would be invented a flow in m³/h to 0.1 — so both get one decimal, and a second would be invented
precision. Integer registers get none. `point_format.check()` fails the build if precision. Integer registers get none. `point_format.check()` fails the build if
a new item has no mask, and the masks are cross-checked against `format_mask` in a new item has no mask, and the masks are cross-checked against `format_mask` in
`04-scada/modbus_points/scada-points.csv`, which is what CI Server imports as `04-scada/modbus_points/ci-server-points.csv`, which is what CI Server imports as
`VALUE_FORMAT`. `VALUE_FORMAT`.
Element order matters to match what CI View saves: `<htmlId>`, `<format>`, Element order matters to match what CI View saves: `<htmlId>`, `<format>`,

View file

@ -35,7 +35,7 @@ decimal is honest and two would not be; a flow in m3/h resolves to 0.1.
Integer registers get no decimal at all - a decimal place there would be Integer registers get no decimal at all - a decimal place there would be
invented precision. invented precision.
**These masks must agree with `format_mask` in `04-scada/modbus_points/scada-points.csv`,** **These masks must agree with `format_mask` in `04-scada/modbus_points/ci-server-points.csv`,**
which is what the item export carries into CI Server as `VALUE_FORMAT`. The which is what the item export carries into CI Server as `VALUE_FORMAT`. The
units and their gains are defined once, in `gen_scada_points.py`. units and their gains are defined once, in `gen_scada_points.py`.
""" """

View file

@ -42,7 +42,7 @@ from pathlib import Path
HERE = Path(__file__).resolve().parent HERE = Path(__file__).resolve().parent
OUT = HERE / "out" OUT = HERE / "out"
POINTS = HERE.parent / "modbus_points" / "scada-points.csv" POINTS = HERE.parent / "modbus_points" / "ci-server-points.csv"
QLI_GEN = HERE.parent / "modbus_points" / "gen_ciserver_qli.py" QLI_GEN = HERE.parent / "modbus_points" / "gen_ciserver_qli.py"
PLC_HOST, PLC_PORT, PLC_UNIT = "192.168.153.192", 502, 1 PLC_HOST, PLC_PORT, PLC_UNIT = "192.168.153.192", 502, 1

View file

@ -7,20 +7,55 @@ Three kinds of file live here, and only the first two are generated:
| | | | | |
|---|---| |---|---|
| **Generated** | `scada-points.csv` and the three `wrps_*.qli` | | **Generated** | `ci-server-points.csv` and the three `wrps_*.qli` |
| **Generators** | `gen_scada_points.py`, `gen_ciserver_qli.py` | | **Generators** | `gen_scada_points.py`, `gen_ciserver_qli.py` |
| **Hand-made** | `historian/` — no generator, and it has drifted. See its README. | | **Hand-made** | `historian/` — no generator, and it has drifted. See its README. |
Deployed with `dssqld`, not by file copy — see `../QUICKLOAD.md`. Deployed with `dssqld`, not by file copy — see `../QUICKLOAD.md`.
## Four namespaces, and which one is which
Getting these confused is the single most common mistake in this folder.
```
LIT-101 instrument tag the field device
%QW0 PLC symbol/address the register the PLC writes
WRPS_PLC:STN_LEVEL CI Server point Modbus station : point name
AID.WRPS.STN.LEVEL CI Server item what displays bind to, and what
the historian is keyed on
```
`ci-server-points.csv` carries all four, one row per point: `ci_item`,
`ci_station`, `ci_point`, `iec_address` and `plc_tag`.
**The historian is keyed on the item, and only the item.** Modbus carries register
numbers, not names, so the point layer and the item layer are free to differ — and
they do.
> [!WARNING]
> **`PS_*` is not one of these namespaces.**
> An earlier version of this file carried a `scada_tag` column with names like
> `PS_STN_WET_WELL_LEVEL`, derived from the PLC register map. **CI Server never
> adopted them.** They named nothing that exists, and they caused a real defect
> downstream when read as if they did.
>
> The **only** legitimate `PS_` names are the four Modbus **poll groups** in the
> `poll_group` column — `PS_STATUS_BITS`, `PS_PUBLISHED`, `PS_SETPOINTS`,
> `PS_SIM_CONTROL`. Those are live configuration.
>
> `ci-server-points.csv` is the as-built delivery from the CI Server side.
> `gen_scada_points.py` reproduces it byte-identically, taking the item names from
> the `LEAF` table in `gen_ciserver_qli.py` so the CSV and the `.qli` cannot
> disagree.
```bash ```bash
python gen_scada_points.py # register-map.csv -> scada-points.csv python gen_scada_points.py # register-map.csv -> ci-server-points.csv
python gen_ciserver_qli.py # scada-points.csv -> the two .qli files python gen_ciserver_qli.py # ci-server-points.csv -> the two .qli files
``` ```
| File | What | | File | What |
|---|---| |---|---|
| `scada-points.csv` | The point list, for reading and for configuring by hand | | `ci-server-points.csv` | The point list, keyed on the **CI Server item** each point feeds |
| `historian/` | Collection groups and 49 item bindings — **hand-made**, see its README | | `historian/` | Collection groups and 49 item bindings — **hand-made**, see its README |
| `wrps_section_df.qli` | `@SECTION_DF` — the six `AID.WRPS.*` sections | | `wrps_section_df.qli` | `@SECTION_DF` — the six `AID.WRPS.*` sections |
| `wrps_modbus_point_df.qli` | `@MODBUS_POINT_DF` — 49 Modbus point definitions, station `WRPS_PLC` | | `wrps_modbus_point_df.qli` | `@MODBUS_POINT_DF` — 49 Modbus point definitions, station `WRPS_PLC` |
@ -29,7 +64,7 @@ python gen_ciserver_qli.py # scada-points.csv -> the two .qli files
**Import in that order.** CI Server derives its hierarchy from the dots in a name, **Import in that order.** CI Server derives its hierarchy from the dots in a name,
and a section must exist before an item can be created inside it. and a section must exist before an item can be created inside it.
The chain is ST sources → `03-plc/register-map.csv``scada-points.csv` → `.qli`, The chain is ST sources → `03-plc/register-map.csv``ci-server-points.csv` → `.qli`,
so a register change propagates by re-running the scripts. **Nothing here is so a register change propagates by re-running the scripts. **Nothing here is
hand-edited**; if CI Server needs a field the generators do not emit, it goes in hand-edited**; if CI Server needs a field the generators do not emit, it goes in
the generator. the generator.
@ -90,7 +125,7 @@ presentation choice, made here, as a pure gain on the raw register:
| `SP.MIN_SPEED` | % | 0.2 | same scale as `STN.SPEED`; **entered in %** | | `SP.MIN_SPEED` | % | 0.2 | same scale as `STN.SPEED`; **entered in %** |
The gains live in one place — `UNITS` in `gen_scada_points.py`. Change a unit The gains live in one place — `UNITS` in `gen_scada_points.py`. Change a unit
there and it propagates to `scada-points.csv`, to both `.qli` files and to the there and it propagates to `ci-server-points.csv`, to both `.qli` files and to the
HMI masks. HMI masks.
> [!IMPORTANT] > [!IMPORTANT]
@ -128,7 +163,7 @@ unsigned; see below.
## The point list ## The point list
`gen_scada_points.py` reads `03-plc/register-map.csv` (the PLC-side list, itself `gen_scada_points.py` reads `03-plc/register-map.csv` (the PLC-side list, itself
generated from the ST sources) and rewrites `scada-points.csv`. Re-run it after any generated from the ST sources) and rewrites `ci-server-points.csv`. Re-run it after any
register change so the two sides cannot drift — that is the §3 invariant. Anything register change so the two sides cannot drift — that is the §3 invariant. Anything
changed by hand here is lost on the next run; if CI Server needs a field the script changed by hand here is lost on the next run; if CI Server needs a field the script
does not emit, it goes in the generator. does not emit, it goes in the generator.

View file

@ -0,0 +1,50 @@
ci_item,ci_station,ci_point,description,poll_group,function_code,modbus_address,data_type,access,eng_units,raw_to_eng,eng_gain,format_mask,iec_address,plc_tag,notes
AID.WRPS.PU301.RUN_CMD,WRPS_PLC,PU301_RUN_CMD,Run command,PS_STATUS_BITS,FC01,0,Boolean,Read,,value,1.0,99999,%QX0.0,PU-301,
AID.WRPS.PU302.RUN_CMD,WRPS_PLC,PU302_RUN_CMD,Run command,PS_STATUS_BITS,FC01,1,Boolean,Read,,value,1.0,99999,%QX0.1,PU-302,
AID.WRPS.PU303.RUN_CMD,WRPS_PLC,PU303_RUN_CMD,Run command,PS_STATUS_BITS,FC01,2,Boolean,Read,,value,1.0,99999,%QX0.2,PU-303,
AID.WRPS.PU301.RUNNING,WRPS_PLC,PU301_RUNNING,Running,PS_STATUS_BITS,FC01,3,Boolean,Read,,value,1.0,99999,%QX0.3,PU-301,
AID.WRPS.PU302.RUNNING,WRPS_PLC,PU302_RUNNING,Running,PS_STATUS_BITS,FC01,4,Boolean,Read,,value,1.0,99999,%QX0.4,PU-302,
AID.WRPS.PU303.RUNNING,WRPS_PLC,PU303_RUNNING,Running,PS_STATUS_BITS,FC01,5,Boolean,Read,,value,1.0,99999,%QX0.5,PU-303,
AID.WRPS.PU301.AVAILABLE,WRPS_PLC,PU301_AVAILABLE,Available,PS_STATUS_BITS,FC01,6,Boolean,Read,,value,1.0,99999,%QX0.6,PU-301,
AID.WRPS.PU302.AVAILABLE,WRPS_PLC,PU302_AVAILABLE,Available,PS_STATUS_BITS,FC01,7,Boolean,Read,,value,1.0,99999,%QX0.7,PU-302,
AID.WRPS.PU303.AVAILABLE,WRPS_PLC,PU303_AVAILABLE,Available,PS_STATUS_BITS,FC01,8,Boolean,Read,,value,1.0,99999,%QX1.0,PU-303,
AID.WRPS.STN.IN_AUTO,WRPS_PLC,STN_IN_AUTO,Station in auto,PS_STATUS_BITS,FC01,9,Boolean,Read,,value,1.0,99999,%QX1.1,STN,
AID.WRPS.STN.HIGH_LEVEL,WRPS_PLC,STN_HIGH_LEVEL,High level alarm,PS_STATUS_BITS,FC01,10,Boolean,Read,,value,1.0,99999,%QX1.2,STN,
AID.WRPS.STN.SPILL_ACTIVE,WRPS_PLC,STN_SPILL_ACTIVE,Spill active,PS_STATUS_BITS,FC01,11,Boolean,Read,,value,1.0,99999,%QX1.3,STN,
AID.WRPS.PU301.TRIPPED,WRPS_PLC,PU301_TRIPPED,Tripped,PS_STATUS_BITS,FC01,12,Boolean,Read,,value,1.0,99999,%QX1.4,PU-301,
AID.WRPS.PU302.TRIPPED,WRPS_PLC,PU302_TRIPPED,Tripped,PS_STATUS_BITS,FC01,13,Boolean,Read,,value,1.0,99999,%QX1.5,PU-302,
AID.WRPS.PU303.TRIPPED,WRPS_PLC,PU303_TRIPPED,Tripped,PS_STATUS_BITS,FC01,14,Boolean,Read,,value,1.0,99999,%QX1.6,PU-303,
AID.WRPS.STN.LEVEL,WRPS_PLC,STN_LEVEL,Wet well level,PS_PUBLISHED,FC03,0,Signed 16-bit,Read,%,value / 60,0.016666666666666666,999.9,%QW0,STN,
AID.WRPS.STN.INFLOW,WRPS_PLC,STN_INFLOW,Inflow,PS_PUBLISHED,FC03,1,Signed 16-bit,Read,m3/h,value * 0.36,0.36,9999.9,%QW1,STN,
AID.WRPS.STN.DISCHARGE,WRPS_PLC,STN_DISCHARGE,Total discharge flow,PS_PUBLISHED,FC03,2,Signed 16-bit,Read,m3/h,value * 0.36,0.36,9999.9,%QW2,STN,
AID.WRPS.STN.PUMPS_RUNNING,WRPS_PLC,STN_PUMPS_RUNNING,Pumps running,PS_PUBLISHED,FC03,3,Signed 16-bit,Read,count,value,1.0,9,%QW3,STN,
AID.WRPS.STN.SPEED,WRPS_PLC,STN_SPEED,Common drive speed,PS_PUBLISHED,FC03,4,Signed 16-bit,Read,%,value * 0.2,0.2,999.9,%QW4,STN,
AID.WRPS.STN.TIME_TO_SPILL,WRPS_PLC,STN_TIME_TO_SPILL,Time to spill weir (32767 = drawing down),PS_PUBLISHED,FC03,5,Signed 16-bit,Read,s,value,1.0,99999,%QW5,STN,
AID.WRPS.STN.TIME_TO_LSHH,WRPS_PLC,STN_TIME_TO_LSHH,Time to LSHH (32767 = drawing down),PS_PUBLISHED,FC03,6,Signed 16-bit,Read,s,value,1.0,99999,%QW6,STN,
AID.WRPS.STN.NET_ACCUM,WRPS_PLC,STN_NET_ACCUM,Net accumulation (signed),PS_PUBLISHED,FC03,7,Signed 16-bit,Read,m3/h,value * 0.36,0.36,9999.9,%QW7,STN,
AID.WRPS.PU301.RUN_HOURS,WRPS_PLC,PU301_RUN_HOURS,Run hours,PS_PUBLISHED,FC03,8,Signed 16-bit,Read,h,value,1.0,99999,%QW8,PU-301,
AID.WRPS.PU302.RUN_HOURS,WRPS_PLC,PU302_RUN_HOURS,Run hours,PS_PUBLISHED,FC03,9,Signed 16-bit,Read,h,value,1.0,99999,%QW9,PU-302,
AID.WRPS.PU303.RUN_HOURS,WRPS_PLC,PU303_RUN_HOURS,Run hours,PS_PUBLISHED,FC03,10,Signed 16-bit,Read,h,value,1.0,99999,%QW10,PU-303,
AID.WRPS.STN.VOL_TO_SPILL,WRPS_PLC,STN_VOL_TO_SPILL,Volume remaining to spill,PS_PUBLISHED,FC03,11,Signed 16-bit,Read,m3,value,1.0,9999,%QW11,STN,
AID.WRPS.STN.STATE,WRPS_PLC,STN_STATE,Station state (enum 3.1),PS_PUBLISHED,FC03,12,Signed 16-bit,Read,,value,1.0,9,%QW12,STN,
AID.WRPS.PU301.STATE,WRPS_PLC,PU301_STATE,Pump state (enum 3.2),PS_PUBLISHED,FC03,13,Signed 16-bit,Read,,value,1.0,9,%QW13,PU-301,
AID.WRPS.PU302.STATE,WRPS_PLC,PU302_STATE,Pump state (enum 3.2),PS_PUBLISHED,FC03,14,Signed 16-bit,Read,,value,1.0,9,%QW14,PU-302,
AID.WRPS.PU303.STATE,WRPS_PLC,PU303_STATE,Pump state (enum 3.2),PS_PUBLISHED,FC03,15,Signed 16-bit,Read,,value,1.0,9,%QW15,PU-303,
AID.WRPS.STN.DUTY_PUMP,WRPS_PLC,STN_DUTY_PUMP,"Current duty pump (0 = none, 1-3)",PS_PUBLISHED,FC03,16,Signed 16-bit,Read,,value,1.0,9,%QW16,STN,
AID.WRPS.STN.ALARM_WORD,WRPS_PLC,STN_ALARM_WORD,Alarm bitmask (section 6) - READ AS UNSIGNED,PS_PUBLISHED,FC03,17,Unsigned 16-bit,Read,,value,1.0,99999,%QW17,STN,
AID.WRPS.STN.CMD_ACK,WRPS_PLC,STN_CMD_ACK,Command acknowledge (echoes %MW1),PS_PUBLISHED,FC03,20,Signed 16-bit,Read,,value,1.0,99,%QW20,STN,
AID.WRPS.SP.MODE,WRPS_PLC,SP_MODE,"Station mode: 1 = auto, 2 = off",PS_SETPOINTS,FC03/FC06,1024,Signed 16-bit,Read/Write,,value,1.0,9,%MW0,STN,
AID.WRPS.SP.CMD_WORD,WRPS_PLC,SP_CMD_WORD,Command word (section 3.3),PS_SETPOINTS,FC03/FC06,1025,Signed 16-bit,Read/Write,,value,1.0,99,%MW1,STN,
AID.WRPS.SP.CMD_PARAM,WRPS_PLC,SP_CMD_PARAM,Command parameter (pump number),PS_SETPOINTS,FC03/FC06,1026,Signed 16-bit,Read/Write,,value,1.0,9,%MW2,STN,
AID.WRPS.SP.LEVEL_SP,WRPS_PLC,SP_LEVEL_SP,Level control setpoint,PS_SETPOINTS,FC03/FC06,1027,Signed 16-bit,Read/Write,%,value / 60,0.016666666666666666,999.9,%MW3,STN,
AID.WRPS.SP.START_DUTY,WRPS_PLC,SP_START_DUTY,Start duty level,PS_SETPOINTS,FC03/FC06,1028,Signed 16-bit,Read/Write,%,value / 60,0.016666666666666666,999.9,%MW4,STN,
AID.WRPS.SP.START_P2,WRPS_PLC,SP_START_P2,Start pump 2 level,PS_SETPOINTS,FC03/FC06,1029,Signed 16-bit,Read/Write,%,value / 60,0.016666666666666666,999.9,%MW5,STN,
AID.WRPS.SP.START_P3,WRPS_PLC,SP_START_P3,Start pump 3 level,PS_SETPOINTS,FC03/FC06,1030,Signed 16-bit,Read/Write,%,value / 60,0.016666666666666666,999.9,%MW6,STN,
AID.WRPS.SP.STOP_ALL,WRPS_PLC,SP_STOP_ALL,Stop all level,PS_SETPOINTS,FC03/FC06,1031,Signed 16-bit,Read/Write,%,value / 60,0.016666666666666666,999.9,%MW7,STN,
AID.WRPS.SP.HIGH_ALARM,WRPS_PLC,SP_HIGH_ALARM,High level alarm,PS_SETPOINTS,FC03/FC06,1032,Signed 16-bit,Read/Write,%,value / 60,0.016666666666666666,999.9,%MW8,STN,
AID.WRPS.SP.MIN_SPEED,WRPS_PLC,SP_MIN_SPEED,Minimum drive speed,PS_SETPOINTS,FC03/FC06,1033,Signed 16-bit,Read/Write,%,value * 0.2,0.2,999.9,%MW9,STN,
AID.WRPS.SP.SERVICE_HRS,WRPS_PLC,SP_SERVICE_HRS,Service interval,PS_SETPOINTS,FC03/FC06,1034,Signed 16-bit,Read/Write,h,value,1.0,99999,%MW10,STN,
AID.WRPS.SIM.INFLOW,WRPS_PLC,SIM_INFLOW,manual inflow (mode 0),PS_SIM_CONTROL,FC03/FC06,1044,Signed 16-bit,Read/Write,m3/h,value * 0.36,0.36,9999.9,%MW20,SIM,SIMULATION CONTROL - simulation build only
AID.WRPS.SIM.SCENARIO,WRPS_PLC,SIM_SCENARIO,scenario 0=man 1=diurnal 2=wet 3=ref,PS_SIM_CONTROL,FC03/FC06,1045,Signed 16-bit,Read/Write,,value,1.0,9,%MW21,SIM,SIMULATION CONTROL - simulation build only
AID.WRPS.SIM.RESET,WRPS_PLC,SIM_RESET,"write 1 to reset scenario, self-clearing",PS_SIM_CONTROL,FC03/FC06,1046,Signed 16-bit,Read/Write,,value,1.0,9,%MW22,SIM,SIMULATION CONTROL - simulation build only
AID.WRPS.SIM.TIME_SCALE,WRPS_PLC,SIM_TIME_SCALE,time scale 1-120,PS_SIM_CONTROL,FC03/FC06,1047,Signed 16-bit,Read/Write,x,value,1.0,999,%MW23,SIM,SIMULATION CONTROL - simulation build only
1 ci_item ci_station ci_point description poll_group function_code modbus_address data_type access eng_units raw_to_eng eng_gain format_mask iec_address plc_tag notes
2 AID.WRPS.PU301.RUN_CMD WRPS_PLC PU301_RUN_CMD Run command PS_STATUS_BITS FC01 0 Boolean Read value 1.0 99999 %QX0.0 PU-301
3 AID.WRPS.PU302.RUN_CMD WRPS_PLC PU302_RUN_CMD Run command PS_STATUS_BITS FC01 1 Boolean Read value 1.0 99999 %QX0.1 PU-302
4 AID.WRPS.PU303.RUN_CMD WRPS_PLC PU303_RUN_CMD Run command PS_STATUS_BITS FC01 2 Boolean Read value 1.0 99999 %QX0.2 PU-303
5 AID.WRPS.PU301.RUNNING WRPS_PLC PU301_RUNNING Running PS_STATUS_BITS FC01 3 Boolean Read value 1.0 99999 %QX0.3 PU-301
6 AID.WRPS.PU302.RUNNING WRPS_PLC PU302_RUNNING Running PS_STATUS_BITS FC01 4 Boolean Read value 1.0 99999 %QX0.4 PU-302
7 AID.WRPS.PU303.RUNNING WRPS_PLC PU303_RUNNING Running PS_STATUS_BITS FC01 5 Boolean Read value 1.0 99999 %QX0.5 PU-303
8 AID.WRPS.PU301.AVAILABLE WRPS_PLC PU301_AVAILABLE Available PS_STATUS_BITS FC01 6 Boolean Read value 1.0 99999 %QX0.6 PU-301
9 AID.WRPS.PU302.AVAILABLE WRPS_PLC PU302_AVAILABLE Available PS_STATUS_BITS FC01 7 Boolean Read value 1.0 99999 %QX0.7 PU-302
10 AID.WRPS.PU303.AVAILABLE WRPS_PLC PU303_AVAILABLE Available PS_STATUS_BITS FC01 8 Boolean Read value 1.0 99999 %QX1.0 PU-303
11 AID.WRPS.STN.IN_AUTO WRPS_PLC STN_IN_AUTO Station in auto PS_STATUS_BITS FC01 9 Boolean Read value 1.0 99999 %QX1.1 STN
12 AID.WRPS.STN.HIGH_LEVEL WRPS_PLC STN_HIGH_LEVEL High level alarm PS_STATUS_BITS FC01 10 Boolean Read value 1.0 99999 %QX1.2 STN
13 AID.WRPS.STN.SPILL_ACTIVE WRPS_PLC STN_SPILL_ACTIVE Spill active PS_STATUS_BITS FC01 11 Boolean Read value 1.0 99999 %QX1.3 STN
14 AID.WRPS.PU301.TRIPPED WRPS_PLC PU301_TRIPPED Tripped PS_STATUS_BITS FC01 12 Boolean Read value 1.0 99999 %QX1.4 PU-301
15 AID.WRPS.PU302.TRIPPED WRPS_PLC PU302_TRIPPED Tripped PS_STATUS_BITS FC01 13 Boolean Read value 1.0 99999 %QX1.5 PU-302
16 AID.WRPS.PU303.TRIPPED WRPS_PLC PU303_TRIPPED Tripped PS_STATUS_BITS FC01 14 Boolean Read value 1.0 99999 %QX1.6 PU-303
17 AID.WRPS.STN.LEVEL WRPS_PLC STN_LEVEL Wet well level PS_PUBLISHED FC03 0 Signed 16-bit Read % value / 60 0.016666666666666666 999.9 %QW0 STN
18 AID.WRPS.STN.INFLOW WRPS_PLC STN_INFLOW Inflow PS_PUBLISHED FC03 1 Signed 16-bit Read m3/h value * 0.36 0.36 9999.9 %QW1 STN
19 AID.WRPS.STN.DISCHARGE WRPS_PLC STN_DISCHARGE Total discharge flow PS_PUBLISHED FC03 2 Signed 16-bit Read m3/h value * 0.36 0.36 9999.9 %QW2 STN
20 AID.WRPS.STN.PUMPS_RUNNING WRPS_PLC STN_PUMPS_RUNNING Pumps running PS_PUBLISHED FC03 3 Signed 16-bit Read count value 1.0 9 %QW3 STN
21 AID.WRPS.STN.SPEED WRPS_PLC STN_SPEED Common drive speed PS_PUBLISHED FC03 4 Signed 16-bit Read % value * 0.2 0.2 999.9 %QW4 STN
22 AID.WRPS.STN.TIME_TO_SPILL WRPS_PLC STN_TIME_TO_SPILL Time to spill weir (32767 = drawing down) PS_PUBLISHED FC03 5 Signed 16-bit Read s value 1.0 99999 %QW5 STN
23 AID.WRPS.STN.TIME_TO_LSHH WRPS_PLC STN_TIME_TO_LSHH Time to LSHH (32767 = drawing down) PS_PUBLISHED FC03 6 Signed 16-bit Read s value 1.0 99999 %QW6 STN
24 AID.WRPS.STN.NET_ACCUM WRPS_PLC STN_NET_ACCUM Net accumulation (signed) PS_PUBLISHED FC03 7 Signed 16-bit Read m3/h value * 0.36 0.36 9999.9 %QW7 STN
25 AID.WRPS.PU301.RUN_HOURS WRPS_PLC PU301_RUN_HOURS Run hours PS_PUBLISHED FC03 8 Signed 16-bit Read h value 1.0 99999 %QW8 PU-301
26 AID.WRPS.PU302.RUN_HOURS WRPS_PLC PU302_RUN_HOURS Run hours PS_PUBLISHED FC03 9 Signed 16-bit Read h value 1.0 99999 %QW9 PU-302
27 AID.WRPS.PU303.RUN_HOURS WRPS_PLC PU303_RUN_HOURS Run hours PS_PUBLISHED FC03 10 Signed 16-bit Read h value 1.0 99999 %QW10 PU-303
28 AID.WRPS.STN.VOL_TO_SPILL WRPS_PLC STN_VOL_TO_SPILL Volume remaining to spill PS_PUBLISHED FC03 11 Signed 16-bit Read m3 value 1.0 9999 %QW11 STN
29 AID.WRPS.STN.STATE WRPS_PLC STN_STATE Station state (enum 3.1) PS_PUBLISHED FC03 12 Signed 16-bit Read value 1.0 9 %QW12 STN
30 AID.WRPS.PU301.STATE WRPS_PLC PU301_STATE Pump state (enum 3.2) PS_PUBLISHED FC03 13 Signed 16-bit Read value 1.0 9 %QW13 PU-301
31 AID.WRPS.PU302.STATE WRPS_PLC PU302_STATE Pump state (enum 3.2) PS_PUBLISHED FC03 14 Signed 16-bit Read value 1.0 9 %QW14 PU-302
32 AID.WRPS.PU303.STATE WRPS_PLC PU303_STATE Pump state (enum 3.2) PS_PUBLISHED FC03 15 Signed 16-bit Read value 1.0 9 %QW15 PU-303
33 AID.WRPS.STN.DUTY_PUMP WRPS_PLC STN_DUTY_PUMP Current duty pump (0 = none, 1-3) PS_PUBLISHED FC03 16 Signed 16-bit Read value 1.0 9 %QW16 STN
34 AID.WRPS.STN.ALARM_WORD WRPS_PLC STN_ALARM_WORD Alarm bitmask (section 6) - READ AS UNSIGNED PS_PUBLISHED FC03 17 Unsigned 16-bit Read value 1.0 99999 %QW17 STN
35 AID.WRPS.STN.CMD_ACK WRPS_PLC STN_CMD_ACK Command acknowledge (echoes %MW1) PS_PUBLISHED FC03 20 Signed 16-bit Read value 1.0 99 %QW20 STN
36 AID.WRPS.SP.MODE WRPS_PLC SP_MODE Station mode: 1 = auto, 2 = off PS_SETPOINTS FC03/FC06 1024 Signed 16-bit Read/Write value 1.0 9 %MW0 STN
37 AID.WRPS.SP.CMD_WORD WRPS_PLC SP_CMD_WORD Command word (section 3.3) PS_SETPOINTS FC03/FC06 1025 Signed 16-bit Read/Write value 1.0 99 %MW1 STN
38 AID.WRPS.SP.CMD_PARAM WRPS_PLC SP_CMD_PARAM Command parameter (pump number) PS_SETPOINTS FC03/FC06 1026 Signed 16-bit Read/Write value 1.0 9 %MW2 STN
39 AID.WRPS.SP.LEVEL_SP WRPS_PLC SP_LEVEL_SP Level control setpoint PS_SETPOINTS FC03/FC06 1027 Signed 16-bit Read/Write % value / 60 0.016666666666666666 999.9 %MW3 STN
40 AID.WRPS.SP.START_DUTY WRPS_PLC SP_START_DUTY Start duty level PS_SETPOINTS FC03/FC06 1028 Signed 16-bit Read/Write % value / 60 0.016666666666666666 999.9 %MW4 STN
41 AID.WRPS.SP.START_P2 WRPS_PLC SP_START_P2 Start pump 2 level PS_SETPOINTS FC03/FC06 1029 Signed 16-bit Read/Write % value / 60 0.016666666666666666 999.9 %MW5 STN
42 AID.WRPS.SP.START_P3 WRPS_PLC SP_START_P3 Start pump 3 level PS_SETPOINTS FC03/FC06 1030 Signed 16-bit Read/Write % value / 60 0.016666666666666666 999.9 %MW6 STN
43 AID.WRPS.SP.STOP_ALL WRPS_PLC SP_STOP_ALL Stop all level PS_SETPOINTS FC03/FC06 1031 Signed 16-bit Read/Write % value / 60 0.016666666666666666 999.9 %MW7 STN
44 AID.WRPS.SP.HIGH_ALARM WRPS_PLC SP_HIGH_ALARM High level alarm PS_SETPOINTS FC03/FC06 1032 Signed 16-bit Read/Write % value / 60 0.016666666666666666 999.9 %MW8 STN
45 AID.WRPS.SP.MIN_SPEED WRPS_PLC SP_MIN_SPEED Minimum drive speed PS_SETPOINTS FC03/FC06 1033 Signed 16-bit Read/Write % value * 0.2 0.2 999.9 %MW9 STN
46 AID.WRPS.SP.SERVICE_HRS WRPS_PLC SP_SERVICE_HRS Service interval PS_SETPOINTS FC03/FC06 1034 Signed 16-bit Read/Write h value 1.0 99999 %MW10 STN
47 AID.WRPS.SIM.INFLOW WRPS_PLC SIM_INFLOW manual inflow (mode 0) PS_SIM_CONTROL FC03/FC06 1044 Signed 16-bit Read/Write m3/h value * 0.36 0.36 9999.9 %MW20 SIM SIMULATION CONTROL - simulation build only
48 AID.WRPS.SIM.SCENARIO WRPS_PLC SIM_SCENARIO scenario 0=man 1=diurnal 2=wet 3=ref PS_SIM_CONTROL FC03/FC06 1045 Signed 16-bit Read/Write value 1.0 9 %MW21 SIM SIMULATION CONTROL - simulation build only
49 AID.WRPS.SIM.RESET WRPS_PLC SIM_RESET write 1 to reset scenario, self-clearing PS_SIM_CONTROL FC03/FC06 1046 Signed 16-bit Read/Write value 1.0 9 %MW22 SIM SIMULATION CONTROL - simulation build only
50 AID.WRPS.SIM.TIME_SCALE WRPS_PLC SIM_TIME_SCALE time scale 1-120 PS_SIM_CONTROL FC03/FC06 1047 Signed 16-bit Read/Write x value 1.0 999 %MW23 SIM SIMULATION CONTROL - simulation build only

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Emit CI Server .qli imports for the WRPS points. """Emit CI Server .qli imports for the WRPS points.
python gen_scada_points.py # first: refresh scada-points.csv python gen_scada_points.py # first: refresh ci-server-points.csv
python gen_ciserver_qli.py python gen_ciserver_qli.py
Writes, alongside this script: Writes, alongside this script:
@ -13,7 +13,7 @@ Writes, alongside this script:
Import them in that order: CI Server derives its hierarchy from the dots Import them in that order: CI Server derives its hierarchy from the dots
in a name, and a section must exist before an item can be created in it. in a name, and a section must exist before an item can be created in it.
The chain is ST sources -> 03-plc/register-map.csv -> scada-points.csv -> The chain is ST sources -> 03-plc/register-map.csv -> ci-server-points.csv ->
these files, so a register change propagates by re-running the three these files, so a register change propagates by re-running the three
scripts rather than by hand-editing anything. scripts rather than by hand-editing anything.
@ -48,7 +48,7 @@ import sys
from pathlib import Path from pathlib import Path
HERE = Path(__file__).resolve().parent HERE = Path(__file__).resolve().parent
POINTS = HERE / "scada-points.csv" POINTS = HERE / "ci-server-points.csv"
STATION = "WRPS_PLC" STATION = "WRPS_PLC"
ROOT = "AID.WRPS" ROOT = "AID.WRPS"
@ -331,7 +331,7 @@ def main():
args = ap.parse_args() args = ap.parse_args()
if not POINTS.is_file(): if not POINTS.is_file():
sys.exit("missing scada-points.csv - run gen_scada_points.py first") sys.exit("missing ci-server-points.csv - run gen_scada_points.py first")
pinned = {} pinned = {}
for spec in args.section_nsid: for spec in args.section_nsid:

View file

@ -4,7 +4,7 @@
python gen_scada_points.py python gen_scada_points.py
Reads ../../03-plc/register-map.csv (PLC side, generated by build.py) Reads ../../03-plc/register-map.csv (PLC side, generated by build.py)
Writes ./scada-points.csv (SCADA side, for CI Server config) Writes ./ci-server-points.csv (SCADA side, for CI Server config)
CLAUDE.md section 3: the two sides are two views of the same points, and CLAUDE.md section 3: the two sides are two views of the same points, and
the PLC side leads. This script makes the SCADA view reproducible the PLC side leads. This script makes the SCADA view reproducible
@ -48,7 +48,7 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parents[2] ROOT = Path(__file__).resolve().parents[2]
SRC_MAP = ROOT / "03-plc" / "register-map.csv" SRC_MAP = ROOT / "03-plc" / "register-map.csv"
OUT = Path(__file__).resolve().parent / "scada-points.csv" OUT = Path(__file__).resolve().parent / "ci-server-points.csv"
# Modbus object -> (function code, poll group name) # Modbus object -> (function code, poll group name)
# #
@ -165,17 +165,31 @@ def gain_expr(gain):
return "value * %g" % gain return "value * %g" % gain
def tag_for(row, description): # The CI Server naming, imported from the .qli generator so the two files
"""Tag name per CLAUDE.md section 8: PS_<EQUIP><NN>_<MEAS>. # cannot disagree. LEAF is keyed on IEC address and is the single place
# section/leaf names are defined.
#
# An earlier version of this script emitted a `scada_tag` column holding
# names like PS_STN_WET_WELL_LEVEL, derived from the PLC register map.
# **CI Server never adopted them.** They named nothing that exists, and
# they caused a real defect downstream when read as if they did. The only
# legitimate PS_ names are the four Modbus POLL GROUPS below, which are
# live configuration.
sys.path.insert(0, str(Path(__file__).resolve().parent))
from gen_ciserver_qli import LEAF, ROOT, STATION
Built from the cleaned description, so the "SIM ONLY:" marker does
not end up inside the tag name. def ci_names(iec):
"""(item, station, point) - the three CI Server namespaces.
AID.WRPS.STN.LEVEL item what the historian is keyed on
WRPS_PLC station the Modbus station
STN_LEVEL point the Modbus point on that station
""" """
equip = row["tag"].replace("-", "") if iec not in LEAF:
meas = description.split("(")[0].split(",")[0].strip() sys.exit(f"no leaf name defined for {iec} - add it to LEAF in gen_ciserver_qli.py")
meas = "".join(ch if ch.isalnum() else "_" for ch in meas) section, leaf = LEAF[iec]
meas = "_".join(p for p in meas.split("_") if p)[:28].upper() return (f"{ROOT}.{section}.{leaf}", STATION, ("%s_%s" % (section, leaf))[:24])
return f"PS_{equip}_{meas}".upper()
def main(): def main():
@ -225,7 +239,9 @@ def main():
out_rows.append( out_rows.append(
{ {
"scada_tag": tag_for(r, description), "ci_item": ci_names(iec)[0],
"ci_station": ci_names(iec)[1],
"ci_point": ci_names(iec)[2],
"description": description, "description": description,
"poll_group": group, "poll_group": group,
"function_code": fc, "function_code": fc,

View file

@ -9,12 +9,30 @@ not, and that is the reason they have drifted from the server.
| `his_group.qli` | `@HIS_GROUP_DF` | 3 collection groups | | `his_group.qli` | `@HIS_GROUP_DF` | 3 collection groups |
| `item_his.qli` | `@ITEM_HIS_DF` | 49 item → group bindings | | `item_his.qli` | `@ITEM_HIS_DF` | 49 item → group bindings |
## The three groups ## ⚠️ These files are the INTENDED rates. The server runs different ones.
| Group | Items | Collection | > **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 |
|---|---|---| |---|---|---|
| `WRPS_ONE_SEC` | 5 | 1 s scan — the fast analogues: level, inflow, discharge | | Fast group | `WRPS_ONE_SEC` at **1 second** | `WRPS_ONE_SEC` at **5 seconds** |
| `WRPS_ONE_MIN` | 4 | 1 min scan — slower trends | | 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 | | `WRPS_EVENT` | 40 | on change — states, commands, alarms, trips |
Written 2026-08-21. Written 2026-08-21.
@ -31,25 +49,16 @@ and headroom — works from live values alone. The push-back that earns trust do
not. **Without these two files there is no historian, and the demo loses the layer not. **Without these two files there is no historian, and the demo loses the layer
it was designed around.** it was designed around.**
## ⚠️ These files disagree with the server ## Why they disagree
`ciserver-backup-2026-08/export_his_group.qli`, exported from CI Server around These files are the *source project's* intent. The server was tuned afterwards and
2026-08-20, contains groups that `his_group.qli` does not define: 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.
| In the CI Server export | In `his_group.qli` | Before importing these onto a working server, **export what is there first**
|---|---| (`../../QUICKLOAD.md`) and compare. Importing blind may remove a group something
| `WRPS_EVENT` | ✅ | depends on.
| `WRPS_ONE_SEC` | ✅ |
| `WRPS_THIRTY_SEC` | ❌ not defined here |
| `WRPS_ONE_MIN` | — not in the export |
| `FIVE_SECONDS` (binding `STN.LEVEL`, `STN.INFLOW`) | ❌ not a WRPS group at all |
**Nobody currently knows which is right.** The export is dated a day before these
files, but contains groups they do not. Resolve it by exporting from `cicore1` and
comparing — see `../../QUICKLOAD.md`.
Until then: **do not import these files onto a working server** without checking
what is already there. You may remove a group something depends on.
## Worth doing: generate these too ## Worth doing: generate these too

View file

@ -1,50 +0,0 @@
scada_tag,description,poll_group,function_code,modbus_address,data_type,access,eng_units,raw_to_eng,eng_gain,format_mask,iec_address,plc_tag,notes
PS_PU301_RUN_COMMAND,Run command,PS_STATUS_BITS,FC01,0,Boolean,Read,,value,1.0,99999,%QX0.0,PU-301,
PS_PU302_RUN_COMMAND,Run command,PS_STATUS_BITS,FC01,1,Boolean,Read,,value,1.0,99999,%QX0.1,PU-302,
PS_PU303_RUN_COMMAND,Run command,PS_STATUS_BITS,FC01,2,Boolean,Read,,value,1.0,99999,%QX0.2,PU-303,
PS_PU301_RUNNING,Running,PS_STATUS_BITS,FC01,3,Boolean,Read,,value,1.0,99999,%QX0.3,PU-301,
PS_PU302_RUNNING,Running,PS_STATUS_BITS,FC01,4,Boolean,Read,,value,1.0,99999,%QX0.4,PU-302,
PS_PU303_RUNNING,Running,PS_STATUS_BITS,FC01,5,Boolean,Read,,value,1.0,99999,%QX0.5,PU-303,
PS_PU301_AVAILABLE,Available,PS_STATUS_BITS,FC01,6,Boolean,Read,,value,1.0,99999,%QX0.6,PU-301,
PS_PU302_AVAILABLE,Available,PS_STATUS_BITS,FC01,7,Boolean,Read,,value,1.0,99999,%QX0.7,PU-302,
PS_PU303_AVAILABLE,Available,PS_STATUS_BITS,FC01,8,Boolean,Read,,value,1.0,99999,%QX1.0,PU-303,
PS_STN_STATION_IN_AUTO,Station in auto,PS_STATUS_BITS,FC01,9,Boolean,Read,,value,1.0,99999,%QX1.1,STN,
PS_STN_HIGH_LEVEL_ALARM,High level alarm,PS_STATUS_BITS,FC01,10,Boolean,Read,,value,1.0,99999,%QX1.2,STN,
PS_STN_SPILL_ACTIVE,Spill active,PS_STATUS_BITS,FC01,11,Boolean,Read,,value,1.0,99999,%QX1.3,STN,
PS_PU301_TRIPPED,Tripped,PS_STATUS_BITS,FC01,12,Boolean,Read,,value,1.0,99999,%QX1.4,PU-301,
PS_PU302_TRIPPED,Tripped,PS_STATUS_BITS,FC01,13,Boolean,Read,,value,1.0,99999,%QX1.5,PU-302,
PS_PU303_TRIPPED,Tripped,PS_STATUS_BITS,FC01,14,Boolean,Read,,value,1.0,99999,%QX1.6,PU-303,
PS_STN_WET_WELL_LEVEL,Wet well level,PS_PUBLISHED,FC03,0,Signed 16-bit,Read,%,value / 60,0.016666666666666666,999.9,%QW0,STN,
PS_STN_INFLOW,Inflow,PS_PUBLISHED,FC03,1,Signed 16-bit,Read,m3/h,value * 0.36,0.36,9999.9,%QW1,STN,
PS_STN_TOTAL_DISCHARGE_FLOW,Total discharge flow,PS_PUBLISHED,FC03,2,Signed 16-bit,Read,m3/h,value * 0.36,0.36,9999.9,%QW2,STN,
PS_STN_PUMPS_RUNNING,Pumps running,PS_PUBLISHED,FC03,3,Signed 16-bit,Read,count,value,1.0,9,%QW3,STN,
PS_STN_COMMON_DRIVE_SPEED,Common drive speed,PS_PUBLISHED,FC03,4,Signed 16-bit,Read,%,value * 0.2,0.2,999.9,%QW4,STN,
PS_STN_TIME_TO_SPILL_WEIR,Time to spill weir (32767 = drawing down),PS_PUBLISHED,FC03,5,Signed 16-bit,Read,s,value,1.0,99999,%QW5,STN,
PS_STN_TIME_TO_LSHH,Time to LSHH (32767 = drawing down),PS_PUBLISHED,FC03,6,Signed 16-bit,Read,s,value,1.0,99999,%QW6,STN,
PS_STN_NET_ACCUMULATION,Net accumulation (signed),PS_PUBLISHED,FC03,7,Signed 16-bit,Read,m3/h,value * 0.36,0.36,9999.9,%QW7,STN,
PS_PU301_RUN_HOURS,Run hours,PS_PUBLISHED,FC03,8,Signed 16-bit,Read,h,value,1.0,99999,%QW8,PU-301,
PS_PU302_RUN_HOURS,Run hours,PS_PUBLISHED,FC03,9,Signed 16-bit,Read,h,value,1.0,99999,%QW9,PU-302,
PS_PU303_RUN_HOURS,Run hours,PS_PUBLISHED,FC03,10,Signed 16-bit,Read,h,value,1.0,99999,%QW10,PU-303,
PS_STN_VOLUME_REMAINING_TO_SPILL,Volume remaining to spill,PS_PUBLISHED,FC03,11,Signed 16-bit,Read,m3,value,1.0,9999,%QW11,STN,
PS_STN_STATION_STATE,Station state (enum 3.1),PS_PUBLISHED,FC03,12,Signed 16-bit,Read,,value,1.0,9,%QW12,STN,
PS_PU301_PUMP_STATE,Pump state (enum 3.2),PS_PUBLISHED,FC03,13,Signed 16-bit,Read,,value,1.0,9,%QW13,PU-301,
PS_PU302_PUMP_STATE,Pump state (enum 3.2),PS_PUBLISHED,FC03,14,Signed 16-bit,Read,,value,1.0,9,%QW14,PU-302,
PS_PU303_PUMP_STATE,Pump state (enum 3.2),PS_PUBLISHED,FC03,15,Signed 16-bit,Read,,value,1.0,9,%QW15,PU-303,
PS_STN_CURRENT_DUTY_PUMP,"Current duty pump (0 = none, 1-3)",PS_PUBLISHED,FC03,16,Signed 16-bit,Read,,value,1.0,9,%QW16,STN,
PS_STN_ALARM_BITMASK,Alarm bitmask (section 6) - READ AS UNSIGNED,PS_PUBLISHED,FC03,17,Unsigned 16-bit,Read,,value,1.0,99999,%QW17,STN,
PS_STN_COMMAND_ACKNOWLEDGE,Command acknowledge (echoes %MW1),PS_PUBLISHED,FC03,20,Signed 16-bit,Read,,value,1.0,99,%QW20,STN,
PS_STN_STATION_MODE_1_AUTO,"Station mode: 1 = auto, 2 = off",PS_SETPOINTS,FC03/FC06,1024,Signed 16-bit,Read/Write,,value,1.0,9,%MW0,STN,
PS_STN_COMMAND_WORD,Command word (section 3.3),PS_SETPOINTS,FC03/FC06,1025,Signed 16-bit,Read/Write,,value,1.0,99,%MW1,STN,
PS_STN_COMMAND_PARAMETER,Command parameter (pump number),PS_SETPOINTS,FC03/FC06,1026,Signed 16-bit,Read/Write,,value,1.0,9,%MW2,STN,
PS_STN_LEVEL_CONTROL_SETPOINT,Level control setpoint,PS_SETPOINTS,FC03/FC06,1027,Signed 16-bit,Read/Write,%,value / 60,0.016666666666666666,999.9,%MW3,STN,
PS_STN_START_DUTY_LEVEL,Start duty level,PS_SETPOINTS,FC03/FC06,1028,Signed 16-bit,Read/Write,%,value / 60,0.016666666666666666,999.9,%MW4,STN,
PS_STN_START_PUMP_2_LEVEL,Start pump 2 level,PS_SETPOINTS,FC03/FC06,1029,Signed 16-bit,Read/Write,%,value / 60,0.016666666666666666,999.9,%MW5,STN,
PS_STN_START_PUMP_3_LEVEL,Start pump 3 level,PS_SETPOINTS,FC03/FC06,1030,Signed 16-bit,Read/Write,%,value / 60,0.016666666666666666,999.9,%MW6,STN,
PS_STN_STOP_ALL_LEVEL,Stop all level,PS_SETPOINTS,FC03/FC06,1031,Signed 16-bit,Read/Write,%,value / 60,0.016666666666666666,999.9,%MW7,STN,
PS_STN_HIGH_LEVEL_ALARM,High level alarm,PS_SETPOINTS,FC03/FC06,1032,Signed 16-bit,Read/Write,%,value / 60,0.016666666666666666,999.9,%MW8,STN,
PS_STN_MINIMUM_DRIVE_SPEED,Minimum drive speed,PS_SETPOINTS,FC03/FC06,1033,Signed 16-bit,Read/Write,%,value * 0.2,0.2,999.9,%MW9,STN,
PS_STN_SERVICE_INTERVAL,Service interval,PS_SETPOINTS,FC03/FC06,1034,Signed 16-bit,Read/Write,h,value,1.0,99999,%MW10,STN,
PS_SIM_MANUAL_INFLOW,manual inflow (mode 0),PS_SIM_CONTROL,FC03/FC06,1044,Signed 16-bit,Read/Write,m3/h,value * 0.36,0.36,9999.9,%MW20,SIM,SIMULATION CONTROL - simulation build only
PS_SIM_SCENARIO_0_MAN_1_DIURNAL_2_W,scenario 0=man 1=diurnal 2=wet 3=ref,PS_SIM_CONTROL,FC03/FC06,1045,Signed 16-bit,Read/Write,,value,1.0,9,%MW21,SIM,SIMULATION CONTROL - simulation build only
PS_SIM_WRITE_1_TO_RESET_SCENARIO,"write 1 to reset scenario, self-clearing",PS_SIM_CONTROL,FC03/FC06,1046,Signed 16-bit,Read/Write,,value,1.0,9,%MW22,SIM,SIMULATION CONTROL - simulation build only
PS_SIM_TIME_SCALE_1_120,time scale 1-120,PS_SIM_CONTROL,FC03/FC06,1047,Signed 16-bit,Read/Write,x,value,1.0,999,%MW23,SIM,SIMULATION CONTROL - simulation build only
1 scada_tag description poll_group function_code modbus_address data_type access eng_units raw_to_eng eng_gain format_mask iec_address plc_tag notes
2 PS_PU301_RUN_COMMAND Run command PS_STATUS_BITS FC01 0 Boolean Read value 1.0 99999 %QX0.0 PU-301
3 PS_PU302_RUN_COMMAND Run command PS_STATUS_BITS FC01 1 Boolean Read value 1.0 99999 %QX0.1 PU-302
4 PS_PU303_RUN_COMMAND Run command PS_STATUS_BITS FC01 2 Boolean Read value 1.0 99999 %QX0.2 PU-303
5 PS_PU301_RUNNING Running PS_STATUS_BITS FC01 3 Boolean Read value 1.0 99999 %QX0.3 PU-301
6 PS_PU302_RUNNING Running PS_STATUS_BITS FC01 4 Boolean Read value 1.0 99999 %QX0.4 PU-302
7 PS_PU303_RUNNING Running PS_STATUS_BITS FC01 5 Boolean Read value 1.0 99999 %QX0.5 PU-303
8 PS_PU301_AVAILABLE Available PS_STATUS_BITS FC01 6 Boolean Read value 1.0 99999 %QX0.6 PU-301
9 PS_PU302_AVAILABLE Available PS_STATUS_BITS FC01 7 Boolean Read value 1.0 99999 %QX0.7 PU-302
10 PS_PU303_AVAILABLE Available PS_STATUS_BITS FC01 8 Boolean Read value 1.0 99999 %QX1.0 PU-303
11 PS_STN_STATION_IN_AUTO Station in auto PS_STATUS_BITS FC01 9 Boolean Read value 1.0 99999 %QX1.1 STN
12 PS_STN_HIGH_LEVEL_ALARM High level alarm PS_STATUS_BITS FC01 10 Boolean Read value 1.0 99999 %QX1.2 STN
13 PS_STN_SPILL_ACTIVE Spill active PS_STATUS_BITS FC01 11 Boolean Read value 1.0 99999 %QX1.3 STN
14 PS_PU301_TRIPPED Tripped PS_STATUS_BITS FC01 12 Boolean Read value 1.0 99999 %QX1.4 PU-301
15 PS_PU302_TRIPPED Tripped PS_STATUS_BITS FC01 13 Boolean Read value 1.0 99999 %QX1.5 PU-302
16 PS_PU303_TRIPPED Tripped PS_STATUS_BITS FC01 14 Boolean Read value 1.0 99999 %QX1.6 PU-303
17 PS_STN_WET_WELL_LEVEL Wet well level PS_PUBLISHED FC03 0 Signed 16-bit Read % value / 60 0.016666666666666666 999.9 %QW0 STN
18 PS_STN_INFLOW Inflow PS_PUBLISHED FC03 1 Signed 16-bit Read m3/h value * 0.36 0.36 9999.9 %QW1 STN
19 PS_STN_TOTAL_DISCHARGE_FLOW Total discharge flow PS_PUBLISHED FC03 2 Signed 16-bit Read m3/h value * 0.36 0.36 9999.9 %QW2 STN
20 PS_STN_PUMPS_RUNNING Pumps running PS_PUBLISHED FC03 3 Signed 16-bit Read count value 1.0 9 %QW3 STN
21 PS_STN_COMMON_DRIVE_SPEED Common drive speed PS_PUBLISHED FC03 4 Signed 16-bit Read % value * 0.2 0.2 999.9 %QW4 STN
22 PS_STN_TIME_TO_SPILL_WEIR Time to spill weir (32767 = drawing down) PS_PUBLISHED FC03 5 Signed 16-bit Read s value 1.0 99999 %QW5 STN
23 PS_STN_TIME_TO_LSHH Time to LSHH (32767 = drawing down) PS_PUBLISHED FC03 6 Signed 16-bit Read s value 1.0 99999 %QW6 STN
24 PS_STN_NET_ACCUMULATION Net accumulation (signed) PS_PUBLISHED FC03 7 Signed 16-bit Read m3/h value * 0.36 0.36 9999.9 %QW7 STN
25 PS_PU301_RUN_HOURS Run hours PS_PUBLISHED FC03 8 Signed 16-bit Read h value 1.0 99999 %QW8 PU-301
26 PS_PU302_RUN_HOURS Run hours PS_PUBLISHED FC03 9 Signed 16-bit Read h value 1.0 99999 %QW9 PU-302
27 PS_PU303_RUN_HOURS Run hours PS_PUBLISHED FC03 10 Signed 16-bit Read h value 1.0 99999 %QW10 PU-303
28 PS_STN_VOLUME_REMAINING_TO_SPILL Volume remaining to spill PS_PUBLISHED FC03 11 Signed 16-bit Read m3 value 1.0 9999 %QW11 STN
29 PS_STN_STATION_STATE Station state (enum 3.1) PS_PUBLISHED FC03 12 Signed 16-bit Read value 1.0 9 %QW12 STN
30 PS_PU301_PUMP_STATE Pump state (enum 3.2) PS_PUBLISHED FC03 13 Signed 16-bit Read value 1.0 9 %QW13 PU-301
31 PS_PU302_PUMP_STATE Pump state (enum 3.2) PS_PUBLISHED FC03 14 Signed 16-bit Read value 1.0 9 %QW14 PU-302
32 PS_PU303_PUMP_STATE Pump state (enum 3.2) PS_PUBLISHED FC03 15 Signed 16-bit Read value 1.0 9 %QW15 PU-303
33 PS_STN_CURRENT_DUTY_PUMP Current duty pump (0 = none, 1-3) PS_PUBLISHED FC03 16 Signed 16-bit Read value 1.0 9 %QW16 STN
34 PS_STN_ALARM_BITMASK Alarm bitmask (section 6) - READ AS UNSIGNED PS_PUBLISHED FC03 17 Unsigned 16-bit Read value 1.0 99999 %QW17 STN
35 PS_STN_COMMAND_ACKNOWLEDGE Command acknowledge (echoes %MW1) PS_PUBLISHED FC03 20 Signed 16-bit Read value 1.0 99 %QW20 STN
36 PS_STN_STATION_MODE_1_AUTO Station mode: 1 = auto, 2 = off PS_SETPOINTS FC03/FC06 1024 Signed 16-bit Read/Write value 1.0 9 %MW0 STN
37 PS_STN_COMMAND_WORD Command word (section 3.3) PS_SETPOINTS FC03/FC06 1025 Signed 16-bit Read/Write value 1.0 99 %MW1 STN
38 PS_STN_COMMAND_PARAMETER Command parameter (pump number) PS_SETPOINTS FC03/FC06 1026 Signed 16-bit Read/Write value 1.0 9 %MW2 STN
39 PS_STN_LEVEL_CONTROL_SETPOINT Level control setpoint PS_SETPOINTS FC03/FC06 1027 Signed 16-bit Read/Write % value / 60 0.016666666666666666 999.9 %MW3 STN
40 PS_STN_START_DUTY_LEVEL Start duty level PS_SETPOINTS FC03/FC06 1028 Signed 16-bit Read/Write % value / 60 0.016666666666666666 999.9 %MW4 STN
41 PS_STN_START_PUMP_2_LEVEL Start pump 2 level PS_SETPOINTS FC03/FC06 1029 Signed 16-bit Read/Write % value / 60 0.016666666666666666 999.9 %MW5 STN
42 PS_STN_START_PUMP_3_LEVEL Start pump 3 level PS_SETPOINTS FC03/FC06 1030 Signed 16-bit Read/Write % value / 60 0.016666666666666666 999.9 %MW6 STN
43 PS_STN_STOP_ALL_LEVEL Stop all level PS_SETPOINTS FC03/FC06 1031 Signed 16-bit Read/Write % value / 60 0.016666666666666666 999.9 %MW7 STN
44 PS_STN_HIGH_LEVEL_ALARM High level alarm PS_SETPOINTS FC03/FC06 1032 Signed 16-bit Read/Write % value / 60 0.016666666666666666 999.9 %MW8 STN
45 PS_STN_MINIMUM_DRIVE_SPEED Minimum drive speed PS_SETPOINTS FC03/FC06 1033 Signed 16-bit Read/Write % value * 0.2 0.2 999.9 %MW9 STN
46 PS_STN_SERVICE_INTERVAL Service interval PS_SETPOINTS FC03/FC06 1034 Signed 16-bit Read/Write h value 1.0 99999 %MW10 STN
47 PS_SIM_MANUAL_INFLOW manual inflow (mode 0) PS_SIM_CONTROL FC03/FC06 1044 Signed 16-bit Read/Write m3/h value * 0.36 0.36 9999.9 %MW20 SIM SIMULATION CONTROL - simulation build only
48 PS_SIM_SCENARIO_0_MAN_1_DIURNAL_2_W scenario 0=man 1=diurnal 2=wet 3=ref PS_SIM_CONTROL FC03/FC06 1045 Signed 16-bit Read/Write value 1.0 9 %MW21 SIM SIMULATION CONTROL - simulation build only
49 PS_SIM_WRITE_1_TO_RESET_SCENARIO write 1 to reset scenario, self-clearing PS_SIM_CONTROL FC03/FC06 1046 Signed 16-bit Read/Write value 1.0 9 %MW22 SIM SIMULATION CONTROL - simulation build only
50 PS_SIM_TIME_SCALE_1_120 time scale 1-120 PS_SIM_CONTROL FC03/FC06 1047 Signed 16-bit Read/Write x value 1.0 999 %MW23 SIM SIMULATION CONTROL - simulation build only