From 7d82a9e223d463cba70bd8c50ab5df9f442c653d Mon Sep 17 00:00:00 2001 From: Preston Hunter Date: Mon, 22 Dec 2025 23:59:02 -0500 Subject: [PATCH] feat: Implement device firmware and command APIs, add individual device administration page, and refine UI styling. --- README.md | 91 ++++-- firmware/config/device.json | 2 +- prisma/dev.db | Bin 49152 -> 49152 bytes src/app/admin/devices/[id]/page.tsx | 343 +++++++++++++++++++++ src/app/admin/page.tsx | 28 +- src/app/api/devices/[id]/command/route.ts | 44 +++ src/app/api/devices/[id]/firmware/route.ts | 39 +++ src/app/api/devices/[id]/route.ts | 5 +- src/app/globals.css | 37 ++- src/app/page.tsx | 58 ++-- src/app/tests/[id]/page.tsx | 12 +- 11 files changed, 579 insertions(+), 80 deletions(-) create mode 100644 src/app/admin/devices/[id]/page.tsx create mode 100644 src/app/api/devices/[id]/command/route.ts create mode 100644 src/app/api/devices/[id]/firmware/route.ts diff --git a/README.md b/README.md index e215bc4..a85bf34 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,85 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). +# HDMI Tester Enterprise -## Getting Started +A high-performance orchestration and telemetry platform designed for real-time monitoring and lifecycle management of HDMI testing hardware. This platform provides a "single pane of glass" view for large fleets of test nodes, offering sub-ms edge latency tracking and remote hardware orchestration. -First, run the development server: +## 🚀 Key Features +- **Operational Telemetry**: Real-time monitoring of active nodes, test results, and system health. +- **Node Insights**: Tactical spectral analysis of HDMI bus metrics including DDC, CEC, and TMDS voltage verification. +- **Command Center**: Enterprise-grade fleet management for device enrollment and environment orchestration. +- **Device Configuration**: + - Remote renaming and identification. + - Multi-slot firmware management (A/B switching). + - Remote Power Controls (Reboot, Shutdown). + - Secure firmware binary deployment (.bin/.elf). +- **Premium UI/UX**: + - High-contrast Light and Dark modes. + - Safari-optimized rendering and backdrop filters. + - Fluid micro-animations and responsive layouts. + +## 🛠 Tech Stack + +- **Framework**: [Next.js 15](https://nextjs.org/) (App Router) +- **Database**: [Prisma](https://www.prisma.io/) with SQLite +- **Icons**: [Lucide React](https://lucide.dev/) +- **Styling**: Tailwind CSS with a custom CSS variable design system +- **Hardware Simulation**: Python-based simulator for headless testing + +## 🏁 Quick Start + +### 1. Prerequisites +Ensure you have Node.js (v18+) and Python 3 installed. + +### 2. Installation ```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev +# Clone the repository +git clone +cd hdmi-tester + +# Install dependencies +npm install ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +### 3. Database Initialisation +```bash +npx prisma db push +``` -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. +### 4. Launch the Platform +```bash +npm run dev +``` +Open [http://localhost:3000](http://localhost:3000) to access the dashboard. -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. +## 🤖 Hardware Simulation -## Learn More +To test the platform without physical hardware, use the provided simulator. It mimics a head unit with active mesh capabilities. -To learn more about Next.js, take a look at the following resources: +```bash +# Register a simulated device +python3 firmware/simulator.py register -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +# Interactive Orchestrator +python3 firmware/simulator.py +``` -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! +### Simulator Commands: +1. **Register / Sync**: Connects the simulator to the mesh. +2. **Report Test**: Generates mock HDMI spectral data. +3. **Swap Slot**: Updates the active orchestration slot (A/B). +4. **Automated Loop**: Continuously reports telemetry. -## Deploy on Vercel +## 🔌 API Overview -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +### Device Interaction +- `POST /api/devices/register`: Hardware enrollment. +- `PATCH /api/devices/[id]`: Update device configuration (Name, Slot). +- `POST /api/devices/[id]/command`: Remote power operations (Reboot, Shutdown). +- `POST /api/devices/[id]/firmware`: Orchestrated firmware deployment. -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. +### Telemetry Reporting +- `POST /api/tests/report`: Transmit spectral analysis results from hardware. +- `GET /api/dashboard/stats`: Retrieve aggregate fleet metrics. + +--- +*Built for precision. Orchestrated for scale.* diff --git a/firmware/config/device.json b/firmware/config/device.json index 3607472..c5ff9ec 100644 --- a/firmware/config/device.json +++ b/firmware/config/device.json @@ -2,5 +2,5 @@ "serial_number": "CB1FCDC3", "mode": "DEV", "active_slot": "A", - "status": "ENROLLED" + "status": "OFFLINE" } \ No newline at end of file diff --git a/prisma/dev.db b/prisma/dev.db index 950f50cbeaa8ee4775aa63c2dccdaf2a6fee81da..58b8b6fcd20bdcb40e00099a0081ba5525b9f802 100644 GIT binary patch delta 78 zcmZo@U~Xt&o*>QGH&Mo!v2SC-GJckc4Ez%}3o5knbLQnT^4iPlYfDd_A@3pY@8;&? g>F3Hg+p|dB(a})PK+gckR`sq1lD&#)ixd_B0EV9y!vFvP delta 78 zcmZo@U~Xt&o*>QGJyFJ)v3p~}GJci`4Ez%|3o5knbL27d+RN%|%TAst@1fx87v%5b g }) { + const { id } = React.use(params); + const router = useRouter(); + const [device, setDevice] = useState(null); + const [loading, setLoading] = useState(true); + const [saving, setSaving] = useState(false); + const [uploading, setUploading] = useState(false); + const [formData, setFormData] = useState({ name: "", activeSlot: "A" }); + const [file, setFile] = useState(null); + const [message, setMessage] = useState<{ type: "success" | "error"; text: string } | null>(null); + + useEffect(() => { + fetchDevice(); + }, [id]); + + const fetchDevice = async () => { + try { + const res = await fetch(`/api/devices`); + const data = await res.json(); + const found = data.find((d: Device) => d.id === id); + if (found) { + setDevice(found); + setFormData({ name: found.name || "", activeSlot: found.activeSlot || "A" }); + } + } catch (error) { + console.error(error); + } finally { + setLoading(false); + } + }; + + const handleSave = async () => { + setSaving(true); + try { + const res = await fetch(`/api/devices/${id}`, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(formData), + }); + if (res.ok) { + setMessage({ type: "success", text: "Device configuration synchronized." }); + fetchDevice(); + } + } catch (error) { + setMessage({ type: "error", text: "Synchronization failed." }); + } finally { + setSaving(false); + setTimeout(() => setMessage(null), 3000); + } + }; + + const handleCommand = async (command: "REBOOT" | "SHUTDOWN") => { + if (!confirm(`Confirm ${command.toLowerCase()} sequence for ${device?.serialNumber}?`)) return; + + try { + const res = await fetch(`/api/devices/${id}/command`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ command }), + }); + if (res.ok) { + setMessage({ type: "success", text: `${command} signal transmitted.` }); + } + } catch (error) { + setMessage({ type: "error", text: "Signal transmission failed." }); + } + }; + + const handleUpload = async () => { + if (!file) return; + setUploading(true); + try { + const fd = new FormData(); + fd.append("file", file); + fd.append("slot", formData.activeSlot); + + const res = await fetch(`/api/devices/${id}/firmware`, { + method: "POST", + body: fd, + }); + if (res.ok) { + setMessage({ type: "success", text: "Firmware orchestration complete." }); + setFile(null); + fetchDevice(); + } + } catch (error) { + setMessage({ type: "error", text: "Firmware deployment failed." }); + } finally { + setUploading(false); + } + }; + + if (loading) { + return ( +
+ +

