Skip to content

Commit 5cdcef2

Browse files
authored
Merge pull request #1368 from custom-components/PS1BB
Add support for Linptech Pressure Sensor PS1BB
2 parents ba9fb8e + 0a4f428 commit 5cdcef2

File tree

8 files changed

+171
-2
lines changed

8 files changed

+171
-2
lines changed

custom_components/ble_monitor/binary_sensor.py

+2
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,8 @@ def entity_registry_enabled_default(self):
361361
"""Return if the entity should be enabled when first added to the entity registry."""
362362
if self._device_type == "ATC":
363363
return False
364+
elif self.entity_description.key == 'reset':
365+
return False
364366
else:
365367
return True
366368

custom_components/ble_monitor/ble_parser/xiaomi.py

+42
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
0x3F0F: "RS1BB",
7878
0x38BB: "PTX",
7979
0x3531: "XMPIRO2SXS",
80+
0x3F4C: "PS1BB",
8081
}
8182

8283
# Structured objects for data conversions
@@ -759,6 +760,35 @@ def obj4818(xobj):
759760
return {}
760761

761762

763+
def obj483c(xobj):
764+
"""Pressure Present State"""
765+
return {"pressure state": xobj[0]}
766+
767+
768+
def obj483d(xobj):
769+
"""Pressure Present Duration"""
770+
(duration,) = struct.unpack("<I", xobj)
771+
return {"pressure present duration": duration}
772+
773+
774+
def obj483e(xobj):
775+
"""Pressure Not Present Duration"""
776+
(duration,) = struct.unpack("<I", xobj)
777+
return {"pressure not present duration": duration}
778+
779+
780+
def obj483f(xobj):
781+
"""Pressure present time set"""
782+
(duration,) = struct.unpack("<I", xobj)
783+
return {"pressure present time set": duration}
784+
785+
786+
def obj4840(xobj):
787+
"""Pressure Not Present Time Set"""
788+
(duration,) = struct.unpack("<I", xobj)
789+
return {"pressure not present time set": duration}
790+
791+
762792
def obj4a01(xobj):
763793
"""Low Battery"""
764794
low_batt = xobj[0]
@@ -839,6 +869,12 @@ def obj4a1a(xobj):
839869
return {}
840870

841871

872+
def obj4a1c(xobj):
873+
"""Device reset"""
874+
reset = xobj[0]
875+
return {"reset": reset}
876+
877+
842878
def obj4c01(xobj):
843879
"""Temperature"""
844880
if len(xobj) == 4:
@@ -1095,6 +1131,11 @@ def obj5a16(xobj):
10951131
0x4810: obj4810,
10961132
0x4811: obj4811,
10971133
0x4818: obj4818,
1134+
0x483c: obj483c,
1135+
0x483d: obj483d,
1136+
0x483e: obj483e,
1137+
0x483f: obj483f,
1138+
0x4840: obj4840,
10981139
0x4a01: obj4a01,
10991140
0x4a08: obj4a08,
11001141
0x4a0c: obj4a0c,
@@ -1104,6 +1145,7 @@ def obj5a16(xobj):
11041145
0x4a12: obj4a12,
11051146
0x4a13: obj4a13,
11061147
0x4a1a: obj4a1a,
1148+
0x4a1c: obj4a1c,
11071149
0x4c01: obj4c01,
11081150
0x4c02: obj4c02,
11091151
0x4c03: obj4c03,

custom_components/ble_monitor/const.py

+70
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,26 @@ class BLEMonitorBinarySensorEntityDescription(
523523
device_class=BinarySensorDeviceClass.POWER,
524524
force_update=True,
525525
),
526+
BLEMonitorBinarySensorEntityDescription(
527+
key="reset",
528+
sensor_class="BaseBinarySensor",
529+
update_behavior="Instantly",
530+
name="reset",
531+
unique_id="reset_",
532+
icon="mdi:arrow-u-left-top",
533+
device_class=None,
534+
force_update=True,
535+
),
536+
BLEMonitorBinarySensorEntityDescription(
537+
key="pressure state",
538+
sensor_class="BaseBinarySensor",
539+
update_behavior="Instantly",
540+
name="pressure state",
541+
unique_id="pressure_state_",
542+
icon="mdi:car-brake-low-pressure",
543+
device_class=None,
544+
force_update=False,
545+
),
526546
)
527547

