2025-09-11 17:10:50 +02:00
2025-09-11 17:10:50 +02:00
2025-09-11 17:10:50 +02:00
2025-09-11 17:10:50 +02:00
2025-09-11 17:10:50 +02:00
2025-09-11 17:10:50 +02:00

PyBLEDetect - ESP32 Tracker Detector

This repository is part of the master thesis Tag'n'Track, providing an implementation of a tracker detector based on an ESP32-32D N4 and Micropython.
The code is developed and tested on such an ESP, therefore, it is recommended to use a similar model as detector.
The purpose of the detector is to evaluate the surrounding BLE devices.
They are classified based on their available GATT services and characteristics to detect BLE trackers.
Trackers are logged and if they are seen over a specific amount of time, there is an alarm.
The detector is mainly for persons affected by IPV and digital stalking, administrated by support infrastructure such as women's consulting centers.
Therefore, it is necessary to have a practical and for non-technical users usable device. More information is part of the master thesis.

Installation and Setup

An ESP32-32D is required to run the detection (and main.py script) on. For initial flashing of the ESP32, the documentation is provided by Micropython directly: https://micropython.org/download/ESP32_GENERIC/

The latest firmware as v1.25.0 (2025-04-15) is used, while flashing is done by esptool.
After successful flashing, it is necessary to deploy the script to the ESP.
For women's consulting centers, this step should be executed by their general IT department, or it should be delivered to be able to start with a Plug and Play approach.

To complete the setup, main.py needs to be placed on the ESP32.
This is achieved by a USB connection between the target device and the computer with the script and this repository.
mpremote is used for copying the script:

mpremote connect auto fs cp main.py :

Running Detection

With the purpose of a detector for trackers, it is necessary to run the detector in an environment where trackers should be detected.
An environment should be stationary or with a defined set of surroundings, for example bags, cars, or other belongings.
An external power source is necessary, for example a nano power bank or when running in a safe environment, a computer with debug output.
Starting the detection is either done manually by running with a Python terminal and directly evaluating the output (expert mode for technically advanced users) or by the web interface.

Debug Mode - Laptop directly

For technically advanced users, the detector can be used in a safe environment, directly plugged in to a laptop or computer.
With mpremote, it is possible to communicate with the ESP32 directly to start scripts, work with the filesystem, ...
For direct output, a USB connection between the ESP32 and the computer is required.
To start the script, it is necessary to connect to the ESP32 with

mpremote connect auto repl

Now the script needs to be executed with

import main

The script is now running and output is available, for example:

 mpremote connect auto repl                                      
Connected to MicroPython at /dev/ttyUSB0
Use Ctrl-] or Ctrl-x to exit this shell
import main
Scanning started
🔍 Scanning for BLE devices...
📡 Found device: 73:38:65:22:e4:21 (Unknown), RSSI=-70
📡 Found device: 31:08:6a:70:7f:1f (Unknown), RSSI=-48
📡 Found device: 4c:ee:56:68:5b:1f (Unknown), RSSI=-68
📡 Found device: dd:03:a6:74:24:d7 (Unknown), RSSI=-55
📡 Found device: ca:f3:86:64:81:c7 (Unknown), RSSI=-63
📡 Found device: e9:18:88:6d:22:53 (Unknown), RSSI=-13
📡 Found device: ce:ef:8f:c3:38:64 (iTrack), RSSI=-72
📡 Found device: d8:08:17:fd:34:a0 (Unknown), RSSI=-68
📡 Found device: 60:6e:cd:a0:36:b6 (Unknown), RSSI=-49
📡 Found device: 69:50:34:a0:e1:6f (Unknown), RSSI=-49
📡 Found device: cb:c2:14:08:87:5e (Unknown), RSSI=-55
📡 Found device: 4b:ed:ef:87:9d:30 (Unknown), RSSI=-67
📡 Found device: 3f:fd:b1:04:1d:b6 (Unknown), RSSI=-60
🔗 Connecting to 31:08:6a:70:7f:1f...
⚠️ Timeout while connecting to 31:08:6a:70:7f:1f
🔗 Connecting to dd:03:a6:74:24:d7...
✅ Connected to dd:03:a6:74:24:d7 (Unknown)
📑 Service on dd:03:a6:74:24:d7: UUID(0x1804)
📑 Service on dd:03:a6:74:24:d7: UUID(0x1801)
📑 Service on dd:03:a6:74:24:d7: UUID(0x1800)
📑 Service on dd:03:a6:74:24:d7: UUID(0xfd44)
📑 Service on dd:03:a6:74:24:d7: UUID('87290102-3c51-43b1-a1a9-11b9dc38478b')
Device classified: Apple
📑 Service on dd:03:a6:74:24:d7: UUID(0xff50)
📑 Service on dd:03:a6:74:24:d7: UUID(0xfd43)
    ◦ Characteristic UUID: UUID(0x2a07)
    ◦ Characteristic UUID: UUID(0x2b29)
    ◦ Characteristic UUID: UUID(0x2a05)
    ◦ Characteristic UUID: UUID(0x2b2a)
    ◦ Characteristic UUID: UUID(0x2a01)
    ◦ Characteristic UUID: UUID(0x2a00)
    ◦ Characteristic UUID: UUID(0x2ac9)
    ◦ Characteristic UUID: UUID('4f860001-943b-49ef-bed4-2f730304427a')
    ◦ Characteristic UUID: UUID('4f860002-943b-49ef-bed4-2f730304427a')
    ◦ Characteristic UUID: UUID('4f860003-943b-49ef-bed4-2f730304427a')
    ◦ Characteristic UUID: UUID('4f860004-943b-49ef-bed4-2f730304427a')
