Beispiel #1
0
def encode(spec, encrypt=True):
	"""Encode a pydict specification into a OpenThings binary payload"""
	# The message is not encrypted, but the CRC is generated here.

	payload = []

	# HEADER
	payload.append(0) # length, fixup later when known
	header = spec["header"]

	payload.append(header["mfrid"])
	payload.append(header["productid"])

	if not ("encryptPIP" in header):
		if encrypt:
			warning("no encryptPIP in header, assuming 0x0100")
		encryptPIP = 0x0100
	else:
		encryptPIP = header["encryptPIP"]
	payload.append((encryptPIP&0xFF00)>>8) # MSB
	payload.append((encryptPIP&0xFF))      # LSB

	sensorId = header["sensorid"]
	payload.append((sensorId>>16) & 0xFF) # HIGH
	payload.append((sensorId>>8) & 0xFF)  # MID
	payload.append((sensorId) & 0XFF)     # LOW

	# RECORDS
	for rec in spec["recs"]:
		wr      = rec["wr"]
		paramid = rec["paramid"]
		typeid  = rec["typeid"]
		if "length" in rec:
			length  = rec["length"]
		else:
			length = None # auto detect

		# PARAMID
		if wr:
			payload.append(0x80 + paramid) # WRITE
		else:
			payload.append(paramid)        # READ

		# TYPE/LENGTH
		payload.append((typeid)) # need to back patch length for auto detect
		lenpos = len(payload)-1 # for backpatch

		# VALUE
		valueenc = [] # in case of no value
		if "value" in rec:
			value = rec["value"]
			valueenc = Value.encode(value, typeid, length)
			if len(valueenc) > 15:
				raise ValueError("value longer than 15 bytes")
			for b in valueenc:
				payload.append(b)
			payload[lenpos] = (typeid) | len(valueenc)

	# FOOTER
	payload.append(0) # NUL
	crc = calcCRC(payload, 5, len(payload)-5)
	payload.append((crc>>8) & 0xFF) # MSB
	payload.append(crc&0xFF)        # LSB

	# back-patch the length byte so it is correct
	payload[0] = len(payload)-1

	if encrypt:
		# ENCRYPT
		# [0]len,mfrid,productid,pipH,pipL,[5]
		crypto.init(crypt_pid, encryptPIP)
		crypto.cryptPayload(payload, 5, len(payload)-5) # including CRC

	return payload
Beispiel #2
0
def encode(spec, encrypt=True):
    """Encode a pydict specification into a OpenThings binary payload"""
    # The message is not encrypted, but the CRC is generated here.

    payload = []

    # HEADER
    payload.append(0)  # length, fixup later when known
    header = spec["header"]

    payload.append(header["mfrid"])
    payload.append(header["productid"])

    if not ("encryptPIP" in header):
        if encrypt:
            warning("no encryptPIP in header, assuming 0x0100")
        encryptPIP = 0x0100
    else:
        encryptPIP = header["encryptPIP"]
    payload.append((encryptPIP & 0xFF00) >> 8)  # MSB
    payload.append((encryptPIP & 0xFF))  # LSB

    sensorId = header["sensorid"]
    payload.append((sensorId >> 16) & 0xFF)  # HIGH
    payload.append((sensorId >> 8) & 0xFF)  # MID
    payload.append((sensorId) & 0XFF)  # LOW

    # RECORDS
    for rec in spec["recs"]:
        wr = rec["wr"]
        paramid = rec["paramid"]
        typeid = rec["typeid"]
        if "length" in rec:
            length = rec["length"]
        else:
            length = None  # auto detect

        # PARAMID
        if wr:
            payload.append(0x80 + paramid)  # WRITE
        else:
            payload.append(paramid)  # READ

        # TYPE/LENGTH
        payload.append((typeid))  # need to back patch length for auto detect
        lenpos = len(payload) - 1  # for backpatch

        # VALUE
        valueenc = []  # in case of no value
        if "value" in rec:
            value = rec["value"]
            valueenc = Value.encode(value, typeid, length)
            if len(valueenc) > 15:
                raise ValueError("value longer than 15 bytes")
            for b in valueenc:
                payload.append(b)
            payload[lenpos] = (typeid) | len(valueenc)

    # FOOTER
    payload.append(0)  # NUL
    crc = calcCRC(payload, 5, len(payload) - 5)
    payload.append((crc >> 8) & 0xFF)  # MSB
    payload.append(crc & 0xFF)  # LSB

    # back-patch the length byte so it is correct
    payload[0] = len(payload) - 1

    if encrypt:
        # ENCRYPT
        # [0]len,mfrid,productid,pipH,pipL,[5]
        crypto.init(crypt_pid, encryptPIP)
        crypto.cryptPayload(payload, 5, len(payload) - 5)  # including CRC

    return payload
