Purpose
The public demo shows a complete but deliberately tiny control path: a browser submits led.on(), the website validates it, RabbitMQ receives a signed command for website Controller, and a Raspberry Pi turns on one LED. The camera provides the physical evidence.
Non-negotiable constraints
- The browser may submit only
led.on(). - The browser cannot select an exchange, queue, routing key, Controller ID, operation, GPIO pin, or argument.
- The website publishes only to the queue named
website Controller. - The message is signed, expires quickly, and includes a unique command ID.
- The Raspberry Pi verifies the signature, target, operation, expiry, and replay state.
- No component uses
eval(),exec(),shell=True, or a remote shell.
Request flow
- Browser validation
JavaScript improves feedback, but the server repeats every validation because browsers are not security boundaries.
- CSRF and rate limit
The website checks the signed session token, per-client quota, global cooldown, and request size.
- Fixed command mapping
The text
led.on()maps internally to the typed operationled.on. No other mapping exists. - Confirmed publish
The Pi consumer or broker administrator declares the durable
website Controllerqueue. The website publishes mandatorily to that pre-existing queue and requires a RabbitMQ publisher confirmation. - Controller validation
The Raspberry Pi rejects stale, malformed, misrouted, unsigned, or duplicate commands.
- Physical verification
The camera—not the HTTP response—shows whether the LED changed state.
It means RabbitMQ confirmed receipt. It does not mean the Raspberry Pi was online, the GPIO handler succeeded, the LED is wired correctly, or the camera is current.
Camera path
The website container proxies the configured camera through the same HTTPS origin at /demo-camera/. The proxy permits read-only viewing and strips browser credentials. Direct camera administration remains outside the public site.
Reference containers
The release contains two Docker-focused components: the public website image and an optional Raspberry Pi agent image under controller_agent/. The website terminates TLS with the host's mounted Let’s Encrypt certificate. The Pi agent mounts persistent replay state and the GPIO device interface required by its deployment.
Certificate and signing-key separation
The HTTPS private key, AMQP credentials, and command signing key solve different problems and remain separate. Rotating one should not require baking a new application image or silently changing another boundary.