RAK10701 field tester returing "null" values

Hi,

Im trying to connect a Rak10701 field tester to my Chirpstack network. ive set up the field tester and i have it connecting to my network through my gateway and then sending packets to Data cake but the ball seams to stop there my debug is saying :
Payload decoder did not return list of measurements Returned instead: null

Log: null

and if i run the payload decoder i get: json: unsupported value: NaN

Ive sifted through the code and cant find anything obvious ive also run through the setup again but still returning the same. any help would be greatly appreciated!
payload decoder code below:

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;
		return dist;
	}
}

function Decoder(bytes, fPort) {
	var decoded = {};
	// avoid sending Downlink ACK to integration (Cargo)
	if (fPort === 1) {
		var lonSign = (bytes[0] >> 7) & 0x01 ? -1 : 1;
		var latSign = (bytes[0] >> 6) & 0x01 ? -1 : 1;

		var encLat = ((bytes[0] & 0x3f) << 17) +
			(bytes[1] << 9) +
			(bytes[2] << 1) +
			(bytes[3] >> 7);

		var encLon = ((bytes[3] & 0x7f) << 16) +
			(bytes[4] << 8) +
			bytes[5];

		var hdop = bytes[8] / 10;
		var sats = bytes[9];

		var maxHdop = 2;
		var minSats = 5;

		if ((hdop < maxHdop) && (sats >= minSats)) {
			// Send only acceptable quality of position to mappers
			decoded.latitude = latSign * (encLat * 108 + 53) / 10000000;
			decoded.longitude = lonSign * (encLon * 215 + 107) / 10000000;
			decoded.altitude = ((bytes[6] << 8) + bytes[7]) - 1000;
			decoded.accuracy = (hdop * 5 + 5) / 10
			decoded.hdop = hdop;
			decoded.sats = sats;
			decoded.location = "(" + decoded.latitude + "," + decoded.longitude + ")";
		} else {
			decoded.error = "Need more GPS precision (hdop must be <" + maxHdop +
				" & sats must be >= " + minSats + ") current hdop: " + hdop + " & sats:" + sats;
			decoded.latitude = latSign * (encLat * 108 + 53) / 10000000;
			decoded.longitude = lonSign * (encLon * 215 + 107) / 10000000;
			decoded.altitude = ((bytes[6] << 8) + bytes[7]) - 1000;
			decoded.accuracy = (hdop * 5 + 5) / 10
			decoded.hdop = hdop;
			decoded.sats = sats;
			decoded.location = "(" + decoded.latitude + "," + decoded.longitude + ")";
		}
		// 		decoded.raw = rawPayload.uplink_message.rx_metadata[0].location;
		decoded.num_gw = normalizedPayload.gateways.length;
		decoded.minRSSI = 0;
		decoded.maxRSSI = 0;
		decoded.minSNR = 0;
		decoded.maxSNR = 0;
		decoded.minDistance = 0;
		decoded.maxDistance = 0;

		var server_type = 0;
		// Check if payload comes from TTN
		if (typeof (rawPayload.uplink_message) != "undefined") {
			console.log("Found TTN format");
			server_type = 1;
			decoded.is_chirpstack = 1;
		}
		// Check if payload comes from Helium
		else if (typeof (rawPayload.hotspots) != "undefined") {
			console.log("Found Helium format");
			server_type = 2;
		}
		// Check if payload comes from Chirpstack
		else if (typeof (rawPayload.rxInfo) != "undefined") {
			console.log("Found Chirpstack format");
			server_type = 3;
			decoded.is_chirpstack = 1;
		}
		//Check if the payload comes from LORIOT
		else if (typeof (rawPayload.cmd) != "undefined") {
			console.log("Found LORIOT format");
			server_type = 4;
			decoded.is_chirpstack = 1;
		}
		else {
			console.log("Unknown raw format");
		}

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

		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;
			}
		}

		var has_location = false;
		for (idx = 0; idx < decoded.num_gw; idx++) {
			has_location = true;
			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;
			}

			switch (server_type) {
				//TTN
				case 1:
					if (typeof (rawPayload.uplink_message.rx_metadata[idx].location) != "undefined") {
						gw_lat[idx] = rawPayload.uplink_message.rx_metadata[idx].location.latitude;
						gw_long[idx] = rawPayload.uplink_message.rx_metadata[idx].location.longitude;
						has_location = true;
					} else {
						has_location = false;
						decoded.num_gw -= 1;
						idx++;
						has_location = false;
					}
					break;
				// Helium
				case 2:
					if (typeof (rawPayload.hotspots[idx].lat) != "undefined") {
						gw_lat[idx] = rawPayload.hotspots[idx].lat;
						gw_long[idx] = rawPayload.hotspots[idx].long;
						gw_loc_valid[idx] = true;
					} else {
						gw_loc_valid[idx] = false;
						decoded.num_gw -= 1;
						idx++;
						has_location = false;
					}
					break;
				// Chirpstack
				case 3:
					if (typeof (rawPayload.rxInfo[idx].location) != "undefined") {
						gw_lat[idx] = rawPayload.rxInfo[idx].location.latitude;
						gw_long[idx] = rawPayload.rxInfo[idx].location.longitude;
						gw_loc_valid[idx] = true;
					} else {
						gw_loc_valid[idx] = false;
						decoded.num_gw -= 1;
						idx++;
						has_location = false;
					}
					break;

				// LORIOT
				case 4:
					if (typeof (rawPayload.gws[0].lat) != "undefined") {
						gw_lat[idx] = rawPayload.gws[0].lat;
						gw_long[idx] = rawPayload.gws[0].lon;
						gw_loc_valid[idx] = true;
					} else {
						gw_loc_valid[idx] = false;
						decoded.num_gw -= 1;
						idx++;
						has_location = false;
					}
					break;
				default:
					console.log("Unknown LNS");
					gw_loc_valid[idx] = false;
					decoded.num_gw -= 1;
					idx++;
					has_location = false;
					break;
			}

			if (has_location == true) {
				console.log("IDX " + idx + " lat " + gw_lat[idx] + " long " + gw_long[idx]);

				// Calculate distance
				var new_distance = distance(gw_lat[idx], gw_long[idx], decoded.latitude, decoded.longitude);
				if ((new_distance * 1000 < decoded.minDistance) || (decoded.minDistance == 0)) {
					decoded.minDistance = new_distance * 1000;
				}
				if ((new_distance * 1000 > decoded.maxDistance) || (decoded.maxDistance == 0)) {
					decoded.maxDistance = new_distance * 1000;
				}
			} else {
				console.log("Gateway IDX " + idx-1 + " has no location");
			}

		}

		var hotspot_name = ""
		for (idx = 0; idx < decoded.num_gw; idx++) {
			var index = idx + 1;
			if (index < 9) {
				hotspot_name = "hotspot_0" + index.toString();
			} else {
				hotspot_name = "hotspot_" + index.toString();
			}
			console.log(hotspot_name);
			decoded[hotspot_name] = "(" + gw_lat[idx] + "," + gw_long[idx] + ")";
		}

		decoded.maxMod = 1 + parseInt((Math.round(decoded.maxDistance / 250.0)), 10);
		decoded.minMod = 1 + parseInt((Math.round(decoded.minDistance / 250.0)), 10);

		return decoded;
	}
	return null;

}

