Things Network Cayenne LLP


#1

Having issue for The Things Network Cayenne LLP. I tried with each steps from add Cayenne integration in TTN to add Lora devices in MyDevices Cayenne. But there’s not any data showing in Cayenne dashboard. Help me in this.


#2

@eptak tagging here


#3

@network Please PM me the deveui of that device. Thanks!


#4

@eptak here it is. 0006110080829003


#5

Hello, is there anyone for Help?


#6

we will look into it and let you know after some time.


#7

Hi,

I’ve looked into the payload we received for your device and there is definitely something wrong with them.
How are you building the payload and what are you trying to send ?

Please make sure your payload match LPP format
https://mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload-uplink-payload-structure

You can check in TTN console the payload received, but you may need a small function to translate from base64 to hex for convenience.

For example with Node.JS and two payload sent by your device:

> Buffer.from('IL8qM5qbAo5QAwdi', 'base64').toString("hex")
'20bf2a339a9b028e50030762'
> Buffer.from('AwVj', 'base64').toString("hex")
'030563'

As you can see that doesn’t match anything to our spec.


#8

Hi,

I’m trying to send GPS data. and here blow is code that i tried in payload Decoder, please check if any suggestion in that let me know.

Thanks and regards.

function Decoder(b,port)
{
var decode = {};
var decode204 = {};
var decode205 = {};
var decode207 = {};

if(port == 204)
{
    decode204.payload    = b;
    decode204.porta      = port;
    decode.lat           = b[0]<<16 | b[1]<<8 | b[2];
    decode.lng           = b[3]<<16 | b[4]<<8 | b[5];
    decode204.altitude   = b[6]<<8  | b[7];
    decode204.hdop       = b[8];
    decode204.temperature=(b[9]&0x0F)*100;
    decode204.temperature+=(b[10]>>4)*10;
    decode204.temperature+=(b[10]&0x0F);
    if (b[9]&0xF0) 
        decode204.temperature/=-10;
    else
        decode204.temperature/=10;

    decode204.battery =(b[11]>>4)*10;
    decode204.battery+=(b[11]&0x0F);

    decode204.latitude      = (decode.lat / 8388606) * 90;
    decode204.longitude     = (decode.lng / 8388606) * 180;

    return {
        payload:     decode204.payload,
        port:        decode204.porta,
        longitude:   decode204.longitude,
        latitude:    decode204.latitude,
        altitude:    decode204.altitude,
        temperature: decode204.temperature,
        hdop:        decode204.hdop,
    }
}
else if(port===205)
{
    decode205.payload     = b;
    decode205.porta       = port;
    decode205.temperature =(b[0]&0x0F)*100;
    decode205.temperature+=(b[1]>>4)*10;
    decode205.temperature+=(b[1]&0x0F);
    if (b[0]&0xF0) 
        decode205.temperature/=-10;
    else
        decode205.temperature/=10;

    decode205.battery=(b[2]>>4)*10;
    decode205.battery+=(b[2]&0x0F);

    return {
        payload:     decode205.payload,
        port:        decode205.porta,
        longitude:   "",
        latitude:    "",
        altitude:    "",
        temperature: decode205.temperature,
        hdop:        "",
    }
}
else if(port===207)
{
    decode207.payload     = b;
    decode207.porta       = port;
    decode207.temperature =(b[0]&0x0F)*100;
    decode207.temperature+=(b[1]>>4)*10;
    decode207.temperature+=(b[1]&0x0F);
    if (b[0]&0xF0) 
        decode207.temperature/=-10;
    else
        decode207.temperature/=10;

    decode207.battery=(b[2]>>4)*10;
    decode207.battery+=(b[2]&0x0F);
    
    return {
        payload:     decode207.payload,
        port:        decode207.porta,
        longitude:   "",
        latitude:    "",
        altitude:    "",
        temperature: decode207.temperature,
        hdop:        "",
    }
}
else 
{
    decode.porta   = port;
    decode.payload = b;
    
    return {
        payload:     decode.payload,
        port:        decode.porta,
        longitude:   "",
        latitude:    "",
        altitude:    "",
        temperature: "",
        hdop:        "",
    }
}

}


