Python control library for Neewer TL-series RGB tube lights over Bluetooth LE
Project description
neewer
Python control library for Neewer TL-series RGB tube lights (TL120C / TL90C and friends) over Bluetooth LE — no app, no pairing.
import asyncio
from neewer import Fleet
async def main():
async with Fleet() as fleet: # scan + connect everything in range
await fleet.set_hsi("all", 240, 100, 100) # all lights blue
asyncio.run(main())
The typed methods (set_hsi, power, set_cct, …) are the primary API. A
one-line string grammar (fleet.dispatch("all hsi 240 100 100")) is also
available as a convenience — see The string grammar.
Or from the terminal:
$ neewer scan # list the lights it can see
$ neewer all hsi 240 100 100 # everything blue
$ neewer all power off
$ neewer t1 cct 100 5600 # position 1 -> 5600 K
Firmware flashing lives in its own tool, neewer-ota (dry-run by default;
--confirm writes). Stop anything else holding the light first:
$ neewer-ota <MAC> --file fw.bin --check # connect, probe, validate, no write
$ neewer-ota <MAC> --file fw.bin --confirm # actually flash
What you get
neewer.Fleet— the batteries-included BLE client: continuous discovery, persistent connections, an auto-reconnect supervisor (exponential backoff + jitter) that survives a light being switched off or grabbed by another device, target addressing (all/t<N>/ MAC / alias / group), and typed methods for every action. Subscribe withfleet.subscribe(cb)to be notified on any state change (connect / disconnect / telemetry / command) instead of polling.neewer.protocol— the pure, standard-library-only frame/reply/model layer, including the typed command model (neewer.protocol.commands, one dataclass per action, with the sharedcommands.ACTIONSargument-order registry) andneewer.protocol.dmxDMX-over-IP personalities (hsi,cct,rgb,rgbw) plusWriteGovernor, a self-tuning per-connection write pacer that keeps each tube at or below its measured BLE delivery rate (dropping the newest frame rather than backing up the Bluetooth transmit queue). It never importsbleak, so a non-BLE transport (an ESP32 bridge, a UART gateway) can reuse all the frame knowledge without a radio.neewer.transport— the radio seam: aTransportProtocol with a bleak-backed default (BleakTransport).Fleettakestransport=so you can inject a fake (for tests) or an alternative backend.neewer.fleetitself imports withoutbleak; only the transport pulls it in, lazily.neewer.errors— typed errors (UnknownTarget/UnknownAction/Unsupported/ …); command failures raise, they don't return sentinel strings.neewer.grammar— the opt-in<target> <action> [args]string grammar (parse,dispatch, OSC mapping) layered over the typed API. Register extra verbs withfleet.register_verb(name, handler).neewer.effects— animation engines (comet / hue-flow / palette) that run against a heldFleet.neewer.devices— the device book: give your lights human names, physical positions, and groups in~/.config/neewer/devices.toml.
The package ships type hints (py.typed).
Install
$ pip install neewer
Requires Python 3.11+. The only runtime dependency is
bleak.
Windows
Installation works out of the box on Windows with Bluetooth LE support. The
bleak dependency automatically installs the required WinRT packages for
Windows Bluetooth access.
If the console scripts (neewer, neewer-ota) are not on your PATH after
installation, you have two options:
-
Add the Scripts directory to your PATH:
- Typically located at
%APPDATA%\Python\Python3XX\Scripts - Add this directory to your system PATH environment variable
- Typically located at
-
Use the module directly:
python -m neewer.cli scan python -m neewer.cli all hsi 240 100 100 python -m neewer.ota <MAC> --file fw.bin --check
The Python module approach works everywhere without PATH configuration.
The typed API
Every action is a method on Fleet; the first argument is always a target
(all / t<N> / MAC / alias / group):
| Method | Example |
|---|---|
power(target, on) |
await fleet.power("all", False) |
set_hsi(target, hue, sat=100, bri=100) |
await fleet.set_hsi("t1", 240, 100, 80) |
set_cct(target, bri, temp, gm=50) |
await fleet.set_cct("t1", 100, 56) |
set_bri(target, bri) |
await fleet.set_bri("all", 50) |
set_rgbcw(target, bri, r, g, b, c, w) |
await fleet.set_rgbcw("t1", 60, 0, 0, 0, 255, 0) |
set_xy(target, bri, x, y) |
await fleet.set_xy("t1", 50, 0.3127, 0.329) |
set_gel(target, hue, sat, bri, brand, gel_no) |
await fleet.set_gel("t1", 45, 100, 50) |
scene(target, effect, *params) |
await fleet.scene("all", 3) |
pixel(target, colors) |
await fleet.pixel("t1", ["0", "off", "240"]) |
identify(target) |
await fleet.identify("t2") |
raw(target, hexstr) |
await fleet.raw("t1", "78 81 01 01 fb") |
flow(mode, **opts) / query(target) / render_state(target) |
await fleet.flow("comet") |
Failures raise neewer.errors.NeewerError subclasses (UnknownTarget,
Unsupported, …). See examples/ for runnable scripts.
The string grammar
For REPLs, wire protocols, and one-liners, neewer.grammar parses a line of
<target> <action> [args] and dispatches it to the typed API. fleet.dispatch()
is a thin convenience over it:
| Action | Example | Effect |
|---|---|---|
power on|off |
all power off |
toggle |
hsi <h> <s> <i> |
all hsi 240 100 100 |
hue/saturation/intensity |
cct <bri> <temp> [gm] |
t1 cct 100 5600 |
white, colour temperature |
bri <0-100> |
all bri 50 |
brightness only |
rgbcw <bri> <r> <g> <b> <c> <w> |
t1 rgbcw 60 0 0 0 255 0 |
RGB + cold/warm white (TL120C) |
xy <bri> <x> <y> |
t1 xy 50 0.3127 0.329 |
CIE-1931 point (TL120C) |
gel <hue> <sat> <bri> [brand] [no] |
t1 gel 45 100 50 lee 7 |
gel colour (TL120C) |
scene <effect> [params...] |
all scene 3 |
built-in scene |
pixel <colour...> |
t1 pixel 0 off 240 k3200 |
per-segment palette (TL120C) |
identify |
t2 identify |
flash to locate |
flow <mode> [k=v...] |
all flow comet |
start a running effect |
scan / state / query |
state |
list / read / refresh cached state |
Targets: all, t<N> (physical position), a MAC, or an alias/group from your
device book.
Related projects
- neewerd — a ready-made control daemon built on this library: holds the BLE links and exposes the lights over socket / MQTT (Home Assistant discovery) / OSC / HTTP + web UI / Art-Net / sACN, plus an MCP server.
- neewer-hardware — the hardware and wire-protocol reference this library implements: frame format, the full opcode table, provisioning, DMX, and per-model capabilities.
License
MIT.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file neewer-0.1.4.tar.gz.
File metadata
- Download URL: neewer-0.1.4.tar.gz
- Upload date:
- Size: 134.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8d88072258ee8239288d82011b86a1dc08ec350c608da0a0cda11cee76eebaa7
|
|
| MD5 |
efdf34833760602c784c857cae06f78f
|
|
| BLAKE2b-256 |
3332c12250eb6b946900abf7038e7d465d2b7812bfc300a1d25715e316fd821b
|
File details
Details for the file neewer-0.1.4-py3-none-any.whl.
File metadata
- Download URL: neewer-0.1.4-py3-none-any.whl
- Upload date:
- Size: 97.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
630103b825280d6117a714153eefac6fc1a90d5929427c9957f77bfec376ce26
|
|
| MD5 |
05a36f54d2d609937f5681421d3c8b2d
|
|
| BLAKE2b-256 |
315cf58ab7f63b465ffc6aad6baca902a4a825d8a7d2054217b7e6967147a794
|