|
| 1 | +# -*- encoding: utf-8 -*- |
| 2 | +from __future__ import print_function, unicode_literals, division, absolute_import |
| 3 | +import logging |
| 4 | + |
| 5 | +import threading |
| 6 | +try: |
| 7 | + import queue |
| 8 | +except ImportError: |
| 9 | + import Queue as queue |
| 10 | +from enocean.protocol.packet import Packet |
| 11 | +from enocean.protocol.constants import PACKET, PARSE_RESULT, RETURN_CODE |
| 12 | + |
| 13 | + |
| 14 | +class ESP2Communicator(threading.Thread): |
| 15 | + ''' |
| 16 | + Communicator base-class for EnOcean. |
| 17 | + Not to be used directly, only serves as base class for SerialCommunicator etc. |
| 18 | + ''' |
| 19 | + logger = logging.getLogger('enocean.communicators.ESP2Communicator') |
| 20 | + |
| 21 | + def __init__(self, callback=None, teach_in=True): |
| 22 | + super(ESP2Communicator, self).__init__() |
| 23 | + # Create an event to stop the thread |
| 24 | + self._stop_flag = threading.Event() |
| 25 | + # Input buffer |
| 26 | + self._buffer = [] |
| 27 | + # Setup packet queues |
| 28 | + self.transmit = queue.Queue() |
| 29 | + self.receive = queue.Queue() |
| 30 | + # Set the callback method |
| 31 | + self.__callback = callback |
| 32 | + # Internal variable for the Base ID of the module. |
| 33 | + self._base_id = None |
| 34 | + # Should new messages be learned automatically? Defaults to True. |
| 35 | + # TODO: Not sure if we should use CO_WR_LEARNMODE?? |
| 36 | + self.teach_in = teach_in |
| 37 | + |
| 38 | + def _get_from_send_queue(self): |
| 39 | + ''' Get message from send queue, if one exists ''' |
| 40 | + try: |
| 41 | + packet = self.transmit.get(block=False) |
| 42 | + #self.logger.info('Sending packet') |
| 43 | + #self.logger.debug(packet) |
| 44 | + return packet |
| 45 | + except queue.Empty: |
| 46 | + pass |
| 47 | + return None |
| 48 | + |
| 49 | + def send(self, packet): |
| 50 | + if not isinstance(packet, Packet): |
| 51 | + self.logger.error('Object to send must be an instance of Packet') |
| 52 | + return False |
| 53 | + self.transmit.put(packet) |
| 54 | + return True |
| 55 | + |
| 56 | + def stop(self): |
| 57 | + self._stop_flag.set() |
| 58 | + |
| 59 | + def parse(self): |
| 60 | + ''' Parses messages and puts them to receive queue ''' |
| 61 | + # Loop while we get new messages |
| 62 | + while True: |
| 63 | + status, self._buffer, packet = Packet.parse_msg_ESP2(self._buffer, communicator=self) |
| 64 | + # If message is incomplete -> break the loop |
| 65 | + if status == PARSE_RESULT.INCOMPLETE: |
| 66 | + return status |
| 67 | + |
| 68 | + # If message is OK, add it to receive queue or send to the callback method |
| 69 | + if status == PARSE_RESULT.OK and packet: |
| 70 | + if self.__callback is None: |
| 71 | + self.receive.put(packet) |
| 72 | + else: |
| 73 | + self.__callback(packet) |
| 74 | + #self.logger.debug(packet) |
| 75 | + |
| 76 | + @property |
| 77 | + def base_id(self): |
| 78 | + ''' Fetches Base ID from the transmitter, if required. Otherwise returns the currently set Base ID. ''' |
| 79 | + # If base id is already set, return it. |
| 80 | + if self._base_id is not None: |
| 81 | + return self._base_id |
| 82 | + |
| 83 | + # Send COMMON_COMMAND 0x08, CO_RD_IDBASE request to the module |
| 84 | + self.send(Packet(PACKET.COMMON_COMMAND, data=[0x08])) |
| 85 | + # Loop over 10 times, to make sure we catch the response. |
| 86 | + # Thanks to timeout, shouldn't take more than a second. |
| 87 | + # Unfortunately, all other messages received during this time are ignored. |
| 88 | + for i in range(0, 10): |
| 89 | + try: |
| 90 | + packet = self.receive.get(block=True, timeout=0.1) |
| 91 | + # We're only interested in responses to the request in question. |
| 92 | + if packet.packet_type == PACKET.RESPONSE and packet.response == RETURN_CODE.OK and len(packet.response_data) == 4: |
| 93 | + # Base ID is set in the response data. |
| 94 | + self._base_id = packet.response_data |
| 95 | + # Put packet back to the Queue, so the user can also react to it if required... |
| 96 | + self.receive.put(packet) |
| 97 | + break |
| 98 | + # Put other packets back to the Queue. |
| 99 | + self.receive.put(packet) |
| 100 | + except queue.Empty: |
| 101 | + continue |
| 102 | + # Return the current Base ID (might be None). |
| 103 | + return self._base_id |
| 104 | + |
| 105 | + @base_id.setter |
| 106 | + def base_id(self, base_id): |
| 107 | + ''' Sets the Base ID manually, only for testing purposes. ''' |
| 108 | + self._base_id = base_id |
0 commit comments