Device classified: Apple
    ◦ Characteristic UUID: UUID('6aa50001-6352-4d57-a7b4-003a416fbb0b')
Device classified: Apple
    ◦ Characteristic UUID: UUID('6aa50002-6352-4d57-a7b4-003a416fbb0b')
Device classified: Apple
    ◦ Characteristic UUID: UUID('6aa50003-6352-4d57-a7b4-003a416fbb0b')
Device classified: Apple
    ◦ Characteristic UUID: UUID('6aa50005-6352-4d57-a7b4-003a416fbb0b')
Device classified: Apple
    ◦ Characteristic UUID: UUID('6aa50006-6352-4d57-a7b4-003a416fbb0b')
Device classified: Apple
    ◦ Characteristic UUID: UUID('6aa50007-6352-4d57-a7b4-003a416fbb0b')
Device classified: Apple
    ◦ Characteristic UUID: UUID('6aa50008-6352-4d57-a7b4-003a416fbb0b')
Device classified: Apple
    ◦ Characteristic UUID: UUID('6aa50009-6352-4d57-a7b4-003a416fbb0b')
Device classified: Apple
    ◦ Characteristic UUID: UUID('6aa5000a-6352-4d57-a7b4-003a416fbb0b')
    ◦ Characteristic UUID: UUID(0xff51)
    ◦ Characteristic UUID: UUID(0xff52)
    ◦ Characteristic UUID: UUID('94110001-6d9b-4225-a4f1-6a4a7f01b0de')
🔌 Disconnected from dd:03:a6:74:24:d7

