Ejemplo n.º 1
0
    def _decode_dispatch(self, p_pyhouse_obj, p_controller_obj):
        """ Decode a message that was ACKed / NAked.
        see IDM pages 238-241

        @return: a flag that is True for ACK and False for NAK/Invalid response.
        """
        l_message = p_controller_obj._Message
        l_ret = False
        l_cmd = p_controller_obj._Message[1]
        if l_cmd == 0:
            LOG.warning("Found a '0' record ->{}.".format(
                FormatBytes(l_message)))
            p_controller_obj._Message = p_controller_obj._Message[1:]
            return l_ret
        elif l_cmd == 0x50:
            l_ret = self._decode_0x50(p_controller_obj)
        elif l_cmd == 0x51:
            l_ret = self._decode_0x51(p_controller_obj)
        elif l_cmd == 0x52:
            l_ret = self._decode_0x52_record(p_controller_obj)
        elif l_cmd == 0x53:
            linkDecode.decode_0x53(p_pyhouse_obj, p_controller_obj)
        elif l_cmd == 0x54:
            linkDecode.decode_0x54(p_pyhouse_obj, p_controller_obj)
        elif l_cmd == 0x55:
            linkDecode.decode_0x55(p_pyhouse_obj, p_controller_obj)
        elif l_cmd == 0x56:
            linkDecode.decode_0x56(p_pyhouse_obj, p_controller_obj)
        elif l_cmd == 0x57:
            linkDecode.decode_0x57(p_pyhouse_obj, p_controller_obj)
        elif l_cmd == 0x58:
            linkDecode.decode_0x58(p_pyhouse_obj, p_controller_obj)
        elif l_cmd == 0x60:
            l_ret = self._decode_0x60_record(p_controller_obj)
        elif l_cmd == 0x61:
            l_ret = self._decode_0x61_record(p_controller_obj)
        elif l_cmd == 0x62:
            l_ret = self._decode_0x62_record(p_controller_obj)
        elif l_cmd == 0x64:
            linkDecode.decode_0x64(p_pyhouse_obj, p_controller_obj)
        elif l_cmd == 0x65:
            linkDecode.decode_0x65(p_pyhouse_obj, p_controller_obj)
        elif l_cmd == 0x69:
            linkDecode.decode_0x69(p_pyhouse_obj, p_controller_obj)
        elif l_cmd == 0x6A:
            linkDecode.decode_0x6A(p_pyhouse_obj, p_controller_obj)
        elif l_cmd == 0x6B:
            l_ret = self._decode_0x6B_record(p_controller_obj)
        elif l_cmd == 0x6C:
            linkDecode.decode_0x6C(p_pyhouse_obj, p_controller_obj)
        elif l_cmd == 0x6F:
            l_ret = self._decode_0x6F_record(p_controller_obj)
        elif l_cmd == 0x73:
            l_ret = self._decode_0x73_record(p_controller_obj)
        else:
            LOG.error("Unknown Insteon message {}, Cmd:{}".format(
                FormatBytes(p_controller_obj._Message), l_cmd))
            # self.check_for_more_decoding(p_controller_obj, l_ret)
        self.check_for_more_decoding(p_controller_obj, l_ret)
        return l_ret
Ejemplo n.º 2
0
 def decode_response(self, p_controller_obj):
     """A response message starts with a 'P' (0x50) and ends with a '\r' (0x0D).
     """
     LOG.debug('DecodeResponse A - {}'.format(
         FormatBytes(p_controller_obj._Message)))
     l_message = self._extract_one_message(p_controller_obj)
     LOG.debug('DecodeResponse B - {}'.format(FormatBytes(l_message)))
     if len(l_message) < 2:
         return
     self._dispatch_decode(l_message)
     self.decode_response(p_controller_obj)
