Diagnosing Toyota TPMS sensors with rtl_433
February 13, 2022
Introduction #
My 2008 Toyota Tacoma is equipped with a direct tire pressure monitoring system (TPMS). This system consists of four wireless sensors (one at each wheel) and an onboard control unit which receives and monitors data from the sensors. The TPMS in this truck is not very advanced. The only information the system provides to the driver is a warning light. It has no way to indicate which tire has low pressure. Currently, one of the TPMS sensors is broken. I know because even when my tire pressures are correct, the TPMS warning light on my dashboard flashes while starting up then stays constantly illuminated. I’d prefer to only replace the broken sensor, and I don’t have a tool to diagnose TPMS sensors. So how do you determine which has failed without buying an expensive TPMS diagnostic tool? I have a RTL-SDR dongle hanging around, so I decided to use rtl_433 to capture and decode signals from the TPMS sensors in order to determine which has failed. This article will describe the process, present some things I learned, and provide a rough guide for someone wanting to do the same thing.
Required tools #
- Some kind of SDR hardware compatible with rtl_433. We will only be receiving, so we don’t need an expensive, TX-capable SDR. I used the cheap, RTL2832U-based RTL-SDR dongle. This came with a telescopic dipole antenna, which works fine for this project. As of this writing, the cost is about $40USD for the RTL-SDR kit, which includes the dongle, antennas, coax and mounts. The dongle itself costs around $30USD. More expensive, full-featured SDRs such as HackRF and LimeSDR will work as well.
- Some kind of antenna and coax for the dongle, I just used the cheap one that came in a kit with the RTL-SDR
- PC that can run rtl_433. A laptop or raspberry pi works, as long as you can physically relocate the antenna near each tire. rtl_433 runs on Windows, Mac and Linux. I used a Macbook, but instructions are the same no matter which platform you use.
Process #
Install rtl_433 #
rtl_433 is a program for receiving and decoding data transmissions in the 433.92 MHz, 868 MHz, 315 MHz, 345 MHz, and 915 MHz bands. We will use it for decoding TPMS sensor transmissions. It has built-in decoders for Toyota TPMS as well as many other vehicle brands. It’s an interesting piece of software with many uses beyond TPMS sensors.
If you are using Windows, binary packages for rtl_433 are available here. If you are using MacOS, rtl_433 can be installed via homebrew. For Linux users, check if your distribution’s package manager includes rtl_433.
If you prefer to build from source, check out the official build instructions.
Set up SDR hardware #
Once you have installed rtl_433, plug in your SDR to the computer and connect your antenna coax. I set up my telescoping dipole with each leg approx. 18" long. The exact length doesn’t matter too much- we don’t need our antenna/receiver to be very sensitive.
I also added a rtl-sdr FM broadcast band-stop filter in between the antenna and the SDR. This is not required, but I have a lot of strong broadcast FM signals in my area and this helps prevent them from interfering with weaker signals.
Receiving TPMS sensor messages #
Once we have rtl_433 installed and our SDR hardware setup, we can start monitoring for transmissions from the car’s TPMS sensors. I moved my computer and SDR setup outside and set the antenna on the ground next to the truck. The Tacoma appears to have a “low line” TPMS system, where the sensors transmit messages at regular intervals, regardless of whether the car is being operated. In order to receive sensor messages, I ran rtl_433 with the following options:
rtl_433 -M level -f 315000000
-M level
displays signal level information along with each decoded transmission. -f 315000000
sets the receiving frequency in Hz. Toyota TPMS sensors transmit at 315 MHz.
After running for a few minutes, we get the following output:
$ rtl_433 -M level -f 315000000
rtl_433 version 21.12-60-g5f0ff6db branch master at 202202121409 inputs file rtl_tcp RTL-SDR
Use -h for usage help and see https://triq.org/ for documentation.
Trying conf file at "rtl_433.conf"...
Trying conf file at "~/.config/rtl_433/rtl_433.conf"...
Trying conf file at "/usr/local/etc/rtl_433/rtl_433.conf"...
Trying conf file at "/etc/rtl_433/rtl_433.conf"...
Registered 182 out of 213 device decoding protocols [ 1-4 8 11-12 15-17 19-23 25-26 29-36 38-60 63 67-71 73-100 102-105 108-116 119 121 124-128 130-149 151-161 163-168 170-175 177-197 199 201-213 ]
Found Rafael Micro R820T tuner
Exact sample rate is: 250000.000414 Hz
[R82XX] PLL not locked!
Sample rate set to 250000 S/s.
Tuner gain set to Auto.
Tuned to 315.000MHz.
baseband_demod_FM: low pass filter for 250000 Hz at cutoff 25000 Hz, 40.0 us
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
time : 2022-02-13 12:57:50
model : PMV-107J type : TPMS id : 04d3c7d2
status : 40 battery_ok: 0 counter : 1 failed : OK pressure_kPa: 205.840 temperature_C: 24.000 Integrity : CRC
Modulation: FSK Freq1 : 315.0 MHz Freq2 : 314.9 MHz
RSSI : -1.0 dB SNR : 32.2 dB Noise : -33.1 dB
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
time : 2022-02-13 12:57:52
model : PMV-107J type : TPMS id : 0b23e7a5
status : 8 battery_ok: 1 counter : 1 failed : OK pressure_kPa: 200.880 temperature_C: 24.000 Integrity : CRC
Modulation: FSK Freq1 : 315.0 MHz Freq2 : 314.9 MHz
RSSI : -1.0 dB SNR : 34.1 dB Noise : -35.2 dB
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
time : 2022-02-13 12:58:04
model : PMV-107J type : TPMS id : 0f4ed4c3
status : 48 battery_ok: 0 counter : 2 failed : OK pressure_kPa: 208.320 temperature_C: 22.000 Integrity : CRC
Modulation: FSK Freq1 : 315.0 MHz Freq2 : 314.9 MHz
RSSI : -7.9 dB SNR : 22.5 dB Noise : -30.4 dB
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
time : 2022-02-13 12:58:49
model : PMV-107J type : TPMS id : 04d3c7d2
status : 48 battery_ok: 0 counter : 2 failed : OK pressure_kPa: 205.840 temperature_C: 24.000 Integrity : CRC
Modulation: FSK Freq1 : 315.0 MHz Freq2 : 314.9 MHz
RSSI : -1.6 dB SNR : 29.7 dB Noise : -31.4 dB
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
time : 2022-02-13 12:58:55
model : PMV-107J type : TPMS id : 0b23e7a5
status : 16 battery_ok: 1 counter : 2 failed : OK pressure_kPa: 200.880 temperature_C: 24.000 Integrity : CRC
Modulation: FSK Freq1 : 315.0 MHz Freq2 : 314.9 MHz
RSSI : -1.0 dB SNR : 31.6 dB Noise : -32.6 dB
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
time : 2022-02-13 12:59:03
model : PMV-107J type : TPMS id : 0f4ed4c3
status : 56 battery_ok: 0 counter : 3 failed : OK pressure_kPa: 208.320 temperature_C: 22.000 Integrity : CRC
Modulation: FSK Freq1 : 315.0 MHz Freq2 : 314.9 MHz
RSSI : -7.4 dB SNR : 24.8 dB Noise : -32.1 dB
We can see three unique ids among these messages, each indicating a data transmission received from a different source. After receiving these, I kept monitoring for several more minutes. Transmissions from these three IDs repeated at 1 minute intervals. I observed no other transmissions. Nothing else seems to be transmitting on 315 MHz, otherwise I might have to use rtl_433’s -R <device>
option to filter out other transmissions.
Interpreting sensor messages #
What useful information can we gather from these messages?
- Only three sensors are transmitting. Since the car has four wheels, each with a sensor, we can deduce that one has failed completely due to a dead battery or some malfunction.
- We see some variation in received signal strength (RSSI) between the three sensors. We can use this to identify the position of each transmitting sensor.
- rtl_433 detects the TPMS model as “PMV-107J”. This is a type of TPMS often fitted to Toyota vehicles. We can use this to filter out any other, unrelated transmissions.
- rtl_433 decodes some interesting fields from the TPMS data, including “status”, “battery_ok”, “counter” and “failed”. We may be able to use these for other sensor diagnostics.
- We can see the temperature (in degrees Celcius) and pressure (in kilopascals) of each tire. My tire pressures are a couple PSI low, I need to top them up!
Locating individual sensors #
Since I wanted to identify which sensor has failed, the next step is to find the position of each working sensor. By a process of elimination, we can check each wheel for a transmitting sensor until we find the wheel without one.
Each TPMS has a unique 32-bit id. This is reported by rtl_433 as the “id” field, represented as hexadecimal values. The car’s ECU uses the id to register each TPMS, distinguishing the signals from those produced by other vehicles’ TPMS. The rtl_433 output above shows 3 unique ids: 04d3c7d2
, 0b23e7a5
and 0f4ed4c3
.
Note: The four 32-bit IDs transmitted by a vehicle’s TPMS sensors can be used as a unique fingerprint to identify that vehicle. In theory, this could be used to track a vehicle’s location, although only at a very short range. The IDs shown in this article have been altered.
I also noticed a variation in received signal strength indication (RSSI) between the three active sensors. We can use this to determine the physical location of each sensor. The radio transmitters used in these sensors are very low power, typically around 250 μW. Like all radio signals, they are attenuated by distance. The body of the truck can also block the signal. Therefore, the strategy is to move the antenna to each wheel, record which sensor ID transmits above a threshold RSSI, then move to the next wheel. By comparing received transmissions and RSSI from all four positions, we can then determine which sensor ID is located at which wheel.
So, let’s place the SDR antenna very close to a wheel and run the following command:
rtl_433 -M level -f 315000000 -R 110 -Y minlevel=-0.5
We have added two options to the rtl_433 command we used before. -R 110
sets rtl_433 to only decode signals from PMV-107J sensors. Any other received signals will be ignored. -Y minlevel=-0.5
sets rtl_433 to only decode signals with a RSSI above -0.5 dB. Weaker signals will be ignored. The combination of these two options will filter out both non-TPMS transmissions and should ignore transmissions from all but the closest wheel. You may need to tweak the value for the -Y option, the signal strength of the nearest wheel will vary depending on the sensor, your hardware/antenna, and local conditions. According to the rtl_433 docs, the highest you can set the minlevel parameter is -1.0, however in my own testing -0.5 seems to work fine.
Let’s look at the results I got from each wheel:
Back right wheel #
time : 2022-02-13 13:26:46
model : PMV-107J type : TPMS id : 04d3c7d2
status : 56 battery_ok: 0 counter : 3 failed : OK pressure_kPa: 208.320 temperature_C: 26.000 Integrity : CRC
Modulation: FSK Freq1 : 315.0 MHz Freq2 : 314.9 MHz
RSSI : -0.0 dB SNR : 13.8 dB Noise : -13.9 dB
We get a very strong signal (RSSI = -0.0 dB) with ID 04d3c7d2. This signal repeats at 1 minute intervals, just like we saw earlier.
Front right wheel #
time : 2022-02-13 13:29:08
model : PMV-107J type : TPMS id : 0f4ed4c3
status : 56 battery_ok: 0 counter : 3 failed : OK pressure_kPa: 210.800 temperature_C: 23.000 Integrity : CRC
Modulation: FSK Freq1 : 315.0 MHz Freq2 : 314.9 MHz
RSSI : -0.0 dB SNR : 20.6 dB Noise : -20.6 dB
Another strong signal with ID 0f4ed4c3.
Back left wheel #
time : 2022-02-13 13:33:54
model : PMV-107J type : TPMS id : 0b23e7a5
status : 16 battery_ok: 1 counter : 2 failed : OK pressure_kPa: 200.880 temperature_C: 24.000 Integrity : CRC
Modulation: FSK Freq1 : 315.0 MHz Freq2 : 314.9 MHz
RSSI : -0.1 dB SNR : 13.8 dB Noise : -13.9 dB
Another strong signal with ID 0b23e7a5.
Front left wheel #
No results to show here because nothing was received. This must be the location of the failed sensor!
Results #
I was able to isolate the transmissions with three unique IDs to three of the truck wheels by repositioning the antenna and filtering out transmissions below a certain signal strength. The output of rtl_433 showed that sensors were transmitting at all wheels except the front left wheel. This is probably the cause of the TPMS warning light, so I will now install a new sensor on this wheel.
I found the failed sensor, which is what I set out to do at the beginning of this project. However, we also saw other data fields transmitted by the sensors: “status”, “battery_ok”, “counter” and “failed.” What can we learn from these? There are few details in the rtl_433 documentation. I found Werner Johansson’s pacific-tpms, which is a decoder for the PMV-107J implemented in python. According to the rtl_433 source code, Johansson’s work was the basis of rtl_433’s PMV-107J decoder. The pacific-tpms README has some information on these additional fields. By comparing the rtl_433 output with this information, as well as by examining the rtl_433 source linked above, we can figure out what these fields mean:
- battery_ok: If the sensor sets a “battery low” bit in its transmission, this field will be 0. Our sensors at the front right wheel and back right wheel both show battery_ok = 0. It’s a good idea to replace these at the same time we replace the dead sensor. They are working now, but they are likely to run out of battery soon.
- failed: This represents the status of each sensor’s self-test. If the “failed” bit is set in the sensor transmission, this will report as “FAIL”, otherwise it will be “OK.” All sensors reported a value of “OK”, so there is nothing to worry about here. According to Johansson, if the car receives a transmission with a “failed” bit set, it will ignore the pressure/temperature values in that message and flash the TPMS light.
- counter: This value increments from 1 to 3 with each message sent from a sensor. The purpose of this is unclear. According to Johansson, the car will still accept sensor transmissions even if the counter is not incremented.
- status: Unfortunately, I could find no information on what the status number means. It’s an integer, and it varied both between individual sensors and over time. If anyone has any more information, please let me know.
Automation #
While this process works well, it requires a fair amount of running commands manually and interpreting the result. It’s possible to configure rtl_433 to output received messages in a machine-readable format for automated parsing and comparison. So, I wrote a bash script that guides the user through this process and creates a simple diagnostic summary explaining which TPMS sensors should be replaced. Check out this follow-up post for more information.
References #
- rtl_433 GitHub repository
- pacific-tpms GitHub repository
- TPMS-related articles on rtl-sdr.com
- Direct TPMS (Wikipedia)
- Smith, C. (2016). The car hacker’s handbook: A guide for the penetration tester. No Starch Press.
- Rouf, I. et al. (2010). “Security and Privacy Vulnerabilities of In-Car Wireless Networks: A Tire Pressure Monitoring System Case Study” (pdf).