Skip to content

About

Flipper Zero + Android RF triangulator: live Sub-GHz RSSI over USB/BLE, Nelder-Mead transmitter localization, CC1101 band scan, offline spectrum lookup

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

9 stars

Watchers

1 watching

Forks

Repository files navigation

Mhz_Localiser

License: MIT CI Platform: Flipper Zero Android 8.0+ Link: USB · BLE Spectrum DB: offline Rolling scan: 2-pass, 300–928 MHz CC1101 bands Status: beta

RF signal triangulation + spectrum allocation lookup — Flipper Zero streams live RSSI over USB or Bluetooth LE to an Android app that logs GPS + signal, estimates the transmitter location on a map, and lets you look up the regulatory allocation (USA, ITU, EU per country) of any frequency you observe.

Contents: How it works · What's new in v3.0 · What's new in v2.2 · What's new in v2.1 · Operational workflow · Field validation · Physical limitations · vs. real RF gear · Use cases · Quick start · Allocation list · Roll Scan · Build from source · Data protocol

ChatGPT Image 16 mai 2026 à 03_50_03

Honest disclaimer: This is a low-cost, mobile RSSI-based approach. It gives approximate results, not GPS-grade precision. Read the Physical Limitations section before drawing conclusions from the output.

Mhz_Localiser/
├── artifacts/              ← Ready-to-flash binaries
│   ├── rf_logger.fap       Copy to /ext/apps/Sub-GHz/ on the Flipper SD card
│   └── RF_Triangulator.apk Sideload or `adb install -r`
│
├── flipper/                ← Flipper Zero FAP source (build with ufbt)
│   ├── rf_logger.c         Digit editor + DB browser + 2-pass rolling scan (v3.0)
│   ├── application.fam     ufbt manifest
│   └── rf_logger_icon.png
│
├── android/                ← Capacitor sources for the Android app
│   ├── www/
│   │   ├── index.html      Triangulator + Allocation List + Roll Scan tabs
│   │   ├── app.js          map / capture / Nelder-Mead + allocation + roll scan
│   │   ├── styles.css      mobile-first dark theme
│   │   └── spectrum.csv    2 967 spectrum allocations — USA/EU/ITU/CH (offline)
│   └── plugin/
│       ├── FlipperSerialPlugin.java   Native USB-CDC bridge
│       └── FlipperBlePlugin.java      Native Bluetooth-LE bridge (GATT serial)
│
├── spectrum_scraper/       ← Python tooling that builds spectrum.csv
│   ├── enrich_spectrum.py  baseline → long-form CSV (EFIS optional)
│   ├── launcher.py         interactive CLI: list / lookup by MHz
│   ├── data/               baseline CSVs (USA, ITU, EU per country)
│   └── output/             generated long-form CSV
│
├── README.md               this file
├── SETUP.md                build and install instructions
└── LICENSE                 MIT

What's new in v3.0

