1

I'm trying to configure a Zigbee sensor network. My "gateway (coordinator)" and "End devices" are made with XBeePro S2B model and configured in API mode "2". The "gateway (coordinator)" also has a SIM900 module, for uploading data to website (recieved on XBee), and Atmega 328p for codes (for "gateway (coordinator)" I'm using a Gboard device here), and for "End devices", I make/print a PCB with a atmega328p, XBee and PIR sensor.

The configuration works fine with several "End devices" (sincerilly, I have only tested with two "End devices", because it is expensive)...

The problem is when the "gateway (coordinator)" recieve data from more than one "End devices" at the same time. In this situation ("End devices" sending simultaneously) the "gateway (coordinator)" only recieves one packet (and only uploads that data to the website). I'm sure that I have a trouble with my code (sorry for the desestructurated and chaotic code, I'm a newbie).

Can anyone help me with the code?

code "gateway (coordinator)":

#include <elapsedMillis.h>
#include <SoftwareSerial.h>
#include <Streaming.h> 
#include <XBee.h>      
int xbeeRecibido;
char urlArreglo[100];
uint8_t slCmd[] = {'S','L'};  
uint8_t dbCmd[] = {'D','B'}; 
char adr_part[8];
char rssiValor_part[8];
String adr="";
String rssiValor="";
AtCommandRequest atRequest = AtCommandRequest();
AtCommandResponse atResponse = AtCommandResponse();  
elapsedMillis timeElapsed = 0;
unsigned long interval = 1800000 ;////en milisegundos  cada 30 min.
String direccionRed;
int bateria;
String valorRssi;
int actividadPir;
String datosHttp; ///concatenacion de datos para enviar por HTTP
int8_t answer;
char data[512];
int data_size;
char aux_str[100];
char aux;
int x = 0;
XBee xbee = XBee();//XBee object
Rx16Response rx = Rx16Response();
SoftwareSerial mySerial(2, 3); //PARA GPRS SIM900
//int b00;  //este seria el primero, que se pierde al buscar el 0X7E
int b01;
int b02;
int b03;
int b04; //source network adress 64Bit 
int b05; //source network adress 64Bit
int b06; //source network adress 64Bit
int b07; //source network adress 64Bit
int b08; //source network adress 64Bit
int b09; //source network adress 64Bit
int b10; //source network adress 64Bit
int b11; //source network adress 64Bit 
int b12; //source network adress 16Bit
int b13; //source network adress 16Bit
int b14;
int b15; //pir digital
int b16; //bateria 
int b17; //checksum
void setup() {
   pinMode(14, OUTPUT);////led debug en 14 ((A0)DEBUGGGG!!!!
   pinMode(6, OUTPUT);///para encender SIM900 ...en pin6 HIGH de arduino GBOARD
   digitalWrite(6, HIGH);///para encender SIM900 ...en pin6 HIGH de arduino GBOARD
    mySerial.begin(9600); 
    Serial.begin(9600);
///////GPRS////////
    power_on();
    delay(3000);
    sendATcommand("AT+ipr=9600", "OK", 2000);///////MIO PARA BAUDERATE A 9600 (por defecto 0=auto..¿se apaga?)
    // sets the PIN code
    sendATcommand("AT+CPIN=****", "OK", 2000);
    delay(3000);
    while (sendATcommand2("AT+CREG?", "+CREG: 0,1", "+CREG: 0,5", 2000) == 0);
    sendATcommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\"", "OK", 2000);
    sendATcommand("AT+SAPBR=3,1,\"APN\",\"gprsmov.pepephone.com\"", "OK", 2000);
    sendATcommand("AT+SAPBR=3,1,\"USER\",\"\"", "OK", 2000);
    sendATcommand("AT+SAPBR=3,1,\"PWD\",\"\"", "OK", 2000);
    while (sendATcommand("AT+SAPBR=1,1", "OK", 20000) == 0)
    {
        delay(5000);
    }
////FIN GPRS////
lanzarHttpAutoControl();
delay(15000);
}

