Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Linptech Pressure Sensor PS1BB #1368

Merged
merged 7 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions custom_components/ble_monitor/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,8 @@ def entity_registry_enabled_default(self):
"""Return if the entity should be enabled when first added to the entity registry."""
if self._device_type == "ATC":
return False
elif self.entity_description.key == 'reset':
return False
else:
return True

Expand Down
42 changes: 42 additions & 0 deletions custom_components/ble_monitor/ble_parser/xiaomi.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
0x3F0F: "RS1BB",
0x38BB: "PTX",
0x3531: "XMPIRO2SXS",
0x3F4C: "PS1BB",
}

# Structured objects for data conversions
Expand Down Expand Up @@ -759,6 +760,35 @@ def obj4818(xobj):
return {}


def obj483c(xobj):
"""Pressure Present State"""
return {"pressure state": xobj[0]}


def obj483d(xobj):
"""Pressure Present Duration"""
(duration,) = struct.unpack("<I", xobj)
return {"pressure present duration": duration}


def obj483e(xobj):
"""Pressure Not Present Duration"""
(duration,) = struct.unpack("<I", xobj)
return {"pressure not present duration": duration}


def obj483f(xobj):
"""Pressure present time set"""
(duration,) = struct.unpack("<I", xobj)
return {"pressure present time set": duration}


def obj4840(xobj):
"""Pressure Not Present Time Set"""
(duration,) = struct.unpack("<I", xobj)
return {"pressure not present time set": duration}


def obj4a01(xobj):
"""Low Battery"""
low_batt = xobj[0]
Expand Down Expand Up @@ -839,6 +869,12 @@ def obj4a1a(xobj):
return {}


def obj4a1c(xobj):
"""Device reset"""
reset = xobj[0]
return {"reset": reset}


def obj4c01(xobj):
"""Temperature"""
if len(xobj) == 4:
Expand Down Expand Up @@ -1095,6 +1131,11 @@ def obj5a16(xobj):
0x4810: obj4810,
0x4811: obj4811,
0x4818: obj4818,
0x483c: obj483c,
0x483d: obj483d,
0x483e: obj483e,
0x483f: obj483f,
0x4840: obj4840,
0x4a01: obj4a01,
0x4a08: obj4a08,
0x4a0c: obj4a0c,
Expand All @@ -1104,6 +1145,7 @@ def obj5a16(xobj):
0x4a12: obj4a12,
0x4a13: obj4a13,
0x4a1a: obj4a1a,
0x4a1c: obj4a1c,
0x4c01: obj4c01,
0x4c02: obj4c02,
0x4c03: obj4c03,
Expand Down
70 changes: 70 additions & 0 deletions custom_components/ble_monitor/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,26 @@ class BLEMonitorBinarySensorEntityDescription(
device_class=BinarySensorDeviceClass.POWER,
force_update=True,
),
BLEMonitorBinarySensorEntityDescription(
key="reset",
sensor_class="BaseBinarySensor",
update_behavior="Instantly",
name="reset",
unique_id="reset_",
icon="mdi:arrow-u-left-top",
device_class=None,
force_update=True,
),
BLEMonitorBinarySensorEntityDescription(
key="pressure state",
sensor_class="BaseBinarySensor",
update_behavior="Instantly",
name="pressure state",
unique_id="pressure_state_",
icon="mdi:car-brake-low-pressure",
device_class=None,
force_update=False,
),
)