Welcome to the forum @Owen385

Can you please send the payload you see in Chirpstack:

And the payload you see in Datacake:

You will see “Payload decoder did not return list of measurements” in the Datacake log, this is normal and for duplicate webhook data received from the LNS. You can ignore them:

Try this decoder in Datacake:
decoder.zip (1.8 KB)

Hi,

Thanks for your reply that makes sense with the duplicate id.

my chirpstack data is:

  • data:“pM7ZgJLlBHQLCQ==”
  • gatewayId:“ac1f09fffe100ee5”
  • uplinkId:34221
  • gwTime:“2024-07-04T08:09:45.912407+00:00”
  • nsTime:“2024-07-04T08:09:45.927845405+00:00”
  • timeSinceGpsEpoch:“1404115803.912s”
  • rssi:-81
  • snr:7
  • channel:3

and my data cake data is:

{“time”:“2024-07-04T08:07:02.770514888+00:00”,“deviceInfo”:{“tenantId”:“52f14cd4-c6f1-4fbd-8f87-4025e1d49242”,“tenantName”:“ChirpStack”,“applicationId”:“ea7e6f37-1586-4eac-b79c-45b1b5b09900”,“applicationName”:"RAK10701 ",“deviceProfileId”:“7e3caa58-bc9a-4a82-a562-ca293b14e6ec”,“deviceProfileName”:“RAK Field Tester”,“deviceName”:“RAK 10701”,“devEui”:“ac1f09fffe0fe746”,“deviceClassEnabled”:“CLASS_A”,“tags”:{}},“level”:“ERROR”,“code”:“UPLINK_CODEC”,“description”:“JS error: Error:191:9 ‘decodeUplink’ is not defined\n at ,[object Object], (eval_script:191:9)\n”,“context”:{“deduplication_id”:“330a2878-a4df-4b03-b81d-49a0eba7b5fe”}}

Also i have noticed im getting an uplink error from the codec maybe?

