N'KOUKA NathanRémi AntonucciJacky ChenAmit Patel
Published © GPL3+

Beestial ( Embedded system project )

Beestial is an autonomous system which monitors a beehive by sending live data of this beehave to a website.

IntermediateFull instructions providedOver 2 days69
Beestial ( Embedded system project )

Things used in this project

Hardware components

Arduino Nano 33 BLE Sense
Arduino Nano 33 BLE Sense
×1
SparkFun Load Cell Amplifier - HX711
SparkFun Load Cell Amplifier - HX711
×1
Adafruit Waterproof DS18B20 Digital temperature sensor
Adafruit Waterproof DS18B20 Digital temperature sensor
×1
DHT22 Temperature Sensor
DHT22 Temperature Sensor
×1
Lipo Rider Pro
×1
Battery Li-Ion 3,7V 1050 mAh
×1
INA219 SENSOR
×1
Module Lora-E5
×1
Cable USB-Série RS232 3,3V
×1
Solar sell
×1
Régulateur de tension Pololu 3.3V
×1
Régulateur de tension 3.3V MCP 1603
×1

Software apps and online services

Arduino IDE
Arduino IDE
Ubidots
Ubidots
BEEP Monitor
KiCad
KiCad
The Things Network
The Things Network

Hand tools and fabrication machines

3D Printer ( for PCB )
Soldering iron
Tin wire
Voltmeter

Story

Read more

Schematics

Electrical Diagram

This circuit represents our electrical diagram which allowed us to make our PCB.

PCB Schematic

This is our PCB schematic.

Code

Monitor Code

C/C++
This code will collect datas sent by each electronic device. Then, it will send these datas to a website named The Things Network
// INCLUDE
#include <Arduino_HTS221.h>
#include <HX711.h> // Balance
#include <DHT.h> // DHT
#include <Wire.h> // INA
#define MAXIMWIRE_EXTERNAL_PULLUP
#include <MaximWire.h> // DSB
#include "DFRobot_INA219.h"

#define T 64
signed short freq_amp[32][2];
signed short amplitude[10];

// --Initialisation LoraWan
static char recv_buf[512];
static bool is_exist = false;
static bool is_join = false;
int ret=0;
// ----------------------

// --Initialisation DHT
#define brocheDeBranchementDHTa 7
#define brocheDeBranchementDHTb 9
#define typeDeDHT DHT22

DHT dhta(brocheDeBranchementDHTa, typeDeDHT);
DHT dhtb(brocheDeBranchementDHTb, typeDeDHT);
// ----------------------

// --Initlisation Balance
HX711 capteurPoids;
#define DAT 13
#define CLK 12
float valeurPoids;
// ----------------------

// --Initialisation Batterie
const float TensionMax = 4.2;
const float TensionMin = 3.3;
// ----------------------

// --Initialisation INA
DFRobot_INA219_IIC     ina219(&Wire, INA219_I2C_ADDRESS4);
float ina219Reading_mA = 1000;
float extMeterReading_mA = 1000;
// ----------------------

// --Initialisation DSB
#define PIN_BUS 6
MaximWire::Bus bus(PIN_BUS);
MaximWire::DS18B20 device;
int cpt=0;
signed short temp_dsb[2];
// ----------------------


// --SETUPS--
void setupLED(){
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(LED_PWR, OUTPUT);

  digitalWrite(LED_PWR, LOW);
  digitalWrite(LED_BUILTIN, HIGH);
  delay(5000);  
  digitalWrite(LED_BUILTIN, LOW);
  
}

void setupDHT(){
  dhta.begin();
  dhtb.begin();
}

void setupBalance(){
  capteurPoids.begin(DAT, CLK);
  capteurPoids.set_scale(30032);
  //capteurPoids.tare();
}

void setupINA(){
  ina219.linearCalibrate(ina219Reading_mA, extMeterReading_mA);
  unsigned long timer = millis();
  while(ina219.begin() != true) {
        if(millis()-timer > 10000) break;
    }
}
// ----------------------

