thepetric 452f99be4b Add web authentication, logout, favicon, and UI fixes
This update improves the BTPrivacy web dashboard by adding basic hardcoded login protection, logout support, and an embedded favicon served directly by the ESP32 web server.
2026-06-21 13:38:06 +00:00
2026-06-21 14:16:52 +02:00
2026-06-21 14:16:52 +02:00
2026-06-21 15:34:25 +02:00
2026-06-21 14:16:52 +02:00
2026-06-21 12:15:33 +00:00
2026-06-21 14:40:15 +02:00

BTPrivacy

BTPrivacy is an ESP32-S3 Arduino project for BLE privacy noise and local counter-recon.

It fills the nearby BLE scanner view with short-lived, non-connectable entries. The point is simple: when testing your own desk, car, garage, workshop or lab, a scanner should not get a clean list of what is actually nearby.

It does not connect to anything, pair with anything or run a GATT server. It also avoids Apple Continuity, Microsoft Swift Pair and Google Fast Pair style payloads, so it is not a pairing-popup sketch.

Use it only in your own environment. Do not run it in public places or anywhere it could annoy people or interfere with normal devices.

Hardware

Target board:

ESP32-S3 N16R8
16 MB flash
8 MB PSRAM

The project uses ESP32-S3 BLE5 multi-advertising through the Arduino ESP32 Bluedroid stack. A classic ESP32/WROOM does not support this in the same way.

What it does

  • runs multiple BLE advertisements at the same time
  • lets you change the active slot count from the web UI
  • rotates one live advertising slot at a time
  • uses valid static-random BLE MAC addresses
  • builds a large PSRAM-backed profile pool
  • avoids MAC reuse until the generated pool wraps
  • uses a larger short-name list so scans look less repetitive
  • serves an optional Bootstrap 5 status page over Wi-Fi
  • keeps working without Wi-Fi if Wi-Fi is disabled or fails

Default build:

4 live advertising slots
4 maximum configured slots
16384 generated profiles
100 short names
30 manufacturer prefixes
1 slot refresh every 2000 ms
about 8 seconds to refresh the live set
about 9.1 hours before the generated MAC pool wraps

Screenshots

Web dashboard

BTPrivacy web dashboard

Phone scanner / visible devices

BTPrivacy visible BLE devices

Arduino IDE setup

Start with this setup:

Arduino IDE
esp32 by Espressif Systems: 3.2.1
Board: ESP32S3 Dev Module
Flash Size: 16MB
PSRAM: OPI PSRAM
Partition Scheme: 16MB Flash / Huge APP or Large APP
USB CDC On Boot: Enabled
USB Mode: Hardware CDC and JTAG, if your menu has it
Upload Speed: 460800 or 921600

Arduino-ESP32 3.2.1 is recommended because this sketch uses Bluedroid BLE5 multi-advertising. Newer cores may push ESP32-S3 BLE sketches toward NimBLE, and NimBLE does not expose the same multi-advertising API here.

No extra BLE library is needed. Do not include NimBLE-Arduino for this sketch.

Uploading

Open:

BTPrivacy/BTPrivacy.ino

If upload hangs at Connecting...:

Hold BOOT
Press and release RST
Keep BOOT held for another second
Release BOOT when upload starts

If it still fails, lower upload speed to 460800 or 115200.

Wi-Fi dashboard

Wi-Fi is optional and disabled by default. There is no AP mode and no fallback hotspot.

To enable the dashboard, edit the Wi-Fi section near the top of BTPrivacyApp.cpp:

static constexpr bool     BTPRIVACY_WIFI_ENABLED      = true;
static constexpr char     BTPRIVACY_WIFI_SSID[]       = "YourWiFiName";
static constexpr char     BTPRIVACY_WIFI_PASSWORD[]   = "YourWiFiPassword";
static constexpr char     BTPRIVACY_WIFI_HOSTNAME[]   = "btprivacy";
static constexpr bool     BTPRIVACY_MDNS_ENABLED      = true;
static constexpr uint16_t BTPRIVACY_WEB_PORT          = 80;
static constexpr uint32_t BTPRIVACY_WIFI_TIMEOUT_MS   = 12000;
static constexpr char     BTPRIVACY_WEB_USERNAME[]    = "admin";
static constexpr char     BTPRIVACY_WEB_PASSWORD[]    = "btprivacy";

BTPRIVACY_WIFI_HOSTNAME is the hostname sent to the router. If mDNS works on your network, the dashboard should also be reachable at:

http://btprivacy.local/

The direct IP address is always printed in Serial Monitor when Wi-Fi connects:

Wi-Fi dashboard: http://192.168.x.x/

The dashboard is protected by a local login page. The default credentials are:

Username: admin
Password: btprivacy

To change them, edit BTPRIVACY_WEB_USERNAME and BTPRIVACY_WEB_PASSWORD near the top of BTPrivacyApp.cpp.

The page shows:

  • advertising state
  • active slot count
  • uptime
  • rotations
  • pool index
  • current live slots
  • current slot MACs and names
  • heap / PSRAM status
  • Wi-Fi IP, RSSI and hostname

The page has controls for:

Pause / resume
Rotate faster
Rotate slower
Less slots
More slots
Restart advertisers
Rebuild pool

Changing the slot count restarts the advertising instances cleanly. If the ESP32 BLE controller starts logging errors, use fewer slots.

If Wi-Fi is not configured or the board cannot join the network in time, it shuts Wi-Fi back down and keeps BLE running normally.

The web page uses Bootstrap 5 from a CDN. If the computer/phone opening the dashboard has no internet access, the page still loads, but the styling may look plain.

Serial Monitor

Use:

115200 baud
Tools > USB CDC On Boot > Enabled
Correct port selected after upload
Serial Monitor closed while uploading

The sketch prints a heartbeat every 5 seconds and prints slot refreshes. If you see BLE devices on your phone but Serial is blank, the firmware is running and the problem is only serial routing.

Serial commands:

s  status
+  rotate faster
-  rotate slower
[  one slot less
]  one slot more
p  pause / resume advertisements
r  rebuild the profile pool
x  restart advertisers

Tuning

Most settings are near the top of BTPrivacyApp.cpp.

Good default:

static constexpr uint8_t  BTPRIVACY_MIN_ADV_SETS      = 1;
static constexpr uint8_t  BTPRIVACY_DEFAULT_ADV_SETS  = 4;
static constexpr uint8_t  BTPRIVACY_MAX_ADV_SETS      = 4;
static constexpr uint16_t BTPRIVACY_PROFILE_POOL      = 16384;
static constexpr uint32_t BTPRIVACY_DEFAULT_ROTATE_MS = 2000;

If the BLE controller complains, reduce default/max slots first:

static constexpr uint8_t BTPRIVACY_DEFAULT_ADV_SETS = 3;
static constexpr uint8_t BTPRIVACY_MAX_ADV_SETS     = 3;

If it is stable and you want faster churn:

static constexpr uint32_t BTPRIVACY_DEFAULT_ROTATE_MS = 1000;

Do not make it too fast. Scanner apps need time to catch the advertisements, and the ESP32 controller needs time to stop and restart a slot cleanly.

Notes

BTPrivacy is a small practical privacy/counter-recon tool for local BLE visibility testing. It creates decoys; it does not connect, pair, exploit or attack.

Keep tests local, keep power reasonable, and do not run it to bother other people.

S
Description
BLE counter-recon firmware for ESP32-S3 that fills local scans with rotating, non-connectable decoy devices.
Readme MIT 873 KiB
Languages
C++ 99.8%
C 0.2%