2024-07-04 09:15:46

DR: 1

Data: a4cece8092e50465090a

FCnt: 1126

FPort: 1

2024-07-04 09:15:46

Code: UPLINK_CODEC

Level: ERROR

Thanks

Error description:
JS error: Error:[eval_script]:49:8 unexpected token in expression: ‘’ at eval_script:49:8 "

Codec Code:

function Decode(fPort, bytes, variables) {
    var decoded = {};
    // avoid sending Downlink ACK to integration (Cargo)
    if ((fPort === 1) || (fPort === 2)){
        var lonSign = (bytes[0] >> 7) & 0x01 ? -1 : 1;
        var latSign = (bytes[0] >> 6) & 0x01 ? -1 : 1;

        var encLat = ((bytes[0] & 0x3f) << 17) +
            (bytes[1] << 9) +
            (bytes[2] << 1) +
            (bytes[3] >> 7);

        var encLon = ((bytes[3] & 0x7f) << 16) +
            (bytes[4] << 8) +
            bytes[5];

        var hdop = bytes[8] / 10;
        var sats = bytes[9];

        var maxHdop = 2;
        var minSats = 5;

        if ((hdop < maxHdop) && (sats >= minSats)) {
            // Send only acceptable quality of position to mappers
            decoded.latitude = latSign * (encLat * 108 + 53) / 10000000;
            decoded.longitude = lonSign * (encLon * 215 + 107) / 10000000;
            decoded.altitude = ((bytes[6] << 8) + bytes[7]) - 1000;
            decoded.accuracy = (hdop * 5 + 5) / 10
            decoded.hdop = hdop;
            decoded.sats = sats;
        } else {
            decoded.error = "Need more GPS precision (hdop must be <" + maxHdop +
                " & sats must be >= " + minSats + ") current hdop: " + hdop + " & sats:" + sats;
            decoded.latitude = latSign * (encLat * 108 + 53) / 10000000;
            decoded.longitude = lonSign * (encLon * 215 + 107) / 10000000;
            decoded.altitude = ((bytes[6] << 8) + bytes[7]) - 1000;
            decoded.accuracy = (hdop * 5 + 5) / 10
            decoded.hdop = hdop;
            decoded.sats = sats;
        }
        return decoded;
    }
    return null;

The payload coming from the device is ok
Base64 ==> pM7ZgJLlBHQLCQ==
Hex array ==> a4 ce d9 80 92 e5 04 74 0b 09

My decoder on Datacake returns:

accuracy = 1.05 (time: auto)
altitude = 140 (time: auto)
hdop = 1.1 (time: auto)
latitude = 52.1045945 (time: auto)
LOCATION = (52.1045945,-0.8085182) (time: auto)
longitude = -0.8085182 (time: auto)
MAXDISTANCE = 0 (time: auto)
MAXMOD = 1 (time: auto)
MAXRSSI = -60 (time: auto)
MAXSNR = 10 (time: auto)
MINDISTANCE = 0 (time: auto)
MINMOD = 1 (time: auto)
MINRSSI = -60 (time: auto)
MINSNR = 10 (time: auto)
NUM_GW = 0 (time: auto)
sats = 9 (time: auto)

That looks good.

This error
JS error: Error:[eval_script]:49:8 unexpected token in expression: ‘’ at eval_script:49:8 "
points to a problem with the javascript, together with the

Code: UPLINK_CODEC
Level: ERROR

The UPLINK_CODEC error points towards a problem in the Chirpstack decoder, but should be irrelevant for Datacake and Chirpstack is still sending the correct payload.

For the functionality, you don’t need any downlink or uplink decoders in Chirpstack. They are more for checking/visualization of the received packets in Chirpstack.

Did you try the decoder script I sent you earlier in Datacake?

If you don’t get it to work with Datacake (it works for me), here is an alternative way to create a backend server for the RAK10701 Field Tester.

RAK10701 - Alternative backend server

1 Like

I tried the decoder you sent and i get json: unsupported value: NaN as an output?

I don’t know why.

I have exactly that decoder on Datacake, connected to a Chirpstack V4 LNS in the cloud and using the latest firmware on the RAK10701.

Works without problems.

i think all these parameters are correct and they are also loading with data?

i also have Field tester LOCATION Location N/A
with a current value but obviously don’t want to hare them

Returned values look ok, I really don’t know why the rest doesn’t work.

im giving your alternative back end ago on Node-red i will let you know if i have more succsess!
Thanks for all your help aswell!

This worked perfectly! Thank you so much for you help! i was pulling my hair out trying to figure out whats wrong!

Me too, no more hairs left.
I have no idea why it works for me on Datacake, but not for others.

2 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.