code: def _handle_message(self, data):
          
  
          try:
              data = data.decode('utf-8')
          except:
              raise InvalidMessageError('Decode failed for message: {0}'.format(data))
  
          if data is not None:
              data = data.lstrip('\0')
  
          if data is None or data == '':
              raise InvalidMessageError()
  
          msg = None
          header = data[0:4]
  
          if header[0] != '!' or header == '!KPM':
              msg = self._handle_keypad_message(data)
  
          elif header == '!EXP' or header == '!REL':
              msg = self._handle_expander_message(data)
  
          elif header == '!RFX':
              msg = self._handle_rfx(data)
  
          elif header == '!LRR':
              msg = self._handle_lrr(data)
  
          elif header == '!AUI':
              msg = self._handle_aui(data)
  
          elif data.startswith('!Ready'):
              self.on_boot()
  
          elif data.startswith('!CONFIG'):
              self._handle_config(data)
  
          elif data.startswith('!VER'):
              self._handle_version(data)
  
          elif data.startswith('!Sending'):
              self._handle_sending(data)
  
          return msg
docs: Parses keypad messages from the panel.
  
          :param data: keypad data to parse
          :type data: string
  
          :returns: :py:class:`~alarmdecoder.messages.Message`