// Fonction LORA
static int at_send_check_response(char *p_ack, int timeout_ms, char *p_cmd, ...){
  int ch;
  int num = 0;
  int index = 0;
  int startMillis = 0;
  memset(recv_buf, 0, sizeof(recv_buf));
  Serial1.write(p_cmd);
  Serial.write(p_cmd);
  delay(200);
  startMillis = millis();
  do{
    while (Serial1.available() > 0){
      ch = Serial1.read();
      recv_buf[index++] = ch;
      Serial.write(ch);
      delay(2);
    }
  } while (millis() - startMillis < timeout_ms);
  
  if (strstr(recv_buf, p_ack) != NULL){return 1;}
  else return 0;
}

void setupLORA(){
  Serial.print("E5 LORAWAN TEST\r\n");
  
    if(at_send_check_response("+AT: OK", 100, "AT\r\n")){
      is_exist = true;
      at_send_check_response("+ID: AppEui", 1000, "AT+ID\r\n");
      at_send_check_response("+MODE: LWOTAA", 1000, "AT+MODE=LWOTAA\r\n");
      at_send_check_response("+DR: DR0", 1000, "AT+DR=DR0\r\n");
      at_send_check_response("+CH: NUM", 1000, "AT+CH=NUM,0-2\r\n");
      at_send_check_response("+KEY: APPKEY", 1000, "AT+KEY=APPKEY,\"6D3E3B5BD04AFA9EBD6C9196EF894740\"\r\n");
      at_send_check_response("+ID: DEVEUI", 1000, "AT+ID=DEVEUI,\"70B3D57ED005642E\"\r\n");
      at_send_check_response("+ID: APPEUI", 1000, "AT+ID=APPEUI,\"0000000000000000\"\r\n");
      at_send_check_response("+CLASS: C", 1000, "AT+CLASS=A\r\n");
      ret=at_send_check_response("+PORT: 9", 1000, "AT+PORT=9\r\n");
      delay(200);
      is_join = true;
    }
    else{
      is_exist = false;
      Serial.print("No E5 module found.\r\n");
    }
}
// ----------------------

// --Fonctions Calculs
float calculBalance(){
  valeurPoids = capteurPoids.get_value(10);
  float val;
  val = float(valeurPoids/32500); // il faut faire un calibrage avec plein de valeurs //
  return(val);
}

signed short calculBatterie(){
  float a0= analogRead(A0);
  float bat= 1.4*2*a0*3.3/1100; //*1.4 car voir pont div.
  float minValue= 1.9;
  float maxValue= 3;

  
  
  signed short bat1= 100*(bat-minValue)/(maxValue-minValue);  
  // if(abs(bat1) > 100){
  //   if(abs(bat1) >150){
  //     bat1 = 0;
  //   }
  //   bat1 = 100;
  // }
  if(bat1 < 0) bat1 = 1;
  if(bat1>100) bat1=100;
  return(bat1);
}