#9

Here is the code I used when I was testing a LoRA device. I can’t remember where it came from, but formatData and padGPS are the functions I made to format data for Cayenne and are probably the only ones of interest to you.

#include <SoftwareSerial.h>
#include <Wire.h> // for IIC communication
#include "TimerOne.h"
#include <Adafruit_GPS.h>

//GPS info
Adafruit_GPS GPS(&Serial1);
// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
// Set to 'true' if you want to debug and listen to the raw GPS sentences. 
#define GPSECHO false
// this keeps track of whether we're using the interrupt
// off by default!
boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy

//************** Device parameters for registration *****************
////////////////////////////////////////////////////////////
char DEVICE_EUI[] = "xxx";
char DEVICE_ADDR[] = "xxx";  //4 bytes required
char APP_KEY[] = "xxx"; //16 bytes required
char NWK_SESSION_KEY[] = "xxx"; //network session key
char APP_SESSION_KEY[] = "xxx"; //network session key
////////////////////////////////////////////////////////////

//************** ACCELEROMETER THRESHOLDS*******************************
#define xThreshold 0.5
#define yThreshold 0.5
#define zThreshold 0.5

//**************** TEMPERATURE SAMPLE TIME *******************************
#define TEMP_SAMPLE_TIME 100   //sample time for temperature


//******************** Channel Status *******************
//set bit channel on = 1, channel off = 0
//bank 0 = channels 0-7, bank 1 = channels 8-15, bank 2 = channels 16-23, bank 3 = channels 24-31, bank 4 = channels 32-39,
//bank 5 = channels 40-47, bank 6 = channels 48-55, bank 7 = channels 56-63, bank 8 = channels 64-71,
//MSB = highest channel number in bank. Example Bank 2 = b11000000. Channels 23 and  22 are on

byte channelBank[] = {B11111111, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B11111111}; 


#define accAddress 0x1D    //right justified accelerometer address
#define tmpAddress 0x48     //right justified TMP112 address
#define I2C_WRITE Wire.write 
#define I2C_READ Wire.read

/******************** ACCELEROMETER Data ************/
// adresss of accelerometer
#define adress_acc    0X1D // MMA8653FC and MMA8652FC

// adress of registers for MMA8653FC
#define ctrl_reg1     0x2A
#define ctrl_reg2     0x2B
#define ctrl_reg3     0x2C
#define ctrl_reg4     0x2D
#define ctrl_reg5     0x2E
#define int_source    0x0C
#define status_       0x00
#define f_setup       0x09
#define out_x_msb     0x01
#define out_y_msb     0x03
#define out_z_msb     0x05
#define sysmod        0x0B
#define xyz_data_cfg  0x0E
#define ff_mt_cfg     0x15
#define ff_mt_src     0x16
#define ff_mt_ths     0x17
#define ff_mt_count   0x18

//************** set resolution of accelerometer *************************
//#define resolution   0.0038;        //resolution for 2g
//#define resolution   0.0078;        //resolution for 4g
#define resolution     0.0156;        //resolution for 8g

//************** set range of accelerometer *************************
//#define range         0x00  //2G full scale
//#define range         0x01  //4G full scale
#define range         0x02  //8G full scale

//************** configure accelerometer *************************
//#define accConfig      0x00    // Output data rate at 800Hz, no auto wake, no auto scale adjust, no fast read mode
//#define accConfig      0x21    // Output data rate at 200Hz, no auto wake, no auto scale adjust, no fast read mode
#define accConfig      0x41    // Output data rate at 50Hz, no auto wake, no auto scale adjust, no fast read mode
//#define accConfig      0x71    // Output data rate at 1.5Hz, no auto wake, no auto scale adjust, no fast read mode



