1Purpose
This application note describes a development methodology in which an AI coding agent performs the complete control-program lifecycle for an EQSP32-based industrial controller (specification, implementation, build, download, test, debugging and reporting) without an engineer writing or even viewing a line of code during the process.
The method is demonstrated end to end using a real worked example: the control application for a single-pass reverse-osmosis (RO) water-treatment skid. The agent was given only a wiring diagram, a process (P&ID-style) diagram, and a short natural-language prompt, from which it developed a formal control specification for the engineer to review and approve. From that approved specification it produced a hardware-in-the-loop (HIL) test plan covering 31 test cases, a fully commented control program, and a test report documenting 31 of 31 passing checks against the real controller, in eighteen minutes of unattended operation.
The purpose of this note is threefold:
- to document the setup so the result is reproducible;
- to explain the HIL principle that makes unattended validation trustworthy rather than merely impressive;
- to describe how the same technique extends beyond physical I/O to fieldbus and IoT communication, where an agent can verify that a device behaves correctly as a network peer, not only as a set of pins.
2Hardware Setup
The worked example is a real industrial control problem: a single-pass RO skid with ten sensors, three actuators, eight operating states and five latched fault conditions. The complete physical layout is defined by two engineering drawings, both of which were given to the agent as the starting point for the specification (Section 4).
2.1 Process (plumbing) diagram
Feed (brackish) water is gravity-fed from a supply tank through a supply electro-valve and cartridge pre-filters to a fixed-speed high-pressure RO pump. The pump forces feed water across the RO membrane. Permeate (product water) flows to the clean-water tank; the concentrate (brine) leaves through a fixed flow restrictor that sets membrane operating pressure, then to drain. A flush valve plumbed in parallel with the restrictor allows a periodic low-pressure, high-cross-flow forward-flush of the membrane.
2.2 Controller and wiring diagram
A single EQSP32 controller handles all I/O with no external expansion. Ten inputs cover pressure (2 channels, 4-20 mA), tank depth (2 channels, 4-20 mA), TDS / water quality (2 channels, 0-5 V), a run/stop selector (digital), motor temperature (10K NTC) and two pulse-counting flow meters. Six outputs drive an RGB status LED and the three 24 V actuators (pump contactor, supply valve, flush valve).
2.3 I/O summary
| Terminal | Signal | Type |
|---|---|---|
| ADIO1 / ADIO2 | Pressure meter IN / OUT | 4-20 mA (CIN) |
| ADIO3 / ADIO4 | Depth (clean tank / supply tank) | 4-20 mA (CIN) |
| ADIO5 / ADIO6 | TDS IN / TDS OUT | 0-5 V (AIN) |
| ADIO7 | Run / Stop selector | Digital in (DIN) |
| ADIO8 | Motor temperature (10K NTC) | Thermistor in (TIN) |
| DIO9 / DIO10 | Flow meter IN / OUT | Pulse in (PCC) |
| DIO11-13 | RGB status LED (R / G / B) | Output (POUT) |
| DIO14-16 | Flush valve / pump contactor / supply valve | Output (POUT, 24 V) |
2.4 Connection to the development PC
The only physical connection between the development PC and the controller is a single USB cable, used for both downloading the compiled control program and running the HIL serial protocol described in Section 5.
No plant was connected. No physical sensors, actuators, or process plant were connected at any point during specification, development, or test. The entire validation ran against injected inputs over the USB link.
2.5 What the agent needs
The setup an agent requires to reproduce this work is deliberately minimal. In full, it is:
- The ESP32 development environment installed on the PC. The agent drives it from the command line to compile the program and download it to the unit; no IDE window is opened at any point.
- A single EQSP32 unit, with nothing connected to it. No sensors, no actuators, no external power supply and no process plant: the unit is both powered and communicated with entirely over the one USB cable. This is the whole of the hardware needed to develop and validate the controller under HIL.
- The COM (serial) port the unit is attached to. The agent needs to be told which port the EQSP32 currently enumerates as, since it is the single channel used for downloading the program and for running the HIL protocol.
- A link to the EQSP32 library header on GitHub. The header at github.com/Erqos/EQSP32 is where the agent finds everything it needs: the HIL protocol and the functions that enable it, the I/O and time API, and the ESP32-specific details of building for and talking to the unit. Pointing the agent at this one file is enough for it to work out the rest.
3Software Setup
This worked example used Cursor as the agentic coding environment, with Claude Opus 4.8 as the underlying model. The method, however, is not tied to that specific pairing. The relevant capability is an agent that can read and write files, run shell commands, and observe their output in a loop, a category that includes Claude Code, OpenAI's Codex CLI, and a growing number of open-source agentic coding tools, paired with any sufficiently capable frontier model. The toolchain in Section 3.1 is what differs by project; the agentic loop in Section 3.2 is what makes this approach general.
3.1 Toolchain
| Component | Value |
|---|---|
| Agentic IDE | Cursor (also validated conceptually with Claude Code, Codex CLI) |
| Model | Claude Opus 4.8 (method is model-agnostic in principle) |
| Target hardware | EQSP32 (ESP32-S3) |
| Control library | EQSP32 library v1.3.2, precompiled for esp32s3 |
| Build toolchain | arduino-cli 1.5.0, esp32 core 2.0.17 |
| Board profile (FQBN) | esp32:esp32:esp32s3:FlashSize=8M,PartitionScheme=default_8MB |
| Connection | USB serial (single cable), 115200 baud, 8-N-1 |
| Test harness | PowerShell script driving the HIL serial protocol, written by the agent itself |
3.2 The agentic loop: the PC, not the IDE
The defining characteristic of this method is that the agent operates the PC directly through its command line and file system; it does not operate the Arduino IDE, and no IDE window is opened at any point in the process. The agent:
- reads the two engineering drawings and a short prompt and writes the specification document directly to disk;
- writes the HIL test plan as a structured document;
- writes the control-program source files using the EQSP32 library's
bind()/expose()API; - invokes
arduino-clifrom the command line to compile the program; - reads the compiler output and, if it does not compile cleanly, edits the source and recompiles, without asking the engineer to intervene;
- invokes
arduino-cliagain to download the compiled binary to the controller over USB; - writes a PowerShell test harness implementing the HIL serial protocol described in Section 5;
- executes that harness, which drives the real controller through all 31 test cases and records what the controller reports back;
- reads the test results, and if any check fails, edits the control program, recompiles, redownloads, and re-runs the affected tests, again without engineer intervention;
- once all checks pass, writes the formal test report from what the controller reported during the run.
Every one of these is an ordinary file-system and command-line operation. There is no special integration between the agent and the EQSP32 beyond arduino-cli and a serial port, which is also why the method transfers cleanly to other agentic tools: any agent capable of running shell commands and reading their output can drive the same loop.
4From Engineering Drawings to a Formal Specification
The agent's starting point was the two drawings reproduced in Section 2, together with a short prompt describing the intent: an automatically operating RO skid with tank-level and supply management, membrane fouling detection, a periodic forward-flush, and the standard protections (over-temperature, dry-run, permeate quality, over-pressure, sensor fault). No I/O list, register map, or control narrative was supplied in text form; those came entirely from the agent reading the drawings.
From this input the agent produced a complete control and operation specification: the I/O assignment table (mapping each terminal in Figure 3 to its function), sensor scaling for every channel (for example, 4-20 mA mapped to 0-300 PSI, pulse counts mapped to L/min), the eight operating states and their transitions, the start permissives, the anti-short-cycle timing, the periodic flush logic, the five-fault protection table with blink codes, and a full default-parameters / setpoints table. It also flagged a list of open points for the engineer to confirm (channel numbers against final wiring, the feed-flow target band, and the exact over-pressure trip value) rather than silently guessing at values the drawings did not make explicit.
This step matters independently of what follows. Translating a wiring diagram and a process diagram into a complete, internally consistent control specification is itself a significant engineering task, normally the first deliverable in any controls project, and one that historically takes a qualified engineer hours to produce and review. Here it was the agent's first output, generated directly from the same drawings an engineer would have used.
4.1 Prompting the agent
The engineering drawings tell the agent what the hardware is; the prompt tells it what to do. Beyond a full description of what the system must do, the prompt should instruct the agent to produce a control specification, develop a test plan from it, verify the result using HIL, and build, download and run the code on the real unit. It also needs the two practical pointers from Section 2.5: where to find the EQSP32 library header on GitHub, and which COM port the unit is currently attached to. With those in place the agent has everything it needs to run the full cycle unattended.
Added to the end of the system description, a prompt as short as the following is enough:
Using the wiring and process diagrams above, write a complete control specification for this system, then develop a HIL test plan that covers its states, faults, warnings, hysteresis and timing. Write, build and download the control program to the EQSP32, and verify it against the real unit using Hardware-in-the-Loop, iterating until every test passes. Produce a final test report.
The EQSP32 library header, describing the HIL functions, the I/O and time API and all ESP32-specific details, is at https://github.com/Erqos/EQSP32/tree/main/src.
The unit is connected on COM4.
The COM port is shown here as COM4 for illustration; the reader substitutes whichever port the unit enumerates as on their own PC. Everything else in the prompt is reusable as written.
5The Hardware-in-the-Loop (HIL) Principle
Hardware-in-the-Loop testing is standard practice in aerospace and automotive ECU development, but it is rarely available on industrial micro-controllers and PLCs. The EQSP32 implements it natively. This section explains the principle in enough detail to be useful to readers unfamiliar with it, since it is the mechanism that makes unattended agentic validation trustworthy rather than simply convenient.
5.1 What HIL does
In HIL mode, the unmodified control program runs on the real microcontroller silicon exactly as it would in production. The only change is at the I/O boundary: instead of reading real sensors, the program's input calls return values injected over the USB serial connection; instead of driving real actuators, output commands are held in a readable output cache rather than physical pins. The control logic itself (every state transition, every timer, every fault condition) executes unmodified. The controller has no way to distinguish a HIL session from a real plant.
This is the property that makes the technique powerful: a test that passes under HIL is a test of the actual control logic that will run in the field, not of a simulation or a model of that logic.
5.2 Enabling HIL
The control program calls a single additional function before its normal initialization:
With this call present, the library intercepts the input and output paths as described above. Removing it (or building without the HIL_TEST flag, see Section 5.5) restores normal operation against physical I/O with no other code changes required.
5.3 The serial protocol
A compact text protocol over the same USB serial connection used for programming drives the entire test session. Four command forms cover all interaction:
| Command | Example | Effect |
|---|---|---|
| Inject an input | -!EQ.1=1333 | Sets the raw HIL value of pin 1 (for example, pressure IN) to 1333 |
| Read an output | -?EQ.15 | Returns EQ.15=1000, the output cache for pin 15 (pump) |
| Set the clock | -!TIME=2026-06-13T08:00:00 | Sets the device system clock, for testing time-of-day and calendar logic (see 5.5) |
| Periodic frame | -!#300/... | Re-applies a full input vector every 300 ms (see 5.4) |
Raw values use the same scaling the program would apply to a real transmitter; for example, a 4-20 mA pressure input scaled 0-300 PSI is injected as milliamps times 100, so 175 PSI is injected as the raw value 1333. This means the test harness reasons in the same engineering units as the specification, not in arbitrary protocol-internal numbers.
Independently of injected inputs, the program sends back a structured status line (in this example, >>STATE) on every state or output change and once per second regardless, carrying the controller state, all actuator commands, the status LED colour and flash pattern, and the live engineering values (pressures, levels, flows, temperatures). This is the primary channel the test harness reads; the -?EQ output-cache query is used as an independent secondary check, so that a test confirms both what the controller reports about itself and what it is actually commanding at the pins.
5.4 Continuous (pulse-counting) inputs
Flow meters and similar pulse-counting inputs present a particular problem for injection: their count accumulates and is consumed (reset) on each read, so a single injected value is not representative of a continuous flow. The protocol's periodic-frame command solves this by re-sending the complete input vector at a fixed interval, in this example every 300 ms, so the flow channels are continuously refreshed while the other, sticky inputs (pressure, level, temperature) are simply repeated harmlessly. This is the kind of detail that the test plan and harness need to get right, and in this example the agent identified and implemented the periodic-frame approach without being told to.
5.5 Time compression
Many of the parameters that matter most for correctness (the membrane flush interval, the permeate-quality trip delay, minimum motor on/off times, the start settling window) are deliberately long in production, on the order of minutes. Run unmodified, a full validation pass would take well over an hour, most of it spent waiting rather than testing. The HIL build addresses this by scaling down only the timers, by a single build-time flag, while leaving every setpoint and every piece of control logic completely unchanged.
| Timer | Production value | HIL test value |
|---|---|---|
| Start settling window | 25 s | 1.5 s |
| Minimum pump ON-time | 10 s | 1.5 s |
| Minimum pump OFF-time | 10 s | 1.5 s |
| Dry-run grace | 10 s | 1.5 s |
| Periodic flush interval | 60 min | 8 s |
| Flush duration | 5 min | 2 s |
| Permeate TDS trip delay | 10 min | 3 s |
| Analog fault debounce | 5 s | 0.6 s |
Critically, this is a compile-time substitution of timer constants behind a single build flag (HIL_TEST), not a rewrite of the logic that uses them. The same code path that waits 60 minutes in production waits 8 seconds under test; building without the flag restores the production values exactly. This is what allows a 31-case test matrix (including three separate sustained, time-based fault conditions) to run to completion in well under a minute of real time, and the full specification-to-report cycle to fit inside an 18-minute session.
A later addition to the HIL protocol, not available when this worked example was run, lets the harness set the device system clock directly with a -!TIME= command (Section 5.3). This is the natural tool for validating time-of-day and calendar logic, a flush scheduled for a particular hour, weekend or seasonal behaviour, and for advancing an absolute timer without waiting. It complements the compile-time compression of relative interval timers described above rather than replacing it: clock injection moves wall-clock time, while the interval timers in this example measure elapsed time, so the two address different parts of a controller's timing.
5.6 Why not just run it on the PC?
An agent could compile the control logic for the host PC and validate it there, but a PC build cannot run the program that ships: the EQSP32 library talks to peripherals, timers and interrupts that do not exist on a PC and must be stubbed, so what runs is a model of the program, not the compiled binary. HIL instead runs the actual binary on the actual ESP32-S3, in real time, while the same processor handles everything the program does in the background, the network stack, any Modbus polling, the status-reporting task and the RTOS scheduling them across its cores. The control logic is validated while it competes for processor time with the exact background work it will face in production. A check that passes under HIL passed on the binary that will ship, executing as it will execute.
This does not claim HIL exercises everything; real RF conditions, network congestion and the real plant remain the province of commissioning (Section 11).
6Summary of Results
With the hardware, software and HIL methodology now described, the outcome of applying them to the RO skid worked example is summarised below.
| Metric | Result |
|---|---|
| Inputs provided to the agent | 1 wiring diagram, 1 process/plumbing diagram, 1 short prompt |
| Specification produced | Full control & operation specification (I/O map, states, setpoints, fault logic) |
| Test plan produced | 31 HIL test cases covering states, faults, warnings, hysteresis, timing |
| Control program | Written, compiled, and downloaded to the controller over USB, unattended |
| Test execution | All 31 cases run against the live controller over the HIL serial protocol |
| Result | 31 / 31 checks passed |
| Total elapsed time | 18 minutes, approved specification through final test report |
| Engineer involvement during the run | None: no code reviewed, no IDE opened, no manual test step |
Two points of scope make these figures precise rather than contradictory. The 18 minutes is the agent's own unattended working time from the approved specification to the final test report; it does not include the specification phase or the time the engineer spent reviewing. And "no engineer involvement during the run" refers to the build-and-test phase: the one human gate is at the specification boundary, where the engineer reviews and approves the spec (and confirms the open points the agent flagged) before code is written. Once that approval is given, the write, build, download, test and debug loop runs to a 31/31 report with no further human step. The method is unattended within that loop, not autonomous of the engineer's judgment about what to build.
These figures are not a benchmark or a marketing claim about speed for its own sake. They are reported because each one is independently checkable: the specification, the test plan, the control program and the test report are all artifacts that exist on disk and can be inspected line by line. Section 7 addresses directly why a result produced this quickly, by a system that can in principle make mistakes, can still be trusted.
7Why an Unattended Result Can Be Trusted
The central engineering question is not whether an agent can produce a specification, a control program and a passing test report quickly (it clearly can) but why an engineer who did not review the code as it was written should be willing to accept the result. This is, ultimately, the same question an engineering manager asks about a new hire: not "is this person capable", but "has this person earned the right to sign off on their own work without supervision yet". The answer here rests on a structural property of the method, not on a claim about the model's reliability.
7.1 Separation of authorship and verification
The agent that writes the control program is not the arbiter of whether that program is correct. The arbiter is the hardware: the same EQSP32 silicon, running the same unmodified logic, exercised through the HIL serial protocol and observed through the controller's own status reports and an independent read-back of its output pins. A test report showing 31/31 passes is not the agent's opinion of its own work; it is a record of what the physical controller actually did when driven through every specified state, fault and timing condition.
This separation is what makes the result meaningful rather than circular. If the agent had simply asserted that the code was correct, that assertion would carry no more weight than any other unverified claim. Because the claim is instead a set of specific, falsifiable, hardware-observed outcomes (this pin reached this state within this timeout, this fault code appeared, this LED pattern matched), the test report stands independently of how much the engineer trusts the agent's judgment.
7.2 Hallucination and bugs are caught, not hidden
An agent can misread a drawing, invent a register address that does not exist, write a debounce condition with an off-by-one error, or simply hallucinate a detail it was not given. None of this is a special property of AI; it is the same category of mistake any engineer can make. What matters is not whether such errors are possible (they always are, for any author) but whether they can reach the field undetected. Under this method they cannot, because the check is indifferent to why the code is wrong.
Consider the over-pressure protection in the worked example: the controller must latch to a fault and stop the pump when feed pressure exceeds its trip threshold. The harness feeds the controller a pressure value above that threshold, a value the program reads exactly as if it had come from a real sensor, and then reads back, over the same USB cable, the state the controller moved to and the commands it is sending to its outputs. The controller either reports the correct fault state, with the pump commanded off, within the timeout, or it does not. A genuine defect in that trip reads back the same way whether it came from a typo, a misread setpoint, or a value the agent hallucinated; the check is the same either way, and a wrong implementation fails it.
This is what makes the loop self-correcting rather than merely fast. When a check fails, the controller's own report shows exactly which behaviour diverged from the specification; the agent reads that back, locates the responsible logic, edits it, recompiles, redownloads, and re-runs the affected cases, and the same hardware decides the second attempt as impartially as the first. The engineer does not have to catch the error by reading the code, because the hardware catches it by running the code.
In this particular run, all 31 checks passed against the controller as first generated: the control logic is a straightforward state machine, and the specification was fully resolved before any code was written (Section 4). But the trustworthiness of the result does not depend on that. Had any check failed, it would have been caught and resolved by the same loop, for the same reason, before the report could read 31/31. The value of the method is not that the agent does not err; it is that the method does not let an error pass silently.
7.3 Radical transparency, not a black box
Despite running unattended, the process is not opaque. At every stage the agent produced a complete, human-readable artifact rather than a result alone:
- the specification documents every I/O assignment, scaling factor, state, setpoint and fault condition, and explicitly lists open points the engineer should confirm rather than silently assuming;
- the control program is abundantly commented, naming the same states, setpoints and fault codes used in the specification, so the two can be read side by side;
- the test plan documents, for every one of the 31 cases, the exact stimulus injected and the exact outcome expected, including the time-compression table and the reasoning behind it;
- the test report records, for every case, the expected condition, what the controller actually reported back, and a pass/fail result, not a summary, but the underlying evidence.
An engineer reviewing this output after the fact is not being asked to take a result on faith. They are being handed exactly the documentation set a competent engineering team would produce for a formal design review (specification, test plan, test report) and can audit any part of it against the actual recorded hardware behaviour.
7.4 The new-engineer analogy
The most accurate way to frame this, for an engineering manager deciding how much autonomy to extend, is the same way one would think about a highly capable new engineer joining the team. Their work is detailed, well-documented, and, when checked, correct far more often than not. But a manager does not sign their own name to a new hire's first design without review, no matter how good the new hire's track record looks after a few weeks. Confidence is built incrementally, through repeated exposure to correct, transparent, independently verifiable work.
That is precisely the position an engineer is in here. The system already performs at a remarkably high level (specification, implementation and test, end to end, with hallucinations and bugs caught by hardware rather than missed) and the trend across model generations has been steadily upward, not flat. The appropriate response is neither blind trust nor blanket rejection: it is the same graduated trust an engineer would extend to any new and very capable colleague, built through review of exactly the kind of transparent documentation this method produces, and increasing as the track record does.
It remains the responsible engineer who signs off that a system will operate reliably and can be maintained over its lifetime. What this method changes is what that engineer is reviewing: not raw, undocumented code produced under time pressure, but a specification, an implementation and a test report that already agree with each other and with the hardware, produced in minutes rather than days, leaving the engineer's time for judgment rather than transcription.
8Why This Materially Increases Test Coverage
The practical effect of removing both the time cost of writing tests and the wall-clock cost of running them is that far more of the specification actually gets tested, not just that the same testing happens faster.
8.1 The cost asymmetry
Writing a HIL test plan, a serial test harness, and running and documenting 31 cases by hand is realistically a multi-hour task for an experienced engineer, even before accounting for the time spent waiting on production-length timers (the periodic flush alone is sixty minutes). Under time and budget pressure, the natural response is to test the happy path and a handful of the most obviously important faults, and to treat full coverage of every hysteresis band, every minimum-time interlock and every fault-reset path as a nice-to-have that rarely survives contact with a deadline.
Because the agent produces the test plan as a natural extension of the specification it has already written, and because time compression collapses the wall-clock cost of running it, the marginal cost of testing one more state, fault, or edge case is small. The 31-case matrix in this example is not a curated subset chosen to look thorough; it is close to the full cross-product of operating states, fault conditions, hysteresis bands and timing interlocks that the specification itself defines.
8.2 Regression, not just initial validation
Because the test plan and harness already exist as artifacts, every subsequent change to the control program (a tweaked setpoint, an added feature, a fix to something unrelated) can be re-validated against the same 31 checks in well under a minute. This converts HIL from a one-time validation exercise into a standing regression suite that can be run after every change, which is a different and considerably more valuable property than simply being able to test thoroughly once.
8.3 Faults that are dangerous or impossible to test by hand
A further advantage follows from injecting inputs over the wire rather than on a real plant: HIL reaches exactly the conditions that are hardest, or unsafe, to provoke by hand. Verifying an over-pressure, dry-run or over-temperature trip on real equipment means driving the actual plant toward the failure it is meant to prevent, at genuine risk to the membrane, the pump, or the operator. Under HIL the same test is a single injected value: the harness feeds the exact trip point, confirms the controller latches and shuts down, and no physical damage is ever risked. The same applies to sensor faults, where an out-of-range or broken-wire reading that would otherwise require physically sabotaging the loop is simply injected directly. Combined with the exact, repeatable threshold and hysteresis testing that a drifting real transmitter cannot provide, this lets the agent validate the entire protection layer, precisely and safely, that manual bench testing can only ever sample.
9Beyond Physical I/O: Fieldbus and Network Verification
The principle described in Section 5 (exercise the real control logic, observe the real outcome, let the controller's own reports be the arbiter) is not limited to the controller's local pins. The same agentic verification approach extends naturally to any interface the EQSP32 supports, including Modbus RTU/TCP and MQTT, because in both cases the question being asked is identical: does the device behave correctly as a peer on the network, not only as a set of I/O terminals.
9.1 Modbus / fieldbus verification
For an application that communicates with remote Modbus devices (for example, the EQSP32 acting as a Modbus master to a salt-chlorinator or a variable-frequency drive), a USB-to-Modbus adapter on the development PC gives the verification agent a second observation point that is completely independent of the EQSP32 itself. The agent can act as a Modbus slave simulator, populate specific registers with test values, and confirm both that the EQSP32 issues the correct requests (function code, register address, polling interval) and that it correctly interprets the responses, including malformed or out-of-range ones, exactly as the HIL serial protocol confirms correct behaviour at the pins. A communication bug (wrong register map, byte-order mismatch, missing timeout handling) is exposed by traffic that does not match the specification, in exactly the same falsifiable way an incorrect pump output is exposed when the controller's reported behaviour does not match the test plan.
9.2 MQTT / IoT verification
The same logic applies to MQTT-based IoT applications. With a broker available to the development PC, the verification agent can subscribe to the same topics the EQSP32 publishes to, inject messages on the topics it subscribes from, and converse with the device exactly as a real broker and a real remote client would. This allows verification of reconnect behaviour after a dropped connection, correct retained-message handling, payload formatting, QoS behaviour, and the device's reaction to malformed or unexpected incoming messages, all without any other physical hardware, real cloud endpoint, or human operator involved.
In both cases the methodology is unchanged from the physical-I/O case described throughout this note: an independent observer exercises the system under test through its real interface and records what actually happened, and that record, not the agent's account of its own work, is what the engineer reviews.
10The Economics
The engineering case for this method is strong on its own, but the cost case is what makes it hard to ignore. Almost everything the method depends on carries no license fee. The EQSP32 library, with all of its Hardware-in-the-Loop functionality, is free: HIL is a standard feature of the platform, not a paid tier. The build toolchain the agent drives is open source and free to use, with no IDE licence or per-seat cost. The only variable cost in the entire cycle is the AI model itself.
AI usage is priced by the token, the unit of text a model reads and writes, with input and output metered separately. An agentic run like this one is input-heavy, because the growing context, the library header, the drawings, the compiler output and the accumulating code, is re-read by the model on every step of the loop. Taking a deliberately conservative estimate for the reverse-osmosis build, on the order of a few million input tokens and a few hundred thousand output tokens, and pricing it at the standard rate of the frontier model used here (Claude Opus 4.8, at 5 USD per million input tokens and 25 USD per million output tokens), the entire specification-to-validated-controller cycle costs in the region of fifty US dollars. In practice the figure is typically lower: prompt caching, which reuses the unchanged context that an agentic loop resends constantly, can substantially reduce the input cost that dominates this workload.
That figure is best understood against what it replaces. Producing the same result by hand, writing the test plan and a serial test harness, then wiring, stimulating and observing every one of the 31 cases, and waiting out production-length timers, is realistically several days of skilled engineering work. On systems with large test matrices, validation of this kind can be a full-time role in its own right, and one that must be repeated in full at every release candidate. The method compresses that into an unattended run measured in minutes, and the standing regression suite (Section 8.2) means each subsequent revalidation costs another few tens of dollars rather than another several days.
Less expensive models, including capable open-source ones that can be run at little or no per-token cost, are able to drive the same loop, and for cost-sensitive or high-volume work they are worth considering. For a one-off industrial controller, however, the recommendation is to use the latest frontier model. Its cost is negligible next to the total cost of the installation it is validating, and its higher reliability directly reduces the number of build-and-test iterations, which lowers both the wall-clock time and the token spend of the run. When the model is a rounding error on the project budget, paying for the best available capability is the straightforward choice.
11Scope and Limitations
HIL validation, agentic or otherwise, demonstrates that the control logic behaves correctly against the inputs and timing it is given. It does not, by itself, validate everything an engineer needs before commissioning a real system, and overstating what it covers would undermine exactly the credibility this method depends on. In particular, HIL does not exercise:
- the real electrical behaviour of sensors and transmitters: noise, drift, nonlinearity, ground loops, and wiring faults beyond the simple broken-wire case the specification models;
- the mechanical and process dynamics of the actual plant: pump inertia, membrane fouling rates, real settling times, or the consequences of a control decision on real fluid behaviour;
- timing under real operational load: interrupt contention, network congestion, or concurrent traffic from other devices sharing the same fieldbus or broker;
- long-term reliability concerns such as component aging, thermal cycling, or program behaviour over months of continuous uptime.
These remain the province of commissioning against the physical plant, environmental and burn-in testing, and ordinary engineering judgment. HIL, agentic or manual, is a necessary and now dramatically cheaper stage of validation, not a replacement for commissioning. The test report in this worked example states this explicitly: the build is accepted for the on-bench stage, with physical commissioning against the real skid as the next, separate step.
12Conclusion
This worked example shows an AI agent carrying a real industrial control project from an approved specification to a documented, hardware-validated result in eighteen minutes, without an engineer opening an IDE or reviewing code as it was written. The result is trustworthy not because the agent is infallible, but because the method places an independent, falsifiable arbiter (the real controller, exercised through Hardware-in-the-Loop and observed through the status it reports back over the wire) between the agent's output and the engineer's sign-off. Hallucinations and bugs are caught by hardware, not by faith in the model; the documentation produced at every stage is detailed enough to audit; and the same separation of authorship from verification extends cleanly from physical I/O to Modbus and MQTT.
The appropriate stance toward this capability is the same graduated trust an engineering manager extends to any new, highly capable colleague: real confidence, built through transparent and independently verifiable work, increasing as the track record does, not blind acceptance, and not reflexive dismissal. What is already true today is that this performs at a remarkably high level. What is also true is that it is improving with each model generation. Both facts are worth taking seriously.
AAppendix: Artifacts Generated by the Agent
The trust argument in this note rests on the artifacts being inspectable rather than taken on description. Everything the agent produced for the worked example is therefore published in full in the Erqos resources repository on GitHub, so any claim in this note can be checked against the actual output:
The repository is organised in three folders. Each item is listed below with what it contains and what it lets a reader verify.
Documents/- the four engineering documents from the run:- Control specification (
RO-Skid-Control-Specification.pdf). The complete specification the agent derived from the two engineering drawings and the prompt: the I/O assignment table, sensor scaling for every channel, the operating states and their transitions, start permissives and anti-short-cycle timing, the periodic-flush logic, the five-fault protection table with blink codes, and the default-parameters and setpoints table. This is the document an engineer reviews and approves before any code is written (Section 4). - HIL test plan (
RO-Skid-HIL-Test-Plan.pdf). The 31-case test matrix, documenting for each case the exact input injected and the exact outcome expected, along with the time-compression table and the reasoning behind it. This is what makes the coverage auditable: a reader can confirm that the matrix covers the operating states, fault conditions, hysteresis bands and timing interlocks the specification defines, rather than a curated subset (Section 8). - HIL test report (
RO-Skid-HIL-Test-Report.pdf). The formal report generated from the run, recording for every one of the 31 cases the expected condition, what the controller actually reported back, and a pass/fail result, ending in the 31/31 outcome and the explicit note that the build is accepted for the on-bench stage with physical commissioning as the next, separate step. - The specification dialogue (
RO-Skid-Appendix_Specification_Dialogue.pdf). A documented record of the collaborative phase that preceded the unattended run: the exchange in which the engineer supplied the drawings and requirements and the agent performed the requirements engineering. It shows the agent validating its inputs (it caught that the two attached files were the same drawing), flagging its assumptions explicitly, and submitting its own design additions for human confirmation, evidence of engineering judgment that test results alone cannot provide.
- Control specification (
Code/- the control program (EQSP32_RO_Skid_Controller.ino). The full, commented source the agent wrote using the EQSP32 library'sbind()andexpose()API, naming the same states, setpoints and fault codes as the specification so the two can be read side by side. This is the deliverable that would run on the controller in the field; building without the HIL flag restores production timers and physical I/O with no other change.HIL-Test/- the test harness and raw results:- Test harness (
run_hil_test.ps1). The PowerShell script the agent wrote to drive the HIL session over the USB serial connection: it injects the inputs for each case, reads back the controller's status reports and output-pin cache, compares them against the expected outcomes, and records the result. This is the independent observer that the trust argument depends on, the part that is separate from the code under test (Section 7). - Raw test output (
TEST_REPORT.md). The machine-generated report written by the harness as the 31 cases executed, the underlying evidence behind the formal PDF report.
- Test harness (
Read together, these artifacts are the same documentation set a competent engineering team would produce for a formal design review (specification, test plan, test harness, implementation and test report), with the difference that here they were generated in a single unattended session and already agree with each other and with the hardware.
See the method in one page
This application note is the detailed reference. For the short version of what agentic development plus native HIL means for the EQSP32, start with the overview.