Complete IoT monitoring platform for Acuvim II power meters via ESP32. Firmware (Phases 1-7): - ESP32-WROVER-B (TTGO T-Call v1.4) with RS485 Modbus RTU - WiFi STA+AP concurrent mode with GSM/GPRS failover - Transport abstraction layer with 4 priority modes - MQTT protocol with 20 commands, LWT, QoS, exponential backoff - SD card offline buffering with JSONL rotation and non-blocking drain - OTA firmware updates with dual partition rollback protection - Watchdog timer, crash loop detection, Acuvim health monitoring - Captive portal provisioning with AP mode Console backend (Phase 8): - .NET 10 minimal API with PostgreSQL + EF Core - JWT authentication, SignalR real-time updates - MQTTnet 5.x bridge service with health monitoring - Device, telemetry, firmware, alert, group management - Rate limiting, security headers, Swagger/OpenAPI Frontend (Phase 9): - React 18 + TypeScript + Vite with Ant Design 5 - ECharts telemetry visualization, TanStack Query - SignalR live updates, device management UI - Dashboard, fleet management, firmware deployment Testing & Production (Phase 10): - 28 firmware unit tests (Modbus, JSON, config, version) - 23 xUnit backend tests (device, telemetry, command, alert) - Docker Compose with nginx, TLS MQTT, PostgreSQL - Production deployment, commissioning, and troubleshooting docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
28 KiB
28 KiB
Phase 9: Console Application Frontend
Objective
Build the web-based frontend dashboard for the console application. The frontend provides device fleet management, real-time telemetry visualization, remote configuration, OTA firmware deployment, and alert management. It connects to the backend API (Phase 8) and uses SignalR for real-time updates.
Prerequisites
- Phase 8 complete (backend API running)
- Node.js 18+ (for frontend build tooling)
- Design system chosen
Deliverables
- React SPA with responsive dashboard
- Device fleet overview with status indicators
- Individual device detail page (telemetry, config, health)
- Real-time telemetry charts
- Remote configuration interface
- Firmware management and deployment UI
- Alert management dashboard
- User authentication flow
9.1 Technology Stack
| Component | Technology | Justification |
|---|---|---|
| Framework | React 18 | Component-based, large ecosystem |
| Language | TypeScript | Type safety, better DX |
| Build | Vite | Fast HMR, modern bundling |
| Routing | React Router v6 | Standard React routing |
| State | TanStack Query (React Query) | Server state caching, auto-refresh |
| UI Library | Ant Design 5 | Complete component set, tables, forms, charts |
| Charts | Apache ECharts (via echarts-for-react) | High-performance, rich chart types |
| Real-time | @microsoft/signalr | SignalR client for live updates |
| HTTP | Axios | HTTP client with interceptors |
| Forms | Ant Design Form | Built-in validation |
| Icons | Ant Design Icons | Consistent with UI library |
9.2 Project Structure
console/
├── frontend/
│ ├── package.json
│ ├── tsconfig.json
│ ├── vite.config.ts
│ ├── index.html
│ ├── public/
│ │ └── favicon.ico
│ └── src/
│ ├── main.tsx
│ ├── App.tsx
│ ├── api/
│ │ ├── client.ts # Axios instance with auth interceptor
│ │ ├── devices.ts # Device API calls
│ │ ├── telemetry.ts # Telemetry API calls
│ │ ├── firmware.ts # Firmware API calls
│ │ ├── alerts.ts # Alert API calls
│ │ ├── auth.ts # Auth API calls
│ │ └── commands.ts # Command API calls
│ ├── hooks/
│ │ ├── useDevices.ts
│ │ ├── useTelemetry.ts
│ │ ├── useSignalR.ts
│ │ └── useAuth.ts
│ ├── pages/
│ │ ├── LoginPage.tsx
│ │ ├── DashboardPage.tsx
│ │ ├── DeviceListPage.tsx
│ │ ├── DeviceDetailPage.tsx
│ │ ├── FirmwarePage.tsx
│ │ ├── AlertsPage.tsx
│ │ ├── GroupsPage.tsx
│ │ └── SettingsPage.tsx
│ ├── components/
│ │ ├── layout/
│ │ │ ├── AppLayout.tsx
│ │ │ ├── Sidebar.tsx
│ │ │ └── Header.tsx
│ │ ├── devices/
│ │ │ ├── DeviceTable.tsx
│ │ │ ├── DeviceCard.tsx
│ │ │ ├── DeviceStatusBadge.tsx
│ │ │ ├── DeviceConfigForm.tsx
│ │ │ ├── WifiScanModal.tsx
│ │ │ └── CommandModal.tsx
│ │ ├── telemetry/
│ │ │ ├── TelemetryChart.tsx
│ │ │ ├── LiveReadings.tsx
│ │ │ ├── PowerGauge.tsx
│ │ │ └── EnergyCounter.tsx
│ │ ├── firmware/
│ │ │ ├── FirmwareUpload.tsx
│ │ │ ├── FirmwareTable.tsx
│ │ │ └── DeployModal.tsx
│ │ ├── alerts/
│ │ │ ├── AlertTable.tsx
│ │ │ └── AlertBadge.tsx
│ │ └── dashboard/
│ │ ├── FleetSummary.tsx
│ │ ├── DeviceMap.tsx
│ │ └── RecentAlerts.tsx
│ ├── types/
│ │ ├── device.ts
│ │ ├── telemetry.ts
│ │ ├── firmware.ts
│ │ └── alert.ts
│ └── utils/
│ ├── formatters.ts
│ └── constants.ts
9.3 Page Layouts
Dashboard (Home)
Fleet-level overview — the first thing operators see.
┌─────────────────────────────────────────────────────────────┐
│ ☰ Tau Acuvim Console admin ▼ [Logout] │
├──────┬──────────────────────────────────────────────────────┤
│ │ │
│ Nav │ Fleet Overview │
│ │ ┌──────────┬──────────┬──────────┬──────────┐ │
│ 📊 │ │ Total │ Online │ Degraded │ Offline │ │
│Dash │ │ 24 │ 21 │ 1 │ 2 │ │
│ │ └──────────┴──────────┴──────────┴──────────┘ │
│ 📱 │ │
│Devs │ ┌────────────────────┬──────────────────────┐ │
│ │ │ Recent Alerts │ Fleet Power │ │
│ 📦 │ │ ⚠ Overvoltage │ ┌─────────────────┐ │ │
│FW │ │ ACV-001 2m ago │ │ Line chart │ │ │
│ │ │ ⚠ Modbus error │ │ (total kW over │ │ │
│ 🔔 │ │ ACV-015 5m ago │ │ last 24h) │ │ │
│Alert │ │ ● Device offline │ └─────────────────┘ │ │
│ │ │ ACV-008 1h ago │ │ │
│ ⚙ │ └────────────────────┴──────────────────────┘ │
│Sets │ │
│ │ Device Status Grid │
│ │ ┌──────┬──────┬──────┬──────┬──────┬──────┐ │
│ │ │●001 │●002 │●003 │●004 │●005 │●006 │ │
│ │ │230V │231V │229V │232V │ OFF │230V │ │
│ │ │10kW │12kW │9kW │11kW │ -- │8kW │ │
│ │ └──────┴──────┴──────┴──────┴──────┴──────┘ │
│ │ │
└──────┴──────────────────────────────────────────────────────┘
Device List
┌──────────────────────────────────────────────────────────────┐
│ Devices [+ Add Group] [⚡ Deploy] │
├──────────────────────────────────────────────────────────────┤
│ Filter: [All ▼] [Online ▼] [Group ▼] Search: [________] │
├──────────────────────────────────────────────────────────────┤
│ Status │ Device ID │ Name │ FW │ Conn │ P │
│────────┼─────────────────┼───────────────┼───────┼──────┼────│
│ ● │ ACV-AABBCCDDEEFF│ Building A │ 1.0.0 │ WiFi │10kW│
│ ● │ ACV-112233445566│ Building B │ 1.0.0 │ GSM │12kW│
│ ◐ │ ACV-FFEEDDCCBBAA│ Warehouse │ 0.9.0 │ WiFi │ 9kW│
│ ○ │ ACV-998877665544│ Solar Farm │ 1.0.0 │ -- │ -- │
├──────────────────────────────────────────────────────────────┤
│ Showing 1-20 of 24 devices < 1 2 > │
└──────────────────────────────────────────────────────────────┘
Status indicators: ● Online ◐ Degraded ○ Offline
Device Detail
┌──────────────────────────────────────────────────────────────┐
│ ← Devices / ACV-AABBCCDDEEFF - Building A │
├──────────────────────────────────────────────────────────────┤
│ [Overview] [Telemetry] [Config] [Alerts] [Commands] [OTA] │
├──────────────────────────────────────────────────────────────┤
│ │
│ ── Overview Tab ── │
│ │
│ Device Info │ Connection │
│ ID: ACV-AABBCCDDEEFF │ Type: WiFi │
│ Name: Building A │ SSID: MyNetwork │
│ Hardware: TTGO T-Call v1.4 │ RSSI: -45 dBm │
│ Firmware: v1.0.0 │ IP: 192.168.1.100 │
│ Uptime: 3d 2h 15m │ MQTT: Connected │
│ Boot count: 12 │ GSM: Available (standby) │
│ Last heartbeat: 30s ago │ SD: 4GB (0.1% used) │
│ │ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Live Readings ● LIVE │ │
│ │ │ │
│ │ Phase Voltages Phase Currents │ │
│ │ Va: 230.1 V Ia: 15.2 A │ │
│ │ Vb: 231.4 V Ib: 14.8 A │ │
│ │ Vc: 229.8 V Ic: 15.5 A │ │
│ │ │ │
│ │ Power Energy │ │
│ │ Active: 10.5 kW Import: 12,345.6 kWh │ │
│ │ Reactive: 2.1 kVAR Export: 0.0 kWh │ │
│ │ Apparent: 10.7 kVA PF: 0.98 │ │
│ │ Freq: 50.01 Hz │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ [Restart] [WiFi Scan] [Send Command] │
└──────────────────────────────────────────────────────────────┘
Device Detail - Telemetry Tab
┌──────────────────────────────────────────────────────────────┐
│ [Overview] [Telemetry] [Config] [Alerts] [Commands] [OTA] │
├──────────────────────────────────────────────────────────────┤
│ │
│ Time Range: [Last 24h ▼] [Custom Range] [Export CSV] │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Phase Voltages (V) │ │
│ │ 240 ┤ │ │
│ │ 235 ┤ ╭─╮ │ │
│ │ 230 ┤───╯ ╰──────────────────────────────────── │ │
│ │ 225 ┤ │ │
│ │ 220 ┤ │ │
│ │ └──┬────┬────┬────┬────┬────┬────┬────┬────┬── │ │
│ │ 00 03 06 09 12 15 18 21 24 │ │
│ │ ── Va ── Vb ── Vc │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Active Power (kW) │ │
│ │ 15 ┤ ╭───╮ │ │
│ │ 10 ┤────╮ ╯ ╰───────╮ │ │
│ │ 5 ┤ ╰──╯ ╰────── │ │
│ │ 0 ┤ │ │
│ │ └──┬────┬────┬────┬────┬────┬────┬────┬────┬── │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Power Factor & Frequency │ │
│ │ ... similar chart ... │ │
│ └──────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
Device Detail - Config Tab
┌──────────────────────────────────────────────────────────────┐
│ [Overview] [Telemetry] [Config] [Alerts] [Commands] [OTA] │
├──────────────────────────────────────────────────────────────┤
│ │
│ WiFi Configuration │ MQTT Configuration │
│ SSID: [MyNetwork____] │ Broker: [broker.example.com] │
│ Password: [**********] │ Port: [1883] │
│ Enabled: [✓] │ Username: [device1] │
│ [Scan Networks] [Save] │ Password: [**********] │
│ │ Topic: [acuvim] │
│ GSM Configuration │ TLS: [ ] │
│ APN: [internet] │ [Test] [Save] │
│ Enabled: [✓] │ │
│ Priority: [WiFi first ▼] │ Sleep Configuration │
│ [Save] │ Enabled: [ ] │
│ │ Sleep: [15] min │
│ Modbus Configuration │ Wake: [300] sec │
│ Slave Address: [1] │ [Save] │
│ Baud Rate: [9600 ▼] │ │
│ Poll Interval: [5] sec │ Console URL │
│ [Save] │ [https://console.example.com] │
│ │ [Save] │
│ │
│ ⚠ Changes are pushed to the device immediately via MQTT. │
│ The device will apply settings and reconnect as needed. │
└──────────────────────────────────────────────────────────────┘
Firmware Management Page
┌──────────────────────────────────────────────────────────────┐
│ Firmware Management [Upload New] │
├──────────────────────────────────────────────────────────────┤
│ │
│ Version │ Size │ Date │ Devices │ Status │ Action │
│─────────┼────────┼──────────────┼─────────┼────────┼─────────│
│ v1.2.0 │ 1.2 MB │ May 16, 2026 │ 0 / 24 │ Active │ [Deploy]│
│ v1.1.0 │ 1.1 MB │ May 10, 2026 │ 3 / 24 │ Active │ [Deploy]│
│ v1.0.0 │ 1.0 MB │ May 01, 2026 │ 21 / 24 │ Active │ [Deploy]│
│ v0.9.0 │ 0.9 MB │ Apr 15, 2026 │ 0 / 24 │ Archived│ │
├──────────────────────────────────────────────────────────────┤
│ │
│ Deploy v1.2.0 to: │
│ ( ) All devices (24) │
│ ( ) Group: [Building A ▼] (8 devices) │
│ (●) Select devices: │
│ [✓] ACV-001 - Building A (v1.0.0) │
│ [✓] ACV-002 - Building B (v1.0.0) │
│ [ ] ACV-003 - Warehouse (v0.9.0) │
│ │
│ Release Notes: │
│ Added THD monitoring improvements │
│ │
│ [Deploy to 2 devices] │
└──────────────────────────────────────────────────────────────┘
Alerts Page
┌──────────────────────────────────────────────────────────────┐
│ Alerts Unresolved: 5 [Mark All Read] │
├──────────────────────────────────────────────────────────────┤
│ Filter: [All ▼] [Warning ▼] [Active ▼] Search: [________] │
├──────────────────────────────────────────────────────────────┤
│ Sev │ Device │ Alert │ Value │ Time │ Ack │
│─────┼───────────┼────────────────┼─────────┼─────────┼───────│
│ ⚠ │ ACV-001 │ Overvoltage │ 265.3V │ 2m ago │ [ ] │
│ ⚠ │ ACV-015 │ Modbus errors │ 12% │ 5m ago │ [ ] │
│ ● │ ACV-008 │ Device offline │ -- │ 1h ago │ [ ] │
│ ℹ │ ACV-003 │ Low PF │ 0.82 │ 2h ago │ [✓] │
│ ⚠ │ ACV-001 │ Undervoltage │ 198V │ 3h ago │ [✓] │
├──────────────────────────────────────────────────────────────┤
│ Showing 1-20 of 45 alerts < 1 2 3 > │
└──────────────────────────────────────────────────────────────┘
Severity: ● Critical ⚠ Warning ℹ Info
9.4 SignalR Integration
Real-Time Hook
// useSignalR.ts
function useSignalR() {
const connection = new HubConnectionBuilder()
.withUrl("/hubs/devices", { accessTokenFactory: () => getToken() })
.withAutomaticReconnect()
.build();
useEffect(() => {
connection.start();
connection.on("DeviceStatusChanged", (deviceId, status) => {
queryClient.invalidateQueries(["devices"]);
});
connection.on("TelemetryReceived", (deviceId, data) => {
queryClient.setQueryData(["telemetry", deviceId, "latest"], data);
});
connection.on("AlertCreated", (deviceId, alert) => {
queryClient.invalidateQueries(["alerts"]);
notification.warning({ message: alert.message });
});
return () => connection.stop();
}, []);
}
Live Data Updates
- Device status badges update in real-time (no page refresh)
- Telemetry readings update live on device detail page
- New alerts appear as toast notifications
- Dashboard counters update automatically
9.5 Authentication Flow
Login Page
┌──────────────────────────────────────┐
│ │
│ Tau Acuvim Console │
│ │
│ Email: [________________] │
│ Password: [________________] │
│ │
│ [Login] │
│ │
│ Forgot password? │
│ │
└──────────────────────────────────────┘
Auth Implementation
// Protected route wrapper
function ProtectedRoute({ children }) {
const { isAuthenticated } = useAuth();
if (!isAuthenticated) {
return <Navigate to="/login" />;
}
return children;
}
- JWT token stored in memory (not localStorage) for security
- Refresh token in httpOnly cookie
- Axios interceptor adds
Authorizationheader automatically - On 401 response: redirect to login
9.6 Responsive Design
- Desktop (>1200px): Full sidebar + content layout
- Tablet (768-1200px): Collapsible sidebar, adjusted grid
- Mobile (<768px): Bottom navigation, stacked cards, simplified tables
Ant Design's grid system handles responsive breakpoints. Charts resize automatically using ECharts' responsive mode.
9.7 Build and Deploy
Development
cd console/frontend
npm install
npm run dev # Vite dev server with HMR (port 5173)
Production Build
npm run build # Output to dist/
Integration with Backend
- In development: Vite proxy forwards
/apiand/hubsto the .NET backend - In production: the .NET backend serves the built frontend files from
wwwroot/ vite.config.tsconfigures the proxy for development
// vite.config.ts
export default defineConfig({
server: {
proxy: {
'/api': 'http://localhost:5000',
'/hubs': {
target: 'http://localhost:5000',
ws: true
}
}
}
});
Docker Integration
Add to the Phase 8 Dockerfile:
# Build frontend
FROM node:18 AS frontend
WORKDIR /app/frontend
COPY console/frontend/package*.json ./
RUN npm ci
COPY console/frontend/ ./
RUN npm run build
# Build backend
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS backend
# ... build steps ...
# Runtime
FROM mcr.microsoft.com/dotnet/aspnet:8.0
# ... copy backend build ...
COPY --from=frontend /app/frontend/dist ./wwwroot/
9.8 Testing & Validation
| Test | Method | Pass Criteria |
|---|---|---|
| Login | Enter valid credentials | Redirected to dashboard |
| Dashboard loads | Navigate to / | Summary cards, alerts, grid visible |
| Device list | Navigate to /devices | All devices listed with status |
| Device detail | Click a device | Overview tab shows live data |
| Telemetry charts | Select Telemetry tab | Charts render with historical data |
| Time range | Change to Last 7 days | Charts update with correct range |
| Config push | Edit WiFi settings, save | Config sent to device via MQTT |
| WiFi scan | Click Scan Networks | Networks returned and displayed |
| Firmware upload | Upload a .bin file | File uploaded, appears in list |
| Firmware deploy | Deploy to selected devices | OTA commands sent |
| Alert display | Trigger alert from device | Alert appears in list and as toast |
| Alert acknowledge | Click acknowledge | Alert marked as acknowledged |
| Real-time update | Watch dashboard while device publishes | Values update without refresh |
| Responsive | Resize browser to mobile | Layout adapts correctly |
| Auth protection | Access /devices without login | Redirected to /login |
| CSV export | Export telemetry | Valid CSV downloaded |
| Send command | Send restart command | Device restarts, response received |
9.9 Phase 9 Completion Criteria
- React frontend builds and serves
- Login/logout flow with JWT authentication
- Dashboard shows fleet summary, alerts, device grid
- Device list with filtering, search, pagination
- Device detail with tabs: Overview, Telemetry, Config, Alerts, Commands, OTA
- Live telemetry readings update via SignalR
- Historical telemetry charts with time range selection
- Remote configuration push (WiFi, MQTT, GSM, sleep, Modbus)
- WiFi scan triggered from console and results displayed
- Firmware upload and deployment UI
- Alert management (list, filter, acknowledge)
- Responsive design (desktop, tablet, mobile)
- Integrated into .NET backend for production deployment
Previous Phase: Phase 8 — Console Application Backend Next Phase: Phase 10 — Integration Testing & Production Hardening