Change Detail
Rolling scan rewritten — two passes, CC1101 bands only Pass 1 (coarse): 300–348 / 387–464 / 779–928 MHz, 600 kHz steps under a 650 kHz RX filter (no blind gap between steps), 100 ms peak-hold dwell. Pass 2 (fine): 58 kHz filter, 20 kHz steps, ±300 kHz around each detection → centre frequency + occupied width. Coarse pass ≈ 48 s computed (461 × ~103 ms) + ~1.3 s per hit for the fine pass, instead of > 20 min — not yet timed on hardware.
No chip reset per step The CC1101 is reset and the preset loaded once per pass; each step is idle → frequency + calibration → RX, exactly like the stock Frequency Analyzer.
Adaptive threshold A hit must clear max(−93 dBm, band noise floor + 10 dB); the floor is the median of the coarse pass, per band. Peak-hold instead of average, so short OOK bursts are no longer diluted into the noise.
Results screen on the Flipper After the scan, a list of hits (fine centre, peak dBm). OK jumps straight into continuous RSSI on that frequency for triangulation.
Crash guard set_frequency_and_path() calls furi_crash() when the quantized frequency leaves its window — this happens for requests exactly on the firmware's lower bounds (299 999 755 / 386 999 938 / 778 999 847 Hz). Every tune is now checked against the quantization first.
Robust USB stream CDC writes are chunked to 64-byte packets with TX-complete flow control (the STM32 endpoint writer does not clamp longer writes and drops writes while busy).
Protocol v3 (backward compatible) ROLL lines keep their first 7 columns and add pass,floor_dbm,width_hz,cluster,seq; progress/end events go on # RF_LOGGER_RSCAN lines, which older APKs ignore.
Android Roll Scan tab Pass-aware progress, fine result replaces the coarse estimate, lost-line counter from seq, Peak/Width columns, and the Tune button works again (it referenced variables outside its scope).
Fixes SD flag no longer stays on after a stop; rolling-scan SD files get the rolling header; Back from a rolling scan closes the SD file; DB entries the CC1101 cannot tune (169.40, 380.5, 466.025 MHz) removed; manual screen flags out-of-band values.
Field-validated Tested on hardware on 4 Oct 2026: full two-pass scan, 20 hits streamed to the phone over the live link — see the Roll Scan screenshot.
Tests make -C flipper/tests (host unit tests, ASan/UBSan) and a jsdom test of the Roll Scan tab, both in CI.

What's new in v2.2

Change Detail
Frequency DB browser Press → on the last digit of the manual screen to open a built-in list of 35 pre-loaded frequencies: ISM/SRD bands, LoRa, TPMS/RKE, PMR446, aviation, Polycom, GSM-R, radiosonde. Select an entry → loaded directly into the manual screen.
Switzerland (CH) section Dedicated CH/OFCOM entries in the DB: Polycom TETRAPOL 380/390 MHz, GSM-R SBB 877/922 MHz, BAKOM SRD 433/868/869 MHz, and more.
Rolling spectrum scan Select ▶ START ROLL SCAN at the top of the DB list to sweep 300–928 MHz in 1 MHz steps, 2 s dwell per step (extended to 3 s for medium signals). Signals are classified SKIP (< −100 dBm) / MED (−100 to −80 dBm) / STRONG (> −80 dBm) and streamed as ROLL,… lines.
Roll Scan APK tab Third tab in the Android app receives the rolling scan stream and displays a sortable table of all detected frequencies with Avg RSSI, Min RSSI, sample count, and signal class. One tap on Tune loads any frequency directly into the Triangulator.
spectrum.csv +487 rows 2,480 → 2,967 entries. Added 59 CH/OFCOM entries (Armée Suisse, Polycom TETRAPOL, GSM-R SBB, ADS-B, DME Skyguide, GNSS, bandes militaires).

What's new in v2.1

Change Detail
Bluetooth LE streaming The Flipper now streams the same CSV over both USB and BLE simultaneously. Go fully wireless — no cable between Flipper and phone.
Dual transport picker Choose USB or Bluetooth in the drawer; the solver, map, and allocation lookup are identical on either.
BLE device picker Scans for the Flipper by serial-service UUID and by name; custom-named units (no "Flipper" prefix) are listed and the chosen device is remembered for one-tap reconnect.
Robust BLE connect Forces the LE transport, self-heals advertising, refreshes Android's stale GATT cache, and binds the correct data characteristic (INDICATE) — so it survives re-pairs and firmware re-flashes.
On-device BT status The Flipper running screen shows BT:off / BT:adv / BT:ok so you can see the link state at a glance.
RSSI smoothing Exponential moving-average filter on the live stream damps single-sample multipath spikes before capture.
Selectable environment / path-loss n Pick open-field / suburban / urban / dense / indoor (or a custom n) in the drawer — the single biggest lever on accuracy.
Automatic outlier rejection Leave-one-out residual check flags and excludes likely-multipath captures before the final solve.
Live capture-geometry hint Warns when captures are too collinear (ambiguous fix) so you spread out for better geometry.
Session persistence Captures + settings survive an app restart (stored locally), so a field session isn't lost.

What's new in v2

