Phone:

Hidden from the page source until you click: friction against scrapers, not a guarantee.

Email:

[email protected]

Role:

Sole designer & engineer

Stack:

C, STM32WB55, ST BLE full stack, Flipper SDK 1.4.3

Status:

Pre-release v0.1, GPLv3, scan and connect proven on hardware

Flipper Blue++

The Flipper Zero has had a full Bluetooth radio in it all along. It just wasn't allowed to use it. Blue++ is the firmware that lets it off the leash: the complete BLE stack, the command API handed to apps, and ten apps that put it to work.

  • Firmware
  • Bluetooth Low Energy
  • Embedded C
  • Open source
  • Security research
Flipper Blue++
The itch

Here is the thing that has quietly annoyed me since the day my Flipper arrived. It has an STM32WB55 inside, a chip with a dedicated second core that exists purely to run Bluetooth. ST ship a full BLE stack for that core. Flipper ship the "light" one. Light means peripheral only: the Flipper can advertise itself to your phone and that is the whole story. It cannot scan. It cannot connect to anything. It cannot read a single GATT characteristic. Sitting in your pocket is a device sold as a multi-tool for wireless, and the one radio it does best is stuck in listen-to-me-only mode.

The really maddening part? The firmware build system already knows how to use the full stack. There is a build flag for it. The runtime already recognises it. It is all just... switched off. Once I had noticed that, I could not un-notice it, and about four evenings later this repository existed.

What I built

Blue++ is a build script and a set of patches that take a clean clone of official firmware 1.4.3 and make three surgical changes, then a suite of ten apps that exploit them. First, it swaps in ST's full BLE stack and widens the GAP roles the firmware initialises to peripheral, central and observer. Second, and this is the bit that actually unlocks everything, it exports the ST BLE command API into the SDK so that ordinary .fap app files can call scan, connect and GATT functions directly. Stock firmware keeps every one of those functions behind a locked door; Blue++ adds over two hundred of them to the API table. Third, it removes the sub-GHz region gate, because if you are going to rebuild the firmware anyway you may as well have the CC1101 free to tune where the hardware allows.

On top of that sits a shared BLE central library that registers with the firmware's own event dispatcher, quietly consumes the events it owns so the stock peripheral code never sees them, and turns the asynchronous ATT event soup into straightforward synchronous calls behind a worker thread. Every BLE app is built on that one layer, so there is exactly one place where the tricky stuff lives.

The result is a Flipper that can see every BLE device in the room, tell you what it is, connect to it, walk its whole GATT database, read and write characteristics, subscribe to notifications, and log the lot to the SD card with timestamps. Which is, frankly, what it should have done out of the box.

Engineering decisions
  • Patch, don't fork: the repo holds no firmware source at all. The build script clones upstream, applies the changes and builds, so tracking a new Flipper release is a tag bump, not a rebase nightmare.
  • Export the vendor API, not a wrapper: apps get the raw ST aci_* and hci_* commands. Anyone who has read the STM32WB documentation can write a Blue++ app without learning a second abstraction.
  • Flash is the currency: every exported function stays in the image and eats internal storage. The build exposes a knob (BLE_API=min|all, or a hand-picked list of command groups) with a table showing exactly how many storage pages each setting costs. You pick the trade.
  • Coexist with the stock stack: a BLE app pauses the Flipper's own advertising and drops the phone link while it owns the radio, then restores both on exit. No permanent damage to the normal experience.
  • Refuse the dangerous exports by default: the coprocessor stack delete and install calls stay unexported because they can erase the radio stack. Raw flash access is exported for research but is a one-variable opt-out.
  • Honest limits, written down: no BLE Classic (the chip has none), no pairing as central yet, at most two links. The README says what does not work before you find out the hard way.
What it demonstrates

Reading a vendor's silicon documentation closely enough to spot that the limitation everyone accepts is a configuration choice, not a hardware one, then doing the unglamorous work of build-system surgery, API table generation and event-dispatcher plumbing to turn that observation into something you can flash on a Friday evening. It is also a decent example of how I like to ship: one shared library, ten small apps on top, everything logged, everything documented, every corner cut called out by name.

Ten apps, one radio

All ten install to the Flipper's app menu. The BLE apps share the same pattern: a live scan list sorted by signal strength, pick a device, do the thing. Everything logs to the SD card, because a finding you cannot show anyone later is not a finding.

BT Inspector

