Dragino LGT-92 - LoRaWAN GPS Tracker

You are dam right.
But Dragino has some tutorials in YouTube that helped me a lot to get my tracker working with their 1ch gateway…maybe I should write Edwin an e-mail.

you are right too … its still not ‘plug and play’ :wink:

I can see some stuff from Dragino on how to get the tracker information into the TTN network, but could not see an explanation of how to forward the data to information services such as Cayenne ?

Yes, this would be my question to Edwin. :wink:

Hm, still waiting for a feedback from Edwin…

Chinese holidays maybe ?

Meanwhile Edwin told me that it is possible with mydevices and they will make a tutorial next week.
I tried it myself and the lgt92 is indeed possible to select now in Cayenne but decoding the payload is not working.
I integrate mydevice and select Cayenne lpp but the payload is not decoded. There appears nothing behind the payload.
Could it be that the deactivated motion sensor might be the problem?
I have an account at mydevice of course.
Anyone an idea?

Meanwhile it worked fine so far.
The problem was that I deactivated the motion sensor to make the payload and airtime smaller.
After activate it again, it works fine.
But the mobile app currently does not show the location correctly as this is not fully implemented yet, but it works with the browser version…
The Cayenne Support works excellent.

Hello everyone!
I wanted to inform you that I received a preview of this information: the new firmware for Dragino LGT-92 has been released: v1.5

Read here!! LGT-92 low GPS accuracy

1 Like

Ciao!

I upgraded my nodes to V1.5.
I updated the TTN decoder payload from the manual v1.5 but something is wrong.

If I try to decode a payload, example: 02A2AF3000B1021D0E0B60

TTN returns the following error: Error(“Internal error: Decoder threw error:Line 39:17 Unexpected identifier”)

Annotazione%202019-11-27%20175536

Decoder:

//The function is :
function Decoder(bytes, port) {
// Decode an uplink message from a buffer
// (array) of bytes to an object of fields.
var value=bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3];
if(bytes[0] & 0x80)
{
value |=0xFFFFFFFF00000000;
}
var latitude=value/1000000;//gps latitude,units: °
value=bytes[4]<<24 | bytes[5]<<16 | bytes[6]<<8 | bytes[7];
if(bytes[4] & 0x80)
{
value |=0xFFFFFFFF00000000;
}
var longitude=value/1000000;//gps longitude,units: °
var alarm=(bytes[8] & 0x40)?"TRUE":"FALSE";//Alarm status
value=((bytes[8] & 0x3f) <<8) | bytes[9];
var batV=value/1000;//Battery,units:V
value=(bytes[10] & 0xC0);
if(value==0x40)
{
var motion_mode="Move";
}
else if(value==0x80)
{
motion_mode="Collide";
}
else if(value==0xC0)
{
motion_mode="User";
}
else
{
motion_mode="Disable";
} //mode of motion
var led_updown=(bytes[10] & 0x20)?"ON":"OFF";//LED status for
position,uplink and downlink
value=bytes[11]<<8 | bytes[12];
if(bytes[11] & 0x80)
{
value |=0xFFFF0000;
}
var roll=value/100;//roll,units: °
value=bytes[13]<<8 | bytes[14];
if(bytes[13] & 0x80)
{
value |=0xFFFF0000;
}
var pitch=value/100; //pitch,units: °
return {
    Latitude: latitude,
Longitud: longitude,
Roll: roll,
Pitch:pitch,
BatV:batV,
ALARM_status:alarm,
MD:motion_mode,
LON:led_updown,
};
}

It seems you hit Enter in the comment in this line:

var led_updown=(bytes[10] & 0x20)?"ON":"OFF";//LED status for
position,uplink and downlink

This should be a single line.

And an aside: if you get wrong coordinates, then look at the following, which I don’t understand. But maybe there’s some weird encoding in the node that needs this:

var value=bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3];
if(bytes[0] & 0x80)
{
value |=0xFFFFFFFF00000000;
}

thanks, meanwhile I made the first correction, but the error remains:

Internal error: Decoder threw error: ReferenceError(“‘zzx’ is not defined”)

If I copy your Decoder into TTN console, then I do not get such error. Also, I don’t see any zzx in the code you posted, so I would simply copy it again.

Another aside, I just noticed that your first error was shown in TTN Console as follows:

ahahahahha !!! I found where it was zzx !!! right in the first line !!! I’m a chicken, sorry !!

here a payload decoded:

02A2AE6800B101740E3260

{
“ALARM_status”: “FALSE”,
“BatV”: 3.634,
“LON”: “ON”,
“Latitude”: censored,
“Longitud”: censored,
“MD”: “Move”,
“Pitch”: 0,
“Roll”: 0
}

Actually, as JavaScript bitwise operators always work with 32 bits, the code in value |=0xFFFFFFFF00000000 (which is 64 bits) is exactly the same as value |=0x00000000, and does nothing at all. Still confusing! I’m quite sure one can remove it, for the two coordinates.

Background:

While I don’t know how the node encodes its data, the above smells like “sign extension”, which indeed is needed when handling signed integers represented with fewer than 4 bytes. But as the coordinates are already 4 bytes, such thing is not needed.

The following code, found further down in the Decoder, does the same. But then it’s handling 2 bytes, while JavaScript indeed needs 4 bytes. And here the mask 0xFFFF0000 is indeed 32 bits, so the following has the desired effect:

value=bytes[13]<<8 | bytes[14];
if(bytes[13] & 0x80)
{
value |=0xFFFF0000;
}

FYI, this is to handle the negative case.

I found an error in the new firmware / payload decoder:
look at the payload translation:

{
“ALARM_status”: “FALSE”,
“BatV”: 3.634,
“LON”: “ON”,
“Latitude”: censored,
“Longitud”: censored,
“MD”: “Move”,
“Pitch”: 0,
“Roll”: 0
}

“Longitud” ???

the correct payload decoder for V1.5 is:

//The function is :
function Decoder(bytes, port) {
// Decode an uplink message from a buffer
// (array) of bytes to an object of fields.
var value=bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3];
if(bytes[0] & 0x80)
{
value |=0xFFFFFFFF00000000;
}
var latitude=value/1000000;//gps latitude,units: °
value=bytes[4]<<24 | bytes[5]<<16 | bytes[6]<<8 | bytes[7];
if(bytes[4] & 0x80)
{
value |=0xFFFFFFFF00000000;
}
var longitude=value/1000000;//gps longitude,units: °
var alarm=(bytes[8] & 0x40)?"TRUE":"FALSE";//Alarm status
value=((bytes[8] & 0x3f) <<8) | bytes[9];
var batV=value/1000;//Battery,units:V
value=(bytes[10] & 0xC0);
if(value==0x40)
{
var motion_mode="Move";
}
else if(value==0x80)
{
motion_mode="Collide";
}
else if(value==0xC0)
{
motion_mode="User";
}
else
{
motion_mode="Disable";
} //mode of motion
var led_updown=(bytes[10] & 0x20)?"ON":"OFF";//LED status for position,uplink and downlink
value=bytes[11]<<8 | bytes[12];
if(bytes[11] & 0x80)
{
value |=0xFFFF0000;
}
var roll=value/100;//roll,units: °
value=bytes[13]<<8 | bytes[14];
if(bytes[13] & 0x80)
{
value |=0xFFFF0000;
}
var pitch=value/100; //pitch,units: °
return {
Latitude: latitude,
Longitude: longitude,
Roll: roll,
Pitch:pitch,
BatV:batV,
ALARM_status:alarm,
MD:motion_mode,
LON:led_updown,
};
}

Like I explained it indeed looks like that, but (luckily!) it doesn’t do anything. As you quoted from my explanation: JavaScript works with 32 bits for bitwise operators, so it will handle 0xFFFFFFFF00000000 as if it were 0x00000000 here.

Just try 0xFFFFFFFF00000000 | 0xFFFFFFFF00000000 to see that evaluates to zero.

Even more, if it would have an effect, then it would erroneously set bits that did not need to be set, as the value was already 32 bits, so would already be negative if applicable.

The following gives the same output for your example payload of 02863D68 FAC29BAF 4B45 60 04D2 FB2E in the 1.5.x user manual:

/**
 * Decoder for Dragino LGT-92.
 *
 * Based on the JSON format of the example decoder from the 1.5 user
 * manual, but with typo fixed in "Longitud", "FW" added for firmware,
 * and returning a true JSON boolean for the Alarm flag.
 *
 * 2020-01-19 Copied fix for FW from LGT92-v1.5.0_decoder_20191129.txt
 */
function Decoder(bytes, port) {
  return {
    // GPS coordinates; signed 32 bits integer, MSB; unit: °
    // When power is low (<2.84v), GPS won’t be able to get location
    // info and GPS feature will be disabled and the location field
    // will be filled with 0x0FFFFFFF, 0x0FFFFFFF. 
    Latitude: 
      (bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3]) / 1000000,
    Longitude:
      (bytes[4]<<24 | bytes[5]<<16 | bytes[6]<<8 | bytes[7]) / 1000000,

    // Alarm status; boolean
    ALARM_status: (bytes[8] & 0x40) > 0,

    // Battery; 14 bits; unit: V
    BatV: ((bytes[8] & 0x3f)<<8 | bytes[9]) / 1000,

    // Motion detection mode; 2 bits
    MD: {
      "0": "Disable",
      "1": "Move",
      "2": "Collide",
      "3": "User"
    }[bytes[10]>>6],

    // LED status for position, uplink and downlink; 1 bit
    LON: (bytes[10] & 0x20) ? "ON" : "OFF",

    // Firmware version; 5 bits
    FW: 150 + (bytes[10] & 0x1f),

    // In firmware version v1.5, Roll and Pitch are disabled by default.

    // Roll; signed 16 bits integer, MSB; unit: °
    // Sign-extend to 32 bits to support negative values: shift 16 bytes
    // too far to the left, followed by sign-propagating right shift
    Roll: (bytes[11]<<24>>16 | bytes[12]) / 100,

    // Pitch; signed 16 bits integer, MSB, unit: °
    Pitch: (bytes[13]<<24>>16 | bytes[14]) / 100,
  };
}
{
  "ALARM_status": true,
  "BatV": 2.885,
  "FW": 150,
  "LON": "ON",
  "Latitude": 42.351976,
  "Longitude": -87.909457,
  "MD": "Move",
  "Pitch": -12.34,
  "Roll": 12.34
}