Change Detail
Manual frequency only Preset menu (315 / 433 / 868 / 915 MHz) removed. App opens directly on the digit editor at launch.
Faster startup No menu navigation — enter frequency and press OK immediately.
Smaller FAP 8.5 KB → 7.5 KB (preset table and menu renderer eliminated).
Auto-reconnect Android plugin reconnects automatically every 2 s if USB is lost — no need to tap Connect again.
Synced allocation panel Panel 2 driven entirely by the live Flipper stream — no offline frequency input required.
Compact allocation view Single dense table: MHz → Country → Region → Service → Status → Application → Source. No tab-swap needed.
Location permissions Fine + Coarse GPS permissions wired up at runtime on first launch.

How it works

  • Flipper Zero runs rf_logger.fap — a Sub-GHz RSSI logger that continuously samples signal strength on a chosen frequency and streams readings as CSV over USB CDC and Bluetooth LE at the same time.
  • Android app (RF_Triangulator.apk) connects to the Flipper over USB-C or Bluetooth LE (your choice), reads the live RSSI stream, and logs GPS + signal captures on a map.
  • With 3 or more captures from different positions, the app runs a Nelder-Mead least-squares solver to estimate the transmitter location.
layout-collage-1779109255380 1000722535 list

RF Architecture

┌─────────────────────────────────────────────────────────────────┐
│                        Flipper Zero                             │
│                                                                 │
│   CC1101 chip  ──►  RSSI register  ──►  rf_logger.fap          │
│   (Sub-GHz)        sampled @ 5 Hz      (FAP app)               │
└──────────────┬───────────────────────────────┬─────────────────┘
               │  USB CDC-ACM (ch1)             │  BLE GATT serial
               │  115200 baud, dual CDC         │  service 0xfe60,
               │                                │  TX char indicate
               │  CSV: ts_ms, req_hz, act_hz, rssi_dbm, rssi_raw, lqi, n
               ▼                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                      Android App                                │
│                                                                 │
│  FlipperSerialPlugin  ─┐                                        │
│  FlipperBlePlugin    ─┴►  transport picker (USB / BLE)          │
│  (native Java)            parses CSV stream, auto-reconnect     │
│                                                                 │
│  Geolocation API      ──►  GPS coordinates                      │
│                                                                 │
│  Capture engine       ──►  {lat, lon, rssi, freq}  x N         │
│                                                                 │
│  Log-distance model   ──►  RSSI → estimated distance           │
│                                                                 │
│  Nelder-Mead solver   ──►  trilateration estimate              │
│  (non-linear LSQ)          + RMS residual error                │
│                                                                 │
│  Leaflet map          ──►  circles + estimated TX marker       │
└─────────────────────────────────────────────────────────────────┘

The CC1101 chip inside the Flipper Zero is a general-purpose Sub-GHz transceiver. Its RSSI register is read at 5 Hz and converted to dBm using the standard formula. The Android app receives this as a raw telemetry stream — it is a mobile RF telemetry pipeline, not a direction-finding antenna system.

Flipper app flow (v2.2)

Launch
  └─► Manual frequency entry screen (default: 433.92 MHz)
        Up/Down    — increment/decrement active digit
        Left/Right — move cursor across XXX.XX MHz display
        Right (at last digit) — open Frequency DB list
        OK         — validate & start RSSI streaming
        Back       — exit app

Frequency DB list
  └─► Scrollable list of 32 pre-loaded frequencies + CH section
        Up/Down — scroll
        OK      — load selected frequency into manual screen
        Top entry (▶ START ROLL SCAN) → starts rolling scan
        Back    — return to manual screen

Running state (manual frequency)
  └─► Live RSSI streamed over USB + BLE CSV to Android
        Status line shows BT:off / BT:adv / BT:ok
        OK   — toggle SD card logging on/off
        Back — return to frequency entry screen

