Skip to content

Commit

Permalink
feat: add raw hex sensor (#91)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ernst79 authored Oct 1, 2023
1 parent 4619caa commit 6f9969e
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 1 deletion.
12 changes: 12 additions & 0 deletions src/bthome_ble/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,21 @@ class MeasTypes:
class ExtendedSensorDeviceClass(BaseDeviceClass):
"""Device class for additional sensors (compared to sensor-state-data)."""

# Raw hex data
RAW = "raw"

# Text
TEXT = "text"


class ExtendedSensorLibrary(SensorLibrary):
"""Sensor Library for additional sensors (compared to sensor-state-data)."""

RAW__NONE = description.BaseSensorDescription(
device_class=ExtendedSensorDeviceClass.RAW,
native_unit_of_measurement=None,
)

TEXT__NONE = description.BaseSensorDescription(
device_class=ExtendedSensorDeviceClass.TEXT,
native_unit_of_measurement=None,
Expand Down Expand Up @@ -382,4 +390,8 @@ class ExtendedSensorLibrary(SensorLibrary):
meas_format=ExtendedSensorLibrary.TEXT__NONE,
data_format="string",
),
0x54: MeasTypes(
meas_format=ExtendedSensorLibrary.RAW__NONE,
data_format="raw",
),
}
9 changes: 8 additions & 1 deletion src/bthome_ble/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ def parse_float(data_obj: bytes, factor: float = 1.0) -> float | None:
return round(val * factor, decimal_places)


def parse_raw(data_obj: bytes) -> str | None:
"""Convert bytes to raw hex string."""
return data_obj.hex()


def parse_string(data_obj: bytes) -> str | None:
"""Convert bytes to string."""
try:
Expand Down Expand Up @@ -397,7 +402,7 @@ def _parse_payload(self, payload: bytes, sw_version: int) -> bool:
prev_obj_meas_type = obj_meas_type
obj_data_format = MEAS_TYPES[obj_meas_type].data_format

if obj_data_format == "string":
if obj_data_format in ["raw", "string"]:
obj_data_length = payload[obj_start + 1]
obj_data_start = obj_start + 2
else:
Expand Down Expand Up @@ -467,6 +472,8 @@ def _parse_payload(self, payload: bytes, sw_version: int) -> bool:
value = parse_float(meas["measurement data"], meas_factor)
elif meas["data format"] == 3 or meas["data format"] == "string":
value = parse_string(meas["measurement data"])
elif meas["data format"] == 4 or meas["data format"] == "raw":
value = parse_raw(meas["measurement data"])
elif meas["data format"] == 5 or meas["data format"] == "timestamp":
value = parse_timestamp(meas["measurement data"])
else:
Expand Down
44 changes: 44 additions & 0 deletions tests/test_parser_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
KEY_PM10 = DeviceKey(key="pm10", device_id=None)
KEY_POWER = DeviceKey(key="power", device_id=None)
KEY_PRESSURE = DeviceKey(key="pressure", device_id=None)
KEY_RAW = DeviceKey(key="raw", device_id=None)
KEY_ROTATION = DeviceKey(key="rotation", device_id=None)
KEY_SIGNAL_STRENGTH = DeviceKey(key="signal_strength", device_id=None)
KEY_SPEED = DeviceKey(key="speed", device_id=None)
Expand Down Expand Up @@ -2503,6 +2504,49 @@ def test_bthome_text(caplog):
)


def test_bthome_raw(caplog):
"""Test BTHome parser for raw hex data."""
data_string = b"\x44\x54\x0C\x48\x65\x6C\x6C\x6F\x20\x57\x6F\x72\x6C\x64\x21"
advertisement = bytes_to_service_info(
data_string, local_name="TEST DEVICE", address="A4:C1:38:8D:18:B2"
)

device = BTHomeBluetoothDeviceData()

assert device.update(advertisement) == SensorUpdate(
title="TEST DEVICE 18B2",
devices={
None: SensorDeviceInfo(
name="TEST DEVICE 18B2",
manufacturer=None,
model="BTHome sensor",
sw_version="BTHome BLE v2",
hw_version=None,
)
},
entity_descriptions={
KEY_RAW: SensorDescription(
device_key=KEY_RAW,
device_class=ExtendedSensorDeviceClass.RAW,
native_unit_of_measurement=None,
),
KEY_SIGNAL_STRENGTH: SensorDescription(
device_key=KEY_SIGNAL_STRENGTH,
device_class=SensorDeviceClass.SIGNAL_STRENGTH,
native_unit_of_measurement=Units.SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
),
},
entity_values={
KEY_RAW: SensorValue(
device_key=KEY_RAW, name="Raw", native_value="48656c6c6f20576f726c6421"
),
KEY_SIGNAL_STRENGTH: SensorValue(
device_key=KEY_SIGNAL_STRENGTH, name="Signal Strength", native_value=-60
),
},
)


def test_bthome_text_invalid(caplog):
"""Test BTHome parser for text sensor with invalid format."""
data_string = b"\x44\x53\x01\x87"
Expand Down

0 comments on commit 6f9969e

Please sign in to comment.