🔗 Connecting to 60:6e:cd:a0:36:b6...
✅ Connected to 60:6e:cd:a0:36:b6 (Unknown)
📑 Service on 60:6e:cd:a0:36:b6: UUID(0x180a)
📑 Service on 60:6e:cd:a0:36:b6: UUID(0x1801)
📑 Service on 60:6e:cd:a0:36:b6: UUID(0x1800)
📑 Service on 60:6e:cd:a0:36:b6: UUID(0xfd59)
📑 Service on 60:6e:cd:a0:36:b6: UUID(0xfe59)
📑 Service on 60:6e:cd:a0:36:b6: UUID('eedd5e73-6aa8-4673-8219-398a489da87c')
📑 Service on 60:6e:cd:a0:36:b6: UUID(0xfd5a)
    ◦ Characteristic UUID: UUID(0x2a26)
    ◦ Characteristic UUID: UUID(0x2a29)
    ◦ Characteristic UUID: UUID(0x2a28)
    ◦ Characteristic UUID: UUID(0x2a01)
    ◦ Characteristic UUID: UUID(0x2a00)
    ◦ Characteristic UUID: UUID(0x2a04)
    ◦ Characteristic UUID: UUID(0x2aa6)
    ◦ Characteristic UUID: UUID('04052818-d201-43eb-9d81-e936dc86ee06')
    ◦ Characteristic UUID: UUID('77b08bec-5890-49d1-b021-811741b417e6')
    ◦ Characteristic UUID: UUID('08a11e38-1c6d-4929-9c32-4f32a64985ce')
    ◦ Characteristic UUID: UUID('5b5f7a4c-257e-4841-92d5-0042658122b6')
    ◦ Characteristic UUID: UUID('12761292-241c-490c-8424-6f7cc8a8a027')
    ◦ Characteristic UUID: UUID('6ea31174-87b8-4ff6-98fa-796d87323792')
    ◦ Characteristic UUID: UUID('d19ddd83-bbe1-4144-bb18-f3ceb57c480a')
    ◦ Characteristic UUID: UUID('7534c394-1f40-4d12-afd7-dc2a75bd6a44')
    ◦ Characteristic UUID: UUID('bcc8cce6-8af6-48dc-a0ae-547f7c095229')
    ◦ Characteristic UUID: UUID('b03bd357-034a-4c57-ae56-575d974fc9de')
    ◦ Characteristic UUID: UUID('b57a3fe1-cf5e-4644-81ab-134d9f8ccaca')
    ◦ Characteristic UUID: UUID('89b0dfcb-0d9e-42b5-bc98-9a786fdc7d35')
    ◦ Characteristic UUID: UUID('661ef3f1-3ac1-483a-9fcb-8014c82bbfae')
    ◦ Characteristic UUID: UUID('be3a2589-1dfa-4a0a-9429-93899936cbed')
    ◦ Characteristic UUID: UUID('6ac16db1-f442-4bf4-b804-04c32356465d')
    ◦ Characteristic UUID: UUID('b5754629-6821-44c6-a118-492feecf6bb2')
    ◦ Characteristic UUID: UUID('bebfaa51-dcb8-44de-a4b8-fc8c9c7ef46d')
    ◦ Characteristic UUID: UUID('30c48d2a-6ccb-4240-9f97-7f97a3f1c030')
    ◦ Characteristic UUID: UUID('f299f805-17b3-43c1-ac12-fbcc59ee2f0d')
    ◦ Characteristic UUID: UUID('d0e8d14e-3d0b-4bda-9dad-4c2790f36210')
    ◦ Characteristic UUID: UUID('5352fee4-f3bc-462c-ba7c-279873bcdd71')
    ◦ Characteristic UUID: UUID('17bc2035-69ab-4a4f-b41b-7deb18ce6413')
    ◦ Characteristic UUID: UUID('abd6e6ba-3843-4786-b9b2-b69548eed881')
    ◦ Characteristic UUID: UUID('8ec90003-f315-4f60-9fb8-838830daea50')
    ◦ Characteristic UUID: UUID('50f98bfd-158c-4efa-add4-0a70c2f5df5d')
    ◦ Characteristic UUID: UUID('a12be31c-5b38-4773-9b9d-3d5735233a7c')
    ◦ Characteristic UUID: UUID('4ebe81f6-b952-465e-9ece-5ca39d4e8955')
    ◦ Characteristic UUID: UUID('dee30001-182d-5496-b1ad-14f216324184')
    ◦ Characteristic UUID: UUID('dee30002-182d-5496-b1ad-14f216324184')
    ◦ Characteristic UUID: UUID('dee30003-182d-5496-b1ad-14f216324184')
    ◦ Characteristic UUID: UUID('dee30004-182d-5496-b1ad-14f216324184')
    ◦ Characteristic UUID: UUID('dee30005-182d-5496-b1ad-14f216324184')
    ◦ Characteristic UUID: UUID('dee30006-182d-5496-b1ad-14f216324184')
    ◦ Characteristic UUID: UUID('dee30007-182d-5496-b1ad-14f216324184')
    ◦ Characteristic UUID: UUID('dee3000a-182d-5496-b1ad-14f216324184')
    ◦ Characteristic UUID: UUID('dee3000b-182d-5496-b1ad-14f216324184')
    ◦ Characteristic UUID: UUID('dee3000c-182d-5496-b1ad-14f216324184')
    ◦ Characteristic UUID: UUID('dee3000d-182d-5496-b1ad-14f216324184')
    ◦ Characteristic UUID: UUID('dee3000e-182d-5496-b1ad-14f216324184')
    ◦ Characteristic UUID: UUID('dee3000f-182d-5496-b1ad-14f216324184')
    ◦ Characteristic UUID: UUID('dee3001a-182d-5496-b1ad-14f216324184')
    ◦ Characteristic UUID: UUID('dee30020-182d-5496-b1ad-14f216324184')
    ◦ Characteristic UUID: UUID('dee30030-182d-5496-b1ad-14f216324184')
🔌 Disconnected from 60:6e:cd:a0:36:b6

