LT-33222-L LoRa I/O Controller - Payload decoder and downlink config


(Zone11) #1

While working with the LT-33222 I found a wrong configuration in the preconfigured device to receive downlink data. Ensure you set the RX2 data rate to SF9/125 with the AT command “AT+RX2DR=3”.

And here is my payload decoder, DIx are inverted to represent the logical state, not the physical one.
Input is 1 when tied to GND (Device LED on).

function Decoder(bytes, port) {
  var decoded = {};
  var inputs = bytes[8];
  
  decoded.ACI1 = ((bytes[0] << 8) + bytes[1])/100;
  decoded.ACI2 = ((bytes[2] << 8) + bytes[3])/100;
  decoded.AVI1 = ((bytes[4] << 8) + bytes[5])/100;
  decoded.AVI2 = ((bytes[6] << 8) + bytes[7])/100;
  decoded.DO1 = inputs & (1 << 0) ? 1 : 0;
  decoded.DO2 = inputs & (1 << 1) ? 1 : 0;  
  decoded.DO3 = inputs & (1 << 2) ? 1 : 0;
  decoded.DI1 = inputs & (1 << 3) ? 0 : 1;
  decoded.DI2 = inputs & (1 << 4) ? 0 : 1;
  decoded.DI3 = inputs & (1 << 5) ? 0 : 1;
  decoded.RO1 = inputs & (1 << 6) ? 1 : 0;
  decoded.RO2 = inputs & (1 << 7) ? 1 : 0;
  
  return decoded;
}

Feel free to use and improve :wink:

  • Christian

The BARGAIN basement part 5
Is there any documentation on payload functions?
(Arjan) #2

Am I right to assume you’re using ABP?

For ABP one indeed needs to manually configure the network settings, which for TTN implies configuring RX2, at least for EU868. For OTAA, the configuration should be automatic. (So, if you’re using OTAA, you might want to report a bug with Dragino.)


(Zone11) #3

No, I’m using OTAA

Unfortunately the RX2 is not configured correctly in my case.
The controller reports RX2 configured as DR_0 (SF12/125) but my all my gateways are sending downlink with DR_3 (SF9/125).

I’m going to file a bug report.


(Pat Molloy) #4

I’m also using OTAA, all the uplinks are fine, but you have to configure (at present) the downlink manually via a serial connection to the device … AT+RX2DR=3 … once this is done, works just great !


(Profiler64) #5

Hey I have a question about the LT-33222. I want to buy one of these controllers and a 8 Ch Gateway. I. want to control one of the onboard relays. My Question is:
How often can i switch the relay on this Controller, because the downlink limitation from TTN. Can i switch every time the Controller sends data to the network and right after that it can receive the data? Or how does it works? I’m completly New to this topic but i think the Controller is the right thing for me.
Maybe you can help me :slight_smile:


#6

  • for basic controlling lights and things in your house, better use one of these modules and not LoRaWAN / TTN

(Profiler64) #7

Yeah i know. But i dont want to control lights. I want to control like 10 solenoidvalves for a irrigation System on fields. My Main question is how often i can downlink to the Controller.


#8

see


(Custom Io T) #9

Encoder:

function Encoder(object, port) {
  
  var bytes = [];
  
  if (object.Control == "DO")
  {
    //test with: {"Control": "DO", "DO1":1 , "DO2":1, "DO3":1} => 02 01 01 01 (where 1 = on, 0 = off)
    
    bytes[0] = 0x02;
    if (object.DO1 ==1)
    {
      bytes[1] = 1;
    }
    else
    {
      bytes[1] = 0;
    }

    if (object.DO2 ==1)
    {
      bytes[2] = 1;
    }
    else
    {
      bytes[2] = 0;
    }

    if (object.DO3 ==1)
    {
      bytes[3] = 1;
    }
    else
    {
      bytes[3] = 0;
    }
  }

  if (object.Control == "RELAY")
  {
    //test with: {"Control": "RELAY", "RO1":1 , "RO2":1} => 03 01 01 (where 1 = close, 0 = open)
    //test with: {"Control": "RELAY", "RO1":0 , "RO2":1} => 03 00 01 (where 1 = close, 0 = open)
    //test with: {"Control": "RELAY", "RO1":1 , "RO2":0} => 03 01 00 (where 1 = close, 0 = open)
    bytes[0] = 0x03;
    if (object.RO1 ==1)
    {
      bytes[1] = 1;
    }
    else
    {
      bytes[1] = 0;
    }
    
    if (object.RO2 ==1)
    {
      bytes[2] = 1;
    }
    else
    {
      bytes[2] = 0;
    }
  }

  if (object.Control == "RESET")
  {
    //test with: {"Control": "RESET"} => 04 FF
    bytes[0] = 0x04;
    bytes[1] = 0xFF;
  }

  if (object.Control == "PERIOD")
  {
    //test with: {"Control": "PERIOD", "Seconds":60} => 01 00 3C
    bytes[0] = 0x01;
    
    // in seconds byte[2]..byte[3]  
    
    bytes[1] = object.Seconds >> 8;
    bytes[2] = object.Seconds;
    
  }

  return bytes;
}

