This solution contains two thin client applications and a backend API, built around a shared orchestration layer utilizing MQTT "channel mobility" (Pi Calculus) for dynamic UI generation:
pi-console: A .NET 10 console application that emulates the look and feel of a classic Bulletin Board System layout, built with a modern static approach usingSpectre.Console.pi-wasm: A .NET 10 Blazor WebAssembly application that replicates the exact same BBS interface within a web browser, communicating directly over secure WebSockets.pi-functions: A .NET 10 Minimal API that acts as a serverless-style backend, persisting Pi Calculus session states to a PostgreSQL database using native JSONB columns.
To support multiple clients, core business logic, MQTT communication, and layout models are decoupled into the Pi.Shared library. Each client project (pi-console and pi-wasm) simply implements the IUiService interface to render the dynamic JSON payloads provided by Node-RED into their respective UI frameworks.
- Static Layouts: Uses rendering loops via
AnsiConsole.Livefor the CLI and a CSS Flexbox grid for WASM to display panels without scrolling or breaking layouts. - Interactive Menu: Fully navigatable using the Up/Down Arrow keys in the console, or mouse clicks in the browser.
- Dynamic Channels (Pi Calculus): Uses MQTT "channel mobility" to dynamically subscribe to new communication sessions established via handshakes.
- Real-time Status Updates: Subscribes to an MQTT broker to display real-time signal messages and apply
Spectre.Consolecolor markup translations (e.g.[green]ONLINE[/]).
- .NET 10 SDK
- An MQTT broker (Optional but recommended to test the status signals).
-
Clone the repository:
git clone https://github.com/cerkit/pi-console.git
-
Make sure you have the required .NET environment set up.
-
Configure Connection Properties: Both clients are set to connect using MQTT over WebSockets (defaulting to
localhost:9001) to prevent native operating system TCP ghost broker conflicts. The connection strings and targetedClientId(eitherpi-consoleorpi-wasm) are explicitly configured in the individualProgram.csfiles during theMqttServicedependency injection registration.MQTT Authentication Setup:
- For
pi-console(CLI): Create asecrets.jsonfile in a.secretsfolder at the root of the repository (.secrets/secrets.json).{ "MqttIpAddress": "localhost", "MqttPort": 9001, "Username": "your_mqtt_username", "Password": "your_mqtt_password" } - For
pi-wasm(Browser): Create anappsettings.jsonfile in thepi-wasm/wwwrootfolder (pi-wasm/wwwroot/appsettings.json).{ "Mqtt": { "Username": "your_mqtt_username", "Password": "your_mqtt_password" } }
(Note: Both
.secrets/andpi-wasm/wwwroot/appsettings.jsonare ignored by Git to prevent committing sensitive credentials.) - For
-
Configure Node-RED Configuration Data: To allow Node-RED flows to pull the customized UI configuration and menu data for all clients, you must create or place the
pi-console-configs.jsonfile into the/datafolder of your Node-RED Docker container. If you mount a local directory to/datain your Docker Compose or run command, place the file there. Node-RED will read this file to dynamically serve configs based onClientId. -
Run the CLI Application (
pi-console): Navigate to thepi-consoledirectory and run:cd pi-console dotnet run -
Run the Web Application (
pi-wasm): Navigate to thepi-wasmdirectory and run:cd pi-wasm dotnet watch runNote: The Blazor WASM client relies on the broker having WebSockets exposed (e.g., Mosquitto on Port
9001).
When the application is running:
- Use the Up/Down Arrow keys to scroll through menu items in
pi-console, or use mouse clicks in thepi-wasmbrowser client. - Press Enter on a menu item (or click it in the browser) to push its label to the Output panel or trigger its dynamic action.
- Press Q or Escape (or press Enter/click on an item labeled "Logoff" or "Exit") to log off and exit the application safely. Both clients support dynamic Pi Calculus actions passed via the UI layout configuration, processed by a centralized
commandProcessorthat enables powerful runtime controls such as clearing the interface (CLEAR) or restarting the orchestration handshake (RESTART).
This application utilizes a "channel mobility" system for MQTT communication. All application UI configuration occurs dynamically, customized per ClientId.
-
Startup: When the app starts, it publishes a JSON payload
{"clientId": "{ClientId}"}to thepi-console/client/startuptopic to announce its presence. -
Session Handshakes: The app listens on its targeted
pi-console/handshake/{clientId}topic for new connection instructions. Handshakes are formatted in JSON:{"action": "CONNECT", "replyToChannel": "session_id"}or
{"action": "INITIATE_SESSION", "channel": "session_id"}When the application receives a handshake, it reads the dynamic channel string, instantly opens a subscription to that active channel, and registers it in the live "Operations" screen.
-
Dynamic Menus and UI Configs: If an
INITIATE_SESSIONhandshake is requested, the application publishes a{"status": "READY"}payload back to the dynamic channel. The Node-RED backend looks up the requestedclientIdin its configuration dictionary and serves targeted UI layout parameters and menu options down the secure channel.- Expected JSON format for a menu array:
[ { "id": 1, "label": "System Status", "icon": "info", "color": "green" }, { "id": 2, "label": "Device Settings", "icon": "settings", "color": "purple" } ]
- Expected JSON format for a menu array:
-
Global Messages: If messages are published to
pi-console/statuson your MQTT broker, they will appear dynamically in the System Status panel at the bottom.
- .NET 10
- Pi.Shared: Class Library for Shared Domain Models and Services.
- pi-console: CLI built using
Spectre.Consolelayout management and widgets. - pi-wasm: Browser client built using
Blazor WebAssembly. - pi-functions: Minimal API for state persistence handling HTTP requests from Node-RED.
- MQTTnet: Used for remote telemetry, supporting both TCP sockets and WebSockets.
- PostgreSQL: Used for storing Pi Calculus session data via Entity Framework Core.
- Podman / Docker Compose: Orchestrates the local containers (Mosquitto, Node-RED, Postgres, and pi-functions).
Please read the `NodeRed_Architecture.md` file located in the root of the workspace to understand the current Pi Calculus orchestration, MQTT topics, and JSON payload schemas.
Task:
[Insert your specific goal here, e.g., "Implement the ClientId property in the shared library and update the startup sequence to publish to the targeted public handshake topic as defined in the architecture document."]
Constraints:
- Ensure all core MQTT and Pi Calculus logic goes into the shared library.
- Keep UI-specific rendering inside the `pi-console` or `pi-wasm` projects.
