walid bouchichitIlyes ELBAHRIYacine OuliéAdam K.
Published © GPL3+

Honey Guys - Monitoring of a bee hive

Monitoring bee hive state with data retrieval on weight, temperature, humidity, luminosity and hive buzzing frequencies through sensors.

IntermediateFull instructions providedOver 2 days524
Honey Guys - Monitoring of a bee hive

Things used in this project

Hardware components

Solar Panel 2W
×1
LiPo rider pro Power adapter
×1
Arduino Nano 33 BLE Sense
Arduino Nano 33 BLE Sense
×1
LoRa-E5:
×1
Li-Ion 3,7V 1050 mAh
×1
USB-Série RS232 3,3V
×1
groove temperature sensor DS18B20
×1
HX711 ADC
×1
DHT22 Temperature and Humidity Sensor
DFRobot DHT22 Temperature and Humidity Sensor
×1
PCBWay Custom PCB
PCBWay Custom PCB
×1
weigh bosh
×1
lapel micro
×1
female jack
×1

Software apps and online services

KiCad
KiCad
Arduino IDE
Arduino IDE
Ubidots
Ubidots
beep monitor
The Things Stack
The Things Industries The Things Stack
diagrams

Hand tools and fabrication machines

PCB Holder, Soldering Iron
PCB Holder, Soldering Iron
thermodynamic sheath
Soldering iron (generic)
Soldering iron (generic)
multiple conductor cable

Story

Read more

Custom parts and enclosures

waterproof pvc box

We have chosen to use a waterproof PVC enclosure for our project, which we have drilled to fit in the cables of our sensors. This waterproof enclosure will protect our electronic components from external elements such as moisture or dust. Additionally, the sturdy PVC material of the enclosure will also protect the system from potential impact or collision.

Schematics

wiring diagram

The wiring diagram for our bee hive monitoring system is well-organized and easy to follow. The connections between the various components are clearly labeled and the layout is logical. The color coding used also helps to make it easy to identify the different wires and connections.

Code

Main with french comment

C/C++
you can use this code and only change the pins you connected with your arduino.
Also, change the parameters for the lorawan uplink with your ttn acount parameters
#include <DHT.h>
#include <HX711.h>
#define MAXIMWIRE_EXTERNAL_PULLUP
#include <MaximWire.h>

//PIN DHT EXT
#define brocheBranchementDHT 6
#define typeDeDHT DHT22
//DHT INT
#define brocheBranchementDHTint 7

#define calibration_factor 20942.00 //This value is obtained using the SparkFun_HX711_Calibration sketch
//PINS HX711
#define LOADCELL_DOUT_PIN  D3
#define LOADCELL_SCK_PIN  D2

#define SHUTDOWN D11

//Wattmetre pour luminosité
#include <Wire.h>
#include "DFRobot_INA219.h"

//PIN température MaximWire
#define PIN_BUS 9
MaximWire::Bus bus(PIN_BUS);
MaximWire::DS18B20 device;

DHT dht(brocheBranchementDHT,typeDeDHT);
DHT dhtint(brocheBranchementDHTint,typeDeDHT);

HX711 scale;


//WattMetre
DFRobot_INA219_IIC     ina219(&Wire, INA219_I2C_ADDRESS4);
float ina219Reading_mA = 1000;
float extMeterReading_mA = 1000;

static char recv_buf[512]; 
static bool is_exist = false; 
static bool is_join = false; 
static int led = 0; 
int ret=0; 

//DHT
float tmpfl;
short tmp =20; 
short hum=50; 

//DHT int
float tmpflint;
short tmpint =20; 
short humint=50; 

//HX711
float massfl;
short mass;

//Température MaximeWire
int iTemp = 0; 
short temp = 0;
short tempM1 = 0;
short tempM2 = 0;

//Pour le pourcentage de batterie
const int analogInPin = A1;  // Analog input pin that the potentiometer is attached to
short sensorValue = 0;        // value read from the pot

//Pour le WattMetre
float voltage = 0;
float current = 0;
float power = 0;
short luminosity =0;

//micro
#define T 64
int freq_amp[32][2];
short Amp[10];
int data[64]={14, 30, 35, 34, 34, 40, 46, 45, 30, 4,  -26,  -48,  -55,  -49,  -37,
-28,  -24,  -22,  -13,  6,  32, 55, 65, 57, 38, 17, 1,  -6, -11,  -19,  -34, 
-51,  -61,  -56,  -35,  -7, 18, 32, 35, 34, 35, 41, 46, 43, 26, -2, -31,  -50,
-55,  -47,  -35,  -27,  -24,  -21,  -10,  11, 37, 58, 64, 55, 34, 13, -1, -7};
//fin micro

//downlink
int freqEnvoi = 600000;
char* down;
int down_int;
char* downlink;

