GitHub

Fox Red Labs / Builds / Smart home and radio

Switch a board's LED from Home Assistant over Zigbee

Flash TI's on/off light example on a CC2340R5 and switch its LED from Home Assistant. It worked on 2026-10-05; a repeat on 2026-10-16 did not join.

HardNo wiring

Parts and steps

You need

Set up your computer once: 1 step. Done already? Start at step 2.
  1. Install the tools once, all free.TERMINAL

    Get the macOS installer for the SimpleLink Low Power F3 SDK 9.21.00.36 LTS from TI's SDK page (0.55 GB download, 2.0 GB installed). Get CCStudio 21.0.1 from TI's CCStudio download page for TI Arm Clang 5.1.1. Get SysConfig 1.26.3 from TI's SysConfig page (0.96 GB installed). Get UniFlash 9.6.0 from TI's UniFlash page (0.3 GB download, 1.9 GB installed). Install steps, times and disk space are in the repository's mac-setup/README.md. This repo's scripts point at SysConfig 1.26.3. It came with the SimpleLink Wi-Fi SDK installer on the test Mac, which put it in /Applications/ti/sysconfig_1.26.3. CCStudio 21.0.1 carries its own 1.28.1. This repo's scripts do not point at it.

    You should see: The SDK folder simplelink_lowpower_f3_sdk_9_21_00_36_LTS and the folders sysconfig_1.26.3 and uniflash_9.6.0 are under /Applications/ti.

  1. Clip the probe onto the board, plug the probe's USB-C cable into the Mac, and read the probe's serial number.BENCH

    Put that serial number into cc2340r5/CC2340R5.ccxml, the connection file the flash command uses; it names the probe and the chip with SWD switched on. Do not write that file by hand. If you need a new one, let CCStudio write it; the import command is in cc2340r5/README.md, gotcha 2.

    /Applications/ti/ccs2101/ccs/ccs_base/common/uscif/xds110/xdsdfu -e
    The LP-EM-CC2340R5 clipped onto the LP-XDS110ET probe, with the probe's USB-C cable plugged in

    You should see: The probe's serial number is printed.

  2. Open cc2340r5/zigbee/onoff_light/on_off_light.syscfg and check that these two lines are set.EDITOR

    They are the whole change to TI's example. The first makes the board a router that joins an existing network. TI ships a coordinator that forms its own network. The second makes it search all 16 channels. TI ships channel 11 only, so a network on any other channel is never found. You can list just your own network's channel instead; Home Assistant shows it in the Zigbee integration's network settings.

    zigbee.deviceType = ["zr"]; zigbee.primaryChannels = [11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26];

    You should see: The file contains zigbee.deviceType = ["zr"]; and zigbee.primaryChannels = [11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]; at lines 109 and 110 in this repository's copy.

  3. Build the example.TERMINAL

    Run the first two commands from cc2340r5/. The three paths are where TI's installers put the tools on this Mac; change them if yours differ.

    cd zigbee/onoff_light/freertos/ticlang make -j4 SIMPLELINK_LOWPOWER_F3_SDK_INSTALL_DIR=/Applications/ti/simplelink_lowpower_f3_sdk_9_21_00_36_LTS \ SYSCONFIG_TOOL=/Applications/ti/sysconfig_1.26.3/sysconfig_cli.sh \ TICLANG_ARMCOMPILER=/Applications/ti/ccs2101/ccs/tools/compiler/ti-cgt-armllvm_5.1.1.LTS cd ../../../..

    You should see: About 30 s of building, then onoff_light.hex in that folder.

  4. Open joining before you flash.BROWSER

    In Home Assistant go to Settings, Devices, Add device (ZHA). Or call the zha.permit service with a duration of 180.

    You should see: Home Assistant is searching for Zigbee devices. In the tries the board joined within 37 to 58 s of booting, so flash straight after this.

  5. Flash it, from cc2340r5/.TERMINAL

    The -e in this command prints progress; it does not erase.

    /Applications/ti/uniflash_9.6.0/dslite.sh --mode flash -c CC2340R5.ccxml -e -f -u zigbee/onoff_light/freertos/ticlang/onoff_light.hex

    You should see: UniFlash prints Loading Program: zigbee/onoff_light/freertos/ticlang/onoff_light.hex, then Setting PC to entry point. and Success, about 14 s.

  6. Watch the Zigbee device list.BROWSER

    Prove the join from here rather than from the board's log.

    You should see: A new device named unk_manufacturer unk_model appears 37 s after the flash finished, shown as a switch rather than a light. Its address starts 00:12:4b, TI's prefix.

  7. Turn the new switch on and off from its device page.BROWSER

    You should see: The board's LED follows the switch. Over 20 switch commands from a script on the Mac, all 20 landed. Home Assistant showed the new state after a median of 95 ms, with a minimum of 73 and a maximum of 292.

