Create a new CEMIMessage initialized from the given CEMI data.

def from_body(cls, cemi):
        """Create a new CEMIMessage initialized from the given CEMI data."""
        # TODO: check that length matches
        message = cls()
        message.code = cemi[0]
        offset = cemi[1]

        message.ctl1 = cemi[2 + offset]
        message.ctl2 = cemi[3 + offset]

        message.src_addr = cemi[4 + offset] * 256 + cemi[5 + offset]
        message.dst_addr = cemi[6 + offset] * 256 + cemi[7 + offset]

        message.mpdu_len = cemi[8 + offset]

        tpci_apci = cemi[9 + offset] * 256 + cemi[10 + offset]
        apci = tpci_apci & 0x3ff

        # for APCI codes see KNX Standard 03/03/07 Application layer
        # table Application Layer control field
        if apci & 0x080:
            # Group write
            message.cmd = CEMIMessage.CMD_GROUP_WRITE
        elif apci == 0:
            message.cmd = CEMIMessage.CMD_GROUP_READ
        elif apci & 0x40:
            message.cmd = CEMIMessage.CMD_GROUP_RESPONSE
        else:
            message.cmd = CEMIMessage.CMD_UNKNOWN

        apdu = cemi[10 + offset:]
        if len(apdu) != message.mpdu_len:
            raise KNXException(
                "APDU LEN should be {} but is {}".format(
                    message.mpdu_len, len(apdu)))

        if len(apdu) == 1:
            message.data = [apci & 0x2f]
        else:
            message.data = cemi[11 + offset:]

        return message