How Can I Decode my TTN Payload in DataCake

Hello folks,
I have been working on integrating some hardware into Datacake and I have reached an impasse. I was hoping someone would be able to possibly give me some insight.

I have a sensor that is sending time of flight data to TTS and using a webhook sending that payload to Datacake. I am using a payload decoder that I wrote in TTS and Im able to see that decoded payload in the debug console of Datacake, but I have no idea how to format the decoder properly so that Datacake can extrapolate the proper fields for use in the dashboard.

I have read through all of the documentation that I can find, but I am unable to get the fixes that are referenced to work. This article is explaining what I need to do, but when I add the “Converter for TTN Payload” to the end of my payload decoder in Datacake, that extra function is unable to reference the data fields earlier in the code.

I should note that I am pretty new to javascript, so i apologize if this is a stupid question. That being said, i have had the TTS → Datacake integration working great for all of my other sensor arrays. Up until now though, those have all been more simple readings like temp, humidity, etc. The time of flight data that I am sending now is separated into many channels and is a bit more complicated.

Below is my payload formatter that I am using successfully in TTS and trying to adapt to Datacake. Any help is really really appreciated. Ive been trying to figure this out for a few days and im hitting a wall.


function Bytes2Float32(bytes) {
   var sign = (bytes & 0x80000000) ? -1 : 1;
   var exponent = ((bytes >> 23) & 0xFF) - 127;
   var significand = (bytes & ~(-1 << 23));

   if (exponent == 128) 
       return sign * ((significand) ? Number.NaN : Number.POSITIVE_INFINITY);

   if (exponent == -127) {
       if (significand == 0) return sign * 0.0;
       exponent = -126;
       significand /= (1 << 22);
   } else significand = (significand | (1 << 23)) / (1 << 23);

   return sign * significand * Math.pow(2, exponent);
}