Rolling scan (300–348 / 387–464 / 779–928 MHz, ≈ 50 s computed)
  └─► Pass 1/2 coarse: 600 kHz steps, 650 kHz filter, 100 ms peak-hold
        Per-band noise floor (median) → threshold max(−93, floor + 10) dBm
        Adjacent hits merged into clusters (max 16, strongest kept)
      Pass 2/2 fine: 58 kHz filter, 20 kHz steps, ±300 kHz per cluster
        → centre frequency (power-weighted) + −6 dB width
        Emits ROLL,… lines + # RF_LOGGER_RSCAN progress/end to USB + BLE
        OK   — toggle SD logging      Back — stop scan

Scan results
  └─► Hits list (centre MHz, peak dBm, F=fine / C=coarse, S/M)
        OK   — start continuous RSSI on the selected hit
        Back — return to frequency entry screen

Bluetooth note: enable Settings → Bluetooth on the Flipper so the app can advertise. Keep the official Flipper mobile app closed while connected here — only one BLE central can hold the link at a time.

Operational Workflow

Most people imagine: "point the Flipper, app finds the source instantly." The reality is mobile statistical inference. Here is the actual workflow:

1. ENTER FREQUENCY
   └─ Dial the target frequency digit by digit on the Flipper
      (300–928 MHz range, 10 kHz resolution)

2. VERIFY SIGNAL
   └─ Confirm RSSI is above noise floor (> -100 dBm)
      before moving — if signal is too weak, get closer first

3. MOVE AROUND THE AREA
   └─ Walk to 3–6 positions that SURROUND the suspected source
      Positions in a straight line = ambiguous fix
      Spread of 90°+ between capture points = best geometry

4. CAPTURE GPS + RSSI AT EACH POSITION
   └─ Tap "Capture here" or enable Auto-capture
      Each capture = {lat, lon, rssi_dBm, freq_Hz}

5. SOLVER RUNS AUTOMATICALLY
   └─ Nelder-Mead minimises sum of squared residuals
      across all distance circles
      Output: estimated lat/lon + RMS error in metres

6. INTERPRET THE ESTIMATE
   └─ Low RMS (<30 m)  = circles agree well, high confidence
      High RMS (>100 m) = noisy environment or bad geometry
      Re-capture from better positions if RMS is high

Field Validation

Tests conducted with a 433.92 MHz transmitter (generic keyfob, ~10 dBm output), Flipper Zero hardware, and a Pixel 7 with GPS lock (accuracy ±5–8 m).

Environment Captures Real distance Estimated distance RMS error Notes
Open field 5 120 m 133 m 13 m Clean line-of-sight, flat terrain
Open field 4 80 m 91 m 22 m Light wind, same conditions
Suburban street 5 65 m 88 m 38 m Parked cars, low buildings
Dense urban 6 80 m 210 m 130 m Multi-storey buildings, reflections
Dense urban 5 50 m 145 m 95 m Corner geometry, NLOS
Indoor (office) 4 30 m unstable — Walls, furniture, multipath — unusable
Indoor (warehouse) 5 40 m 67 m 51 m Large open space, concrete walls

Key takeaways:

  • Open field with good capture geometry: error under 25 m consistently.
  • Suburban environments: 30–60 m error is realistic.
  • Dense urban or indoor: results degrade sharply. Use as a search area, not a precise fix.
  • Captures in a straight line (bad geometry) inflated RMS by 3–4× vs. well-spread captures.

Physical Limitations

RSSI ≠ distance

The log-distance path loss model used here is:

d = d₀ · 10^( (PL(d) − PL(d₀)) / (10 · n) )

where:
  d₀ = 1 m (reference distance)
  n  = path-loss exponent (3.0 default — urban/cluttered)
  PL = path loss in dB = Tx_power − RSSI

This model assumes that signal decays smoothly and predictably with distance. In practice:

Assumption Reality
Free propagation Reflections from buildings, vehicles, ground
Single path Multipath — multiple copies of signal arrive with different phases
Static environment People walking, doors opening change RSSI by 5–15 dB
Isotropic antenna Flipper's PCB antenna has directional variation
Known Tx power Actual output may differ from nominal

Multipath is the primary failure mode. In urban environments, a signal reflected off a building wall can arrive stronger than the direct path, making the solver place the estimated source in completely the wrong direction. This is why the dense urban results above show 130 m error for an 80 m actual distance.

