diff --git a/README.md b/README.md
index 68ae31ba..c1f57113 100644
--- a/README.md
+++ b/README.md
@@ -337,6 +337,7 @@ See [CONTRIBUTING.md](./docs/CONTRIBUTING.md).
     [249]  Bresser lightning
     [250]  Schou 72543 Day Rain Gauge, Motonet MTX Rain, MarQuant Rain Gauge
     [251]  Fine Offset / Ecowitt WH55 water leak sensor
+    [252]  BMW Gen5 TPMS, multi-brand HUF, Continental, Schrader/Sensata
 
 * Disabled by default, use -R n or a conf file to enable
 
diff --git a/conf/rtl_433.example.conf b/conf/rtl_433.example.conf
index ae6fc29a..1ab831f9 100644
--- a/conf/rtl_433.example.conf
+++ b/conf/rtl_433.example.conf
@@ -478,6 +478,7 @@ convert si
   protocol 249 # Bresser lightning
   protocol 250 # Schou 72543 Day Rain Gauge, Motonet MTX Rain, MarQuant Rain Gauge
   protocol 251 # Fine Offset / Ecowitt WH55 water leak sensor
+  protocol 252 # BMW Gen5 TPMS, multi-brand HUF, Continental, Schrader/Sensata
 
 ## Flex devices (command line option "-X")
 
diff --git a/include/rtl_433_devices.h b/include/rtl_433_devices.h
index 3561c4d7..abb5157a 100644
--- a/include/rtl_433_devices.h
+++ b/include/rtl_433_devices.h
@@ -259,6 +259,7 @@
     DECL(bresser_lightning) \
     DECL(schou_72543_rain) \
     DECL(fineoffset_wh55) \