function decodeUplink(input) {
 var data1 = {};
 var data2 = {};
 var data3 = {};
 var data4 = {};
 var data5 = {};
 var data6 = {};
 var data7 = {};
 var data8 = {};
 var data = {};
 var fportcaller = [input.fPort];
 var events = {
   1: "setup",
   2: "5 Minute",
   3: "1 Hour",
   4: "6 Hour pt. 1",
   5: "6 Hour pt. 2",
   6: "6 Hour pt. 3",
   7: "6 Hour pt. 4",
 };



 //Startup
 data1.event = events[input.fPort];
 data1.status =(input.bytes[0]);
 data1.heading = (input.bytes[1]) + (input.bytes[2]);
 data1.pitch = (input.bytes[3]);
 data1.roll = (input.bytes[4]);
 data1.altitude = (input.bytes[4] <<34);
 data1.temperature = (((input.bytes[5] & 0x80 ? input.bytes[5] - 0x100 : input.bytes[5]) << 8) + input.bytes[5]) / 100;
 data1.humidity = (((input.bytes[6] & 0x80 ? input.bytes[6] - 0x100 : input.bytes[6]) << 8) + input.bytes[6]) / 100;
 data1.current = (input.bytes[7] << 1);
 data1.voltage = (input.bytes[8] << 1);
 data1.firmware = (input.bytes[8] << 4);
 data1.gpslong = (input.bytes[8] << 43);
 data1.gpslat = (input.bytes[8] << 23);

 //5 Minute
 data2.event = events[input.fPort];
 data2.status =(input.bytes[0]);
 data2.VL53L5CX_Range_CH1 = (input.bytes[1]) + (input.bytes[2]);
 data2.VL53L5CX_Range_CH2 = (input.bytes[3]) + (input.bytes[4]);
 data2.VL53L5CX_Range_CH3 = (input.bytes[5]) + (input.bytes[6]);
 data2.VL53L5CX_Range_CH4 = (input.bytes[7]) + (input.bytes[8]);
 data2.VL53L5CX_Range_CH5 = (input.bytes[9]) + (input.bytes[10]);
 data2.VL53L5CX_Range_CH6 = (input.bytes[11]) + (input.bytes[12]);
 data2.VL53L5CX_SigStrength_CH1 = (input.bytes[13]);
 data2.VL53L5CX_SigStrength_CH2 = (input.bytes[14]);
 data2.VL53L5CX_SigStrength_CH3 = (input.bytes[15]);
 data2.VL53L5CX_SigStrength_CH4 = (input.bytes[16]);
 data2.VL53L5CX_SigStrength_CH5 = (input.bytes[17]);
 data2.VL53L5CX_SigStrength_CH6 = (input.bytes[18]);
 data2.VL53L5CX_AmbientLight_CH1 = (input.bytes[19]);
 data2.VL53L5CX_AmbientLight_CH2 = (input.bytes[20]);
 data2.VL53L5CX_AmbientLight_CH3 = (input.bytes[21]);
 data2.VL53L5CX_AmbientLight_CH4 = (input.bytes[22]);
 data2.VL53L5CX_AmbientLight_CH5 = (input.bytes[23]);
 data2.VL53L5CX_AmbientLight_CH6 = (input.bytes[24]);
 data2.VL53L5CX_UltrasonicRange_CH1 = (input.bytes[25]);
 data2.VL53L5CX_UltrasonicRange_CH2 = (input.bytes[26]);

 //1 Hour
 data3.event = events[input.fPort];
 data3.status =(input.bytes[2]);
 data3.heading = (input.bytes[1]) + (input.bytes[2]);
 data3.pitch = (input.bytes[1]<< 8);
 data3.roll = (input.bytes[4] << 8);
 data3.temperature = (((input.bytes[5] & 0x80 ? input.bytes[5] - 0x100 : input.bytes[5]) << 8) + input.bytes[5]) / 100;
 data3.humidity = (((input.bytes[6] & 0x80 ? input.bytes[6] - 0x100 : input.bytes[6]) << 8) + input.bytes[6]) / 100;
 data3.current = (input.bytes[3] << 1);
 data3.voltage = (input.bytes[3] << 1);

 //24 Hour
 data4.event = events[input.fPort];
 data4.status =(input.bytes[0]);
 data4.firmware = (input.bytes[1]);
 data4.accuracy = (input.bytes[2]);
 data4.altitude = (input.bytes[3]) + (input.bytes[4]);
 data4.gpslong = (input.bytes[5]) + (input.bytes[6]) + (input.bytes[7]) + (input.bytes[8]);
 data4.gpslong = (input.bytes[9]) + (input.bytes[10]) + (input.bytes[11]) + (input.bytes[12]);


   //6 Hour Part 1
 data5.event = events[input.fPort];
 data5.VL53L5CX_Range_CH1 = (input.bytes[0]) + (input.bytes[1]);
 data5.VL53L5CX_Range_CH2 = (input.bytes[2]) + (input.bytes[3]);
 data5.VL53L5CX_Range_CH3 = (input.bytes[4]) + (input.bytes[5]);
 data5.VL53L5CX_Range_CH4 = (input.bytes[6]) + (input.bytes[7]);
 data5.VL53L5CX_Range_CH5 = (input.bytes[8]) + (input.bytes[9]);
 data5.VL53L5CX_Range_CH6 = (input.bytes[10]) + (input.bytes[11]);
 data5.VL53L5CX_Range_CH7 = (input.bytes[12]) + (input.bytes[13]);
 data5.VL53L5CX_Range_CH8 = (input.bytes[14]) + (input.bytes[15]);
 data5.VL53L5CX_Range_CH9 = (input.bytes[16]) + (input.bytes[17]);
 data5.VL53L5CX_Range_CH10 = (input.bytes[18]) + (input.bytes[19]);
 data5.VL53L5CX_Range_CH11 = (input.bytes[20]) + (input.bytes[21]);
 data5.VL53L5CX_Range_CH12 = (input.bytes[22]) + (input.bytes[23]);
 data5.VL53L5CX_Range_CH13 = (input.bytes[24]) + (input.bytes[25]);
 data5.VL53L5CX_Range_CH14 = (input.bytes[26]) + (input.bytes[27]);
 data5.VL53L5CX_Range_CH15 = (input.bytes[28]) + (input.bytes[29]);
 data5.VL53L5CX_Range_CH16 = (input.bytes[30]) + (input.bytes[31]);
 data5.VL53L5CX_Range_CH17 = (input.bytes[32]) + (input.bytes[33]);
 data5.VL53L5CX_Range_CH18 = (input.bytes[34]) + (input.bytes[35]);
 data5.VL53L5CX_Range_CH19 = (input.bytes[36]) + (input.bytes[37]);
 data5.VL53L5CX_Range_CH20 = (input.bytes[38]) + (input.bytes[39]);
 data5.VL53L5CX_Range_CH21 = (input.bytes[40]) + (input.bytes[41]);
 data5.VL53L5CX_Range_CH22 = (input.bytes[42]) + (input.bytes[43]);
 data5.VL53L5CX_Range_CH23 = (input.bytes[44]) + (input.bytes[45]);
 data5.VL53L5CX_Range_CH24 = (input.bytes[46]) + (input.bytes[47]);
 data5.VL53L5CX_Range_CH25 = (input.bytes[48]) + (input.bytes[49]);
 data5.VL53L5CX_Range_CH26 = (input.bytes[50]) + (input.bytes[51]);

     //6 Hour Part 2
 data6.event = events[input.fPort];
 data6.VL53L5CX_Range_CH27 = (input.bytes[0]) + (input.bytes[1]);
 data6.VL53L5CX_Range_CH28 = (input.bytes[2]) + (input.bytes[3]);
 data6.VL53L5CX_Range_CH29 = (input.bytes[4]) + (input.bytes[5]);
 data6.VL53L5CX_Range_CH30 = (input.bytes[6]) + (input.bytes[7]);
 data6.VL53L5CX_Range_CH31 = (input.bytes[8]) + (input.bytes[9]);
 data6.VL53L5CX_Range_CH32 = (input.bytes[10]) + (input.bytes[11]);
 data6.VL53L5CX_Range_CH33 = (input.bytes[12]) + (input.bytes[13]);
 data6.VL53L5CX_Range_CH34 = (input.bytes[14]) + (input.bytes[15]);
 data6.VL53L5CX_Range_CH35 = (input.bytes[16]) + (input.bytes[17]);
 data6.VL53L5CX_Range_CH36 = (input.bytes[18]) + (input.bytes[19]);
 data6.VL53L5CX_Range_CH37 = (input.bytes[20]) + (input.bytes[21]);
 data6.VL53L5CX_Range_CH38 = (input.bytes[22]) + (input.bytes[23]);
 data6.VL53L5CX_Range_CH39 = (input.bytes[24]) + (input.bytes[25]);
 data6.VL53L5CX_Range_CH40 = (input.bytes[26]) + (input.bytes[27]);
 data6.VL53L5CX_Range_CH41 = (input.bytes[28]) + (input.bytes[29]);
 data6.VL53L5CX_Range_CH42 = (input.bytes[30]) + (input.bytes[31]);
 data6.VL53L5CX_Range_CH43 = (input.bytes[32]) + (input.bytes[33]);
 data6.VL53L5CX_Range_CH44 = (input.bytes[34]) + (input.bytes[35]);
 data6.VL53L5CX_Range_CH45 = (input.bytes[36]) + (input.bytes[37]);
 data6.VL53L5CX_Range_CH46 = (input.bytes[38]) + (input.bytes[39]);
 data6.VL53L5CX_Range_CH47 = (input.bytes[40]) + (input.bytes[41]);
 data6.VL53L5CX_Range_CH48 = (input.bytes[42]) + (input.bytes[43]);
 data6.VL53L5CX_Range_CH49 = (input.bytes[44]) + (input.bytes[45]);
 data6.VL53L5CX_Range_CH50 = (input.bytes[46]) + (input.bytes[47]);
 data6.VL53L5CX_Range_CH51 = (input.bytes[48]) + (input.bytes[49]);
 data6.VL53L5CX_Range_CH52 = (input.bytes[50]) + (input.bytes[51]);

       //6 Hour Part 3
 data7.event = events[input.fPort];
 data7.VL53L5CX_Range_CH53 = (input.bytes[0]) + (input.bytes[1]);
 data7.VL53L5CX_Range_CH54 = (input.bytes[2]) + (input.bytes[3]);
 data7.VL53L5CX_Range_CH55 = (input.bytes[4]) + (input.bytes[5]);
 data7.VL53L5CX_Range_CH56 = (input.bytes[6]) + (input.bytes[7]);
 data7.VL53L5CX_Range_CH57 = (input.bytes[8]) + (input.bytes[9]);
 data7.VL53L5CX_Range_CH58 = (input.bytes[10]) + (input.bytes[11]);
 data7.VL53L5CX_Range_CH59 = (input.bytes[12]) + (input.bytes[13]);
 data7.VL53L5CX_Range_CH60 = (input.bytes[14]) + (input.bytes[15]);
 data7.VL53L5CX_Range_CH61 = (input.bytes[16]) + (input.bytes[17]);
 data7.VL53L5CX_Range_CH62 = (input.bytes[18]) + (input.bytes[19]);
 data7.VL53L5CX_Range_CH63= (input.bytes[20]) + (input.bytes[21]);
 data7.VL53L5CX_Range_CH64 = (input.bytes[22]) + (input.bytes[23]);
 data7.VL53L5CX_SigStrength_CH1 = (input.bytes[24]);
 data7.VL53L5CX_SigStrength_CH2 = (input.bytes[25]);
 data7.VL53L5CX_SigStrength_CH3 = (input.bytes[26]);
 data7.VL53L5CX_SigStrength_CH4 = (input.bytes[27]);
 data7.VL53L5CX_SigStrength_CH5 = (input.bytes[28]);
 data7.VL53L5CX_SigStrength_CH6 = (input.bytes[29]);
 data7.VL53L5CX_SigStrength_CH7 = (input.bytes[30]);
 data7.VL53L5CX_SigStrength_CH8 = (input.bytes[31]);
 data7.VL53L5CX_SigStrength_CH9 = (input.bytes[32]);
 data7.VL53L5CX_SigStrength_CH10 = (input.bytes[33]);
 data7.VL53L5CX_SigStrength_CH11 = (input.bytes[34]);
 data7.VL53L5CX_SigStrength_CH12 = (input.bytes[35]);
 data7.VL53L5CX_SigStrength_CH13 = (input.bytes[36]);
 data7.VL53L5CX_SigStrength_CH14 = (input.bytes[37]);
 data7.VL53L5CX_SigStrength_CH15 = (input.bytes[38]);  
 data7.VL53L5CX_SigStrength_CH16 = (input.bytes[39]);
 data7.VL53L5CX_SigStrength_CH17 = (input.bytes[40]);
 data7.VL53L5CX_SigStrength_CH18 = (input.bytes[41]);
 data7.VL53L5CX_SigStrength_CH19 = (input.bytes[42]);
 data7.VL53L5CX_SigStrength_CH20 = (input.bytes[43]);
 data7.VL53L5CX_SigStrength_CH21 = (input.bytes[44]);
 data7.VL53L5CX_SigStrength_CH22 = (input.bytes[45]);
 data7.VL53L5CX_SigStrength_CH23 = (input.bytes[46]);
 data7.VL53L5CX_SigStrength_CH24 = (input.bytes[47]);
 data7.VL53L5CX_SigStrength_CH25 = (input.bytes[48]);
 data7.VL53L5CX_SigStrength_CH26 = (input.bytes[49]);
 data7.VL53L5CX_SigStrength_CH27 = (input.bytes[50]);
 data7.VL53L5CX_SigStrength_CH28 = (input.bytes[51]);


       //6 Hour Part 4  
 data8.VL53L5CX_SigStrength_CH29 = (input.bytes[0]);
 data8.VL53L5CX_SigStrength_CH30 = (input.bytes[1]);
 data8.VL53L5CX_SigStrength_CH31 = (input.bytes[2]);
 data8.VL53L5CX_SigStrength_CH32 = (input.bytes[3]);
 data8.VL53L5CX_SigStrength_CH33 = (input.bytes[4]);
 data8.VL53L5CX_SigStrength_CH34 = (input.bytes[5]);  
 data8.VL53L5CX_SigStrength_CH35 = (input.bytes[6]);  
 data8.VL53L5CX_SigStrength_CH36 = (input.bytes[7]);
 data8.VL53L5CX_SigStrength_CH37 = (input.bytes[8]);
 data8.VL53L5CX_SigStrength_CH38 = (input.bytes[9]);
 data8.VL53L5CX_SigStrength_CH39 = (input.bytes[10]);
 data8.VL53L5CX_SigStrength_CH40 = (input.bytes[11]);
 data8.VL53L5CX_SigStrength_CH41 = (input.bytes[12]);
 data8.VL53L5CX_SigStrength_CH42 = (input.bytes[13]);
 data8.VL53L5CX_SigStrength_CH43 = (input.bytes[14]);
 data8.VL53L5CX_SigStrength_CH44 = (input.bytes[15]);  
 data8.VL53L5CX_SigStrength_CH45 = (input.bytes[16]);
 data8.VL53L5CX_SigStrength_CH46 = (input.bytes[17]);
 data8.VL53L5CX_SigStrength_CH47 = (input.bytes[18]);
 data8.VL53L5CX_SigStrength_CH48 = (input.bytes[19]);
 data8.VL53L5CX_SigStrength_CH49 = (input.bytes[20]);
 data8.VL53L5CX_SigStrength_CH50 = (input.bytes[21]);
 data8.VL53L5CX_SigStrength_CH51 = (input.bytes[22]);
 data8.VL53L5CX_SigStrength_CH52 = (input.bytes[23]);
 data8.VL53L5CX_SigStrength_CH53 = (input.bytes[24]);
 data8.VL53L5CX_SigStrength_CH54 = (input.bytes[25]);
 data8.VL53L5CX_SigStrength_CH55 = (input.bytes[26]);
 data8.VL53L5CX_SigStrength_CH56 = (input.bytes[27]);
 data8.VL53L5CX_SigStrength_CH57 = (input.bytes[28]);
 data8.VL53L5CX_SigStrength_CH58 = (input.bytes[29]);
 data8.VL53L5CX_SigStrength_CH59 = (input.bytes[30]);
 data8.VL53L5CX_SigStrength_CH60 = (input.bytes[31]);
 data8.VL53L5CX_SigStrength_CH61 = (input.bytes[32]);
 data8.VL53L5CX_SigStrength_CH62 = (input.bytes[33]);
 data8.VL53L5CX_SigStrength_CH63 = (input.bytes[34]);
 data8.VL53L5CX_SigStrength_CH64 = (input.bytes[35]);
 data8.VL53L5CX_AmbientLight_CH1 = (input.bytes[36]);
 data8.VL53L5CX_AmbientLight_CH2 = (input.bytes[37]);  
 data8.VL53L5CX_AmbientLight_CH3 = (input.bytes[38]);
 data8.VL53L5CX_AmbientLight_CH4 = (input.bytes[39]);
 data.depth = data8.VL53L5CX_AmbientLight_CH4;




 var warnings = [x];
 if (data1.temperature < -10) {
   warnings.push("it's cold");
 }

if(fportcaller == 1) {
 return {
    data:data1
 }
}else if(fportcaller == 2) {
 return{
   data:data2
 }
}else if(fportcaller == 3) {
 return{
   data:data3
 }
}else if(fportcaller == 4) {
 return{
   data:data4
 }
}else if(fportcaller == 5) {
 return{
   data:data5
 }
}else if(fportcaller == 6) {
 return{
   data:data6
 }
}else if(fportcaller == 7) {
 return{
   data:data7
 }
}else if(fportcaller == 8) {
 return{
   data:data8
 }

}

}