Ejemplo n.º 3
0
    def _queue_62_command(p_controller_obj,
                          p_obj,
                          p_cmd1,
                          p_cmd2,
                          p_text='None'):
        """Send Insteon Standard Length Message (8 bytes) (SD command).
        or Extended length (22 Bytes) (ED command)
        See page 230(243) of 2009 developers guide.

        @param p_obj: is the device object.
        @param p_cmd1: is the first command byte
        @param p_cmd2: is the second command byte

        [0] = x02
        [1] = 0x62
        [2-4] = to address
        [5] = Message Flags
        [6] = Command 1
        [7] = Command 2
        (8-21) = Extended data in ED type
        """
        try:
            l_command = insteon_utils.create_command_message('insteon_send')
            insteon_utils.insert_address_into_message(p_obj.Family.Address,
                                                      l_command, 2)
            l_command[5] = FLAG_MAX_HOPS + FLAG_HOPS_LEFT  #  0x0F
            l_command[6] = p_obj._Command1 = p_cmd1
            l_command[7] = p_obj._Command2 = p_cmd2
            insteon_utils.queue_command(p_controller_obj, l_command, p_text)
            # LOG.debug('Send Command: {}'.format(FormatBytes(l_command)))
        except Exception as _e_err:
            LOG.error('Error creating command: {}\n{}\n>>{}<<'.format(
                _e_err, PrettyFormatAny.form(p_obj, 'Device'),
                FormatBytes(l_command)))
Ejemplo n.º 4
0
    def decode_message(self, p_controller_obj):
        """Decode a message that was ACKed / NAked.
        see Insteon Developers Manual pages 238-241

        A controller response may contain multiple messages and the last message may not be complete.
        This should be invoked every time we pick up more messages from the controller.
        It should loop and decode each message present and leave when done

        @return: a flag that is True for ACK and False for NAK/Invalid response.
        """
        while len(p_controller_obj._Message) >= 2:
            l_stx = p_controller_obj._Message[0]
            if l_stx == STX:
                l_need_len = insteon_utils.get_message_length(
                    p_controller_obj._Message)
                l_cur_len = len(p_controller_obj._Message)
                if l_cur_len >= l_need_len:
                    # LOG.debug('Got response:{}'.format(FormatBytes(p_controller_obj._Message[0:l_need_len])))
                    self._decode_dispatch(self.m_pyhouse_obj, p_controller_obj)
                    return 'Ok'
                else:
                    LOG.debug(
                        'Message was too short - waiting for rest of message. {}'
                        .format(FormatBytes(p_controller_obj._Message)))
                    return 'Short'
            else:
                # LOG.warn("Dropping a leading char {:#x}  {}".format(l_stx, FormatBytes(p_controller_obj._Message)))
                p_controller_obj._Message = p_controller_obj._Message[1:]
                return 'Drop'
Ejemplo n.º 5
0
 def fetch_read_data(self):
     l_ret = self.m_USB_obj.message
     self.m_USB_obj.message = bytearray()
     if len(l_ret) == 0:
         return l_ret
     LOG.debug("Msg:{}".format(FormatBytes(l_ret)))
     return l_ret
Ejemplo n.º 6
0
    def _dispatch_decode(self, p_message):
        """
        Dispatch to the various message received methods

        See Page 12 of - UPB Powerline Interface Module (PIM) Description Ver 1.6
        """
        l_hdr = p_message[1]
        if l_hdr == 0x41:  # 'A'
            self._decode_A()
        elif l_hdr == 0x42:  # 'B'
            self._decode_B()
        elif l_hdr == 0x45:  # 'E'
            self._decode_E()
        elif l_hdr == 0x4B:  # 'K'
            self._decode_K()
        elif l_hdr == 0x4E:  # 'N'
            self._decode_N()
        elif l_hdr == 0x52:  # 'R'
            self._decode_R()
        elif l_hdr == 0x55:  # 'U'
            self._decode_U()
        else:
            LOG.error(
                "UPB_Pim.decode_response() found unknown code {} {}".format(
                    l_hdr, FormatBytes(p_message)))
