Skip to content

Commit b484a17

Browse files
committed
Add holyiot
1 parent 55d314c commit b484a17

File tree

5 files changed

+109
-1
lines changed

5 files changed

+109
-1
lines changed

custom_components/ble_monitor/ble_parser/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from .helpers import to_mac, to_unformatted_mac
1717
from .bthome import parse_bthome
1818
from .hhcc import parse_hhcc
19+
from .holyiot import parse_holyiot
1920
from .hormann import parse_hormann
2021
from .ibeacon import parse_ibeacon
2122
from .inkbird import parse_inkbird
@@ -207,6 +208,10 @@ def parse_advertisement(
207208
# UUID16 = User Data and Bond Management (used by BTHome)
208209
sensor_data = parse_bthome(self, service_data, uuid16, mac, rssi)
209210
break
211+
elif uuid16 == 0x5242:
212+
# UUID16 = HolyIOT
213+
sensor_data = parse_holyiot(self, service_data, mac, rssi)
214+
break
210215
elif uuid16 in [0xAA20, 0xAA21, 0xAA22] and local_name == "ECo":
211216
# UUID16 = Relsib
212217
sensor_data = parse_relsib(self, service_data, mac, rssi)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""Parser for HolyIOT BLE advertisements"""
2+
import logging
3+
from struct import unpack
4+
5+
from .helpers import (
6+
to_mac,
7+
to_unformatted_mac,
8+
)
9+
10+
_LOGGER = logging.getLogger(__name__)
11+
12+
13+
def parse_holyiot(self, data, source_mac, rssi):
14+
"""HolyIOT parser"""
15+
msg_length = len(data)
16+
firmware = "HolyIOT"
17+
result = {"firmware": firmware}
18+
19+
if msg_length == 17:
20+
device_type = "HolyIOT BLE tracker"
21+
holyiot_mac = data[6:12]
22+
if holyiot_mac != source_mac:
23+
_LOGGER.debug(
24+
"HolyIOT MAC address doesn't match data MAC address. Data: %s with source mac: %s and HolyIOT mac: %s",
25+
data.hex(),
26+
source_mac,
27+
holyiot_mac,
28+
)
29+
return None
30+
batt = data[5]
31+
meas_type = data[14]
32+
meas_value, = unpack(">H", data[15:17])
33+
34+
if meas_type == 4:
35+
measurement_type = "vibration"
36+
elif meas_type == 6:
37+
measurement_type = "remote single press"
38+
else:
39+
return None
40+
result.update(
41+
{
42+
measurement_type: meas_value,
43+
"battery": batt
44+
}
45+
)
46+
else:
47+
if self.report_unknown == "HolyIOT":
48+
_LOGGER.info(
49+
"BLE ADV from UNKNOWN HolyIOT DEVICE: RSSI: %s, MAC: %s, ADV: %s",
50+
rssi,
51+
to_mac(source_mac),
52+
data.hex()
53+
)
54+
return None
55+
56+
# check for MAC presence in sensor whitelist, if needed
57+
if self.discovery is False and holyiot_mac.lower() not in self.sensor_whitelist:
58+
_LOGGER.debug("Discovery is disabled. MAC: %s is not whitelisted!", to_mac(holyiot_mac))
59+
return None
60+
61+
result.update({
62+
"rssi": rssi,
63+
"mac": to_unformatted_mac(holyiot_mac),
64+
"type": device_type,
65+
"packet": "no packet id",
66+
"firmware": firmware,
67+
"data": True
68+
})
69+
return result

custom_components/ble_monitor/const.py

+12
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,16 @@ class BLEMonitorBinarySensorEntityDescription(
304304
device_class=None,
305305
force_update=False,
306306
),
307+
BLEMonitorBinarySensorEntityDescription(
308+
key="vibration",
309+
sensor_class="BaseBinarySensor",
310+
update_behavior="Instantly",
311+
name="ble vibration",
312+
unique_id="vi_",
313+
icon="mdi:vibration",
314+
device_class=BinarySensorDeviceClass.VIBRATION,
315+
force_update=True,
316+
),
307317
BLEMonitorBinarySensorEntityDescription(
308318
key="dropping",
309319
sensor_class="BaseBinarySensor",
@@ -1290,6 +1300,7 @@ class BLEMonitorBinarySensorEntityDescription(
12901300
'K6 Sensor Beacon' : [["temperature", "humidity", "acceleration", "voltage", "battery", "rssi"], [], []],
12911301
'DSL-C08' : [["battery", "rssi", "voltage"], [], ["lock", "childlock"]],
12921302
'SmartDry cloth dryer' : [["temperature", "humidity", "voltage", "battery", "shake", "rssi"], [], ["switch"]],
1303+
'HolyIOT BLE tracker' : [["battery", "rssi"], [], ["remote single press", "vibration"]],
12931304
}
12941305

12951306
# Sensor manufacturer dictionary
@@ -1420,6 +1431,7 @@ class BLEMonitorBinarySensorEntityDescription(
14201431
'Acconeer XM122' : 'Acconeer',
14211432
'K6 Sensor Beacon' : 'KKM',
14221433
'SmartDry cloth dryer' : 'SmartDry',
1434+
'HolyIOT BLE tracker' : 'HolyIOT',
14231435
}
14241436

14251437

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.0.0"
17+
"version": "12.0.1-beta"
1818
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""The tests for the HolyIOT ble_parser."""
2+
from ble_monitor.ble_parser import BleParser
3+
4+
5+
class TestHolyIOT:
6+
"""Tests for the HolyIOT parser"""
7+
def test_holyiot(self):
8+
"""Test HolyIOT parser for BLE tracker mini."""
9+
data_string = "043e49020102018ef1f645b5c63d0201061AFF4C0002159976AED5F58C49AF85EBD0AC7281E3F6271B4CB9240D0962696E2D747261636B657200101642524164C6B545F6F18E0606060000CC"
10+
data = bytes(bytearray.fromhex(data_string))
11+
# pylint: disable=unused-variable
12+
ble_parser = BleParser()
13+
sensor_msg, tracker_msg = ble_parser.parse_raw_data(data)
14+
15+
assert sensor_msg["firmware"] == "HolyIOT"
16+
assert sensor_msg["type"] == "HolyIOT BLE tracker"
17+
assert sensor_msg["mac"] == "C6B545F6F18E"
18+
assert sensor_msg["packet"] == "no packet id"
19+
assert sensor_msg["data"]
20+
assert sensor_msg["battery"] == 100
21+
assert not sensor_msg["remote single press"]
22+
assert sensor_msg["rssi"] == -52

0 commit comments

Comments
 (0)