godox-tl

A Node.js + TypeScript + Effect toolkit for controlling a Godox TL30 over BLE

2
0
2
TypeScript
public

godox-tl

A Node.js + TypeScript + Effect toolkit for controlling
a Godox TL30 over BLE. Monorepo with a core library, native BLE mesh transport,
a CLI, and a Homebridge plugin for HomeKit integration.

Packages

Path Package name Role
packages/core/ @godox-tl/core Domain types, LightController service, registry, factory conveniences, and an experimental DMX transport kept out of the main TL30 path.
packages/cli/ @godox-tl/cli godox binary built on @effect/cli — scan / lights / provision / rebind / set / off / rename / forget.
packages/mesh/ @godox-tl/mesh Primary native Node BLE transport for TL30: provisioning, rebind, CCT, HSI, RGBW, FX, off, and scan via @stoprocent/noble.
packages/homebridge/ homebridge-godox-tl Homebridge dynamic platform plugin. CCT/color/presets over HomeKit, registry-first startup, periodic scan, and auto-provision/re-provision.

Core stays free of BLE deps; consumers compose core + mesh.

Hardware reality

Model DMX in BLE (Godox Light app) Works via this library
TL30 no yes yes, tested locally

The Godox Light app uses encrypted Bluetooth SIG Mesh (com.godox.ble.mesh,
Telink stack). For TL30 the only remote-control path is BLE Mesh.
@godox-tl/mesh is the implementation used by the CLI and Homebridge plugin.

Other Godox app-controlled fixtures may use similar BLE protocol pieces, but
this repo should not be read as a compatibility claim for hardware not tested
here. The known target is the TL30.

Install

For CLI users after the package is published:

vp add -g @godox-tl/cli
# or: pnpm add -g @godox-tl/cli
godox --help

For Homebridge users after the plugin is published:

vp add -g homebridge-godox-tl
# or: pnpm add -g homebridge-godox-tl

For library users:

vp add @godox-tl/core @godox-tl/mesh effect
# or: pnpm add @godox-tl/core @godox-tl/mesh effect

For local development:

Note: You need Vite+ installed for the commands below.

vp install

CLI quick start

Install the CLI globally:

vp add -g @godox-tl/cli
# or: pnpm add -g @godox-tl/cli
godox --help

Then use the godox binary directly:

godox scan                                      # list nearby BLE devices
godox lights                                    # list registered lights
godox provision <addr> --name kitchen           # one-step provision + rebind + register
godox set kitchen --brightness 50 --cct 4500
godox hsi kitchen --brightness 100 --hue 0 --saturation 100
godox rgbw kitchen --brightness 10 --red 255
godox fx kitchen --brightness 100 --effect 2 --level 1
godox off kitchen
godox rename kitchen office
godox forget kitchen

Per-light state files live at ~/.config/godox-tl/states/<name>.json; the
registry at ~/.config/godox-tl/registry.json. --help prints autogenerated
docs for every subcommand.

From this workspace, use vp run @godox-tl/cli#godox -- <subcommand> instead
of a global install.

The legacy demo (packages/cli/src/demo.ts) is kept as an internal playground,
not as part of the TL30 BLE workflow.

Homebridge plugin

homebridge-godox-tl is a dynamic platform plugin. Drop this into your
Homebridge config.json:

{
  "platforms": [
    {
      "platform": "GodoxTL",
      "name": "Godox TL",
      "autoProvision": false,
      "autoProvisionOnStartup": false,
      "discoveryFilters": ["^GD_LED$"],
      "scanIntervalSeconds": 60
    }
  ]
}

Discovery is registry-first: the plugin loads
~/.config/godox-tl/registry.json (or a custom registryPath) at startup and
exposes each entry as a Service.Lightbulb with On / Brightness /
ColorTemperature characteristics. The startup BLE scan does not provision by
default. To provision factory-reset lights from Homebridge, opt in with
autoProvisionOnStartup: true for a one-shot startup provisioning pass, or
autoProvision: true to scan every scanIntervalSeconds; matching lights are
added as HomeKit accessories with the nameTemplate (default
godox-{shortAddr}).