Ejemplo n.º 7
0
 def test_02_Addr(self):
     """
     """
     l_addr = '12.34.56'
     l_msg = bytearray(b'0000000000')
     l_ret = insteon_utils.insert_address_into_message(l_addr, l_msg, 2)
     print('B1-02-A - {}'.format(FormatBytes(l_ret)))
Ejemplo n.º 8
0
 def read_usb(self, p_pyhouse_obj):
     """Routine that reads the USB device.
     Calls either HID or Non-HID routines to fetch tha actual data.
     """
     p_pyhouse_obj._Twisted.Reactor.callLater(RECEIVE_TIMEOUT,
                                              self.read_usb, p_pyhouse_obj)
     if self.m_USB_obj.hid_device:
         l_msg = self.read_hid_report(self.m_USB_obj)
     else:
         l_msg = self.read_device(self.m_USB_obj)
     for l_ix in range(len(l_msg)):
         self.m_USB_obj.message.append(l_msg[l_ix])
     if len(l_msg) > 0:
         LOG.debug('Driver - ReadUSB  JustRead:{}'.format(
             FormatBytes(l_msg)))
     if len(self.m_USB_obj.message) > 0:
         LOG.debug('Driver - ReadUSB  Accumulated:{}'.format(
             FormatBytes(self.m_USB_obj.message)))
     return l_msg
Ejemplo n.º 9
0
 def dequeue_and_send(self, p_controller_obj):
     self.m_pyhouse_obj._Twisted.Reactor.callLater(SEND_TIMEOUT,
                                                   self.dequeue_and_send,
                                                   p_controller_obj)
     try:
         l_command = p_controller_obj._Queue.get(False)
     except Queue.Empty:
         return
     if p_controller_obj.Interface._DriverApi != None:
         LOG.debug('Sending to controller:{}, Message: {} '.format(
             p_controller_obj.Name, FormatBytes(l_command)))
         p_controller_obj.Interface._DriverApi.Write(l_command)
Ejemplo n.º 10
0
 def _extract_one_message(self, p_controller_obj):
     """Valid messages start with a 'P' (0x50) and end with a NewLine (0x0dD).
     Remove any leading Junk characters
     Skip over any 0xFx characters as they are a USB HID length of data byte.
     Find the next Newline - If none we do not have a command so leave things in the _Message buffer.
     """
     l_start = p_controller_obj._Message.find('P')
     l_end = p_controller_obj._Message.find('\r')
     if l_end < 0:
         return ''  # Not a complete message yet.
     if l_start > 0:
         LOG.warning('Decoding result - discarding leading junk {}'.format(
             FormatBytes(p_controller_obj._Message[0:l_start])))
         p_controller_obj._Message = p_controller_obj._Message[l_start:]
         l_start = 0
         l_end = p_controller_obj._Message.find('\r')
         if l_end < 0:
             return ''  # Not a complete message yet.
     l_message = p_controller_obj._Message[l_start:l_end]
     p_controller_obj._Message = p_controller_obj._Message[l_end + 1:]
     LOG.debug('Extracted message {}'.format(FormatBytes(l_message)))
     return l_message
Ejemplo n.º 11
0
    def write_device(self, p_USB_obj, p_message):
        """Send message to the USB device.

        Sending speed is up to the controller.
        Someday we may provide notification that a command is complete.

        @return: the number of bytes written
        """
        LOG.debug("write_device() - {}".format(FormatBytes(p_message)))
        if p_USB_obj.epi_type == 0:
            self._write_control_device(p_USB_obj, p_message)
        else:
            self._write_bis_device(p_USB_obj, p_message)
Ejemplo n.º 12
0
 def _write_bis_device(self, p_USB_obj, p_message):
     """Bulk, Interrupt, isoSynchronous
     """
     l_message = p_message
     LOG.debug("write_bis_device() - Ep_out: {:#04X}, - {}".format(
         p_USB_obj.epo_addr, FormatBytes(l_message)))
     try:
         l_len = p_USB_obj.UsbDevice.write(p_USB_obj.epo_addr, l_message)
     except Exception as e:
         LOG.error(
             "_write_bis_device() - Error in writing to USB device {}".
             format(e))
         l_len = 0
     return l_len