Ouch - just one data array will do

Not sure what JS will do with the around the variable.

You may be accumulating all sorts of hidden exceptions if there isn’t enough data. So rather than trying to process a payload as if it is all of them, move the port selection so it calculates the data return only for port/type.

And just return the one array. If you look at the docs / a template one it will show you how to return the warning as well. And ditch the Float conversion before the LoRaWAN payload police come along to discuss such things with you - your best defence is that you aren’t actually using it.

Too late, here he comes :rotating_light: :police_car: :policeman: :policewoman: :oncoming_police_car: :man_police_officer: :rotating_light:

Which languages do you normally program in?

This probably worked with v2 but even then is somewhat muddled so can’t have been fun to do it back then. Now you have to take in to account the newer data structures that are sent.

Thank you for your help Nick.
I will change to working with one array. I was doing an array for each different payload type, but i now understand that I dont need to do that.
I took the brackets off of that variable. Not sure why i put those on.
I also removed the byte to float conversion at the start. I have been very diligent with setting everything up to respect the the fair use agreement for TTN. That is why everything is separated into different events.
I am very new to programming. Because of that, most of my process with this has been relying largely on example code and documentation.
Understood on the datacake documentation being largely for V2. My frustration is that I can see all of my decoded payloads in the debug section of datacake, but I just dont know how to access them. I understand that that might just be a question for the folks at datacake though. I have reached out.

No one said anything about FUP - it’s just about efficiency & ease of decoding.

Yeah, that’s what everyone says, because that’s pretty much where everyone starts from, just like I did, any rumours about me eating a Z80 chip when I was 12 are false. It was a 6502. Which languages do you normally program in? The only reason I ask is that it will enable me to put answers in context.

If you tidy up the TTN payload formatter first, then we should be able to figure out the Datacake instructions.

people

anybody can help me how i can convert this uplink from TTN to datacase temperature field, the temperature is decoded alreday (see below) i need convert it to a field Temperature on dataCase.

“frm_payload”: string"B4s="

“decoded_payload”:{ 1 item

“payload”: float19.31

}

thanks for help
CDV