From fd64e3f5badaa2cc3efaa84f8eadd0bff7009a94 Mon Sep 17 00:00:00 2001 From: Joojo Dontoh Date: Thu, 30 Jul 2026 12:29:56 +0800 Subject: [PATCH 1/9] =?UTF-8?q?feat:=20cockpit=20UI=20=E2=80=94=20redesign?= =?UTF-8?q?ed=20simulator=20dashboard=20(webapp-src=20cockpit-redesign)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitmodules | 2 +- public/bundle.html.gz | Bin 36613 -> 109169 bytes webapp-src | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index ceb826b..17f5180 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,7 +12,7 @@ url = https://github.com/cesanta/mongoose [submodule "webapp-src"] path = webapp-src - url = https://github.com/agruenb/arduino-ocpp-dashboard.git + url = https://github.com/Pitvolt/micro-ocpp-dashboard.git [submodule "lib/mbedtls"] path = lib/mbedtls url = https://github.com/Mbed-TLS/mbedtls diff --git a/public/bundle.html.gz b/public/bundle.html.gz index d419b54b2ec28252c7c8204f9fe51e6a6dfe9ea8..4cf9efdfebc78aef205993d70ac1a99de8b11dce 100644 GIT binary patch literal 109169 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�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 diff --git a/webapp-src b/webapp-src index 015a0e8..3bad52f 160000 --- a/webapp-src +++ b/webapp-src @@ -1 +1 @@ -Subproject commit 015a0e816ca4fc617e67acdbe7d067688d6b3939 +Subproject commit 3bad52f556d5fbab434f59155b89b42b65a52b94 From 80274588222c00e68cb4b3697ec0b7de1e40f707 Mon Sep 17 00:00:00 2001 From: Joojo Dontoh Date: Thu, 30 Jul 2026 12:39:23 +0800 Subject: [PATCH 2/9] feat: color-coded status badges in cockpit UI --- public/bundle.html.gz | Bin 109169 -> 109210 bytes webapp-src | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/public/bundle.html.gz b/public/bundle.html.gz index 4cf9efdfebc78aef205993d70ac1a99de8b11dce..81e5e88769302d37db01d0e97cb5a0218f0dc7ff 100644 GIT binary patch delta 19444 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 delta 19433 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 VJ9#}1cFJjD*V2SK55Sk`{sX Date: Sun, 2 Aug 2026 00:56:51 +0800 Subject: [PATCH 3/9] Add deploy/staging Fly.io bundle for Pitvolt staging OCPP Layered runtime entrypoint on top of the upstream build so ONE image targets any charger via STATION_ID + WSS_URL env vars. Small always-off Fly machine idles for free; auto-starts on request. Full bring-up steps in deploy/staging/README.md. Co-Authored-By: Claude Opus 4.7 --- deploy/staging/Dockerfile | 31 ++++++++++++++++++++ deploy/staging/README.md | 56 ++++++++++++++++++++++++++++++++++++ deploy/staging/entrypoint.sh | 31 ++++++++++++++++++++ deploy/staging/fly.toml | 40 ++++++++++++++++++++++++++ 4 files changed, 158 insertions(+) create mode 100644 deploy/staging/Dockerfile create mode 100644 deploy/staging/README.md create mode 100755 deploy/staging/entrypoint.sh create mode 100644 deploy/staging/fly.toml diff --git a/deploy/staging/Dockerfile b/deploy/staging/Dockerfile new file mode 100644 index 0000000..1e585bf --- /dev/null +++ b/deploy/staging/Dockerfile @@ -0,0 +1,31 @@ +# Staging-bundle image (deploy/staging/): rebuilds the simulator with the +# runtime entrypoint layered on top, so the browser UI at :8000 always +# targets whichever station+endpoint STATION_ID and WSS_URL name. Same +# build recipe as the root Dockerfile -- kept separate so the upstream +# image stays clean. + +FROM alpine:latest + +RUN apk update && \ + apk add --no-cache \ + git \ + cmake \ + openssl-dev \ + build-base + +WORKDIR /MicroOcppSimulator + +# Bring in the whole repo -- Docker build context is the repo root when +# `docker build -f deploy/staging/Dockerfile .` runs. +COPY . . + +RUN git submodule init && git submodule update +RUN cmake -S . -B ./build -DCMAKE_POLICY_VERSION_MINIMUM=3.5 +RUN cmake --build ./build -j 16 --target mo_simulator -j 16 +RUN chmod +x /MicroOcppSimulator/build/mo_simulator + +COPY deploy/staging/entrypoint.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh + +EXPOSE 8000 +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] diff --git a/deploy/staging/README.md b/deploy/staging/README.md new file mode 100644 index 0000000..0e173e8 --- /dev/null +++ b/deploy/staging/README.md @@ -0,0 +1,56 @@ +# Staging OCPP simulator bundle + +A small always-off Fly.io machine running MicroOcppSimulator, pre-pointed at +Pitvolt staging (`wss://staging.ocpp.pitvolt.com`) and the e2e charger +(`PVE2-VAJN`). Auto-starts on first request; idles for free. + +Runs the same binary as the upstream repo (built by `deploy/staging/Dockerfile`), +just with a runtime entrypoint that writes `mo_store/ws-conn.jsn` from +`STATION_ID` + `WSS_URL` env vars so one image works for any charger. + +## First-time bring-up + +Prereq: `brew install flyctl` and `flyctl auth login`. + +```bash +cd deploy/staging +# Create the Fly app (uses this fly.toml, does not deploy yet). +flyctl launch --no-deploy --copy-config --name pitvolt-ocpp-sim \ + --org personal --region fra +# Build + deploy from the REPO ROOT (Dockerfile expects the whole repo). +cd ../.. +flyctl deploy --config deploy/staging/fly.toml --dockerfile deploy/staging/Dockerfile +``` + +Once live: — the simulator's web UI. +Drive charging sessions from the browser; the running backend on staging +(`stg.api.pitvolt.com`) treats it as a real charger. + +## Retarget a different charger + +```bash +flyctl secrets set STATION_ID= +# For a completely different environment: +flyctl secrets set WSS_URL=wss:///ocpp +``` + +Fly restarts the machine automatically. + +## Local dry-run without Fly + +```bash +docker build -f deploy/staging/Dockerfile -t pitvolt/micro-ocpp-sim:staging . +docker run -p 8000:8000 \ + -e STATION_ID=PVE2-VAJN \ + -e WSS_URL=wss://staging.ocpp.pitvolt.com \ + pitvolt/micro-ocpp-sim:staging +# UI at http://localhost:8000 +``` + +## Cost + safety + +- Auto-stops when idle; a warm start is ~2s. Effectively free on Fly's + hobby tier. +- Publicly reachable (no auth). Fine because it's a staging tool that can + only drive whatever charger `STATION_ID` names. **Never** point it at + production without adding a Fly access policy or basic auth in front. diff --git a/deploy/staging/entrypoint.sh b/deploy/staging/entrypoint.sh new file mode 100755 index 0000000..b9726ed --- /dev/null +++ b/deploy/staging/entrypoint.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# Runtime OCPP config for the staging bundle. Overwrites mo_store/ws-conn.jsn +# from env vars so ONE image can target any charger / any environment: +# +# docker run -p 8000:8000 \ +# -e STATION_ID=PVE2-VAJN \ +# -e WSS_URL=wss://staging.ocpp.pitvolt.com \ +# -e AUTH_KEY= \ +# pitvolt/micro-ocpp-sim:staging +# +# The simulator reads this file exactly once at startup; changing env at +# runtime = restart container. The UI at :8000 lets you drive sessions. + +set -eu + +: "${STATION_ID:?STATION_ID env required (OCPP charge box id, e.g. PVE2-VAJN)}" +: "${WSS_URL:?WSS_URL env required (e.g. wss://staging.ocpp.pitvolt.com)}" +AUTH_KEY="${AUTH_KEY:-}" + +cat > /MicroOcppSimulator/mo_store/ws-conn.jsn <})" +exec /MicroOcppSimulator/build/mo_simulator diff --git a/deploy/staging/fly.toml b/deploy/staging/fly.toml new file mode 100644 index 0000000..e772276 --- /dev/null +++ b/deploy/staging/fly.toml @@ -0,0 +1,40 @@ +# Fly.io config for the staging OCPP simulator (deploy/staging/README.md). +# Small always-off machine that auto-starts on request; ~$0/month idle. +# +# Bring-up: +# cd deploy/staging +# flyctl launch --no-deploy --copy-config --name pitvolt-ocpp-sim --org personal --region fra +# flyctl deploy --dockerfile Dockerfile --config fly.toml +# +# Override the target charger without redeploying: +# flyctl secrets set STATION_ID= +# +# Public URL after deploy: https://pitvolt-ocpp-sim.fly.dev +# WARNING: publicly reachable. Only use against staging chargers. + +app = "pitvolt-ocpp-sim" +primary_region = "fra" + +[build] + # Build context is the REPO ROOT (fly deploy runs from deploy/staging/ + # so we escape one dir up); the Dockerfile COPYs the whole repo in. + dockerfile = "Dockerfile" + +[env] + STATION_ID = "PVE2-VAJN" + WSS_URL = "wss://staging.ocpp.pitvolt.com" + # AUTH_KEY is deliberately empty: staging OCPP endpoint uses station-id + # auth only (see docs/architecture note, 2026-08-01). Set as a fly secret + # if the endpoint ever adds a password check. + +[http_service] + internal_port = 8000 + force_https = true + auto_stop_machines = "stop" + auto_start_machines = true + min_machines_running = 0 + +[[vm]] + cpu_kind = "shared" + cpus = 1 + memory_mb = 512 From be1b48d1b487680e8dc3fb3b88d3e91a145db7c1 Mon Sep 17 00:00:00 2001 From: Joojo Dontoh Date: Sun, 2 Aug 2026 00:57:01 +0800 Subject: [PATCH 4/9] WIP: cockpit UI iterations and Docker build tweak Draft cockpit HTML mockup, redesign prompt, docs folder, and matching webapp-build/Dockerfile tweaks. Co-Authored-By: Claude Opus 4.7 --- Dockerfile | 4 +- OCPP Simulator Cockpit.html | 385 +++++++ UI_REDESIGN_PROMPT.md | 81 ++ build-webapp/build_webapp.sh | 0 .../plans/2026-07-30-cockpit-ui-port.md | 1004 +++++++++++++++++ 5 files changed, 1473 insertions(+), 1 deletion(-) create mode 100644 OCPP Simulator Cockpit.html create mode 100644 UI_REDESIGN_PROMPT.md mode change 100644 => 100755 build-webapp/build_webapp.sh create mode 100644 docs/superpowers/plans/2026-07-30-cockpit-ui-port.md diff --git a/Dockerfile b/Dockerfile index d90093e..7442e11 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,9 @@ WORKDIR /MicroOcppSimulator COPY . . RUN git submodule init && git submodule update -RUN cmake -S . -B ./build +# Alpine ships cmake 4+, which drops support for `cmake_minimum_required` < 3.5. +# The bundled mbedtls submodule still declares 3.4, so pass the compat flag. +RUN cmake -S . -B ./build -DCMAKE_POLICY_VERSION_MINIMUM=3.5 RUN cmake --build ./build -j 16 --target mo_simulator -j 16 # Grant execute permissions to the shell script diff --git a/OCPP Simulator Cockpit.html b/OCPP Simulator Cockpit.html new file mode 100644 index 0000000..462fb08 --- /dev/null +++ b/OCPP Simulator Cockpit.html @@ -0,0 +1,385 @@ + + + + + OCPP Simulator — Cockpit + +