Ejemplo n.º 13
0
    def _convert_pim(p_array):
        """Take a command ByteArray and convert it for the serial interface of the pim.

        I think this means taking each nibble of the command and converting it to an ASCII byte.

        """
        # return p_array
        l_ret = bytearray(0)
        for l_byte in p_array:
            l_str = BuildCommand._byte_to_2chars(l_byte)
            l_ret.append(l_str[0])
            l_ret.append(l_str[1])
        LOG.debug("Convert_pim - {}".format(FormatBytes(l_ret)))
        return l_ret
Ejemplo n.º 14
0
 def check_for_more_decoding(self, p_controller_obj, p_ret=True):
     """ Chop off the current message from the head of the buffered response stream from the controller.
     @param p_ret: is the result to return.
     """
     l_ret = p_ret
     l_cur_len = len(p_controller_obj._Message)
     l_chop = insteon_utils.get_message_length(p_controller_obj._Message)
     if l_cur_len >= l_chop:
         p_controller_obj._Message = p_controller_obj._Message[l_chop:]
         l_ret = self.decode_message(p_controller_obj)
     else:
         l_msg = "check_for_more_decoding() trying to chop an incomplete message - {}".format(
             FormatBytes(p_controller_obj._Message))
         LOG.error(l_msg)
     return l_ret
Ejemplo n.º 15
0
 def receive_loop(self, p_controller_obj):
     """Periodically, get the current RX data from the driver.
     """
     self.m_pyhouse_obj._Twisted.Reactor.callLater(RECEIVE_TIMEOUT,
                                                   self.receive_loop,
                                                   p_controller_obj)
     if p_controller_obj.Interface._DriverApi != None:
         l_msg = p_controller_obj.Interface._DriverApi.Read()
         if len(l_msg) == 0:
             return
         LOG.debug('Fetched message  {}'.format(FormatBytes(l_msg)))
         p_controller_obj._Message += l_msg
         self.decode_response(p_controller_obj)
     else:
         LOG.info('No driver defined ')
Ejemplo n.º 16
0
    def _accumulatePacket(self, p_data):
        """ Get 1 packet.
        Packet format:
            Fixed Header(2 - 5 bytes)
            Variable Header (0 - 268,435,455 bytes)

        Fixed Header:
           Various Flags: 1 Byte
           RemainingLength = 1-4 Bytes

        Variable Header:
            :
        """
        self.m_buffer.extend(p_data)
        l_RemainingLength = None
        while len(self.m_buffer):
            if l_RemainingLength is None:
                #  Start on a new packet
                if len(self.m_buffer) < 2:
                    break  #  Haven't got enough data to start a new packet, wait for some more
                l_rl_len = 1  # Initial length of the RemainingLength field.
                #  get the variable length RemainingLength field
                while l_rl_len < len(
                        self.m_buffer
                ):  # Find the bytes in the RemainingLength field.
                    if not self.m_buffer[l_rl_len] & 0x80:
                        break  # We have the full RemainingLength field
                    l_rl_len += 1  # Field is longer - get another byte
                # Get the variable part -  We still haven't got all of the remaining length field so quit and wait for another chunk
                if l_rl_len < len(self.m_buffer) and self.m_buffer[
                        l_rl_len] & 0x80:  # Is there more to to come of the RemainingLength field?
                    LOG.debug(
                        '### Early return - Another chunk is needed {}'.format(
                            FormatBytes(self.m_buffer)))
                    return
                l_RemainingLength = EncodeDecode._decodeLength(
                    self.m_buffer[1:])
            l_FixedHeaderLength = l_rl_len + 1  # Length of the fixed Header portion of the packet
            l_PacketLength = l_FixedHeaderLength + +l_RemainingLength
            if len(self.m_buffer) >= l_PacketLength:
                l_one_message_packet = self.m_buffer[:l_PacketLength]
                self._processPacket(l_one_message_packet)

                self.m_buffer = self.m_buffer[l_PacketLength:]
                l_RemainingLength = None
            else:
                # LOG.debug('### exit without processing\n\t{}'.format(FormatBytes(self.m_buffer)))
                break