Set handlers are debounced 100 ms so HomeKit slider drags don’t flood the
mesh. Mesh sends are serialized per controller so concurrent HomeKit updates
reserve sequence numbers in order.

Auto-provision scan failures are surfaced in the Homebridge log and retried on
the next scan interval; they are not treated as an empty scan result.
If a previously provisioned light is factory-reset, Homebridge can
auto-provision it again when it appears as an unprovisioned BLE candidate,
even if the old address is still in the accessory cache.

Provisioning (TL30 / SIG Mesh)

# Factory-reset the light first (Bluetooth menu → RESET).
godox provision <BLE-address> --name kitchen

This runs provision + rebind + register in one step. The address is the
CoreBluetooth UUID on macOS, a real MAC on Linux — godox scan prints both.

Programmatic use

import { Effect } from "effect";
import { Domain, getLight, LightController } from "@godox-tl/core";
import { makeNodeMeshLayer } from "@godox-tl/mesh";

const program = Effect.gen(function* () {
  const entry = yield* getLight("kitchen");
  const layer = makeNodeMeshLayer({
    address: entry.address,
    statePath: entry.statePath,
  });
  const light = yield* LightController;
  yield* light.send(
    Domain.Cct.make({
      brightness: Domain.pct(75),
      temperature: Domain.kelvin(4200),
    }),
  );
}).pipe(Effect.provide(layer));

Domain

LightCommand is a tagged union:

  • Off — power off.
  • Cct { brightness: Percent, temperature: Kelvin } — bi-color tube mode.
  • Hsi { brightness, hue, saturation } — HSI color mode.
  • Rgbw { brightness, red, green, blue, white } — RGBW color mode.
  • Fx { brightness, effect, subtype, filter } — FX mode; mesh maps subtype as the observed level/speed byte.

Hsi/Rgbw/Fx are supported by @godox-tl/mesh.

@godox-tl/mesh — Native BLE Transport

Native transport for TL30 control. The Homebridge plugin can run on a Raspberry
Pi without a Python runtime.

Milestones:

  • ✅ 1. Crypto primitives — AES-CCM, AES-CMAC, k1/k2/k3/k4, P-256 ECDH, Godox CRC-8.
  • ✅ 2. PDU codecs — Provisioning, Network, Lower/Upper Transport, Access, Proxy.
  • ✅ 3. BLE transport — @stoprocent/noble wrapper, Mesh Proxy Service 0x1828, SAR.
  • ✅ 4. Provisioning state machine (Invite → Capabilities → … → Complete).
  • ✅ 5. ConfigSession — Config App Key Add + Model App Bind.
  • ✅ 6. Godox V2 payload encoder — brightness/CCT, off.
  • ✅ 7. End-to-end: provision → rebind → set verified against real hardware.
  • ✅ 8. Native mesh wiring — CLI and Homebridge plugin use @godox-tl/mesh.

Crypto and PDU codecs are validated against captured wire-byte fixtures at
packages/mesh/tests/fixtures/ — 30 set + 1 off, byte-exact round-trips.

TL30 Smoke-Test Checklist

  • Factory-reset the TL30 and confirm godox scan shows it as
    [unprovisioned].
  • Provision from the CLI: godox provision <addr> --name <name>.
  • Confirm godox lights shows the light and the state file path.
  • Send CCT: godox set <name> --brightness 50 --cct 4200.
  • Send HSI: godox hsi <name> --brightness 80 --hue 210 --saturation 70.
  • Send RGBW: godox rgbw <name> --brightness 20 --red 255.
  • Send FX: godox fx <name> --brightness 80 --effect 2 --level 1.
  • Send off: godox off <name>.
  • Start Homebridge and confirm the light appears in HomeKit.
  • In HomeKit, verify CCT/color controls, off/on restore, and reset/re-provision.

Develop

vp install          # workspace install
vp check            # format + lint + type check (everything)
vp test             # vitest, every package
vp run @godox-tl/cli#godox -- <subcommand>

To work in a single package:

cd packages/core && vp test

License

MIT

v0.3.3[beta]