Payload Parse for RAK10701 in the TagoIO

I have to create a Decoder(uplink)/Encoder(downlink) for a RakWireless RAK10701-P Field Tester. I did a customization in the original Rakwireless script: RAK10701-P Field Tester Pro for LoRaWAN Quick Start Guide | RAKwireless Documentation Center

I already tested a lot of options but I can´t see the JS decoder running in the Live Inspector and without error messages.

Could you help me? My version script is here:

function distance(lat1, lon1, lat2, lon2) {
    if ((lat1 == lat2) && (lon1 == lon2)) {
        return 0;
    }
    else {
        var radlat1 = Math.PI * lat1 / 180;
        var radlat2 = Math.PI * lat2 / 180;
        var theta = lon1 - lon2;
        var radtheta = Math.PI * theta / 180;
        var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
        if (dist > 1) {
            dist = 1;
        }
        dist = Math.acos(dist);
        dist = dist * 180 / Math.PI;
        dist = dist * 60 * 1.1515;
        dist = dist * 1.609344;
		context.log = ("distancia = " + dist);
        return dist;
    }
}

function Decoder(payload, fPort) {
try {
    console.log = ("começou o try")
    var decoded = {};
    // avoid sending Downlink ACK to integration (Cargo)
    if ((fPort === 1) || (fPort === 2)) {
        var lonSign = (payload[0] >> 7) & 0x01 ? -1 : 1;
        var latSign = (payload[0] >> 6) & 0x01 ? -1 : 1;
        var encLat = ((payload[0] & 0x3f) << 17) + (payload[1] << 9) + (payload[2] << 1) +  (payload[3] >> 7);
        var encLon = ((payload[3] & 0x7f) << 16) + (payload[4] << 8) + payload[5];
        var maxHdop = 2;
        var minSats = 5;

        if ((hdop < maxHdop) && (sats >= minSats)) {
            // Send only acceptable quality of position to mappers
        } else {
            decoded.error = "Need more GPS precision (hdop must be <" + maxHdop +
                " & sats must be >= " + minSats + ") current hdop: " + hdop + " & sats:" + sats;
        }
// latitude
		const latitude = {
			variable: 'latitude',
			value: latSign * (encLat * 108 + 53) / 10000000,
			unit: '°'
			};
		decoded.latitude = latitude;
// longitude
		const longitude = {
			variable: 'longitude',
			value: lonSign * (encLon * 215 + 107) / 10000000,
			unit: '°'
			};
		decoded.longitude = longitude;
// altitude
        const altitude = {
            variable: 'altitude',
            value: ((payload[6] << 8) + payload[7]) - 1000,
            unit: 'm'
            };
        decoded.altitude = altitude;

// HDOP: Diluição da Precisão Horizontal
// VDOP: Diluição da Precisão Vertical
// PDOP: Diluição da Precisão de Posição (3D). Geralmente VDOP e HDOP foram substituidas pelo PDOP que já dá a precisão das duas anteriores na mesma variável.
// TDOP: Diluição da Precisão Temporal
// GDOP: Diluição da Precisão Geométrica. Basicamente a combinação de todos acima. GDOP=RaizQuadrada(PDOP^2 + TDOP^2)
        const hdop = {
            variable: 'hdop',
            value: payload[8] / 10,
            unit: ''
            };
        decoded.hdop = hdop;
// accuracy
        const accuracy = {
            variable: 'accuracy',
            value: (hdop * 5 + 5) / 10,
            unit: '%'
            };
        decoded.accuracy = accuracy;
// Satellites
            const sats = {
            variable: 'sats',
            value: payload[9],
            unit: ''
            };
        decoded.sats = sats;
// Location = Latitude and Longitude
        const location = {
            variable: 'location',
            value: "(" + decoded.latitude + "," + decoded.longitude + ")",
            unit: ''
            };
        decoded.location = location
		
		context.log = ("location = " + decoded.location);
				
//      decoded.raw = rawPayload.uplink_message.rx_metadata[0].location;
// Gateways Quantity
        const num_gw = {
            variable: 'nw_gw',
            value: normalizedPayload.gateways.length,
            unit: ''
            };

        decoded.num_gw = num_gw;
// Received Signal Strength Idication - RSSI
        var server_type = 0;
        // Check if payload comes from TTN
        if (typeof (rawPayload.uplink_message) != "undefined") {
            console.log("Found TTN format");
            server_type = 1;
        }
		else {
            console.log("Unknown raw format");
        }

        var gw_lat = {};
        var gw_long = {};

        decoded.num_gw = 0;

        for (idx_tst = 0; idx_tst < 10; idx_tst++)
        {
            if (typeof (normalizedPayload.gateways[idx_tst]) != "undefined")
            {
                console.log("Found gateway with IDX " + idx_tst);
                decoded.num_gw += 1;
            }
        }

        decoded.minRSSI = 0;
        decoded.maxRSSI = 0;
        decoded.minSNR = 0;
        decoded.maxSNR = 0;


        for (idx = 0; idx < decoded.num_gw; idx++) {
            var new_rssi = (!!normalizedPayload.gateways && !!normalizedPayload.gateways[idx] && normalizedPayload.gateways[idx].rssi) || 0;
            var new_snr = (!!normalizedPayload.gateways && !!normalizedPayload.gateways[idx] && normalizedPayload.gateways[idx].snr) || 0;
            if ((new_rssi < decoded.minRSSI) || (decoded.minRSSI == 0)) {
                decoded.minRSSI = new_rssi;
            }
            if ((new_rssi > decoded.maxRSSI) || (decoded.maxRSSI == 0)) {
                decoded.maxRSSI = new_rssi;
            }
            if ((new_snr < decoded.minSNR) || (decoded.minSNR == 0)) {
                decoded.minSNR = new_snr;
            }
            if ((new_snr > decoded.maxSNR) || (decoded.maxSNR == 0)) {
                decoded.maxSNR = new_snr;
            }

            // var gw_lat = 0.0;
            // var gw_long = 0.0;
            switch (server_type) {
                //TTN
                case 1:
                    gw_lat[idx] = rawPayload.uplink_message.rx_metadata[idx].location.latitude;
                    gw_long[idx] = rawPayload.uplink_message.rx_metadata[idx].location.longitude;
                    break;
                default:
                    console.log("Unknown LNS");
                    break;
            }

            console.log("IDX " + idx + " lat " + gw_lat[idx] + " long " + gw_long[idx]);
            // decoded.gw_lat[idx] = gw_lat;
            // decoded.gw_long[idx] = gw_long;

            // Calculate distance
            decoded.minDistance = 0;
            decoded.maxDistance = 0;
            var new_distance = distance(gw_lat[idx], gw_long[idx], decoded.latitude, decoded.longitude);
            if ((new_distance < decoded.minDistance) || (decoded.minDistance == 0)) {
                decoded.minDistance = new_distance * 1000;
            }
            if ((new_distance > decoded.maxDistance) || (decoded.maxDistance == 0)) {
                decoded.maxDistance = new_distance * 1000;
            }
        }

        switch (decoded.num_gw) {
            case 20:
                decoded.hotspot_10 = "(" + gw_lat[19] + "," + gw_long[19] + ")";
            case 19:
                decoded.hotspot_09 = "(" + gw_lat[18] + "," + gw_long[18] + ")";
            case 18:
                decoded.hotspot_08 = "(" + gw_lat[17] + "," + gw_long[17] + ")";
            case 17:
                decoded.hotspot_07 = "(" + gw_lat[16] + "," + gw_long[16] + ")";
            case 16:
                decoded.hotspot_06 = "(" + gw_lat[15] + "," + gw_long[15] + ")";
            case 15:
                decoded.hotspot_05 = "(" + gw_lat[14] + "," + gw_long[14] + ")";
            case 14:
                decoded.hotspot_04 = "(" + gw_lat[13] + "," + gw_long[13] + ")";
            case 13:
                decoded.hotspot_03 = "(" + gw_lat[12] + "," + gw_long[12] + ")";
            case 12:
                decoded.hotspot_02 = "(" + gw_lat[11] + "," + gw_long[11] + ")";
            case 11:
                decoded.hotspot_01 = "(" + gw_lat[10] + "," + gw_long[10] + ")";
            case 10:
                decoded.hotspot_10 = "(" + gw_lat[9] + "," + gw_long[9] + ")";
            case 9:
                decoded.hotspot_09 = "(" + gw_lat[8] + "," + gw_long[8] + ")";
            case 8:
                decoded.hotspot_08 = "(" + gw_lat[7] + "," + gw_long[7] + ")";
            case 7:
                decoded.hotspot_07 = "(" + gw_lat[6] + "," + gw_long[6] + ")";
            case 6:
                decoded.hotspot_06 = "(" + gw_lat[5] + "," + gw_long[5] + ")";
            case 5:
                decoded.hotspot_05 = "(" + gw_lat[4] + "," + gw_long[4] + ")";
            case 4:
                decoded.hotspot_04 = "(" + gw_lat[3] + "," + gw_long[3] + ")";
            case 3:
                decoded.hotspot_03 = "(" + gw_lat[2] + "," + gw_long[2] + ")";
            case 2:
                decoded.hotspot_02 = "(" + gw_lat[1] + "," + gw_long[1] + ")";
            case 1:
                decoded.hotspot_01 = "(" + gw_lat[0] + "," + gw_long[0] + ")";
            default:
                break;
        }

        decoded.maxMod = parseInt((decoded.maxDistance / 250), 10);
        decoded.minMod = parseInt((decoded.minDistance / 250), 10);
        decoded.maxDistance = parseInt((decoded.maxMod * 250), 10);
        decoded.minDistance = parseInt((decoded.minMod * 250), 10);
        if (decoded.maxDistance <= 1) {
            decoded.maxDistance = parseInt(250, 10);
        }
        if (decoded.minDistance <= 1) {
            decoded.minDistance = parseInt(250, 10);
        }
        console.log = ("termino normal = " + decoded);
        return decoded;
    }
    console.log = ("terminou o try");
} catch (error) {
    console.log = ("termino com erro");
    console.error("codigo de erro = " + error);
} finally {
    console.log ("terminou sem erros")
}
    return null;
}

