Skip to main content

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 with fleet.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 shared commands.ACTIONS argument-order registry) and neewer.protocol.dmx DMX-over-IP personalities (hsi, cct, rgb, rgbw) plus WriteGovernor, 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 imports bleak, 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: a Transport Protocol with a bleak-backed default (BleakTransport). Fleet takes transport= so you can inject a fake (for tests) or an alternative backend. neewer.fleet itself imports without bleak; 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 with fleet.register_verb(name, handler).
  • neewer.effects — animation engines (comet / hue-flow / palette) that run against a held Fleet.
  • 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:

  1. Add the Scripts directory to your PATH:

    • Typically located at %APPDATA%\Python\Python3XX\Scripts
    • Add this directory to your system PATH environment variable
  2. 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

neewer-0.1.4.tar.gz (134.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

neewer-0.1.4-py3-none-any.whl (97.0 kB view details)

Uploaded Python 3

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

Hashes for neewer-0.1.4.tar.gz
Algorithm Hash digest
SHA256 8d88072258ee8239288d82011b86a1dc08ec350c608da0a0cda11cee76eebaa7
MD5 efdf34833760602c784c857cae06f78f
BLAKE2b-256 3332c12250eb6b946900abf7038e7d465d2b7812bfc300a1d25715e316fd821b

See more details on using hashes here.

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

Hashes for neewer-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 630103b825280d6117a714153eefac6fc1a90d5929427c9957f77bfec376ce26
MD5 05a36f54d2d609937f5681421d3c8b2d
BLAKE2b-256 315cf58ab7f63b465ffc6aad6baca902a4a825d8a7d2054217b7e6967147a794

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page