Ejemplo n.º 17
0
 def read_device(self, p_USB_obj):
     """
     Get any data the USB device has and append it to the controller _Data field.
     @return: the number of bytes fetched from the controller
     """
     try:
         l_msg = p_USB_obj.UsbDevice.read(
             p_USB_obj.epi_addr, p_USB_obj.epi_packet_size,
             timeout=100)  # Note - No device to _test with
         LOG.debug("read_device() - Msg:{}".format(FormatBytes(l_msg)))
     except usb.USBError as e_err:
         LOG.error("ERROR - read_device() got USBError - {}".format(e_err))
         l_msg = bytearray(0)
     except Exception as e_err:
         LOG.error("ERROR - read_device() {}".format(e_err))
         l_msg = bytearray(0)
     return l_msg
Ejemplo n.º 18
0
    def _extract_hid_report(self, p_message):
        """
        Take a HID report and clean up the data to be useful

        @param p_message: is the data received from the USB device
        @type p_message: bytearray

        @return: a bytearray with the length byte removes and trimmed to the length
        """
        l_ret = bytearray(0)
        if len(p_message) == 0:
            return l_ret
        l_len = p_message[0] & 0x0F
        if l_len > 0:
            LOG.debug("read_hid_report() A - Msg:{}".format(
                FormatBytes(p_message)))
            l_ret = p_message[1:l_len + 1]
        return l_ret
Ejemplo n.º 19
0
 def dataReceived(self, p_data):
     LOG.debug("USB_driver.dataReceived() - {}".format(FormatBytes(p_data)))
     self.m_USB_obj.message += p_data
Ejemplo n.º 20
0
 def XXXqueue_pim_command(self, p_controller_obj, p_command):
     l_msg = "Queue_pim_command {}".format(FormatBytes(p_command))
     LOG.debug(l_msg)
     p_controller_obj._Queue.put(p_command)
Ejemplo n.º 21
0
 def write_report(self, p_USB_obj, p_message):
     LOG.debug("Write Report - {}".format(FormatBytes(p_message)))
     self._write_bis_device(p_USB_obj, p_message)
