Commit graph

15 commits

Author SHA1 Message Date
5be48b6bbb fix: CI Server on cicore1 is R1.05, not R1.03
Corrected in README.md, CLAUDE.md, 02-environment/README.md and
03-plc/VERSIONS.md.

The @VERSION 1.03.00 header inside the .qli files is the quickload FILE
FORMAT version, not the CI Server release. Left alone.

This also sharpens a caveat that was previously stated wrongly. The
EQP-E-DUP_ITEM rejection - an item import fails if two items share an
IO_ADDRESS - was observed on 2026-08-14 on the DEVELOPMENT machine, which
ran R1.03. Production runs R1.05, where it has never been tested. The
design still works around it by publishing level and speed in % only, and
that workaround costs nothing; but anyone wanting a second unit for a
measurement should try it on R1.05 before assuming they need a second PLC
register to carry it.
2026-09-02 17:34:58 +10:00
a042b7936f docs: CLAUDE.md, rewritten for the production environment
Replaces the dev-era file entirely. The old one described PXiSEDev and
dev-ubuntu on 192.168.153.0/24, a runtime reachable only through an SSH
tunnel, a docker-compose.yml in a folder that no longer exists, and a
pending R1.03-to-R1.05 migration. None of that is true any more.

Kept: the working protocol - state the plan and its acceptance test, make
the minimal change, show the evidence, wait for confirmation, commit. It
is the reason this project has evidence behind its claims.

Changed in substance:

  - the shared-host warning is now prominent. yau-sls-poc-lin001 runs ~28
    containers for other projects and serves customer-facing demos; this
    project owns one of them.
  - a section of non-obvious truths, each of which produces plausible
    wrong answers rather than errors: %MW at HR 1024, %QW17 unsigned, all
    %IW reading 0 by design, port 502 needing a running program, STruC++
    living only inside the Editor GUI, an item import killing every
    display, PS_ naming only poll groups.
  - guardrails rewritten around what is now live: the container is live
    control with CI Server polling it, and %MW writes are real commands.
  - a 'verification, not assertion' section. The user is auditing this
    work; read the live system rather than inferring it, prove
    regenerations still reproduce, and label anything about CI Server as
    belief - that machine is not reachable from here.
  - open items stated so they are not presented as solved.

Points at the detailed documents rather than restating them.
2026-09-02 17:32:51 +10:00
a7db705399 docs: top-level README
The old repo had no landing page at all - a reader arriving on the git
server saw a folder listing and CLAUDE.md, which is written for an agent.

Leads with what the repo is, that the demo is live, and that the pump
station is fiction generated from a one-page idea. Then the two machines,
the architecture invariant, and the generation chain, which is the spine
of the whole thing.

Two tables aimed at the team this is being handed to:

  'Where to start'  - one row per question someone actually arrives with
  'What to reuse'   - reuse as-is / adapt per demo / WRPS-only, so the
                      next demo does not start by guessing which parts
                      are method and which are this example

Open items are on the front page rather than buried: no acceptance tests
have been run, there is no deployment toolchain, CI Server state is
unverified, the historian has drifted, the runtime image is
irreplaceable, and live setpoint tuning is not in the repo.

Closes with what was verified against the running systems on 2026-09-02,
so the claims above are traceable rather than asserted.
2026-09-02 17:29:30 +10:00
bed824a9a5 test: Modbus verification harness
The old 06-tests, with paths retargeted and both tools proven to run.

Verified end to end during the move - fake_plc.py served on a spare port
and verify_modbus.py read it:

    read     : 69/69 points OK
    writable : 15/15 RW points OK
    PASS     : the runtime matches the register map

fake_plc.py --expect was BROKEN by the PS_* removal in the previous
commit: it fell back to the scada_tag column, which no longer exists, and
died with KeyError. It now uses ci_item, so the names it prints are the
CI Server items an operator actually sees. Regenerated
expected_readings.txt; fake_values.json came back byte-identical, which
confirms the seed really is deterministic as the docstring claims.

