Skip to content

Lights 2: NEEWER FS230B / FS300B control over GATT (#209) - #265

Merged
bubulux merged 4 commits into
mainfrom
feat/209-neewer-gatt
Oct 23, 2026
Merged

bubulux merged 4 commits into
mainfrom
feat/209-neewer-gatt

Conversation

@bubulux

@bubulux bubulux commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #209. Part of the Lights epic #206.

The NEEWER FS230B and FS300B can now be switched, dimmed, set to a white and given a dimming curve from a light's screen.

What changed

  • fixtures/codecs/neewer.ts: the frame (78 <tag> <len> <MAC> <payload> <checksum>), power, the white frame and the app's hello, plus notification parsing. Decoded from the capture in Lights 0: capture an HCI snoop log of the NEEWER app (owner) #207; the details are on the lights page and in the comment on Lights 2: Neewer FS230B / FS300B control over GATT #209.
  • fixtures/drivers/neewerInfinity.ts:
    • Intensity, white and curve share one frame, so the driver keeps each light's last values and always sends all three.
    • 150 ms after power-on before the next white frame; one write per 100 ms, the app's own pace.
    • On connect it turns notifications on and replays the app's hello and queries. The model name from the info reply goes to the debug log.
  • Registry: the driver is registered for both FS kinds. Scan suggestions read the model code in the advertised name (NW-20230051 = FS230B; unknown codes fall back to every NEEWER kind).
  • Shared: LightState.curve, and startState(kind) for the values shown before the phone has set any.
  • Screen: power (Off/On), intensity, white, green/magenta when the kind has it, and dimming curve (Linear, Expo, Log, S). Greyed out while not connected.
  • Slider in the phone's component library: drag on a 48 dp track, or − and + for exact steps.

Decisions

  • Start values instead of the light's real values. The lights answer queries, but the replies aren't decoded yet, so the screen shows what this phone last set, or half intensity, mid white and linear. The screen says so.
  • Green/magenta on the FS300B only. The FS230B's app has no control for it and always sends neutral. The FS300B gets a slider on the same byte, −50..+50 per the published NEEWER protocol; its range is checked on the light, not captured.
  • The hello is replayed because it's cheap and makes the light see the same start as with its own app. Whether it's needed is a phone test.
  • The FS300B uses the same driver without a capture. It's in the known issues until tested.

Checked

  • Every one of the 110 FS230B frames in the capture is rebuilt byte for byte by the codec. That check runs outside the repo, because the capture holds real addresses; the committed tests use a made-up address.
  • make check is green: 50 phone tests, including the codec and the driver against a fake link and clock.

Not clicked through

Nothing has run against a light from OpenClapper yet. That needs the owner's phone and lights.

🤖 Generated with Claude Code

bubulux and others added 4 commits October 23, 2026 17:57
The frame codec and driver decoded from the NEEWER app's traffic (#207):
power, and one frame carrying intensity, white and the dimming curve,
so the driver keeps each light's last values and sends all three. 150 ms
after power-on, 100 ms pace, the app's hello replayed on connect. Every
captured frame was rebuilt byte for byte (outside the repo, the capture
holds real addresses); the committed tests use a made-up address.

Scan suggestions read NEEWER's model code (NW-20230051 = FS230B).
LightState gains the curve; startState gives the shared start values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Power, intensity, white, green/magenta and dimming curve, as the kind
allows, greyed out while not connected. Slider: drag on a 48 dp track or
step with − and +. Docs: the NEEWER protocol on the lights page, the
Slider in the design docs, known issues moved from #208 (tested on the
phone) to #209.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The white frame's green/magenta byte, −50..+50 sent as +50 as in the
published NEEWER protocol; the FS230B stays neutral (its app has no such
control). Not captured: the owner checks the range on the light.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bubulux
bubulux merged commit b8e3be5 into main Oct 23, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lights 2: Neewer FS230B / FS300B control over GATT

1 participant