528548

@@ -1278,6 +1298,54 @@ class BLEMonitorBinarySensorEntityDescription(
12781298
suggested_display_precision=3,
12791299
state_class=SensorStateClass.MEASUREMENT,
12801300
),
1301+
BLEMonitorSensorEntityDescription(
1302+
key="pressure present duration",
1303+
sensor_class="InstantUpdateSensor",
1304+
update_behavior="Instantly",
1305+
name="pressure present duration",
1306+
unique_id="pressure_present_duration_",
1307+
icon="mdi:clock-time-eight",
1308+
native_unit_of_measurement="s",
1309+
device_class=None,
1310+
suggested_display_precision=0,
1311+
state_class=SensorStateClass.MEASUREMENT,
1312+
),
1313+
BLEMonitorSensorEntityDescription(
1314+
key="pressure not present duration",
1315+
sensor_class="InstantUpdateSensor",
1316+
update_behavior="Instantly",
1317+
name="pressure not present duration",
1318+
unique_id="pressure_not_present_duration_",
1319+
icon="mdi:clock-remove",
1320+
native_unit_of_measurement="s",
1321+
device_class=None,
1322+
suggested_display_precision=0,
1323+
state_class=SensorStateClass.MEASUREMENT,
1324+
),
1325+
BLEMonitorSensorEntityDescription(
1326+
key="pressure present time set",
1327+
sensor_class="InstantUpdateSensor",
1328+
update_behavior="Instantly",
1329+
name="pressure present time set",
1330+
unique_id="pressure_present_time_set_",
1331+
icon="mdi:clock-time-eight",
1332+
native_unit_of_measurement="s",
1333+
device_class=None,
1334+
suggested_display_precision=0,
1335+
state_class=SensorStateClass.MEASUREMENT,
1336+
),
1337+
BLEMonitorSensorEntityDescription(
1338+
key="pressure not present time set",
1339+
sensor_class="InstantUpdateSensor",
1340+
update_behavior="Instantly",
1341+
name="pressure not present time set",
1342+
unique_id="pressure_not_present_time_set_",
1343+
icon="mdi:clock-remove",
1344+
native_unit_of_measurement="s",
1345+
device_class=None,
1346+
suggested_display_precision=0,
1347+
state_class=SensorStateClass.MEASUREMENT,
1348+
),
12811349
BLEMonitorSensorEntityDescription(
12821350
key="current",
12831351
sensor_class="InstantUpdateSensor",
@@ -1780,6 +1848,7 @@ class BLEMonitorBinarySensorEntityDescription(
17801848
'K9BB-1BTN' : [["battery", "rssi"], ["one btn switch"], []],
17811849
'MS1BB(MI)' : [["battery", "rssi"], ["button"], ["opening"]],
17821850
'HS1BB(MI)' : [["illuminance", "battery", "rssi"], [], ["motion"]],
1851+
'PS1BB' : [["battery", "rssi", "pressure present duration", "pressure not present duration", "pressure present time set", "pressure not present time set"], [], ["reset", "pressure state"]],
17831852
'XMPIRO2SXS' : [["illuminance", "battery", "rssi"], [], ["motion"]],
17841853
'XMWXKG01YL' : [["rssi"], ["two btn switch left", "two btn switch right"], []],
17851854
'XMWXKG01LM' : [["battery", "rssi"], ["one btn switch"], []],
@@ -1919,6 +1988,7 @@ class BLEMonitorBinarySensorEntityDescription(
19191988
'K9BB-1BTN' : 'Linptech',
19201989
'MS1BB(MI)' : 'Linptech',
19211990
'HS1BB(MI)' : 'Linptech',
1991+
'PS1BB' : 'Linptech',
19221992
'XMWXKG01YL' : 'Xiaomi',
19231993
'XMWXKG01LM' : 'Xiaomi',
19241994
'PTX' : 'Xiaomi',

custom_components/ble_monitor/manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@
1414
"btsocket>=0.2.0",
1515
"pyric>=0.1.6.3"
1616
],
17-
"version": "12.11.3"
17+
"version": "12.12.0"
1818
}

custom_components/ble_monitor/sensor.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,10 @@ class BaseSensor(RestoreSensor, SensorEntity):
351351
# | |**distance
352352
# | |**distance mm
353353
# | |**duration
354+
# | |**pressure present duration
355+
# | |**pressure not present duration
356+
# | |**pressure present time set
357+
# | |**pressure present not time set
354358
# | |**current
355359
# | |**speed
356360
# | |**gyroscope
@@ -527,7 +531,10 @@ def entity_registry_enabled_default(self) -> bool:
527531
if not self.is_beacon:
528532
return True
529533

530-
if self.entity_description.key in ['cypress temperature', 'cypress humidity', 'uuid']:
534+
if self.entity_description.key in [
535+
'cypress temperature', 'cypress humidity', 'uuid', 'pressure present duration',
536+
'pressure not present duration', 'pressure present time set', 'pressure not present time set'
537+
]:
531538
return False
532539

533540
return True

custom_components/ble_monitor/test/test_xiaomi_parser.py

+26
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,32 @@ def test_Xiaomi_RS1BB(self):
366366
assert sensor_msg["moisture detected"] == 0
367367
assert sensor_msg["rssi"] == -64
368368

369+
def test_Xiaomi_PS1BB(self):
370+
"""Test Xiaomi parser for Linptech PS1BB."""
371+
self.aeskeys = {}
372+
data_string = "043E26020100009bd60f38c1a41a020106161695fe48594c3f21f4957fb405c9cf040000d8252537CC"
373+
data = bytes(bytearray.fromhex(data_string))
374+
375+
aeskey = "9b4441bc2505db3c3484bae6b7631b34"
376+
377+
is_ext_packet = True if data[3] == 0x0D else False
378+
mac = (data[8 if is_ext_packet else 7:14 if is_ext_packet else 13])[::-1]
379+
mac_address = mac.hex()
380+
p_mac = bytes.fromhex(mac_address.replace(":", "").lower())
381+
p_key = bytes.fromhex(aeskey.lower())
382+
self.aeskeys[p_mac] = p_key
383+
# pylint: disable=unused-variable
384+
ble_parser = BleParser(aeskeys=self.aeskeys)
385+
sensor_msg, tracker_msg = ble_parser.parse_raw_data(data)
386+
387+
assert sensor_msg["firmware"] == "Xiaomi (MiBeacon V5 encrypted)"
388+
assert sensor_msg["type"] == "PS1BB"
389+
assert sensor_msg["mac"] == "A4C1380FD69B"
390+
assert sensor_msg["packet"] == 33
391+
assert sensor_msg["data"]
392+
assert sensor_msg["pressure present duration"] == 7800
393+
assert sensor_msg["rssi"] == -52
394+
369395
def test_Xiaomi_MJYD02YL(self):
370396
"""Test Xiaomi parser for MJYD02YL."""
371397

docs/_devices/Linptech PS1BB.md

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
manufacturer: Linptech
3+
name: Linptech Pressure Sensor
4+
model: PS1BB
5+
image: Linptech_PS1BB.png
6+
physical_description:
7+
broadcasted_properties:
8+
- reset
9+
- battery
10+
- pressure state
11+
- pressure present duration
12+
- pressure not present duration
13+
- pressure present time set
14+
- pressure not present time set
15+
- rssi
16+
broadcasted_property_notes:
17+
broadcast_rate:
18+
active_scan:
19+
encryption_key: true
20+
custom_firmware:
21+
notes:
22+
---

docs/assets/images/Linptech_PS1BB.png

7.55 KB
Loading

0 commit comments

Comments
 (0)