-
• #2
Is the bind really creating a connection or just take note of the device id in a registration and then taking into account only advertisements of the registered device id? That is the way to get away from having to connect and still get data, assuming the data is in the advertisement.
TPMS has version bluetooth 4 and 5. Your's look like they are 4. But that's just from the outside look.
Interesting pub at https://www.amarinfotech.com/differences-comparisons-bluetooth-5-vs-4-2.html (print attached as .pdf)
2 Attachments
-
• #3
Hey, @allObjects thanks for your response.
Since the devices were quite cheap and on the market for a while I guess it's all old-fashioned BLE 4.
My guess was also that a connection actually might have been avoided by the creators since it means complexity and drawing more battery power.
But my question is this:
Does the quoted advertisement data contain everything the device has to tell us?
Where is the device name that my LightBlue BLE sniffer app shows?
How can I obtain any data from the advertised service and its characteristics when I cannot connect to the device?PS: I just found the same item on aliexpress and they explicitly say it's BLE 4 - look: https://www.aliexpress.com/item/33041131063.html
1 Attachment
-
• #4
Update:
Doing some more research I found this:
https://raspberrypi.stackexchange.com/questions/76959/how-to-decode-tpms-sensor-data-through-rpi3-bluetoothMaybe it is the same protocol, maybe similar.
At least the temperature reading would make sense in my case - not sure with the pressure yet.So it most probably is about the
manufacturerData
and no connection is required.
That would be quite simple to do, I'll just get my Pixl.js ready to take over from there... ;-) -
• #5
OK. Another update.
Some more investigation and some coding later I have a working solution now:const ttl = 30; var idlog = {}; function i2h(i) { return ('0'+i.toString(16)).slice(-2); } function a2h(a, i, l) { var res = ''; for(var j=i; j<i+l; j++) { res += i2h(a[j]); } return res; } function dec32(a, i) { var res = Uint32Array(1); res[0] = (a[i+3] << 24) | (a[i+2] << 16) | (a[i+1] << 8) | a[i]; return res[0]; } function decodeData(device) { var d = device.manufacturerData; var id = a2h(d, 0, 6); var data = { battery: d[14], flat: d[15], temp: dec32(d, 10) / 100, pressure: dec32(d, 6) / 100000 }; var t = getTime(); if( idlog[id] == undefined || idlog[id].last + ttl < t) { idlog[id] = { last: t, data: data }; console.log(id, data); } } function onInit() { NRF.setScan(function(device){ decodeData(device); }, { filters:[{ services: ['fbb0'] }] }); }
This is the output from a few sensors (*ba52 sits on a "real" tire, the others are just blown into to wake them up):
82eaca30bc95 { "battery": 85, "flat": 0, "temp": 23.11, "pressure": 0.07926 } 82eaca30bc95 { "battery": 85, "flat": 1, "temp": 23.55, "pressure": 0 } 80eaca10ba52 { "battery": 85, "flat": 0, "temp": 18.67, "pressure": 8.36479 } 80eaca10ba52 { "battery": 85, "flat": 0, "temp": 18.67, "pressure": 8.36479 } 80eaca10ba52 { "battery": 85, "flat": 0, "temp": 18.67, "pressure": 8.36479 } 82eaca30bc95 { "battery": 85, "flat": 0, "temp": 23.7, "pressure": 0.07018 } 81eaca207bdd { "battery": 75, "flat": 0, "temp": 23.73, "pressure": 0.053 } 80eaca10ba52 { "battery": 85, "flat": 0, "temp": 18.67, "pressure": 8.36479 } 82eaca30bc95 { "battery": 85, "flat": 1, "temp": 24.85, "pressure": 0 } 81eaca207bdd { "battery": 75, "flat": 1, "temp": 24.15, "pressure": 0 }
Now everything needs to be wrapped up, put into a working solution including low pressure / battery indication (sound, LED), missing signal detection, pairing etc...
-
• #6
@ChristianW, thanks, you just made my day! - you really push it to the limit with:
Now everything needs to be wrapped up, put into a working solution including low pressure / battery indication (sound, LED), missing signal detection, pairing etc...
-
• #7
@allObjects what do you mean by push it to the limit?
It is not ready yet, just the core piece.
But at least I know it is possible... -
• #8
That's great! Sorry I was a bit late to this, but yes, it makes sense that the relevant data would be in manufacturerData. Those look amazingly neat - I'd love to see something working on a Pixl.js or Bangle.js.
The code you have there looks spot on - all I'd say is you can always use
DataView
to decode the data without needingdec32
...d = new DataView(device.manufacturerData); d.getUint8(14) //d.getUint32(10) or d.getUint32(10,1) if byte order is different // you can also use getInt32 for signed data (eg temperature?)
For anyone else interested in this you seem to be able to just search for "v11 tpms" and find them on eBay around £30.
If you're doing this for a bike you could maybe even detect which sensor is which using signal strength (I guess the rear wheel would be lower strength than the front :).
-
• #11
Nice - thanks!
-
• #12
@ChristianW, thanks a LOT. I have the exact same device and have been struggling with which bytes to decode.
I already did most of the "wrapping up" in an android app i made for a home made tyre temperature monitor for trackdays. So just needed to convert to a bluetooth device and parse the data. -
• #13
Short update:
I have the feeling the sensors are crap. Some of them seem to work for a few weeks or more, but others drain their battery within hours or sometimes minutes.
I have no idea why and even bought another two sets of sensor to rule out a bad batch.Maybe it's because I use them in a unusually high pressure range of 6 to 8 Bar.
Or maybe there is something in the protocol that I did not get and they rely on some handshake by the original app...
@user126998 can you confirm anything of my observations or are yours just working fine? -
• #14
Just a thought, but sometimes bluetooth devices advertise quickly (high power state) when they are first turned on, and only go to a lower power state when they've been 'paired'.
I guess you could try pairing one with their official app and see if it lasts any longer?
Disclaimer: I have played around with Espruino some while ago and my JS and BLE knowledge may have gotten a bit rusty - so sorry for any stupid questions in advance.
I got a Chinese TPMS (tire pressure monitoring system) consisting of 4 coincell powered BLE enabled oversized valve caps and an iOS / Android App.
The sensors support pressures over 10 Bar, but the App doesn't allow warning thresholds beyond 6,4 and since I want to monitor my bike tires I am stuck here.
Espruino to the rescue! (so I thought) - so I started hacking.
I can see the Sensors appearing in the iOS LightBlue app from time to time. Name "TPMSn-xxxxx" with n being 1..4 and xxxxxx being the hex suffix of the device ID.
Each device reports 1 service, but any connection attempt times out.
So I got out my old Nordic development board with the Espruino port loaded and finally used this:
to log this:
From time to time devices appear. But this is it.
When I actually try to connect a device using this code:
I guess the device avoids connections to save power.
Or at least makes connections as brief as possible.
So my questions:
2 Attachments