Skip to content

About

Open AirTag-style BLE finder tag for Vicharak ShrikeFi (ESP32-S3): iBeacon + Find Me alert. Not Apple Find My.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ShrikeFi BLE Tag

An open, AirTag-style Bluetooth LE finder tag built on the Vicharak ShrikeFi (ESP32-S3 + Renesas ForgeFPGA).

Lose your bag, keys or bike? Clip a ShrikeFi to it. The board continuously advertises over Bluetooth Low Energy; your phone sees it, shows how strong the signal is ("hotter / colder") and can make the tag blink (and beep) so you can find it β€” just like the "Play Sound" / proximity part of an AirTag.

Important

This is not an Apple AirTag and it does not work with Apple's Find My app or network. It is a local BLE beacon: you can find it only when your own phone is within Bluetooth range (roughly 10–30 m indoors, more outdoors). There is no crowd-sourced, worldwide location. See Limitations.

Built for the Vicharak Fellowship 2026 challenge "can we make an AirTag using ShrikeFi?" β€” with complete documentation so anyone with a ShrikeFi can reproduce it.


Contents

Features

v0.1 (this release)
πŸ“‘ iBeacon advertising Your own 128-bit UUID + Major/Minor + calibrated 1 m power, readable by any beacon scanner app
πŸ”” "Find Me" alert Standard Bluetooth SIG Immediate Alert Service (0x1802) β€” write 1 (mild) or 2 (high) from a phone and the tag blinks fast / beeps; 0 stops it; auto-stops after 15 s
πŸ“± Works on Android and iPhone Tested flow with nRF Connect and LightBlue (free apps) β€” no custom app needed
πŸ’‘ Status LED (GPIO21) heartbeat blink = advertising Β· solid = phone connected Β· fast blink = alert
πŸ”Š Optional buzzer any 3.3 V active buzzer on a spare GPIO
πŸ’» Laptop finder tools/find_tag.py β€” live RSSI bar + distance estimate + alert trigger (Windows / Linux / macOS)
πŸ—ΊοΈ Last-seen map (phone) companion/ PWA β€” Web Bluetooth + phone GPS pins on a Leaflet map (Android Chrome; not Find My / no onboard GPS)
πŸ› οΈ Beginner-friendly build Arduino IDE or PlatformIO, one config file

Hardware

You need only: a ShrikeFi board and a USB-C data cable (charge-only cables will not flash). Full list in docs/BOM.md.

ShrikeFi feature Used for
ESP32-S3 (dual-core LX7, 240 MHz) runs the firmware
Bluetooth LE 5.0 radio (on-chip) beacon advertising + GATT alert service
MCU user LED β€” GPIO21, active high status / alert indicator
Dual USB-C (CH9102 USB-UART + native USB) power, flashing, serial log
Renesas SLG47910 ForgeFPGA not used in v0.1 β€” see Roadmap
Optional BMS / LiPo charger (DNP on base board) not required β€” power from USB-C or a power bank

Board docs: Hardware overview Β· Pinouts Β· Getting started

Quick start

Full step-by-step guide with screenshots-to-take and troubleshooting: docs/HOWTO.md.

