GenControl
An HMI where every button is a request, never a command — and a browser mockup that let the screen flow get argued about before anyone opened the vendor editor.
A touchscreen HMI for a generator controller. 480×272, driving a physical machine.
Eight files. It’s a design artifact, not an application — and the two ideas in it are worth more than the line count suggests.
The button is a request
The rule the whole thing is built on: the touchscreen can only ask.
Every button is a request. Not a command. It cannot actuate anything. All of it — safety checks, lockouts, timing, relay control, the decision to say no — lives in firmware. The panel sends “the operator would like the load transferred” and the firmware decides whether that is currently a sane thing to do.
This sounds obvious and is routinely violated, because it’s easier to let the screen drive the relay. The moment it does, your safety logic is spread across a GUI editor and a microcontroller, and the GUI is now a safety-rated component maintained by whoever last dragged a widget. Keeping the panel dumb means the safety story lives in exactly one place you can reason about, and the screen can be redesigned, replaced, or unplugged without touching it.
Unplugging it should be survivable. That’s the test.
Mock the screen in a browser first
The other move: the HMI was prototyped as a pixel-locked browser mockup before anything was built in the vendor’s editor.
Vendor GUI editors are miserable to iterate in and impossible to review — you can’t diff them, you can’t send someone a link, you can’t argue about a screen flow in a pull request. So the flow got built in plain HTML/CSS/JS at exactly 480×272, where it could be clicked through, shown to people, and rearranged in minutes.
Component names and IDs are kept in sync with the firmware through a shared C header, so the mockup and the real panel don’t drift into two different products.
Status: dormant, and honest about it
The ESP32 firmware is referenced throughout and isn’t here. There’s a spec, a mockup, a parts list, and a header. The hard half — the half that actually has to say no to the operator — was never written.
Filed because the two ideas survive the project.