class DevicePayloadView(APIView): SUBMETER_TYPE = 1 CONCENTRATOR_TYPE = 2 authentication_classes = () permission_classes = () def post(self, request, eui): """ Proof of concept POST API point, to help Vali deserialize the binary payload. Payload params: EUI - 4 bytes - the unique ID of the device, provisioned in factory for each device. type - 1 byte - device type. Sub-Meter = 1, Concentrator = 2. timestamp - 4 bytes - the Epoch timestamp NTP synced. delta - 2 bytes - the aggregation period in seconds. (usually around 60 seconds). unit- 3 bytes - sensor unit tag. """ if not isinstance(request.body, bytes): raise APIException(detail="Binary body expected", code=400) body = bytearray(request.body) device_eui = int.from_bytes(body[0:4], byteorder='big', signed=False) device_type = int.from_bytes(body[4:5], byteorder='big', signed=False) timestamp = int.from_bytes(body[5:9], byteorder='big', signed=False) delta = int.from_bytes(body[9:11], byteorder='big', signed=False) unit = int.from_bytes(body[11:14], byteorder='big', signed=False) response_dict = { 'EUI': "RED{}".format(device_eui), 'type': device_type, 'timestamp': timestamp, 'data': { 'unit': unit, 'delta': delta, 'aggregated': self.getAggregatedDictFor(body, device_type), 'debug': {}, 'samples': [] }, 'body': body.hex(), } service = AWSIoTMQTTService() service.publish_device_processed_payload_to( response_dict.get('EUI'), response_dict.get('data'), 'dCVX3RgiYQOOCglK' ) return Response(response_dict) def getAggregatedDictFor(self, body, device_type): if device_type == self.SUBMETER_TYPE: return self.get_submeter_aggregated_dict_for(body) elif device_type == self.CONCENTRATOR_TYPE: return self.get_concentrator_aggregated_dict_for(body) return {} def get_submeter_aggregated_dict_for(self, body): """ Energy - 4 bytes - the energy used or produced for all phases, measured in Wh. Phase R Average Power - 4 bytes - the average power on phase R, measured in W. Phase S Average Power - 4 bytes - the average power on phase S, measured in W. Phase T Average Power - 4 bytes - the average power on phase S, measured in W. IMPORTANT: All these parameters are computed from the last successfully sent payload! """ energy = int.from_bytes(body[14:18], byteorder='big', signed=True) / 100 power_R = int.from_bytes(body[18:22], byteorder='big', signed=True) / 100 power_S = int.from_bytes(body[22:26], byteorder='big', signed=True) / 100 power_T = int.from_bytes(body[26:30], byteorder='big', signed=True) / 100 return { 'energy': energy, 'power_R': power_R, 'power_S': power_S, 'power_T': power_T, } def get_concentrator_aggregated_dict_for(self, body): param1B20 = int.from_bytes(body[14:22], byteorder='big', signed=True) / 100 param1B24 = int.from_bytes(body[22:30], byteorder='big', signed=True) / 100 param1B28 = int.from_bytes(body[30:38], byteorder='big', signed=True) / 100 param1B2C = int.from_bytes(body[38:46], byteorder='big', signed=True) / 100 param1B30 = int.from_bytes(body[46:54], byteorder='big', signed=True) / 100 param0002 = int.from_bytes(body[54:58], byteorder='big', signed=True) / 100 param0004 = int.from_bytes(body[58:62], byteorder='big', signed=True) / 100 param0006 = int.from_bytes(body[62:66], byteorder='big', signed=True) / 100 param0008 = int.from_bytes(body[66:70], byteorder='big', signed=True) / 10000 param000A = int.from_bytes(body[70:74], byteorder='big', signed=True) / 10000 param000C = int.from_bytes(body[74:78], byteorder='big', signed=True) / 10000 param0048 = int.from_bytes(body[78:82], byteorder='big', signed=True) / 10000 param0026 = int.from_bytes(body[82:86], byteorder='big', signed=True) / 10000 param0028 = int.from_bytes(body[86:90], byteorder='big', signed=True) / 10000 param002A = int.from_bytes(body[90:94], byteorder='big', signed=True) / 10000 return { '1B20': param1B20, '1B24': param1B24, '1B28': param1B28, '1B2C': param1B2C, '1B30': param1B30, '0002': param0002, '0004': param0004, '0006': param0006, '0008': param0008, '000A': param000A, '000C': param000C, '0048': param0048, '0026': param0026, '0028': param0028, '002A': param002A, }