diff --git a/custom_components/ble_monitor/ble_parser/__init__.py b/custom_components/ble_monitor/ble_parser/__init__.py index 2ff652de..1ceb0bf4 100644 --- a/custom_components/ble_monitor/ble_parser/__init__.py +++ b/custom_components/ble_monitor/ble_parser/__init__.py @@ -29,6 +29,7 @@ from .kegtron import parse_kegtron from .kkm import parse_kkm from .laica import parse_laica +from .michelin import parse_michelin_tms from .mikrotik import parse_mikrotik from .miscale import parse_miscale from .moat import parse_moat @@ -297,6 +298,10 @@ def parse_advertisement( comp_id = (man_spec_data[3] << 8) | man_spec_data[2] data_len = man_spec_data[0] # Filter on Company Identifier + if comp_id == 0x0828: + # Michelin TMS + sensor_data = parse_michelin_tms(self, man_spec_data, mac) + break if comp_id == 0x0001 and data_len in [0x09, 0x0C, 0x22, 0x25]: # Govee H5101/H5102/H5106/H5177 sensor_data = parse_govee(self, man_spec_data, service_class_uuid16, local_name, mac) diff --git a/custom_components/ble_monitor/ble_parser/michelin.py b/custom_components/ble_monitor/ble_parser/michelin.py new file mode 100644 index 00000000..7d7c4986 --- /dev/null +++ b/custom_components/ble_monitor/ble_parser/michelin.py @@ -0,0 +1,50 @@ +"""Parser for Michelin TMS BLE advertisements.""" +import logging +from struct import unpack + +from .helpers import to_mac, to_unformatted_mac + +_LOGGER = logging.getLogger(__name__) + + +def parse_michelin_tms(self, data: bytes, mac: bytes): + """Parser for Michelin TMS.""" + msg_length = len(data) + device_type = "TMS" + firmware = "TMS" + result = {"firmware": firmware} + frame_type = data[5] + if frame_type in [0x03, 0x04]: + if msg_length != 18: + _LOGGER.error("Found %s bytes from sensor: %s", msg_length, to_mac(mac)) + return + (raw_temp, raw_volt, absolute_pressure_bar, tyre_id, steps, frame_counter) = unpack( + "=0.3.0", "pyric>=0.1.6.3" ], - "version": "13.11.1" + "version": "13.12.0" } diff --git a/custom_components/ble_monitor/test/test_michelin.py b/custom_components/ble_monitor/test/test_michelin.py new file mode 100644 index 00000000..64e8f6d0 --- /dev/null +++ b/custom_components/ble_monitor/test/test_michelin.py @@ -0,0 +1,26 @@ +"""The tests for the Michelin TMS ble_parser.""" +from ble_monitor.ble_parser import BleParser + + +class TestMichelin: + """Tests for the Michelin TMS parser""" + def test_parse_michelin_tms(self): + data_string = "043e2102010300e07c03a703bc1502010611ff280801034fc8d403505643017d511e00bc" + data = bytes(bytearray.fromhex(data_string)) + + # pylint: disable=unused-variable + ble_parser = BleParser() + sensor_msg, tracker_msg = ble_parser.parse_raw_data(data) + + assert sensor_msg["firmware"] == "TMS" + assert sensor_msg["type"] == "TMS" + assert sensor_msg["mac"] == "BC03A7037CE0" + assert sensor_msg["packet"] == "no packet id" + assert sensor_msg["data"] == True + assert sensor_msg["temperature"] == 19 + assert sensor_msg["voltage"] == 3.0 + assert sensor_msg["pressure"] == 980 + assert sensor_msg["count"] == 1986941 + assert sensor_msg["steps"] == 1 + assert sensor_msg["text"] == "PVC" + assert sensor_msg["rssi"] == -68 diff --git a/docs/_devices/Michelin_TMS.md b/docs/_devices/Michelin_TMS.md new file mode 100644 index 00000000..89846764 --- /dev/null +++ b/docs/_devices/Michelin_TMS.md @@ -0,0 +1,22 @@ +--- +manufacturer: MFP Michelin +name: "TMS" +model: TMS +image: "Michelin_TMS_AL.jpg" +physical_description: "Round body, no screen" +broadcasted_properties: + - temperature + - absolute pressure + - battery + - tire ID + - step (internal FSM) + - count (number of transmitted frames) + - rssi +broadcasted_property_notes: +broadcast_rate: +active_scan: +encryption_key: +custom_firmware: +notes: + - Sold under TMS AF, AL and AQ +--- diff --git a/docs/assets/images/Michelin_TMS_AL.jpg b/docs/assets/images/Michelin_TMS_AL.jpg new file mode 100644 index 00000000..21bf36c8 Binary files /dev/null and b/docs/assets/images/Michelin_TMS_AL.jpg differ