The path-loss exponent n is the biggest tuning knob:

  • n = 2.0 — free space, vacuum or very open field
  • n = 2.7–3.5 — typical outdoor urban
  • n = 3.5–5.0 — indoor, heavy obstruction

Wrong n = systematically biased distance estimates = bad triangulation even with good geometry.

What this tool cannot do

  • ❌ Real-time tracking of a moving transmitter
  • ❌ Sub-10 m precision in any environment
  • ❌ Direction finding (it has no antenna array)
  • ❌ Work reliably indoors without tuning n per-room
  • ❌ Replace dedicated DF equipment for serious applications

Comparison with Real RF Equipment

Solution Method Typical accuracy Cost
Mhz_Localiser (this project) RSSI trilateration, mobile 15–150 m depending on env. ~$60 (Flipper + phone)
KrakenSDR 5-element coherent SDR phase array 2–10 m outdoors ~$500
HackRF + directional antenna Manual DF, SDR 5–20 m with skill ~$350 + antenna
RTL-SDR + Doppler DF Software Doppler shift 10–30 m ~$30 + antenna
Professional TDOA systems Time-difference of arrival <1 m $5,000–$50,000

Mhz_Localiser is the lowest cost and lowest barrier option. It trades precision for accessibility — the entire system fits in a pocket and requires no RF expertise to operate. For hobbyist fox-hunting, lost-sensor searches, or educational RF experiments, the 15–50 m accuracy in open environments is genuinely useful.

Realistic Use Cases

Good fits ✓

  • Lost LoRa sensor or tracker — device is stationary, open outdoor environment, you just need to narrow a search area to ~50 m
  • RF interference source hunt — approximate location of a jammer or misbehaving device in a building or parking lot
  • Keyfob / garage door transmitter — short range, open space, works well
  • Educational RF experiments — understanding path loss, multipath, trilateration geometry
  • Sub-GHz survey — mapping signal coverage of a fixed transmitter across a site
  • Amateur radio fox-hunting — recreational hidden transmitter hunt

Poor fits ✗

  • Precise tracking — 15 m minimum error even in ideal conditions
  • Indoor room-level localisation — multipath makes results unreliable
  • Moving transmitter — solver assumes static source
  • Surveillance or legal evidence — far too imprecise and unvalidated for any serious application
  • Dense urban precision — error easily exceeds 100 m

Quick Start

Step 1 — Install the Flipper app

Copy artifacts/rf_logger.fap to your Flipper SD card:

/ext/apps/Sub-GHz/rf_logger.fap

On the Flipper: Apps → Sub-GHz → RF Logger

  • App opens directly on the manual frequency entry screen (433.92 MHz default).
  • ↑/↓ change the active digit · ←/→ move the cursor across XXX.XX MHz · OK starts the scan · Back exits.
  • Range clamped to 300–928 MHz (CC1101 Sub-GHz hardware limit).
  • In running mode: OK toggles SD card logging on/off · Back returns to frequency entry.

Step 2 — Install the Android app

Enable Install unknown apps in Android settings, or use ADB:

adb install artifacts/RF_Triangulator.apk

Grant Location permission when prompted (required for GPS capture).

Step 3 — Connect and capture

Open RF Triangulator → tap ☰ and pick your transport:

USB (wired)

  1. Plug the Flipper into your Android phone with a USB-C cable.
  2. Transport USB → Connect Flipper → accept the USB permission dialog. Auto-reconnects if USB drops.

Bluetooth (wireless)

  1. On the Flipper: Settings → Bluetooth ON, then launch RF Logger (status shows BT:adv).
  2. Transport Bluetooth (BLE) → Connect Flipper → pick your Flipper from the list → accept pairing on both devices. Its address is remembered for one-tap reconnect next time.

Then, on either transport:

  1. The top panel mirrors the Flipper: frequency, RSSI, signal bar.
  2. Walk to a position and tap Capture here — the app logs GPS + live RSSI.
  3. Repeat from 3+ different positions surrounding the suspected transmitter.
  4. The drawer shows the triangulation estimate with RMS error once you have 3+ captures. Tune the environment / path-loss n there for your surroundings.

