fix(dmx-driver): accept a signed inputs word so bit 31 stops freezing the lights - #1587
Merged
Merged
Conversation
…ng the lights `inputs` from the mbsl32di driver is a signed 32-bit word — it is built as `data[1] << 16 | data[0]`, so it is negative exactly when input bit 31 is closed. Bit 31 is a door contact in production, so the `payload.inputs < 0` clause added in c92cae9 dropped *every* dry-switch reading for as long as that one door was in that state, freezing all three bath door indicators at their last frame. On routy the universe sat at [0, 0, 128] from 2026-09-09T05:22:06Z with 305 readings dropped against 145 frames written. Accept the full 32-bit range, signed or unsigned, and normalise with `>>> 0` before the bit tests, as `mqtt-influx/converters/mbsl32di.js` already does. The `Number.isSafeInteger` guard is what closes `Infinity` (reachable from JSON as `1e999`) and fractional values; the range check now closes only values that are genuinely outside 32 bits, which the bitwise operators would otherwise wrap into a different reading. The drop log said "unsigned integer inputs field", which no longer describes the guard; it now names the 32-bit range. `CLAUDE.md` documented the `>= 0` check as intended behaviour and is corrected. Fixes #1586 Claude-Session: https://claude.ai/code/session_01DAyhJDqko1EAvddsatHRDo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1586.
The bug
message-handler.jsrejected any reading whoseinputsfield was negative. Butinputsfrom thembsl32didriver is a signed 32-bit word — built asdata[1] << 16 | data[0], so it is negative exactly when input bit 31 is closed.Bit 31 is a door contact in production, so whenever that one door was in that
state the driver dropped every dry-switch reading and all three bath door
indicators froze at their last frame.
On routy the universe sat at
[0, 0, 128]from 2026-09-09T05:22:06Z: 305readings dropped, 145 frames written, last frame 05:21:31Z. Sample dropped
reading:
{"inputs":-39828385, ...}—(-39828385) >>> 0is0b11111101101000000100010001011111, a perfectly valid word with bit 31 set.Introduced by c92cae9 (#1543). That hardening was right to reject
Infinityandfractional values; the
< 0clause overreached — its rationale assumed-1anddid not account for bit 31 being a used input on a 32-input module.
The fix
Accept the full 32-bit range, signed or unsigned, and normalise with
>>> 0before the bit tests — the same thing
docker/mqtt-influx/converters/mbsl32di.jsalready does.
Number.isSafeIntegerstill closesInfinity(reachable from JSON as1e999)and fractional values.
bitwise operators would otherwise wrap into a different reading.
inputsis now a normal reading.-1is all 32 inputs closed.the guard; it now names the 32-bit range.
dmx-driverwas the only service carrying the< 0clause; the other sitestouched by c92cae9 are unaffected.
Tests
Written first, watched fail, then fixed — the four new negative/range cases
failed against the old guard for exactly the expected reasons.
-39828385drives the channels instead of being dropped-2147481056(every mapped bit closed and bit 31) lights all three channels-1is all inputs closed, not a malformed reading4294967296and-2147483649are still dropped, universe untouchedInfinity/1e999and fractional values still dropped (unchanged)The obsolete
drops a negative inputs field rather than lighting every channeltest encoded the bug and is replaced by the out-of-range cases.
Done when
message-handler.jsaccepts a reading with bit 31 set and drives channels 1-3 from its bitsInfinity,1e999, fractional and out-of-32-bit-range values are still dropped, universe untouchedinputs(-39828385) asserting the expected channel levelsnpm testgreen indocker/dmx-driver/docker/dmx-driver/CLAUDE.mdcorrecteddocker logs homy-dmx-driver-1shows frames written with no "Ignoring payload" lines for well-formed readingshttps://claude.ai/code/session_01DAyhJDqko1EAvddsatHRDo