+ This page requires JavaScript to display. +
+ + + +
+
Unpacking...
+ + + + + + + + + + + + \ No newline at end of file diff --git a/UI_REDESIGN_PROMPT.md b/UI_REDESIGN_PROMPT.md new file mode 100644 index 0000000..09cea1d --- /dev/null +++ b/UI_REDESIGN_PROMPT.md @@ -0,0 +1,81 @@ +# Prompt: Redesign the MicroOcppSimulator Web UI + +Copy everything below this line into a fresh Claude session opened at the repo root. + +--- + +## Mission + +Redesign the web UI of this OCPP charge-point simulator from scratch. The current UI is a dated, form-heavy "debug dashboard" (Kube CSS, fieldsets, manual Fetch buttons, raw protocol booleans). I want a modern, intuitive, human-centred simulator UI that makes an EV-charging session feel tangible — plug in a car, tap a card, watch it charge — while the C++ simulator underneath stays exactly as it is. + +**Hard rule: NO CORE LOGIC CHANGES.** Everything in `lib/` (MicroOcpp, MicroOcppMongoose, mongoose, mbedtls, ArduinoJson) and the simulation logic in `src/evse.cpp`, `src/main.cpp`, `src/net_mongoose.cpp` is untouchable. The only C++ file you may lightly touch is `src/api.cpp` / `src/api.h` (the HTTP glue layer) — and only to rename/alias endpoints or JSON field names so the API reads more human, or to add a trivial aggregate GET. Never change simulation behaviour, OCPP behaviour, timing, or state machines. + +## Architecture you must preserve + +- The C++ binary (mongoose web server) serves **one single gzipped HTML file** — `public/bundle.html.gz` — at `/`, with `Content-Encoding: gzip`. All CSS and JS must be inlined into that one file. No external assets, no CDN, no separate JS/CSS files at runtime. +- The webapp source lives in the `webapp-src/` git submodule (Preact + webpack). Build pipeline: + 1. `npm run build` (webpack prod → `dist/main.js` + `dist/main.css`) + 2. `npm run compress` (`deploy/bundle_all.js` inlines CSS+JS into `dist/bundle.html`, gzips it) + 3. `build-webapp/build_webapp.sh` moves `bundle.html.gz` → `../public/` + 4. Requires a `.env.production` file in `webapp-src/` defining `API_ROOT` (empty string = same origin). +- Keep the stack lightweight: Preact is fine (3KB), plain CSS or a tiny utility layer is fine. **No React, no Tailwind-via-CDN, no heavy component libraries.** Target: final `bundle.html.gz` stays under ~150KB (it's currently ~36KB). +- The UI talks to the backend via **HTTP polling only** (no browser websocket, no SSE). Current UI polls at 1s intervals on the Status page; that cadence is fine. +- CORS is wide open on the server; optional HTTP Basic Auth may be configured but the UI doesn't handle it — ignore auth. + +## The API contract (current, verified from `src/api.cpp`) + +Legacy JSON API (what the UI uses today): + +| Endpoint | Methods | Body / Response | +|---|---|---| +| `/connectors` | GET | `["1","2"]` (2 simulated connectors, IDs are 1-indexed strings) | +| `/connector/{id}/evse` | GET, POST | `{evPlugged, evsePlugged, evReady, evseReady: bool, chargePointStatus: string}` — status is an OCPP value: Available, Preparing, Charging, SuspendedEV, SuspendedEVSE, Finishing, Faulted, … | +| `/connector/{id}/meter` | GET | `{energy: Wh int, power: W int, current: A float, voltage: V float}` | +| `/connector/{id}/transaction` | GET, POST | GET → `{idTag: string, transactionId: int (-1 = none), authorizationStatus}`; POST `{idTag}` simulates presenting an RFID card | +| `/connector/{id}/smartcharging` | GET | `{maxPower: W, maxCurrent: A}` | +| `/api/websocket` | GET, POST | `{backendUrl, chargeBoxId, authorizationKey, pingInterval, reconnectInterval}` — configures the simulator's OCPP connection to a CSMS | + +Newer query-param API (plain-text responses, exists but unused by UI): `POST /api/plugin|plugout|end|state|authorize?evse_id=N&...`. You may use these or ignore them. + +Semantics cheat-sheet (J1772): +- `evPlugged` = cable plugged into the car; `evReady` = car requests charge (State C); `evseReady` = charger contactor closed. Charging happens when all three true + transaction authorized. +- Typical happy path: plug in → present idTag (POST transaction) → status Preparing → Charging → present same idTag again or unplug to stop. + +**Allowed API tweaks** (optional, in `src/api.cpp` only): add friendlier alias routes or field names (e.g. `carPlugged`, `carReady`, `chargerReady`, or a combined `GET /connector/{id}/summary` returning evse+meter+transaction in one response to reduce polling). If you rename anything, keep the old routes/fields working — other tools may depend on them. + +## What the current UI is (so you know what you're replacing) + +Six sidebar pages (`webapp-src/src/components/`): +1. **Status** — live cards per connector (1s polling), gradient background by status, three toggle chips (Plugged / EV Ready / EVSE Ready), raw meter numbers. +2. **OCPP 1.6 Connection** — form for backendUrl / chargeBoxId / authorizationKey with manual Fetch/Send buttons. +3. **Station** — station-level config forms. +4. **Connectors** — tabbed per-connector debug panels (EVSE booleans, meter, transaction idTag entry, smart charging), each section with its own Fetch button and success/error alert + timestamp. +5. **Network** — **hardcoded fake demo content** (fake WiFi list). +6. **Security** — CA-cert textarea (real, posts to backend) + **hardcoded fake cipher-suite table**. + +Known problems to NOT carry over: +- Everything is manual-fetch forms; only Status is live. Feels like Postman with CSS. +- Protocol jargon leaks everywhere ("evPlugged", "idTag", "OCPP 1.6 Websocket"). +- Fake demo pages (Network, most of Security) mislead users — drop them or clearly mark real vs. mock, keep only the real CA-cert feature somewhere in a settings area. +- Existing bugs (don't replicate): `Gui.EvseLiveDisplay.js` uses `DateFormatter` without importing it (crashes on POST success path), and the POST omits `evsePlugged`, and compares the response against stale pre-update state. +- 5100-line kube.css for a handful of controls. + +## Design brief + +Build a **single-page, real-time simulator cockpit**. Suggested shape (you have creative freedom, but hit these notes): + +1. **Connector-first layout.** One card/panel per connector showing a visual EV↔charger scene: a car, a cable, a charger. State is communicated visually (cable connected/disconnected, energy-flow animation while Charging, colour-coded status pill using human words: "Available", "Car connected", "Charging", "Paused by car", "Paused by charger", "Fault"). +2. **Actions as scenario verbs, not booleans.** Primary buttons like "Plug in car", "Tap RFID card", "Stop charging", "Unplug" that map onto the boolean POSTs / transaction POST under the hood. Keep an "Advanced" disclosure per connector exposing the three raw toggles and idTag field for power users. +3. **Live telemetry.** Poll the meter and render power as a small live sparkline/chart (rolling ~60s window, canvas or inline SVG — no chart library), energy counter, current, voltage. Numbers formatted for humans (kW / kWh with sensible precision). +4. **Connection status always visible.** A persistent header strip showing the OCPP backend connection (backend URL, charge box ID) with a settings drawer/modal to edit the `/api/websocket` fields and the CA cert. Use plain labels: "Backend server", "Station ID", "Password/Auth key". +5. **Everything auto-refreshes.** No Fetch buttons anywhere. Poll continuously (1s for active connector state, slower for config), show a subtle "live" indicator, and surface network failures as one unobtrusive banner, not per-form alerts. +6. **Look and feel:** modern, clean, dark-mode-friendly (dark default is fine for a tool like this), CSS custom properties for theming, good typography, subtle motion for state transitions. Responsive down to a phone. All icons as inline SVG. + +## Process requirements + +- Work only in `webapp-src/` (and optionally `src/api.cpp`/`api.h` per the rules above). Keep the webpack + `bundle_all.js` pipeline working — you may simplify it, but the output must remain a single `bundle.html.gz` that `build-webapp/build_webapp.sh` places into `public/`. +- You may delete/replace all existing components, CSS, and the kube.css framework entirely. +- After building, verify end-to-end: build the C++ sim (`cmake -S . -B build -DCMAKE_POLICY_VERSION_MINIMUM=3.5 && cmake --build build --target mo_simulator`), run it, open `http://localhost:8000`, and exercise the golden path in a browser: plug in → tap card → observe Charging + live meter → stop → unplug. Also verify both connectors, the settings drawer round-trips `/api/websocket` values, and the UI degrades gracefully when the backend is unreachable. +- If you change `src/api.cpp`, prove old routes still respond identically (curl before/after). + +Start by reading `src/api.cpp`, `webapp-src/src/index.js`, and `webapp-src/deploy/bundle_all.js`, then propose the screen layout before writing code. diff --git a/build-webapp/build_webapp.sh b/build-webapp/build_webapp.sh old mode 100644 new mode 100755 diff --git a/docs/superpowers/plans/2026-07-30-cockpit-ui-port.md b/docs/superpowers/plans/2026-07-30-cockpit-ui-port.md new file mode 100644 index 0000000..e8070ac --- /dev/null +++ b/docs/superpowers/plans/2026-07-30-cockpit-ui-port.md @@ -0,0 +1,1004 @@ +# Cockpit UI Port Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Replace the MicroOcppSimulator web UI with the "OCPP Simulator Cockpit" design (dark HUD, connector bays, scenario verbs, wire trace), wired to the real simulator REST API, shipped through the existing single-file bundle pipeline. + +**Architecture:** Preact app in the `webapp-src/` submodule. A `CockpitStore` (dependency-injected API client, framework-free, unit-tested with `node --test`) polls the simulator every 1s and exposes actions; Preact components render from store state. Webpack inlines fonts as data URLs; `deploy/bundle_all.js` inlines JS+CSS into one `bundle.html`, gzipped to `public/bundle.html.gz` and served by the C++ mongoose server at `/`. + +**Tech Stack:** Preact 10 (already a dependency), webpack 5 (existing config), plain CSS with custom properties, `node:test` for unit tests. No new runtime dependencies. + +## Global Constraints + +- **NO C++ changes.** Nothing under `lib/`, and no edits to `src/*.cpp`, `src/*.h` in the main repo. The API already supports everything needed (partial `POST /connector/{id}/evse` bodies confirmed at `src/api.cpp:87-98`). +- All UI work happens in `/Users/joojodontoh/Documents/PersonalProjects/MicroOcppSimulator/webapp-src/` (its own git repo; `origin` = `Pitvolt/micro-ocpp-dashboard`). Commit there. Main-repo commits only in Task 9. +- Browser-facing API paths are prefixed `/api` (server strips it, `src/net_mongoose.cpp:122-148`). `API_ROOT=/api` in `.env.production`, `http://localhost:8000/api` in `.env.development`. Endpoints used: `GET /connectors`, `GET|POST /connector/{id}/evse`, `GET /connector/{id}/meter`, `GET|POST /connector/{id}/transaction`, `GET /connector/{id}/smartcharging`, `GET|POST /websocket` (full browser path `/api/websocket` — handled before the prefix-strip, same effective URL), `GET|POST /ca_cert` with body `{caCert}`. +- `pingInterval` / `reconnectInterval` are integers in **seconds**. +- `transactionId === -1` means no transaction. Presenting the same `idTag` again via `POST /connector/{id}/transaction` ends the session (server-side toggle). +- There is **no fault-injection endpoint** — the prototype's "INJECT FAULT" button is dropped. `Faulted` status is still rendered if the server reports it. +- Final `public/bundle.html.gz` must be ≤ 150 KB. +- Design reference files (extracted prototype, read-only, delete in Task 9): `webapp-src/design-reference/{ds-components.js, tokens.css, app-shell.jsx, bay.jsx, settings-drawer.jsx, sim-engine.js, michroma-latin.woff2, jetbrains-mono-latin.woff2, ibm-plex-sans-latin.woff2}`. +- **Canonical style source:** the prototype's tokens derive from the Alfred design system at `/Users/joojodontoh/Documents/PersonalProjects/project-alfred/apps/dashboard-web/styles/tokens/{colors,typography,spacing,effects}.css`. Colors and fonts must match it exactly (verified: `design-reference/tokens.css` values are identical). Font stack is non-negotiable: display `Michroma`, body `IBM Plex Sans`, data/readouts `JetBrains Mono` — all three ship inline. +- JSX pragma is `h` / `Fragment` (configured in `webpack_config/webpack.common.js` babel-loader options). Every component file needs `import { h } from "preact"` (plus `Fragment` if used). +- Unit tests run with `node --test tests/` (Node 22 available). Pure logic lives in `.mjs` files with **no JSX and no imports from Preact or DataService** so Node can run them natively. + +## File Structure (end state of `webapp-src/src/`) + +``` +index.js entry — renders into #app +DataService.js KEEP UNCHANGED (fetch wrapper, API_ROOT prefix) +constants.js trimmed to API_ROOT / NODE_ENV exports only +css/tokens.css design tokens + hud utility classes + @font-face (replaces kube/custom/layout/vars.css) +fonts/michroma-latin.woff2 display font (11.6 KB) +fonts/jetbrains-mono-latin.woff2 mono font (31 KB) +fonts/ibm-plex-sans-latin.woff2 body font (40 KB) +lib/status.mjs OCPP status → label/tone mapping (pure) +lib/format.mjs number/time formatting (pure) +store.mjs CockpitStore: state, polling, actions, wire trace (pure, DI) +components/ds.js Button, CornerBracketCard, SectionLabel, TwoPartPrompt, Chip, ConnectionDot, MonoStat, StatusPill, Spark +components/TopStrip.js sticky header strip +components/Trace.js wire-trace event log +components/Bay.js connector bay card (FlowScene, stats, verbs, advanced) +components/SettingsDrawer.js backend link + CA cert drawer +components/App.js cockpit assembly + poll timers +components/icons/ KEEP directory (SVGR imports; unused files add no bundle weight) +``` + +Deleted: `css/kube.css`, `css/custom.css`, `css/layout.css`, `css/vars.css`, `HtmlBuilder.js`, `StyleBuilder.js`, `DateFormatter.js`, `DataService_wasm.js.template` stays (used by wasm build script), all old `components/*.js` except the `icons/` directory, `components/component_styles/`. + +--- + +### Task 1: Workspace reset + design tokens + build plumbing + +**Files:** +- Create: `webapp-src/src/css/tokens.css`, `webapp-src/src/fonts/michroma-latin.woff2`, `webapp-src/src/fonts/jetbrains-mono-latin.woff2`, `webapp-src/src/fonts/ibm-plex-sans-latin.woff2` +- Modify: `webapp-src/webpack_config/webpack.common.js`, `webapp-src/public/index.html`, `webapp-src/src/index.js`, `webapp-src/src/constants.js`, `webapp-src/package.json` +- Delete: old css files, old components (see File Structure above) + +**Interfaces:** +- Produces: `css/tokens.css` custom properties (`--bg-0`, `--gold`, `--font-mono`, `--sp-1..8`, `--fs-micro/caption/small/body/lead/hero/metric`, `--dur-fast`, `--ease-hud`, `--glow-gold/red/ice`, `--strip-h`, `--bracket`, `--ls-label`, `--fw-medium/semibold`) and classes `.hud-clip`, `.hud-display`, `.hud-decode`, `.hud-grid-bg`, `.flow-bar`, `.live-dot`, `.trace` — all later components rely on these names exactly. + +- [ ] **Step 1: Create a work branch in webapp-src** + +```bash +cd webapp-src && git checkout -b cockpit-redesign +``` + +- [ ] **Step 2: Delete old UI files** + +```bash +cd webapp-src +git rm src/css/kube.css src/css/custom.css src/css/layout.css src/css/vars.css \ + src/HtmlBuilder.js src/StyleBuilder.js src/DateFormatter.js +git rm -r src/components/component_styles +cd src/components && git rm $(ls *.js) && cd ../.. +``` +(Keep `src/components/icons/`. Keep `DataService.js`, `DataService_wasm.js.template`.) + +- [ ] **Step 3: Create tokens.css** + +Copy the entire contents of `webapp-src/design-reference/tokens.css` (the four `:root` blocks and `.hud-*` classes extracted from the prototype) into `webapp-src/src/css/tokens.css`, then **prepend** these `@font-face` rules and **append** the app-level styles: + +Prepend: +```css +@font-face { + font-family: "Michroma"; + font-style: normal; font-weight: 400; font-display: swap; + src: url("../fonts/michroma-latin.woff2") format("woff2"); +} +@font-face { + font-family: "JetBrains Mono"; + font-style: normal; font-weight: 400 700; font-display: swap; + src: url("../fonts/jetbrains-mono-latin.woff2") format("woff2"); +} +@font-face { + font-family: "IBM Plex Sans"; + font-style: normal; font-weight: 400 600; font-display: swap; + src: url("../fonts/ibm-plex-sans-latin.woff2") format("woff2"); +} +``` + +Append: +```css +html, body { height: 100%; } +body { margin: 0; background: var(--bg-0); overflow-x: hidden; } +#app { min-height: 100vh; } +a { color: var(--ice); text-decoration: none; } +a:hover { color: var(--gold); } +@keyframes flow { 0% { opacity: .18 } 45% { opacity: 1 } 100% { opacity: .18 } } +.flow-bar { animation: flow 1.15s var(--ease-hud) infinite; } +@keyframes livepulse { 0%, 100% { opacity: .35 } 50% { opacity: 1 } } +.live-dot { animation: livepulse 1.6s ease-in-out infinite; } +@media (prefers-reduced-motion: reduce) { .flow-bar, .live-dot { animation: none } } +@media (max-width: 1000px) { .strip-min { display: none !important } } +.trace::-webkit-scrollbar { width: 8px; } +.trace::-webkit-scrollbar-thumb { background: var(--hairline-strong); } +button { font: inherit; } +``` + +Do **not** alter any token values — fonts and colors must stay exactly as in the reference: `--font-display: "Michroma", "Arial Black", sans-serif`, `--font-body: "IBM Plex Sans", system-ui, sans-serif`, `--font-mono: "JetBrains Mono", "SFMono-Regular", monospace`. Remove any `@font-face` blocks that came along in the copy (the reference file should include none — verify). + +Fidelity check against the canonical Alfred tokens: +```bash +diff <(grep -o '\-\-[a-z0-9-]*:[^;]*;' src/css/tokens.css | sort -u) \ + <(cat "/Users/joojodontoh/Documents/PersonalProjects/project-alfred/apps/dashboard-web/styles/tokens/"{colors,typography,spacing,effects}.css | grep -o '\-\-[a-z0-9-]*:[^;]*;' | sort -u) +``` +Expected: only additions on the Alfred side (extended categorical palette `--coral/--teal/--violet/--magenta/--lime/--steel/--rose`, `--fs-data`, `--hud-panel-h`) and the prototype-local `--bk` helper plus the three `@font-face` families on ours. **No value differences on any shared variable.** + +- [ ] **Step 4: Add fonts** + +```bash +cd webapp-src && mkdir -p src/fonts +cp design-reference/michroma-latin.woff2 src/fonts/ +cp design-reference/jetbrains-mono-latin.woff2 src/fonts/ +cp design-reference/ibm-plex-sans-latin.woff2 src/fonts/ +``` + +- [ ] **Step 5: Inline fonts in webpack** + +In `webapp-src/webpack_config/webpack.common.js`, add this rule **before** the existing `file-loader` rule (which matches woff but not woff2): + +```js +{ + test: /\.woff2$/, + type: "asset/inline", +}, +``` + +- [ ] **Step 6: Update the HTML shell** + +Replace the `` and theme-color lines in `webapp-src/public/index.html`: + +```html +<title>MicroOCPP Simulator — Cockpit + +``` +(Remove both old `theme-color` lines; keep `
`, the `main.js` script tag, and both `` comments exactly as they are — `bundle_all.js` depends on them.) + +- [ ] **Step 7: Stub the entry point** + +Replace `webapp-src/src/index.js` with: + +```js +import { h, render } from "preact"; +import "./css/tokens.css"; + +render(
COCKPIT BOOT
, document.getElementById("app")); +``` + +Replace `webapp-src/src/constants.js` with: + +```js +const API_ROOT = process.env.API_ROOT; +const NODE_ENV = process.env.NODE_ENV; + +export { API_ROOT, NODE_ENV }; +``` + +- [ ] **Step 8: Add unit-test script** + +In `webapp-src/package.json` scripts, replace `"test": "jest --watch"` with: + +```json +"test": "node --test tests/" +``` +(jest was never installed; no tests exist yet — `tests/` arrives in Task 2.) + +- [ ] **Step 9: Verify production build compiles** + +Run: `cd webapp-src && npm install && npm run build && npm run compress` +Expected: webpack exits 0, `dist/bundle.html.gz` produced. Open `dist/bundle.html` and confirm it contains `COCKPIT BOOT` and an inlined `data:font/woff2` URL. + +- [ ] **Step 10: Commit** + +```bash +cd webapp-src && git add -A && git commit -m "feat: reset UI shell — cockpit tokens, inline fonts, new entry" +``` + +--- + +### Task 2: Pure logic — status mapping and formatting + +**Files:** +- Create: `webapp-src/src/lib/status.mjs`, `webapp-src/src/lib/format.mjs` +- Test: `webapp-src/tests/status.test.mjs`, `webapp-src/tests/format.test.mjs` + +**Interfaces:** +- Produces: `statusLabel(status) -> [text, tone]`, `PILL_TONE` map, `isActiveStatus(status) -> bool`; `kw(watts) -> string`, `kwh(wattHours) -> string`, `amps(a) -> string`, `volts(v) -> string`, `pad2(n) -> string`, `stamp() -> "HH:MM:SS"`. Tones are one of `"text" | "green" | "amber" | "red" | "ice"`. + +- [ ] **Step 1: Write failing tests** + +`webapp-src/tests/status.test.mjs`: +```js +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { statusLabel, PILL_TONE, isActiveStatus } from "../src/lib/status.mjs"; + +test("known OCPP statuses map to human labels and tones", () => { + assert.deepEqual(statusLabel("Available"), ["AVAILABLE", "text"]); + assert.deepEqual(statusLabel("Preparing"), ["CAR CONNECTED", "ice"]); + assert.deepEqual(statusLabel("Charging"), ["CHARGING", "green"]); + assert.deepEqual(statusLabel("SuspendedEV"), ["PAUSED BY CAR", "amber"]); + assert.deepEqual(statusLabel("SuspendedEVSE"), ["PAUSED BY CHARGER", "amber"]); + assert.deepEqual(statusLabel("Finishing"), ["SESSION ENDING", "ice"]); + assert.deepEqual(statusLabel("Faulted"), ["FAULT", "red"]); +}); + +test("unknown status falls back to uppercase text tone", () => { + assert.deepEqual(statusLabel("Reserved"), ["RESERVED", "text"]); + assert.deepEqual(statusLabel(""), ["UNKNOWN", "text"]); + assert.deepEqual(statusLabel(undefined), ["UNKNOWN", "text"]); +}); + +test("tone → StatusPill palette mapping is total", () => { + for (const tone of ["text", "green", "amber", "red", "ice"]) { + assert.ok(PILL_TONE[tone], `missing ${tone}`); + } +}); + +test("isActiveStatus true only while energy can flow", () => { + assert.equal(isActiveStatus("Charging"), true); + assert.equal(isActiveStatus("Available"), false); + assert.equal(isActiveStatus("Faulted"), false); +}); +``` + +`webapp-src/tests/format.test.mjs`: +```js +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { kw, kwh, amps, volts, pad2, stamp } from "../src/lib/format.mjs"; + +test("power formats W → kW with 2 decimals", () => { + assert.equal(kw(7400), "7.40"); + assert.equal(kw(0), "0.00"); +}); + +test("energy formats Wh → kWh with 3 decimals", () => { + assert.equal(kwh(1234), "1.234"); +}); + +test("current and voltage format with 1 decimal", () => { + assert.equal(amps(16.04), "16.0"); + assert.equal(volts(229.96), "230.0"); +}); + +test("pad2 zero-pads", () => { + assert.equal(pad2(3), "03"); + assert.equal(pad2(12), "12"); +}); + +test("stamp is HH:MM:SS", () => { + assert.match(stamp(), /^\d{2}:\d{2}:\d{2}$/); +}); +``` + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `cd webapp-src && npm test` +Expected: FAIL — cannot find `../src/lib/status.mjs`. + +- [ ] **Step 3: Implement** + +`webapp-src/src/lib/status.mjs`: +```js +export const STATUS_LABEL = { + Available: ["AVAILABLE", "text"], + Preparing: ["CAR CONNECTED", "ice"], + Charging: ["CHARGING", "green"], + SuspendedEV: ["PAUSED BY CAR", "amber"], + SuspendedEVSE: ["PAUSED BY CHARGER", "amber"], + Finishing: ["SESSION ENDING", "ice"], + Faulted: ["FAULT", "red"], +}; + +// tone key → StatusPill palette name (ds.js StatusPill TONES) +export const PILL_TONE = { text: "OFFLINE", green: "ONLINE", amber: "PENDING", red: "ERROR", ice: "APPROVED" }; + +export function statusLabel(status) { + if (!status) return ["UNKNOWN", "text"]; + return STATUS_LABEL[status] || [String(status).toUpperCase(), "text"]; +} + +export function isActiveStatus(status) { + return status === "Charging"; +} +``` + +`webapp-src/src/lib/format.mjs`: +```js +export const kw = (w) => (w / 1000).toFixed(2); +export const kwh = (wh) => (wh / 1000).toFixed(3); +export const amps = (a) => Number(a).toFixed(1); +export const volts = (v) => Number(v).toFixed(1); +export const pad2 = (n) => String(n).padStart(2, "0"); + +export function stamp() { + const d = new Date(); + return [d.getHours(), d.getMinutes(), d.getSeconds()].map(pad2).join(":"); +} +``` + +- [ ] **Step 4: Run tests to verify they pass** + +Run: `cd webapp-src && npm test` +Expected: all tests PASS. + +- [ ] **Step 5: Commit** + +```bash +cd webapp-src && git add src/lib tests && git commit -m "feat: status/format pure modules with node:test coverage" +``` + +--- + +### Task 3: CockpitStore — polling, actions, wire trace + +**Files:** +- Create: `webapp-src/src/store.mjs` +- Test: `webapp-src/tests/store.test.mjs` + +**Interfaces:** +- Consumes: `stamp` from `lib/format.mjs`. API client shape `{ get(path) -> Promise, post(path, body) -> Promise }` (matches `DataService.js`). +- Produces: `class CockpitStore { constructor(api); state; subscribe(fn); init(); pollFast(); pollSlow(); plugIn(id); unplug(id); tapCard(id, idTag); endSession(id); toggle(id, key); saveBackend(form); loadCert(); saveCert(pem); }` + - `state = { connectors: [...], backend: {backendUrl, chargeBoxId, authorizationKey, pingInterval, reconnectInterval}, link: "init"|"ok"|"down", log: [{t, cid, line, tone}] }` + - Connector shape: `{ id: string, evPlugged, evsePlugged, evReady, evseReady: bool, chargePointStatus: string, transactionId: number, idTag: string, energy, power, current, voltage: number, maxPower, maxCurrent: number, history: number[60] }` + +- [ ] **Step 1: Write failing tests** + +`webapp-src/tests/store.test.mjs`: +```js +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { CockpitStore } from "../src/store.mjs"; + +function fakeApi(routes = {}) { + const calls = []; + return { + calls, + get(path) { + calls.push(["GET", path]); + if (path in routes) return Promise.resolve(routes[path]); + return Promise.reject(new Error("no route " + path)); + }, + post(path, body) { + calls.push(["POST", path, body]); + if (path in routes) return Promise.resolve({ ...routes[path], ...body }); + return Promise.reject(new Error("no route " + path)); + }, + }; +} + +const baseRoutes = () => ({ + "/connectors": ["1", "2"], + "/websocket": { backendUrl: "ws://x", chargeBoxId: "CB01", authorizationKey: "", pingInterval: 5, reconnectInterval: 30 }, + "/connector/1/evse": { evPlugged: false, evsePlugged: true, evReady: false, evseReady: false, chargePointStatus: "Available" }, + "/connector/2/evse": { evPlugged: false, evsePlugged: true, evReady: false, evseReady: false, chargePointStatus: "Available" }, + "/connector/1/meter": { energy: 100, power: 7400, current: 10.7, voltage: 230.1 }, + "/connector/2/meter": { energy: 0, power: 0, current: 0, voltage: 229.8 }, + "/connector/1/transaction": { idTag: "", transactionId: -1 }, + "/connector/2/transaction": { idTag: "", transactionId: -1 }, + "/connector/1/smartcharging": { maxPower: 11000, maxCurrent: 16 }, + "/connector/2/smartcharging": { maxPower: 11000, maxCurrent: 16 }, +}); + +test("init seeds connectors from /connectors and loads backend config", async () => { + const store = new CockpitStore(fakeApi(baseRoutes())); + await store.init(); + assert.equal(store.state.connectors.length, 2); + assert.equal(store.state.connectors[0].id, "1"); + assert.equal(store.state.backend.chargeBoxId, "CB01"); +}); + +test("pollFast merges evse/meter/transaction, pushes power history, sets link ok", async () => { + const store = new CockpitStore(fakeApi(baseRoutes())); + await store.init(); + await store.pollFast(); + const c = store.state.connectors[0]; + assert.equal(c.power, 7400); + assert.equal(c.chargePointStatus, "Available"); + assert.equal(c.history.length, 60); + assert.equal(c.history[59], 7400); + assert.equal(store.state.link, "ok"); +}); + +test("pollFast failure flips link to down and logs once; recovery logs restore", async () => { + const routes = baseRoutes(); + const api = fakeApi(routes); + const store = new CockpitStore(api); + await store.init(); + await store.pollFast(); + const good = routes["/connector/1/evse"]; + delete routes["/connector/1/evse"]; + await store.pollFast(); + assert.equal(store.state.link, "down"); + const downLogs = store.state.log.filter((l) => l.line.includes("POLL FAILED")); + assert.equal(downLogs.length, 1); + routes["/connector/1/evse"] = good; + await store.pollFast(); + assert.equal(store.state.link, "ok"); + assert.ok(store.state.log.some((l) => l.line.includes("LINK RESTORED"))); +}); + +test("plugIn posts partial evse body and merges the response", async () => { + const api = fakeApi(baseRoutes()); + const store = new CockpitStore(api); + await store.init(); + await store.plugIn("1"); + const post = api.calls.find(([m, p]) => m === "POST" && p === "/connector/1/evse"); + assert.deepEqual(post[2], { evPlugged: true, evReady: true }); + assert.equal(store.state.connectors[0].evPlugged, true); +}); + +test("unplug posts all-off body", async () => { + const api = fakeApi(baseRoutes()); + const store = new CockpitStore(api); + await store.init(); + await store.unplug("1"); + const post = api.calls.find(([m, p]) => m === "POST" && p === "/connector/1/evse"); + assert.deepEqual(post[2], { evPlugged: false, evReady: false, evseReady: false }); +}); + +test("tapCard posts idTag; endSession re-presents the current session tag", async () => { + const routes = baseRoutes(); + const api = fakeApi(routes); + const store = new CockpitStore(api); + await store.init(); + await store.tapCard("1", "D7A4-0001"); + let post = api.calls.filter(([m, p]) => m === "POST" && p === "/connector/1/transaction"); + assert.deepEqual(post[0][2], { idTag: "D7A4-0001" }); + store.state.connectors[0].idTag = "D7A4-0001"; + store.state.connectors[0].transactionId = 1181; + await store.endSession("1"); + post = api.calls.filter(([m, p]) => m === "POST" && p === "/connector/1/transaction"); + assert.deepEqual(post[1][2], { idTag: "D7A4-0001" }); +}); + +test("toggle flips a single evse boolean via partial POST", async () => { + const api = fakeApi(baseRoutes()); + const store = new CockpitStore(api); + await store.init(); + await store.toggle("1", "evseReady"); + const post = api.calls.find(([m, p]) => m === "POST" && p === "/connector/1/evse"); + assert.deepEqual(post[2], { evseReady: true }); +}); + +test("saveBackend coerces intervals to ints and posts /websocket", async () => { + const api = fakeApi(baseRoutes()); + const store = new CockpitStore(api); + await store.init(); + await store.saveBackend({ backendUrl: "ws://y", chargeBoxId: "CB02", authorizationKey: "k", pingInterval: "7", reconnectInterval: "20" }); + const post = api.calls.find(([m, p]) => m === "POST" && p === "/websocket"); + assert.equal(post[2].pingInterval, 7); + assert.equal(post[2].reconnectInterval, 20); + assert.equal(store.state.backend.chargeBoxId, "CB02"); +}); + +test("actions append wire-trace entries, capped at 60", async () => { + const api = fakeApi(baseRoutes()); + const store = new CockpitStore(api); + await store.init(); + for (let i = 0; i < 70; i++) store.trace("1", "line " + i, "text"); + assert.equal(store.state.log.length, 60); + await store.plugIn("1"); + assert.ok(store.state.log[0].line.includes("POST /connector/1/evse")); +}); +``` + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `cd webapp-src && npm test` +Expected: FAIL — cannot find `../src/store.mjs`. + +- [ ] **Step 3: Implement store.mjs** + +`webapp-src/src/store.mjs`: +```js +import { stamp } from "./lib/format.mjs"; + +const HISTORY_LEN = 60; +const LOG_CAP = 60; + +export function makeConnector(id) { + return { + id: String(id), + evPlugged: false, evsePlugged: true, evReady: false, evseReady: false, + chargePointStatus: "", + transactionId: -1, idTag: "", + energy: 0, power: 0, current: 0, voltage: 0, + maxPower: 11000, maxCurrent: 16, + history: new Array(HISTORY_LEN).fill(0), + }; +} + +export class CockpitStore { + constructor(api) { + this.api = api; + this.state = { + connectors: [], + backend: { backendUrl: "", chargeBoxId: "", authorizationKey: "", pingInterval: 0, reconnectInterval: 30 }, + link: "init", + log: [], + }; + this.listeners = new Set(); + this.polling = false; + } + + subscribe(fn) { this.listeners.add(fn); return () => this.listeners.delete(fn); } + emit() { for (const fn of this.listeners) fn(); } + + trace(cid, line, tone = "text") { + this.state.log.unshift({ t: stamp(), cid, line, tone }); + if (this.state.log.length > LOG_CAP) this.state.log.length = LOG_CAP; + this.emit(); + } + + connector(id) { return this.state.connectors.find((c) => c.id === String(id)); } + + markLink(ok) { + const prev = this.state.link; + const next = ok ? "ok" : "down"; + if (prev === next) return; + this.state.link = next; + if (next === "down") this.trace(0, "POLL FAILED · SIMULATOR UNREACHABLE", "red"); + else if (prev === "down") this.trace(0, "LINK RESTORED · POLLING RESUMED", "green"); + this.emit(); + } + + async init() { + const ids = await this.api.get("/connectors"); + this.state.connectors = ids.map(makeConnector); + try { await this.loadBackend(); } catch (e) { /* backend config panel shows blanks */ } + this.emit(); + } + + async loadBackend() { + const cfg = await this.api.get("/websocket"); + this.state.backend = { ...this.state.backend, ...cfg }; + this.emit(); + } + + async pollFast() { + if (this.polling || this.state.connectors.length === 0) return; + this.polling = true; + try { + await Promise.all(this.state.connectors.map(async (c) => { + const [evse, meter, txn] = await Promise.all([ + this.api.get(`/connector/${c.id}/evse`), + this.api.get(`/connector/${c.id}/meter`), + this.api.get(`/connector/${c.id}/transaction`), + ]); + Object.assign(c, evse, meter, { + idTag: txn.idTag || "", + transactionId: typeof txn.transactionId === "number" ? txn.transactionId : -1, + }); + c.history.push(c.power || 0); + if (c.history.length > HISTORY_LEN) c.history.shift(); + })); + this.markLink(true); + } catch (e) { + this.markLink(false); + } finally { + this.polling = false; + this.emit(); + } + } + + async pollSlow() { + try { + await Promise.all(this.state.connectors.map(async (c) => { + const sc = await this.api.get(`/connector/${c.id}/smartcharging`); + c.maxPower = sc.maxPower ?? c.maxPower; + c.maxCurrent = sc.maxCurrent ?? c.maxCurrent; + })); + this.emit(); + } catch (e) { /* smartcharging is cosmetic; fast poll owns link state */ } + } + + async postEvse(id, body) { + const c = this.connector(id); + try { + const resp = await this.api.post(`/connector/${id}/evse`, body); + Object.assign(c, resp); + this.trace(id, `POST /connector/${id}/evse ${JSON.stringify(body)} → 200`, "ice"); + } catch (e) { + this.trace(id, `POST /connector/${id}/evse FAILED`, "red"); + } + this.emit(); + } + + plugIn(id) { return this.postEvse(id, { evPlugged: true, evReady: true }); } + unplug(id) { return this.postEvse(id, { evPlugged: false, evReady: false, evseReady: false }); } + toggle(id, key) { + const c = this.connector(id); + return this.postEvse(id, { [key]: !c[key] }); + } + + async tapCard(id, idTag) { + const c = this.connector(id); + try { + const resp = await this.api.post(`/connector/${id}/transaction`, { idTag }); + c.idTag = resp.idTag ?? c.idTag; + if (typeof resp.transactionId === "number") c.transactionId = resp.transactionId; + this.trace(id, `POST /connector/${id}/transaction {idTag:"${idTag}"} → 200`, "green"); + } catch (e) { + this.trace(id, `POST /connector/${id}/transaction FAILED`, "red"); + } + this.emit(); + } + + endSession(id) { + const c = this.connector(id); + return this.tapCard(id, c.idTag); + } + + async saveBackend(form) { + const body = { + backendUrl: form.backendUrl, + chargeBoxId: form.chargeBoxId, + authorizationKey: form.authorizationKey, + pingInterval: parseInt(form.pingInterval, 10) || this.state.backend.pingInterval, + reconnectInterval: parseInt(form.reconnectInterval, 10) || this.state.backend.reconnectInterval, + }; + const resp = await this.api.post("/websocket", body); + this.state.backend = { ...this.state.backend, ...resp }; + this.trace(0, `POST /api/websocket {chargeBoxId:"${body.chargeBoxId}"} → 200 · RECONNECTING`, "gold"); + this.emit(); + } + + async loadCert() { + const resp = await this.api.get("/ca_cert"); + return resp.caCert || ""; + } + + async saveCert(pem) { + await this.api.post("/ca_cert", { caCert: pem }); + this.trace(0, "POST /api/ca_cert → 200 · CERTIFICATE UPDATED", "gold"); + this.emit(); + } +} +``` + +- [ ] **Step 4: Run tests to verify they pass** + +Run: `cd webapp-src && npm test` +Expected: all tests PASS (status, format, store). + +- [ ] **Step 5: Commit** + +```bash +cd webapp-src && git add src/store.mjs tests/store.test.mjs && git commit -m "feat: CockpitStore polling engine and actions with DI tests" +``` + +--- + +### Task 4: Design-system primitives (`ds.js`) + +**Files:** +- Create: `webapp-src/src/components/ds.js` + +**Interfaces:** +- Consumes: CSS variables/classes from `tokens.css`. +- Produces (named exports, Preact): `Button({variant, size, clip, disabled, onClick, style, children})`, `CornerBracketCard({selected, tone, clip, padding, style, children})`, `SectionLabel({label, action, color, style})`, `TwoPartPrompt({label, action, tone, filled, onClick, disabled, style})`, `Chip({label, tone, style})`, `ConnectionDot({label, status, style})`, `MonoStat({value, label, unit, tone, size, align, style})`, `StatusPill({status, tone, dot, style})`, `Spark({data, max})`, plus shared style objects `LABEL` and `MONO`. + +- [ ] **Step 1: Port the primitives** + +Port each component in `webapp-src/design-reference/ds-components.js` from `React.createElement` calls to Preact JSX (`import { h, Fragment } from "preact"; import { useState } from "preact/hooks";`). Rules for the port: +- Keep every style object, tone table, and prop default **byte-identical** to the reference — this is a faithful port, not a redesign. +- `className` → keep as `className` (Preact accepts it). +- Drop the `__ds_scope` / try-catch wrappers; use `export function`. +- Add `Spark` and the shared label styles (used by Bay/Trace/TopStrip/SettingsDrawer), source `design-reference/bay.jsx` lines 5-19: + +```js +export const LABEL = { fontFamily: "var(--font-mono)", fontSize: "var(--fs-micro)", textTransform: "uppercase", letterSpacing: "var(--ls-label)", color: "var(--text-2)" }; +export const MONO = { fontFamily: "var(--font-mono)", fontVariantNumeric: "tabular-nums" }; + +export function Spark({ data, max }) { + const w = 100, h2 = 30; + const peak = Math.max(max * 0.25, ...data) || 1; + const pts = data.map((v, i) => `${(i / (data.length - 1)) * w},${h2 - (v / peak) * h2}`).join(" "); + return ( + + + + + ); +} +``` + +- [ ] **Step 2: Smoke-render in the entry stub** + +Temporarily extend `src/index.js` to render one of each primitive (a `CornerBracketCard` containing `StatusPill status="CHARGING" tone="ONLINE"`, a `TwoPartPrompt label="BAY 1" action="PLUG IN CAR"`, a `MonoStat value="7.40" unit="KW" label="POWER"`, a `Spark data={[0,2,5,3,8]} max={10}`). Run `npm run dev` (dev server opens on a local port) and visually confirm: dark page, gold clipped buttons, bracket corners on `selected`, mono uppercase labels, Michroma renders on `.hud-display`. + +- [ ] **Step 3: Verify production build still compiles** + +Run: `cd webapp-src && npm run build` +Expected: exit 0. + +- [ ] **Step 4: Commit** (leave the smoke-render in place; Task 7 replaces `index.js` anyway) + +```bash +cd webapp-src && git add src/components/ds.js src/index.js && git commit -m "feat: port HUD design-system primitives to Preact" +``` + +--- + +### Task 5: TopStrip, Trace, Bay + +**Files:** +- Create: `webapp-src/src/components/TopStrip.js`, `webapp-src/src/components/Trace.js`, `webapp-src/src/components/Bay.js` + +**Interfaces:** +- Consumes: `ds.js` exports; `statusLabel`, `PILL_TONE`, `isActiveStatus` from `../lib/status.mjs`; `kw`, `kwh`, `amps`, `volts`, `pad2`, `stamp` from `../lib/format.mjs`; store instance via props. +- Produces: `TopStrip({ store, onSettings })`, `Trace({ log })`, `Bay({ store, c })` — where `c` is a connector object from `store.state.connectors`. + +- [ ] **Step 1: Port TopStrip and Trace** + +Port from `design-reference/app-shell.jsx` (functions `TopStrip` and `Trace`) with these changes: +- `S.state.backend` → `store.state.backend`; `down` → `store.state.link === "down"`; `S.stamp()` → `stamp()`. +- The `ri-settings-3-line` icon → import the existing SVGR icon: `import IControls from "./icons/IControls.svg";` rendered at 13px. +- The METER ConnectionDot status: `store.state.link === "ok" ? "ok" : "error"`. +- Brand text: `MICROOCPP SIM` + gold dot; subtitle `OCPP 1.6J CHARGE POINT`. +- Everything else (layout, styles, LIVE · 1S pulse dot, strip-min responsive class) byte-identical. + +- [ ] **Step 2: Port Bay** + +Port from `design-reference/bay.jsx` with these changes: +1. Props are `{ store, c }`; every `act(() => S.xxx(c))` becomes a direct `store.xxx(c.id)` call (the store emits — no `bump` prop). +2. `const status = c.chargePointStatus;` (server truth, not client derivation) and `const [text, tone] = statusLabel(status); const charging = isActiveStatus(status);` +3. `FlowScene` icons: `import IEvseIcon from "./icons/IEvseIcon.svg";` for the charger, `import IEv from "./icons/IEv.svg";` for the car (render ~34px via width/height props or wrapping span with `display:flex`). Keep the 16 flow bars and wire-color logic identical. +4. Stats row: ``, `value={kwh(c.energy)} unit="KWH" label="ENERGY"`, `value={amps(c.current)} unit="A" label="CURRENT"`, `value={volts(c.voltage)} unit="V" label="VOLTAGE"`. +5. Verb logic identical: `!c.evPlugged` → `TwoPartPrompt label={"BAY " + c.id} action="PLUG IN CAR"` calling `store.plugIn(c.id)`; else if `c.transactionId < 0` → `action="TAP RFID CARD"` calling `store.tapCard(c.id, tag)`; else → `label={"TXN " + c.transactionId} action="STOP CHARGING" tone="amber"` calling `store.endSession(c.id)`. `UNPLUG` outline button when plugged. +6. **Remove** the `INJECT FAULT` button (no endpoint). Keep `ADVANCED` toggle. +7. Advanced panel: four `Toggle`s — `EVPLUGGED`, `EVSEPLUGGED`, `EVREADY`, `EVSEREADY` — each calling `store.toggle(c.id, key)`; the idTag input (local `useState`, default `"D7A4-1180"`) + `AUTHORISE` button calling `store.tapCard(c.id, tag)`; readout line shows `CHARGEPOINTSTATUS {status || "—"}`, `TRANSACTIONID {c.transactionId}`, `MAXCURRENT {c.maxCurrent} A`. +8. Header right side: `TYPE 2 · {kw(c.maxPower)} KW LIMIT` (was `.toFixed(1)` of kW — use `(c.maxPower/1000).toFixed(1)` to stay identical to the prototype). +9. `PEAK {kw(Math.max(...c.history))} KW` above ``. + +- [ ] **Step 3: Compile check** + +Run: `cd webapp-src && npm run build` +Expected: exit 0. (Visual verification happens in Task 7 with the full app.) + +- [ ] **Step 4: Commit** + +```bash +cd webapp-src && git add src/components/TopStrip.js src/components/Trace.js src/components/Bay.js && git commit -m "feat: port TopStrip, Trace, Bay to Preact wired to CockpitStore" +``` + +--- + +### Task 6: SettingsDrawer + +**Files:** +- Create: `webapp-src/src/components/SettingsDrawer.js` + +**Interfaces:** +- Consumes: `SectionLabel`, `Button`, `Chip`, `ConnectionDot`, `LABEL`, `MONO` from `ds.js`; `stamp` from `../lib/format.mjs`; store via props. +- Produces: `SettingsDrawer({ store, open, onClose })`. + +- [ ] **Step 1: Port from `design-reference/settings-drawer.jsx`** + +Changes from the reference: +1. On `open` becoming true: `setForm({ ...store.state.backend })`, `setSaved(false)`, and `store.loadCert().then(setCert).catch(() => {})` (`useEffect` on `[open]`). +2. `save()` becomes async: `await store.saveBackend(form)`; then `if (certDirty) await store.saveCert(cert);` then `setSaved(true)`. Track `certDirty` with a boolean set in the cert field's onChange. Wrap in try/catch — on failure render `SAVE FAILED` in `var(--red)` instead of the `WRITTEN · {stamp()}` confirmation. +3. **Remove** the DIAGNOSTICS section entirely (`SIMULATE LINK LOSS` was mock-only; link state now comes from real poll failures). +4. `ConnectionDot` in the BACKEND LINK header: `status={store.state.link === "ok" ? "ok" : "error"}`. +5. Field labels/hints identical: `BACKEND SERVER`, `STATION ID`, `AUTH KEY`, `PING (S)`, `RECONNECT (S)`, `CA CERTIFICATE` with hint `PEM, POSTED TO THE SIMULATOR ON SAVE`, chip `REAL` → change chip to `LIVE` tone green. +6. Footer button: `SAVE & RECONNECT` (`Button clip`). + +- [ ] **Step 2: Compile check** + +Run: `cd webapp-src && npm run build` +Expected: exit 0. + +- [ ] **Step 3: Commit** + +```bash +cd webapp-src && git add src/components/SettingsDrawer.js && git commit -m "feat: port settings drawer with live websocket + ca_cert round-trip" +``` + +--- + +### Task 7: App assembly + end-to-end browser verification + +**Files:** +- Create: `webapp-src/src/components/App.js` +- Modify: `webapp-src/src/index.js` + +**Interfaces:** +- Consumes: everything above; `DataService` from `../DataService`. +- Produces: `App({ store })` — the complete cockpit. + +- [ ] **Step 1: Write App.js** + +Port the `Cockpit` function from `design-reference/app-shell.jsx`: + +```js +import { h } from "preact"; +import { useEffect, useReducer, useState } from "preact/hooks"; +import TopStrip from "./TopStrip"; +import Trace from "./Trace"; +import Bay from "./Bay"; +import SettingsDrawer from "./SettingsDrawer"; +import { MonoStat, Chip, LABEL, MONO } from "./ds"; +import { isActiveStatus } from "../lib/status.mjs"; +import { kw, pad2 } from "../lib/format.mjs"; +import IForbidden from "./icons/IForbidden.svg"; + +export default function App({ store }) { + const [, bump] = useReducer((n) => n + 1, 0); + const [open, setOpen] = useState(false); + + useEffect(() => { + const unsub = store.subscribe(bump); + store.init().then(() => store.pollFast()).catch(() => store.markLink(false)); + const fast = setInterval(() => store.pollFast(), 1000); + const slow = setInterval(() => store.pollSlow(), 5000); + return () => { unsub(); clearInterval(fast); clearInterval(slow); }; + }, []); + + const cs = store.state.connectors; + const down = store.state.link === "down"; + const active = cs.filter((c) => isActiveStatus(c.chargePointStatus)).length; + const total = cs.reduce((a, c) => a + (c.power || 0), 0); + const energy = cs.reduce((a, c) => a + (c.energy || 0), 0); + + return ( +
+ setOpen(true)} /> + {down && ( +
+ + + SIMULATOR UNREACHABLE · SHOWING LAST KNOWN STATE · RETRYING EVERY 1S + +
+ )} +
+
+
+

