Debian laptop with real OpenPLC Editor (brewery project) aligned to the screen

Reverse-engineering OpenPLC with its open source: brewery automation with AI

Most industrial stacks force you to guess. Vendor IDEs hide the compiler pipeline; fieldbuses arrive as opaque binaries; the “manual” is a PDF that disagrees with the firmware. OpenPLC is the opposite: Editor, Runtime, and the IEC 61131-3 project on disk are readable. For a brewery supervisory layer — reservoir alarms, cooling permissives, shared pump demand, and a Raspberry Pi operator sidecar — that readability was the difference between folklore and engineering.

This note is about that reverse-engineering loop: how we used OpenPLC’s own source and on-disk project format to write automation that a CONTROLLINO can own, and how open source made AI assistance useful instead of decorative.

What we were building

The target is a classic PLC pattern, not a “Python runs the plant” experiment:

  • Control pillar — PLC logic (Structured Text function blocks + a thin ladder program) intended for a CONTROLLINO MEGA Pure.
  • Operator companion — a local-first Pi sidecar (browser UI + Modbus contract) for settings, bypass workflows, and status — never the owner of process safety.
  • Bench path — Linux-hosted OpenPLC Runtime for simulator-first integration before field upload.

Implemented baseline includes reservoir level alarm latching and indication, per-channel bypass with PLC-owned timing, cooling vessel evaluation and arbitration (priority / mode codes → resolved permissives), and first-pass hot-side gating with raw shared pump-demand generation. Vessel temperature acquisition is headed cabinet-native (PT100 → transmitter → 0–10 V → CONTROLLINO), not sidecar-owned RS485 controllers.

What “reverse-engineering” meant here

We did not reverse proprietary silicon. We read the project the way OpenPLC actually stores it, then traced how that becomes something a Runtime or a controller can execute:

  • Source of truth on disk — pous/programs/main.ld, pous/function-blocks/*.st, project.json, devices/configuration.json. Generated build/… artefacts are confirmation, not the place to invent behaviour.
  • POU kinds are not interchangeable — OpenPLC’s FUNCTION vs FUNCTION_BLOCK serialization is easy to get wrong; the open layout made the mistake visible (wrong folder, wrong END_* form) instead of a silent UI quirk.
  • Debugger watches as project data — preselecting simulator variables in project.json (data.debugVariables) is faster and more reviewable than clicking icons one by one — because the selection is just JSON.
  • Two upload stories — bench Runtime web upload vs preferred Editor → CONTROLLINO field path. Open docs and open tooling let us keep those paths separate instead of collapsing them into one mythical “deploy” button.
  • Contract at the edge — sidecar ↔ PLC Modbus/mailbox behaviour documented against what the Runtime actually exposes, so the companion UI mirrors PLC truth rather than inventing mock numbers.

That is reverse engineering in the open-source sense: walk the real pipeline until the mental model matches the bits.

Why open source makes AI useful

An assistant that only sees your ladder screenshots will invent IEC folklore. An assistant that can read OpenPLC’s project files, the generated ST, Runtime upload artefacts, and your own architecture notes can propose changes that compile and that a human can still refuse.

In practice we treat the brewery repo like any other serious codebase under Cursor: short rules (terminology, fail-safe outputs, PLC authority), bounded skills for bench checks, and docs that name the control pillar explicitly. OpenPLC’s openness feeds that loop — the model is not guessing a closed vendor schema; it is navigating a public stack plus our contracts.

Related discipline on this blog: How I write code with Cursor.

What we still refuse to blur

  • PLC owns safety — if the sidecar is down, cabinet logic and hardwired behaviour remain the production path.
  • Simulator ≠ field timing — raw pump demand in software is not proof of timer-relay minimum run/rest on the shared cold pump.
  • Resolved state beats source codes — cooling decisions are read from normalized bits after priority/mode interpretation, not from the raw config codes alone.
  • Open source ≠ lax process — readable code improves AI outcomes; it does not replace review, simulator matrices, or hardware validation.

Sandbox note (short)

IDE agent sandboxes remain a machine safety boundary (filesystem, network, blast radius). OpenPLC’s openness improves what the assistant can reason about; it does not invent a separate, stricter sandbox religion for this project. Escalate network or host access when the job needs it, keep secrets out of prompts, and keep judgment human — same posture as elsewhere. Privacy and residency are covered in AI in the IDE: privacy, sandboxes, and on-prem DeepSeek; this article is about using an open stack well, not about inventing extra sandbox theatre.

Takeaway

Brewery automation on OpenPLC worked as an AI-assisted engineering project because the stack could be inspected: project layout, ST generation, Runtime vs controller paths, Modbus contract. Closed tools make assistants bluff. Open tools make them interlocutors you can still overrule.

The plant still needs a named human on the commit — and a CONTROLLINO that does not care how eloquent the chat was.

Written with the help of an AI assistant.