Could work Open joining in Home Assistant first and retry if the board does not join.

Or hand it to a coding assistant

Paste this in a terminal. It hands off to an AI assistant.

git clone --depth 1 --filter=blob:none https://github.com/Fox-Red-Labs/fox-red-labs.git && cd fox-red-labs ./start.sh cc2340r5 zigbee-light --assistant claude

It runs the steps above and reports what it saw.

Not Claude Code? Copy this prompt instead.
Clone https://github.com/Fox-Red-Labs/fox-red-labs and read cc2340r5/AGENTS.md first. Then run Switch a board's LED from Home Assistant over Zigbee on my LP-EM-CC2340R5, following docs/builds/zigbee-light.md. Tell me when to plug in a board and what you saw at each step.

If something goes wrong

Your tools live somewhere elseThe three paths on the make line in step 4 and the dslite.sh path in step 6 are the only places to change.
A later flash says The target failed to see a correctly formatted SWD header (error -615)Pull the probe off the board and press it back on, then plug the cable in again. That cleared it on this bench.
You start from TI's own copy instead of this repository's copySet both lines or the board never appears in Home Assistant and nothing says why.
The make step cannot find a toolCheck the three paths. The SDK's own imports.mak points at folders that do not exist, which is why the paths are on the command line.
Joining closes before the board arrivesOpen it again.
More troubleshooting
The connection failsSee the SWD line in step 2.
You are starting over on a board that joined beforeRemove the device in Home Assistant first. Wait until it is gone from the device list. Re-pairing early left a stale record and the error Failed to send request: device did not respond.
The example leaves the manufacturer and model names empty, so Home Assistant fills in those wordsIt is harmless.
Nothing appears in about a minuteThe channel is the usual cause: recheck step 3.
Latency is one run on one deskAbout two hours later, after a re-pairing, the same image answered in 3.5 to 7.0 s, median about 5 s, while the coordinator reported a weaker link. The cause was not found. Measure more than once before you quote a number.

Every fix for this board: the FAQ.

What to build next

Every build. The code for all of them is in the GitHub repository.

Evidence and limitsJoined Home Assistant and switched in 95 ms on the CC2340R5, 20 of 20; a repeat on 2026-10-16 did not join. Ran on 1 board. Results, sources, timing and limits.

Expected result: On 2026-10-05 the board appeared in Home Assistant about 40 s after the flash as a switch, and the LED followed it. A repeat on 2026-10-16 did not join, so this result is not reproducible today.

What this shows

  • TI's Zigbee on/off light example joins a Home Assistant (ZHA) network through a ZBT-2 coordinator on a 36 kB-RAM LaunchPad, with two lines changed in a text file.
  • Commands from Home Assistant reach the board and change the LED: 20 of 20 in one run, median 95 ms until Home Assistant showed the new state.
What this does not establish, and limits

What this does not establish

  • That a lamp or any other real light was switched. The only light in any run is the board's own LED. A Zigbee plug with a lamp, switched from the same Home Assistant, is not part of the recorded run.
  • Range, current draw, packet loss over hours, or a sleeping battery device. The board is a router here and stays awake.
  • That other coordinators or Zigbee2MQTT work; only a ZBT-2 with ZHA was tried.
  • That the 95 ms is typical. It is one run of 20; the same board answered in about 5 s after a re-pairing two hours later, cause unknown.