//****************** sensor variables **************************
float axeXnow ;
float axeYnow ;
float axeZnow ;
float axeXprev;
float axeYprev;
float axeZprev;
float tempC;

int printTemp;
int printXaxis;
int printYaxis;
int printZaxis;
long printLat;
long printLong;
long printAlt;
char charVal[4][5];
char charGPS[2][7];
long tempCounter;

//*******************************************************************************************************
SoftwareSerial loraSerial(10, 11); // RX, TX   ** Set to 10, 11 for Mega2560 boards

void setup() {

delay(1000);                //startup delay - gives Lora module time to reset if cold start
Serial.begin(115200);        //terminal serial port
loraSerial.begin(57600);      
Wire.begin();                              // join i2c bus
ACC_INIT();                                //initialize accelerometer

getConfig();                           //get module information
setChannelStatus();                        //configure channels to be on or off

configureABP();                          //configure Access By Personalization (ABP)
//configureOTAA();                         //configure Over The Air Activation (OTAA)

Timer1.initialize(500000);         // initialize timer1, and set to 0.5 second period
Timer1.attachInterrupt(systemTimer);    //set ISR

I2C_READ_ACC(0x01);   //get initial readings
axeXprev = axeXnow;
axeYprev = axeYnow;
axeZprev = axeZnow;

tempCounter = 0;

  //GPS Setup
  // 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
  GPS.begin(9600);
  // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  // Set the update rate
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 1 Hz update rate
  // Request updates on antenna status, comment out to keep quiet
  GPS.sendCommand(PGCMD_ANTENNA);
  // the nice thing about this code is you can have a timer0 interrupt go off
  // every 1 millisecond, and read data from the GPS for you. that makes the
  // loop code a heck of a lot easier!
  useInterrupt(true);
  delay(1000);
}

//GPS Functions
// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
  char c = GPS.read();
  // if you want to debug, this is a good time to do it!
#ifdef UDR0
  if (GPSECHO)
    if (c) UDR0 = c;  
    // writing direct to UDR0 is much much faster than Serial.print 
    // but only one character can be written at a time. 
#endif
}

void useInterrupt(boolean v) {
  if (v) {
    // Timer0 is already used for millis() - we'll just interrupt somewhere
    // in the middle and call the "Compare A" function above
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
    usingInterrupt = true;
  } else {
    // do not call the interrupt function COMPA anymore
    TIMSK0 &= ~_BV(OCIE0A);
    usingInterrupt = false;
  }
}

String padGPS(String hex){
  String validHEX;
  int len = hex.length();
  switch (len){
    case 1:
      validHEX = "00000" + hex;
      break;
    case 2:
      validHEX = "0000" + hex;
      break;
    case 3:
      validHEX = "000" + hex;
      break;
    case 4:
      validHEX = "00" + hex;
      break;
    case 5:
      validHEX = "0" + hex;
      break;
    case 6:
      validHEX = hex;
      break;
    default:
      validHEX = hex.substring(len - 6, len);
      break;
  }
  return validHEX;
}