CHARGE BAYS

+ {pad2(cs.length)} SIMULATED CONNECTORS + {active > 0 && } +
+
+ + + +
+
+
+ {cs.map((c) => )} +
+ +
+ setOpen(false)} /> +
+ ); +} +``` + +- [ ] **Step 2: Rewrite index.js** + +```js +import { h, render } from "preact"; +import "./css/tokens.css"; +import App from "./components/App"; +import DataService from "./DataService"; +import { CockpitStore } from "./store.mjs"; + +render(, document.getElementById("app")); +``` + +- [ ] **Step 3: Build and run the real simulator** + +```bash +cd /Users/joojodontoh/Documents/PersonalProjects/MicroOcppSimulator +cmake -S . -B build -DCMAKE_POLICY_VERSION_MINIMUM=3.5 +cmake --build build -j 8 --target mo_simulator +./build/mo_simulator & +``` +Verify API up: `curl -s http://localhost:8000/api/connectors` → `["1","2"]`. + +- [ ] **Step 4: Golden-path browser verification (dev server)** + +Run `cd webapp-src && npm run dev` (proxies to `http://localhost:8000/api` via `.env.development`). In the browser verify, in order: +1. Two bays render, status pills say AVAILABLE, TopStrip shows backend URL + charge box ID fetched from `/api/websocket`, LIVE · 1S pulses. +2. Click **PLUG IN CAR** on bay 1 → pill → CAR CONNECTED (Preparing), wire trace logs the POST. +3. Click **TAP RFID CARD** → within a few seconds pill → CHARGING, power climbs to ~11 kW, sparkline draws, SITE DRAW updates. (OCPP transaction needs the backend link; with the default echo server the simulator still starts transactions locally.) +4. Click **STOP CHARGING** → power ramps to 0, transaction id disappears. +5. Click **UNPLUG** → AVAILABLE. +6. ADVANCED: toggle EVREADY off during a charge → PAUSED BY CAR. +7. SETUP drawer: values round-trip (change STATION ID, save, reopen → persisted; `curl -s http://localhost:8000/api/websocket` confirms). +8. Kill the simulator (`kill %1`) → red SIMULATOR UNREACHABLE banner within ~2s, NO POLL in strip; restart it → banner clears, LINK RESTORED in trace. +9. Narrow the window to ~380px — bays stack, strip-min elements hide. + +Fix anything broken before proceeding. This step is the acceptance gate for the whole port. + +- [ ] **Step 5: Run unit tests** + +Run: `cd webapp-src && npm test` +Expected: PASS. + +- [ ] **Step 6: Commit** + +```bash +cd webapp-src && git add -A && git commit -m "feat: assemble cockpit app — live polling, scenario verbs, settings drawer" +``` + +--- + +### Task 8: Production bundle + embedded serving verification + +**Files:** +- Modify: `webapp-src/dist/*` (generated), `public/bundle.html.gz` (main repo, generated) + +- [ ] **Step 1: Build the production bundle** + +```bash +cd /Users/joojodontoh/Documents/PersonalProjects/MicroOcppSimulator +./build-webapp/build_webapp.sh +``` +Expected: "Up-to-date version of the web-app bundle was placed in the /public folder!" + +- [ ] **Step 2: Size gate** + +Run: `ls -la public/bundle.html.gz` +Expected: ≤ 150 KB. The three woff2 files total ~83 KB raw (~110 KB as base64, partially recovered by the final gzip), so expect ~120-140 KB. If over: check `webpack-bundle-analyzer` (uncomment in `webpack.common.js`). Do NOT drop fonts to make budget — they are part of the design contract; raise the concern instead. + +- [ ] **Step 3: Serve through the C++ binary** + +```bash +./build/mo_simulator & +curl -sI http://localhost:8000/ | grep -i 'content-encoding' +``` +Expected: `Content-Encoding: gzip`. Open `http://localhost:8000/` in the browser and repeat golden-path items 1-5 from Task 7 Step 4 against the **bundled** app (this catches prod-only issues: minification, `API_ROOT=/api` same-origin paths, inlined fonts). + +- [ ] **Step 4: Commit the bundle source state in webapp-src** + +```bash +cd webapp-src && git add -A && git commit -m "chore: production bundle build" +``` +(If `dist/` is gitignored in webapp-src, this commit may be empty — skip it then.) + +--- + +### Task 9: Main-repo integration + +**Files:** +- Modify: `.gitmodules` (main repo), submodule pointer, `public/bundle.html.gz` +- Delete: `webapp-src/design-reference/` + +- [ ] **Step 1: Remove the design reference from webapp-src** + +```bash +cd webapp-src && git rm -r design-reference && git commit -m "chore: drop design reference used during port" +``` + +- [ ] **Step 2: Point .gitmodules at the Pitvolt fork** + +In `/Users/joojodontoh/Documents/PersonalProjects/MicroOcppSimulator/.gitmodules`, change the `webapp-src` entry URL from `https://github.com/agruenb/arduino-ocpp-dashboard.git` to `https://github.com/Pitvolt/micro-ocpp-dashboard.git`, then `git submodule sync webapp-src`. + +- [ ] **Step 3: Verify tests and builds one final time** + +```bash +cd webapp-src && npm test && npm run build && cd .. +ls -la public/bundle.html.gz +``` +Expected: tests pass, build clean, bundle present and ≤ 150 KB. + +- [ ] **Step 4: Commit in the main repo** + +```bash +git add .gitmodules webapp-src public/bundle.html.gz +git commit -m "feat: cockpit UI — redesigned simulator dashboard (webapp-src cockpit-redesign)" +``` +**Do not push** either repo — pushing to Pitvolt is the user's call (the submodule commit must be pushed to `Pitvolt/micro-ocpp-dashboard` *before* the main-repo commit is pushed, otherwise clones break; remind the user of this ordering). + +--- + +## Self-Review Notes + +- Spec coverage: connector-first bays (T5), scenario verbs (T5), live telemetry + sparkline (T3/T5), persistent connection strip (T5 TopStrip), settings drawer with websocket + CA cert (T6), auto-refresh everywhere with single failure banner (T3/T7), dark HUD look (T1/T4), single-bundle pipeline preserved (T1/T8), no C++ changes (global), fake demo pages dropped (old components deleted in T1), prototype bugs not carried over (store is single source of truth; no stale-state comparison; no missing imports — verified by build + tests). +- Dropped from prototype deliberately: INJECT FAULT (no endpoint), SIMULATE LINK LOSS (mock-only). All three Alfred fonts (Michroma, IBM Plex Sans, JetBrains Mono) ship inline; colors verified identical to `project-alfred/apps/dashboard-web/styles/tokens/colors.css`. +- Type consistency check: `store.state.link` values `"init" | "ok" | "down"` used in T3 tests, T5 TopStrip, T6 drawer, T7 banner. Connector field names match `src/api.cpp` JSON exactly. `PILL_TONE` keys match `statusLabel` tones and `StatusPill` TONES palette names. From 43aef4eaf68077ac8183321c42cf6721281f5c95 Mon Sep 17 00:00:00 2001 From: Joojo Dontoh Date: Sun, 2 Aug 2026 01:04:29 +0800 Subject: [PATCH 5/9] Bring cockpit UI onto webapp-src master + host all submodules under Pitvolt Merges cockpit-redesign into webapp-src master (Pitvolt/micro-ocpp-dashboard) and repoints the five upstream lib submodules to freshly-created Pitvolt forks (ArduinoJson, MicroOcpp, MicroOcppMongoose, mbedtls, mongoose). Every dependency the staging bundle builds from now lives in the Pitvolt org. Co-Authored-By: Claude Opus 4.7 --- .gitmodules | 10 +++++----- webapp-src | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitmodules b/.gitmodules index 17f5180..c854846 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,18 +1,18 @@ [submodule "lib/ArduinoJson"] path = lib/ArduinoJson - url = https://github.com/bblanchon/ArduinoJson.git + url = https://github.com/Pitvolt/ArduinoJson.git [submodule "lib/MicroOcpp"] path = lib/MicroOcpp - url = https://github.com/matth-x/MicroOcpp + url = https://github.com/Pitvolt/MicroOcpp.git [submodule "lib/MicroOcppMongoose"] path = lib/MicroOcppMongoose - url = https://github.com/matth-x/MicroOcppMongoose + url = https://github.com/Pitvolt/MicroOcppMongoose.git [submodule "lib/mongoose"] path = lib/mongoose - url = https://github.com/cesanta/mongoose + url = https://github.com/Pitvolt/mongoose.git [submodule "webapp-src"] path = webapp-src url = https://github.com/Pitvolt/micro-ocpp-dashboard.git [submodule "lib/mbedtls"] path = lib/mbedtls - url = https://github.com/Mbed-TLS/mbedtls + url = https://github.com/Pitvolt/mbedtls.git diff --git a/webapp-src b/webapp-src index dddf828..957680e 160000 --- a/webapp-src +++ b/webapp-src @@ -1 +1 @@ -Subproject commit dddf8283636e8df5188abf59ca9ae0b49d8fb577 +Subproject commit 957680e99271f19f6899aceef93d6c66b9050cc7 From 62cf60e77310c84cb444207e0560bf9ea075fab3 Mon Sep 17 00:00:00 2001 From: Joojo Dontoh Date: Sun, 2 Aug 2026 01:16:46 +0800 Subject: [PATCH 6/9] Add Render.com config for the staging simulator (no-card alternative to Fly) Free web-service tier, auto-sleeps at 15m idle, wakes in ~30s. Same Dockerfile and STATION_ID/WSS_URL contract; connect the repo once in the Render dashboard and Render deploys the blueprint automatically. Co-Authored-By: Claude Opus 4.7 --- deploy/staging/README.md | 42 +++++++++++++++++++++----------------- deploy/staging/render.yaml | 32 +++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 19 deletions(-) create mode 100644 deploy/staging/render.yaml diff --git a/deploy/staging/README.md b/deploy/staging/README.md index 0e173e8..2406244 100644 --- a/deploy/staging/README.md +++ b/deploy/staging/README.md @@ -8,33 +8,37 @@ Runs the same binary as the upstream repo (built by `deploy/staging/Dockerfile`) just with a runtime entrypoint that writes `mo_store/ws-conn.jsn` from `STATION_ID` + `WSS_URL` env vars so one image works for any charger. -## First-time bring-up +## First-time bring-up (Render.com — no card required) -Prereq: `brew install flyctl` and `flyctl auth login`. +Free web-service tier, 750 h/month, sleeps after 15 min idle, wakes in ~30s. -```bash -cd deploy/staging -# Create the Fly app (uses this fly.toml, does not deploy yet). -flyctl launch --no-deploy --copy-config --name pitvolt-ocpp-sim \ - --org personal --region fra -# Build + deploy from the REPO ROOT (Dockerfile expects the whole repo). -cd ../.. -flyctl deploy --config deploy/staging/fly.toml --dockerfile deploy/staging/Dockerfile -``` +1. Log in at (GitHub SSO — no card asked). +2. **New → Blueprint → Connect** the `Pitvolt/MicroOcppSimulator` repo. +3. Render reads `deploy/staging/render.yaml`, creates the service, and + deploys from `deploy/staging/Dockerfile`. First build takes ~5 min. +4. Public URL: `https://pitvolt-ocpp-sim.onrender.com` — the simulator's + web UI. Drive charging sessions from the browser; staging + (`stg.api.pitvolt.com`) treats it as a real charger. -Once live: — the simulator's web UI. -Drive charging sessions from the browser; the running backend on staging -(`stg.api.pitvolt.com`) treats it as a real charger. +Change the targeted charger from the Render dashboard → Environment → +edit `STATION_ID` → save (Render redeploys automatically). -## Retarget a different charger +## Alternative: Fly.io bring-up (requires a card) ```bash -flyctl secrets set STATION_ID= -# For a completely different environment: -flyctl secrets set WSS_URL=wss:///ocpp +brew install flyctl && flyctl auth login +flyctl launch --no-deploy --copy-config --name pitvolt-ocpp-sim \ + --org personal --region fra --config deploy/staging/fly.toml +flyctl deploy --config deploy/staging/fly.toml \ + --dockerfile deploy/staging/Dockerfile +# URL: https://pitvolt-ocpp-sim.fly.dev ``` -Fly restarts the machine automatically. +## Retarget a different charger + +- **Render**: Dashboard → Environment → edit `STATION_ID` (or `WSS_URL`) → + save. Redeploys automatically. +- **Fly**: `flyctl secrets set STATION_ID=`. ## Local dry-run without Fly diff --git a/deploy/staging/render.yaml b/deploy/staging/render.yaml new file mode 100644 index 0000000..9f8e05e --- /dev/null +++ b/deploy/staging/render.yaml @@ -0,0 +1,32 @@ +# Render.com config for the staging OCPP simulator (deploy/staging/README.md). +# Zero-cost web service on the free tier: no card required, auto-sleeps at +# 15 min idle, wakes on request in ~30s. Same STATION_ID / WSS_URL contract +# as the Fly bundle; the Dockerfile is reused as-is. +# +# Bring-up (one-time in the Render dashboard): +# 1. Log in at https://dashboard.render.com (GitHub SSO fine, no card) +# 2. New -> Blueprint -> connect Pitvolt/MicroOcppSimulator repo +# 3. Render reads this file and creates the service; deploy runs +# automatically from the deploy/staging/Dockerfile +# 4. Public URL after first deploy: https://pitvolt-ocpp-sim.onrender.com + +services: + - type: web + name: pitvolt-ocpp-sim + runtime: docker + plan: free + # Build context is the repo root (Dockerfile COPYs the whole tree in); + # dockerfilePath is relative to that root. + dockerfilePath: ./deploy/staging/Dockerfile + dockerContext: . + envVars: + - key: STATION_ID + value: PVE2-VAJN + - key: WSS_URL + value: wss://staging.ocpp.pitvolt.com + # AUTH_KEY deliberately empty: staging OCPP endpoint uses station-id + # auth only. Set via the Render dashboard if the endpoint ever adds a + # password check (keep it out of source control). + # Free tier sleeps after 15 min idle; wakes on the first request. + healthCheckPath: / + autoDeploy: true From e909786a9279ecde869d9a5581ac6abc2f210af6 Mon Sep 17 00:00:00 2001 From: Joojo Dontoh Date: Sun, 2 Aug 2026 01:25:43 +0800 Subject: [PATCH 7/9] staging: clone fresh from GitHub in-container instead of COPY + submodule init Render's build context does not preserve .git, so `git submodule init && update` inside the container fails with "not a git repository". Cloning fresh with --recurse-submodules removes the host-dependency entirely and works on any platform (Render, Fly, laptop) with the same command. Co-Authored-By: Claude Opus 4.7 --- deploy/staging/Dockerfile | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/deploy/staging/Dockerfile b/deploy/staging/Dockerfile index 1e585bf..19d36a0 100644 --- a/deploy/staging/Dockerfile +++ b/deploy/staging/Dockerfile @@ -13,18 +13,27 @@ RUN apk update && \ openssl-dev \ build-base -WORKDIR /MicroOcppSimulator +# Clone fresh from GitHub with submodules recursively -- avoids relying on +# either .git being COPYed (Render strips it) or the host performing a +# recursive checkout. Rebuilds pick up the LATEST main; pin to a tag via +# `--branch ` when a specific release matters. +# NB: the parent's .gitmodules points at Pitvolt/* forks, so `--recursive` +# fetches the exact submodules the staging bundle expects. +ARG SIM_REF=main +RUN git clone --depth 1 --branch "${SIM_REF}" --recurse-submodules \ + --shallow-submodules \ + https://github.com/Pitvolt/MicroOcppSimulator.git /MicroOcppSimulator -# Bring in the whole repo -- Docker build context is the repo root when -# `docker build -f deploy/staging/Dockerfile .` runs. -COPY . . +WORKDIR /MicroOcppSimulator -RUN git submodule init && git submodule update RUN cmake -S . -B ./build -DCMAKE_POLICY_VERSION_MINIMUM=3.5 RUN cmake --build ./build -j 16 --target mo_simulator -j 16 RUN chmod +x /MicroOcppSimulator/build/mo_simulator -COPY deploy/staging/entrypoint.sh /usr/local/bin/entrypoint.sh +# The entrypoint is bundled with the freshly-cloned tree, but copy the +# staging-bundle canonical version onto /usr/local/bin so any future edit +# to the file on main takes effect on the next rebuild. +RUN cp /MicroOcppSimulator/deploy/staging/entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod +x /usr/local/bin/entrypoint.sh EXPOSE 8000 From d4a1d252895cf6d0f8af02ffe6215eb1f98bbc46 Mon Sep 17 00:00:00 2001 From: Joojo Dontoh Date: Sun, 2 Aug 2026 01:32:07 +0800 Subject: [PATCH 8/9] Load system CA bundle at boot so wss:// endpoints work mbedtls has no default trust store, so passing "" as ca_cert to the MOcppMongooseClient constructor fails every TLS handshake with fatal alert -0x7780. Read /etc/ssl/certs/ca-certificates.crt (Alpine standard path, override with CA_CERT_PATH env) into a static std::string at boot and pass its pointer to the socket. Also install ca-certificates in the staging Dockerfile so the file exists. Co-Authored-By: Claude Opus 4.7 --- deploy/staging/Dockerfile | 4 +++- src/main.cpp | 42 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/deploy/staging/Dockerfile b/deploy/staging/Dockerfile index 19d36a0..635fe83 100644 --- a/deploy/staging/Dockerfile +++ b/deploy/staging/Dockerfile @@ -11,7 +11,9 @@ RUN apk update && \ git \ cmake \ openssl-dev \ - build-base + build-base \ + ca-certificates && \ + update-ca-certificates # Clone fresh from GitHub with submodules recursively -- avoids relying on # either .git being COPYed (Render strips it) or the host performing a diff --git a/src/main.cpp b/src/main.cpp index 0e945fd..e945c24 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,8 @@ #include #include +#include +#include #include @@ -40,6 +42,43 @@ unsigned int g_bootNotificationTime = 0; struct mg_mgr mgr; MicroOcpp::MOcppMongooseClient *osock; +// System CA bundle (populated at boot from CA_CERT_PATH env or /etc/ssl/certs). +// Needed for TLS handshake against wss:// endpoints (Let's Encrypt chains, +// etc.) -- mbedtls has no default trust store, so a nullptr ca_cert fails +// the handshake. Stored as a static string so its lifetime matches the +// socket (the MOcppMongooseClient stores the pointer, does not copy). +static std::string g_ca_cert_pem; + +static const char *load_system_ca_cert() { + const char *env_path = std::getenv("CA_CERT_PATH"); + const char *candidates[] = { + env_path, + "/etc/ssl/certs/ca-certificates.crt", + "/etc/ssl/cert.pem", + nullptr, + }; + for (const char *p : candidates) { + if (!p || !*p) continue; + if (FILE *f = std::fopen(p, "rb")) { + std::fseek(f, 0, SEEK_END); + long sz = std::ftell(f); + std::fseek(f, 0, SEEK_SET); + if (sz > 0) { + g_ca_cert_pem.resize(static_cast(sz)); + std::fread(&g_ca_cert_pem[0], 1, static_cast(sz), f); + } + std::fclose(f); + if (!g_ca_cert_pem.empty()) { + std::cerr << "loaded CA bundle from " << p + << " (" << g_ca_cert_pem.size() << " bytes)\n"; + return g_ca_cert_pem.c_str(); + } + } + } + std::cerr << "no CA bundle found; TLS wss:// endpoints will fail\n"; + return nullptr; +} + #elif MO_NETLIB == MO_NETLIB_WASM #include @@ -165,11 +204,12 @@ int main() { mg_http_listen(&mgr, api_url, http_serve, (void*)api_url); // Create listening connection + const char *ca_cert_arg = load_system_ca_cert(); osock = new MicroOcpp::MOcppMongooseClient(&mgr, "ws://echo.websocket.events", "charger-01", "", - "", + ca_cert_arg, filesystem, g_isOcpp201 ? MicroOcpp::ProtocolVersion{2,0,1} : From 76a644596cb68c85a94400e224c236793e8f102d Mon Sep 17 00:00:00 2001 From: Joojo Dontoh Date: Sun, 2 Aug 2026 10:59:41 +0800 Subject: [PATCH 9/9] Point Render simulator at PVE2-3BYA to unblock the CI E2E suite PVE2-VAJN is reserved for the integration-test suite in surge-core. OCPP allows only one live connection per station id; the always-on Render simulator was holding that slot and every CI E2E deploy was failing to open its own OCPP connection. PVE2-3BYA is a dedicated "Simulator Playground" charger on the same e2e tenant provisioned via the admin API. Co-Authored-By: Claude Opus 4.7 --- deploy/staging/render.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/deploy/staging/render.yaml b/deploy/staging/render.yaml index 9f8e05e..1c20326 100644 --- a/deploy/staging/render.yaml +++ b/deploy/staging/render.yaml @@ -20,8 +20,13 @@ services: dockerfilePath: ./deploy/staging/Dockerfile dockerContext: . envVars: + # PVE2-3BYA is the "Simulator Playground" charger on the e2e tenant + # (spec 2026-08-02): a dedicated station id for user-driven simulator + # runs, kept SEPARATE from PVE2-VAJN which is reserved for the CI + # integration-test suite. OCPP allows only one live connection per + # station id, so sharing would race with every CI deploy. - key: STATION_ID - value: PVE2-VAJN + value: PVE2-3BYA - key: WSS_URL value: wss://staging.ocpp.pitvolt.com # AUTH_KEY deliberately empty: staging OCPP endpoint uses station-id