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 <noreply@anthropic.com>
This commit is contained in:
@@ -138,10 +138,19 @@ static void net_apply(const cJSON *g)
|
|||||||
|
|
||||||
static void net_status(cJSON *st)
|
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;
|
esp_netif_ip_info_t info;
|
||||||
if (esp_netif_get_ip_info(s_netif, &info) == ESP_OK && info.ip.addr) {
|
if (esp_netif_get_ip_info(s_netif, &info) == ESP_OK && info.ip.addr) {
|
||||||
snprintf(ip, sizeof(ip), IPSTR, IP2STR(&info.ip));
|
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];
|
uint8_t mac[6];
|
||||||
if (esp_netif_get_mac(s_netif, mac) == ESP_OK) {
|
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.
|
// Single untagged interface until the VLAN split: AES67 and web share it.
|
||||||
cJSON_AddStringToObject(st, "ip", ip);
|
cJSON_AddStringToObject(st, "ip", ip);
|
||||||
cJSON_AddStringToObject(st, "aes67_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, "mac", mac_s);
|
||||||
cJSON_AddStringToObject(st, "link", s_link);
|
cJSON_AddStringToObject(st, "link", s_link);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,12 +26,13 @@ Reference devices for UI and defaults: Riedel Bolero (PTP status), Riedel Direct
|
|||||||
## Core API
|
## Core API
|
||||||
- GET/POST /api/config (full JSON; POST validates, stores to NVS, applies live where possible, returns 4xx with message on bad values)
|
- 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).
|
- 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).
|
- 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
|
- 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)
|
- Firmware: GET /api/ota, POST /api/ota, POST /api/ota/confirm, POST /api/ota/rollback (see Firmware update)
|
||||||
|
|
||||||
## Temperatures
|
## 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.
|
- `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.
|
- 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.
|
- 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.
|
||||||
|
|||||||
@@ -341,6 +341,13 @@ function read() {
|
|||||||
return out;
|
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() {
|
function toggle() {
|
||||||
PROJECT.toggle?.(f);
|
PROJECT.toggle?.(f);
|
||||||
const role = f['ptp.role'].value;
|
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.
|
// 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;
|
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).
|
// 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 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) &&
|
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)
|
...temps(st.temps)
|
||||||
});
|
});
|
||||||
showPtp(st.ptp);
|
showPtp(st.ptp);
|
||||||
|
netLive();
|
||||||
sdp();
|
sdp();
|
||||||
} catch { table($('status'), {'Device': 'offline'}); showPtp(null); }
|
} catch { table($('status'), {'Device': 'offline'}); showPtp(null); }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user