Auto-capture mode

Tap Auto-capture to log readings automatically at a set interval (1 s / 2 s / 5 s / 10 s) while you walk around. Tap Stop Auto to end.

Import Flipper files

Tap ☰ → Load .sub / .log to import files captured directly on the Flipper SD card. Supports .sub, .log, .csv, .txt with RSSI: and Latitude/Longitude: fields.

Export

  • CSV — one row per capture: id, lat, lon, rssi_dbm, freq_hz, source
  • JSON — full capture list + triangulation estimate

Allocation List

A second tab in the Android app lets you look up the regulatory allocation of any frequency without leaving the app — driven live from the Flipper stream, no manual input needed.

Each result shows: band · country · region · service (FIXED / MOBILE / AMATEUR / SRD ISM / BROADCASTING / …) · status (PRIMARY / Secondary) · application (LoRa, GSM 900, Wi-Fi 2.4 GHz, TETRA, NFC, …) · source (FCC 47 CFR 2.106, ITU RR, ARCEP, BNetzA, Ofcom, CNAF, ECC/DEC, ERC/REC 70-03, …).

Data is bundled into the APK as spectrum.csv — 2,967 rows covering ITU R1/R2/R3, USA federal + non-federal, per-country EU allocations, and 59 Swiss (CH/OFCOM) entries including Armée Suisse military bands, Polycom TETRAPOL, GSM-R SBB, ADS-B, DME, and GNSS. Fully offline, no network required.

Roll Scan

The third tab (Roll Scan) receives the rolling sweep stream from the Flipper and builds a map of everything active in the three CC1101 bands (300–348, 387–464, 779–928 MHz).

Roll Scan tab during a v3 two-pass scan: 20 hits, STRONG/MED classification, Tune buttons

Field test, 4 Oct 2026: rf_logger.fap 3.0 streaming into the Roll Scan tab — 20 hits, coarse lines (100–300 samples) and fine-pass lines (600–1800 samples). This capture comes from the previous APK (v2.2 column headers Min RSSI / Samples), which shows the v3 stream is backward compatible; the rebuilt APK shows Peak RSSI / Width, the ·F/·C pass tag and the end-of-scan summary.

Column Description
Freq (MHz) Fine centre frequency (·F) or, until the fine pass reaches it, the strongest coarse step (·C)
Avg RSSI Mean dBm over the dwell at that frequency
Peak RSSI Strongest sample (peak-hold)
Width Occupied width: −6 dB width from the fine pass, or the cluster span from the coarse pass
Signal STRONG (peak ≥ −80 dBm) / MED (detected, below −80 dBm)
Action Tune — sets the frequency as Triangulator target

The status line shows the pass in progress, then the hit count, scan time, per-band noise floor and any lines lost in transit (from the seq column). Use MED+ / All / STRONG only to filter; results are sorted by peak, strongest first. Older firmware (v2.x stream) is still accepted.

Build from Source

Flipper FAP (ufbt — recommended)

pip install ufbt
cd flipper/
ufbt build
# Output: ~/.ufbt/build/rf_logger.fap

# Deploy directly to connected Flipper
ufbt launch

Flipper FAP (fbt — full firmware repo)

cp -r flipper/ flipper-firmware/applications_user/rf_logger
cd flipper-firmware
./fbt fap_rf_logger

Android APK

Requires Android Studio, Java 17+, Node.js 18+.

cd android/
npm install
npx cap sync android
cd android
./gradlew assembleDebug
# Output: app/build/outputs/apk/debug/app-debug.apk

Stack: Capacitor · usb-serial-for-android (CDC-ACM) · Android BLE (BluetoothGatt, GATT serial) · Leaflet (OpenStreetMap)

Both native bridges (FlipperSerialPlugin.java, FlipperBlePlugin.java) must be registered in MainActivity and expose the same connect/disconnect/data/status interface, so the web UI treats USB and BLE as interchangeable.

Data Protocol (USB + BLE)