🔗 Connecting to ce:ef:8f:c3:38:64...
✅ Connected to ce:ef:8f:c3:38:64 (iTrack)
📑 Service on ce:ef:8f:c3:38:64: UUID(0x1802)
📑 Service on ce:ef:8f:c3:38:64: UUID(0x1801)
📑 Service on ce:ef:8f:c3:38:64: UUID(0x1800)
📑 Service on ce:ef:8f:c3:38:64: UUID(0xffe0)
📑 Service on ce:ef:8f:c3:38:64: UUID(0x180f)
📑 Service on ce:ef:8f:c3:38:64: UUID(0x1803)
📑 Service on ce:ef:8f:c3:38:64: UUID(0xfe59)
📑 Service on ce:ef:8f:c3:38:64: UUID(0xfff0)
    ◦ Characteristic UUID: UUID(0x2a06)
    ◦ Characteristic UUID: UUID(0x2a05)
    ◦ Characteristic UUID: UUID(0x2a01)
    ◦ Characteristic UUID: UUID(0x2a00)
    ◦ Characteristic UUID: UUID(0x2a04)
    ◦ Characteristic UUID: UUID(0x2aa6)
    ◦ Characteristic UUID: UUID(0xffe1)
    ◦ Characteristic UUID: UUID(0x2a19)
    ◦ Characteristic UUID: UUID(0x2a06)
    ◦ Characteristic UUID: UUID('8ec90003-f315-4f60-9fb8-838830daea50')
    ◦ Characteristic UUID: UUID(0xfff2)
    ◦ Characteristic UUID: UUID(0xfff1)
    ◦ Characteristic UUID: UUID(0xfff4)
    ◦ Characteristic UUID: UUID(0xfff3)
    ◦ Characteristic UUID: UUID(0xfff5)
🔌 Disconnected from ce:ef:8f:c3:38:64

🔗 Connecting to 73:38:65:22:e4:21...
✅ Connected to 73:38:65:22:e4:21 (Unknown)
📑 Service on 73:38:65:22:e4:21: UUID(0x180a)
📑 Service on 73:38:65:22:e4:21: UUID(0x1801)
📑 Service on 73:38:65:22:e4:21: UUID(0x1800)
📑 Service on 73:38:65:22:e4:21: UUID('d0611e78-bbb4-4591-a5f8-487910ae4366')
📑 Service on 73:38:65:22:e4:21: UUID('9fa480e0-4967-4542-9390-d343dc5d04ae')
📑 Service on 73:38:65:22:e4:21: UUID(0x1805)
📑 Service on 73:38:65:22:e4:21: UUID(0x180f)
📑 Service on 73:38:65:22:e4:21: UUID('7905f431-b5ce-4e99-a40f-4b1e122d00d0')
📑 Service on 73:38:65:22:e4:21: UUID('89d3502b-0f36-433a-8ef4-c502ad55f8dc')
    ◦ Characteristic UUID: UUID(0x2a29)
    ◦ Characteristic UUID: UUID(0x2a24)
    ◦ Characteristic UUID: UUID(0x2a05)
    ◦ Characteristic UUID: UUID(0x2a00)
    ◦ Characteristic UUID: UUID(0x2a01)
    ◦ Characteristic UUID: UUID('8667556c-9a37-4c91-84ed-54ee27d90049')
    ◦ Characteristic UUID: UUID('af0badb1-5b99-43cd-917a-a77bc549e3cc')
    ◦ Characteristic UUID: UUID(0x2a2b)
    ◦ Characteristic UUID: UUID(0x2a0f)
    ◦ Characteristic UUID: UUID(0x2a19)
    ◦ Characteristic UUID: UUID('69d1d8f3-45e1-49a8-9821-9bbdfdaad9d9')
    ◦ Characteristic UUID: UUID('9fbf120d-6301-42d9-8c58-25e699a21dbd')
    ◦ Characteristic UUID: UUID('22eac6e9-24d6-4bb5-be44-b36ace7c7bfb')
    ◦ Characteristic UUID: UUID('9b3c81d8-57b1-4a8a-b8df-0e56f7ca51c2')
    ◦ Characteristic UUID: UUID('2f7cabce-808d-411f-9a0c-bb92ba96c102')
    ◦ Characteristic UUID: UUID('c6b2f38c-23ab-46d8-a6ab-a3a870bbd5d7')
🔌 Disconnected from 73:38:65:22:e4:21

🔗 Connecting to cb:c2:14:08:87:5e...
✅ Connected to cb:c2:14:08:87:5e (Unknown)
📑 Service on cb:c2:14:08:87:5e: UUID(0xfeed)
Device classified: Tile
📑 Service on cb:c2:14:08:87:5e: UUID(0x1801)
📑 Service on cb:c2:14:08:87:5e: UUID(0x1800)
Device classified: Tile
    ◦ Characteristic UUID: UUID('9d410018-35d6-f4dd-ba60-e7bd8dc491c0')
