Skip to content

Commit

Permalink
Add manufacturer_data parser for contact sensor (#152)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdraco committed Dec 17, 2022
1 parent 94a86a2 commit e1894f0
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 6 deletions.
25 changes: 19 additions & 6 deletions switchbot/adv_parsers/contact.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,27 @@

def process_wocontact(data: bytes, mfr_data: bytes | None) -> dict[str, bool | int]:
"""Process woContact Sensor services data."""
battery = data[2] & 0b01111111
tested = bool(data[1] & 0b10000000)
contact_timeout = data[3] & 0b00000100 == 0b00000100
contact_open = data[3] & 0b00000010 == 0b00000010

if mfr_data and len(mfr_data) >= 13:
motion_detected = bool(mfr_data[7] & 0b10000000)
contact_open = bool(mfr_data[7] & 0b00010000)
button_count = mfr_data[12] & 0b00001111
is_light = bool(mfr_data[7] & 0b01000000)
else:
motion_detected = bool(data[1] & 0b01000000)
contact_open = data[3] & 0b00000010 == 0b00000010
button_count = data[8] & 0b00001111
is_light = bool(data[3] & 0b00000001)

return {
"tested": bool(data[1] & 0b10000000),
"motion_detected": bool(data[1] & 0b01000000),
"battery": data[2] & 0b01111111,
"tested": tested,
"motion_detected": motion_detected,
"battery": battery,
"contact_open": contact_open or contact_timeout, # timeout still means its open
"contact_timeout": contact_timeout,
"is_light": bool(data[3] & 0b00000001),
"button_count": (data[8] & 0b00001111),
"is_light": is_light,
"button_count": button_count,
}
139 changes: 139 additions & 0 deletions tests/test_adv_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,3 +408,142 @@ def test_parse_advertisement_data_curtain_firmware_six_fully_open():
device=ble_device,
rssi=-2,
)


def test_contact_sensor_mfr():
"""Test parsing adv data from new bot firmware."""
ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
adv_data = generate_advertisement_data(
manufacturer_data={2409: b"\xcb9\xcd\xc4=FA,\x00F\x01\x8f\xc4"},
service_data={
"0000fd3d-0000-1000-8000-00805f9b34fb": b"d\x00\xda\x04\x00F\x01\x8f\xc4"
},
tx_power=-127,
rssi=-70,
)
result = parse_advertisement_data(ble_device, adv_data)
assert result == SwitchBotAdvertisement(
address="aa:bb:cc:dd:ee:ff",
data={
"data": {
"battery": 90,
"button_count": 4,
"contact_open": True,
"contact_timeout": True,
"is_light": False,
"motion_detected": False,
"tested": False,
},
"isEncrypted": False,
"model": "d",
"modelFriendlyName": "Contact Sensor",
"modelName": SwitchbotModel.CONTACT_SENSOR,
"rawAdvData": b"d\x00\xda\x04\x00F\x01\x8f\xc4",
},
device=ble_device,
rssi=-70,
)


def test_contact_sensor_srv():
"""Test parsing adv data from new bot firmware."""
ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
adv_data = generate_advertisement_data(
service_data={
"0000fd3d-0000-1000-8000-00805f9b34fb": b"d\x00\xda\x04\x00F\x01\x8f\xc4"
},
tx_power=-127,
rssi=-70,
)
result = parse_advertisement_data(ble_device, adv_data)
assert result == SwitchBotAdvertisement(
address="aa:bb:cc:dd:ee:ff",
data={
"data": {
"battery": 90,
"button_count": 4,
"contact_open": True,
"contact_timeout": True,
"is_light": False,
"motion_detected": False,
"tested": False,
},
"isEncrypted": False,
"model": "d",
"modelFriendlyName": "Contact Sensor",
"modelName": SwitchbotModel.CONTACT_SENSOR,
"rawAdvData": b"d\x00\xda\x04\x00F\x01\x8f\xc4",
},
device=ble_device,
rssi=-70,
)


def test_contact_sensor_open():
"""Test parsing mfr adv data from new bot firmware."""
ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
adv_data = generate_advertisement_data(
manufacturer_data={2409: b"\xcb9\xcd\xc4=F\x84\x9c\x00\x17\x00QD"},
service_data={
"0000fd3d-0000-1000-8000-00805f9b34fb": b"d@\xda\x02\x00\x17\x00QD"
},
tx_power=-127,
rssi=-59,
)
result = parse_advertisement_data(ble_device, adv_data)
assert result == SwitchBotAdvertisement(
address="aa:bb:cc:dd:ee:ff",
data={
"data": {
"battery": 90,
"button_count": 4,
"contact_open": True,
"contact_timeout": False,
"is_light": False,
"motion_detected": True,
"tested": False,
},
"isEncrypted": False,
"model": "d",
"modelFriendlyName": "Contact Sensor",
"modelName": SwitchbotModel.CONTACT_SENSOR,
"rawAdvData": b"d@\xda\x02\x00\x17\x00QD",
},
device=ble_device,
rssi=-59,
)


def test_contact_sensor_closed():
"""Test parsing mfr adv data from new bot firmware."""
ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
adv_data = generate_advertisement_data(
manufacturer_data={2409: b"\xcb9\xcd\xc4=F\x89\x8c\x00+\x00\x19\x84"},
service_data={
"0000fd3d-0000-1000-8000-00805f9b34fb": b"d@\xda\x00\x00+\x00\x19\x84"
},
tx_power=-127,
rssi=-50,
)
result = parse_advertisement_data(ble_device, adv_data)
assert result == SwitchBotAdvertisement(
address="aa:bb:cc:dd:ee:ff",
data={
"data": {
"battery": 90,
"button_count": 4,
"contact_open": False,
"contact_timeout": False,
"is_light": False,
"motion_detected": True,
"tested": False,
},
"isEncrypted": False,
"model": "d",
"modelFriendlyName": "Contact Sensor",
"modelName": SwitchbotModel.CONTACT_SENSOR,
"rawAdvData": b"d@\xda\x00\x00+\x00\x19\x84",
},
device=ble_device,
rssi=-50,
)

0 comments on commit e1894f0

Please sign in to comment.