float Q_FFT(int in[],int N,float Frequency){ 

  unsigned int Pow2[13]={1,2,4,8,16,32,64,128,256,512,1024,2048}; // declaring this as global array will save 1-2 ms of time

  int a,c1,f,o,x;         
  byte check=0;
  a=N;  
                                 
  for(int i=0;i<12;i++){                 //calculating the levels
    if(Pow2[i]<=a) o=i; 
  }
      
  int out_r[Pow2[o]]={};   //real part of transform
  int out_im[Pow2[o]]={};  //imaginory part of transform
           
  x=0;  
  for(int b=0;b<o;b++){                     // bit reversal
    c1=Pow2[b];
    f=Pow2[o]/(c1+c1);
    for(int j=0;j<c1;j++){ 
      x=x+1;
      out_im[x]=out_im[j]+f;
    }
  }
  for(int i=0;i<Pow2[o];i++){            // update input array as per bit reverse order       
    out_r[i]=in[out_im[i]]; 
    out_im[i]=0;
  }

  int i10,i11,n1,tr,ti;
  float e;
  int c,s;
  for(int i=0;i<o;i++) {                                   //fft
    i10=Pow2[i];              // overall values of sine/cosine  
    i11=Pow2[o]/Pow2[i+1];    // loop with similar sine cosine
    e=360/Pow2[i+1];
    e=0-e;
    n1=0;

    for(int j=0;j<i10;j++){
      c=e*j;
      while(c<0){c=c+360;}
      while(c>360){c=c-360;}
      n1=j;
      for(int k=0;k<i11;k++){
        if(c==0) { 
          tr=out_r[i10+n1];
          ti=out_im[i10+n1];
        }
        else if(c==90){ 
          tr= -out_im[i10+n1];
          ti=out_r[i10+n1];
        }
        else if(c==180){
          tr=-out_r[i10+n1];
          ti=-out_im[i10+n1];
        }
        else if(c==270){
          tr=out_im[i10+n1];
          ti=-out_r[i10+n1];
        }
        else if(c==360){
          tr=out_r[i10+n1];
          ti=out_im[i10+n1];
        }
        else if(c>0  && c<90){
          tr=out_r[i10+n1]-out_im[i10+n1];
          ti=out_im[i10+n1]+out_r[i10+n1];
        }
        else if(c>90  && c<180){
          tr=-out_r[i10+n1]-out_im[i10+n1];
          ti=-out_im[i10+n1]+out_r[i10+n1];
        }
        else if(c>180 && c<270){
          tr=-out_r[i10+n1]+out_im[i10+n1];
          ti=-out_im[i10+n1]-out_r[i10+n1];
        }
        else if(c>270 && c<360){
          tr=out_r[i10+n1]+out_im[i10+n1];
          ti=out_im[i10+n1]-out_r[i10+n1];
        }
        out_r[n1+i10]=out_r[n1]-tr;
        out_r[n1]=out_r[n1]+tr;
        if(out_r[n1]>15000 || out_r[n1]<-15000) check=1; 
        out_im[n1+i10]=out_im[n1]-ti;
        out_im[n1]=out_im[n1]+ti;
        if(out_im[n1]>15000 || out_im[n1]<-15000) check=1;      
        n1=n1+i10+i10;
      }       
    }

    if(check==1){                                             // scale the matrics if value higher than 15000 to prevent varible from overloading
      for(int i=0;i<Pow2[o];i++){
        out_r[i]=out_r[i]/100;
        out_im[i]=out_im[i]/100;    
      }
      check=0;  
    }           
  }

/*
for(int i=0;i<Pow2[o];i++)
{
Serial.print(out_r[i]);
Serial.print("\t");                                     // un comment to print RAW o/p    
Serial.print(out_im[i]); Serial.println("i");      
}
*/

  //---> here onward out_r contains amplitude and our_in conntains frequency (Hz)
  int fout,fm,fstp;
  float fstep;
  fstep=Frequency/N;
  fstp=fstep;
  fout=0;fm=0;

  for(int i=1;i<Pow2[o-1];i++){               // getting amplitude from compex number
    if((out_r[i]>=0) && (out_im[i]>=0)){out_r[i]=out_r[i]+out_im[i];}
    else if((out_r[i]<=0) && (out_im[i]<=0)){out_r[i]=-out_r[i]-out_im[i];}
    else if((out_r[i]>=0) && (out_im[i]<=0)){out_r[i]=out_r[i]-out_im[i];}
    else if((out_r[i]<=0) && (out_im[i]>=0)){out_r[i]=-out_r[i]+out_im[i];}
   // to find peak sum of mod of real and imaginery part are considered to increase speed
        
    out_im[i]=out_im[i-1]+fstp;
    if (fout<out_r[i]){fm=i; fout=out_r[i];}
         /*
         Serial.print(out_im[i]);Serial.print("Hz");
         Serial.print("\t");                            // un comment to print freuency bin    
         Serial.println(out_r[i]); 
          */
    freq_amp[i][0]=out_im[i];
    freq_amp[i][1]=20*out_r[i];
  }

  amplitude[0] = ( freq_amp[5][1]  +freq_amp[6][1]   +freq_amp[7][1]   +freq_amp[8][1]   );
  amplitude[1] = ( freq_amp[8][1]  +freq_amp[9][1]   +freq_amp[10][1]                    );
  amplitude[2] = ( freq_amp[10][1] +freq_amp[11][1]  +freq_amp[12][1]  +freq_amp[13][1]+freq_amp[14][1]  );
  amplitude[3] = ( freq_amp[13][1] +freq_amp[14][1]  +freq_amp[15][1]                    ); 
  amplitude[4] = ( freq_amp[16][1] +freq_amp[17][1]  +freq_amp[18][1]                    ); 
  amplitude[5] = ( freq_amp[18][1] +freq_amp[19][1]  +freq_amp[20][1]                    ); 
  amplitude[6] = ( freq_amp[21][1] +freq_amp[22][1]  +freq_amp[23][1]                    ); 
  amplitude[7] = ( freq_amp[23][1] +freq_amp[24][1]  +freq_amp[25][1]                    ); 
  amplitude[8] = ( freq_amp[26][1] +freq_amp[27][1]  +freq_amp[28][1]                    ); 
  amplitude[9] = ( freq_amp[28][1] +freq_amp[29][1]  +freq_amp[30][1]  +freq_amp[31][1]  ); 
  float fa,fb,fc;
  fa=out_r[fm-1];
  fb=out_r[fm]; 
  fc=out_r[fm+1];
  fstep=(fa*(fm-1)+fb*fm+fc*(fm+1))/(fa+fb+fc);
  return(fstep*Frequency/N);
  }

