Wiz PureSmart TruColor Bulb Teardown

I swapped recently away from Philips Hue as a smart lighting system and moved to PureSmart TruColor bulbs. If you're like me and can't afford $100k for a Lutron Ketra system (and accompanying installation hardware), TruColor bulbs were compelling.

  • Very high CRI, noteably better than Gen 1 Philips Hue (haven't tested v2). Side by side and dollar for dollar, these are a much better LED (or set of LEDs).
  • Local control possible over WiFi. While WiFi smart products are taboo, if you run a nice network with VLAN segmentation and PPSK, it's easy to feel safe using these things.
  • Nice tie-ins to Home Assistant and great support there.
  • Affordable! So much cheaper than Hue for higher quality LEDs. ~$15 a bulb at time of writing.

The cons have been lack of dimming < 10%, and lack of transition control while commanding the light (fade rates). With some small modifications, I have had no problems dropping them into my Home Assistant environment.

One Dies

I had one bulb, an A21 variant, give up the ghost recently. Not bad, I initially purchased about 60 bulbs so one failure is not bad so far. Again, for the price. I'm happy to replace a few duds for the higher quality light compared to Hue.

Yay! Permission to open it!

I used a hack saw to lop off the plastic bulbous cover and the very tip of the E26 base. No surprise, inside is a combination of power circuitry and an aluminum-backed LED puck. The interior is shrouded in aluminum for heat dissipation, but the antenna is for the MCU's Bluetooth and Wifi is allowed to poke through to avoid a Faraday-effect.

I immediately found the problem (or at least a symptom) with a swelling capacitor on the board. I'll replace it so that I can bench test this and maybe re-use the LED tech.

After some destruction and prizing the PCBs out, here is what we are met with (sorry, no photos of the carnage. I was too busy being primal). The two PCBs are mated with a 6-pin 1.5mm pitch connector, 2x3. I see DATA/CLOCK pins... I2C?

Power Circuit PCB

L/N entry, of course. Missing population for RV1, probably an MOV that was saved for cost? Ironically maybe it would have helped prevent the C8 capacitor from blowing that ultimately killed this circuit.

The UL markings read E199273, and a Google shows that Zhejiang Leuchtek Technology Co Ltd is likely the manufacturer of this power control circuit.

Embedded on the power PCB is a perpendicular daughter board where the MCU lives to control the 'smarts'. Interestingly, this is a white-glove board made for WiZ by Espressif. It is shrouded except for the surface-mount antenna that extends upwards.

Interestingly, the PCB for this daughter board has labels: GND, VCC, R, B, G, CW, CC, and EN. The traces label the VCC at 3.3v, no surprise. It's interesting to me that this board appears to drive the individual channels. Maybe via PWM?

These traces also go through other circuits on the PCB before they reach the 6-pin mating connection. Some more translation?

LED Wafer

Looking at the LED wafer, it obviously accepts the 6-pin connection from the power PCB and ESP. The rows here make sense and describe the RGBTW nature of this bulb: W(arm), C(old), R(ed), G(reen), B(lue). The blue chips look the most interesting, as they have little to no phosphor coating and you can see the diodes themselves very well.

The board is also UL marked E502352, belonging to Jiangxi Hengqing Lighting Co Ltd.

I'm curious about the U1 SOC. It's labeled:

BP5758 LA3JLKX C852D

From the Tuya doc this is a "...5-channel dimmable linear constant-current LED driver with high-precision from the manufacturer Bright Power Semiconductor".

Interesting, so the level outputs from the Espressif chip are not directly sent to the 6-pin connector. The LED chip needs I2C!

PWM? I2C?

Looking at the underside, I find that 2 of the pins on the 6-pin mate connection are labeled CLK and DAT. Another is labeled LED+ and an obvious ground plane leads to another. That leaves 2 mysteries, probably another voltage reference for the LED chip. Another voltage reference maybe?

The other chips are a BP2636D and a BP2571, other power circuits.

With some more tracing, I'm confident that one of the 6 connections is a "HV" pin, voltage directly from the rectifier bridge. There is no middle layer to this PCB, so I'm 99% sure that the last mystery pin is just actually unused. I probed everything and found no tone.

So the list is:

HV, LED+ NC, GND SDA, SCL

At this point after looking at the datasheets, I think that the R/G/B/CC/CW labels on the Espressif board are not used like that. Obviously the connections have been repurposed in firmware for I2C communication instead of PWM output.

Espressif

Okay so the moment I saw that logo I started getting excited. "Can I flash ESPHome onto this?" was my natural question.

There are TX, RX, GND, IRR, and BOOT test pads on the ESP board. The backside labels it as an ESP32-C3. Nice! Firmware hacking is theoretically possible.

Later I'll try to dump the firmware on it and see if we can binwalk and find anything cool with WiZ. Theoretically I can replace the broken capacitor and reflash some new firmware on here and be off to the races!

Benching

I got a UART hooked up to the test pins. The baud rate is 115200 as you'd guess. Here's a sample:

ESP-ROM:esp32c3-api1-20210207
wizclick state: 0, fav cnt: 1, pair cnt: 1, soft: 0, force mode:[Built]: 1.36.1 Dec 18 2025 04:21:26
[Chip_Family]: binary-image-esp32-c3:1.36.1 
wizclick state: 0, fav cnt: 1, pair cnt: 1, soft: 0, force mode: 0
ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0xf (BROWNOUT_RST),boot:0xc (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd6268,len:0x1798
load:0x403ce000,len:0x6e8
load:0x403d0000,len:0x39ac
entry 0x403ce000
[Built]: 1.36.1 Dec 18 2025 04:21:26
[Chip_Family]: binary-image-esp32-c3:1.36.1 
wizclick state: 0, fav cnt: 1, pair cnt: 1, soft: 0, force mode: 0
ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0xf (BROWNOUT_RST),boot:0xc (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd6268,len:0x1798
load:0x403ce000,len:0x6e8
load:0x403d0000,len:0x39ac
entry 0x403ce000
[Built]: 1.36.1 Dec 18 2025 04:21:26
[Chip_Family]: binary-image-esp32-c3:1.36.1 
wizclick state: 0, fav cnt: 1, pair cnt: 1, soft: 0, force mode: 0
ESP-ROM:esp32c3-api1-20210207

This was with the ESP board still attached, so it's possible that lack of power to the rest of the board is causing these errors. After getting a good 3.3v supply attached:

ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0x1 (POWERON),boot:0xc (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd6268,len:0x1798
load:0x403ce000,len:0x6e8
load:0x403d0000,len:0x39ac
entry 0x403ce000
[Built]: 1.36.1 Dec 18 2025 04:21:26
[Chip_Family]: binary-image-esp32-c3:1.36.1
wizclick state: 0, fav cnt: 1, pair cnt: 1, soft: 0, force mode: 0
Firmware Version: 1.36.1, Paired: 0
MAC address: d8a0115cfc1a
Model: 1748148700 ,Boot Up Reason: 1 , Boot-Loader Version: 1, Matter: 0

Next I'll try to dump.

esptool.py --chip esp32c3 --port /dev/tty.usbserial-20140 --baud 115200 read_flash 0x0 0x400000 wiz_firmware_dump.bin

Before running this, power up holding BOOT low to GND. It took some finaggling to get this to dump fully. You will need an extra power supply to do this (unless you desolder the MCU daughter board).

After wasting a bunch of time with this I finally got a dump but realized I never checked if the firmware was encrypted. It is. Duh.

esptool --chip esp32c3 --port /dev/tty.usbserial-20140 get-security-info                                                                 

esptool v5.1.0
Connected to ESP32-C3 on /dev/tty.usbserial-20140:
Chip type:          ESP32-C3 (QFN32) (revision v0.4)
Features:           Wi-Fi, BT 5 (LE), Single Core, 160MHz, Embedded Flash 4MB (XMC)
Crystal frequency:  40MHz
MAC:                40:4c:ca:eb:48:a8

Stub flasher is already running. No upload is necessary.

Security Information:
=====================
Flags: 0x00000480 (0b10010000000)
Key Purposes: (0, 4, 0, 0, 0, 0, 12)
  BLOCK_KEY0 - USER/EMPTY
  BLOCK_KEY1 - XTS_AES_128_KEY
  BLOCK_KEY2 - USER/EMPTY
  BLOCK_KEY3 - USER/EMPTY
  BLOCK_KEY4 - USER/EMPTY
  BLOCK_KEY5 - USER/EMPTY
Chip ID: 5
API Version: 3
Secure Boot: Disabled
Flash Encryption: Enabled
SPI Boot Crypt Count (SPI_BOOT_CRYPT_CNT): 0x1
Icache in UART download mode: Disabled
JTAG: Permanently Disabled

Hard resetting via RTS pin...
espefuse --port /dev/tty.usbserial-20140 summary

espefuse v5.1.0
Connecting...
Detecting chip type... ESP32-C3

=== Run "summary" command ===
EFUSE_NAME (Block) Description  = [Meaningful Value] [Readable/Writeable] (Hex Value)
----------------------------------------------------------------------------------------
Calibration fuses:
K_RTC_LDO (BLOCK1)                                 BLOCK1 K_RTC_LDO                                   = 56 R/W (0b0001110)
K_DIG_LDO (BLOCK1)                                 BLOCK1 K_DIG_LDO                                   = -8 R/W (0b1000010)
V_RTC_DBIAS20 (BLOCK1)                             BLOCK1 voltage of rtc dbias20                      = 108 R/W (0x1b)
V_DIG_DBIAS20 (BLOCK1)                             BLOCK1 voltage of digital dbias20                  = 20 R/W (0x05)
DIG_DBIAS_HVT (BLOCK1)                             BLOCK1 digital dbias when hvt                      = -16 R/W (0b10100)
THRES_HVT (BLOCK1)                                 BLOCK1 pvt threshold when hvt                      = 1600 R/W (0b0110010000)
TEMP_CALIB (BLOCK2)                                Temperature calibration data                       = -12.9 R/W (0b110000001)
OCODE (BLOCK2)                                     ADC OCode                                          = 76 R/W (0x4c)
ADC1_INIT_CODE_ATTEN0 (BLOCK2)                     ADC1 init code at atten0                           = 1404 R/W (0b0101011111)
ADC1_INIT_CODE_ATTEN1 (BLOCK2)                     ADC1 init code at atten1                           = 2004 R/W (0b0111110101)
ADC1_INIT_CODE_ATTEN2 (BLOCK2)                     ADC1 init code at atten2                           = -48 R/W (0b1000001100)
ADC1_INIT_CODE_ATTEN3 (BLOCK2)                     ADC1 init code at atten3                           = -564 R/W (0b1010001101)
ADC1_CAL_VOL_ATTEN0 (BLOCK2)                       ADC1 calibration voltage at atten0                 = -292 R/W (0b1001001001)
ADC1_CAL_VOL_ATTEN1 (BLOCK2)                       ADC1 calibration voltage at atten1                 = -92 R/W (0b1000010111)
ADC1_CAL_VOL_ATTEN2 (BLOCK2)                       ADC1 calibration voltage at atten2                 = -260 R/W (0b1001000001)
ADC1_CAL_VOL_ATTEN3 (BLOCK2)                       ADC1 calibration voltage at atten3                 = -436 R/W (0b1001101101)

Config fuses:
WR_DIS (BLOCK0)                                    Disable programming of individual eFuses           = 17039892 R/W (0x01040214)
RD_DIS (BLOCK0)                                    Disable reading from BlOCK4-10                     = 2 R/W (0b0000010)
DIS_ICACHE (BLOCK0)                                Set this bit to disable Icache                     = False R/- (0b0)
DIS_TWAI (BLOCK0)                                  Set this bit to disable CAN function               = False R/- (0b0)
DIS_DIRECT_BOOT (BLOCK0)                           Disable direct boot mode                           = False R/- (0b0)
UART_PRINT_CONTROL (BLOCK0)                        Set the default UARTboot message output mode       = Enable R/- (0b00)
ERR_RST_ENABLE (BLOCK0)                            Use BLOCK0 to check error record registers         = with check R/W (0b1)
BLOCK_USR_DATA (BLOCK3)                            User data
   = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W
BLOCK_SYS_DATA2 (BLOCK10)                          System data part 2 (reserved)
   = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W

Flash fuses:
FLASH_TPUW (BLOCK0)                                Configures flash waiting time after power-up; in u = 0 R/- (0x0)
                                                   nit of ms. If the value is less than 15; the waiti
                                                   ng time is the configurable value; Otherwise; the
                                                   waiting time is twice the configurable value
FORCE_SEND_RESUME (BLOCK0)                         Set this bit to force ROM code to send a resume co = False R/- (0b0)
                                                   mmand during SPI boot
FLASH_CAP (BLOCK1)                                 Flash capacity                                     = 4M R/W (0b001)
FLASH_TEMP (BLOCK1)                                Flash temperature                                  = 105C R/W (0b01)
FLASH_VENDOR (BLOCK1)                              Flash vendor                                       = XMC R/W (0b001)

Identity fuses:
DISABLE_WAFER_VERSION_MAJOR (BLOCK0)               Disables check of wafer version major              = False R/W (0b0)
DISABLE_BLK_VERSION_MAJOR (BLOCK0)                 Disables check of blk version major                = False R/W (0b0)
WAFER_VERSION_MINOR_LO (BLOCK1)                    WAFER_VERSION_MINOR least significant bits         = 4 R/W (0b100)
PKG_VERSION (BLOCK1)                               Package version                                    = 0 R/W (0b000)
BLK_VERSION_MINOR (BLOCK1)                         BLK_VERSION_MINOR                                  = 3 R/W (0b011)
WAFER_VERSION_MINOR_HI (BLOCK1)                    WAFER_VERSION_MINOR most significant bit           = False R/W (0b0)
WAFER_VERSION_MAJOR (BLOCK1)                       WAFER_VERSION_MAJOR                                = 0 R/W (0b00)
OPTIONAL_UNIQUE_ID (BLOCK2)                        Optional unique 128-bit ID
   = 95 87 76 dc 47 be bf 85 c6 9a 99 75 2a 4b 14 1a R/W
BLK_VERSION_MAJOR (BLOCK2)                         BLK_VERSION_MAJOR of BLOCK2                        = With calibration R/W (0b01)
WAFER_VERSION_MINOR (BLOCK0)                       calc WAFER VERSION MINOR = WAFER_VERSION_MINOR_HI  = 4 R/W (0x4)
                                                   << 3 + WAFER_VERSION_MINOR_LO (read only)

Jtag fuses:
SOFT_DIS_JTAG (BLOCK0)                             Set these bits to disable JTAG in the soft way (od = 0 R/W (0b000)
                                                   d number 1 means disable ). JTAG can be enabled in
                                                    HMAC module
DIS_PAD_JTAG (BLOCK0)                              Set this bit to disable JTAG in the hard way. JTAG = True R/- (0b1)
                                                    is disabled permanently

Mac fuses:
MAC (BLOCK1)                                       MAC address
   = 40:4c:ca:eb:48:a8 (OK) R/W
CUSTOM_MAC (BLOCK3)                                Custom MAC address
   = 00:00:00:00:00:00 (OK) R/W

Security fuses:
DIS_DOWNLOAD_ICACHE (BLOCK0)                       Set this bit to disable Icache in download mode (b = True R/- (0b1)
                                                   oot_mode[3:0] is 0; 1; 2; 3; 6; 7)
DIS_FORCE_DOWNLOAD (BLOCK0)                        Set this bit to disable the function that forces c = False R/- (0b0)
                                                   hip into download mode
DIS_DOWNLOAD_MANUAL_ENCRYPT (BLOCK0)               Set this bit to disable flash encryption when in d = True R/- (0b1)
                                                   ownload boot modes
SPI_BOOT_CRYPT_CNT (BLOCK0)                        Enables flash encryption when 1 or 3 bits are set  = Enable R/- (0b001)
                                                   and disables otherwise
SECURE_BOOT_KEY_REVOKE0 (BLOCK0)                   Revoke 1st secure boot key                         = False R/W (0b0)
SECURE_BOOT_KEY_REVOKE1 (BLOCK0)                   Revoke 2nd secure boot key                         = False R/W (0b0)
SECURE_BOOT_KEY_REVOKE2 (BLOCK0)                   Revoke 3rd secure boot key                         = False R/W (0b0)
KEY_PURPOSE_0 (BLOCK0)                             Purpose of Key0                                    = USER R/W (0x0)
KEY_PURPOSE_1 (BLOCK0)                             Purpose of Key1                                    = XTS_AES_128_KEY R/- (0x4)
KEY_PURPOSE_2 (BLOCK0)                             Purpose of Key2                                    = USER R/W (0x0)
KEY_PURPOSE_3 (BLOCK0)                             Purpose of Key3                                    = USER R/W (0x0)
KEY_PURPOSE_4 (BLOCK0)                             Purpose of Key4                                    = USER R/W (0x0)
KEY_PURPOSE_5 (BLOCK0)                             Purpose of Key5                                    = USER R/W (0x0)
SECURE_BOOT_EN (BLOCK0)                            Set this bit to enable secure boot                 = False R/W (0b0)
SECURE_BOOT_AGGRESSIVE_REVOKE (BLOCK0)             Set this bit to enable revoking aggressive secure  = False R/W (0b0)
                                                   boot
DIS_DOWNLOAD_MODE (BLOCK0)                         Set this bit to disable download mode (boot_mode[3 = False R/- (0b0)
                                                   :0] = 0; 1; 2; 3; 6; 7)
ENABLE_SECURITY_DOWNLOAD (BLOCK0)                  Set this bit to enable secure UART download mode   = False R/- (0b0)
SECURE_VERSION (BLOCK0)                            Secure version (used by ESP-IDF anti-rollback feat = 0 R/- (0x0000)
                                                   ure)
BLOCK_KEY0 (BLOCK4)
  Purpose: USER
               Key0 or user data
   = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W
BLOCK_KEY1 (BLOCK5)
  Purpose: XTS_AES_128_KEY
    Key1 or user data
   = ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? -/-
BLOCK_KEY2 (BLOCK6)
  Purpose: USER
               Key2 or user data
   = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W
BLOCK_KEY3 (BLOCK7)
  Purpose: USER
               Key3 or user data
   = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W
BLOCK_KEY4 (BLOCK8)
  Purpose: USER
               Key4 or user data
   = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W
BLOCK_KEY5 (BLOCK9)
  Purpose: USER
               Key5 or user data
   = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W

Spi Pad fuses:
SPI_PAD_CONFIG_CLK (BLOCK1)                        SPI PAD CLK                                        = 0 R/W (0b000000)
SPI_PAD_CONFIG_Q (BLOCK1)                          SPI PAD Q(D1)                                      = 0 R/W (0b000000)
SPI_PAD_CONFIG_D (BLOCK1)                          SPI PAD D(D0)                                      = 0 R/W (0b000000)
SPI_PAD_CONFIG_CS (BLOCK1)                         SPI PAD CS                                         = 0 R/W (0b000000)
SPI_PAD_CONFIG_HD (BLOCK1)                         SPI PAD HD(D3)                                     = 0 R/W (0b000000)
SPI_PAD_CONFIG_WP (BLOCK1)                         SPI PAD WP(D2)                                     = 0 R/W (0b000000)
SPI_PAD_CONFIG_DQS (BLOCK1)                        SPI PAD DQS                                        = 0 R/W (0b000000)
SPI_PAD_CONFIG_D4 (BLOCK1)                         SPI PAD D4                                         = 0 R/W (0b000000)
SPI_PAD_CONFIG_D5 (BLOCK1)                         SPI PAD D5                                         = 0 R/W (0b000000)
SPI_PAD_CONFIG_D6 (BLOCK1)                         SPI PAD D6                                         = 0 R/W (0b000000)
SPI_PAD_CONFIG_D7 (BLOCK1)                         SPI PAD D7                                         = 0 R/W (0b000000)

Usb fuses:
DIS_USB_JTAG (BLOCK0)                              Set this bit to disable function of usb switch to  = True R/- (0b1)
                                                   jtag in module of usb device
DIS_USB_SERIAL_JTAG (BLOCK0)                       USB-Serial-JTAG                                    = Enable R/- (0b0)
USB_EXCHG_PINS (BLOCK0)                            Set this bit to exchange USB D+ and D- pins        = False R/W (0b0)
DIS_USB_SERIAL_JTAG_ROM_PRINT (BLOCK0)             USB printing                                       = Enable R/- (0b0)
DIS_USB_SERIAL_JTAG_DOWNLOAD_MODE (BLOCK0)         Disable UART download mode through USB-Serial-JTAG = True R/- (0b1)

Vdd fuses:
VDD_SPI_AS_GPIO (BLOCK0)                           Set this bit to vdd spi pin function as gpio       = False R/W (0b0)

Wdt fuses:
WDT_DELAY_SEL (BLOCK0)                             RTC watchdog timeout threshold; in unit of slow cl = 40000 R/W (0b00)
                                                   ock cycle

So no spelunking in the factory firmware, nor can we upload anything that isn't encrypted.

  • SPI_BOOT_CRYPT_CNT: R/- (write protected) — can't disable encryption
  • BLOCK_KEY1: -/- (read/write protected) — can't extract key to pre-encrypt firmware
  • DIS_DOWNLOAD_MANUAL_ENCRYPT: True — can't use download mode's encrypt-on-write feature
  • DIS_PAD_JTAG: True — no hardware debug
  • DIS_USB_JTAG: True — no USB JTAG either

So that's that for the firmware. I shouldn't be surprised. Nice job, Philips/Signifyd.

Some more searching unearthed some application notes for the ESP.

Revival with ESPHome

Okay well what if we just stick our own ESP on to here?

Looking at the documentation for WiZ's ESP module, it's not particularly complex. Like we thought, 5 PWM outputs that this bulb has repurposed 2 of for I2C.

Arguably, a regular ESP would be a better fit anyway. Philips probably just distributes the hardware/firmware package for easy integration. We don't do anything the easy way so lets try ourselves.

After desoldering the WiZ ESP, an ESP32-C6 SuperMini has no problem hooking up to the SDA/SCL pins. Because the 3.3v supply is out of commission until my DigiKey order arrives, I'm powering the ESP separately via USB-C.

I could certainly just replace the $0.50 capacitor and be done but this is a chance for me to fix a few gripes I have with WiZ:

  • lack of < 10% dimming
  • can't set transition/fade rates by command
  • can't do custom color math

ESPHome, being the amazing community that it is, already has a driver for the BP5758D (I believe it's common in Tuya stuff). Life is good.

esphome:
  name: puresmart-trucolor

esp32:
  board: esp32-c6-devkitm-1
  framework:
    type: esp-idf

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

logger:

api:

ota:
  platform: esphome

bp5758d:
  data_pin: GPIO1
  clock_pin: GPIO0

output:
  - platform: bp5758d
    id: bp_blue
    channel: 1
    current: 10
  - platform: bp5758d
    id: bp_green
    channel: 2
    current: 10
  - platform: bp5758d
    id: bp_red
    channel: 3
    current: 10
  - platform: bp5758d
    id: bp_ww
    channel: 4
    current: 10
  - platform: bp5758d
    id: bp_cw
    channel: 5
    current: 10

light:
  - platform: rgbww
    name: "TruColor Bulb"
    red: bp_red
    green: bp_green
    blue: bp_blue
    cold_white: bp_cw
    warm_white: bp_ww
    cold_white_color_temperature: 6500 K
    warm_white_color_temperature: 1500 K
    color_interlock: false

Colors

I don't have a Sekonic to measure the actual CCT, but it's clear to my eyes that the WW and CW channels alone don't reach 1500K/6500K. Therefore this bulb must be mixing in other channels to reach those temperatures. By disabling color_interlock Home Assistant will allow for mixing all 5 channels from their UI. I don't really want this for anything other than the warmest temps, but I think I can script this out using Home Assistant templates.

Conclusion

This was an enjoyable attempt at reverse engineering the PureSmart TruColor bulb. I really like the TruColor line so I'm glad I'm able to give this device new life by strapping a $5 MCU of my own onto it and gaining some extra functionality with ESPHome.

A better solution might be to take the CAD drawings and design a new PCB that can be easily dropped into the slot and take control with ESPHome. The hard part would be getting that assembly back into a bulb.