void loop() {  
if (timeElapsed > interval) 
    {               
        lanzarHttpAutoControl();
        delay(15000);
    timeElapsed = 0;
    }
if (Serial.available()==18) {//make sure the frame is all there      
  if (Serial.read()==0x7E) {   
     b01 = Serial.read();     
     b02 = Serial.read();
     b03 = Serial.read();    
     b04 = Serial.read(); //source network adress 64Bit 
     b05 = Serial.read(); //source network adress 64Bit    
     b06 = Serial.read(); //source network adress 64Bit 
     b07 = Serial.read(); //source network adress 64Bit     
     b08 = Serial.read(); //source network adress 64Bit 
     b09 = Serial.read(); //source network adress 64Bit     
     b10 = Serial.read(); //source network adress 64Bit 
     b11 = Serial.read(); //source network adress 64Bit 
     b12 = Serial.read(); //source network adress 16Bit
     b13 = Serial.read(); //source network adress 16Bit
     b14 = Serial.read(); 
     b15 = Serial.read(); //pir digital   
     b16 = Serial.read(); //bateria
     b17 = Serial.read();  //checksum
     direccionRed =  String(b04, HEX); 
     direccionRed +=  String(b05, HEX); 
     direccionRed +=  String(b06, HEX);
     direccionRed +=  String(b07, HEX);
     direccionRed +=  String(b08, HEX);
     direccionRed +=  String(b09, HEX);
     direccionRed +=  String(b10, HEX);
     direccionRed +=  String(b11, HEX);  
     actividadPir = b15;
     bateria = int(b16);
     digitalWrite(14, HIGH);//FOR DEBUG LED
     delay(1000);//FOR DEBUG LED
     digitalWrite(14, LOW);//FOR DEBUG LED
     xbeeRecibido = 1;
        } //fin if 0x7E 
  }///fin recorrer bytes 
   else {
         if (xbeeRecibido == 1) {///si se ha recibido info de xbee sensor
         colectorDatos();
         xbeeRecibido = 0;         
        }
   }
delay (10);
}//fin loop


void rss() {  ///PARA RSSI
   /* returns received signal strength value for the last RF data packet */
   union {byte B; char C;} atCmd[3];
   AtCommandRequest atCmdReq;
   AtCommandResponse atResp;
   byte respLen, *resp, dBm;
   strcpy(&atCmd[0].C, "DB");
   atCmdReq = AtCommandRequest(&atCmd[0].B);
   atResp = AtCommandResponse();
   xbee.send(atCmdReq);
   if (xbee.readPacket(5000)) {
       if (xbee.getResponse().getApiId() == AT_COMMAND_RESPONSE) {
           xbee.getResponse().getAtCommandResponse(atResp);
           if (atResp.isOk()) {
               respLen = atResp.getValueLength();
               if (respLen == 1) {
                   resp = atResp.getValue();
                   dBm = resp[0];
                   valorRssi = (String)dBm;  
               }
               else {
               }
           }
           else {
           }
       }
       else {
       }
   }
   else {
   } 
}///fin rss()


void power_on(){
    uint8_t answer=0;
    // checks if the module is started
    answer = sendATcommand("AT", "OK", 2000);
    if (answer == 0)
    {
        // waits for an answer from the module
        while(answer == 0){  
            // Send AT every two seconds and wait for the answer   
            answer = sendATcommand("AT", "OK", 2000);    
        }
    }
}


int8_t sendATcommand(char* ATcommand, char* expected_answer1, unsigned int timeout){
    uint8_t x=0,  answer=0;
    char response[100];
    unsigned long previous;
    memset(response, '\0', 100);    // Initialize the string
    delay(100);
    while( mySerial.available() > 0) mySerial.read();    // Clean the input buffer
    mySerial.println(ATcommand);    // Send the AT command 
        x = 0;
    previous = millis();
    // this loop waits for the answer
    do{
        if(mySerial.available() != 0){    
            response[x] = mySerial.read();
            x++;
            // check if the desired answer is in the response of the module
            if (strstr(response, expected_answer1) != NULL)    
            {
                answer = 1;
            }
        }
        // Waits for the asnwer with time out
    }
    while((answer == 0) && ((millis() - previous) < timeout));    
    return answer;
}


int8_t sendATcommand2(char* ATcommand, char* expected_answer1, 
char* expected_answer2, unsigned int timeout){
    uint8_t x=0,  answer=0;
    char response[100];
    unsigned long previous;
    memset(response, '\0', 100);    // Initialize the string
    delay(100);
    while( mySerial.available() > 0) mySerial.read();    // Clean the input buffer
    mySerial.println(ATcommand);    // Send the AT command 
        x = 0;
    previous = millis();
    // this loop waits for the answer
    do{        
        if(mySerial.available() != 0){    
            response[x] = mySerial.read();
            x++;
            // check if the desired answer 1 is in the response of the module
            if (strstr(response, expected_answer1) != NULL)    
            {
                answer = 1;
            }
            // check if the desired answer 2 is in the response of the module
            if (strstr(response, expected_answer2) != NULL)    
            {
                answer = 2;
            }
        }
     // Waits for the asnwer with time out
    }while((answer == 0) && ((millis() - previous) < timeout));    
    return answer;
}