Expand Down Expand Up @@ -1278,6 +1298,54 @@ class BLEMonitorBinarySensorEntityDescription(
suggested_display_precision=3,
state_class=SensorStateClass.MEASUREMENT,
),
BLEMonitorSensorEntityDescription(
key="pressure present duration",
sensor_class="InstantUpdateSensor",
update_behavior="Instantly",
name="pressure present duration",
unique_id="pressure_present_duration_",
icon="mdi:clock-time-eight",
native_unit_of_measurement="s",
device_class=None,
suggested_display_precision=0,
state_class=SensorStateClass.MEASUREMENT,
),
BLEMonitorSensorEntityDescription(
key="pressure not present duration",
sensor_class="InstantUpdateSensor",
update_behavior="Instantly",
name="pressure not present duration",
unique_id="pressure_not_present_duration_",
icon="mdi:clock-remove",
native_unit_of_measurement="s",
device_class=None,
suggested_display_precision=0,
state_class=SensorStateClass.MEASUREMENT,
),
BLEMonitorSensorEntityDescription(
key="pressure present time set",
sensor_class="InstantUpdateSensor",
update_behavior="Instantly",
name="pressure present time set",
unique_id="pressure_present_time_set_",
icon="mdi:clock-time-eight",
native_unit_of_measurement="s",
device_class=None,
suggested_display_precision=0,
state_class=SensorStateClass.MEASUREMENT,
),
BLEMonitorSensorEntityDescription(
key="pressure not present time set",
sensor_class="InstantUpdateSensor",
update_behavior="Instantly",
name="pressure not present time set",
unique_id="pressure_not_present_time_set_",
icon="mdi:clock-remove",
native_unit_of_measurement="s",
device_class=None,
suggested_display_precision=0,
state_class=SensorStateClass.MEASUREMENT,
),
BLEMonitorSensorEntityDescription(
key="current",
sensor_class="InstantUpdateSensor",
Expand Down Expand Up @@ -1780,6 +1848,7 @@ class BLEMonitorBinarySensorEntityDescription(
'K9BB-1BTN' : [["battery", "rssi"], ["one btn switch"], []],
'MS1BB(MI)' : [["battery", "rssi"], ["button"], ["opening"]],
'HS1BB(MI)' : [["illuminance", "battery", "rssi"], [], ["motion"]],
'PS1BB' : [["battery", "rssi", "pressure present duration", "pressure not present duration", "pressure present time set", "pressure not present time set"], [], ["reset", "pressure state"]],
'XMPIRO2SXS' : [["illuminance", "battery", "rssi"], [], ["motion"]],
'XMWXKG01YL' : [["rssi"], ["two btn switch left", "two btn switch right"], []],
'XMWXKG01LM' : [["battery", "rssi"], ["one btn switch"], []],
Expand Down Expand Up @@ -1919,6 +1988,7 @@ class BLEMonitorBinarySensorEntityDescription(
'K9BB-1BTN' : 'Linptech',
'MS1BB(MI)' : 'Linptech',
'HS1BB(MI)' : 'Linptech',
'PS1BB' : 'Linptech',
'XMWXKG01YL' : 'Xiaomi',
'XMWXKG01LM' : 'Xiaomi',
'PTX' : 'Xiaomi',
Expand Down
2 changes: 1 addition & 1 deletion custom_components/ble_monitor/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@
"btsocket>=0.2.0",
"pyric>=0.1.6.3"
],
"version": "12.11.3"
"version": "12.12.0"
}
9 changes: 8 additions & 1 deletion custom_components/ble_monitor/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,10 @@ class BaseSensor(RestoreSensor, SensorEntity):
# | |**distance
# | |**distance mm
# | |**duration
# | |**pressure present duration
# | |**pressure not present duration
# | |**pressure present time set
# | |**pressure present not time set
# | |**current
# | |**speed
# | |**gyroscope
Expand Down Expand Up @@ -527,7 +531,10 @@ def entity_registry_enabled_default(self) -> bool:
if not self.is_beacon:
return True

if self.entity_description.key in ['cypress temperature', 'cypress humidity', 'uuid']:
if self.entity_description.key in [
'cypress temperature', 'cypress humidity', 'uuid', 'pressure present duration',
'pressure not present duration', 'pressure present time set', 'pressure not present time set'
]:
return False

return True
Expand Down
26 changes: 26 additions & 0 deletions custom_components/ble_monitor/test/test_xiaomi_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,32 @@ def test_Xiaomi_RS1BB(self):
assert sensor_msg["moisture detected"] == 0
assert sensor_msg["rssi"] == -64

def test_Xiaomi_PS1BB(self):
"""Test Xiaomi parser for Linptech PS1BB."""
self.aeskeys = {}
data_string = "043E26020100009bd60f38c1a41a020106161695fe48594c3f21f4957fb405c9cf040000d8252537CC"
data = bytes(bytearray.fromhex(data_string))

aeskey = "9b4441bc2505db3c3484bae6b7631b34"

is_ext_packet = True if data[3] == 0x0D else False
mac = (data[8 if is_ext_packet else 7:14 if is_ext_packet else 13])[::-1]
mac_address = mac.hex()
p_mac = bytes.fromhex(mac_address.replace(":", "").lower())
p_key = bytes.fromhex(aeskey.lower())
self.aeskeys[p_mac] = p_key
# pylint: disable=unused-variable
ble_parser = BleParser(aeskeys=self.aeskeys)
sensor_msg, tracker_msg = ble_parser.parse_raw_data(data)

assert sensor_msg["firmware"] == "Xiaomi (MiBeacon V5 encrypted)"
assert sensor_msg["type"] == "PS1BB"
assert sensor_msg["mac"] == "A4C1380FD69B"
assert sensor_msg["packet"] == 33
assert sensor_msg["data"]
assert sensor_msg["pressure present duration"] == 7800
assert sensor_msg["rssi"] == -52

def test_Xiaomi_MJYD02YL(self):
"""Test Xiaomi parser for MJYD02YL."""

Expand Down
22 changes: 22 additions & 0 deletions docs/_devices/Linptech PS1BB.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
manufacturer: Linptech
name: Linptech Pressure Sensor
model: PS1BB
image: Linptech_PS1BB.png
physical_description:
broadcasted_properties:
- reset
- battery
- pressure state
- pressure present duration
- pressure not present duration
- pressure present time set
- pressure not present time set
- rssi
broadcasted_property_notes:
broadcast_rate:
active_scan:
encryption_key: true
custom_firmware:
notes:
---
Binary file added docs/assets/images/Linptech_PS1BB.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading