Command line interface
Connect to the device with a USB cable, and open it in your favorite serial terminal. Your terminal needs to be VT102 compatible for the colors to work.
- Hardware - not much to interesting; just shows the ESP32-S3 information
- GPS - shows current lock status, long/lat coordinates, GPS time, and number of satellites. If the GPS is not receiving good data, the display will be "NO GPS LOCK"
- Filesystem - shows used/free space
- Memories - shows free heap space for both internal and external RAM
- Wall clock - synced to GPS, shows current date/time and offset as well as timezone.
Configuration
Device configuration is performed using the `config` command:
- Device name - saved in the `survey` data
- Timezone - local timezone. GPS time is GMT, this is used to translate to local time
- MAX LED brightness - a value from 0 to 255. 255 is unnecessarily bright - if the device is used in a vehicle after dark, a value of 255 will definitely cause issues with night vision. Values below 10 are barely visible
- Debug logging - enabling this will cause the device to log most actions to a plain text file in the filesystem
- Scan logging - enabling this will cause the device to save real-time scan information to a file in the filesystem
- Debug file count - if debug logging is enabled, a new file is created each time the device is powered up or resets. The previous files will be "rolled". The "current" file is named `system.log`. On reset or power up, the existing system.log file will be renamed system.1.log; existing system.1.log will be renamed system.2.log, etc., up to this count.
- Scan file count - works the same as debug file rolling. Scan files are named `autoscan.log`, `autoscan.1.log`, etc.
- Minimum RSSI - minimum signal level (both WiFi and Bluetooth) for a target to be detected.
- Minimum alert time - when in scan mode (either manually triggered or autoscan), this is the minimum amount of time that the LEDs will flash when a target was detected.
The configuration data is stored in `config.json`. If any changes are made, the "old" file will be saved as `config.bak`. Changes can be reverted by copying the backup over the current and restarting ("mv config.bak config.json", and then "reset")
If the `reset` command is issued with the `--factory`, the entire filesystem is formatted (all files deleted), and default config file built.
Scan
In `scan` mode, the device will continually monitor WiFi and Bluetooth signals, "looking" for packets that match preset criteria. When scanning, the RF LED on the device will glow a steady blue; if a matching device is nearby, the RF LED will alternate blue/purple flashing. The LED will flash as long as the matching device is present. (Minimum flash time is defined in the configuration, for a case when the matching device moves by quickly).
A scan can be started in one of two ways:
Automatic scan
When the device is powered up or reset, if no communication is seen on the serial interface in the first 5 seconds, a scan will automatically start. If scan logging is enabled, the files will roll according to the file count, and a new `autoscan.log` will be created.
Manual scan
A manual scan can be started with the `scan` command on the CLI. If the `-l <FILENAME>` parameter is passed, the scan will be saved to that filename; otherwise it will use `autoscan.log`
Stopping a scan
A manual or automatic scan is stopped when any key is pressed while connected to the serial interface.
Scan data
Example scan data. 3 devices (2 WiFi, 1 Bluetooth) matched scan criteria. One of them was seen only for about 29 seconds, then disappeared.
Currently, there are some default matching criteria hardcoded into the device; this will be more configurable in a future release.
Survey
A survey will do a single scan of all WiFi channels and Bluetooth to get an idea of the devices in the area. The command takes a few parameters:
In this example, a survey was started with each WiFi channel being scanned for 100ms. The scan found 10 WiFi devices and 8 BT. Since no file was specified, the raw JSON is output in the console:
Passing a filename with the `-f` parameter will save this (minified) JSON data in the filesystem. Currently, this device has a few saved surveys:
Survey data can be exported by the device and used to populate a Sqlite database using the included Python script:
The file `survey.sm11.json` was pulled form the device, parsed, then loaded into the sqlite3 file `example.db`. The database file did not exist, so extra data was loaded to initialize it - this data comes from yaml and json files in the project folder: Bluetooth serviceUUID, serviceDataUUID, and a recent MAC OUI file. This helps in later analysis.
If the database files existed, the status of the UUID and OUI data is checked and not reloaded if up to date. More survey files can be loaded into the database to generate more data to work with.
SQL Queries
The database can be queried using the `sqlite3` CLI command or a GUI.
The survey table contains the header information for all surveys in the database.:
select * from surveys;
| surveyInx | version | device | notes | dateTime | longitude | lattitude | satCount |
|---|---|---|---|---|---|---|---|
| 1 | 2 | Super Secret Sniffer | South Milwaukee 10th Marquette | 2026-02-09 13:14:22 | 42.90744 | -87.86145 | 11 |
| 2 | 2 | Super Secret Sniffer | South MKE Marquette Chicago | 2026-02-09 13:23:34 | 42.90746 | -87.86475 | 11 |
| 3 | 2 | Super Secret Sniffer | Hwy 32 near Elm | 2026-02-09 13:36:21 | 42.84986 | -87.85328 | 12 |
| 4 | 2 | Super Secret Sniffer | carwash | 2026-02-09 13:48:06 | 42.8873 | -87.91386 | 11 |
There are two tables for WiFi results, depending on the type of WiFi packet: wifi_data and wifi_management. They are similar, but the packet data is parsed a bit differently:
select * from wifi_data limit 10;
| wifiInx | surveyInx | subtype | sourceAddr | destAddr | rssi | channel |
|---|---|---|---|---|---|---|
| 1 | 1 | QoS Data | 24:0a:c4:50:5d:58 | 00:30:44:48:b8:14 | -82 | 11 |
| 2 | 1 | Data | 24:81:3b:6c:4f:c0 | 24:81:3b:6c:4f:c0 | -90 | 1 |
| 3 | 1 | Data | ac:8f:a9:37:a2:b4 | 01:80:c2:00:00:00 | -79 | 6 |
| 4 | 2 | ND CF-ACK + CF-Poll | 00:a0:84:8b:d6:9c | c5:3c:b0:e2:69:2d | -84 | 157 |
| 5 | 2 | ND CF-ACK + CF-Poll | 10:a0:84:8b:d6:9c | c5:3c:b0:e2:69:2d | -84 | 157 |
| 6 | 2 | ND CF-ACK + CF-Poll | 20:a0:84:8b:d6:9c | c5:3c:b0:e2:69:2d | -89 | 153 |
| 7 | 2 | ND CF-ACK + CF-Poll | 30:a0:84:8b:d6:9c | c5:3c:b0:e2:69:2d | -86 | 157 |
| 8 | 2 | ND CF-ACK + CF-Poll | 40:a0:84:8b:d6:9c | c5:3c:b0:e2:69:2d | -81 | 157 |
| 9 | 2 | ND CF-ACK + CF-Poll | 50:a0:84:8b:d6:9c | c5:3c:b0:e2:69:2d | -88 | 153 |
| 10 | 2 | ND CF-ACK + CF-Poll | 60:a0:84:8b:d6:9c | c5:3c:b0:e2:69:2d | -83 | 157 |
select * from wifi_management limit 10;
| wifiInx | surveyInx | subtype | ssid | bssid | rssi | channel |
|---|---|---|---|---|---|---|
| 1 | 1 | beacon | HPEE0633 | 00:25:b3:ee:06:33 | -73 | 10 |
| 2 | 1 | probe request | HPEF468B | 00:25:b3:ef:46:8b | -79 | 8 |
| 3 | 1 | beacon | TT-CRD2063 | 00:30:44:48:b8:14 | -75 | 11 |
| 4 | 1 | probe response | ahc01 | 00:42:68:be:1f:80 | -84 | 1 |
| 5 | 1 | beacon | ahc02 | 00:42:68:be:1f:81 | -83 | 1 |
| 6 | 1 | probe response | AHC_Guest | 00:42:68:be:1f:82 | -82 | 1 |
| 7 | 1 | probe request | SpectrumSetup-83 | 00:e0:4c:19:52:b0 | -88 | 7 |
| 8 | 1 | beacon | MySpectrumWiFib2-2G | 08:3e:5d:b7:da:b8 | -90 | 1 |
| 9 | 1 | beacon | SMC-31C011200916 | 10:98:c3:5d:07:93 | -79 | 5 |
| 10 | 1 | beacon | SpectrumSetup-D9 | 14:7d:05:4b:02:db | -75 | 11 |
For both of those tables, the surveyInx is a foreign key into the surveys table.
Bluetooth data is stored in several tables. The main bluetooth table contains devices, and there are separate tables for UUID data (using a foreign key back into the bluetooth table).
select * from btle limit 10:
| btInx | surveyInx | name | mac | rssi |
|---|---|---|---|---|
| 1 | 1 | 03:62:20:af:fd:41 | -42 | |
| 2 | 1 | 03:de:d7:aa:24:60 | -60 | |
| 3 | 1 | 0a:e1:7b:b0:34:72 | -80 | |
| 4 | 1 | 42:5d:b3:10:0c:a4 | -89 | |
| 5 | 1 | 5d:85:0d:d1:48:50 | -90 | |
| 6 | 1 | 5f:b0:bc:46:75:30 | -65 | |
| 7 | 1 | 6e:46:30:d9:cb:b4 | -86 | |
| 8 | 1 | 73:d7:24:05:98:11 | -87 | |
| 9 | 1 | Employee Enc. | b4:e3:f9:1f:72:f7 | -89 |
| 10 | 1 | Bank Manager | b4:e3:f9:1f:84:8a | -88 |
select * from uuid16 limit 10;
| uuidInx | btInx | uuid16 |
|---|---|---|
| 1 | 7 | 65,267 |
| 2 | 22 | 65,214 |
| 3 | 24 | 6,159 |
| 4 | 32 | 65,267 |
Joining tables for the bigger picture
The tables can be joined to get a better picture of what was seen in the survey. An example of this would be something like:
select distinct sta.subtype "station data subtype",
ap.ssid "AP SSID",
ap.bssid "AP BSSID",
sta.sourceAddr "station MAC",
sta.channel "CH",
s.notes "survey",
mv.vendorName "station vendor"
from wifi_data sta
join surveys s on s.surveyInx = sta.surveyInx
join wifi_management ap on ap.bssid = sta.destAddr and ap.surveyInx = sta.surveyInx
left join mac_vendor mv on mv.prefix like substr(sta.sourceAddr, 1, 8)
order by ap.bssid, sta.sourceAddr
limit 20;
| station data subtype | AP SSID | AP BSSID | station MAC | CH | survey | station vendor |
|---|---|---|---|---|---|---|
| ND (null no data) | TT-CRD2063 | 00:30:44:48:b8:14 | 24:0a:c4:50:5d:58 | 11 | day2 posn8 | Espressif Inc. |
| ND QoS | NETGEAR25 | 14:59:c0:c9:45:74 | 00:f6:20:79:f8:d2 | 8 | day2 posn 1 | Google, Inc. |
| ND (null no data) | SpectrumSetup-ED | 14:7d:05:67:6e:ef | 34:5f:45:cf:50:b8 | 11 | day2 posn 1 | Espressif Inc. |
| QoS Data | TMOBILE-6C38 | 18:60:41:49:6c:3a | 40:2a:34:84:70:56 | 3 | day2 posn5 | |
| ND (null no data) | SpectrumSetup-D01C | 2c:67:be:31:d0:20 | ba:3e:54:15:25:b3 | 10 | day2 posn4 | |
| QoS Data | sticky-fingers | 34:19:4d:bf:fc:94 | 38:83:9a:9f:ee:96 | 8 | day2 posn 1 | SHENZHEN RF-LINK TECHNOLOGY CO.,LTD. |
| QoS Data | Verizon_M73QVW | 4c:ab:f8:7c:cb:a8 | 2c:aa:8e:6b:30:d8 | 1 | day2 posn4 | Wyze Labs Inc |
| ND QoS | Lotus | 60:32:b1:a7:4f:02 | 64:9a:63:eb:e3:6f | 10 | day2 posn8 | Ring LLC |
| ND QoS | Lotus | 60:32:b1:a7:4f:02 | 90:48:6c:e1:c2:c7 | 10 | day2 posn8 | Ring LLC |
| ND (null no data) | pussy palace | 74:37:5f:56:84:ab | 3c:31:74:2a:56:15 | 11 | day2 posn5 | Google, Inc. |
| ND QoS | pussy palace | 74:37:5f:56:84:ab | 50:14:79:a3:74:95 | 12 | day2 posn 1 | iRobot Corporation |
| QoS Data | pussy palace | 74:37:5f:56:84:ab | 50:14:79:a3:74:95 | 11 | day2 posn5 | iRobot Corporation |
| QoS Data | Tonrol7 | 78:6a:1f:6c:c0:04 | 08:12:a5:bc:30:2a | 6 | day2 posn 1 | Amazon Technologies Inc. |
| QoS Data | SpectrumSetup-913B | a0:55:1f:09:91:41 | 18:ef:3a:c7:a7:ab | 7 | day2 posn4 | Sichuan AI-Link Technology Co., Ltd. |
| QoS Data | SpectrumSetup-913B | a0:55:1f:09:91:41 | 18:ef:3a:c7:a7:ab | 5 | day2 posn5 | Sichuan AI-Link Technology Co., Ltd. |
| QoS Data | SpectrumSetup-913B | a0:55:1f:09:91:41 | 18:ef:3a:c7:a7:ab | 6 | day2 posn 7 | Sichuan AI-Link Technology Co., Ltd. |
| ND (null no data) | YKLhome | c4:41:1e:ea:74:1e | 44:87:63:b3:ff:d0 | 10 | day2 posn 7 | FN-LINK TECHNOLOGY Ltd. |
Comments
Post a Comment