uint32_t timer = millis();
void loop() {
  // if a sentence is received, we can check the checksum, parse it...
  if (GPS.newNMEAreceived()) {
    // a tricky thing here is if we print the NMEA sentence, or data
    // we end up not listening and catching other sentences! 
    // so be very wary if using OUTPUT_ALLDATA and trytng to print out data
    //Serial.println(GPS.lastNMEA());   // this also sets the newNMEAreceived() flag to false
  
    if (!GPS.parse(GPS.lastNMEA()))   // this also sets the newNMEAreceived() flag to false
      return;  // we can fail to parse a sentence in which case we should just wait for another
  }
  
  /*if (millis() - timer > 2000) { 
    timer = millis(); // reset the timer

    if (GPS.fix) {
      int len;
      Serial.print("Lat : ");Serial.println(GPS.latitudeDegrees,4);
      printLat = (GPS.latitudeDegrees * 10000);
      Serial.print("Lat * 10000: ");Serial.println(printLat);
      String stringLat = String(printLat,HEX);
      Serial.print("stringLat: ");Serial.println(stringLat);
      String hexLat = padGPS(stringLat);
      Serial.print("Lat HEX: ");Serial.println(hexLat);
      hexLat.toCharArray(charGPS[0],7);
      Serial.print("Lat toCharArray: ");Serial.println(hexLat);
      
      Serial.print("Long : ");Serial.println(GPS.longitudeDegrees,4);
      printLong = (GPS.longitudeDegrees * 10000);
      Serial.print("Long * 10000: ");Serial.println(printLong);
      String stringLong = String(printLong,HEX);
      Serial.print("stringLong: ");Serial.println(stringLong);
      String hexLong = padGPS(stringLong);
      Serial.print("Long HEX: ");Serial.println(hexLong);
      hexLong.toCharArray(charGPS[1],7);
      Serial.print("Long toCharArray: ");Serial.println(hexLong);

      Serial.print("Alt: ");Serial.println(GPS.altitude);
      printAlt = GPS.altitude;
      String stringAlt = String(printAlt,HEX);
      Serial.print("stringAlt: ");Serial.println(stringAlt);
      String hexAlt = padGPS(stringAlt);
      Serial.print("Alt HEX: ");Serial.println(hexAlt);
      hexAlt.toCharArray(charGPS[2],7);
      Serial.print("Alt toCharArray: ");Serial.println(hexAlt);

      Serial.print("Prefix; ");
      Serial.println("0188");
      Serial.print("Lat; ");
      Serial.println(charGPS[0]);
      Serial.print("Long; ");
      Serial.println(charGPS[1]);
      Serial.print("Alt; ");
      Serial.println(charGPS[2]);
      Serial.print("0188");Serial.print(charGPS[0]);Serial.print(charGPS[1]);Serial.print(charGPS[2]);
    }
  }*/
  
  while (loraSerial.available()) {
    Serial.write(loraSerial.read());
  }

  if (tempCounter >= TEMP_SAMPLE_TIME)   //send data every x time
  {
     getTemperature();
     I2C_READ_ACC(0x01);
     sendAllData();
     tempCounter = 0;
  }
  delay(50);
  I2C_READ_ACC(0x01);
#if 0 
  if ((abs(axeXprev-axeXnow))>xThreshold || (abs(axeYprev-axeYnow))>yThreshold || (abs(axeZprev-axeZnow))>zThreshold)  //send data if any axis exceeds threshold
  {
     getTemperature();
     sendAllData();
     axeXprev = axeXnow;
     axeYprev = axeYnow;
     axeZprev = axeZnow;
  }
#endif
}

void sendAllData(void)
{
  Serial.println();
  Serial.println("****************************************");
  Serial.print("Temperature (deg C): ");Serial.println(tempC);
  Serial.print("X Axis Now: ");Serial.println(axeXnow);
  Serial.print("Y Axis Now: ");Serial.println(axeYnow);
  Serial.print("Z Axis Now: ");Serial.println(axeZnow);
  Serial.print("X Axis Previous: ");Serial.println(axeXprev);
  Serial.print("Y Axis Previous: ");Serial.println(axeYprev);
  Serial.print("Z Axis Previous: ");Serial.println(axeZprev);
  if (GPS.fix) {
    Serial.print("Location (in degrees, works with Google Maps): ");
    Serial.print(GPS.latitudeDegrees, 4);
    Serial.print(", "); 
    Serial.println(GPS.longitudeDegrees, 4);
    Serial.print("Alt: ");Serial.println(GPS.altitude);
  }
  Serial.println();

  formatData();
  loraSerial.print("mac tx uncnf 10 ");loraSerial.print("0167");loraSerial.print(charVal[0]);
  loraSerial.print("0271");loraSerial.print(charVal[1]);loraSerial.print(charVal[2]);loraSerial.println(charVal[3]);
  delay(5000);
  loraSerial.print("mac tx uncnf 10 ");loraSerial.print("0388");loraSerial.print(charGPS[0]);loraSerial.print(charGPS[1]);loraSerial.println(charGPS[2]);
  
  Serial.print("mac tx uncnf 10 ");Serial.print("0167");Serial.print(charVal[0]);
  Serial.print("0471");Serial.print(charVal[1]);Serial.print(charVal[2]);Serial.println(charVal[3]);
  Serial.print("mac tx uncnf 10 ");Serial.print("0388");Serial.print(charGPS[0]);Serial.print(charGPS[1]);Serial.println(charGPS[2]);
  
  waitCommandResponse();

}

