A bash script for TPMS testing

A bash script for TPMS testing

March 13, 2022
cars, programming, radio

Introduction #

Previously, I wrote a post describing how to test Toyota tire pressure monitoring system (TPMS) sensors using rtl_433 and affordable SDR hardware such as a rtl-sdr dongle. The process described in that post is fairly manual. I decided to write a wrapper script, tpms-helper, that guides the user through this process and does basic parsing and interpretation of the results.

Requirements #

  • bash shell, version 4.0 or later. This script uses associative arrays and mapfile, which are not available on earlier bash versions.
  • jq: This is a lightweight command-line JSON processor, used to parse output from rtl_433
  • bc: Calculator for arbitrary precision numbers. Used to compare floating point numbers, as pure bash only supports integer math.
  • rtl_433
  • SDR hardware compatible with rtl_433

I have chosen some non-builtin tools (such as jq and bc). While I could replicate the functionality provided by these tools in “pure” bash, the simplicity of calling a purpose-built tool increases the readability and maintainability of the code. Since this script also requires installation of rtl_433, it’s likely not an issue to install dependencies in any environment where this script is used. Additionally, some language features used in this script require later versions of bash, which may require updating on platforms such as MacOS (which as of 2022 still ships bash 3.2). I believe the improvement in readability from using mapfile and associative arrays outweighs the portability advantages of supporting older bash versions.

Installing the script #

The latest version of the script can be downloaded from the tpms-helper GitHub repository.

git clone https://github.com/rouyng/tpms-helper.git
cd tpms-helper
chmod +x tpms-helper

Running the script #

Make sure all dependencies are installed and the rtl-sdr dongle/antenna is connected, then invoke the script as follows:


If you are running bash <4.0, a dependency is missing, or rtl_433 cannot connect to the SDR, the script will exit with an appropriate error message.

You will be prompted to place the antenna at one of the four tires then press any button. The script will attempt to detect TPMS signals for 60 seconds at each tire, report what was received, then prompt you to place the antenna at the next tire. This repeats for all four tires. Once complete, the script generates a summary report showing what signals were detected at each tire, including sensor ID, RSSI and battery status.

Interpreting the results #

Let’s look at an example. I ran the script using the same truck and sensors in my previous article. Here is the summary generated by the script. For brevity’s sake, I omitted the beginning of the script output (including prompts to place the antenna and rtl_433 messages).

Summary of sensors detected
back right wheel
  └─ID: "05b323g6", RSSI: -0.129, Battery status: ok
  └─ID: "04d3c7d2", RSSI: -0.123, Battery status: ok <- strongest signal

front left wheel
  └─ID: "0f4ed4c3", RSSI: -0.5, Battery status: ok

front right wheel
  └─ID: "0b23e7a5", RSSI: -0.5, Battery status: ok
  └─ID: "0f4ed4c3", RSSI: -0.137, Battery status: ok <- strongest signal

back left wheel
  └─ID: "0f4ed4c3", RSSI: -0.5, Battery status: ok
  └─ID: "04d3c7d2", RSSI: -0.122, Battery status: ok
  └─ID: "0b23e7a5", RSSI: -0.107, Battery status: ok <- strongest signal

Warning: Received more than one signal at a wheel. Consider increasing the MINLEVEL from the current value of -0.5, to filter adjacent sensors

First, we can see that we detected multiple signals at three of the four wheels. Even with a minimum RSSI threshold of -0.5 dB, we were still able to receive signals from sensors at other wheels. However, the script assists with this situation by ranking signals by RSSI and adding a “strongest signal” note to the strongest one received at each wheel. This immediately gives us candidates for the sensors at three of the wheels: 0b23e7a5 at back left, 0f4ed4c3 at front right, and 04d3c7d2 at back right. 0f4ed4c3 also shows up at front left, but the RSSI is low (-0.5) compared to when it appears at front right, so front right is probably the true location. This is also consistent with the results from my previous, manual testing process, which showed that the sensor at front left had failed and was not transmitting.

The results are the same as the manual process, but the script guides the user through the process, keeps track of signals received, and suggests possible sensors based on relative RSSI. While we’re still not 100% automatic, this script does speed up the process and reduce cognitive overhead, and therefore the chance of error.

Looking towards full automation #

While this script turns a fully manual process into a guided one and simplifies the interpretive work involved, it still requires human intervention and interpretation. The antenna must be moved between each wheel and a button pressed to continue the script. Is it possible to eliminate this step? rtl_433 can be run with a -d <RTL-SDR USB device index> flag. This directs rtl_433 to interface with a specific rtl-sdr dongle when multiple are attached. Using this flag, we could create a version of our wrapper script that runs four instances of rtl_433 simultaneously, switching the device index to correspond to a dongle with antenna placed at each wheel. Since I don’t have three more rtl-sdr dongles handy, I’ll leave this as an exercise for the reader.

We could also extend this script to compare RSSI of multiple signals with the same ID, received at multiple wheels, in order to provide a guess at the position of each sensor. Since changes in RSSI predictably vary as position of the antenna changes, we can make a script that reasons about the probable position of a sensor given signals received at set locations, as well as absences of working sensors. This would further simplify the interpretation of the results in our example.

If I were to implement either or both of these proposed features, my preference would be to rewrite the script in a more full-featured language. While I have no doubt a bash wizard could write them in pure bash, I would appreciate the features and expressiveness of a language like Python when dealing with the more complex state introduced by these proposals.

Issues? Suggestions? #

If you find a bug with this script, or if you have a suggestion to improve it, head on over to the issues section of the script’s GitHub repository.