Beispiel #3
0
def decode(payload, decrypt=True, receive_timestamp=None):
	"""Decode a raw buffer into an OpenThings pydict"""
	#Note, decrypt must already have run on this for it to work
	length = payload[0]

	# CHECK LENGTH
	if length+1 != len(payload) or length < 10:
		raise OpenThingsException("bad payload length")
		##return {
		##	"type":         "BADLEN",
		##	"len_actual":   len(payload),
		##	"len_expected": length,
		##	"payload":      payload[1:]
		##}

	# DECODE HEADER
	mfrId      = payload[1]
	productId  = payload[2]
	encryptPIP = (payload[3]<<8) + payload[4]
	header = {
		"mfrid"     : mfrId,
		"productid" : productId,
		"encryptPIP": encryptPIP
	}


	if decrypt:
		# DECRYPT PAYLOAD
		# [0]len,mfrid,productid,pipH,pipL,[5]
		crypto.init(crypt_pid, encryptPIP)
		crypto.cryptPayload(payload, 5, len(payload)-5) # including CRC
		##printhex(payload)
	# sensorId is in encrypted region
	sensorId = (payload[5]<<16) + (payload[6]<<8) + payload[7]
	header["sensorid"] = sensorId


	# CHECK CRC
	crc_actual  = (payload[-2]<<8) + payload[-1]
	crc_expected = calcCRC(payload, 5, len(payload)-(5+2))
	##trace("crc actual:%s, expected:%s" %(hex(crc_actual), hex(crc_expected)))

	if crc_actual != crc_expected:
		raise OpenThingsException("bad CRC")
		##return {
		##	"type":         "BADCRC",
		##	"crc_actual":   crc_actual,
		##	"crc_expected": crc_expected,
		##	"payload":      payload[1:],
		##}


	# DECODE RECORDS
	i = 8
	recs = []
	while i < length and payload[i] != 0:
		# PARAM
		param = payload[i]
		wr = ((param & 0x80) == 0x80)
		paramid = param & 0x7F
		if paramid in param_info:
			paramname = (param_info[paramid])["n"] # name
			paramunit = (param_info[paramid])["u"] # unit
		else:
			paramname = "UNKNOWN_" + hex(paramid)
			paramunit = "UNKNOWN_UNIT"
		i += 1

		# TYPE/LEN
		typeid = payload[i] & 0xF0
		plen = payload[i] & 0x0F
		i += 1

		rec = {
			"wr":         wr,
			"paramid":    paramid,
			"paramname":  paramname,
			"paramunit":  paramunit,
			"typeid":     typeid,
			"length":     plen
		}

		if plen != 0:
			# VALUE
			valuebytes = []
			for x in range(plen):
				valuebytes.append(payload[i])
				i += 1
			value = Value.decode(valuebytes, typeid, plen)
			rec["valuebytes"] = valuebytes
			rec["value"] = value

		# store rec
		recs.append(rec)

	m = {
		"type":    "OK",
		"header":  header,
		"recs":    recs
	}
	if receive_timestamp != None:
		m["rxtimestamp"] = receive_timestamp
	return Message(m)
Beispiel #4
0
def decode(payload, decrypt=True, receive_timestamp=None):
    """Decode a raw buffer into an OpenThings pydict"""
    #Note, decrypt must already have run on this for it to work
    length = payload[0]

    # CHECK LENGTH
    if length + 1 != len(payload) or length < 10:
        raise OpenThingsException("bad payload length")
        ##return {
        ##	"type":         "BADLEN",
        ##	"len_actual":   len(payload),
        ##	"len_expected": length,
        ##	"payload":      payload[1:]
        ##}

    # DECODE HEADER
    mfrId = payload[1]
    productId = payload[2]
    encryptPIP = (payload[3] << 8) + payload[4]
    header = {"mfrid": mfrId, "productid": productId, "encryptPIP": encryptPIP}

    if decrypt:
        # DECRYPT PAYLOAD
        # [0]len,mfrid,productid,pipH,pipL,[5]
        crypto.init(crypt_pid, encryptPIP)
        crypto.cryptPayload(payload, 5, len(payload) - 5)  # including CRC
        ##printhex(payload)
    # sensorId is in encrypted region
    sensorId = (payload[5] << 16) + (payload[6] << 8) + payload[7]
    header["sensorid"] = sensorId

    # CHECK CRC
    crc_actual = (payload[-2] << 8) + payload[-1]
    crc_expected = calcCRC(payload, 5, len(payload) - (5 + 2))
    ##trace("crc actual:%s, expected:%s" %(hex(crc_actual), hex(crc_expected)))

    if crc_actual != crc_expected:
        raise OpenThingsException("bad CRC")
        ##return {
        ##	"type":         "BADCRC",
        ##	"crc_actual":   crc_actual,
        ##	"crc_expected": crc_expected,
        ##	"payload":      payload[1:],
        ##}

    # DECODE RECORDS
    i = 8
    recs = []
    while i < length and payload[i] != 0:
        # PARAM
        param = payload[i]
        wr = ((param & 0x80) == 0x80)
        paramid = param & 0x7F
        if paramid in param_info:
            paramname = (param_info[paramid])["n"]  # name
            paramunit = (param_info[paramid])["u"]  # unit
        else:
            paramname = "UNKNOWN_" + hex(paramid)
            paramunit = "UNKNOWN_UNIT"
        i += 1

        # TYPE/LEN
        typeid = payload[i] & 0xF0
        plen = payload[i] & 0x0F
        i += 1

        rec = {
            "wr": wr,
            "paramid": paramid,
            "paramname": paramname,
            "paramunit": paramunit,
            "typeid": typeid,
            "length": plen
        }

        if plen != 0:
            # VALUE
            valuebytes = []
            for x in range(plen):
                valuebytes.append(payload[i])
                i += 1
            value = Value.decode(valuebytes, typeid, plen)
            rec["valuebytes"] = valuebytes
            rec["value"] = value

        # store rec
        recs.append(rec)

    m = {"type": "OK", "header": header, "recs": recs}
    if receive_timestamp != None:
        m["rxtimestamp"] = receive_timestamp
    return Message(m)