Parse the message from the device.

        :param data: message data
        :type data: string

        :raises: :py:class:`~alarmdecoder.util.InvalidMessageError`

def _parse_message(self, data):
        """
        Parse the message from the device.

        :param data: message data
        :type data: string

        :raises: :py:class:`~alarmdecoder.util.InvalidMessageError`
        """
        match = self._regex.match(str(data))

        if match is None:
            raise InvalidMessageError('Received invalid message: {0}'.format(data))

        header, self.bitfield, self.numeric_code, self.panel_data, alpha = match.group(1, 2, 3, 4, 5)

        is_bit_set = lambda bit: not self.bitfield[bit] == "0"

        self.ready = is_bit_set(1)
        self.armed_away = is_bit_set(2)
        self.armed_home = is_bit_set(3)
        self.backlight_on = is_bit_set(4)
        self.programming_mode = is_bit_set(5)
        self.beeps = int(self.bitfield[6], 16)
        self.zone_bypassed = is_bit_set(7)
        self.ac_power = is_bit_set(8)
        self.chime_on = is_bit_set(9)
        self.alarm_event_occurred = is_bit_set(10)
        self.alarm_sounding = is_bit_set(11)
        self.battery_low = is_bit_set(12)
        self.entry_delay_off = is_bit_set(13)
        self.fire_alarm = is_bit_set(14)
        self.check_zone = is_bit_set(15)
        self.perimeter_only = is_bit_set(16)
        self.system_fault = is_bit_set(17)
        if self.bitfield[18] in list(PANEL_TYPES):
            self.panel_type = PANEL_TYPES[self.bitfield[18]]
        # pos 20-21 - Unused.
        self.text = alpha.strip('"')
        self.mask = int(self.panel_data[3:3+8], 16)

        if self.panel_type in (ADEMCO, DSC):
            if int(self.panel_data[19:21], 16) & 0x01 > 0:
                # Current cursor location on the alpha display.
                self.cursor_location = int(self.panel_data[21:23], 16)