Limits to keep in mind

  • Not reproducible today: the 2026-10-16 repeat did not join Home Assistant (cause open). Open joining in Home Assistant first and retry if the board does not join.
  • RAM is nearly full: 799 bytes free with logging on. Turn loggingEnabled off in SysConfig before adding application code.
  • The serial log is TI's binary format. The decoder tilogger fails on a Mac as shipped (unpack requires a buffer of 8 bytes); the one-line fix is in the board FAQ.
  • Checked on an Intel Mac only.
  • The over-the-air update from Home Assistant stalled at about 1% in four tries; cause unknown.

Sources

Why this board

TI's own Zigbee example runs on this chip with two lines changed in a text file. The 36 kB of RAM leaves 799 bytes free, so the demo shows a small radio chip doing a real home job.

Versions, sizes and timing

Image size275.7 kB of flash; 35.2 kB of RAM used, 799 bytes free (logging on), from the linker map of the same source rebuilt later that eveningREADME notes
ToolchainSimpleLink Low Power F3 SDK 9.21.00.36 LTS, TI Arm Clang 5.1.1, SysConfig 1.26.3, UniFlash 9.6.0 (DSLite 21.0.0.4106)
Build and flash time30 s build (31 s after the channel fix), 14 to 15 s flash, 37 s from the flash finishing to the device listed in ZHAREADME notes
Switch latency20 of 20 landed; Home Assistant service call median 85 ms; state shown after a median of 95 ms, min 73, max 292
Link at first pairingLQI 60, RSSI -85 dBm as the coordinator reported it (weak)README notes
Same board after a re-pairing, two hours later30 of 30 landed, median about 5 s (3.5 to 7.0 s); cause unknown, suspected radio environment

Evidence

  • Repeated on 2026-10-16 on the same board, with the image rebuilt byte for byte from this source: it did not appear in Home Assistant's ZHA in three tries (about 4 minutes of open joining each). The board's own log was inconsistent between tries: once it reported a successful join as a router 6.2 s after a reset, once steering cancelled at 6.3 s and no active links left at 16 s. As a control, the Zigbee alarm image on the same board joined the same Home Assistant in 31 s and 7 s. README notes
  • Ran on the CC2340R5 on 2026-10-05: the board joined 37 s after the flash finished, and 20 of 20 on/off commands from Home Assistant landed (median 95 ms until Home Assistant showed the new state, min 73, max 292). One run. README notes
  • The flash output: the image loaded and the program started (Success).

Other boards

What the status words mean

Works ran here and did what it shouldCould work some of it ran; real porting effort is left; hover for whatNot for this chip the chip or its vendor software cannot; hover for why

Result grid

Project
LP-MSPM0G3507MSPM0G3507 chip
LP-MSPM0L1306MSPM0L1306 chip
LP-EM-CC2340R5CC2340R52 chip
LAUNCHXL-F2800137TMS320F2800137 chip
Switch a board's LED from Home Assistant over Zigbee
LP-MSPM0G3507Not for this chipNo radio
LP-MSPM0L1306Not for this chipNo radio
LP-EM-CC2340R5Could workWorked on 2026-10-05 (20 of 20, median 95 ms);
Detailsthe 2026-10-16 repeat did not join Home Assistant in three tries (cause open)
LP-EM-CC2340R5 Zigbee notes
LAUNCHXL-F2800137Not for this chipNo radio on this chip

Works ran here and did what it shouldShould work it builds; only naming, packaging or build glue is in the way; hover for whichCould work some of it ran; real porting effort is left; hover for whatNot for this chip the chip or its vendor software cannot; hover for why

Source files

Get the code and tell us how it wentThe clone command, the board folder with its AGENTS.md, reports from others, and the three report forms.

Get the code

Clone the repository and open the board's folder below. AGENTS.md is a plain text file of notes for AI coding assistants, and llms.txt at the root indexes the site for one.

git clone https://github.com/Fox-Red-Labs/fox-red-labs.git

Code is BSD-3-Clause, writing is CC BY 4.0; third-party folders keep their own licenses.

Built it? Tell us

Built this, or got stuck? Report it on GitHub with a few short answers. Your report shows here in your words, marked as yours. A failure that repeats on the bench gets its fix here.