Flipper streams over USB CDC-ACM channel 1 at 115200 baud and over Bluetooth LE (GATT serial service 0000fe60-…, TX characteristic 0000fe61-… via indications). The Android side parses both identically.

Normal RSSI stream

# RF_LOGGER_DBG req=433920000 act=433920000
ts_ms,req_hz,act_hz,rssi_dbm,rssi_raw,lqi,n
1234567,433920000,433920000,-85,0x57,12,1
1234767,433920000,433920000,-83,0x59,14,2
Column Type Description
ts_ms uint64 Uptime milliseconds
req_hz uint32 Requested frequency Hz
act_hz uint32 Actual tuned frequency Hz
rssi_dbm int Signal strength dBm
rssi_raw hex Raw CC1101 RSSI register byte
lqi uint8 Link Quality Indicator
n uint32 Sample counter

Sample rate: 200 ms (5 Hz). The Android app auto-detects frequency from req_hz.

Rolling scan stream (v3)

# RF_LOGGER_ROLL v=3 bands=300000000-348000000,387000000-464000000,779000000-928000000 step=600000 bw=650000 dwell_ms=100 fine_step=20000 fine_bw=58000 fine_span=300000 fine_dwell_ms=40 points=461
ROLL,ts_ms,freq_hz,rssi_avg,rssi_peak,samples,flag,pass,floor_dbm,width_hz,cluster,seq
# RF_LOGGER_RSCAN pos pass=C idx=16 total=461 hz=309000000
…
# RF_LOGGER_RSCAN floor b0=-104 b1=-100 b2=-98 thr0=-93 thr1=-90 thr2=-88
ROLL,51234,433800000,-70,-60,97,STRONG,C,-100,600000,0,0
# RF_LOGGER_RSCAN pos pass=F idx=0 total=1 hz=433800000
ROLL,52610,433921000,-66,-58,1180,STRONG,F,-100,40000,0,1
# RF_LOGGER_RSCAN end status=ok clusters=1 coarse_ms=48210 total_ms=49640 tune_err=0 usb_drops=0
Column Type Description
ts_ms uint32 Uptime ms when the line was emitted
freq_hz uint32 C: strongest coarse step · F: power-weighted centre of the −3 dB lobe
rssi_avg int Mean dBm over the dwell at freq_hz
rssi_peak int Peak-hold dBm (was named rssi_min in v2, same meaning: strongest sample)
samples uint32 RSSI samples behind this line
flag string STRONG (peak ≥ −80 dBm) / MED
pass char C coarse / F fine
floor_dbm int Median noise floor of the band (coarse pass)
width_hz uint32 C: cluster span · F: −6 dB width
cluster uint Cluster id; the F line supersedes the C line with the same id
seq uint32 Line sequence number — a gap means a lost line

Event lines start with # RF_LOGGER_RSCAN followed by pos, floor, end, err or warn and key=value pairs. They do not start with # RF_LOGGER_ROLL, so v2 APKs ignore them; v2 APKs also ignore the extra ROLL columns. BLE packet reassembly is newline-based, so framing is transport-independent.

Security

  • No API keys, tokens, or credentials in this codebase.
  • No hardcoded IP addresses — all communication is local (USB or Bluetooth LE), device-to-phone only.
  • USB permission via standard Android intent (UsbManager.requestPermission); Bluetooth via runtime BLUETOOTH_SCAN/BLUETOOTH_CONNECT permissions (scan flagged neverForLocation).
  • Location permission requested at runtime only (for GPS capture).
  • No outbound network requests from the app (map tiles load from OpenStreetMap via WebView only).

Requirements

Component Requirement
Flipper Zero Firmware 0.97+ (official or Unleashed); Bluetooth ON for wireless mode
Android 8.0+ (API 26); USB OTG or Bluetooth LE
Connection USB-C cable (USB-A OTG adapter), or Bluetooth LE — no cable needed
GPS Required for capture; indoor = poor accuracy

License

MIT — see LICENSE.

About

Flipper Zero + Android RF triangulator: live Sub-GHz RSSI over USB/BLE, Nelder-Mead transmitter localization, CC1101 band scan, offline spectrum lookup

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

9 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages