Copyright 2026 Andreas Remigius Schmidt
An OpenSCAD-printed clip-on jig for flashing a Tuya WB3S Wi-Fi/BT module after it has been SMD-soldered onto a host PCB — no test header, and no soldering of flying leads.
The jig is a cap that drops over the module's shield can. Female-to-male Dupont jumper wires are held (male end first) in vertical sleeves carried on sprung parallelogram flexure arms — one per signal — for the five pads needed for flashing (VCC, GND, TXD1, RXD1, CEN). Seating the cap flexes the arms so each pin presses down onto the exposed solder toe just outboard of the module's castellated edge. The female ends plug into a USB-UART adapter, so the jig itself never wears out. A sprung C-clip squeezes the cap down onto the host PCB to keep the pins loaded.
wb3s_jig.scad— the cap + clamp (renders both, side by side).tuya-ir.md— flashing guide for a Tuya IR-only blaster.tuya-ir-rf.md— flashing guide for a Tuya IR + 433 MHz RF blaster (extendstuya-ir.md).
- Registration: the roof drops over the shield can; internal rims hug the can sides (X/Y) and the roof rests on the can top (Z).
- Contacts: each Dupont pin sits in a vertical sleeve on a two-arm
parallelogram flexure; seating the cap flexes the arms and presses the pin onto
the solder toe just outboard of its edge pad (the parallelogram keeps the pin
vertical so it can't walk off). Each pin sits ~0.4 mm proud at rest (
preload) and lands ~1.6 N on its toe once seated. TXD1/RXD1 share one wide tower because their pads are only 2 mm apart. - Inspection: a viewport over each pad lets you watch the pin tip seat.
- Labels: pin names are debossed on top next to each viewport; the antenna meander is engraved on top as an orientation key (long parallel segments to the right = matches the chip viewed top-down).
- Clamp: a C-clip hooks over the cap top and under the host PCB at the back
(antenna side, no pads), springing the stack together. Its relaxed jaw is
~0.2 mm under the stack height (
press), and it has to resist the sum of the five arm reactions (~8 N), not merely seat the jig. Assumes the host PCB is reachable from behind the module.
| edge | pads (back → front) |
|---|---|
| left (X = 0) | CEN … VCC |
| right (X = pcb_w) | TXD1, RXD1 … GND |
The Y = 0 short edge carries only the flash/test pads (SCK/CS/SI/SO) — not used (the smaller Tuya boards don't even connect them).
Flashing chain: PC → USB isolator → USB-UART adapter (3.3 V) → Dupont wires → this jig → WB3S.
- USB-to-TTL UART adapter (CH340G / CH340E) —
AliExpress. Switch it to
3.3 V — the WB3S is a 3.3 V part and 5 V logic can damage it.
TXD1/RXD1are the module's own UART1 pins (named from the chip's side), so they cross: module TXD1 → adapter RX, RXD1 → adapter TX; plus VCC / GND / CEN. Use UART1 (TXD1/RXD1) — TXD2/RXD2 is only the Tuya boot log, not the programming port.- Printable case: MakerWorld
- USB isolator (ADuM3160, 1500 V) —
AliExpress. Galvanic
isolation between PC and target; strongly recommended when the host board is
(or has been) mains-powered.
- Printable case: Printables
With the jig's pins on the pads (TXD1, RXD1, CEN, VCC, GND) and the chain
connected (PC → isolator → 3.3 V UART → jig), use
ltchiptool (LibreTiny's CLI,
which wraps bk7231tools).
The WB3S's chip family is BK7231T. (The pin-compatible CB3S uses the
BK7231N instead; the flash tools auto-detect the chip during the handshake,
and a CRC error usually means the wrong chip type was selected. Read the marking
on the can if unsure: WB3S → BK7231T, CB3S → BK7231N.)
Install the tool (ltchiptool is a Python package, not a distro package):
pipx install ltchiptool # or: pip install --user ltchiptoolReset into download mode: start a command, then within a few seconds reset the chip so the tool can catch it. CEN is the reset line (active-low), brought out by the jig: briefly bridge the CEN wire → GND by hand. The adapter does not need a flow-control pin — that only automates the reset: wire CEN → RTS (a driven output the tool can toggle), not CTS (an input that can't drive anything). Without it, reset manually. (You can also just power-cycle by interrupting the VCC wire, but CEN is cleaner.) Keep the supply at 3.3 V — a weak adapter regulator can brown out during reset, so power from a proper 3.3 V rail if needed.
ltchiptool flash read BK7231T wb3s-stock-backup.bin- Dumps the full 2 MB flash. A valid backup is exactly 2,097,152 bytes — any other size is incomplete; redo it.
⚠️ The dump contains the device's Wi-Fi SSID/password — keep it private.- Keep several copies; it's your only route back to stock.
- Underlying-tool equivalent:
bk7231tools read_flash -d /dev/ttyUSB0 wb3s-stock-backup.bin
- A separate full erase usually isn't needed —
flash writeerases the app region before writing it, and the new firmware replaces the old one (including stored config/credentials). ⚠️ Do not erase/overwrite the bootloader (flash offset0x000000). Unlike the BK7231N, the BK7231T has no ROM download mode, so wiping the bootloader bricks the chip — recoverable only by SPI flashing (e.g. BK7231_SPI_Flasher). A "full-chip erase" over UART is therefore a bad idea on the WB3S.
ltchiptool flash write firmware.uf2- Auto-detects file type and offset. For OpenBeken, download the
OpenBK7231T_UA_*.bin("UART flash") image from the releases: it is the app-only image (no bootloader, flashed at0x11000), so it cannot touch the bootloader and brick the BK7231T. Avoid theQIOimage (a full bootloader-and-app image at0x0) — needless flash wear on the bootloader region. For LibreTiny / ESPHome, use the built.uf2. - Power-cycle when done and watch the firmware's UART console to confirm it boots.
- A Windows GUI alternative backs up then flashes in one cycle and can
auto-download the firmware:
BK7231Flasher.exein BK7231GUIFlashTool. But it's a .NET Framework app — Windows-native, and on Linux only via Mono (mono BK7231Flasher.exe), where it's flaky. On Linux just useltchiptoolabove with the_UA_image; the Pythonhid_download_pyis a no-Mono CLI fallback.
- Material: PETG. The contacts are sprung parallelogram flexure arms
that flex each time the jig is seated; the design is dimensioned around PETG
(
E_petg = 2000, surface strain capped at 2 % for fatigue life). PLA is wrong here — too brittle, the thin arms would snap rather than spring. - Layer height 0.16 mm or finer. Each flexure arm is a whole number of
layers (
arm_t = 2 × layer_h) and needs at least two, so it isn't a single bead — spring force scales with thickness³, so a coarser layer both makes the force a gamble and starves the central block.wb3s_jig.scadhard-assertslayer_h ≤ 0.16; 0.12 / 0.08 are fine. - Use a well dialed-in printer — there's little wiggle room. The Dupont towers sit deliberately close to the central block (rigidity), the cap has to match the module/can size, and clearances are tight (module fit 0.3 mm, can slip 0.25 mm, pocket relief 0.35 mm). Dimensional drift binds the module or walks the pins off the solder toes.
- Tuned for a 0.4 mm nozzle. Print the cap flipped — top face (labels, antenna key, sleeve covers) flat on the bed, cavity opening upward — so every coplanar top is the first layer and no support is needed.
- Debossed text stems are thin — legible but not crisp; raise
label_sizeif your printer needs it. - Verify the module/can dimensions against your actual part with calipers
before printing — the
shield_*values are read off low-resolution datasheet figures.
openscad -o preview.png --camera=10,15,8,55,0,25,90 \
--imgsize=1000,800 --autocenter --viewall --render=true wb3s_jig.scadAll the tunable parameters (module/can geometry, clamp, contacts, labels) are
grouped at the top of wb3s_jig.scad.
Not redistributed here for licensing reasons (see License):
- WB3S datasheet (© Tuya) — https://fcc.report/FCC-ID/2ANDL-WB3S/4580793.pdf
- LibreTiny WB3S board & pinout — https://docs.libretiny.eu/boards/wb3s/
The jig design and documentation in this repository are released under the MIT
License — see LICENSE.
Third-party material is not bundled here, only linked: the WB3S datasheet is © Tuya, and the LibreTiny pinout is part of the MIT-licensed LibreTiny project (© 2022 Kuba Szczodrzyński).
Not affiliated with or endorsed by Tuya, Beken, or any device manufacturer; all product names and trademarks belong to their respective owners. This project is intended for use on hardware you own. Flashing third-party firmware can brick devices, voids the manufacturer warranty, and — because these modules are often built into mains-powered products — can be dangerous: use proper galvanic isolation and work at your own risk. Everything here is provided "as is", without warranty of any kind (see the MIT License).