void colectorDatos(){ ///funcion para recolectar datos recibidos del xbee y gestionarlos para enviarlos por GPRS
    rss(); ////recupero rssi que se pone en variable valorRssi
    datosHttp = direccionRed +";"; ///cualquier valor del array, todos deverian tener mismo valor (direccion64bits)
    datosHttp += bateria; 
    datosHttp += ";";
    datosHttp += valorRssi;
    datosHttp += ";";
    datosHttp += actividadPir; //pir 
    envio(datosHttp); ///envio por gprs    
}///fin colectorDatos


void lanzarHttpAutoControl() {
  adr="";
  atRequest.setCommand(slCmd);  // set command to SL to get low part of MAC address 
  while (!sendAtCommand()) {};
  for (int i = 0; i < atResponse.getValueLength(); i++) {
    mySerial.print(atResponse.getValue()[i], HEX);
    sprintf(adr_part, "%lX", (unsigned long)(atResponse.getValue()[i]));
    if (atResponse.getValue()[i]<=0xF) 
        adr += 0;      
        adr += adr_part; 
  } 
  envio(adr); ///envio por gprs

}


void envio(String entrada){///envio GPRS...recibe String con datos (o control o sensor)
   memset(urlArreglo, 0, sizeof(urlArreglo));///a cero el array
    answer = sendATcommand("AT+HTTPINIT", "OK", 10000);
    if (answer == 1)
    {
        // Sets CID parameter
        answer = sendATcommand("AT+HTTPPARA=\"CID\",1", "OK", 5000);
        if (answer == 1)
        {
      sprintf(urlArreglo,  "AT+HTTPPARA=\"URL\",\"www.pestmonitors.com/dream/prueba_gsm_get.php?datos=%s\"",entrada.c_str());
      answer = sendATcommand(urlArreglo, "OK", 5000);
       delay(5000);       
            if (answer == 1)
            {
                answer = sendATcommand("AT+HTTPACTION=0", "+HTTPACTION:0,200", 10000);             
            }
    else
    {
    }  
    sendATcommand("AT+HTTPTERM", "OK", 5000);
    delay(5000);   
      }
    }  
}


int sendAtCommand() { // used here to sens AT command to the Xbee to get information such as the MAC address
  xbee.send(atRequest);
  if (xbee.readPacket(5000)) {
    if (xbee.getResponse().getApiId() == AT_COMMAND_RESPONSE) {
      xbee.getResponse().getAtCommandResponse(atResponse);
      if (atResponse.isOk()) {
        if (atResponse.getValueLength() > 0) {
          mySerial.println(atResponse.getValueLength(), DEC);
          for (int i = 0; i < atResponse.getValueLength(); i++) {
            mySerial.print(atResponse.getValue()[i], HEX);
          }
        }
        return 1;
      } 
      else {
      }
    } else {
      mySerial.print(xbee.getResponse().getApiId(), HEX);
    }   
  } else {
    if (xbee.getResponse().isError()) {
    } 
    else {  
    }
  }
  return 0;
}

code "End devices":

