August 29, 2021

Sniffing car tire (TPMS) data (and tracking cars)

Last year I was interested in what kind of 433 MHz data there is in the air. I placed one RTL-SDR (software-defined radio) to capture 433 MHz traffic with rtl_433 for 75 days. The antenna was attached to indoor window, and it wasn’t optimized for anything specific. Now, after 1 year I finally began to check the captured data.

Data import 🔗

The outcome from 75 days was a ~500 MB CSV file. It had 260 columns and over 1.5 million rows.

Normally I use Python Pandas for analysis of CSV data. Now I wanted to test something new, something that is more suitable for data investigation. I found CSVKit and decided to test it. It did provide nice but basic analysis features. However, it was remarkably slow with that amount of data. The best feature of CSVKit was its ability to create RDBMS schema based on CSV columns and data, and insert CSV data to a database.

So, I used CSVKit to insert data into PostgreSQL database. The amount of data caused again problems that manifested by long processing time (1.5 hours) and high memory consumption (45 GB). I can’t understand how 500 MB CSV can consume 45 GB RAM.

Data analysis 🔗

The first observation of data was what I expected; 1.4 million records were from nearby sensors, and mainly my own sensors. In total there were 180 different devices (30 different models). It was interesting to see that they were not only temperature/humidity/door/smoke sensors but also car keys.

Much more interesting were 75 000 records sent by car tire-pressure sensors (TPMS). In total there were almost 10 000 unique tire sensor IDs. There is a road next to the building, but there is also concrete and brick obstacles between antenna and cars on the road.

TPMS sensors send pressure and temperature data. Unfortunately different manufacturers use different measurement units. Hence, I needed to convert all measurements to kilopascals and degree Celsius.

select
    model,
    round(min(tire_pressure), 1) as min_tire_pressure,
    round(avg(tire_pressure), 1) as avg_tire_pressure,
    round(max(tire_pressure), 1) as max_tire_pressure,
    round(min(tire_temperature), 1) as min_tire_temperature,
    round(avg(tire_temperature), 1) as avg_tire_temperature,
    round(max(tire_temperature), 1) as max_tire_temperature,
    count(*) as records
from
    (
    select
        distinct
    time,
        model,
        id,
        case
            when "temperature_C" is not null then "temperature_C"
            when "temperature_F" is not null then round(("temperature_F" - 32.0) * (5 / 9.0), 1)
        end as tire_temperature,
        case
            when "pressure_kPa" is not null then "pressure_kPa"
            when "pressure_PSI" is not null then round(6.8947572932 * "pressure_PSI", 1)
        end as tire_pressure
    from
        data_final
    where
        type = 'TPMS') as data
where
    tire_pressure is not null
    and tire_temperature is not null
group by
    model
order by
    model

I’m not doing deep data analysis because I already got answer to my original question. However, below are some data samples that I found interesting. I think TPMS data capture could be utilized by researches, spies and people who are being followed.

Sensor models 🔗

Below is distribution of records by sensor model. I’ve dropped duplicate (time + id) records.

Model Records
Abarth 124 Spider 2721 ▉▉▉▉▉▍
Citroen 4251 ▉▉▉▉▉▉▉▉▍
Elantra2012 3
Renault 6085 ▉▉▉▉▉▉▉▉▉▉▉▉▏
Schrader 6574 ▉▉▉▉▉▉▉▉▉▉▉▉▉▏
Schrader-EG53MA4 2083 ▉▉▉▉▏
Toyota 15025 ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉

Tire pressures 🔗

Following kind of data could be used to answer questions like “do Renaults have higher tire pressure than Toyota?” This data is not valid for that because average is from 75 days and weather changed.

Model Min (kPa) Avg (kPa) Max (kPa)
Abarth 124 Spider 0 222.3 350.5 ▉▌
Citroen 83.2 ▉▉▉ 244.5 ▉▉▉▊ 342.4 ▉▍
Elantra2012 227 ▉▉▉▉▉▉▉▉ 235.7 ▉▉▎ 248
Renault 0 249 ▉▉▉▉▋ 756.8 ▉▉▉▉▉▉▉▉
Schrader 190 ▉▉▉▉▉▉▋ 268 ▉▉▉▉▉▉▉▉ 587.5 ▉▉▉▉▉▎
Schrader-EG53MA4 115 ▉▉▉▉ 226.6 425 ▉▉▋
Toyota 93.1 ▉▉▉▎ 251.2 ▉▉▉▉▉ 375.8 ▉▉

Tire temperatures 🔗

It can be cold in Finland but never that cold in August. This is raw data.

Model Min (°C) Avg (°C) Max (°C)
Abarth 124 Spider -50 15.2 205 ▉▉▉▉▉▉▉▎
Citroen -49 17.5 ▉▌ 39
Elantra2012 16 ▉▉▉▉▉▉▉▌ 19.3 ▉▉▋ 25
Renault -23 ▉▉▉▏ 19.4 ▉▉▋ 222 ▉▉▉▉▉▉▉▉
Schrader 5 ▉▉▉▉▉▉▎ 19.9 ▉▉▉▏ 41
Schrader-EG53MA4 19.4 ▉▉▉▉▉▉▉▉ 27.3 ▉▉▉▉▉▉▉▉ 40.6
Toyota 5 ▉▉▉▉▉▉▎ 18.3 ▉▉ 42

Tracking of sensor IDs 🔗

This is the scariest part because this shows how TPMS could be (ab)used. Every sensor has permanent and unique ID, and sensors are constantly broadcasting it. It would be exceedingly easy to link car and person to sensor ID.

My data contains 50 different sensor IDs which each have over 100 measurement records. Couple sensors even have over 500 records each. I checked the time distribution of one single sensor. That exposed that I have seen that sensor on different days and times.

select distinct id, time from data_final where  id = 'f166e7bb'
ID Time
f166e7bb 2020-07-28 07:42:42
f166e7bb 2020-07-31 07:42:44
f166e7bb 2020-08-04 07:40:09
f166e7bb 2020-08-05 09:42:32
f166e7bb 2020-08-05 09:42:33
f166e7bb 2020-08-06 07:49:02
Timeline when one sensor (car) was next to my building

Timeline when one sensor (car) was next to my building

For example, I can see from the data that on September 3 the car was parked next to my building between 9:50 and 17:30, as I received data from that sensor every few minutes.

If one has a stalker like police or crazy ex-wife, one could deduce stalker car’s sensor ID and build a system to alert when stalker is nearby. Or, someone could build similar system to a car to alert if certain sensor ID is often nearby (i.e., exposes new followers).

People who want to be in stealth mode (criminals, police surveillance) know how to be anonymously. But, do they remember to silence their car tires? Especially because TPMS is mandatory in many countries.

I have ADS-B receiver to track airplanes and I feed that information to three different platforms. Similar system for TPMS would be interesting. There could be a map like Flightradar24 which would show in real time who is where. TPMS network would just need little bit more volunteers and sensors due to shorter signal range. ADS-B range is easily hunreds of kilometers, TPMS is tens of meters. Though, big brother could integrate TPMS receivers into light poles 😉.