How to Enable the Zephyr BLE Shell for Debugging Your Hubble Firmware

You’ve got your Hubble firmware building on Zephyr. It flashes cleanly. You open a serial terminal, type bt, and… nothing. Maybe a terse “command not found.” Maybe just silence.
People run bt init and bt advertise on in forum posts. The Zephyr docs show an interactive Bluetooth shell. But your project doesn’t have it, and it’s not obvious why.
Zephyr’s BLE shell exists, it’s powerful, and it’s probably 4 lines of config away from working in your project. Zephyr compiles in only what you ask for, though. If you didn’t ask for the BLE shell, it doesn’t exist in your binary.
This guide gets you from “bt command not found” to running bt init and bt advertise on from your serial console. The whole fix takes about 5 minutes.
What You’ll Need Before Starting
- A working Zephyr dev environment (
west buildruns without errors) - A Hubble firmware project that builds and flashes. If you’re starting fresh, the Hubble Zephyr reference application is a good baseline.
- A BLE-capable board (nRF52840-based boards are the most common)
- A serial terminal (minicom, PuTTY, screen, or similar) connected to your board’s UART at 115200 baud
One quick check: if you don’t see any shell prompt over UART yet, you’ll need CONFIG_SHELL=y and CONFIG_UART_CONSOLE=y in your config first. The steps below assume you at least have a uart:~$ prompt.
Why You’re Seeing “bt command not found”
Zephyr’s build system is driven by Kconfig, the same configuration system the Linux kernel uses. Every feature, subsystem, and driver is a config symbol that defaults to off. If you don’t flip the switch, the code doesn’t get compiled into your binary.
The bt command group comes from CONFIG_BT_SHELL. But it doesn’t work alone; it depends on two other symbols being set first:
CONFIG_SHELL=y
└── CONFIG_BT=y
└── CONFIG_BT_SHELL=y ← registers the "bt" commandIf any link in that chain is missing, the bt command doesn’t exist at runtime. There’s no helpful error telling you why. It just isn’t there.
Zephyr’s own samples/bluetooth/shell sample has all of these set in its prj.conf, which is why it works out of the box. Your custom Hubble project almost certainly doesn’t inherit those settings.
Step-by-Step: Enabling the BLE Shell
This is purely a configuration change. You won’t touch any C code.
Step 1: Edit Your prj.conf
Open your project’s prj.conf and add these lines:
# Enable the shell subsystem (may already be set)
CONFIG_SHELL=y
# Enable the Bluetooth stack
CONFIG_BT=y
# Set a device name (shows up in advertising)
CONFIG_BT_DEVICE_NAME="HubbleDev"
# Enable roles you need — pick one or both
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_CENTRAL=y
# Enable the BLE shell command group
CONFIG_BT_SHELL=yA few of these might already be in your config (especially CONFIG_BT=y if you’ve got a Hubble project). Don’t duplicate them; just make sure they’re present.
Two optional but useful additions:
# Enables "bt scan on" — needed for scanning nearby devices
CONFIG_BT_OBSERVER=y
# Enables "bt advertise on" — needed for broadcasting
CONFIG_BT_BROADCASTER=yOn the dependency side: CONFIG_BT_PERIPHERAL=y automatically enables CONFIG_BT_BROADCASTER, and CONFIG_BT_CENTRAL pulls in CONFIG_BT_OBSERVER. You can list them explicitly without any harm, and it makes your config easier to read.
Step 2: Verify the UART Shell Backend
The shell needs a transport to talk to you. UART is the default, and it’s almost always what you want. Confirm this line exists (or add it):
CONFIG_SHELL_BACKEND_SERIAL=yOn most boards this is already the default, but I’ve seen projects where it got turned off by a board-level defconfig. Worth checking.
Step 3: Pristine Rebuild and Flash
This is the step people skip, and then spend 20 minutes confused. Kconfig changes require a pristine build. Zephyr’s CMake cache can hold onto stale config values if you do an incremental build.
west build -p -b <your_board>
west flashThe -p flag tells west to wipe the build directory and start fresh. Don’t skip it.
If you’re targeting an nRF52840 DK, that looks like:
west build -p -b nrf52840dk_nrf52840
west flashStep 4: Connect and Verify
Open your serial terminal at 115200 baud. You should see the uart:~$ prompt. Type help and press Enter.
uart:~$ help
Available commands:
bt : Bluetooth shell commands
clear : Clear screen
device : Device commands
help : Display help
history : Command history
kernel : Kernel commands
shell : Useful shell commands
...If bt shows up in that list, the hard part is done.
┌──────────────────────────────────────────────────┐
│ TROUBLESHOOTING │
│ │
│ Still no "bt" command? │
│ 1. Confirm you used a pristine build (-p flag) │
│ 2. Check build log for "BT_SHELL" warnings │
│ 3. Run: west build -t menuconfig │
│ Search for BT_SHELL — verify it shows [*] │
│ 4. Ensure your board's devicetree has a BLE │
│ controller node enabled │
│ │
└──────────────────────────────────────────────────┘The menuconfig trick (step 3 above) is especially useful. It shows the resolved state of every Kconfig symbol, including dependencies. If BT_SHELL shows as [ ] with unmet dependencies, menuconfig will tell you exactly which ones.
Running Your First BLE Shell Commands
Two commands to confirm everything works.
bt init
This initializes the BLE stack at runtime:
uart:~$ bt init
Bluetooth initializedIf you see “Bluetooth initialized,” the HCI transport to your radio is working and the stack is live.
A failure here (something like “HCI driver not found” or a hang) usually means the board’s BLE controller isn’t properly defined in the devicetree, or there’s a hardware issue. That’s a separate problem from the shell config.
bt advertise on
This starts connectable advertising using the device name you set in CONFIG_BT_DEVICE_NAME:
uart:~$ bt advertise on
Advertising startedGrab your phone, open nRF Connect (free from Nordic Semiconductor, available on iOS and Android), and scan. You should see “HubbleDev” (or whatever name you chose) broadcasting.
To stop advertising:
uart:~$ bt advertise off
Advertising stoppedHere’s a quick reference for other commands you’ll probably want:
| Command | What it does |
|---|---|
bt init | Initialize the BLE stack |
bt advertise on | Start connectable advertising |
bt scan on | Start scanning for nearby devices |
bt scan off | Stop scanning |
bt disconnect | Drop the current connection |
bt info | Show local device info and address |
All of these are subcommands, so bt help will list everything available. The set of commands you see depends on which CONFIG_BT_* options are enabled.
Flash, RAM, and Why You Shouldn’t Ship This
The BLE shell isn’t free. Enabling CONFIG_BT_SHELL along with its dependencies adds roughly 10 to 30 KB of flash, depending on how many subcommands get pulled in. RAM overhead is smaller but still meaningful on constrained devices.
The shell is also an open command interface over UART. Anyone with physical access to the serial port can poke at your BLE stack. Fine on a dev bench; a security hole in a production device.
The cleanest approach: keep a separate config file for debug builds. Create a debug_shell.conf next to your prj.conf:
# debug_shell.conf — BLE shell overlay for development only
CONFIG_SHELL=y
CONFIG_SHELL_BACKEND_SERIAL=y
CONFIG_BT_SHELL=yThen build with it as an overlay:
west build -p -b nrf52840dk_nrf52840 -- -DOVERLAY_CONFIG=debug_shell.confYour project structure looks something like this:
hubble-firmware/
├── prj.conf # Base config (no shell)
├── debug_shell.conf # Adds shell + BT_SHELL
├── boards/
│ └── nrf52840dk_nrf52840.overlay
└── src/
└── main.cProduction builds use prj.conf alone. Debug builds layer on the overlay. No risk of accidentally shipping the shell, and your base config stays clean. You can read more about structuring firmware integration in the Hubble device integration guide.
Using the Shell Beyond Basic Debugging
The fix for “bt command not found” is almost always the same: add CONFIG_BT_SHELL=y (and its dependencies) to your prj.conf, do a pristine rebuild, and you’re set.
Once the shell is running, it becomes one of the most useful tools in your Zephyr workflow:
- Inspect GATT services with
bt gatt-show - Test connection parameters
- Debug pairing
- Examine the advertising data format
No throwaway test code required. If you’re working with Hubble’s BLE advertising packet structure, the advertising packet documentation pairs well with what you can observe through shell commands.
Hubble Network lets you connect BLE devices directly to satellite networks—no gateways, no extra infrastructure. See how it works →