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.