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:
10
HARDWARE.md
10
HARDWARE.md
@@ -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.
|
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
|
### 1. Microcontroller: ESP32 (S3 or DevKitV1)
|
||||||
- **ESP32**: Integrated Wi-Fi/BT (good for future logging), multiple ADCs.
|
- **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)**: Great documentation, dual-core, very affordable, stable ADCs.
|
- **RP2040 (Pico W)**: Also an option, but ESP32 has better community support for async HTTP clients.
|
||||||
- **Recommendation**: **Raspberry Pi Pico** for its simplicity and 3.3V logic which is safer for HDMI lines.
|
- **Recommendation**: **ESP32-S3** for its high number of GPIOs and built-in Wi-Fi.
|
||||||
|
|
||||||
### 2. Multiplexers (Mux)
|
### 2. Multiplexers (Mux)
|
||||||
Since the Pico doesn't have 19 ADC pins, we need multiplexers to switch between the HDMI pins.
|
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
|
## Next Steps
|
||||||
1. Define the Pinout mapping.
|
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.
|
3. Implement the measurement logic.
|
||||||
|
|||||||
36
server/index.js
Normal file
36
server/index.js
Normal 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
65
server/public/index.html
Normal 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
34
src/esp32_wifi.ino
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user