The flagship. A full BLE scanner and GATT explorer in the spirit of BTInspector for iOS. Every advertiser in range refreshed every 300 ms with name, RSSI bars, address and vendor. Open a device and it decodes the whole advertisement: flags, service UUIDs, service data, Tx power, appearance and manufacturer data, with dedicated decoders for Apple Continuity (iBeacon, AirPods and Beats model names with left, right and case battery levels, Find My, AirDrop, Handoff, AirPlay), Microsoft CDP, Google Fast Pair, Eddystone and Exposure Notification. Connect, and it negotiates MTU, discovers every service, reads Device Information in one press, then lets you read, write and subscribe to any characteristic, with SIG value decoding and a timestamped history per characteristic.

BLE HID Host

Connect a Bluetooth keyboard or mouse and watch its input decoded live on the Flipper's screen. It finds the HID service, picks Boot or Report protocol mode, subscribes to input reports and keeps the device out of suspend. Keystrokes come out as modifier and key names, mouse reports as buttons and dx, dy and wheel. Every event is logged with raw bytes.

BLE Sensor Dashboard

Point it at any BLE sensor and get a live readings screen. It discovers the services, picks out every characteristic with a known SIG meaning, reads each once and subscribes to the ones that notify. Battery, heart rate, temperature, humidity, pressure, Tx power, time and more, updating as the data arrives.

BLE Tracker Detector

Passive, always-on detection of item trackers: Apple Find My and AirTag by manufacturer data, Tile and Samsung SmartTag by service UUID. Anything seen repeatedly over roughly two minutes gets a "following" flag. It never connects, never de-anonymises, never disables. Detection only, logged with first-seen and follow events.

BLE GATT Fuzzer

For authorised testing of devices you own. Connects, walks every service and characteristic, reads every readable value and logs UUIDs, handles, properties and results. One more press runs a fuzz pass that fires boundary payloads (empty, 0x00, 0xFF, a run of 0x41) at every writable characteristic and records whether each was accepted or rejected.

BLE Beacon Toolkit

Broadcast an advertisement of your choosing from a random MAC of your choosing. iBeacon mode takes UUID, major, minor and Tx power; Raw mode sends whatever bytes you type, up to the 31-byte limit. It uses the firmware's extra-beacon API, so it advertises alongside the normal stack rather than fighting it.

BLE GATT Server

The Flipper as a connectable peripheral you can talk to. It brings up the serial GATT service with RX and TX characteristics and echoes back whatever a central writes as a notification. Connect from nRF Connect on a phone, write to RX, watch it come back. On-screen connection state, byte counters and the last received text.

Sub-GHz Scanner

Sweeps the CC1101's range in 250 kHz steps, draws a live spectrum bar graph, tracks the peak and logs every frequency that crosses a threshold with a timestamp. Cycle between the three hardware bands or sweep the lot.

Sub-GHz Spectrum

A live spectrum on top and a scrolling intensity waterfall underneath, so you can watch activity over time. Retune the centre frequency by a quarter-span, widen or narrow the window from 250 kHz to 8 MHz. Receive only.

Battery Health

Live readings straight from the fuel-gauge IC: charge, state, voltage, current, temperature, remaining, full and design capacity, a derived wear estimate and USB voltage, with a rolling voltage graph. Read-only, and the one app in the set that also runs on stock firmware.

Installing it

Grab the update package from the releases page. It contains the firmware, the full radio stack and all ten apps. Unpack it and use qFlipper's "Install from file" on the update file inside, or copy the folder to the SD card and run it from the Flipper's file browser. Already on Blue++ and just want fresh apps? There is a separate zip of the ten .fap files, which is a plain file copy to the SD card.

For the full technical story, including why scanning has to go through the GAP observation procedure and what the shared library does with the firmware's event dispatcher, read the blog post on Blue++.

Prefer to build it yourself? One script does the whole job: clone the firmware, apply the patches, build, and optionally flash over USB. The first build takes five to fifteen minutes and downloads its own ARM toolchain; later builds are incremental.

Run ./build.sh to clone, patch and build everything, ./build.sh flash to do the same and flash over USB, or ./build.sh fap to rebuild only the apps once the firmware exists.

Two things worth knowing before you press the button. Installing replaces the Bluetooth radio stack as well as the firmware, so take a backup in qFlipper first; going back to any official release restores the stock stack. And the sub-GHz unlock means transmitting outside the frequencies and power levels allocated to you may be illegal where you are. It is there for research and authorised testing, and one variable keeps the region limits in place if you would rather it were not.