void systemTimer(void)
{
  tempCounter++;
  
}


//************************ format data for lora tx **********************************
//modified for Cayenne Lora
void formatData(void)
{
  int len;
   
  printTemp = int(tempC*10);
  String stringT = String(printTemp,HEX);
  len = stringT.length();
  stringT.toCharArray(charVal[0],5);
  leadingZero(0,len);
  
  printXaxis = int(axeXnow * 1000);
  String stringX = String(printXaxis,HEX);
  len = stringX.length();
  stringX.toCharArray(charVal[1],5);
  leadingZero(1,len);

  printYaxis = int(axeYnow * 1000);
  String stringY = String(printYaxis,HEX);
  len = stringY.length();
  stringY.toCharArray(charVal[2],5);
  leadingZero(2,len);

  printZaxis = int(axeZnow * 1000);
  String stringZ = String(printZaxis,HEX);
  len = stringZ.length();
  stringZ.toCharArray(charVal[3],5);
  leadingZero(3,len);

  printLat = (GPS.latitudeDegrees * 10000);
  String stringLat = String(printLat,HEX);
  String hexLat = padGPS(stringLat);
  hexLat.toCharArray(charGPS[0],7);

  printLong = (GPS.longitudeDegrees * 10000);
  String stringLong = String(printLong,HEX);
  String hexLong = padGPS(stringLong);
  hexLong.toCharArray(charGPS[1],7);
  
  printAlt = GPS.altitude;
  String stringAlt = String(printAlt,HEX);
  String hexAlt = padGPS(stringAlt);
  hexAlt.toCharArray(charGPS[2],7);
}
//********************* Add leading zeros to hex value ********************************
void leadingZero(byte dataID, byte lenStr)
{
  charVal[dataID][4]='\0';
  
  if (lenStr==3)
  {
    charVal[dataID][3]=charVal[dataID][2];
    charVal[dataID][2]=charVal[dataID][1];
    charVal[dataID][1]=charVal[dataID][0];
    charVal[dataID][0]='0';
  }
  else if (lenStr==2)
  {    
    charVal[dataID][3]=charVal[dataID][1];
    charVal[dataID][2]=charVal[dataID][0];
    charVal[dataID][1]='0';
    charVal[dataID][0]='0';
  }
  else if (lenStr==1)
  {
    charVal[dataID][3]=charVal[dataID][0];
    charVal[dataID][2]='0';
    charVal[dataID][1]='0';
    charVal[dataID][0]='0';
  }
}
//****************** Write to I2C Slave Registers *********************************************

void I2C_SEND(unsigned char REG_ADDRESS, unsigned  char DATA)  //SEND data to MMA7660
{
  
  Wire.beginTransmission(adress_acc);
  Wire.write(REG_ADDRESS);
  Wire.write(DATA);
  Wire.endTransmission();
}

//****************************** Read I2C Slave register *******************************************
void I2C_READ_REG(int ctrlreg_address) //READ number data from i2c slave ctrl-reg register and return the result in a vector
{
  unsigned char REG_ADDRESS;
  int i=0; 
  Wire.beginTransmission(adress_acc); //=ST + (Device Adress+W(0)) + wait for ACK
  Wire.write(ctrlreg_address);  // register to read
  Wire.endTransmission();
  Wire.requestFrom(adress_acc,1); // read a number of byte and store them in write received
}