+    DECL(tpms_bmw) \
 
     /* Add new decoders here. */
 
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 55c4469a..5fed8604 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -232,6 +232,7 @@ add_library(r_433 STATIC
     devices/thermopro_tx2c.c
     devices/tpms_abarth124.c
     devices/tpms_ave.c
+    devices/tpms_bmw.c
     devices/tpms_citroen.c
     devices/tpms_eezrv.c
     devices/tpms_elantra2012.c
diff --git a/src/devices/tpms_bmw.c b/src/devices/tpms_bmw.c
new file mode 100644
index 00000000..8fc1c0f9
--- /dev/null
+++ b/src/devices/tpms_bmw.c
@@ -0,0 +1,151 @@
+/** @file
+    BMW Gen5 TPMS sensor.
+
+    Copyright (C) 2024 Bruno OCTAU (ProfBoc75), \@petrjac, Christian W. Zuckschwerdt <christian@zuckschwerdt.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+*/
+/**
+BMW Gen5 TPMS sensor.
+
+issue #2821 BMW Gen5 TPMS support open by \@petrjac
+
+Samples raw :
+
+    555554b2aab4b2b552acb4d332accb32b552aaacd334d32ad334
+    555554b2aab4b2b552acb4d332acb4cab54caaacd4cad32b4b55
+
+- Preamble {16} 0xaa59 before MC
+- MC Zero bit coded, 11 bytes
+
+Samples after MC Inverted:
+
+     0  1  2  3  4  5  6  7  8  9 10
+    MM II II II II PP TT F1 F2 F3 CC
+    03 23 e1 36 a1 4a 3e 01 6b 68 6b
+    03 23 e1 36 a1 34 3d 01 74 68 cf
+
+- MM : Brand BRAND ID, 0x03 = HUF Gen 5, 0x23 = Schrader/Sensata, 0x80 = Continental
+- II : Sensor ID
+- PP : Pressure * 2.45 kPa
+- TT : Temp - 52 C
+- F1 : Warning Flags , battery, fast deflating ... not yet guess
+- F2 : Sequence number, to be confirmed
+- F3 : Target Nominal Pressure * 0.0245 for 0x03
+- CC : CRC 8 of 10 byte, init 0xaa , poli 0x2f
+
+Data layout after MC for HUF Gen 5:
+
+    BRAND = 8h | SENSOR_ID = 32h      | PRESS = 8d  | TEMP = 8d  | FLAGS1 = 8h | FLAGS2 = 8h | FLAGS3 = 8d  | CRC = 8h
+
+    BRAND = 03 | SENSOR_ID = 23e136a1 | PRESS = 074 | TEMP = 062 | FLAGS1 = 01 | FLAGS2 = 6b | FLAGS3 = 104 | CRC = 6b
+    BRAND = 03 | SENSOR_ID = 23e136a1 | PRESS = 052 | TEMP = 061 | FLAGS1 = 01 | FLAGS2 = 74 | FLAGS3 = 104 | CRC = cf
+
+Continental model:
+
+    F1, F2, F3 to guess
+
+Schrader/Sensata model:
+
+    F1, F2, F3 to guess
+*/
+
+#include "decoder.h"
+
+static int tpms_bmw_decode(r_device *decoder, bitbuffer_t *bitbuffer)
+{
+    bitbuffer_t decoded = { 0 };
+    uint8_t *b;
+    // preamble is aa59
+    uint8_t const preamble_pattern[] = {0xaa, 0x59};
+
+    if (bitbuffer->num_rows != 1) {
+        decoder_logf(decoder, 2, __func__, "row error");
+        return DECODE_ABORT_EARLY;
+    }
+
+    int pos = 0;
+    pos = bitbuffer_search(bitbuffer, 0, 0, preamble_pattern, sizeof(preamble_pattern) * 8);
+    if (pos >= bitbuffer->bits_per_row[0]) {
+        decoder_logf(decoder, 2, __func__, "Preamble not found");
+        return DECODE_ABORT_EARLY;
+    }
+
+    decoder_log_bitrow(decoder, 2, __func__, bitbuffer->bb[0], bitbuffer->bits_per_row[0], "MSG");
+
+    bitbuffer_manchester_decode(bitbuffer, 0, pos + sizeof(preamble_pattern) * 8, &decoded, 11 * 8);
+
+    decoder_log_bitrow(decoder, 2, __func__, decoded.bb[0], decoded.bits_per_row[0], "MC");
+
+    if (decoded.bits_per_row[0] < 88) {
+        decoder_logf(decoder, 1, __func__, "Too short");
+        return DECODE_ABORT_LENGTH;
+    }
+
+    bitbuffer_invert(&decoded); // MC Zerobit
+    decoder_log_bitrow(decoder, 2, __func__, decoded.bb[0], decoded.bits_per_row[0], "MC inverted");
+    b = decoded.bb[0];
+    if (crc8(b, 11, 0x2f, 0xaa)) {
+        decoder_logf(decoder, 1, __func__, "crc error, expected %02x, calculated %02x", b[11], crc8(b, 11, 0x2f, 0xaa));
+        return DECODE_FAIL_MIC; // crc mismatch
+    }
+    decoder_log(decoder, 2, __func__, "BMW found");
+    int brand_id            = b[0]; // 0x03 = HUF Gen 5, 0x80 = Continental, 0x23 = Sensata, 0x88 = ??
+    float pressure_kPa      = b[5] * 2.45;
+    int temperature_C       = b[6] - 52;
+    int flags1              = b[7]; // depends on brand_id, could be pressure or SEQ ID and other WARM flags Battery , fast deflating ...
+    int flags2              = b[8]; // depends on brand_id, could be pressure and other WARM flags Battery , fast deflating ...
+    int flags3              = b[9]; // Nominal Pressure for brand HUF 0x03, depends on brand_id, could be SEQ ID and other WARM flags Battery , fast deflating ...
+
+    char id_str[9];
+    snprintf(id_str, sizeof(id_str), "%02x%02x%02x%02x", b[1], b[2], b[3], b[4]);
+    char msg_str[23];
+    snprintf(msg_str, sizeof(msg_str), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10]);
+
+    /* clang-format off */
+    data_t *data = data_make(
+            "model",               "",                DATA_STRING, "BMW-GEN5",
+            "type",                "",                DATA_STRING, "TPMS",
+            "brand",               "Brand",           DATA_INT,    brand_id,
+            "id",                  "",                DATA_STRING, id_str,
+            "pressure_kPa",        "Pressure",        DATA_FORMAT, "%.1f kPa", DATA_DOUBLE, (double)pressure_kPa,
+            "temperature_C",       "Temperature",     DATA_FORMAT, "%.1f C",   DATA_DOUBLE, (double)temperature_C,
+            "flags1",              "",                DATA_INT,    flags1,
+            "flags2",              "",                DATA_INT,    flags2,
+            "flags3",              "",                DATA_INT,    flags3, // Nominal Pressure for brand HUF 0x03
+            "msg",                 "msg",             DATA_STRING, msg_str, // To remove after guess all tags
+            "mic",                 "Integrity",       DATA_STRING, "CRC",
+            NULL);
+    /* clang-format on */
+
+    decoder_output_data(decoder, data);
+    return 1;
+}
+
+static char const *const output_fields[] = {
+        "model",
+        "type",
+        "id",
+        "brand",
+        "battery_ok",
+        "pressure_kPa",
+        "flags1",
+        "flags2",
+        "flags3",
+        "msg",
+        "mic",
+        NULL,
+};
+
+r_device const tpms_bmw = {
+        .name        = "BMW Gen5 TPMS, multi-brand HUF, Continental, Schrader/Sensata",
+        .modulation  = FSK_PULSE_PCM,
+        .short_width = 25,
+        .long_width  = 25,
+        .reset_limit = 100,
+        .decode_fn   = &tpms_bmw_decode,
+        .fields      = output_fields,
+};