#include <Sleep_n0m1.h>
#include <XBee.h>
XBee xbee = XBee();
uint8_t payload[] = { 0, 0 };
XBeeAddress64 addr64 = XBeeAddress64(0x0, 0xFFFF);
ZBTxRequest zbTx = ZBTxRequest(addr64, payload, sizeof(payload));
ZBTxStatusResponse txStatus = ZBTxStatusResponse();
boolean apagar;
int battVolts;
int PinEntradaBat = A0;
int valorBateriaTotal;
int valorBateria;
int mapeoValorBateria;
Sleep sleep;
unsigned long sleepTime; //how long you want the arduino to sleep
int salida = 7; ////pin salida 7 para DTR xbee
int entradaInterrumpirSleep =2; ////pin desde pir para interrumpir/despertar 
boolean abortSleep; //cancel sleep cycle
int modo;
int cicloTiempoSleep;///establecer ciclo alarma
int numeroCiclos; ///para retomar ciclo si falsa alarma
boolean enviado; ///para comprobar si recepción de xbbe, sino, reenviar!
uint8_t atdCmd[]={'D','5'};
uint8_t value[]={4};///pongo DIO5 a output LOW
uint8_t length=1;
AtCommandRequest atRequest = AtCommandRequest(atdCmd, value, length);
AtCommandResponse atResponse = AtCommandResponse(); 
//boolean saltarPrimerPir = true; ////PARA NUEVO PIR, SALTAR LA ALARMA AL ARRANCAR ¿PORQUE?
void setup()
{  
  analogReference(DEFAULT); 
  enviado = true;
  numeroCiclos = 0; 
  apagar = false; 
  pinMode(salida, OUTPUT); //para DTR en xbee
  pinMode(6, OUTPUT); //para MOSFET (en digitalPin6 PWM)!!
  digitalWrite(salida, LOW); //EMITE 5V HACIA DTR, ENVIAR EN XBEE
  delay(120000);//2 minutos para evitar primer interrupt!y dar tiempo a comprobar tecnico la asociación
  abortSleep = false; //can be used to cancel the sleep cycle
  sleep.setCalibrationInterval(1);
  sleepTime = 1000;//set sleep time in ms, max sleep time is 49.7 days (1/2 1 min)
  modo = 0; //para empezar con modo CONTROL 
  numeroCiclos = 0;
  Serial.begin(9600);
  xbee.setSerial(Serial);  
  xbee.send(atRequest);// set command to ATD50 to stop LED Assoc...////DESCOMENTAR PARA APAGAR LED ASSOC!!!!!!
  delay(5000);
}//fin setup


void loop()
{
if (apagar == true) { ///APAGAR SI BATERIA MUY BAJA!!!!
  detachInterrupt(0);  
  while (apagar == true) {
  }
}   
  if (modo == 0) {
    detachInterrupt(0);
    digitalWrite(salida, LOW); //EMITE 0V HACIA DTR, ENVIAR EN XBEE
    digitalWrite(6, HIGH); //EMITE 5V HACIA mosfet/regulador, ENCIENDE XBEE    
    cicloTiempoSleep = 21600; //6 horas
    delay(10);
    enviarXbee(0);    
    digitalWrite(salida, HIGH);//EMITE 5V HACIA DTR, ACTIVAR DTR (XBEE SLEEP)   
    digitalWrite(6, LOW); //EMITE 0V HACIA mosfet/regulador, APAGAR 
    delay(30000);///30seg de inactividad post envio control!
    attachInterrupt(0, interrumpirPir, RISING);    
  } //fin modo0 CONTROL
  if (modo == 1) {
        detachInterrupt(0);
        digitalWrite(salida, LOW); //EMITE 0V HACIA DTR, ENVIAR EN XBEE
        digitalWrite(6, HIGH); //EMITE 5V HACIA mosfet/regulador, ENCIENDE XBEE
        modo = 0; //modo CONTROL
        numeroCiclos = 0; 
        cicloTiempoSleep = 21600; //6 horas para enviar CONTROL despues de ACTIVIDAD
        delay(10);
        enviarXbee(1); 
        digitalWrite(salida, HIGH);//EMITE 5V HACIA DTR, ACTIVAR DTR (XBEE SLEEP)   
        digitalWrite(6, LOW); //EMITE 0V HACIA mosfet/regulador, APAGAR 
        delay(120000);///2 minutos de inactividad post envio alarma! (para no enviar otra enseguida)
        attachInterrupt(0, interrumpirPir, RISING);
  }//fin modo1 ACTIVIDAD
  abortSleep = false;
  for (int i=0; i < cicloTiempoSleep; i++){ /////ARREGLO CON FOR PARA REITERAR 1000ms (1seg) x VECES (hace extraños el int0 con SleepDelay juntos) 
        numeroCiclos = i;
        sleep.pwrDownMode(); //set sleep mode 
        sleep.sleepDelay(sleepTime,abortSleep); //sleep for: sleepTime
        if (abortSleep == true) {
          break;
        }
   }//fin contador tiempo
  if (cicloTiempoSleep <= 1 || numeroCiclos == --cicloTiempoSleep) { ///estos dos -- restan 1 al valor de la variable
    modo = 0;
  }
}//fin loop


void interrumpirPir() // si disparo PIR por interrupt0 (isr)
{  
  if (numeroCiclos != 0) {/////AQUI EVITAR PRIMERA INTERRUPCION AL INICIARSE EL SENSOR/////
  abortSleep = true;
  cicloTiempoSleep = cicloTiempoSleep - numeroCiclos;
  modo = 1; 
  }//fin saltar primer PIR 
}///fin interrumpir! ISR


