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

PDU status custom errors #64

Merged
merged 1 commit into from
Feb 6, 2022
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
47 changes: 12 additions & 35 deletions aiohomekit/controller/coap/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,15 @@ async def post_bytes(self, payload: bytes, timeout: int = 16.0):

async def post(
self, opcode: OpCode, iid: int, data: bytes
) -> tuple[int, bytes | PDUStatus | ValueError]:
) -> tuple[int, bytes | PDUStatus]:
tid = random.randint(1, 254)
req_pdu = encode_pdu(opcode, tid, iid, data)
res_pdu = await self.post_bytes(req_pdu)
return decode_pdu(tid, res_pdu)

async def post_all(
self, opcode: OpCode, iids: list[int], data: list[bytes]
) -> list[bytes | PDUStatus | ValueError]:
) -> list[bytes | PDUStatus]:
req_pdu = encode_all_pdus(opcode, iids, data)
res_pdu = await self.post_bytes(req_pdu)

Expand Down Expand Up @@ -478,8 +478,16 @@ async def read_characteristics(self, ids: list[tuple[int, int]]):

results = dict()
for (idx, result) in enumerate(pdu_results):
if isinstance(result, bytes):
aid_iid = ids[idx]
aid_iid = ids[idx]
if isinstance(result, PDUStatus):
logger.warning(
"Failed to read aid %d iid %d" % (int(aid_iid[0]), int(aid_iid[1]))
)
results[aid_iid] = {
"description": result.description,
"status": -result.value, # XXX
}
else:
# decode TLV to get byte value
value = decode_pdu_03(result) if len(result) > 0 else b""
# find characteristic so we can get the data type
Expand All @@ -502,20 +510,6 @@ async def read_characteristics(self, ids: list[tuple[int, int]]):
value,
)
)
else:
logger.warning(
"Failed to read aid %d iid %d" % (int(aid_iid[0]), int(aid_iid[1]))
)
if isinstance(result, PDUStatus):
results[aid_iid] = {
"description": result.description,
"status": -result.value, # XXX
}
else:
results[aid_iid] = {
"description": str(result),
"status": -777, # XXX something went badly wrong
}

logger.debug(f"Read characteristics: {results!r}")
return results
Expand Down Expand Up @@ -555,11 +549,6 @@ async def write_characteristics(self, ids_values: list[tuple[int, int, Any]]):
"descripton": result.description,
"status": -result.value, # XXX
}
elif isinstance(result, ValueError):
results[key] = {
"desciption": str(result),
"status": -777, # XXX something went badly wrong
}
else:
logger.debug(
"Wrote value for aid %d iid %d"
Expand All @@ -585,11 +574,6 @@ async def subscribe_to(self, ids: list[tuple[int, int]]):
"descripton": result.description,
"status": -result.value, # XXX
}
elif isinstance(result, ValueError):
results[key] = {
"desciption": str(result),
"status": -777, # XXX something went badly wrong
}
else:
logger.debug(
"Subscribed to aid %d iid %d"
Expand All @@ -615,11 +599,6 @@ async def unsubscribe_from(self, ids: list[tuple[int, int]]):
"descripton": result.description,
"status": -result.value, # XXX
}
elif isinstance(result, ValueError):
results[key] = {
"desciption": str(result),
"status": -777, # XXX something went badly wrong
}
else:
logger.debug(
"Unsubscribed from aid %d iid %d"
Expand Down Expand Up @@ -719,7 +698,5 @@ async def remove_pairing(self, pairing_id):
raise AuthenticationError("Remove pairing failed")
else:
raise UnknownError("Remove pairing failed")
elif isinstance(result, ValueError):
raise UnknownError("Remove pairing failed") from result

return True
17 changes: 8 additions & 9 deletions aiohomekit/controller/coap/pdu.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ class PDUStatus(EnumWithDescription):
INVALID_INSTANCE_ID = 4, "Invalid instance ID"
INSUFFICIENT_AUTHENTICATION = 5, "Insufficient authentication"
INVALID_REQUEST = 6, "Invalid request"
# custom error states
TID_MISMATCH = 256, "Transaction ID mismatch"
BAD_CONTROL = 257, "Control field doesn't have expected bits set"


def encode_pdu(opcode: OpCode, tid: int, iid: int, data: bytes) -> bytes:
Expand All @@ -70,9 +73,7 @@ def encode_all_pdus(opcode: OpCode, iids: list[int], data: list[bytes]) -> bytes
return req_pdu


def decode_pdu(
expected_tid: int, data: bytes
) -> tuple[int, bytes | PDUStatus | ValueError]:
def decode_pdu(expected_tid: int, data: bytes) -> tuple[int, bytes | PDUStatus]:
control, tid, status, body_len = struct.unpack("<BBBH", data[0:5])
status = PDUStatus(status)

Expand All @@ -87,17 +88,15 @@ def decode_pdu(
)

if tid != expected_tid:
msg = f"Expected transaction {expected_tid} but got transaction {tid}"
logger.warning(msg)
return (body_len, ValueError(msg))
logger.warning(f"Expected transaction {expected_tid} but got transaction {tid}")
return (body_len, PDUStatus.TID_MISMATCH)

if status != PDUStatus.SUCCESS:
logger.warning(f"Transaction {tid} failed with error {status}")
return (body_len, status)

if control & 0b0000_1110 != 0b0000_0010:
msg = f"Transaction {tid} control doesn't have response bit set"
logger.warning(msg)
return (body_len, ValueError(msg))
logger.warning(f"Transaction {tid} control doesn't have response bit set")
return (body_len, PDUStatus.BAD_CONTROL)

return body_len, data[5 : 5 + body_len]
4 changes: 2 additions & 2 deletions tests/test_controller_coap_pdu.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def test_decode_with_bad_tid():
res_len, res_val = decode_pdu(0x60, res_pdu)

assert res_len == 0
assert isinstance(res_val, ValueError)
assert res_val == PDUStatus.TID_MISMATCH


def test_decode_with_status_error():
Expand All @@ -84,4 +84,4 @@ def test_decode_with_bad_control():
res_len, res_val = decode_pdu(0x99, res_pdu)

assert res_len == 0
assert isinstance(res_val, ValueError)
assert res_val == PDUStatus.BAD_CONTROL