Option A β€” Arduino IDE (easiest)

  1. Install Arduino IDE 2.x.
  2. File β†’ Preferences β†’ Additional boards manager URLs, add (same as Vicharak's guide):
    https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
    
  3. Tools β†’ Board β†’ Boards Manager β†’ install "esp32" by Espressif Systems (3.x).
  4. Open firmware/ShrikeFiBleTag/ShrikeFiBleTag.ino. Edit config.h (at least generate your own IBEACON_UUID).
  5. Tools menu:
    Setting Value
    Board ESP32S3 Dev Module (Vicharak's guide calls it "Generic ESP32-S3")
    Port the ShrikeFi's COM / tty port
    USB Mode Hardware CDC and JTAG
    USB CDC On Boot Disabled if plugged into the CH9102 USB-UART port Β· Enabled if plugged into the native ESP32-S3 USB port
    Flash Size 4MB (safe on every ShrikeFi; firmware is ~0.6 MB) β€” 8MB as in Vicharak's guide also works if your board has 8 MB
    Partition Scheme Default
    Upload Speed 460800 (drop to 115200 if uploads fail)
  6. Click Upload. First time only: if upload fails with "Failed to connect", hold BOOT while plugging in the cable (or hold BOOT, tap RESET, release BOOT), then upload again.
  7. Open Serial Monitor at 115200 and press RESET β€” you should see the tag's name, MAC, UUID; the blue LED blinks once a second.

Option B β€” PlatformIO (CLI or VS Code)

pip install platformio            # or install the PlatformIO IDE extension in VS Code
cd firmware
pio run -e shrikefi -t upload     # CH9102 USB-UART port
pio device monitor                # 115200 baud
# native USB port instead:  pio run -e shrikefi_native_usb -t upload

Find the tag with your phone

Install a free BLE scanner β€” nRF Connect for Mobile (Nordic Semiconductor; Android & iOS) or LightBlue (Punch Through; iOS & Android).

Android (tested target: OnePlus 11 5G) iPhone (tested target: iPhone 14 / 15)
Sees ShrikeFi-Tag by name βœ… βœ…
Live RSSI ("hotter / colder") βœ… nRF Connect RSSI + graph βœ… RSSI in device list / LightBlue signal view
Sees the iBeacon frame (UUID, Major, Minor) βœ… nRF Connect decodes it ❌ iOS hides iBeacon packets from Bluetooth apps by design (only Core Location beacon apps that know your UUID can range it)
Make the tag blink / beep βœ… connect β†’ Immediate Alert β†’ write 01/02 βœ… connect β†’ service 1802 β†’ Alert Level β†’ write 01/02
  1. Power the tag (USB-C to laptop or power bank). LED blinks once per second.
  2. Open the app β†’ Scan β†’ find ShrikeFi-Tag (use the name filter).
  3. Find by signal: walk around and watch RSSI. β‰ˆ βˆ’50 dBm = right next to you, βˆ’70 = same room, βˆ’90 = far / behind walls.
  4. Make it blink: tap Connect β†’ Immediate Alert service (0x1802) β†’ Alert Level (0x2A06) β†’ write 02 (high, fast blink) or 01 (mild) β†’ write 00 to stop.

Detailed per-app taps, Android permissions (Nearby devices / Location) and calibration: docs/HOWTO.md.

Last-seen map

A single-page companion under companion/ records where your phone was when it last saw the tag (Web Bluetooth + geolocation), and shows pins + a short trail on an offline-friendly Leaflet / OpenStreetMap map.

Not Apple Find My. The ShrikeFi has no GPS. Pins are phone-GPS β€œlast sightings” while you are in BLE range β€” not a crowd-sourced world map.

Best on Android Chrome (OnePlus and similar)
iPhone Safari usually lacks Web Bluetooth β€” keep using LightBlue / nRF Connect for find-me; the map companion is Android-primary
How to open GitHub Pages: geneticscrol.github.io/shrikefi-ble-tag/companion/ Β· or local python -m http.server + adb reverse β€” see companion/README.md
Usage Connect to tag β†’ auto pins while connected Β· Mark last seen for a manual pin Β· trail stored in the browser (localStorage)

Step-by-step, screenshots and limitations: docs/HOWTO.md Β§8.

Onboard GPS (roadmap) β€” NEO-M8N

A u-blox NEO-M8N GNSS module will be wired to the ShrikeFi over UART so the tag can store its own lat/lng outdoors (no phone required for the fix). Until that lands:

  • Location in the repo today is still phone last-seen via the companion (Web Bluetooth + phone GPS).
  • NEO-M8N is outdoor-oriented (needs sky view); indoor find-me stays BLE RSSI + Find Me alert.
  • Firmware will read NMEA / u-blox over UART; exact pins and power notes will land with the hardware hookup.

How it works

flowchart LR
    subgraph ShrikeFi["ShrikeFi (ESP32-S3)"]
        CFG[config.h<br/>name, UUID, major/minor] --> FW[Firmware loop]
        FW -->|every 1 s swap| A1[Frame 1: iBeacon<br/>non-connectable]
        FW -->|every 1 s swap| A2[Frame 2: Find Me<br/>connectable, name + 0x1802]
        GATT[GATT server<br/>Immediate Alert 0x1802<br/>Alert Level 0x2A06] --> FW
        FW --> LED[GPIO21 LED]
        FW -.optional.-> BZ[Active buzzer]
    end
    A1 -. BLE adv .-> AND[Android<br/>nRF Connect]
    A2 -. BLE adv .-> AND
    A2 -. BLE adv .-> IOS[iPhone<br/>LightBlue / nRF Connect]
    A2 -. BLE adv .-> PC[Laptop<br/>tools/find_tag.py]
    AND -- connect + write 01/02 --> GATT
    IOS -- connect + write 01/02 --> GATT
    PC -- connect + write 01/02 --> GATT
Loading
  1. Two advertising frames, alternated every second.
    • iBeacon frame (non-connectable): Apple's iBeacon manufacturer-data layout (4C 00 02 15 + UUID + Major + Minor + measured power). Beacon apps use it to identify your tag and estimate distance.
    • Find Me frame (connectable): flags + 16-bit service UUID 0x1802 + complete local name. This is the frame iPhones can see, and the one a phone connects to. Why two? iOS/macOS strip any advertisement containing iBeacon data from normal Bluetooth (CoreBluetooth) apps. Splitting them means every phone sees something.
  2. Distance from RSSI. Phones measure received signal strength (RSSI, dBm). With the 1 m reference (IBEACON_MEASURED_POWER, default βˆ’59 dBm) a rough distance is d β‰ˆ 10^((Pβ‚β‚˜ βˆ’ RSSI) / (10Β·n)), n β‰ˆ 2 (open air) … 3 (indoors). Treat it as warmer/colder, not metres.
  3. Find Me alert. The firmware hosts the Bluetooth SIG Immediate Alert Service. When a phone writes Alert Level 1/2, the LED (and optional buzzer) switch to a fast pattern for 15 s or until 0 is written. While a phone is connected the tag keeps advertising the iBeacon frame.
  4. Portable code. Builds on Arduino-ESP32 3.x (NimBLE host) and 2.0.x (Bluedroid); the few API differences are handled in the sketch.

Data flow, packet bytes and design decisions are explained in more depth in docs/HOWTO.md.

Configuration

Everything lives in firmware/ShrikeFiBleTag/config.h:

Setting Default Meaning
TAG_NAME ShrikeFi-Tag name shown in scanner apps (≀ 12 chars)
IBEACON_UUID example UUID replace with your own (uuidgen / python -c "import uuid;print(uuid.uuid4())")
IBEACON_MAJOR / IBEACON_MINOR 1 / 1 tell multiple tags apart
IBEACON_MEASURED_POWER βˆ’59 RSSI at 1 m, calibrate for better distance
ENABLE_IBEACON_FRAME / ENABLE_FINDME_FRAME 1 / 1 turn either frame off
FRAME_SWITCH_MS 1000 how long each frame is advertised
ADV_INTERVAL_MS 200 lower = faster RSSI updates, higher = less power
LED_PIN 21 ShrikeFi MCU LED
BUZZER_PIN βˆ’1 GPIO of an optional active buzzer
ALERT_DURATION_MS 15000 alert auto-stop

Limitations

Being honest about what this is (and isn't):

  • No Apple Find My / Google Find My Device network. Those networks rely on manufacturer-certified accessories (Apple MFi / Google's Find Hub spec), rotating cryptographic keys and millions of phones relaying encrypted locations. This project does none of that. Community reverse-engineering projects (e.g. OpenHaystack) exist, but they are unofficial, fragile, not first-class on ESP32-S3 and not used or claimed here.
  • Range-limited. You can only find the tag when your phone is within BLE range. The tag has no onboard GPS; the companion/ last-seen map uses your phone’s GPS when the tag is nearby (Android Chrome). There is still no crowd-sourced worldwide location.
  • RSSI is noisy. Bodies, walls, board orientation and the breadboard (the ShrikeFi antenna is sensitive to nearby metal β€” discussion) easily swing Β±5–10 dB.
  • iPhone can't see the iBeacon frame in LightBlue / nRF Connect (iOS policy). The Find Me frame works fine.
  • Privacy. The tag uses a fixed Bluetooth address and fixed UUID, so anyone with a scanner can recognise it. Real AirTags rotate identifiers and include anti-stalking alerts. Only attach this to your own belongings β€” never use it to track people.
  • Power. The base ShrikeFi has the battery charger/BMS not populated, and v0.1 does not use deep sleep, so expect power-bank/USB power rather than coin-cell life.
  • Trademarks. "AirTag", "iBeacon" and "Find My" are trademarks of Apple Inc. This project is not affiliated with or endorsed by Apple. The iBeacon packet layout is used here for hobby/educational interoperability.

Roadmap

  • FPGA status LED β€” drive the ForgeFPGA user LED (FPGA GPIO16) with a hardware pattern generator, triggered by the MCU over the FPGA–MCU link (shows why ShrikeFi instead of a bare ESP32).
  • Low-power mode β€” longer advertising interval + light sleep; measure current; LiPo via the optional BMS.
  • Link-loss / "left behind" alert (Bluetooth Link Loss Service 0x1803).
  • Last-seen map companion (PWA) β€” companion/ Web Bluetooth + phone GPS pins (Android Chrome) Β· Pages.
  • NEO-M8N onboard GPS β€” UART lat/lng outdoors; phone last-seen remains until then (see Onboard GPS).
  • Richer companion (Flutter / Capacitor) β€” UUID filter, hot/cold gauge, richer history UI.
  • Eddystone-UID frame option (Google's open beacon format).
  • Button on a GPIO to toggle beacon / pairing mode.

Repository layout

shrikefi-ble-tag/
β”œβ”€β”€ firmware/
β”‚   β”œβ”€β”€ platformio.ini                # PlatformIO envs (CH9102 port, native USB, core 2.x)
β”‚   └── ShrikeFiBleTag/
β”‚       β”œβ”€β”€ ShrikeFiBleTag.ino        # firmware (open this in Arduino IDE)
β”‚       └── config.h                  # ← your settings
β”œβ”€β”€ companion/                        # last-seen map PWA (Android Chrome)
β”‚   β”œβ”€β”€ index.html / app.js / styles.css
β”‚   β”œβ”€β”€ manifest.webmanifest / sw.js
β”‚   └── README.md                     # how to open on OnePlus
β”œβ”€β”€ tools/
β”‚   └── find_tag.py                   # laptop finder (Python + bleak)
β”œβ”€β”€ docs/
β”‚   β”œβ”€β”€ HOWTO.md                      # build, flash, phone test, calibration, troubleshooting
β”‚   β”œβ”€β”€ BOM.md                        # bill of materials
β”‚   β”œβ”€β”€ screenshots/                  # privacy-scrubbed nRF + companion captures
β”‚   └── images/                       # photos & screenshots for docs/blog
└── LICENSE                           # MIT

Credits and license

Released under the MIT License.

About

Open AirTag-style BLE finder tag for Vicharak ShrikeFi (ESP32-S3): iBeacon + Find Me alert. Not Apple Find My.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages