From c2033b95fb130f5063e5fea7e9734b2c863a4393 Mon Sep 17 00:00:00 2001 From: ScreenTinker Date: Mon, 10 Aug 2026 11:47:23 -0500 Subject: [PATCH] BrightSign: find the LAN address on any interface, and say when there is none MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dashboard has a "Local IP" field, the server stores it, the bridge relays it and autorun.brs collects it — the whole path has existed since 1.9.29. It has never once produced a value for a BrightSign. Our XT245 has 6000 telemetry rows with local_ip NULL while sitting on a healthy PoE network at 192.168.1.46, and every other field in the same payload arrives. Confirmed against the device itself over its DWS: the installed autorun.brs is ours (61055 bytes vs 61058 in tree) and contains this exact code, so it runs and yields nothing. Interface 0 alone is not enough. Now walks every interface the platform documents — 0/"eth0", "eth1", 1/"wlan0" — instead of assuming the first answers. The string forms are the point: per the Object Reference an INTEGER interface "must currently exist on the player; otherwise the object-creation function will return Invalid", while the string names carry no such condition. And when nothing answers it now says so on the host log. Silence is what made this invisible for a whole fleet: the column stayed NULL and read as a server-side gap rather than a player that never sent anything. Not fixed blind — the first attempt at this used roDeviceInfo.GetIPAddrs(), which is ROKU's API. BrightSign's roDeviceInfo has no network method of any kind; the string does not occur once in the published Object Reference. It would have raised "Member function not found" from inside SendHostTelemetry, once a minute, forever — while ostensibly fixing telemetry. Caught by checking the docs before shipping, and now added to the deny-list in brightscript-api-surface.test.js so the next person cannot repeat it. Verified the entry bites: injecting the call fails that suite. ⚠️ Untested on hardware. BrightScript has no interpreter outside a player, so this is docs plus block-balance checking. The XT245 is reachable at 192.168.1.46 (DWS on 8080, not 80) to confirm once the package updates. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Bvjey4FNam49MN7ybjcq6A --- brightsign/autorun.brs | 41 +++++++++++++++++--- server/test/brightscript-api-surface.test.js | 6 +++ 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/brightsign/autorun.brs b/brightsign/autorun.brs index 2a4a124..f1ae287 100644 --- a/brightsign/autorun.brs +++ b/brightsign/autorun.brs @@ -896,13 +896,42 @@ Sub SendHostTelemetry(widget As Object, cfg As Object) t.os_version = di.GetVersion() end if - ' The wired address. Empty string when nothing is configured, per the documented contract. - nc = CreateObject("roNetworkConfiguration", 0) - if nc <> invalid then - cur = nc.GetCurrentConfig() - if cur <> invalid and cur.ip4_address <> invalid and cur.ip4_address <> "" then - t.local_ip = cur.ip4_address + ' The address this player holds on the LAN — the one an integrator needs to reach its DWS on + ' site, and the one the dashboard has never been able to show for a BrightSign. + ' + ' Interface 0 alone was not enough. Our XT245 produced 6000 telemetry rows with local_ip NULL + ' while sitting on a healthy PoE network with a perfectly good address, and every other field in + ' this same payload arrived. So try each interface the platform documents rather than assuming + ' the first one answers: 0/"eth0" is the Ethernet port, "eth1" the control port on players that + ' have one, 1/"wlan0" the internal WiFi. + ' + ' ⚠️ The STRING forms matter. Per the Object Reference, an INTEGER interface "must currently + ' exist on the player; otherwise the object-creation function will return Invalid" — the string + ' names carry no such condition, so they are the ones that answer when the integer does not. + ' + ' NOT roDeviceInfo.GetIPAddrs(): that is Roku's API. BrightSign's roDeviceInfo has no network + ' method at all, and calling it would raise "Member function not found" here every minute. This + ' is the exact family of mistake server/test/brightscript-api-surface.test.js exists to catch. + ' The list is mixed integer/string on purpose (see above) and is walked in full rather than with + ' an early exit, because the guard is the same either way and a typed `exit for` inside a nested + ' if is exactly the sort of thing that cannot be checked from this repo. + for each iface in [0, "eth0", "eth1", 1, "wlan0"] + if t.local_ip = invalid then + nc = CreateObject("roNetworkConfiguration", iface) + if nc <> invalid then + cur = nc.GetCurrentConfig() + if cur <> invalid and cur.ip4_address <> invalid and cur.ip4_address <> "" then + t.local_ip = cur.ip4_address + end if + end if end if + end for + + ' Say so when nothing answered. Silence here is what made this invisible for a whole fleet: the + ' field simply stayed NULL and looked like a server-side gap rather than a player that never + ' sent it. One line on the host log costs nothing and names the real state. + if t.local_ip = invalid then + HostLog(widget, "net", "no ip4_address on any interface (0/eth0/eth1/1/wlan0)") end if vm = CreateObject("roVideoMode") diff --git a/server/test/brightscript-api-surface.test.js b/server/test/brightscript-api-surface.test.js index 4c0f8f3..93a9db3 100644 --- a/server/test/brightscript-api-surface.test.js +++ b/server/test/brightscript-api-surface.test.js @@ -68,6 +68,12 @@ const BAD_METHODS = [ ['.VerifyPackage(', 'roBrightPackage has no VerifyPackage — hash the bytes yourself'], ['.UnpackAll(', 'roBrightPackage has Unpack(path) and UnpackFile(name, path)'], ['SetOrientation(vm', 'roVideoMode has no SetOrientation — rotation is SetScreenModes()[i].transform'], + // Nearly shipped 2026-08-10, while fixing the very thing it would have broken. BrightSign's + // roDeviceInfo has NO network method of any kind — checked against the published Object + // Reference, where the string does not occur once. The address comes from + // roNetworkConfiguration(iface).GetCurrentConfig().ip4_address. Calling this would have raised + // "Member function not found" from inside SendHostTelemetry, once a minute, forever. + ['GetIPAddrs', 'roDeviceInfo has no network methods on BrightSign; use roNetworkConfiguration(iface).GetCurrentConfig().ip4_address'], ]; for (const [needle, advice] of BAD_METHODS) {