${t('device.info.battery')}
@@ -330,7 +347,7 @@ async function loadDevice(deviceId, activeTab = null) {
${device.android_version && !device.android_version.startsWith('Web/') ? `
${t('device.info.wifi')}
-
${latestTelemetry.wifi_ssid || '--'}
+
${ssidLabel(latestTelemetry.wifi_ssid)}
` : ''}
@@ -1868,7 +1885,8 @@ function updateTelemetryDisplay(telemetry) {
};
if (telemetry.battery_level != null) update('telBattery', telemetry.battery_level + '%');
if (telemetry.storage_free_mb) update('telStorage', t('device.info.size_free', { size: formatBytes(telemetry.storage_free_mb) }));
- if (telemetry.wifi_ssid) update('telWifi', telemetry.wifi_ssid);
+ if (telemetry.wifi_ssid !== undefined) update('telWifi', ssidLabel(telemetry.wifi_ssid));
+ if (telemetry.local_ip) update('telLocalIp', telemetry.local_ip);
if (telemetry.wifi_rssi) update('telRssi', telemetry.wifi_rssi + ' dBm');
if (telemetry.uptime_seconds) update('telUptime', formatUptime(telemetry.uptime_seconds));
if (telemetry.ram_free_mb) update('telRam', t('device.info.size_free', { size: formatBytes(telemetry.ram_free_mb) }));
diff --git a/server/db/database.js b/server/db/database.js
index 1e15421..d49470c 100644
--- a/server/db/database.js
+++ b/server/db/database.js
@@ -348,6 +348,10 @@ const migrations = [
// boot, so an `IS NULL` backfill would silently swallow the first alert of any outage
// that began since the last restart. The one-time backfill is below, in schema_migrations.
"ALTER TABLE devices ADD COLUMN offline_alert_heartbeat INTEGER",
+ // The device's OWN address on the local network, reported by the player. devices.ip_address is
+ // the PUBLIC address the server sees the connection arrive from — both are useful and they are
+ // not the same thing. A customer reading the public IP as "my screen's IP" prompted this.
+ "ALTER TABLE device_telemetry ADD COLUMN local_ip TEXT",
// Backfill a unique 6-digit PIN for already-paired devices that predate the
// settings_pin column (their next reconnect re-sends device:paired with it, so
// the existing fleet isn't locked out of the on-device menu). Idempotent: the
diff --git a/server/routes/devices.js b/server/routes/devices.js
index ce9d221..30e56b5 100644
--- a/server/routes/devices.js
+++ b/server/routes/devices.js
@@ -22,7 +22,7 @@ router.get('/', (req, res) => {
const devices = db.prepare(`
SELECT d.*,
t.battery_level, t.battery_charging, t.storage_free_mb, t.storage_total_mb,
- t.ram_free_mb, t.ram_total_mb, t.wifi_ssid, t.wifi_rssi, t.uptime_seconds,
+ t.ram_free_mb, t.ram_total_mb, t.wifi_ssid, t.wifi_rssi, t.uptime_seconds, t.local_ip,
t.cpu_usage,
s.filepath as screenshot_path, s.captured_at as screenshot_at,
u.email as owner_email, u.name as owner_name
diff --git a/server/ws/deviceSocket.js b/server/ws/deviceSocket.js
index 5b367ba..ad947bd 100644
--- a/server/ws/deviceSocket.js
+++ b/server/ws/deviceSocket.js
@@ -985,8 +985,8 @@ module.exports = function setupDeviceSocket(io) {
if (telemetry && deviceExists(device_id)) {
db.prepare(`
INSERT INTO device_telemetry (device_id, battery_level, battery_charging, storage_free_mb, storage_total_mb,
- ram_free_mb, ram_total_mb, cpu_usage, wifi_ssid, wifi_rssi, uptime_seconds)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ ram_free_mb, ram_total_mb, cpu_usage, wifi_ssid, wifi_rssi, uptime_seconds, local_ip)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
device_id,
telemetry.battery_level ?? null,
@@ -998,7 +998,10 @@ module.exports = function setupDeviceSocket(io) {
telemetry.cpu_usage ?? null,
telemetry.wifi_ssid ?? null,
telemetry.wifi_rssi ?? null,
- telemetry.uptime_seconds ?? null
+ telemetry.uptime_seconds ?? null,
+ // Device-supplied text headed for a column the dashboard renders: trim and cap it.
+ // 45 chars is the longest legitimate value (a full IPv6 address).
+ typeof telemetry.local_ip === 'string' ? telemetry.local_ip.trim().slice(0, 45) || null : null
);
pruneTelemetry(device_id);