Rebranded to console tester.

This commit is contained in:
2025-12-23 11:21:02 -05:00
parent a0403eef57
commit 7d8c835fee
7 changed files with 309 additions and 207 deletions

View File

@@ -1,11 +1,12 @@
# HDMI Tester Enterprise
# HDMI Console Diagnostics (Enterprise)
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.
A high-performance orchestration platform designed for real-time monitoring and repair diagnostics of **Console HDMI Ports** (PS5, Xbox, Switch). 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 for front-desk and technical staff.
## 🚀 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.
- **Port Telemetry**: Real-time monitoring of active nodes, port diagnostic results, and system health.
- **Port Insights**: Tactical spectral analysis of HDMI pins (DDC, CEC, TMDS) for board-level repair verification.
- **Retail & Enterprise Views**: Simplified "Good/Bad" UI for front-desk staff and detailed telemetry for technicians.
- **Command Center**: Enterprise-grade fleet management for device enrollment and environment orchestration.
- **Device Configuration**:
- Remote renaming and identification.
@@ -15,6 +16,7 @@ A high-performance orchestration and telemetry platform designed for real-time m
- **Premium UI/UX**:
- High-contrast Light and Dark modes.
- Safari-optimized rendering and backdrop filters.
- **Virtual Hardware Simulator**: A web-based tactile OLED emulator for immediate testing.
- Fluid micro-animations and responsive layouts.
## 🛠 Tech Stack
@@ -53,8 +55,13 @@ Open [http://localhost:3000](http://localhost:3000) to access the dashboard.
## 🤖 Hardware Simulation
To test the platform without physical hardware, use the provided simulator. It mimics a head unit with active mesh capabilities.
To test the platform without physical hardware, you can use either the interactive web emulator or the Python-based CLI simulator.
### Web Simulator (Recommended)
Access the tactile OLED emulator directly in your browser: [http://localhost:3000/simulator](http://localhost:3000/simulator)
- **Features**: Real-time OLED display, keyboard shortcuts (R/T/S/B), and live system logs.
### Python CLI Simulator
```bash
# Register a simulated device
python3 firmware/simulator.py register

View File

@@ -5,7 +5,7 @@ import requests
import uuid
import socket
class HeadUnit:
class PortTester:
def __init__(self, server_url="http://localhost:3000", config_path="firmware/config/device.json"):
self.server_url = server_url
self.config_path = config_path
@@ -109,42 +109,39 @@ class HeadUnit:
self.save_config()
print(f"[*] Switched to Slot {self.active_slot}.")
def generate_mock_hdmi_test():
def generate_console_port_test():
"""Generates mock spectral data for a console HDMI port."""
pins = ["DDC_SCL", "DDC_SDA", "CEC", "HPD", "TMDS_CLK+", "TMDS_CLK-"]
results = {pin: round(0.400 + (random.random() * 0.2), 3) for pin in pins}
return {
"type": "HDMI_OFFLINE",
"type": "PORT_DIAGNOSTIC",
"status": "PASS",
"hdmi5v": False,
"summary": "Offline diode check completed. All lines within tolerance.",
"diodeResults": {
"DDC_SCL": 0.542,
"DDC_SDA": 0.544,
"CEC": 0.612,
"HPD": 0.589,
"TMDS_CLK+": 0.498,
"TMDS_CLK-": 0.497
}
"hdmi5v": True,
"summary": "Port handshake confirmed. Pin continuity within spec.",
"diodeResults": results
}
if __name__ == "__main__":
hu = HeadUnit()
hu = PortTester()
def print_menu():
print("\n" + "="*45)
print(f" HDMI TESTER - HARDWARE SIMULATOR (v1.2.0)")
print(f" HDMI PORT DIAGNOSTICS - HARDWARE SIMULATOR")
print("="*45)
print(f" Status: [{hu.status}]")
print(f" Mode: [{hu.mode}]")
print(f" Active: [Slot {hu.active_slot}]")
print(f" Serial: [{hu.serial_number}]")
print(f" Node: [{hu.serial_number}]")
print("-" * 45)
print(" 1. Register / Sync Device")
print(" 2. Report Mock HDMI Test")
print(" 1. Register / Sync Port Diagnostics")
print(" 2. Run Console Port Sweep")
print(" 3. Switch to DEV Mode")
print(" 4. Switch to PROD Mode")
print(" 5. Swap Active Slot (A/B)")
print(" 6. Start Automated Loop")
print(" 7. Request Re-enlistment")
print(" 0. Exit Orchestrator")
print(" 0. Power Down Node")
print("-" * 45)
while True:
@@ -154,7 +151,7 @@ if __name__ == "__main__":
if choice == "1":
hu.register()
elif choice == "2":
hu.report_test(generate_mock_hdmi_test())
hu.report_test(generate_console_port_test())
elif choice == "3":
hu.switch_mode("DEV")
elif choice == "4":
@@ -171,7 +168,7 @@ if __name__ == "__main__":
break
if hu.status == "ENROLLED":
hu.report_test(generate_mock_hdmi_test())
hu.report_test(generate_console_port_test())
time.sleep(5)
if hu.status == "OFFLINE":

Binary file not shown.

View File

@@ -1,7 +1,7 @@
"use client";
import { useState, useEffect } from "react";
import { Shield, ArrowRight, Settings2, PlusCircle, CheckCircle2, XCircle, Clock, ChevronRight, RefreshCw } from "lucide-react";
import { Shield, ArrowRight, Settings2, PlusCircle, CheckCircle2, XCircle, Clock, ChevronRight, RefreshCw, Activity } from "lucide-react";
import Link from "next/link";
interface Device {
@@ -73,11 +73,25 @@ export default function AdminPage() {
</h1>
<p className="text-secondary font-medium text-sm tracking-wide">Manage device fleet, enrollment, and firmware orchestration.</p>
</div>
<div className="flex items-center gap-4">
<Link
href="/simulator"
className="group flex items-center gap-3 bg-secondary/5 border border-border px-5 py-2.5 rounded-2xl hover:bg-sky-500/10 hover:border-sky-500/30 transition-all active:scale-95"
>
<div className="w-8 h-8 rounded-lg bg-sky-500/10 flex items-center justify-center text-sky-500 group-hover:bg-sky-500 group-hover:text-white transition-all">
<Activity className="w-4 h-4" />
</div>
<div className="text-left">
<p className="text-[10px] font-black uppercase tracking-widest text-foreground">Launch Virtual Node</p>
<p className="text-[8px] font-bold text-secondary uppercase tracking-tight">OLED Hardware Emulator</p>
</div>
</Link>
<button className="bg-sky-500 hover:bg-sky-400 text-white px-6 py-2.5 rounded-2xl text-[10px] font-black uppercase tracking-widest flex items-center gap-3 transition-all shadow-[0_0_25px_rgba(56,189,248,0.2)] hover:scale-105 active:scale-95">
<PlusCircle className="w-4 h-4" />
Proactive Provisioning
</button>
</div>
</div>
<div className="grid grid-cols-1 gap-6">
<div className="bg-background border border-border rounded-[2rem] overflow-hidden backdrop-blur-xl">

View File

@@ -1,7 +1,7 @@
"use client";
import { useState, useEffect } from "react";
import { Activity, Cpu, CheckCircle2, AlertCircle, Clock, Zap } from "lucide-react";
import { Activity, Cpu, CheckCircle2, AlertCircle, Clock, Zap, RefreshCw } from "lucide-react";
import Link from "next/link";
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
@@ -41,6 +41,7 @@ export default function DashboardPage() {
const [loading, setLoading] = useState(true);
const [lastUpdate, setLastUpdate] = useState<Date | null>(null);
const [isUpdating, setIsUpdating] = useState(false);
const [viewMode, setViewMode] = useState<"ENTERPRISE" | "RETAIL">("ENTERPRISE");
const fetchData = async () => {
try {
@@ -97,6 +98,27 @@ export default function DashboardPage() {
Operational Telemetry
</h1>
</div>
<div className="flex items-center gap-4">
<div className="flex items-center gap-2 bg-secondary/5 p-1 rounded-xl border border-border">
<button
onClick={() => setViewMode("RETAIL")}
className={cn(
"px-4 py-1.5 rounded-lg text-[9px] font-black uppercase tracking-widest transition-all",
viewMode === "RETAIL" ? "bg-background text-foreground shadow-sm" : "text-secondary hover:text-foreground"
)}
>
Retail
</button>
<button
onClick={() => setViewMode("ENTERPRISE")}
className={cn(
"px-4 py-1.5 rounded-lg text-[9px] font-black uppercase tracking-widest transition-all",
viewMode === "ENTERPRISE" ? "bg-background text-foreground shadow-sm" : "text-secondary hover:text-foreground"
)}
>
Enterprise
</button>
</div>
<div className="flex items-center gap-3">
<div className="text-[10px] font-mono text-secondary uppercase tracking-tighter">
Last sync: <span className="text-foreground">{lastUpdate ? lastUpdate.toLocaleTimeString() : "--:--:--"}</span>
@@ -107,7 +129,67 @@ export default function DashboardPage() {
)} />
</div>
</div>
</div>
{viewMode === "RETAIL" ? (
/* Retail Mode UI - Ultra Simplified */
<div className="flex flex-col items-center justify-center py-20 animate-in zoom-in-95 duration-700">
<div className={cn(
"w-full max-w-2xl overflow-hidden rounded-[3rem] p-16 text-center border-2 transition-all duration-1000",
data.recentTests[0]?.status === "PASS"
? "bg-emerald-500/5 border-emerald-500/20 text-emerald-500 shadow-[0_20px_100px_rgba(16,185,129,0.1)]"
: "bg-rose-500/5 border-rose-500/20 text-rose-500 shadow-[0_20px_100px_rgba(244,63,94,0.1)]"
)}>
<div className="space-y-8">
<div className="flex justify-center">
<div className={cn(
"w-32 h-32 rounded-full flex items-center justify-center border-8 transition-all duration-1000 shadow-xl",
data.recentTests[0]?.status === "PASS" ? "bg-emerald-500/10 border-emerald-500" : "bg-rose-500/10 border-rose-500"
)}>
{data.recentTests[0]?.status === "PASS" ? (
<CheckCircle2 className="w-16 h-16" />
) : (
<AlertCircle className="w-16 h-16" />
)}
</div>
</div>
<div className="space-y-4">
<h2 className="text-8xl font-black tracking-tighter uppercase">
{data.recentTests[0]?.status === "PASS" ? "Port OK" : "Port Fail"}
</h2>
<div className="h-px w-24 bg-current/20 mx-auto" />
<p className="text-foreground/70 font-bold text-2xl uppercase tracking-widest italic">
{data.recentTests[0]?.status === "PASS" ? "HDMI Port is Functional" : "Console Port Requires Repair"}
</p>
</div>
<div className="pt-10 flex flex-col items-center gap-4">
<div className="px-6 py-2 bg-foreground/5 border border-foreground/10 rounded-full flex items-center gap-3">
<div className="w-2 h-2 rounded-full bg-foreground animate-pulse" />
<span className="text-[10px] font-black uppercase tracking-[0.2em] text-foreground">Waiting for Next Console</span>
</div>
<p className="text-secondary font-medium text-sm">
Last test: {data.recentTests[0]?.summary}
</p>
</div>
</div>
</div>
<div className="mt-12 flex items-center gap-8">
<div className="text-center">
<p className="text-[10px] font-black text-secondary uppercase tracking-widest mb-1">Active Station</p>
<p className="text-sm font-black text-foreground">{data.enrolledDevices[0]?.name || "Front Desk 01"}</p>
</div>
<div className="w-px h-8 bg-border" />
<div className="text-center">
<p className="text-[10px] font-black text-secondary uppercase tracking-widest mb-1">Today's Volume</p>
<p className="text-sm font-black text-foreground">{data.stats.testCount} Tests</p>
</div>
</div>
</div>
) : (
<div className="space-y-10">
{/* Hero Stats */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{[
@@ -243,7 +325,7 @@ export default function DashboardPage() {
</h4>
<div className="space-y-3 relative z-10">
<p className="text-xs text-secondary leading-relaxed font-medium">
Real-time spectral analysis of HDMI bus metrics. Processing orchestrated with <span className="text-sky-400 font-bold">sub-ms</span> edge latency.
Real-time spectral analysis of <span className="text-foreground">Console HDMI Ports</span>. Processing orchestrated with <span className="text-sky-400 font-bold">sub-ms</span> edge latency.
</p>
<div className="flex items-center gap-2 py-3 border-t border-sky-500/10">
<span className="relative flex h-2 w-2">
@@ -286,5 +368,7 @@ export default function DashboardPage() {
</div>
</div>
</div>
)}
</div>
);
}

View File

@@ -102,7 +102,7 @@ export default function WebSimulatorPage() {
return;
}
setState(s => ({ ...s, isTesting: true }));
addLog("[OP] Initiating HDMI spectral sweep...");
addLog("[OP] Initiating HDMI Port Diagnostic sweep...");
await new Promise(r => setTimeout(r, 1500));
@@ -111,10 +111,10 @@ export default function WebSimulatorPage() {
method: "POST",
body: JSON.stringify({
serialNumber: state.serialNumber,
type: "HDMI_OFFLINE",
type: "PORT_DIAGNOSTIC",
status: "PASS",
hdmi5v: false,
summary: "Virtual sweep completed within threshold.",
hdmi5v: true,
summary: "Port handshake confirmed. Pin continuity within spec.",
diodeResults: {
"DDC_SCL": 0.500 + Math.random() * 0.1,
"DDC_SDA": 0.500 + Math.random() * 0.1,
@@ -215,9 +215,9 @@ export default function WebSimulatorPage() {
{/* Main Content */}
<div className="flex flex-col items-center justify-center flex-1">
<div className="text-white text-lg font-black tracking-tighter leading-none mb-1">
{state.isTesting ? "RUNNING SWEEP" : state.serialNumber}
{state.isTesting ? "PORT SWEEP" : state.serialNumber}
</div>
<div className="text-[8px] text-sky-400/60 font-black uppercase tracking-[0.2em]">Validated Path v1.0</div>
<div className="text-[8px] text-sky-400/60 font-black uppercase tracking-[0.2em]">Console Interface v1.0</div>
</div>
{/* Bottom Console */}

View File

@@ -28,7 +28,7 @@ export default async function TestDetailsPage({ params }: { params: Promise<{ id
<Activity className="w-3 h-3" /> Dashboard
</Link>
<span className="opacity-20">/</span>
<span className="text-secondary/70">Node Insights</span>
<span className="text-secondary/70">Port Diagnostic Insights</span>
</div>
<div className="flex flex-col md:flex-row md:items-end justify-between gap-8 pb-8 border-b border-border">
@@ -85,7 +85,7 @@ export default async function TestDetailsPage({ params }: { params: Promise<{ id
<div className="w-10 h-10 rounded-xl bg-sky-500/10 flex items-center justify-center">
<Info className="w-5 h-5 text-sky-400" />
</div>
<h2 className="text-[10px] font-black uppercase tracking-[0.3em] text-secondary">Response Spectrum Analysis</h2>
<h2 className="text-[10px] font-black uppercase tracking-[0.3em] text-secondary">HDMI Port Pinout Analysis</h2>
</div>
<div className="px-4 py-1.5 bg-sky-500/10 border border-sky-500/20 rounded-full text-[9px] font-black text-sky-400 uppercase tracking-widest">
Calibration: 0.8V VDD