HEART Embedded Systems logoHEART

Guide 7: A HEART-Embedded water pump station#

Reading tracks1 Basic3 Advanced
Basic: monitoring a PLC, HEART Basic, A1. Advanced readers building machines (Stop 3C) read it too. Which track am I?

A case study. A water utility runs pump stations that lift water from a river intake to a reservoir on the hill, which feeds a town. Each station has two pumps and a PLC that runs them. The utility wants every station to be a HEART-embedded system: it should know when it is unwell, say so in one standard language, explain what is wrong, tell the on-call operator, and never leak anything it should not. This guide goes step by step from day 1 to a station that can claim HEART Basic, Autonomy Level A1, and shows how an owner registers it and watches it on HEART Hub.

A working demo comes with it: pumpStationSimulator/, one Python file that simulates a town, a river, a station, its PLC and its HEART, and reports to https://heartcortex.ai.

Status. A design case study with a simulator. No real station, PLC or utility was involved. The town, the river, the pumps, the PLC and its register map are all simulated; the numbers are plausible, not engineering data. A real station's controls and safety functions are designed and certified under their own standards.


Before you start: the PLC runs the station, HEART watches it#

A pump station's job, keeping the reservoir supplied by starting and stopping pumps, and protecting them when something goes wrong, belongs to the PLC and its interlocks. They are in the control loop and in the safety chain. HEART stays out of both.

Stays in the PLC, its program and any safety relaysGoes to HEART
Starting and stopping pumps on reservoir levelKnowing whether the station can actually pump
Duty and standby, duty rotation, restart after a power cutWatching levels, flow, pressure, motors and power
Dry-run protection from the low-level float switchNoticing a sensor that has stopped telling the truth
The high discharge pressure trip, with a local resetRaising alerts with standard fault codes
Motor thermal tripsExplaining what is wrong and what to check
Every setpoint, which only the utility's engineers changeTelling the on-call operator, even with no internet

This is Part 6, Section 9 of the standard, and its table "Where HEART sits in a control system", applied to a station:

LayerIn a pump stationRun byHEART's role
Safety (trips, interlocks, safety PLC)Dry-run stop, high-pressure trip, thermal trips, emergency stopThe PLC and hardwired relaysNone. Read-only at most
Real-time controlStart and stop on level, duty and standby, PLC scanThe PLCNone in the loop. It may read values
SupervisionStart and stop levels, duty rotation periodOperators and engineersAdvises only, in this guide
Maintenance and diagnosisCavitation, hot motors, stuck sensors, run hoursEngineersIts main value: explains, predicts, gathers evidence

This HEART has no commands at all. Every PUT, POST, PATCH or DELETE is refused with 403 capability-not-allowed, even with the owner key. It cannot start a pump, reset a trip or change a setpoint. If HEART crashes, is removed or is hacked, the PLC goes on running the station exactly as before (Part 6, Section 9, rules 1, 3 and 6).


Step 1: Decide where HEART runs#

A PLC is certified, deterministic and busy. It must not carry a HEART, and its program should not change for one. The usual station has room beside it:

sensors, pumps ──(wired I/O)──► PLC ──(Modbus TCP, read only)──► edge gateway ──(router)──► control room and HEART Hub
                                 runs the station                 HEART runs here
PartWhat it doesHEART's place
Sensors, float switch, pumps, motorsMeasure and move waterNone
PLCRuns the station and its interlocks; holds values in a Modbus register mapNone. Read only, through the Modbus map it already has
Edge gateway (an industrial Linux box in the panel, next to the PLC)Polls the PLC, serves the HEART API on the station networkRuns the HEART: for example heartd from heart-core-rs, with its Modbus TCP adapter (heart-core-rs/examples/pump-station is a complete configuration), class Core-M
RouterThe telemetry link to the control roomCarries HEART's reports and escalations
Control room SCADAOperators watch every stationReads the HEART API; receives escalations

So the HEART-embedded system is the station as seen by its gateway. The gateway adds no new path into the PLC: it uses only the read functions of the Modbus map (input registers and discrete inputs), and the PLC's Modbus server, or a firewall in front of it, should accept nothing else from the gateway's address.

What a real station needs that the simulator does not have. The simulator reads the map straight from the simulation. A real gateway needs a Modbus TCP client. heartd's adapter today reads holding registers (function 3) and writes one register (function 6); for a read-only map in input registers and discrete inputs, either have the PLC mirror the values into a block of holding registers, or add functions 2 and 4 to the adapter. Leave out heartd's command definitions (custom/set-flow.json in the example) for a monitoring-only station.


Step 2: Give the system an identity#

The gateway's HEART serves a Card at /.well-known/heart-card.json:

{ "system": { "id": "org.example.water.pump-station", "name": "Hill Road pump station", "version": "1.0.0" },
  "level": "basic", "bindings": ["http-server"], "pulse": { "intervalSec": 30 },
  "modules": ["properties"], "shares": { "pulse": "public", "arrhythmia": "public", "property": "internal" },
  "autonomy": { "level": 1 }, "template": "heart/embeddedstandard/python/v1.2611.2" }

