Interactive desktop tool to monitor external TPMS sensors via Bluetooth Low Energy.
- Interactive UI - Menu-driven interface for discovering and monitoring sensors
- Auto-Detection - Automatically identifies TPMS sensors from all nearby BLE devices
- Multi-Sensor - Track 4+ sensors simultaneously with friendly names
- Modular Decoders - Plugin system supports different TPMS sensor types
- Dual Units - Pressure displayed in both BAR and PSI
- HEX Packet View - Raw BLE packet data for debugging
- Color-Coded Display - Status indicators at a glance
- Saved Configuration - Remembers your sensors between sessions
- Packet Log - Every TPMS-decodable packet is appended to
packet_log.jsonl(timestamp, raw hex, decoded fields) during discovery and monitoring - the long-term dataset behind the protocol reverse-engineering in PROTOCOL.md
| Decoder | Sensor Type | Data Size | Identification | Status |
|---|---|---|---|---|
| TPMS3-16byte | Generic BLE TPMS (VSTM/ZEEPIN/TP630) | 16 bytes | Name TPMS{N}_*, CID 0x0100 |
Tested (incl. rapid-drop alarm) |
| LyTPMS-15byte | Nameless "5BC45B"-type (CID 0x00AC) | 15 bytes | MAC-in-payload match, structure, UUID 0xFBB0 | Tested (2 units, pressure calibrated) |
| BR-7byte | Generic "BR" sensors | 7 bytes | Name "BR", UUID 0x27a5 | Reference |
| SYTPMS-6byte | SYTPMS sensors | 6 bytes | Name "TPMS", 6-byte data | Reference |
| Generic | Unknown sensors | 4+ bytes | Fallback with heuristics | Always |
Tested with: Generic external BLE TPMS cap sensors (VSTM/Visture, ZEEPIN/TP630, WISTEK, and other rebranded variants widely sold on AliExpress/Amazon)
New sensor types can be added via the modular decoder system. See DECODER_GUIDE.md.
# One-time setup (creates virtual environment, installs dependencies)
./setup.sh
# Run the monitor
./run.shBLE TPMS Monitor - Interactive
================================
Current Configuration:
Front Left (AC:15:85:C3:A2:01)
Rear Left (82:EA:CA:33:4F:E2)
Options:
1 - Discover and select sensors
2 - Start monitoring
3 - Remove a sensor
4 - Clear all sensors
5 - List available decoders
q - Quit
- Discover - Scan for nearby BLE devices (option 1)
- Select - Choose which sensors to monitor, give them names
- Monitor - Start live monitoring (option 2)
# MAC Address Name RSSI Decoder TPMS?
---------------------------------------------------------------------------
1 82:EA:CA:33:4F:E2 TPMS3_334FE2 -45 TPMS3-16byte TPMS Sensor
2 AC:15:85:C3:A2:01 BR -48 BR-7byte BR Sensor
3 AA:BB:CC:DD:EE:FF Unknown -72 Unknown
Select sensors by number, or press a to auto-select all detected TPMS devices.
Sensor Decoder Pressure Temp Battery Note HEX Packet
------------------------------------------------------------------------------------------------------
Rear Left TPMS3-16byte 1.82 bar (26.4 psi) 29C 100% Pos:RL Abs:40.9 82eaca334fe2...
Front Left BR-7byte 2.15 bar (31.2 psi) 22C 2.9V ROTAT 281d160105a376
Press Ctrl+C to stop monitoring and return to menu.
Pressure change is the ONLY wake trigger. Extensive testing confirmed these sensors contain no roll switch, accelerometer, or wake timer - the MEMS pressure interrupt is the sole wake mechanism. Motion, rotation, and vibration have zero effect. (On a driven tire they broadcast anyway, because flexing and thermal drift constantly cross the pressure threshold.)
Sleep / Wake cycle:
- Deep sleep - No broadcasts. Default state; only a pressure change wakes it
- On tire (parked) - Occasional wakes as thermal drift crosses the pressure threshold
- Pressure event - Immediate ~36 s burst at ~4 s intervals
Rapid-drop alarm (byte 15): flips to 0x01 on a fast pressure drop (even
~1 PSI in a moment), clears within one broadcast on pressure recovery, and
latches ~40 s if pressure stays low - so a puncture keeps alarming in every
packet. Rising pressure never sets it. See PROTOCOL.md for the full dynamics.
Tip: If no sensor is detected, deflate/inflate the tire slightly, or slowly screw the sensor on/off the valve to create air flow. See PROTOCOL.md for full details.
Valve interaction: An internal pin depresses the Schrader valve core when the sensor is screwed on, opening an air path. A twist-lock nut must be engaged for a proper seal. Without engagement, the sensor only reads atmospheric pressure (~0 PSI gauge).
Broadcast-only like the TPMS{N}, also purely pressure-event driven. Notable protocol features (fully documented in PROTOCOL.md):
- Trend byte: every packet carries a pressure-trend state -
stable,falling, orrising(shown live in the monitor).fallingis effectively the deflation alarm; it needs a drop faster than ~0.1-0.3 PSI/s to set and clears within seconds of stability - Coarse readings by design: pressure in 0.45 PSI steps, temperature in 1 C
- Wake burst is ~48 identical frames in ~1.4 s, then new readings every ~2 s while pressure changes, occasional idle reports ~26 s apart, then silence
- Rotating: Frequent broadcasts (~10-30s) above 4 km/h
- Stationary: Every 2-5 minutes
- Pressure change: Immediate transmission on >0.5 psi change
- Python 3.7+
- Bluetooth adapter
- Linux, macOS, or Windows
Dependencies installed automatically by setup.sh:
bleak- Cross-platform BLE library (no sudo required)colorama- Colored terminal output
TPMS/
├── tpms-interactive.py # Main application
├── sensor_decoders.py # Modular decoder library
├── btsnoop_analyze.py # Offline analyzer for Android btsnoop HCI captures
├── setup.sh # One-time setup (venv + dependencies)
├── run.sh # Launch the app
├── activate.sh # Quick venv activation helper
├── requirements.txt # Python dependencies
├── README.md # This file
├── PROTOCOL.md # BLE TPMS protocol documentation
├── DECODER_GUIDE.md # Guide for adding new sensor types
├── packet_log.jsonl # Persistent packet capture log (grows as you monitor)
└── BTSnoopLogs/ # Raw Android btsnoop captures used for analysis
- Create a decoder class in
sensor_decoders.py - Implement
can_decode()to identify your sensor - Implement
decode()to parse the data - Register it in the factory
See DECODER_GUIDE.md for a complete guide with a real-world reverse-engineering case study.
- Verify Bluetooth is enabled
- Sensor is likely asleep - these sensors wake on PRESSURE CHANGE, not motion
- To wake: deflate/inflate the tire briefly, or slowly screw the sensor on/off a valve
- Rolling or shaking the sensor will NOT wake it
- Use the interactive discovery (option 1) and keep scanning in 5-second rounds
- Use a BLE scanner app (e.g., nRF Connect) to verify the sensor is broadcasting
- Move closer to sensors (<5m)
- The twist-lock mechanism may not be engaged
- Sensor must fully depress the Schrader valve core to read tire pressure
- Without engagement, it correctly reads atmospheric pressure (~14.5 PSI absolute = ~0 gauge)
- If
pip installfails with "externally-managed-environment", use./setup.sh(uses venv) - If
python3-venvis missing:sudo apt install python3-venv
- TPMS Protocol Details: PROTOCOL.md
- Home Assistant ESPHome TPMS: https://community.home-assistant.io/t/ble-tire-pressure-monitor/509927
- ricallinson/tpms: https://github.com/ricallinson/tpms
- bkbilly/tpms_ble: https://github.com/bkbilly/tpms_ble
- theengs/decoder: https://decoder.theengs.io/devices/TPMS.html
- Instructables BLE TPMS: https://www.instructables.com/BLE-Direct-Tire-Pressure-Monitoring-System-TPMS-Di/
This project is provided as-is for educational and personal use.