docs: switch to ESP32-S3 and add logging server

- Update HARDWARE.md to recommend ESP32-S3 over RP2040 to support Wi-Fi
  logging capabilities and better GPIO availability.
- Initialize a Node.js Express server to receive and store test results
  from the hardware device.
- Add a web-based dashboard to visualize HDMI pin status history, including
  basic pass/fail logic for voltage drops.
This commit is contained in:
2025-12-24 00:24:55 -05:00
parent fbba9e731b
commit 2bfb34724d
4 changed files with 140 additions and 5 deletions

View File

@@ -9,10 +9,10 @@ This project aims to create a handheld HDMI tester for console repair technician
To measure diode mode (voltage drop across a diode junction), we need a microcontroller with an ADC and the ability to source a small constant current or use a pull-up resistor.
### 1. Microcontroller: ESP32 or Raspberry Pi Pico
- **ESP32**: Integrated Wi-Fi/BT (good for future logging), multiple ADCs.
- **RP2040 (Pico)**: Great documentation, dual-core, very affordable, stable ADCs.
- **Recommendation**: **Raspberry Pi Pico** for its simplicity and 3.3V logic which is safer for HDMI lines.
### 1. Microcontroller: ESP32 (S3 or DevKitV1)
- **ESP32**: Integrated Wi-Fi/BT is essential for the server-side logging feature. It has multiple ADCs and enough GPIOs to drive the multiplexers.
- **RP2040 (Pico W)**: Also an option, but ESP32 has better community support for async HTTP clients.
- **Recommendation**: **ESP32-S3** for its high number of GPIOs and built-in Wi-Fi.
### 2. Multiplexers (Mux)
Since the Pico doesn't have 19 ADC pins, we need multiplexers to switch between the HDMI pins.
@@ -39,5 +39,5 @@ Since the Pico doesn't have 19 ADC pins, we need multiplexers to switch between
## Next Steps
1. Define the Pinout mapping.
2. Create the software structure (C++ or MicroPython).
2. Create the software structure (C++ / Arduino with ESP32 WiFi libraries).
3. Implement the measurement logic.

36
server/index.js Normal file
View File

@@ -0,0 +1,36 @@
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
app.use(express.static('public'));
let testResults = [];
// Endpoint for the HDMI Tester to upload results
app.post('/api/results', (req, res) => {
const { deviceId, mode, results } = req.body;
const testId = testResults.length + 1;
const timestamp = new Date().toISOString();
const newEntry = {
testId,
deviceId,
mode,
timestamp,
results
};
testResults.push(newEntry);
console.log(`Received test #${testId} from ${deviceId}`);
res.status(201).json({ status: 'success', testId });
});
// Endpoint for the Web Interface to get all results
app.get('/api/results', (req, res) => {
res.json(testResults);
});
app.listen(port, () => {
console.log(`HDMI Tester Server running at http://localhost:${port}`);
});

65
server/public/index.html Normal file
View File

@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HDMI Tester Dashboard</title>
<style>
body { font-family: sans-serif; background: #f4f4f4; padding: 20px; }
.test-card { background: white; border-radius: 8px; padding: 15px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
.pass { color: green; font-weight: bold; }
.fail { color: red; font-weight: bold; }
table { width: 100%; border-collapse: collapse; margin-top: 10px; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
.short { background-color: #ffcccc; }
.open { background-color: #fff3cd; }
</style>
</head>
<body>
<h1>HDMI Tester History</h1>
<div id="results-container">Loading results...</div>
<script>
async function fetchResults() {
const response = await fetch('/api/results');
const data = await response.json();
const container = document.getElementById('results-container');
container.innerHTML = '';
data.reverse().forEach(test => {
const card = document.createElement('div');
card.className = 'test-card';
let isPass = true;
let rows = '';
test.results.forEach(r => {
let statusClass = '';
if (r.voltage < 0.1) { statusClass = 'short'; isPass = false; }
else if (r.voltage > 1.0 && r.pinName !== '+5V') { statusClass = 'open'; isPass = false; }
rows += `<tr class="${statusClass}">
<td>${r.pinName}</td>
<td>${r.voltage.toFixed(2)}V</td>
</tr>`;
});
card.innerHTML = `
<h3>Test #${test.testId} - ${new Date(test.timestamp).toLocaleString()}</h3>
<p>Device: ${test.deviceId} | Mode: ${test.mode}</p>
<p>Status: <span class="${isPass ? 'pass' : 'fail'}">${isPass ? 'PASS' : 'FAIL'}</span></p>
<table>
<thead><tr><th>Pin Name</th><th>Voltage</th></tr></thead>
<tbody>${rows}</tbody>
</table>
`;
container.appendChild(card);
});
}
fetchResults();
setInterval(fetchResults, 5000); // Auto-refresh every 5s
</script>
</body>
</html>

34
src/esp32_wifi.ino Normal file
View File

@@ -0,0 +1,34 @@
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* serverUrl = "http://YOUR_SERVER_IP:3000/api/results";
void sendResultsToServer(String mode, JsonArray results) {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(serverUrl);
http.addHeader("Content-Type", "application/json");
StaticJsonDocument<2048> doc;
doc["deviceId"] = "HDMI_TESTER_01";
doc["mode"] = mode;
doc["results"] = results;
String requestBody;
serializeJson(doc, requestBody);
int httpResponseCode = http.POST(requestBody);
if (httpResponseCode > 0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
} else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
http.end();
}
}