The simulator's system ID is org.heartaispec.demo.pump-station. The device ID used by HEART Hub (Step 8) is random: it does not reveal the station's name or place.


Step 3: List what the system knows, and how private each item is#

Nothing in a pump station is personal, but almost all of it is operational: where the station is weak, when it is down and how long the town can last are things an attacker would like to know. Decide every value's level before writing code.

ValueSourcePrivacyWhy
Healthy or not; open fault codesDerived by HEARTpublicThe only things HEART Hub ever receives (Step 8)
Sump and reservoir levelsPLC (input registers 0, 1)internalFor the operators
Station flow, outflow to the townPLC (input registers 2, 16)internalReveals the town's demand pattern
Discharge pressurePLC (input register 3)internal
Motor current, winding temperature, vibration, run hours per pumpPLC (input registers 4 to 13)internalMaintenance
Mains voltage, UPS charge and statePLC (input registers 14, 17; discrete input 3)internalReveals when the station is vulnerable
Pump running states, float switch, trip and status bitsPLC (discrete inputs 0 to 4; input register 15)internal
The PLC's event log: starts, stops, trips, resetsPLCinternal
Operator names, call-out rosters, customer accountsUtility systemsnot on the gatewayThe HEART does not need them, so it never has them

Nothing is private, because nothing is personal. The full register map, with 0-based addresses as sent on the wire, table by table, is in the simulator's README, Section 5.


Step 4: Say what "doing its main job" means#

The main job of a pump station is: when the town needs water, the station can pump it. The gateway's HEART checks this from the PLC's values:

def check_main_function(r):
    """CHANGE: return (True, "") if the station can pump, else (False, "what is wrong, in plain words")."""
    if r.available == 0:                       # pumps not tripped, not locked out, with mains
        return False, f"{r.why_lost()}. About {r.hours_left:.1f} h of supply left in the reservoir."
    if r.call and r.n == 0:                    # the PLC calls for water, nothing runs
        return False, "The PLC is calling for water but no pump is running."
    return True, ""

A pump is available when the PLC has not tripped it, the station is not locked out, the sump is not at its dry-run level and mains power is on. The main job is degraded when a pump runs but delivers less than three quarters of its commissioned flow while vibrating hard: the signature of cavitation.

A condition must hold for a few seconds before it is raised, because one odd reading is not a fault.


Step 5: The faults it recognises#

Every alert carries a fault code from Part 3, Section 5.4, so the gateway, the control room and any monitor site read it the same way.

What happensFault codeSeverityStatus of the system
No pump available (tripped, locked out, dry-run, no mains), or the PLC calls and nothing runssystem.main-function-lostcriticalfailing
A pump runs with vibration above 7.1 mm/s and flow below 75 % of its commissioned flow (likely cavitation)system.main-function-degradedwarningdegraded
The sump level transmitter has not changed for 90 s while water movessensors.stuckwarningdegraded
A motor winding at 100 Cel or more (the PLC trips at 120)performance.too-hotwarningdegraded
Mains supply lost: PLC and gateway on the UPSpower.supply-losterrordegraded
The telemetry link to the control room is downconnectivity.link-lostwarningdegraded
The PLC stops answering the gatewayconnectivity.dependency-unreachableerrordegraded (a real gateway should add this; the simulator cannot lose its PLC)
Gateway silent for three Pulse intervalssystem.flatlineraised by HEART Hub

HEART's thresholds sit below the PLC's trips on purpose: a person hears that a motor is hot before the PLC stops it, and the PLC stops it whether or not HEART is there. The numbers are illustrations; a real station takes them from its pumps' commissioning curves, the vibration limits for its machines (ISO 10816 or ISO 20816) and the motor maker's data.

A stuck sensor teaches the split. When the level transmitter sticks, HEART says "do not trust it", and marks the sump_level property "quality": "bad". It does not try to protect the pumps: the PLC's dry-run protection comes from its own hardwired float switch, not from the transmitter HEART watches.


Step 6: No commands, and why there is no Stop button#

The HEART has no capabilities: the Card lists none, and every change request is refused with 403 capability-not-allowed. Starting a pump, resetting a trip and changing a setpoint stay with the PLC and the people at the station. A high-pressure trip needs a local reset on purpose: someone must go and find the shut valve.

The standard requires a Stop control only from Autonomy Level A3 up, because A1 and A2 take no action and so have nothing to stop. The station's emergency stop is a hardwired safety function, not a HEART control.


Step 7: Tell a person#

Autonomy Level A1 needs an escalation route. For a pump station there are two, and both are needed:

  1. The utility's own route: an alarm in the control room's SCADA, and a page to the on-call operator.
  2. Locally, with no network: the station's alarm lamp, so a crew on site sees it.

Change escalate() to use them. The explanation tells the operator what to do first: for a lost main function it gives the town's draw and the hours of supply left in the reservoir, so the operator knows how urgent the call-out is.