void freq_envoi(){

  downlink= strstr(recv_buf,"\"");
  down = strtok(downlink,"\"");
  down_int = strtol(down,NULL,16);
  if(down_int>0 && down_int < 31){
        freqEnvoi = down_int*60000;
        //Serial.println("freq envoyé=");   
        //Serial.println(freqEnvoi);
        delay(freqEnvoi);
      }
      else{
        //Serial.println("freq envoyé du else =");
        //Serial.println(freqEnvoi);
        delay(freqEnvoi);
      }
}

void allume_led() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(5000); 
  digitalWrite(LED_BUILTIN, LOW);
}

void DHT1(){
    // Serial.print("\n ");      
    hum = dht.readHumidity();
    tmpfl = dht.readTemperature()+100;
    tmp = short(tmpfl*100-40);
     //Serial.print("Humidité = "); Serial.print(hum); Serial.println(" %");
     //Serial.print("Température = "); Serial.print(tmpfl); Serial.println(" °C");
     //Serial.print("TempératureShort = "); Serial.print(tmp); Serial.println(" °C");
}

void DHT2(){
    // Serial.print("\n ");      
    humint = dhtint.readHumidity();
    tmpflint = dhtint.readTemperature()+100;
    tmpint = short(tmpflint*100+80);
    // Serial.print("Humidité Intérieur = "); Serial.print(humint); Serial.println(" %");
    // Serial.print("Température Intérieur = "); Serial.print(tmpflint); Serial.println(" °C");
}

void MaximeWireTemp(){

   MaximWire::Discovery discovery = bus.Discover();
    do {
        MaximWire::Address address;
        if (discovery.FindNextDevice(address)) {
            // Serial.print("FOUND: ");
            // Serial.print(address.ToString());
            if (address.IsValid()) {
                // Serial.print(" (VALID)");
            } else {
                // Serial.print(" (INVALID)");
            }
            if (address.GetModelCode() == MaximWire::DS18B20::MODEL_CODE) {
                // Serial.print(" (DS18B20)");
                MaximWire::DS18B20 device(address);
                if (device.IsParasitePowered(bus)) {
                    // Serial.print(" (PARASITE POWER)");
                }
                float tempfl = device.GetTemperature<float>(bus);
                temp = short((100+tempfl)*100);
          
                if (iTemp==0){
                    tempM1= short(float(temp+100)+80) ;//* 0.0669;
                    //Serial.print(" temp1=");
                     //Serial.print(tempM1);
                    //Serial.print(" °C");
                    //Serial.println();                  
                }
                else{
                    tempM2= temp ;//* 0.06425;
                    //Serial.print(" temp2=");
                    //Serial.print(tempM2);
                    //Serial.print(" °C");
                    //Serial.println();                  
                }
                iTemp = ~iTemp;

                device.Update(bus);
            } else {
                // Serial.println();
            }
        } else {
            // Serial.println("NOTHING FOUND");
        }
    } while (discovery.HaveMore());
}

void Wattmetre(){


    voltage = ina219.getBusVoltage_V();
    current = ina219.getCurrent_mA();
    power = ina219.getPower_mW();
    luminosity = 5*pow(10,(ina219.getBusVoltage_V()-0.4));

    // Serial.print("BusVoltage:   "); Serial.print(ina219.getBusVoltage_V(), 2); Serial.println("V");
    // Serial.print("ShuntVoltage: "); Serial.print(ina219.getShuntVoltage_mV(), 3); Serial.println("mV");
    // Serial.print("Current:      "); Serial.print(ina219.getCurrent_mA(), 1); Serial.println("mA");
    // Serial.print("Power:        "); Serial.print(ina219.getPower_mW(), 1); Serial.println("mW"); Serial.println("");
    // Serial.print("lum = "); Serial.print(luminosity); Serial.print("\n"); 
}

void calibreWattmetre(){
  // Serial.println();
  //Initialize the sensor
  //while(ina219.begin() != true) {
  //  Serial.println("INA219 begin faild");
  //  delay(2000);
  //}
  //Linear calibration
  ina219.begin();
  ina219.linearCalibrate(/*The measured current before calibration*/ina219Reading_mA, /*The current measured by other current testers*/extMeterReading_mA);

}
void bat(){
      int bat_in = 0;
      bat_in = analogRead(analogInPin);
      float bat = 100*(bat_in-469);
      bat=bat/187;
      // Serial.print(analogRead(analogInPin));
      // Serial.print("\n");
      sensorValue = short(bat);
}
void HX711(){
    scale.power_up();
    // Serial.print("\n ");      
    massfl = scale.get_units()-38.77;//scale.get_units() returns a float
    mass = short(massfl*100);
    if(massfl<=1){mass=0;}
    // Serial.print(massfl, 2); 
    // Serial.println(" kg"); //You can change this to kg but you'll need to refactor the calibration_factor
    scale.power_down();
}