The script that we have available in the “quick start guide” has not defined variable ```
normalizedPayload . Who can fix this?
``
Regards,

Claudio

The scripts in the quickstart guide is for Datacake, which provides the gateway information (how many gateways have received the packet from the RAk10701 and what is there geo-location) in a variable called normalizedPayload.

You might ask TagoIO if they provide this information to their payload parser and how.

I can see some information in the raw payload that TagoIO receives from the LoRaWAN server, but I am not sure if you can access this from the parser.

[{\"gatewayID\":\"YMWo//52YjI=\",\"time\":null,\"timeSinceGPSEpoch\":null,\"rssi\":-72,\"loRaSNR\":5.3,\"channel\":6,\"rfChain\":1,\"board\":0,\"antenna\":0,\"location\":{\"latitude\":14.42141,\"longitude\":121.00693,\"altitude\":80,\"source\":\"UNKNOWN\",\"accuracy\":0},\"fineTimestampType\":\"NONE\",\"context\":\"XPxQRA==\",\"uplinkID\":\"v5m7PzS0QP+3B1mmkriR/w==\",\"crcStatus\":\"CRC_OK\"}]

Thank you by your support!

If I understood your explanation, normalizedPayload is a Datacake variable, then in the TagoIO we have: https://help.tago.io/portal/en/kb/articles/213-payload-parser-context-global-variables

Am I correct?

Regards,

Claudio

I am very new to TagoIO. Just started to using it and still learning.

I have purchased the same RAK FieldTester and same as you I tought at first it was plug and play. I am also using TAGOIO. Have you had any luck succeeding in getting TAGOIO to send the correct informatin back to the FieldTester? I am using Thinkpark Enterprise as my gateway and devices manager

Welcome back to the forum @sandovalch

Plug&Play is true for the RAK10702-H version which works on the Helium Network and where the device is already registered on a Helium Console and uses the default back-end.

For RAK10702-P and RAK10702-L when using Helium and TTN servers, it is 50% true if you use the suggested back-end as shown in our documentation. You still have to register the device on the LoRaWAN servers.

For other LoRaWAN servers and “self-made” back-ends, it requires manual work and might not work with all integration’s. The integration with Chirpstack and Datacake was made as an example how to create your own back-end, TagoIO seems to be way more complicated and I got it only 50% working (receiving and parsing the incoming packets) when using Chirpstack V3 but could not go further due to other work.

Good morning Mrs,

@sandovalch , I am working on a @beegee javascript code to make the decoder as a object oriented programming. I am trying to map all fields that I have in the TTN Payload, not only for RAK10701 payload, but for future use. But its is not ready yet, but i hope it will be ready next week. Take a look in the code that I have today and above you will see the TTN_Payload example with 2 Rakwireless LoRaWAN gateways:

  1. RAK7249 => “gateway_id”: “eui-60c5a8fffe74d472”
  2. RAK7258 => “gateway_id”: “brrjnasondasgw01”
try {
	raw_payload_JSON       = JSON.parse(raw_payload[0].value);
	
	class TTN_payload  {
		
		name
		time
		device_id
	    application_id
		dev_eui
		join_eui
		dev_addr
		correlation_ids
		rcv_at
		session_key_id
		f_port
		f_cnt
		frm_payload
		// gateway ids array
        gw_numb
		gw_id = []
		eui   = []
		time  = []
		timestamp = []
		rssi      = []
		channel_RSSI = []
		snr			 = []
		latitude	 = []
		longitude	 = []
		altitude	 = []
		source		 = []
		uplink_token = []
		receive_at	 = []
        rx_metadata  =   [
						gw_id,
						gw_eui,
                        gw_time,
						gw_timestamp,
						gw_rssi,
						gw_channel_RSSI,
						gw_snr,
						gw_latitude,
						gw_longitude,
						gw_altitude,
						gw_source,
						gw_uplink_token,
						gw_receive_at
                         ]
        bandwidth
		spreading_factor
		coding_rate
		frequency
		timestamp
        time 
        received_at
        confirmed
		consumed_airtime
        latitude
		longitude
        altitude
        source
        net_id
        tenant_id
        cluster_id
        cluster_addr
        correlation_ids
        origin
        tenant_id
        rights
        unique_id
        // end of payload fields
		
		
		maxRSSI
		minRSSI
		minSNR 
		maxSNR

        constructor () {
            this.name            = raw_payload_JSON.name;
            this.time            = raw_payload_JSON.time;
            this.device_id       = raw_payload_JSON.identifiers.device_ids.device_id;
            this.application_id  = raw_payload_JSON.identifiers.device_ids.application_ids.application_id;
            this.dev_eui         = raw_payload_JSON.identifiers.device_ids.dev_eui;
            this.join_eui        = raw_payload_JSON.identifiers.device_ids.join_eui;
            this.dev_addr        = raw_payload_JSON.identifiers.device_ids.dev_addr;
            this.correlation_ids = raw_payload_JSON.data.correlation_ids;
            this.rcv_at          = raw_payload_JSON.data.received_at;
            this.session_key_id  = raw_payload_JSON.data.uplink_message.session_key_id;
            this.f_port          = raw_payload_JSON.data.uplink_message.f_port;
            this.f_cnt           = raw_payload_JSON.data.uplink_message.f_cnt;
            this.frm_payload     = raw_payload_JSON.data.uplink_message.frm_payload;
            this.gw_qdty         = raw_payload_JSON.data.uplink_message.rx_metadata.length;

			get_gw_data(gw_qdty)

			this.bandwidth 		  = raw_payload_JSON.uplink_message.settings.data_rate.lora.bandwidth;
			this.spreading_factor = raw_payload_JSON.uplink_message.settings.data_rate.lora.spreading_factor;
			this.coding_rate  	  = raw_payload_JSON.uplink_message.settings.data_rate.lora.coding_rate;
			this.frequency		  = raw_payload_JSON.uplink_message.settings.frequency;
			this.timestamp 		  = raw_payload_JSON.uplink_message.settings.timestamp;
			this.time 			  = raw_payload_JSON.uplink_message.settings.time;
			this.received_at 	  = raw_payload_JSON.uplink_message.received_at;
			this.confirmed		  = raw_payload_JSON.uplink_message.confirmed;
			this.consumed_airtime = raw_payload_JSON.uplink_message.consumed_airtime;
			this.latitude  		  = raw_payload_JSON.uplink_message.locations.frm_locations.latitude;
			this.longitude 		  = raw_payload_JSON.uplink_message.locations.frm_locations.longitude;
			this.altitude  		  = raw_payload_JSON.uplink_message.locations.frm_locations.altitude;
			this.source    		  = raw_payload_JSON.uplink_message.locations.frm_locations.source;
			this.tenant_id 		  = raw_payload_JSON.uplink_message.network_ids.tenant_id;
			this.cluster_id 	  = raw_payload_JSON.uplink_message.network_ids.cluster_id;
			this.cluster_addr 	  = raw_payload_JSON.uplink_message.network_ids.cluster_addr;
			this.correlation_ids  = raw_payload_JSON.correlation_ids;
			this.origin 		  = raw_payload_JSON.origin;
			}

2 gateways coverage TTN payload example:

{
    "name": "as.up.data.forward",
    "time": "2023-03-23T11:02:08.442016478Z",
    "identifiers": [
      {
        "device_ids": {
          "device_id": "eui-ac1f09fffe08e7af",
          "application_ids": {
            "application_id": "rakwireless-field-tester"
          },
          "dev_eui": "AC1F09FFFE08E7AF",
          "join_eui": "AC1F09FFF9150701",
          "dev_addr": "260B218D"
        }
      }
    ],
    "data": {
      "@type": "type.googleapis.com/ttn.lorawan.v3.ApplicationUp",
      "end_device_ids": {
        "device_id": "eui-ac1f09fffe08e7af",
        "application_ids": {
          "application_id": "rakwireless-field-tester"
        },
        "dev_eui": "AC1F09FFFE08E7AF",
        "join_eui": "AC1F09FFF9150701",
        "dev_addr": "260B218D"
      },
      "correlation_ids": [
        "as:up:01GW72469PNQV409YM8H1HYKH2",
        "gs:conn:01GW595BKTEQ0X7C5DYC0ZGMXP",
        "gs:up:host:01GW595BM3WJ9P4KR2ZG9RPCGY",
        "gs:uplink:01GW724632XEBZC34GZC7C99D8",
        "ns:uplink:01GW724634P15027XEK74Z1K37",
        "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01GW72463445NRMFMZQN25SHA6",
        "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01GW72469PSKRPDFDKH4QDGP1K"
      ],
      "received_at": "2023-03-23T11:02:08.438550175Z",
      "uplink_message": {
        "session_key_id": "AYcLtE//FdjGYCRDhKrEiQ==",
        "f_port": 1,
        "f_cnt": 1413,
        "frm_payload": "0D8Nnsr7A+IHDQ==",
        "rx_metadata": [
          {
            "gateway_ids": {
              "gateway_id": "brrjnasondasgw01",
              "eui": "60C5A8FFFE74D380"
            },
            "time": "2023-03-23T11:02:07.849514961Z",
            "timestamp": 3894624931,
            "rssi": -80,
            "channel_rssi": -80,
            "snr": 9.5,
            "location": {
              "latitude": -22.998018054874855,
              "longitude": -43.38812005529691,
              "altitude": 5,
              "source": "SOURCE_REGISTRY"
            },
            "uplink_token": "Ch4KHAoQYnJyam5hc29uZGFzZ3cwMRIIYMWo//5004AQo4WNwQ4aCwiw4/CgBhDbntdrILiZ8c2syg0=",
            "received_at": "2023-03-23T11:02:08.127537073Z"
          },
          {
            "gateway_ids": {
              "gateway_id": "eui-60c5a8fffe74d472",
              "eui": "60C5A8FFFE74D472"
            },
            "time": "2023-03-23T11:02:07.078655958Z",
            "timestamp": 1703380539,
            "rssi": -54,
            "channel_rssi": -54,
            "snr": 10.25,
            "uplink_token": "CiIKIAoUZXVpLTYwYzVhOGZmZmU3NGQ0NzISCGDFqP/+dNRyELuMnqwGGgwIsOPwoAYQ9KfqsQEg+KyRy8nebg==",
            "received_at": "2023-03-23T11:02:08.120798893Z"
          }
        ],
        "settings": {
          "data_rate": {
            "lora": {
              "bandwidth": 125000,
              "spreading_factor": 7,
              "coding_rate": "4/5"
            }
          },
          "frequency": "916000000",
          "timestamp": 3894624931,
          "time": "2023-03-23T11:02:07.849514961Z"
        },
        "received_at": "2023-03-23T11:02:08.228969009Z",
        "confirmed": true,
        "consumed_airtime": "0.061696s",
        "locations": {
          "frm-payload": {
            "latitude": -22.9978493,
            "longitude": -43.3880212,
            "altitude": 26,
            "source": "SOURCE_GPS"
          }
        },
        "network_ids": {
          "net_id": "000013",
          "tenant_id": "ttn",
          "cluster_id": "eu1",
          "cluster_address": "eu1.cloud.thethings.network"
        }
      }
    },
    "correlation_ids": [
      "as:up:01GW72469PNQV409YM8H1HYKH2",
      "gs:conn:01GW595BKTEQ0X7C5DYC0ZGMXP",
      "gs:up:host:01GW595BM3WJ9P4KR2ZG9RPCGY",
      "gs:uplink:01GW724632XEBZC34GZC7C99D8",
      "ns:uplink:01GW724634P15027XEK74Z1K37",
      "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01GW72463445NRMFMZQN25SHA6",
      "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01GW72469PSKRPDFDKH4QDGP1K"
    ],
    "origin": "ip-10-100-5-244.eu-west-1.compute.internal",
    "context": {
      "tenant-id": "CgN0dG4="
    },
    "visibility": {
      "rights": [
        "RIGHT_APPLICATION_TRAFFIC_READ"
      ]
    },
    "unique_id": "01GW72469TS0MGEJ8KGEMZ2TE8"
  }