README corrections:
  - default host was dev-ubuntu; now 10.0.0.17, with the container
    fallback for when that address is not routable
  - said 11 RW points; there are 15 (11 control + 4 simulation)
  - the 'reading the output' section described the FIELD build - tripped
    pumps, alarm word 16500, seeded %MW defaults - as though it were what
    you would see. The deployed PLC runs the SIMULATION build. Both are
    now shown side by side, with the simulation column marked as the one
    that is live.
  - says plainly that none of the 20 acceptance tests are implemented
    here: this harness verifies the contract, not the behaviour
  - adds a caution against running fake_plc.py on port 502 of the live
    host, where the real PLC is serving and CI Server is polling
2026-09-02 17:27:30 +10:00
2b8f88d01f feat(env): hosts, access, ports and the PLC container
02-environment merges the old 02-env and 03-containers - both answered the
same question, 'where does this run and how do I reach it', and were split
for no reason.

  README.md              the two hosts, access, ports, secrets, health
                         checks, known issues
  YAU_Linux_Host_Onboarding.md  the Linux host's own brief, copied with a
                         provenance banner: owned by the host owner, not
                         maintained here, and its 'save this as CLAUDE.md'
                         instruction does not apply in this repo
  openplc-container.md   the container as read from the running host
  openplc-compose.yml    verbatim copy of the live file
  MIGRATION.md           moving the container - as-built plus runbook
  secrets.local.md.template  the shape of the git-ignored secrets file

The README leads with the fact that shapes every decision on that machine:
yau-sls-poc-lin001 is a SHARED, LIVE host running ~28 containers for
several projects behind Caddy and Authelia, and this project owns exactly
one of them. Never restart Caddy or Authelia, never publish on 0.0.0.0,
never put growing data on the 62 GB root disk.

Records four known issues rather than leaving them in anyone's head: the
100 ms scan overruns, the 354 MB migration tarballs still sitting on the
host with the JWT secret inside one of them, the runtime image existing in
no registry, and the missing Editor toolchain.

Not carried across: Host_Documentation.md. ~400 lines on ChirpStack,
Forgejo, EQP licensing and the Telegraf fleet - none of it WRPS, owned
elsewhere, and a stale copy here would be worse than a pointer.
2026-09-02 17:24:09 +10:00
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
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
0bbff348f8 docs(plc): architecture overview
The folder described behaviour and listed points, but nothing showed the
shape of the program. ARCHITECTURE.md covers what a reader needs before
opening any ST file:

  - counts up front: 4 function blocks, 3 programs, 1 task, 69 located
    variables, 65 process globals, 69 Modbus points, 1 comms interface
  - the one architectural rule - only 10_globals.st and 50_prog_io_mux.st
    may touch located variables, enforced by build.py - and why it is what
    lets identical control logic run against a simulation or a real plant
  - a layer diagram: Modbus slave / IO_MUX / CONTROL + its four FBs /
    SIMULATION, with the direction of every flow
  - what each of the 10 source files owns, with line counts
  - execution order per build, and why SIMULATION runs first
  - the 100 ms task interval is not independently adjustable: four POUs
    integrate against a hardcoded SCAN_S := 0.1
  - one comms interface, which is a runtime plugin rather than program
    code - the reason 502 can be published and still refuse connections
  - the 69 points by function code, with the %MW HR1024 warning
2026-09-02 16:51:45 +10:00
55279ca78f docs(plc): as-built copy, versions, and a getting-started guide
Adds what the folder was missing for someone picking it up cold.

as-built/  the STruC++ output copied out of the live container - the C++
           the PLC is actually executing, plus program.st and the Modbus
           buffer config. The running image was made with docker commit
           and exists in no registry, so this is the only other copy of
           the compiled form.

           Verified while copying: the deployed program.st matches
           build/wrps.st generated from src/. Identical POU structure,
           ZERO differences in non-declaration lines. src/ is genuinely
           canonical and the running PLC agrees with it.