Initialising Secure Direct Link...

+
+ ); + } + + if (!device) return
Device not found
; + + return ( +
+ {/* Breadcrumbs */} +
+ Admin + + Device Configuration + + {device.serialNumber} +
+ + {/* Header Area */} +
+
+

+ + {device.name || "Unnamed Node"} +

+

+ + HWID: {device.serialNumber} • {device.macAddress} +

+
+ +
+ + +
+
+ + {message && ( +
+ {message.type === "success" ? : } + {message.text} +
+ )} + +
+ {/* General Configuration */} +
+
+
+ +
+ +
+
+ +
+

General Parameters

+
+ +
+
+ + setFormData({ ...formData, name: e.target.value })} + className="w-full bg-secondary/5 border border-border rounded-xl px-5 py-3 text-sm font-bold text-foreground focus:border-sky-500/50 outline-none transition-all" + placeholder="Enter node name..." + /> +
+ +
+ +
+ {["A", "B"].map((s) => ( + + ))} +
+
+
+ +
+ +
+
+ + {/* Firmware Manifest */} +
+
+ +
+ +
+
+ +
+

Firmware Orchestration

+
+ +
+ {file ? ( +
+

{file.name}

+

{(file.size / 1024 / 1024).toFixed(2)} MB • Ready for deployment

+
+ ) : ( + <> +
+ +
+
+

Click to select manifest

+

Valid .bin or .elf binaries only

+
+ + )} + setFile(e.target.files?.[0] || null)} + accept=".bin,.elf" + /> +
+ + {file && ( + + )} +
+
+ + {/* Status Sidebar */} +
+
+

+ + Live Metrics +

+ +
+
+ Active Slot + Slot {device.activeSlot} +
+
+ Core Version + v{device.firmwareVersion} +
+
+ Mesh Status +
+ + {device.status} +
+
+
+ +
+
+
+
+ System Load + 24% +
+
+
+
+
+
+
+
+
+
+
+ ); +} diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index b5b07e4..b8c2cab 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -1,7 +1,7 @@ "use client"; import { useState, useEffect } from "react"; -import { Shield, ArrowRight, Settings2, PlusCircle, CheckCircle2, XCircle, Clock } from "lucide-react"; +import { Shield, ArrowRight, Settings2, PlusCircle, CheckCircle2, XCircle, Clock, ChevronRight } from "lucide-react"; import Link from "next/link"; interface Device { @@ -57,7 +57,7 @@ export default function AdminPage() {
Command Center -

Manage device fleet, enrollment, and firmware orchestration.

+

Manage device fleet, enrollment, and firmware orchestration.