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
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
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)
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)