VERSIONS.md         every version read from the running system, not from
                    documentation: runtime v4.1.10, STruC++ 0.6.2, Editor
                    4.2.11, Debian 12, g++ 12.2, pymodbus 3.11.2, CI
                    Server R1.03. Plus which plugins are enabled -
                    ethercat is on for no reason - and a v3-vs-v4 table,
                    since most OpenPLC guidance online is for v3 and the
                    %MW HR1024 change silently produces wrong data.

GETTING-STARTED.md  three questions answered in a page: how to modify the
                    program, how to stand up a new PLC container from
                    scratch, how to move this one. Includes the compose
                    file, the Editor steps that are not generated and are
                    always missed, and a symptom-to-document table.
2026-09-02 16:48:30 +10:00
13a05d0135 feat(plc): ST sources, generators and the Modbus contract
The PLC program from the old repo's 04-plc/, flattened into one folder and
checked against the running system.

Verified during the move:
  - build.py regenerates register-map.csv byte-identically (69 points)
  - polled the live PLC: the SIMULATION build is what is deployed and
    running, %MW21=2 wet weather, values moving, run hours accumulating
  - addresses, %MW HR1024 segmentation and %QW17/%QW7 signedness all
    match the map

Corrections against the old repo:
  - 10_globals.st header cited WRPS-CTL-002 (the FDS); it means CTL-003
  - build.py wrote the map to its parent directory; now beside itself
  - deploy/README.md was a single-file folder; now DEPLOY.md
  - dropped the empty editor-devices/remote/
  - README no longer claims the simulation build is uncompiled - it is
    the one running

Two open items are now stated plainly rather than buried:
  - none of the 20 acceptance tests in CTL-003 have ever been run
  - the OpenPLC Editor lived only on the retired dev-ubuntu host, so
    there is currently NO route to deploy a new program (DEPLOY.md 0)

Documents the setpoint distinction: IO_MUX seeds %MW defaults once at
first scan, operators retune them live, and that tuning exists only in
the container volume - a restart reverts it.
2026-09-02 15:48:49 +10:00
f6b32b42a1 docs(design): design set, with its origin and the method that made it
The five design documents plus the implementation brief, brought across
as issued. Adds two things the old repo never recorded:

  00-origin/  the one-page idea the whole document set was generated from
  README.md   how the set was produced - idea -> basic design -> detailed
              design -> implementation brief - so the team can repeat the
              method for their own demos, including what to do differently

CTL-003 gains a dated amendment block. Its section 2 register map was
verified line by line against register-map.csv and is correct; its
sections 1 and 9 specify a MatIEC flat-file build that does not exist on
Runtime v4, and forbid the PLCopen route actually used. Nine corrections
listed, body unchanged.

Not brought across: superseded/WRPS-CTL-002_OpenPLC_Build_Brief.md - dead,
and its number collides with the live FDS.
2026-09-02 15:25:54 +10:00
4fc5f80b21 chore: preserve reference files byte-for-byte
.gitattributes normalised the CI Server exports under 99-reference/ to LF.
They are a format specification and must match what CI Server actually
wrote, so mark the folder -text and restore the originals.
2026-09-02 15:17:49 +10:00
e60e8d3e60 docs(reference): worked CI Server examples, trimmed 138 MB to 5 MB
CI Server publishes no file-format documentation, so real .qli exports and a
real HMI deployment are the only specification the .qli and display generators
were written against. Kept the parts that carry that knowledge:

  ciserver-qli-exports/     10 exports - the .qli format
  ciserver-hmi-deployment/  components, layouts, thresholds, locales
                            + 6 of 84 displays

Dropped symbols/ (107 MB - CI Server's own installed library, already on
cicore1), the colour-variant displays, editor lock/autosave artefacts, and the
stock OpenPLC sample projects.
2026-09-02 15:16:56 +10:00
392f06dbef chore: normalise line endings to LF 2026-09-02 15:07:38 +10:00
4431d6bb59 chore: initialise wrps-demo-kit
Blank starting point for the CI Server + OpenPLC demo kit. Content is
brought across from the earlier WRPS working repo folder by folder, as
each part is audited.
2026-09-02 15:07:31 +10:00