Device classified: Tile
    ◦ Characteristic UUID: UUID('9d410019-35d6-f4dd-ba60-e7bd8dc491c0')
    ◦ Characteristic UUID: UUID(0x2a01)
    ◦ Characteristic UUID: UUID(0x2a00)
    ◦ Characteristic UUID: UUID(0x2a04)
    ◦ Characteristic UUID: UUID(0x2ac9)
🔌 Disconnected from cb:c2:14:08:87:5e

🔗 Connecting to e9:18:88:6d:22:53...
⚠️ Timeout while connecting to e9:18:88:6d:22:53
🔗 Connecting to 4c:ee:56:68:5b:1f...
✅ Connected to 4c:ee:56:68:5b:1f (Unknown)
📑 Service on 4c:ee:56:68:5b:1f: UUID(0x180a)
📑 Service on 4c:ee:56:68:5b:1f: UUID(0x1800)
📑 Service on 4c:ee:56:68:5b:1f: UUID(0x1801)
📑 Service on 4c:ee:56:68:5b:1f: UUID('15190001-12f4-c226-88ed-2ac5579f2a85')
📑 Service on 4c:ee:56:68:5b:1f: UUID('0000fa25-0000-1000-8000-00805f9b34fb')
Device classified: Pebblebee
📑 Service on 4c:ee:56:68:5b:1f: UUID(0xfe2c)
📑 Service on 4c:ee:56:68:5b:1f: UUID(0x1804)
    ◦ Characteristic UUID: UUID(0x2a24)
    ◦ Characteristic UUID: UUID(0x2a29)
    ◦ Characteristic UUID: UUID(0x2a26)
    ◦ Characteristic UUID: UUID(0x2a00)
    ◦ Characteristic UUID: UUID(0x2a01)
    ◦ Characteristic UUID: UUID(0x2a04)
    ◦ Characteristic UUID: UUID(0x2a05)
    ◦ Characteristic UUID: UUID(0x2b29)
    ◦ Characteristic UUID: UUID(0x2b2a)
    ◦ Characteristic UUID: UUID('8e0c0001-1d68-fb92-bf61-48377421680e')
Device classified: Pebblebee
    ◦ Characteristic UUID: UUID('00002c07-0000-1000-8000-00805f9b34fb')
    ◦ Characteristic UUID: UUID('fe2c1233-8366-4814-8eb0-01de32100bea')
    ◦ Characteristic UUID: UUID('fe2c1234-8366-4814-8eb0-01de32100bea')
    ◦ Characteristic UUID: UUID('fe2c1235-8366-4814-8eb0-01de32100bea')
    ◦ Characteristic UUID: UUID('fe2c1236-8366-4814-8eb0-01de32100bea')
    ◦ Characteristic UUID: UUID('fe2c1238-8366-4814-8eb0-01de32100bea')
    ◦ Characteristic UUID: UUID(0x2a07)
🔌 Disconnected from 4c:ee:56:68:5b:1f

The information on trackers is also stored on the ESP32 in the file trackers.csv, which is used for evaluation later on.

Standalone - Web Interface

Besides running the detector for technically advanced users, there is the (main) possibility to use the web interface.
The interface itself is available at: https://gitlab.oth-regensburg.de/lal45210/tracker-detector-interface
In general, it requires a USB connection to the ESP32 for initialization and evaluation.
Similar mpremote commands are executed to start the detection mode, logging information to the file trackers.csv.
An external power source is necessary to the ESP32, for example a nano power bank.
It is also necessary to hide the ESP32 with the power source in a compatible device or place, for example a bag of menstruation products.

Detection Functionality

The ESP32 provides BLE communication, allowing to scan for devices and to classify them.
Due to a missing GPS module, functionality for following by a tracker is not implemented, resulting in only counting occurrences during specific time frames.
There is a scan for BLE devices every 10 minutes.
The last 4 hours are evaluated.
If a tracker has been seen at least 3 times during the last 4 hours with a time delta of at least 30 minutes, it is considered as a tracker following the detector and person using it.
An alarm is triggered by the output in the terminal as well as the LED on the ESP32.
It is recommended to evaluate the trackers.csv to gain additional insights.
False positives are possible, therefore, evaluation is necessary to get a context of detection.

Description
No description provided
Readme 50 KiB
Languages
Python 100%