Skip to content
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
54 changes: 54 additions & 0 deletions tests/test_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import zigpy_deconz.types as t


def test_deconz_address_group():
data = b'\x01\x55\xaa'
extra = b'the rest of the owl'

addr, rest = t.DeconzAddress.deserialize(data + extra)
assert rest == extra
assert addr.address_mode == t.ADDRESS_MODE.GROUP
assert addr.address_mode == 1
assert addr.address == 0xaa55

assert addr.serialize() == data


def test_deconz_address_nwk():
data = b'\x02\x55\xaa'
extra = b'the rest of the owl'

addr, rest = t.DeconzAddress.deserialize(data + extra)
assert rest == extra
assert addr.address_mode == t.ADDRESS_MODE.NWK
assert addr.address_mode == 2
assert addr.address == 0xaa55

assert addr.serialize() == data


def test_deconz_address_ieee():
data = b'\x03\x55\xaa\xbb\xcc\xdd\xee\xef\xbe'
extra = b'the rest of the owl'

addr, rest = t.DeconzAddress.deserialize(data + extra)
assert rest == extra
assert addr.address_mode == t.ADDRESS_MODE.IEEE
assert addr.address_mode == 3
assert addr.address == [0xbe, 0xef, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x55]

assert addr.serialize() == data


def test_deconz_address_nwk_and_ieee():
data = b'\x04\x55\xaa\x88\x99\xbb\xcc\xdd\xee\xef\xbe'
extra = b'the rest of the owl'

addr, rest = t.DeconzAddress.deserialize(data + extra)
assert rest == extra
assert addr.address_mode == t.ADDRESS_MODE.NWK_AND_IEEE
assert addr.address_mode == 4
assert addr.ieee == [0xbe, 0xef, 0xee, 0xdd, 0xcc, 0xbb, 0x99, 0x88]
assert addr.address == 0xaa55

assert addr.serialize() == data
69 changes: 56 additions & 13 deletions zigpy_deconz/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ class ADDRESS_MODE(uint8_t, enum.Enum):
GROUP = 0x01
NWK = 0x02
IEEE = 0x03
NWK_AND_IEEE = 0x04


class Struct:
Expand Down Expand Up @@ -158,45 +159,87 @@ def __repr__(self):
return r


class EUI64(list):
def serialize(self):
assert len(self) == 8
return b''.join([i.serialize() for i in self[::-1]])

@classmethod
def deserialize(cls, data):
r = []
for i in range(8):
item, data = uint8_t.deserialize(data)
r.append(item)
return cls(r[::-1]), data

def __repr__(self):
return ':'.join('%02x' % i for i in self)

def __hash__(self):
return hash(repr(self))


class HexRepr:
_hex_len = 2

def __repr__(self):
return ('0x{:0' + str(self._hex_len) + 'x}').format(self)

def __str__(self):
return ('0x{:0' + str(self._hex_len) + 'x}').format(self)


class NWK(HexRepr, uint16_t):
_hex_len = 4


class DeconzAddress(Struct):
_fields = [
# The address format (AddressMode)
('address_mode', uint8_t),
('address_mode', ADDRESS_MODE),
('address', uint64_t),
]

@classmethod
def deserialize(cls, data):
r = cls()
mode, data = data[0], data[1:]
setattr(r, cls._fields[0][0], mode)
v = None
if mode in [ADDRESS_MODE.GROUP, ADDRESS_MODE.NWK]:
v, data = uint16_t.deserialize(data)
mode, data = ADDRESS_MODE.deserialize(data)
r.address_mode = mode
if mode in [ADDRESS_MODE.GROUP,
ADDRESS_MODE.NWK,
ADDRESS_MODE.NWK_AND_IEEE]:
r.address, data = NWK.deserialize(data)
elif mode == ADDRESS_MODE.IEEE:
v, data = uint64_t.deserialize(data)
setattr(r, cls._fields[1][0], v)
r.address, data = EUI64.deserialize(data)
if mode == ADDRESS_MODE.NWK_AND_IEEE:
r.ieee, data = EUI64.deserialize(data)
return r, data

def serialize(self):
r = super().serialize()
if self.address_mode == ADDRESS_MODE.NWK_AND_IEEE:
r += self.ieee.serialize()
return r


class DeconzAddressEndpoint(Struct):
_fields = [
# The address format (AddressMode)
('address_mode', uint8_t),
('address_mode', ADDRESS_MODE),
('address', uint64_t),
('endpoint', uint8_t)
]

@classmethod
def deserialize(cls, data):
r = cls()
mode, data = data[0], data[1:]
setattr(r, cls._fields[0][0], mode)
mode, data = ADDRESS_MODE.deserialize(data)
r.address_mode = mode
a = e = None
if mode in [ADDRESS_MODE.GROUP, ADDRESS_MODE.NWK]:
a, data = uint16_t.deserialize(data)
a, data = NWK.deserialize(data)
elif mode == ADDRESS_MODE.IEEE:
a, data = uint64_t.deserialize(data)
a, data = EUI64.deserialize(data)
setattr(r, cls._fields[1][0], a)
if mode in [ADDRESS_MODE.NWK, ADDRESS_MODE.IEEE]:
e, data = uint8_t.deserialize(data)
Expand Down