//****************** Accelerometer Initialization ************************************
 void ACC_INIT()
{
    I2C_SEND(ctrl_reg1 ,0X00); // standby to be able to configure
    delay(10);
    I2C_SEND(f_setup ,B01100000); // set FIFO mode - circular mode 32 byte watermark
    delay(5);
    I2C_SEND(xyz_data_cfg ,range); // set full range
    delay(1);
    I2C_SEND(ctrl_reg1 ,accConfig); // configure accelerometer
    delay(1);
}
//************************** Read Acceleromter Registers ************************************

void I2C_READ_ACC(int ctrlreg_address) //READ number data from i2c slave ctrl-reg register and return the result in a vector
{
  byte REG_ADDRESS[7];
  int accel[4];
  int i=0; 
  Wire.beginTransmission(adress_acc); //=ST + (Device Adress+W(0)) + wait for ACK
  Wire.write(ctrlreg_address);  // store the register to read in the buffer of the wire library
  Wire.endTransmission(); // actually send the data on the bus -note: returns 0 if transmission OK-
  Wire.requestFrom(adress_acc,7); // read a number of byte and store them in wire.read (note: by nature, this is called an "auto-increment register adress")

  for(i=0; i<7; i++) // 7 because on datasheet p.19 if FREAD=0, on auto-increment, the adress is shifted
  // according to the datasheet, because it's shifted, outZlsb are in adress 0x00
  // so we start reading from 0x00, forget the 0x01 which is now "status" and make the adapation by ourselves
  //this gives:
  //0 = status
  //1= X_MSB
  //2= X_LSB
  //3= Y_MSB
  //4= Y_LSB
  //5= Z_MSB
  // 6= Z_LSB
  {
  REG_ADDRESS[i]=Wire.read(); //each time you read the write.read it gives you the next byte stored. The couter is reset on requestForm
}


// MMA8653FC gives the result in 10bits. 8bits are in _MSB, and 2 are in _LSB
// this part is used to concatenate both, and then put a sign on it (the most significant bit is giving the sign)
// the explanations are on p.14 of the 'application notes' given by freescale.
      for (i=1;i<7;i=i+2)
      {
      accel[0] = (REG_ADDRESS[i+1]|((int)REG_ADDRESS[i]<<8))>>6; // X
        if (accel[0]>0x01FF) {accel[1]=(((~accel[0])+1)-0xFC00);} // note: with signed int, this code is optional
        else {accel[1]=accel[0];} // note: with signed int, this code is optional
            switch(i){
            case 1: axeXnow=accel[1]*resolution;
                              break;
            case 3: axeYnow=accel[1]*resolution;
                              break;
             case 5: axeZnow=accel[1]*resolution;
                              break;
                }
       }

}

//******************** Temperature Sensor (TMP112) Reading *****************************
void getTemperature(void)
{
  long tempSum;
  int tempReadingIn[2];
  Wire.requestFrom(tmpAddress,2); 
  tempReadingIn[0] = Wire.read();
  tempReadingIn[1] = Wire.read();

  //it's a 12bit int, using two's compliment for negative
  tempSum = ((tempReadingIn[0] << 8) | tempReadingIn[1]) >> 4; 
  tempC = tempSum*0.0625;
}

