Best way for a Wireless IoT Lambda decoder to determine decoder type?

1

Hi, I'm trying to figure out the best design pattern for having a Lambda function that handles decoding multiple binary payload types to determine which decoder to use on an incoming LoRa payload.

The vanilla input event looks like this:

{
    "WirelessDeviceId": "<<REDACTED>>",
    "PayloadData": "BA==",
    "WirelessMetadata": {
      "LoRaWAN": {
        "ADR": true,
        "Bandwidth": 125,
        "ClassB": false,
        "CodeRate": "4/5",
        "DataRate": "3",
        "DevAddr": "01b9c3bb",
        "DevEui": "<<REDACTED>>",
        "FCnt": 312,
        "FOptLen": 0,
        "FPort": 4,
        "Frequency": "904500000",
        "Gateways": [
          {
            "GatewayEui": "<<REDACTED>>",
            "Rssi": -96,
            "Snr": 2.5
          }
        ],
        "MIC": "0110ac72",
        "MType": "UnconfirmedDataUp",
        "Major": "LoRaWANR1",
        "Modulation": "LORA",
        "PolarizationInversion": false,
        "SpreadingFactor": 7,
        "Timestamp": "2021-12-23T19:58:35Z"
      }
    }
  }

Which on it's own doesn't contain any useful information for my Lambda decoder to determine which decoder to use.

Inside Lambda, I have a nodejs script with a bunch of custom decoders as individual modules, each specifically built for a particular device type (categorized by manufacturer & model). The handler imports the appropriate module using a simple if statement and runs the payload through that decoder. Something like this...

const decodera = require('./lib/decodera');
const decoderb = require('./lib/decoderb');

exports.handler = async (event) => {

    // Call the correct transformer function
    if (event.DecoderType === 'a') {
        return decodera(event);

    } else if (event.DecoderType === 'b') {
        return decoderb(event);

    } else {
        console.log(`A transformer for ${event.DecoderType} was not found.`);
    }
    
};

Originally I had a separate Lambda for each decoder, but that gets complex since you need to manage a whole bunch of functions, rules, and topics for each new device type. So I'd prefer to have only one, and let the function determine the correct decoder once the event arrives.

Thats the idea at least. However, this method seems to require an enriched version of the example event above with information about which decoder to use. So I'm trying to figure out how best to handle.

  1. Do I store that info in Dynamo and use a separate rule with get_dynamodb() first (with something like "decoder_type" and add it to the event and then republish it, where the aws_lambda() rule would then send it to the decoder function, where I would republish a second time to the final topic?

  2. Can I at least combine both the get_dynamodb() and aws_lambda() functions into one rule? The point here is it seems I still need Dynamo to store some kind of key to tell Lambda which decoder to use?

  3. Is there a simpler way?

asked 2 years ago344 views
1 Answer
1
Accepted Answer

Hi,

using DynamoDB to store decoder for each WirelessDeviceId and using this DynamoDB table in your Lambda could be a viable approach. In particular that approach makes sense if you need to store any additional per-device information (e.g. some metadata) in DynamoDB anyway. You could also use get_dynamod() and aws_lambda() in one rule.

However there is also an alternative which removes the need for DynamoDB table to store decoder for each WirelessDeviceId:

  1. Create an individual Wireless Destination for each kind of device (i.e for each of decoders). E.g. if you have decoders A and B, you create Wireless Destinations Dest_A and Dest_B. Now if you have device D1,D2 of type A,, and devices D3,D4 of type B, you will need to ensure that each of devices is assigned an appropriate Wireless Destination (i.e. Dest_A for D1,D2 and Dest_B for D3 ,D4).

  2. All of the Wireless Destinations should point to the same IoT Rule. However, in the topic field of the Wireless Destination (click on the "Advanced" dropdown in the console, you specify the name of the decoder (e.g. for decoder A you point to the IoT Rule "ProcescLoRaWANUplink" and use topic name "A")

  3. Now in the IoT Rule you can use expression like:

select topic() as DecoderName, .... 
  1. Now your Lambda function has access to the DecoderName.

This approach moves part of complexity to the management of relationship between the individual LoRaWAN device and correct Wireless Destination. It makes sense if decoder name is the only additional information you want to store per device, according to the requirements of your use case.

Let me know if it helped or if you have other questions here.

answered 2 years ago
  • Great thank you Andrei. I'm trying to make the unique destination/one rule method work. I've set up a test destination/rule combo and and am using the "Advanced" setting in the test destination with a topic of transformer01. In my rule I have the query SELECT *, topic() as TransformerName FROM 'test/lora/uplink' and republishing to test/lora/transformed. However, when I test using the MQTT interface, I get a result of TransformerName": "test/lora/uplink", which means the topic() isn't pulling the value of transformer01 in the destinations Advanced setting. What am I missing?

  • Also, if I try to drop the FROM 'test/lora/uplink' from the rule's query I get no messages (assuming that is what topic() is reading). This may be slightly off topic, but it's pretty confusing since the destination is configured to point directly to the rule, but it still needs to look for the topic on which the destination was published? Starting to get a little lost.... Thanks for your help!

  • Rookie mistake, I wasn't thinking that of course that wouldn't work with the MQTT test client as its not publishing to the destination only the topic specified in the interface. I just tested with a real device pointing to the new destination and it worked. Thank you!

  • Thanks for your feedback and great to hear that it worked! Please mark the question as answered, as it will help other customers to benefit from our fruitful discussion. Have a great day!

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions