in transform_binary_payload/src-iotrule-transformation/app.py [0:0]
def lambda_handler(event, context):
""" Transforms a binary payload by invoking "decode_{event.type}" function
Parameters
----------
PayloadData : str (obligatory parameter)
Base64 encoded input payload
PayloadDecoderName : string (obligatory parameter)
The value of this attribute defines the name of a Python module which will be used to perform binary decoding. If value of "type" is for example "sample_device", then this function will perform an invocation of "sample_device.dict_from_payload" function. For this approach to work, you have to import the necessary modules, e.g. by performing a "import sample_device01" command in the beginning of this file.
WirelessDeviceId : str (optional parameter)
Wireless Device Id
WirelessMetadata : json (obligatory parameter)
This parameter contains Metadata of transmission according to the example below.
Obligatory element is: LoRaWAN.FPort
All other elements are optional and ignored in the current implementation.
Sample input:
{
"LoRaWAN": {
"DataRate": 0,
"DevEui": "a84041d55182720b",
"FPort": 21,
"Frequency": 867900000,
"Gateways": [
{
"GatewayEui": "dca632fffe45b3c0",
"Rssi": -76,
"Snr": 9.75
}
],
"Timestamp": "2020-12-07T14:41:48Z"
}
Returns
-------
This function returns a JSON object with the following keys:
- status: 200 or 500
- transformed_payload: output of function "decode_{event.type}" (only if status == 200)
- error_type (only if status == 500)
- error_message (only if status == 500)
- stackTrace (only if status == 500)
"""
logger.info("Received event: %s" % json.dumps(event))
# Store event input and perform input validation
input_base64 = event.get("PayloadData")
payload_decoder_name = event.get("PayloadDecoderName")
# Validate existence of payload type
if payload_decoder_name is None:
raise InvalidInputException(
"PayloadDecoderName is not specified")
# Validate if payload type is in the list of allowed values
if payload_decoder_name not in VALID_PAYLOAD_DECODER_NAMES:
raise InvalidInputException(
"PayloadDecoderName have one of the following values:"+(".".join(VALID_PAYLOAD_DECODER_NAMES)))
logger.info(f"Base64 input={input_base64}, Type={payload_decoder_name}")
# Retrieve FPort from the metadata. In case FPort or surrounding attributes is missing,
# the function will intentionally not fail but proceed with fPort == None.
# The binary decoder function is expected to handle fPort == None.
fPort = None
if "WirelessMetadata" in event:
if "LoRaWAN" in event.get("WirelessMetadata"):
if "FPort" in event.get("WirelessMetadata").get("LoRaWAN"):
fPort = event.get("WirelessMetadata").get(
"LoRaWAN").get("FPort")
else:
logger.warn(
"Attribute 'WirelessMetadata.LoRaWAN' is missing. Will proceed with fPort == None.")
else:
logger.warn(
"Attribute 'WirelessMetadata.LoRaWAN' is missing. Will proceed with fPort == None.")
else:
logger.warn(
"Attribute 'WirelessMetadata' is missing. Will proceed with fPort == None.")
# Derive a name of a payload conversion function based on the value of 'type' attribute
conversion_function_name = f"{payload_decoder_name}.dict_from_payload"
logger.info(f"Function name={conversion_function_name}")
# Invoke a payload conversion function and return a result
try:
result = eval(conversion_function_name)(input_base64, fPort)
result["status"] = 200
result["decoder_name"] = payload_decoder_name
logger.info(result)
return result
except Exception as exp:
exception_type, exception_value, exception_traceback = sys.exc_info()
traceback_string = traceback.format_exception(
exception_type, exception_value, exception_traceback)
result = {
"status": 500,
"decoder_name": payload_decoder_name,
"errorType": exception_type.__name__,
"errorMessage": str(exception_value),
"stackTrace": traceback_string
}
logger.error(result)
return result