Skip to content

Commit 2fe1402

Browse files
ProfBoc75buxtronix
andauthored
Fix Steelmate pressure formula (#3209)
* Fix Steelmate pressure formula * Improve Steelmate TPMS readouts (#3271) * Change Steelmate TPMS to native units BREAKING CHANGE (#3274) --------- Co-authored-by: buxtronix <bbuxton@gmail.com>
1 parent a1b10df commit 2fe1402

File tree

1 file changed

+64
-40
lines changed

1 file changed

+64
-40
lines changed

src/devices/steelmate.c

Lines changed: 64 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
Copyright (C) 2016 Benjamin Larsson
55
Copyright (C) 2016 John Jore
6+
Copyright (C) 2025 Bruno OCTAU (ProfBoc75)
67
78
This program is free software; you can redistribute it and/or modify
89
it under the terms of the GNU General Public License as published by
@@ -12,7 +13,23 @@
1213
/**
1314
Steelmate TPMS FSK protocol.
1415
15-
Packet payload: 9 bytes.
16+
Reference:
17+
18+
- model TP-S15
19+
20+
Brand:
21+
22+
- Steelmate
23+
- R-Lake
24+
25+
S.a. issue #3200 Pressure issue :
26+
27+
- The originally guessed formula was : Pressure in PSI scale 2, but more the pressure is important more the value diverged between the TPMS display and rtl_433.
28+
- New analysis : Based on data collected by \@e100 + the technical specification ( 0~7.9Bar ) + analysis by \@e100 and refined by \@ProfBoc75, the pressure is given in Bar at scale 32.
29+
30+
Packet payload:
31+
32+
- 9 bytes.
1633
1734
Bytes 2 to 9 are inverted Manchester with swapped MSB/LSB:
1835
@@ -24,9 +41,12 @@ Bytes 2 to 9 are inverted Manchester with swapped MSB/LSB:
2441
- S = sync, (0x00)
2542
- A = preamble, (0x01)
2643
- I = id, 0xc3f0
27-
- P = Pressure as double the PSI, 0x14 = 10 PSI
28-
- T = Temperature in Fahrenheit, 0x4a = 74 'F
29-
- B = Battery as half the millivolt, 0x8e = 2.84 V
44+
- P = Pressure in Bar, scale 32, 0xA0 / 32 = 5 Bar, or 0xA0 * 3.125 = 500 kPA, see issue #3200
45+
- T = Temperature in Celcius + 50, 0x4a = 24 'C
46+
- B = Battery, where mV = 3900-(value*10). E.g 0x8e becomes 3900-(1420) = 2480mV.
47+
- This calculation is approximate fit from sample data, any improvements are welcome.
48+
- > If this field is set to 0xFF, a "fast leak" alarm is triggered.
49+
- > If this field is set to 0xFE, a "slow leak" alarm is triggered.
3050
- C = Checksum, adding bytes 2 to 7 modulo 256 = byte 8,(0x01+0xc3+0xf0+0x14+0x4a+0x8e) modulus 256 = 0xa0
3151
3252
*/
@@ -35,58 +55,61 @@ Bytes 2 to 9 are inverted Manchester with swapped MSB/LSB:
3555

3656
static int steelmate_callback(r_device *decoder, bitbuffer_t *bitbuffer)
3757
{
58+
uint8_t const preamble_pattern[] = {0x00, 0x00, 0x7f}; // inverted, raw value is 0x5a
3859
//Loop through each row of data
39-
for (int row = 0; row < bitbuffer->num_rows; row++)
40-
{
60+
for (int row = 0; row < bitbuffer->num_rows; row++) {
4161
//Payload is inverted Manchester encoded, and reversed MSB/LSB order
42-
uint8_t *b = bitbuffer->bb[row];
62+
unsigned row_len = bitbuffer->bits_per_row[row];
4363

44-
//Length must be 72 bits to be considered a valid packet
45-
if (bitbuffer->bits_per_row[row] != 72)
64+
//Length must be 72, 73, 208 or 209 bits to be considered a valid packet
65+
if (row_len != 72 && row_len != 73 && row_len != 209 && row_len != 208)
4666
continue; // DECODE_ABORT_LENGTH
4767

4868
//Valid preamble? (Note, the data is still wrong order at this point. Correct pre-amble: 0x00 0x00 0x01)
49-
if (b[0] != 0x00 || b[1] != 0x00 || b[2] != 0x7f)
69+
unsigned bitpos = bitbuffer_search(bitbuffer, row, 0, preamble_pattern, 24);
70+
if (bitpos > row_len - 72)
5071
continue; // DECODE_ABORT_EARLY
72+
bitbuffer_invert(bitbuffer);
73+
uint8_t b[9];
74+
bitbuffer_extract_bytes(bitbuffer, row, bitpos, b, 72);
5175

52-
//Preamble
53-
uint8_t preamble = ~reverse8(b[2]);
76+
reflect_bytes(b, 9);
5477

55-
//Sensor ID
56-
uint8_t id1 = ~reverse8(b[3]);
57-
uint8_t id2 = ~reverse8(b[4]);
78+
//Checksum is a sum of all the other values
79+
if ((add_bytes(&b[2], 6) & 0xFF) != b[8])
80+
continue; // DECODE_FAIL_MIC
5881

59-
//Pressure is stored as twice the PSI
60-
uint8_t p1 = ~reverse8(b[5]);
82+
//Sensor ID
83+
uint8_t id1 = b[3];
84+
uint8_t id2 = b[4];
6185

62-
//Temperature is stored in Fahrenheit. Note that the datasheet claims operational to -40'C, but can only express values from -17.8'C
63-
uint8_t tempFahrenheit = ~reverse8(b[6]);
86+
//Pressure is stored as 32 * the Bar
87+
uint8_t p1 = b[5];
6488

65-
//Battery voltage is stored as half the mV
66-
uint8_t tmpbattery_mV = ~reverse8(b[7]);
89+
//Temperature is sent as degrees Celcius + 50.
90+
int temp_c = b[6] - 50;
6791

68-
//Checksum is a sum of all the other values
69-
uint8_t payload_checksum = ~reverse8(b[8]);
70-
uint8_t calculated_checksum = preamble + id1 + id2 + p1 + tempFahrenheit + tmpbattery_mV;
71-
if (payload_checksum != calculated_checksum)
72-
continue; // DECODE_FAIL_MIC
92+
//Battery voltage is stored as 100*(3.9v-<volt>).
93+
uint8_t b1 = b[7];
94+
int battery_mv = 3900 - b1 * 10;
7395

7496
int sensor_id = (id1 << 8) | id2;
75-
float pressure_psi = p1 * 0.5f;
76-
int battery_mV = tmpbattery_mV * 2;
97+
float pressure_kpa = p1 * 3.125f; // as guessed in #3200
7798

7899
char sensor_idhex[7];
79100
snprintf(sensor_idhex, sizeof(sensor_idhex), "0x%04x", sensor_id);
80101

81102
/* clang-format off */
82103
data_t *data = data_make(
83-
"type", "", DATA_STRING, "TPMS",
84-
"model", "", DATA_STRING, "Steelmate",
85-
"id", "", DATA_STRING, sensor_idhex,
86-
"pressure_PSI", "", DATA_DOUBLE, pressure_psi,
87-
"temperature_F", "", DATA_DOUBLE, (float)tempFahrenheit,
88-
"battery_mV", "", DATA_INT, battery_mV,
89-
"mic", "Integrity", DATA_STRING, "CHECKSUM",
104+
"type", "", DATA_STRING, "TPMS",
105+
"model", "", DATA_STRING, "Steelmate",
106+
"id", "", DATA_STRING, sensor_idhex,
107+
"pressure_kPa", "", DATA_FORMAT, "%.0f kPa", DATA_DOUBLE, pressure_kpa,
108+
"temperature_C", "", DATA_FORMAT, "%d C", DATA_INT, temp_c,
109+
"battery_mV", "", DATA_COND, b1 < 0xFE, DATA_INT, battery_mv,
110+
"alarm", "", DATA_COND, b1 == 0xFF, DATA_STRING, "fast leak",
111+
"alarm", "", DATA_COND, b1 == 0xFE, DATA_STRING, "slow leak",
112+
"mic", "Integrity", DATA_STRING, "CHECKSUM",
90113
NULL);
91114
/* clang-format on */
92115

@@ -103,19 +126,20 @@ static char const *const output_fields[] = {
103126
"type",
104127
"model",
105128
"id",
106-
"pressure_PSI",
107-
"temperature_F",
129+
"pressure_kPa",
130+
"temperature_C",
108131
"battery_mV",
132+
"alarm",
109133
"mic",
110134
NULL,
111135
};
112136

113137
r_device const steelmate = {
114138
.name = "Steelmate TPMS",
115139
.modulation = FSK_PULSE_MANCHESTER_ZEROBIT,
116-
.short_width = 12 * 4,
117-
.long_width = 0,
118-
.reset_limit = 27 * 4,
140+
.short_width = 50,
141+
.long_width = 50,
142+
.reset_limit = 120,
119143
.decode_fn = &steelmate_callback,
120144
.fields = output_fields,
121145
};

0 commit comments

Comments
 (0)