Ejemplo n.º 22
0
    def decode_0x50(self, p_pyhouse_obj, p_controller_obj, p_device_obj):
        """
        There are 2 types of responses here.
        One is from a request for information from the light type device.
        The other is a change of status from a light type device.

        @param p_controller_obj: is the controller that received the message
        @param p_device_obj: is

        A Standard-length INSTEON message is received from either a Controller or Responder that you are ALL-Linked to.
        See p 233(246) of 2009 developers guide.
        [0] = x02
        [1] = 0x50
        [2-4] = from address
        [5-7] = to address / group
        [8] = message flags
        [9] = command 1
        [10] = command 2
        """
        l_message = p_controller_obj._Message

        l_mqtt_publish = False
        p_device_obj.BrightnessPct = '?'
        p_device_obj.ControllerNode = p_pyhouse_obj.Computer.Name
        p_device_obj.ControllerName = p_controller_obj.Name
        l_flags = utilDecode._decode_insteon_message_flag(l_message[8])
        l_cmd1 = l_message[9]
        l_cmd2 = l_message[10]
        l_data = [l_cmd1, l_cmd2]
        l_debug_msg = 'Fm:"{}"; Flg:{}; C1:{:#x},{:#x}; '.format(
            p_device_obj.Name, l_flags, l_cmd1, l_cmd2)
        #
        #  Break down bits 7(msb), 6, 5 into message type
        #
        if l_message[8] & 0xE0 == 0x80:  #  100 - SB [Broadcast]
            l_debug_msg += utilDecode._devcat(l_message[5:7], p_device_obj)
        elif l_message[
                8] & 0xE0 == 0xC0:  #  110 - SA Broadcast = all link broadcast of group id
            l_group = l_message[7]
            l_debug_msg += 'A-L-brdcst-Gp:"{}","{}"; '.format(l_group, l_data)
        try:
            # Query responses
            if l_cmd1 == MESSAGE_TYPES[
                    'assign_to_group'] and l_message[8] & 0xE0 == 0x80:  # 0x01
                l_debug_msg += ' Device-Set-Button-Pressed '
            elif l_cmd1 == MESSAGE_TYPES['delete_from_group'] and l_message[
                    8] & 0xE0 == 0x80:  # 0x02
                l_debug_msg += ' Controller-Set-Button-Pressed '
            elif l_cmd1 == MESSAGE_TYPES['product_data_request']:  #  0x03
                l_debug_msg += " Product-data-request."
            elif l_cmd1 == MESSAGE_TYPES['cleanup_success']:  #  0x06
                l_debug_msg += 'CleanupSuccess with {} failures; '.format(
                    l_cmd2)
            elif l_cmd1 == MESSAGE_TYPES['engine_version']:  #  0x0D
                p_device_obj.EngineVersion = l_cmd2
                l_debug_msg += 'Engine-version:"{}(i-{})"; '.format(
                    l_cmd2, l_cmd2 + 1)
            elif l_cmd1 == MESSAGE_TYPES['id_request']:  #  0x10
                p_device_obj.FirmwareVersion = l_cmd2
                l_debug_msg += 'Request-ID:"{}"; '.format(
                    p_device_obj.FirmwareVersion)

            elif l_cmd1 == MESSAGE_TYPES['on']:  #  0x11
                p_device_obj.BrightnessPct = 100
                l_mqtt_publish = True
                l_debug_msg += 'Turn ON; '.format(p_device_obj.Name)
            elif l_cmd1 == MESSAGE_TYPES['off']:  #  0x13
                p_device_obj.BrightnessPct = 0
                l_mqtt_publish = True
                l_debug_msg += 'Turn OFF; '.format(p_device_obj.Name)
            elif l_cmd1 == MESSAGE_TYPES['status_request']:  #  0x19
                p_device_obj.BrightnessPct = l_level = utilDecode.decode_insteon_light_brightness(
                    l_cmd2)
                l_mqtt_publish = True
                l_debug_msg += 'Status of light:"{}"-level:"{}"; '.format(
                    p_device_obj.Name, l_level)
            else:
                l_debug_msg += '\n\tUnknown-type:{} - "{}"; '.format(
                    l_cmd1, FormatBytes(l_message))
                p_device_obj.BrightnessPct = utilDecode.decode_insteon_light_brightness(
                    l_cmd2)
                l_mqtt_publish = True
        except AttributeError as e_err:
            LOG.error('ERROR decoding 0x50 record {}'.format(e_err))

        insteon_utils.update_insteon_obj(p_pyhouse_obj, p_device_obj)
        p_controller_obj.Ret = True
        LOG.debug('Light Response {}'.format(l_debug_msg))
        LOG.info('Light: {}, Brightness: {}'.format(
            p_device_obj.Name, p_device_obj.BrightnessPct))
        if l_mqtt_publish:
            l_topic = 'house/lighting/light/status'
            p_pyhouse_obj._APIs.Core.MqttAPI.MqttPublish(l_topic, p_device_obj)
            pass
        return l_debug_msg
Ejemplo n.º 23
0
 def test_00_Print(self):
     print('Id: test_mqtt_util')
     _w = FormatBytes('123')
     _x = PrettyFormatAny.form(
         '_test', 'title',
         190)  # so it is defined when printing is cleaned up.