void enviarXbee(int valorPir) // si disparo PIR por interrupt0 (isr)
{    
battVolts=getBandgap();
valorBateriaTotal = 0;
for (int e=0; e < 20; e++) 
    {
       mapeoValorBateria = map(analogRead(A1), 0, 1023, 0, battVolts);
       valorBateriaTotal = valorBateriaTotal + mapeoValorBateria;
     delay(10);
    } 
valorBateriaTotal = valorBateriaTotal/20;
if (mapeoValorBateria <= 95) {///APAGAR SI BATERIA MUY BAJA!!!!
apagar = true;
}    
    payload[0] = valorPir; ///PIR
    payload[1] = mapeoValorBateria & 0xff;
    delay (10000);
    xbee.send(zbTx);
    //delay (15000);
    if (xbee.readPacket(5000)) {        
      if (xbee.getResponse().getApiId() == ZB_TX_STATUS_RESPONSE) {
        xbee.getResponse().getZBTxStatusResponse(txStatus);
        if (txStatus.getDeliveryStatus() == SUCCESS) {
         // enviado = true;
        } else {
        //  enviado = false;     
        }
      }
    } else if (xbee.getResponse().isError()) {
    } else {
    } 
}//end enviar xbee


long leerBateria()//para ver estado bateria
{
}
int getBandgap(void) // Returns actual value of Vcc (x 100)
   {      
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    // For mega boards
    const long InternalReferenceVoltage = 1115L;  // Adjust this value to your boards specific internal BG voltage x1000
       // REFS1 REFS0          --> 0 1, AVcc internal ref. -Selects AVcc reference
       // MUX4 MUX3 MUX2 MUX1 MUX0  --> 11110 1.1V (VBG)         -Selects channel 30, bandgap voltage, to measure
    ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR)| (0<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#else
    // For 168/328 boards
    const long InternalReferenceVoltage = 1056L;  // Adjust this value to your boards specific internal BG voltage x1000
       // REFS1 REFS0          --> 0 1, AVcc internal ref. -Selects AVcc external reference
       // MUX3 MUX2 MUX1 MUX0  --> 1110 1.1V (VBG)         -Selects channel 14, bandgap voltage, to measure
    ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);     
#endif
    delay(50);  // Let mux settle a little to get a more stable A/D conversion
       // Start a conversion  
    ADCSRA |= _BV( ADSC );
       // Wait for it to complete
    while( ( (ADCSRA & (1<<ADSC)) != 0 ) );
       // Scale the value
    int results = (((InternalReferenceVoltage * 1023L) / ADC) + 5L) / 10L; // calculates for straight line value 
    return results;
   }
int sendAtCommand() {
  xbee.send(atRequest);
  if (xbee.readPacket(5000)) {// wait up to 5 seconds for the status response
    if (xbee.getResponse().getApiId() == AT_COMMAND_RESPONSE) {// should be an AT command response
      xbee.getResponse().getAtCommandResponse(atResponse);
      if (atResponse.isOk()) {
        if (atResponse.getValueLength() > 0) {
          for (int i = 0; i < atResponse.getValueLength(); i++) {
          }
        }
      } 
      else {
      }
    } else {
    }   
  } else {
    if (xbee.getResponse().isError()) {
    } 
    else {
    }
  }
}

Thank you very much. I really appreciate your help.

  • I didn't parse through your code, nor have i used the xBee Pro you mentioned. I did however solve a similar problem once by having each send transmission occur 3 times with a random delay from 400-1200 milliseconds between transmissions (used trial and error to determine those values). With multiple transmissions with randomly generated delay between each most transmissions should make it on at least one of the tries, of course the receiving end then needs to be able to decide if it got dup packets and throw out the extra data. – Tyson Mar 29 '15 at 20:20
  • This looks like a good solution, Tyson! I understand that you suggest to send several data packets from the "End device" spaciated by a random delay, to make sure that at least one gets to the "gateway (coordinator)". So, how do I modify my code to make the "End device" repeatedly send the same message? Also, I have the same problem with how to modify my code for the "gateway (coordinator)" to discriminate the identical packages. Thanks a lot for your answer and time and to all the altruistic people here like you, Tyson. You rule! Can anyone help me to try to implement this solution? – xavi Mar 29 '15 at 21:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.