From 62ee217426d7c3707f9cad160a495cdb03e653d2 Mon Sep 17 00:00:00 2001 From: Kimmo Huoman Date: Mon, 15 Feb 2016 23:19:02 +0200 Subject: [PATCH] Create new `Packet` -type, `UTETeachIn` to fix issue #13. - Currently parses an incoming teach-in request from D2-01-01. - Still requires a response packet creation. --- enocean/protocol/constants.py | 34 ++++++++++++++++++++ enocean/protocol/packet.py | 60 +++++++++++++++++++++++++++++++++-- tests/test_teachin.py | 28 ++++++++++++++++ 3 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 tests/test_teachin.py diff --git a/enocean/protocol/constants.py b/enocean/protocol/constants.py index eaa854e..8d1196e 100644 --- a/enocean/protocol/constants.py +++ b/enocean/protocol/constants.py @@ -50,6 +50,7 @@ class RORG(IntEnum): SYS_EX = 0xC5 SEC = 0x30 SEC_ENCAPS = 0x31 + UTE = 0xD4 # Results for message parsing @@ -103,3 +104,36 @@ class DB3: BIT_5 = -30 BIT_6 = -31 BIT_7 = -32 + + +class DB4: + BIT_0 = -33 + BIT_1 = -34 + BIT_2 = -35 + BIT_3 = -36 + BIT_4 = -37 + BIT_5 = -38 + BIT_6 = -39 + BIT_7 = -40 + + +class DB5: + BIT_0 = -41 + BIT_1 = -42 + BIT_2 = -43 + BIT_3 = -44 + BIT_4 = -45 + BIT_5 = -46 + BIT_6 = -47 + BIT_7 = -48 + + +class DB6: + BIT_0 = -49 + BIT_1 = -50 + BIT_2 = -51 + BIT_3 = -52 + BIT_4 = -53 + BIT_5 = -54 + BIT_6 = -55 + BIT_7 = -56 diff --git a/enocean/protocol/packet.py b/enocean/protocol/packet.py index 1c7488f..efd5a2a 100644 --- a/enocean/protocol/packet.py +++ b/enocean/protocol/packet.py @@ -5,7 +5,7 @@ import enocean.utils from enocean.protocol import crc8 from enocean.protocol.eep import EEP -from enocean.protocol.constants import PACKET, RORG, PARSE_RESULT, DB0, DB2, DB3 +from enocean.protocol.constants import PACKET, RORG, PARSE_RESULT, DB0, DB2, DB3, DB4, DB6 logger = logging.getLogger('enocean.protocol.packet') @@ -48,7 +48,9 @@ def _bit_data(self): if self.rorg == RORG.RPS or self.rorg == RORG.BS1: return enocean.utils.to_bitarray(self.data[1], 8) if self.rorg == RORG.BS4: - return enocean.utils.to_bitarray(self.data[1:5], 32) + return enocean.utils.to_bitarray(self.data[1:5], 4 * 8) + if self.rorg == RORG.UTE: + return enocean.utils.to_bitarray(self.data[1:8], 7 * 8) @_bit_data.setter def _bit_data(self, value): @@ -57,6 +59,9 @@ def _bit_data(self, value): if self.rorg == RORG.BS4: for byte in range(4): self.data[byte+1] = enocean.utils.from_bitarray(value[byte*8:(byte+1)*8]) + if self.rorg == RORG.UTE: + for byte in range(7): + self.data[byte+1] = enocean.utils.from_bitarray(value[byte*8:(byte+1)*8]) # # COMMENTED OUT, AS NOTHING TOUCHES _bit_optional FOR NOW. # # Thus, this is also untested. @@ -131,7 +136,11 @@ def parse_msg(buf): # If we got this far, everything went ok (?) if packet_type == PACKET.RADIO: - p = RadioPacket(packet_type, data, opt_data) + # Need to handle UTE Teach-in here, as it's a separate packet type... + if data[0] == RORG.UTE: + p = UTETeachIn(packet_type, data, opt_data) + else: + p = RadioPacket(packet_type, data, opt_data) elif packet_type == PACKET.RESPONSE: p = ResponsePacket(packet_type, data, opt_data) else: @@ -305,6 +314,51 @@ def parse(self): return super(RadioPacket, self).parse() +class UTETeachIn(RadioPacket): + # Request types + TEACH_IN = 0b00 + DELETE = 0b01 + NOT_SPECIFIC = 0b10 + + # Response types + NOT_ACCEPTED = 0b00 + TEACHIN_ACCEPTED = 0b01 + DELETE_ACCEPTED = 0b10 + EEP_NOT_SUPPORTED = 0b11 + + unidirectional = False + response_expected = False + number_of_channels = 0xFF + rorg_of_eep = RORG.UNDEFINED + request_type = NOT_SPECIFIC + + @property + def bidirectional(self): + return not self.unidirectional + + @property + def teach_in(self): + return self.request_type != self.DELETE + + @property + def delete(self): + return self.request_type == self.DELETE + + def parse(self): + super(UTETeachIn, self).parse() + self.unidirectional = not self._bit_data[DB6.BIT_7] + self.response_expected = not self._bit_data[DB6.BIT_6] + self.request_type = enocean.utils.from_bitarray(self._bit_data[DB6.BIT_5:DB6.BIT_3]) + self.rorg_manufacturer = enocean.utils.from_bitarray(self._bit_data[DB3.BIT_2:DB2.BIT_7] + self._bit_data[DB4.BIT_7:DB3.BIT_7]) + self.rorg_type = self.data[5] + self.rorg_func = self.data[6] + self.rorg_of_eep = self.data[7] + return self.parsed + + def create_response(self, accepted=True, not_accepted_reason=EEP_NOT_SUPPORTED): + pass + + class ResponsePacket(Packet): response = 0 response_data = [] diff --git a/tests/test_teachin.py b/tests/test_teachin.py new file mode 100644 index 0000000..96abcf2 --- /dev/null +++ b/tests/test_teachin.py @@ -0,0 +1,28 @@ +# -*- encoding: utf-8 -*- +from __future__ import print_function, unicode_literals, division + +from enocean.protocol.packet import Packet +from enocean.protocol.constants import RORG + + +def test_ute(): + # ['0xd4', '0xa0', '0xff', '0x3e', '0x0', '0x1', '0x1', '0xd2', '0x1', '0x94', '0xe3', '0xb9', '0x0'] ['0x1', '0xff', '0xff', '0xff', '0xff', '0x40', '0x0'] + status, buf, p = Packet.parse_msg(bytearray([ + 0x55, + 0x00, 0x0D, 0x07, 0x01, + 0xFD, + 0xD4, 0xA0, 0xFF, 0x3e, 0x00, 0x01, 0x01, 0xD2, 0x01, 0x94, 0xE3, 0xB9, 0x00, + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x00, + 0xAB + ])) + assert p.sender_hex == '01:94:E3:B9' + assert p.unidirectional is False + assert p.bidirectional is True + assert p.response_expected is True + assert p.number_of_channels == 0xFF + assert p.rorg_manufacturer == 0x3E + assert p.rorg_of_eep == RORG.VLD + assert p.rorg_func == 0x01 + assert p.rorg_type == 0x01 + assert p.teach_in is True + assert p.delete is False