signed short calculLumiere(){
  signed short luminosite;
  luminosite=(5*pow(10,(ina219.getBusVoltage_V()-0.4)));
  return luminosite;
}

void calculDSB(){
  cpt=0;
    MaximWire::Discovery discovery = bus.Discover();
  do {
    MaximWire::Address address;
    if (discovery.FindNextDevice(address)) {
      if (address.GetModelCode() == MaximWire::DS18B20::MODEL_CODE) {
        MaximWire::DS18B20 device(address);
        temp_dsb[cpt] = device.GetTemperature<float>(bus);
        device.Update(bus);
      }
    }
    if (cpt == 1) cpt = 0;
    else cpt++;
  } while ((discovery.HaveMore())||(cpt==1)); 
}
// ----------------------

void setup() {
 // put your setup code here, to run once:
  digitalWrite(4, HIGH);

  setupLED();
  setupDHT();
  setupBalance();
  setupINA();


  delay(3000);
  Serial.begin(9600);
  Serial1.begin(9600);
  Serial.print("E5 LORAWAN TEST\r\n");
  
  setupLORA();
  
}

void loop() {

  digitalWrite(4, HIGH); //On r-allume les capteurs

  delay(1000);
  
  if (is_exist){
    
    int ret = 0;
    
    if (is_join){
      
      ret = at_send_check_response("+JOIN: Network joined", 12000, "AT+JOIN\r\n");
      
      if (ret){
        is_join = false;
        Serial.println();
        Serial.print("Network JOIN !\r\n\r\n");
      }
      
      else{
        at_send_check_response("+ID: AppEui", 1000, "AT+ID\r\n");
        Serial.println();
        Serial.print("JOIN failed!\r\n\r\n");
        delay(3000);
      }
    }
    else{
      char cmd[128];


      signed short temperatureDHT_a, humidityDHT_a;
      signed short temperatureDHT_b, humidityDHT_b;
      signed short f1, f2, f3, f4, f5, f6, f7, f8, f9, f0;
      int poids;
      signed short pourcentageBatterie;
      signed short courantINA;
      float freqFondamentale;
      signed short tempDSB_a, tempDSB_b;
      int tab[T]; // pour la FFT
      for (int i=0;i<T;i++){
        tab[i]=analogRead(A6);
        delayMicroseconds(800);
      }

                                              f0=  amplitude[0];
                                              f1=  amplitude[1];
                                              f2=  amplitude[2];
                                              f3=  amplitude[3];
                                              f4=  amplitude[4];
                                              f5=  amplitude[5];
                                              f6=  amplitude[6];
                                              f7=  amplitude[7];
                                              f8=  amplitude[8];
                                              f9=  amplitude[9];

      freqFondamentale= Q_FFT(tab,T,1250);
      temperatureDHT_a =     (dhta.readTemperature()*10 ); // +50 pour les tempratures ngatives
      temperatureDHT_a +=50*10;
      humidityDHT_a =    ( dhta.readHumidity()*10 ); 
      temperatureDHT_b =     (dhtb.readTemperature()*10 ); // +50 pour les tempratures ngatives
      temperatureDHT_b +=50*10;
      humidityDHT_b =       ( dhtb.readHumidity()*10 );
      poids =               int( calculBalance()*100 ); if(poids < 0) poids = 0;
      pourcentageBatterie = ( calculBatterie() );
      courantINA =          ( calculLumiere() );
      calculDSB();
      tempDSB_a = ((temp_dsb[0]+50)*10); // +50 pour les tempratures ngatives
      tempDSB_b = ((temp_dsb[1]+50)*10); // +50 pour les tempratures ngatives

      Serial.println("Temperature 1 : "); 
      Serial.println(temperatureDHT_a);
      Serial.println("Humidite 1 :");
      Serial.println(humidityDHT_a);
      Serial.println("Temperature 2 : "); 
      Serial.println(temperatureDHT_b);
      Serial.println("Humidite 2 : "); 
      Serial.println(humidityDHT_b);
      Serial.println("poids : ");
      Serial.println(poids);
      Serial.println("batterie : ");
      Serial.println(pourcentageBatterie);
      Serial.println("Lumiere en % : ");
      Serial.println(courantINA);
      Serial.println("Temprature DSB 1 : ");
      Serial.println(tempDSB_a);
      Serial.println("Temprature DSB 2 : ");
      Serial.println(tempDSB_b);
      Serial.println(" Amplitude 98-146Hz :");
      Serial.println(amplitude[0]);
      Serial.println(" Amplitude 146-195Hz :");
      Serial.println(amplitude[1]);
      Serial.println(" Amplitude 195-244Hz :");
      Serial.println(amplitude[2]);
      Serial.println(" Amplitude 244-293Hz :");
      Serial.println(amplitude[3]);
      Serial.println(" Amplitude 293-342Hz :");
      Serial.println(amplitude[4]);
      Serial.println(" Amplitude 342-391Hz :");
      Serial.println(amplitude[5]);
      Serial.println(" Amplitude 391-439Hz :");
      Serial.println(amplitude[6]);
      Serial.println(" Amplitude 439-488Hz :");
      Serial.println(amplitude[7]);
      Serial.println(" Amplitude 488-537Hz :");
      Serial.println(amplitude[8]);
      Serial.println(" Amplitude 537-586Hz :");
      Serial.println(amplitude[9]);
      Serial.println(" Fondamentale :");
      Serial.println(freqFondamentale);


      sprintf(cmd, "AT+MSGHEX=%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X\r\n", 
                                                temperatureDHT_a, 
                                                humidityDHT_a,
                                                temperatureDHT_b,
                                                humidityDHT_b,
                                                poids,
                                                pourcentageBatterie,
                                                courantINA,
                                                tempDSB_a,
                                                tempDSB_b,
                                                f0, f1, f2, f3, f4, f5, f6, f7, f8, f9
                                                );
      at_send_check_response("ACK Received", 5000, cmd);
      
      digitalWrite(4, LOW); //On teint les capteurs
      delay(30000); //600000 pour 10 minutes de temps-off
    }
  }
  else{delay(1000);}
    delay(2000);
}

Credits

N'KOUKA Nathan

N'KOUKA Nathan

1 project • 1 follower
Rémi Antonucci

Rémi Antonucci

1 project • 2 followers
Jacky Chen

Jacky Chen

1 project • 1 follower
Amit Patel

Amit Patel

1 project • 1 follower

Comments

Add projectSign up / Login