BrightSign: find the LAN address on any interface, and say when there is none

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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bvjey4FNam49MN7ybjcq6A
This commit is contained in:
ScreenTinker 2026-08-10 11:47:23 -05:00
parent f58c537d15
commit c2033b95fb
2 changed files with 41 additions and 6 deletions

View file

@ -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")

View file

@ -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) {