From c4468c4af0120e62d4e66269c24c6d5359c0c0a2 Mon Sep 17 00:00:00 2001 From: Ben Nicholson Date: Fri, 25 Sep 2026 23:42:35 +1000 Subject: [PATCH] Network: status reports mask/gw/dns; UI shows the DHCP lease in the static fields With DHCP on, the greyed-out IP/netmask/gateway/DNS fields show the addresses in use. Unticking DHCP keeps them as the starting point for a static setup. (Static addressing itself is not applied yet.) Co-Authored-By: Claude Opus 5.5 --- components/aes67_net/aes67_net.c | 14 +++++++++++++- docs/aes67-core-base.md | 3 ++- web/index.html | 9 +++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/components/aes67_net/aes67_net.c b/components/aes67_net/aes67_net.c index f984828..ba95825 100644 --- a/components/aes67_net/aes67_net.c +++ b/components/aes67_net/aes67_net.c @@ -138,10 +138,19 @@ static void net_apply(const cJSON *g) static void net_status(cJSON *st) { - char ip[16] = "", mac_s[18] = ""; + char ip[16] = "", mask[16] = "", gw[16] = "", dns[16] = "", mac_s[18] = ""; esp_netif_ip_info_t info; if (esp_netif_get_ip_info(s_netif, &info) == ESP_OK && info.ip.addr) { snprintf(ip, sizeof(ip), IPSTR, IP2STR(&info.ip)); + snprintf(mask, sizeof(mask), IPSTR, IP2STR(&info.netmask)); + if (info.gw.addr) { + snprintf(gw, sizeof(gw), IPSTR, IP2STR(&info.gw)); + } + } + esp_netif_dns_info_t d; + if (esp_netif_get_dns_info(s_netif, ESP_NETIF_DNS_MAIN, &d) == ESP_OK && d.ip.type == ESP_IPADDR_TYPE_V4 && + d.ip.u_addr.ip4.addr) { + snprintf(dns, sizeof(dns), IPSTR, IP2STR(&d.ip.u_addr.ip4)); } uint8_t mac[6]; if (esp_netif_get_mac(s_netif, mac) == ESP_OK) { @@ -151,6 +160,9 @@ static void net_status(cJSON *st) // Single untagged interface until the VLAN split: AES67 and web share it. cJSON_AddStringToObject(st, "ip", ip); cJSON_AddStringToObject(st, "aes67_ip", ip); + cJSON_AddStringToObject(st, "mask", mask); // in use (from DHCP or static) + cJSON_AddStringToObject(st, "gw", gw); + cJSON_AddStringToObject(st, "dns", dns); cJSON_AddStringToObject(st, "mac", mac_s); cJSON_AddStringToObject(st, "link", s_link); } diff --git a/docs/aes67-core-base.md b/docs/aes67-core-base.md index b9829e6..edeaf6f 100644 --- a/docs/aes67-core-base.md +++ b/docs/aes67-core-base.md @@ -26,12 +26,13 @@ Reference devices for UI and defaults: Riedel Bolero (PTP status), Riedel Direct ## Core API - GET/POST /api/config (full JSON; POST validates, stores to NVS, applies live where possible, returns 4xx with message on bad values) - Write-only keys (`cfg_mark_secret`, e.g. passwords/client secrets): GET returns "" for them; a POST with "" keeps the stored value, null clears it. Stored in NVS in plain text (NVS encryption is not enabled). -- GET /api/status -> {model?, fw?, power?, ip, aes67_ip, inet_ip, inet_vlan, mac, link, tx_packets, underruns, uptime_s, heap_free, psram_free, temps:[…], ptp:{…}, …project fields} +- GET /api/status -> {model?, fw?, power?, ip, aes67_ip, mask, gw, dns, inet_ip, inet_vlan, mac, link, tx_packets, underruns, uptime_s, heap_free, psram_free, temps:[…], ptp:{…}, …project fields} - model, fw, power are optional; rows only appear when present (power e.g. "PoE" / "USB" if the board can detect it). - GET /stream.sdp, POST /api/reboot, POST /api/log/test - Firmware: GET /api/ota, POST /api/ota, POST /api/ota/confirm, POST /api/ota/rollback (see Firmware update) ## Temperatures +- `status.ip/mask/gw/dns` = the addresses in use (from DHCP or static; "" when none). With DHCP on, the UI shows them in the greyed-out static fields; unticking DHCP keeps them there as the starting point for a static setup. - `status.temps` = array of {name, c, min_c, max_c, warn_c}; min/max since boot, warn_c optional. Any number of sensors; the UI renders one row per sensor and marks HIGH (red) at or above warn_c. - ESP32-P4: on-die sensor via the `temperature_sensor` driver (driver/temperature_sensor.h). Pick the measurement range to suit (e.g. -10..80 °C), sample every ~2 s in the health task, and report it as "SoC". It measures the die, not ambient: expect it to read well above room temperature. - Implemented with range 20..100 °C (±2 °C; the warning level must lie inside the range), warn_c 85 °C. On the test board the die reads ~27 °C at idle in a cool room. diff --git a/web/index.html b/web/index.html index 9925965..25546ad 100644 --- a/web/index.html +++ b/web/index.html @@ -341,6 +341,13 @@ function read() { return out; } +// With DHCP on, the greyed-out static fields show what DHCP gave us. Unticking DHCP leaves the values +// there (a starting point for static addressing) until they are edited. +function netLive() { + if (!f['net.dhcp'].checked || !st.ip) return; + for (const k of ['ip','mask','gw','dns']) f['net.' + k].value = st[k] ?? ''; +} + function toggle() { PROJECT.toggle?.(f); const role = f['ptp.role'].value; @@ -354,6 +361,7 @@ function toggle() { } // VLAN split: default route lives on the internet VLAN, so the AES67 side gets no gateway/DNS. if (vlan) f['net.gw'].disabled = f['net.dns'].disabled = true; + netLive(); // RTP multicast must be 224.0.2.0 – 239.255.255.255 (same range Riedel Director enforces). const m = f['aes67.mcast'], o = m.value.split('.').map(Number); const ok = o.length === 4 && o.every(x => Number.isInteger(x) && x >= 0 && x <= 255) && @@ -497,6 +505,7 @@ async function poll() { ...temps(st.temps) }); showPtp(st.ptp); + netLive(); sdp(); } catch { table($('status'), {'Device': 'offline'}); showPtp(null); } }