void calibreHX711(){
  // Serial.println("HX711 scale demo"); 
  scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
  // Serial.println("DOUT et SCK OK"); 
  scale.set_scale(calibration_factor); //This value is obtained by using the SparkFun_HX711_Calibration sketch
  //scale.tare(); //Assuming there is no weight on the scale at start up, reset the scale to 0
  // Serial.println("Calibrage OK"); 
}

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 setup() {
  digitalWrite(SHUTDOWN, HIGH);  
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_PWR, LOW);
  allume_led();
 // put your setup code here, to run once: 
  dht.begin();
  dhtint.begin();
  //Serial.begin(9600); 
  Serial1.begin(9600); 
  // Serial.print("Serial1 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: EU868", 1000, "AT+DR=EU868\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,\"YOUR TTN KEY\"\r\n"); 
  at_send_check_response("+KEY: DEVEUI", 1000, "AT+ID=DEVEUI,\"YOUR TTN ID \"\r\n"); 
  at_send_check_response("+KEY: 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: 8", 1000, "AT+PORT=8\r\n"); 
  delay(200); 
  is_join = true;   
  }
  else { 
    is_exist = false; 
    // Serial.print("No Serial1 module found.\r\n");
  }

  //Capteur de poids
  calibreHX711();

  //WattMetre
  calibreWattmetre();

  // Serial.println("Readings:");
}

void loop() { 
  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(5000); 
      } 
    } 
    else { //capteurs et envoie ubidots
      // Serial.print("Reading: ");

      //Capteur de poids
      HX711();

      //Capteur humidité et température DHT
      DHT1();
      DHT2();

      //Capteurs de température DS18B20 MaximWire
      // Serial.print("\n ");      
      MaximeWireTemp();    
      
      //Récupération de la tension délivrée par la batterie pour pourcentage
      // Serial.print("\n ");
      
      //sensorValue = static_cast<short>(100*analogRead(analogInPin)/630 - 3);
      bat();

      // Serial.print("sensor = "); // Serial.print(sensorValue); // Serial.print("%\n");

      //Recuperations des informations du wattmetre
      // Serial.print("\n ");  
      Wattmetre();

      //micro 
      int tab[T]; 
      for (int i=0;i<T;i++){
        tab[i]=analogRead(A0);
        delayMicroseconds(800);    
      }
      int working = Q_FFT(tab,T,1250);
  
      //Communication avec ubidots

      char cmd[128]; 
      sprintf(cmd, "AT+MSGHEX=%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X%04X\r\n", tmpint, humint*100, mass, sensorValue, tempM1, 
                                                        tempM2, tmp, Amp[0],Amp[1],Amp[2],Amp[3],Amp[4],Amp[5],Amp[6],Amp[7],Amp[8],Amp[9], luminosity); 
      at_send_check_response("ACK Received", 5000, cmd); 
      freq_envoi();
      //delay(2000);
    } 
  } 
  else { 
    delay(1000); 
  } 
} 
///////////////////////////////////////////////////////------------------        FFT         -----------------//////////////////////////////////////////////////////////////////


int 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;  
                }           

     }




//---> 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];}
         freq_amp[i][0]=out_im[i];
         freq_amp[i][1]=40*out_r[i];
        }
Amp[0] = (freq_amp[5][1]+freq_amp[6][1]+freq_amp[7][1]+freq_amp[8][1])/4;
Amp[1] = (freq_amp[8][1]+freq_amp[9][1]+freq_amp[10][1])/3;
Amp[2] = (freq_amp[10][1]+freq_amp[11][1]+freq_amp[12][1]+freq_amp[13][1])/4;//247hz = 13
Amp[3] = (freq_amp[13][1]+freq_amp[14][1]+freq_amp[15][1])/3; // 15 = 285hz
Amp[4] = (freq_amp[16][1]+freq_amp[17][1]+freq_amp[18][1])/3; // 18 = 342hz
Amp[5] = (freq_amp[18][1]+freq_amp[19][1]+freq_amp[20][1])/3; // 20 = 380 hz
Amp[6] = (freq_amp[21][1]+freq_amp[22][1]+freq_amp[23][1])/3; // 23 = 437 hz
Amp[7] = (freq_amp[23][1]+freq_amp[24][1]+freq_amp[25][1])/3; // 25 = 475 hz
Amp[8] = (freq_amp[26][1]+freq_amp[27][1]+freq_amp[28][1])/3; // 28 = 532 hz
Amp[9] = (freq_amp[28][1]+freq_amp[29][1]+freq_amp[30][1]+freq_amp[31][1])/4; // 31 = 589 hz

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);
float ff = (fstep*Frequency/N);
if (ff<=1) {return 0;}
else{ return 1;}
}

Credits

walid bouchichit

walid bouchichit

1 project • 2 followers
Ilyes ELBAHRI

Ilyes ELBAHRI

1 project • 2 followers
Yacine Oulié

Yacine Oulié

1 project • 3 followers
Adam K.

Adam K.

1 project • 3 followers

Comments