//********************* configure ABP ************************************************
void configureABP(void)
{
  loraSerial.print("mac set deveui ");loraSerial.println(DEVICE_EUI);
  Serial.print("mac set deveui ");Serial.println(DEVICE_EUI);
  waitCommandResponse();
  
  //loraSerial.print("mac set appeui ");loraSerial.println(APP_EUI);
  //Serial.print("mac set appeui ");Serial.println(APP_EUI);
  //waitCommandResponse();
  
  loraSerial.print("mac set appkey ");loraSerial.println(APP_KEY);
  Serial.print("mac set appkey ");Serial.println(APP_KEY);
  waitCommandResponse();
  loraSerial.print("mac set devaddr ");loraSerial.println(DEVICE_ADDR);
  Serial.print("mac set devaddr ");Serial.println(DEVICE_ADDR);
  waitCommandResponse();
  loraSerial.print("mac set nwkskey ");loraSerial.println(NWK_SESSION_KEY);
  Serial.print("mac set nwkskey ");Serial.println(NWK_SESSION_KEY);
  waitCommandResponse();
  loraSerial.print("mac set appskey ");loraSerial.println(APP_SESSION_KEY);
  Serial.print("mac set appskey ");Serial.println(APP_SESSION_KEY);
  waitCommandResponse();
  loraSerial.println("mac save");
  Serial.println("mac save");
  waitCommandResponse();
  loraSerial.println("mac join abp");
  Serial.println("mac join abp");
  waitCommandResponse();
}

#if 0 //not supported on free account
//************************ configure OTAA ************************************
void configureOTAA(void)
{
  loraSerial.print("mac set deveui ");loraSerial.println(DEVICE_EUI);
  Serial.print("mac set deveui ");Serial.println(DEVICE_EUI);
  waitCommandResponse();
  loraSerial.print("mac set appeui ");loraSerial.println(APP_EUI);
  Serial.print("mac set appeui ");Serial.println(APP_EUI);
  waitCommandResponse();
  loraSerial.print("mac set appkey ");loraSerial.println(APP_KEY);
  Serial.print("mac set appkey ");Serial.println(APP_KEY);
  waitCommandResponse();
  loraSerial.println("mac save");
  Serial.println("mac save");
  waitCommandResponse();
  loraSerial.println("mac join otaa");
  Serial.println("mac join otaa");
   waitCommandResponse();
}
#endif

//********************* configure channels on or off ******************************
void setChannelStatus()
{
  byte channelNumber=0;
  for (int x=0; x<9; x++)
  {
    for (int b=0; b<8; b++)
    {
      if (bitRead(channelBank[x],b))
      {
        loraSerial.print("mac set ch status ");loraSerial.print(channelNumber);loraSerial.println(" on");
        Serial.print("mac set ch status ");Serial.print(channelNumber);Serial.println(" on");
      }
      else
      {
        loraSerial.print("mac set ch status ");loraSerial.print(channelNumber);loraSerial.println(" off");
        Serial.print("mac set ch status ");Serial.print(channelNumber);Serial.println(" off");
      }
    channelNumber++;
    waitCommandResponse();
    }
  }
  loraSerial.println("mac set adr off");
  Serial.println("mac set adr off");
  waitCommandResponse();
  loraSerial.println("mac set pwridx 5");
  Serial.println("Set Tx power");
  waitCommandResponse();
  //loraSerial.println("mac set dr 4");
  //Serial.println("Set Data Rate 4");
  //waitCommandResponse();
  loraSerial.println("mac save");
  delay(200);
}

//******************** wait for response from module *************************************
void waitCommandResponse(void)
{
  unsigned long currentTime,startTime;
  startTime = millis(); 
  while (loraSerial.available() == 0)
  {
    currentTime = millis();
    if (currentTime > (startTime + 3000))       //exit wait routine if nor response in 3 seconds
    {
      Serial.println("No Response from Lora Module");
      return;
    }
  }
 
  while (loraSerial.available()) 
    {
      Serial.write(loraSerial.read());
    }
}

//************************ get configuration information from module *********************
void getConfig(void)
{
  loraSerial.println("sys get ver");      //get module version
  Serial.print("Module Version: ");
  waitCommandResponse();
  Serial.println();
  
  loraSerial.println("sys get hweui");      //get module version
  Serial.print("EUI Node Address: ");
  waitCommandResponse();
  Serial.println();
}