Skip to content

Commit 715d867

Browse files
fhirschmannclaude
andcommitted
feat: system-info dialog as a table + PN5180 reader firmware
Renders the information dialog as a property/value table instead of a preformatted text blob and adds the PN5180 RFID-reader firmware version. The version is read once from the reader EEPROM during init, cached, and exposed through /info (hardware.readerFirmware) for RFID_READER_TYPE_RUNTIME builds. New systeminfo label keys added to all locales. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent aef1765 commit 715d867

8 files changed

Lines changed: 133 additions & 73 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ neon logo that doubles as the SVG favicon ([`8d9725c`](../../commit/8d9725c)):
8888
| Control buttons (single-track Repeat toggle, Sleep-Timer with dropdown and live remaining countdown, Night Mode/Dimming) directly in the control tab of the web interface | [`6918d36`](../../commit/6918d36) |
8989
| Bluetooth-mode dropdown in the control tab (Normal / Speaker / Headphones), mirroring the sleep-timer dropdown; selecting a mode restarts the device into it and the button highlights the active BT mode | [`b9f1e5c`](../../commit/b9f1e5c) |
9090
| Mobile-optimized control tab: the hard-to-drag volume slider is replaced by full-width louder/quieter (+ EQ) buttons on phones, and the control header stacks so the legend stays on one line with the action buttons below | [`f10bc93`](../../commit/f10bc93) |
91+
| System-information dialog rendered as a clean property/value table (instead of preformatted text) and extended with the PN5180 RFID-reader firmware version (read once from the reader's EEPROM at init and exposed via `/info`) | [`56f5fda`](../../commit/56f5fda) |
9192

9293
#### Feature highlights
9394

‎html/locales/de.json‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,25 @@
595595
"seconds": "Sekunden"
596596
},
597597
"systeminfo": {
598+
"lblSoftware": "Software",
599+
"lblGit": "Git-Revision",
600+
"lblEnv": "Arduino / ESP-IDF",
601+
"lblChip": "Chip",
602+
"lblCpu": "CPU-Takt",
603+
"lblReader": "RFID-Reader-Firmware",
604+
"lblHeap": "Freier Heap",
605+
"lblHeapBlock": "Größter freier Block",
606+
"lblPsram": "Freies PSRAM",
607+
"lblIp": "IP-Adresse",
608+
"lblMac": "MAC-Adresse",
609+
"lblRssi": "WLAN-Signal",
610+
"lblSince": "In Betrieb seit",
611+
"lblPlayTotal": "Gesamte Spielzeit",
612+
"lblPlaySince": "Spielzeit seit Start",
613+
"lblSd": "SD-Karte",
614+
"lblVoltage": "Akkuspannung",
615+
"lblCharge": "Ladezustand",
616+
"lblHall": "Hall-Sensor",
598617
"title": "Information",
599618
"softwareversion": "ESPuino {{softwareversion}}",
600619
"gitversion": "ESPuino {{gitversion}}",

‎html/locales/en.json‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,25 @@
597597
"seconds": "seconds"
598598
},
599599
"systeminfo": {
600+
"lblSoftware": "Software",
601+
"lblGit": "Git revision",
602+
"lblEnv": "Arduino / ESP-IDF",
603+
"lblChip": "Chip",
604+
"lblCpu": "CPU clock",
605+
"lblReader": "RFID reader firmware",
606+
"lblHeap": "Free heap",
607+
"lblHeapBlock": "Largest free block",
608+
"lblPsram": "Free PSRAM",
609+
"lblIp": "IP address",
610+
"lblMac": "MAC address",
611+
"lblRssi": "WiFi signal",
612+
"lblSince": "In service since",
613+
"lblPlayTotal": "Total playtime",
614+
"lblPlaySince": "Playtime since start",
615+
"lblSd": "SD card",
616+
"lblVoltage": "Battery voltage",
617+
"lblCharge": "Charge level",
618+
"lblHall": "Hall sensor",
600619
"title": "Information",
601620
"softwareversion": "ESPuino {{softwareversion}}",
602621
"gitversion": "ESPuino {{gitversion}}",

‎html/locales/fr.json‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,25 @@
584584
"seconds": "secondes"
585585
},
586586
"systeminfo": {
587+
"lblSoftware": "Logiciel",
588+
"lblGit": "Révision Git",
589+
"lblEnv": "Arduino / ESP-IDF",
590+
"lblChip": "Puce",
591+
"lblCpu": "Fréquence CPU",
592+
"lblReader": "Firmware du lecteur RFID",
593+
"lblHeap": "Mémoire libre",
594+
"lblHeapBlock": "Plus grand bloc libre",
595+
"lblPsram": "PSRAM libre",
596+
"lblIp": "Adresse IP",
597+
"lblMac": "Adresse MAC",
598+
"lblRssi": "Signal WiFi",
599+
"lblSince": "En service depuis",
600+
"lblPlayTotal": "Temps de lecture total",
601+
"lblPlaySince": "Lecture depuis le démarrage",
602+
"lblSd": "Carte SD",
603+
"lblVoltage": "Tension batterie",
604+
"lblCharge": "Niveau de charge",
605+
"lblHall": "Capteur Hall",
587606
"title": "Informations",
588607
"softwareversion": "ESPuino {{softwareversion}}",
589608
"gitversion": "ESPuino {{gitversion}}",

‎html/management.html‎

Lines changed: 50 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,25 @@
10561056
font-family: "Share Tech Mono", monospace;
10571057
}
10581058