(Arjan) #10

Nice, thanks for sharing! But beware, the following won’t work for values larger than 255 seconds:

bytes[1] = object.Seconds >> 8;
bytes[2] = object.Seconds;

Unlike in, e.g., C++ where a byte can really only hold 8 bits and all other bits are simply discarded, JavaScript does not have such specific types. (Instead, everything is a floating point.) Above, bytes[2] will hold the full value, not just limited to its 8 least significant bits. You can try with {"Control": "PERIOD", "Seconds": 300}, which will not throw an error in the JavaScript, but TTN will still reject with Error("Encoder Output not valid: Numbers in Array should be between 0 and 255").

Also, it seems you need 3 bytes for the time?

downlink payload

So, I’d use:

// test with: {"Control": "PERIOD", "Seconds": 86400} => 01 01 51 80 (24 hours)
bytes[1] = object.Seconds >> 16;
bytes[2] = object.Seconds >> 8 & 0xFF;
bytes[3] = object.Seconds & 0xFF;

For bytes[1] you don’t need the & 0xFF to limit to 8 bits (as all bits in the leftmost bytes are zeroes), but it won’t harm either.

And just some notes in case you didn’t know:

You’re defaulting to zero. Probably by design, but just so you’re aware: {"Control": "DO", "DO1": 2, "DO2": "foo"} (where DO3 is missing and the others have invalid values) will silently set all outputs to zero. If you don’t expect errors in the input, then you could simply use:

bytes[1] = object.DO1;
bytes[2] = object.DO2;
bytes[3] = object.DO3;

You can define helper functions too, either above Encoder or within that function. Like:

// Decodes the value to either 1 or 0
function onoff(val) {
  // Non-strict equals: return 1 for the number 1 or the string "1"
  if (val == 1) {
    return 1;
  }
  // Default all missing or invalid values to 0
  return 0;
}

function Encoder(object, port) {
  var bytes = [];
  if (object.Control === "DO") {
    //test with: {"Control": "DO", "DO1":1 , "DO2":1, "DO3":1} => 02 01 01 01 (where 1 = on, 0 = off)
    bytes[0] = 0x02;
    bytes[1] = onoff(object.DO1);
    bytes[2] = onoff(object.DO2);
    bytes[3] = onoff(object.DO3);
  }
  ...
}

If you want to fail on invalid inputs then we’d need to investigate on how TTN acts on returning a null value or on throwing an error. (TTN Console might work differently from the APIs there; not sure if there’s any documentation about that.)


(Custom Io T) #11

Thanks Arjan
I was a little lazy with period - thanks for correction.
I am still trying to get the unit to uplink a payload. I have only been able to test the encoder. Just preparing an email to Dragino support. (yet other lansetic units work as soon as you turn then on.


(Bryansmith) #12

The four voltage and current variables should be divided by 1000 and not 100 :stuck_out_tongue_closed_eyes:

Instead of this:

This:

decoded.ACI1 = ((bytes[0] << 8) + bytes[1])/1000;
decoded.ACI2 = ((bytes[2] << 8) + bytes[3])/1000;
decoded.AVI1 = ((bytes[4] << 8) + bytes[5])/1000;
decoded.AVI2 = ((bytes[6] << 8) + bytes[7])/1000;


(Zone11) #13

Sorry @bryansmith but can’t confirm this.
The device documentation (LoRa_IO_Controller_UserManual_v1.0.2) defines on page 9:

For example if payload is: 0131013004AB04ACAA

The value for the interface is:
ACI2 channel current is 0x0130/100=3.04mA
AVI1 channel voltage is 0x04AB/100=11.95V
AVI2 channel voltage is 0x04AC/100=11.96V

My devices monitor their supply voltage (about 12v) and the readings are fine with /100:

{
“ACI1”: 0,
“ACI2”: 0,
“AVI1”: 11.97,
“AVI2”: 0,
“DI1”: 1,
“DI2”: 0,
“DI3”: 0,
“DO1”: 0,
“DO2”: 0,
“DO3”: 0,
“RO1”: 0,
“RO2”: 0
}


(Bryansmith) #14

I see your reference to user manual version 1.0.2 yet under versions 1.1.0 and 1.1.1 the decoder provides inaccurate data.

Page 9 of version 1.0.2 payload format:
0131013004AB04ACAA

Page 11 of version 1.1.1 payload format:
1310 1300 04AB 04ACAA

Your decoder works fine on version 1.0.2 and 1.0.4 but anything above that Dragino changed the format by removing the leading 0 :see_no_evil:


(Zone11) #15

:roll_eyes: this is going to be funny in an environment with different firmware versions… thank you for pointing it out!