When the telemetry link is down, the lamp is the only route, and alerts wait on the gateway until the link returns. HEART Hub (Step 8) adds one more: an email when the station goes silent.


Step 8: Register and watch it on HEART Hub#

HEART Hub lets an owner see a station's health from anywhere, on a private page.

  1. First start. The gateway makes a random device ID, claim code and key, keeps them, and shows the claim code only to the person holding it: on a label inside the panel door, or on its console.
  2. Sign in. The owner opens https://heartcortex.ai/login and enters an email address. A 6-digit code arrives; there are no passwords.
  3. Register. At https://heartcortex.ai/register?id=<device ID> (a QR code on the label can open it), the owner enters the claim code. Holding the device is the proof of ownership.
  4. Watch. The station's page, https://heartcortex.ai/device/<device ID>, shows its status and open alerts, private to the owner until they share it.
  5. Silence. If no report arrives for three Pulse intervals, the page shows a Flatline and the owner gets one email. Reports go out through the station's router, so a lost telemetry link shows as a Flatline too.

Only the public Pulse and public alerts are sent, and the site keeps only the status, timing and fault codes: never a level, a flow, a pressure or a PLC event.

Warning for a real utility. Even "this station has lost its main function" tells someone when a town's water is vulnerable. A utility should run its own monitor site (the code is open, in heart-monitor/), inside its own network security rules (for example IEC 62443 zones and conduits), rather than send a station's alerts to a public site. heartcortex.ai is right for the simulator and for trials, not for live plant.


Step 9: Try it with the simulator#

python3 pumpStationSimulator/pumpStationSimulator.py --scenario all

It prints a device ID and claim code; register them as in Step 8 and watch the page while it stages each fault in turn:

ScenarioWhat happensCode
stuckThe sump level transmitter freezessensors.stuck
linkThe telemetry router drops out, and so do the reportsconnectivity.link-lost
cavitationThe suction strainer blocks: flow down, vibration upsystem.main-function-degraded
hotPump 1's cooling fan is blocked; HEART warns, then the PLC trips the pump and starts pump 2performance.too-hot
tripA valve is shut by mistake; the PLC trips both pumps on high pressure while the town keeps drawingsystem.main-function-lost
powerMains is lost; the PLC and gateway run on the UPSpower.supply-lost, system.main-function-lost

Each fault is "fixed by the maintenance crew" a few minutes later, so you can watch alerts open, escalate and resolve. With the owner key, /heart/v1/plc-events shows what the PLC did meanwhile: trips, duty changes, restarts. Details and every option are in pumpStationSimulator/README.md.


Step 10: Test it, rate it and claim only what passed#

  1. Run the HEART-Rating client (heart-rating/client/heart_rating.py) against the gateway, and the hands-on tests of Part 9: cause each fault in the table of Step 5 with a PLC simulator or on a test rig, cut the internet, cut the telemetry link, stop the PLC, pull the gateway's power and check the station carries on.
  2. Publish a Declaration with every result.
  3. Claim HEART Basic, Autonomy Level A1.
LevelFits a pump station?
A1 (notices and tells a person)Yes: this guide
A2 (says why, with a confidence)Yes, at HEART Connected, with Rhythm events as evidence: "flow fell from 300 to 175 m3/h and vibration rose from 2.2 to 9.4 mm/s within a minute, with the sump level normal: likely a blocked suction strainer, confidence medium"
A3 (suggests a fix and waits for a yes)Only at HEART Full, with approval and Stop, and only for what is in the supervision layer: for example "make pump 2 duty until pump 1's bearing is checked", which a person at the station approves, and which the PLC still accepts or refuses with its own interlocks. Physical changes always need a person present (Part 6). Resetting a trip stays local
A4 (fixes known problems by itself)Only for the gateway's own housekeeping, with adopted Playbooks and an allowlist entry for rule for each: for example "telemetry link lost: send reports through the backup cellular modem", or "PLC not answering: reconnect the Modbus client". Never a pump, a trip or a setpoint
A5 (learns)Needs the ai and evolving modules: for example a model that learns each pump's normal flow and vibration and predicts bearing wear. It still only suggests

HEART conformance says nothing about the safety or security of the station. The PLC program, the safety functions and the network still need their own work (for example IEC 61508 or IEC 61511 for safety functions, IEC 62443 for industrial security, and the utility's own regulator).


What the case study shows#

  • A HEART with no commands is still useful. In a station run by a PLC, the value is noticing, explaining and telling the right person in one standard way: cavitation, a hot motor or a stuck sensor reach an engineer before they become a trip.
  • Where HEART lives is a design decision. It lives on a gateway beside the PLC, reads the map the PLC already has, and adds no path into it.
  • The interlocks stay where they are. HEART's thresholds sit below the PLC's trips, and the PLC trips whether or not HEART is there.
  • "Internal" is the default for infrastructure. Nothing here is personal, yet almost nothing is public: status and fault codes only, and a utility runs its own monitor site.