1059+
/* system information table */
1060+
.cp-info-table th {
1061+
white-space: nowrap;
1062+
width: 1%;
1063+
padding-right: 18px;
1064+
color: var(--cp-cyan);
1065+
font-weight: 600;
1066+
}
1067+
1068+
.cp-info-table td {
1069+
word-break: break-word;
1070+
color: var(--cp-text, #cfe9ff);
1071+
}
1072+
1073+
.cp-info-table tr+tr th,
1074+
.cp-info-table tr+tr td {
1075+
border-top: 1px solid var(--cp-border);
1076+
}
1077+
10591078
/* ---------- toasts ---------- */
10601079
.toast {
10611080
background: var(--cp-panel);
@@ -1441,7 +1460,7 @@
14411460
<div class="modal-header">
14421461
<h5 class="modal-title" data-i18n="infos"></h5>
14431462
</div>
1444-
<div class="modal-body" style="white-space: pre" id="modalInfoContent">
1463+
<div class="modal-body" id="modalInfoContent">
14451464
</div>
14461465
<div class="modal-footer">
14471466
<button type="button" id="modalInfoRefresh" class="btn btn-primary me-auto"><i
@@ -5442,76 +5461,38 @@ <h5 class="modal-title" data-i18n="tools.nvs.erase.title"></h5>
54425461
async function fetchInfo() {
54435462
let info = await (await fetch("http://" + host + "/info")).json();
54445463
console.log(info);
5445-
let content = i18next.t("systeminfo.softwareversion", {
5446-
softwareversion: info.software.version
5447-
}) + "<br>";
5448-
content += i18next.t("systeminfo.gitversion", {
5449-
gitversion: info.software.git
5450-
}) + "<br>";
5451-
content += i18next.t("systeminfo.arduinoversion", {
5452-
arduinoversion: info.software.arduino,
5453-
idfversion: info.software.idf
5454-
}) + "<br>";
5455-
content += i18next.t("systeminfo.hardware", {
5456-
hwmodel: info.hardware.model,
5457-
hwrevision: info.hardware.revision,
5458-
hwfreq: info.hardware.freq
5459-
}) + "<br>";
5460-
content += i18next.t("systeminfo.freeheap", {
5461-
freeheap: info.memory.freeHeap
5462-
}) + "<br>";
5463-
content += i18next.t("systeminfo.largestfreeblock", {
5464-
largestfreeblock: info.memory.largestFreeBlock
5465-
}) + "<br>";
5466-
if (info.memory.freePSRam) {
5467-
content += i18next.t("systeminfo.freepsram", {
5468-
freepsram: info.memory.freePSRam
5469-
}) + "<br>";
5470-
}
5471-
content += i18next.t("systeminfo.currentip", {
5472-
currentip: info.wifi.ip
5473-
}) + "<br>";
5474-
content += i18next.t("systeminfo.macAddress", {
5475-
macAddress: info.wifi.macAddress
5476-
}) + "<br>";
5477-
content += i18next.t("systeminfo.rssi", {
5478-
rssi: info.wifi.rssi
5479-
}) + "<br>";
5480-
content += i18next.t("systeminfo.audiotimetotal", {
5481-
firststart: secondsToDate(info.audio.firstStart),
5482-
audiotimetotal: timestampToDuration(info.audio.playtimeTotal, false)
5483-
}) + "<br>";
5484-
if (info.audio.playtimeSinceStart > 0) {
5485-
content += i18next.t("systeminfo.audiotimesincestart", {
5486-
audiotimesincestart: timestampToDuration(info.audio.playtimeSinceStart, true)
5487-
}) + "<br>";
5488-
}
5489-
if (info.sdcard && info.sdcard.size) {
5490-
content += i18next.t("systeminfo.sdcard", {
5491-
free: (info.sdcard.free / 1024).toFixed(1),
5492-
total: (info.sdcard.size / 1024).toFixed(1)
5493-
}) + "<br>";
5494-
}
5464+
const esc = (typeof escapeHtml === 'function') ? escapeHtml : function (x) { return x; };
5465+
const num = function (n) { return Number(n).toLocaleString(); };
5466+
const rows = [];
5467+
const add = function (labelKey, value) {
5468+
if (value === undefined || value === null || value === '') return;
5469+
rows.push('<tr><th scope="row">' + i18next.t(labelKey) + '</th><td>' + esc(String(value)) + '</td></tr>');
5470+
};
5471+
5472+
add('systeminfo.lblSoftware', info.software.version);
5473+
add('systeminfo.lblGit', info.software.git);
5474+
add('systeminfo.lblEnv', info.software.arduino + ' / ' + info.software.idf);
5475+
add('systeminfo.lblChip', info.hardware.model + ' (rev ' + info.hardware.revision + ')');
5476+
add('systeminfo.lblCpu', info.hardware.freq + ' MHz');
5477+
if (info.hardware.readerFirmware) add('systeminfo.lblReader', 'PN5180 ' + info.hardware.readerFirmware);
5478+
add('systeminfo.lblHeap', num(info.memory.freeHeap) + ' B');
5479+
add('systeminfo.lblHeapBlock', num(info.memory.largestFreeBlock) + ' B');
5480+
if (info.memory.freePSRam) add('systeminfo.lblPsram', num(info.memory.freePSRam) + ' B');
5481+
add('systeminfo.lblIp', info.wifi.ip);
5482+
add('systeminfo.lblMac', info.wifi.macAddress);
5483+
add('systeminfo.lblRssi', info.wifi.rssi + ' dBm');
5484+
add('systeminfo.lblSince', secondsToDate(info.audio.firstStart));
5485+
add('systeminfo.lblPlayTotal', timestampToDuration(info.audio.playtimeTotal, false));
5486+
if (info.audio.playtimeSinceStart > 0) add('systeminfo.lblPlaySince', timestampToDuration(info.audio.playtimeSinceStart, true));
5487+
if (info.sdcard && info.sdcard.size) add('systeminfo.lblSd', (info.sdcard.free / 1024).toFixed(1) + ' / ' + (info.sdcard.size / 1024).toFixed(1) + ' GB');
54955488
if (info.battery) {
5496-
content += i18next.t("systeminfo.currvoltage", {
5497-
currvoltage: info.battery.currVoltage.toFixed(2)
5498-
}) + "<br>";
5499-
if (info.battery.chargelevel) {
5500-
content += i18next.t("systeminfo.chargelevel", {
5501-
chargelevel: info.battery.chargeLevel.toFixed(1)
5502-
}) + "<br>";
5503-
}
5489+
add('systeminfo.lblVoltage', info.battery.currVoltage.toFixed(2) + ' V');
5490+
if (info.battery.chargeLevel) add('systeminfo.lblCharge', info.battery.chargeLevel.toFixed(1) + ' %');
55045491
}
5505-
if (info.hallsensor) {
5506-
content += i18next.t("systeminfo.hallsensor", {
5507-
hsnullfieldvalue: info.hallsensor.nullFieldValue,
5508-
hsactual: info.hallsensor.actual,
5509-
hsdiff: info.hallsensor.diff,
5510-
hslastwaitforstate: info.hallsensor.lastWaitState,
5511-
hswaited: info.hallsensor.lastWaitMS
5512-
}) + "<br>";
5513-
}
5514-
$('#modalInfoContent').html(content);
5492+
if (info.hallsensor) add('systeminfo.lblHall', 'null ' + info.hallsensor.nullFieldValue + ', actual ' + info.hallsensor.actual + ', diff ' + info.hallsensor.diff);
5493+
5494+
const html = '<table class="table table-sm table-borderless cp-info-table mb-0"><tbody>' + rows.join('') + '</tbody></table>';
5495+
$('#modalInfoContent').html(html);
55155496
}
55165497
var liveLogInterval;
55175498
async function fetchLog() {

‎src/Rfid.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ void Rfid_TaskResume(void);
1414
void Rfid_TaskReset(void);
1515
void Rfid_WakeupCheck(void);
1616
void Rfid_PreferenceLookupHandler(void);
17+
const char *Rfid_GetReaderFirmwareVersion(void); // PN5180 reader firmware version (RFID_READER_TYPE_RUNTIME builds only)

‎src/RfidPn5180.cpp‎

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ static void RfidPn5180_Task(void *parameter);
4747
uint8_t stateMachine = RFID_PN5180_STATE_INIT;
4848
static bool rfidTaskResetRequested = false;
4949
static byte lastValidcardId[cardIdSize];
50+
static char Rfid_ReaderFwVersion[12] = ""; // cached PN5180 firmware version (e.g. "4.0"), read once at init
5051

5152
static bool Rfid_Pn5180LpcdEnabled(void) {
5253
return gPrefsRfid.getBool("pn5180Lpcd", false);
@@ -188,10 +189,17 @@ void RfidPn5180_Task(void *parameter) {
188189
if (RFID_PN5180_STATE_INIT == stateMachine) {
189190
nfc14443.begin();
190191
nfc14443.reset();
191-
// show PN5180 reader version
192-
// uint8_t firmwareVersion[2];
193-
// nfc14443.readEEprom(FIRMWARE_VERSION, firmwareVersion, sizeof(firmwareVersion));
194-
// Log_Printf(LOGLEVEL_DEBUG, "PN5180 firmware version=%d.%d", firmwareVersion[1], firmwareVersion[0]);
192+
// read and cache the PN5180 reader firmware version once (for the info dialog).
193+
// Only cache a plausible value: if no (or a non-PN5180) reader is connected the
194+
// EEPROM read yields garbage (0x00/0xFF), which we reject so /info omits the field.
195+
if (Rfid_ReaderFwVersion[0] == '\0') {
196+
uint8_t firmwareVersion[2] = {0, 0};
197+
if (nfc14443.readEEprom(FIRMWARE_VERSION, firmwareVersion, sizeof(firmwareVersion))
198+
&& firmwareVersion[1] != 0x00 && firmwareVersion[1] != 0xFF) {
199+
snprintf(Rfid_ReaderFwVersion, sizeof(Rfid_ReaderFwVersion), "%d.%d", firmwareVersion[1], firmwareVersion[0]);
200+
Log_Printf(LOGLEVEL_DEBUG, "PN5180 firmware version=%s", Rfid_ReaderFwVersion);
201+
}
202+
}
195203

196204
// activate RF field
197205
delay(4u);
@@ -537,4 +545,9 @@ void RfidPn5180_WakeupCheck(void) {
537545
}
538546
nfc14443.end();
539547
}
548+
549+
// Returns the cached PN5180 reader firmware version (e.g. "4.0"), or "" if not yet read.
550+
const char *Rfid_GetReaderFirmwareVersion(void) {
551+
return Rfid_ReaderFwVersion;
552+
}
540553
#endif

‎src/Web.cpp‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1712,6 +1712,13 @@ void handleGetInfo(AsyncWebServerRequest *request) {
17121712
hardwareObj["model"] = String(ESP.getChipModel());
17131713
hardwareObj["revision"] = ESP.getChipRevision();
17141714
hardwareObj["freq"] = ESP.getCpuFreqMHz();
1715+
#if defined(RFID_READER_TYPE_RUNTIME)
1716+
// PN5180 reader firmware version (empty until the reader has been initialised once)
1717+
const char *readerFw = Rfid_GetReaderFirmwareVersion();
1718+
if (readerFw && readerFw[0] != '\0') {
1719+
hardwareObj["readerFirmware"] = String(readerFw);
1720+
}
1721+
#endif
17151722
}
17161723
// memory
17171724
if ((section == "") || (section == "memory")) {

0 commit comments

Comments
 (0)