Youssef ChaouiMonsieur-ugurdiadjiRizlène.B
Published © GPL3+

Projet OpenRucheG2

Hive monitoring using sensors and LoraWan network.

IntermediateShowcase (no instructions)Over 1 day427
Projet OpenRucheG2

Things used in this project

Hardware components

Arduino MKRWAN1300
×1
DHT22 Temperature and Humidity Sensor
DFRobot DHT22 Temperature and Humidity Sensor
×1
Adafruit Waterproof DS18B20 Digital temperature sensor
Adafruit Waterproof DS18B20 Digital temperature sensor
×1
DHT22 Temperature and Humidity Sensor
DFRobot DHT22 Temperature and Humidity Sensor
×2
SparkFun Load Cell Amplifier - HX711
SparkFun Load Cell Amplifier - HX711
×1
ESP32 Camera Module Development Board
M5Stack ESP32 Camera Module Development Board
×1
Lipo 3.7V 1000mAh
×1
LiPo Rider Pro 106990008
×1
Arduino MKR WAN 1300
Arduino MKR WAN 1300
×1
Solar Pannel 180x80
×1
Grove amplifier (and CAN) for HX711
×1
Microphone Amplifier Breakout
Adafruit Microphone Amplifier Breakout
×1
Multiconductor Cable, Flexible
Multiconductor Cable, Flexible
(4 wires inside)
×1
Adafruit TPL5510
×1

Software apps and online services

Ubidots
Ubidots
In this project we used BEEP but Ubidots is a free and easy alternative.
The Things Stack
The Things Industries The Things Stack
Arduino IDE
Arduino IDE
KiCad
KiCad

Hand tools and fabrication machines

Solder Wire, Lead Free
Solder Wire, Lead Free
Soldering iron (generic)
Soldering iron (generic)
3D Printer (generic)
3D Printer (generic)
(optional)
Drill / Driver, Cordless
Drill / Driver, Cordless

Story

Read more

Schematics

PCB for the hive

A PCB design and schematic made using KiCAD, with a connector for every component except for the ESP32 CAM.

Code

Lora Sensors

Arduino
It contains the code necessary to collect data from all of the sensors presented in the article.
#include <MKRWAN.h>
#include "DHT.h"
#include <OneWire.h>
#include <ArduinoLowPower.h>
#include <HX711.h>
#include <arduinoFFT.h>
#include <DFRobot_B_LUX_V30B.h>
#include <DallasTemperature.h>
#define DONEPIN A3
#define DELAY A2
#define DHT22PIN1 7 //V
#define DHT22PIN2 8 //V

//#define LUMIERE A0 //V
DFRobot_B_LUX_V30B    myLux(0, 0, 1); 
#define BATTERIE A1 //pin de la batterie V
#define BUZZER 5

#define TENSIONMIN 2.4973 //tension min
#define TENSIONMAX 3.1784 //tension max

#define RXESP 13
#define TXESP 14

#define ONE_WIRE_BUS 10
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);


// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = 11;
const int LOADCELL_SCK_PIN = 12;
static int timetosleep=10;
int frequency = 600000;

//OneWire  ds(10);  // on pin 10 (a 4.7K resistor is necessary)

#define DHTTYPE DHT22
DHT dht1(DHT22PIN1, DHT22);
DHT dht2(DHT22PIN2, DHT22);
LoRaModem modem;

HX711 scale; //création de l'instance de l'objet HX11 nommé scale
String appEui = "AAAAAAAAAAAAAAAA";
String appKey = "B53BAECF2AA9B641F7840FA68292E8EA";

//String appEui = "1122334455667788";
//String appKey = "901D1126F748C4C69F9D7B0F501A366F";

bool connected;
int err_count;
short con;

//FFT
short s_bin098_146Hz = 0; //this short takes the sum of the amplitudes within this frequency span
short s_bin146_195Hz = 0; 
short s_bin195_244Hz = 0;
short s_bin244_293Hz = 0; 
short s_bin293_342Hz = 0;
short s_bin342_391Hz = 0;
short s_bin391_439Hz = 0;
short s_bin439_488Hz = 0;



  // Decoder function to convert byte array to string
  String decodeBytes(byte* bytes, int length) {
    String result = "";
    for (int i = 0; i < length; i++) {
      result += char(bytes[i]);
    }
    return result;
  }

  void scale_init(){
    scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
    scale.set_scale(30105.f); // the scale value that was found while calibrating the wheight scale

  }

  void batterie_init(){
    pinMode(BATTERIE, INPUT); //put the battery pin as input
  }

  int getWeight() {
    scale.power_up(); //leave sleep mode

    float weightFloat = scale.get_units(10)-4; //get measure
    delay(1000); //we need this delay or the waight scale sends weird values

    scale.power_down(); //enter low power mode

    int weight = (int)(100*weightFloat); // cast
    //Serial.println("weight :");
    //Serial.println(weight);

    return weight;
  }



int getLum() { 
    //Serial.print("value: ");
    //Serial.print(myLux.lightStrengthLux());
    //Serial.println(" (lux).");
}


short getBattery () // sur la pin A0
{
  float b = analogRead(BATTERIE); //valeur analogique
  b= 3.3*(b /(0.24*1023.0));
  //Serial.println("batterie :");
  //Serial.println(b*100);
  return (short)(b*100); //returns battery percentage in volts
}





//Analyse son
//fft with filtering 
const int micPin = A4;
const int sampleSize = 512; 
const double samplingFrequency = 10000;

arduinoFFT FFT = arduinoFFT();
 
double vReal[sampleSize];
double vImag[sampleSize];


const double cutoffFrequency = 50.0;
const double RC = 1.0 / (cutoffFrequency * 2 * 3.1416);
const double dt = 1.0 / samplingFrequency;
const double alpha = RC / (RC + dt);

double lastFilteredValue = 0;



 //Analyse son
  void son(){
  for (int i = 0; i < sampleSize; i++) {
      vReal[i] = analogRead(micPin);
      vImag[i] = 0;
      delayMicroseconds(1000000 / samplingFrequency);
    }

    FFT.Windowing(vReal, sampleSize, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
    FFT.Compute(vReal, vImag, sampleSize, FFT_FORWARD);
    FFT.ComplexToMagnitude(vReal, vImag, sampleSize);

    double maxAmplitude = 0;
    int maxIndex = 0;
    for (int i = 5; i < (sampleSize / 2); i++) {
      if (vReal[i] > maxAmplitude) {
        maxAmplitude = vReal[i];
        maxIndex = i;
      }
    }




    for(int i = 5; i < (sampleSize / 2); i ++){
      if (((double)i * samplingFrequency / sampleSize)*1.06667/10 >= 98 && ((double)i * samplingFrequency / sampleSize)*1.06667/10 <= 146){
        s_bin098_146Hz += vReal[i];
      }
      if (((double)i * samplingFrequency / sampleSize)*1.06667/10 >= 146 && ((double)i * samplingFrequency / sampleSize)*1.06667/10 <= 195){
        s_bin146_195Hz += vReal[i];
      }
      if (((double)i * samplingFrequency / sampleSize)*1.06667/10 >= 195 && ((double)i * samplingFrequency / sampleSize)*1.06667/10 <= 244){
        s_bin195_244Hz += vReal[i];
      }
      if (((double)i * samplingFrequency / sampleSize)*1.06667/10 >= 244 && ((double)i * samplingFrequency / sampleSize)*1.06667/10 <= 293){
        s_bin244_293Hz += vReal[i];
      }
      if (((double)i * samplingFrequency / sampleSize)*1.06667/10 >= 293 && ((double)i * samplingFrequency / sampleSize)*1.06667/10 <= 342){
        s_bin293_342Hz += vReal[i];
      }
      if (((double)i * samplingFrequency / sampleSize)*1.06667/10 >= 342 && ((double)i * samplingFrequency / sampleSize)*1.06667/10 <= 391){
        s_bin342_391Hz += vReal[i];
      }
      if (((double)i * samplingFrequency / sampleSize)*1.06667/10 >= 391 && ((double)i * samplingFrequency / sampleSize)*1.06667/10 <= 439){
        s_bin391_439Hz += vReal[i];
      }
      if (((double)i * samplingFrequency / sampleSize)*1.06667/10 >= 439 && ((double)i * samplingFrequency / sampleSize)*1.06667/10 <= 488){
        s_bin439_488Hz += vReal[i];
      }
    }



    double maxFrequency = (double)maxIndex * samplingFrequency / sampleSize;
      double frequence = maxFrequency*1.06667/10;
  }





void setup() {

  dht1.begin(); //begin comm with dht sensors
  sensors.begin(); //begin comm with dsb18x20 sensors

  
  
  modem.begin(EU868); //begin lora comm on 868MHz
  scale_init();
  
 
  delay(2000);  // apparently the murata dislike if this tempo is removed...
  connected = false;
  err_count = 0;
  con = 0;


  
    //put your setup code here, to run once:
  pinMode(BUZZER, OUTPUT); 
  digitalWrite(BUZZER, HIGH); //generate sound on buzzer to let know the system has been powered on
  delay(1000);
  digitalWrite(BUZZER,LOW); //stops
  
  pinMode(DONEPIN, OUTPUT);
  pinMode(DELAY, OUTPUT); //pins to command the TPL that powers sensors
}





void loop() {
  // active le TPL
  digitalWrite(DONEPIN,LOW);
  digitalWrite(DELAY, HIGH);// power the sensors
  modem.minPollInterval(60);
  delay(500);
  byte i;
  byte present = 0;
  byte type_s;
  byte data[9];
  byte addr[8];
  float celsius, fahrenheit;
  delay(100);
 
  for( i = 0; i < 8; i++) {
    
  }

  
  sensors.requestTemperatures(); // Send the command to get temperatures
  
  float tempA = sensors.getTempCByIndex(0); //temperature on index 0
  float tempB = sensors.getTempCByIndex(1); //temperature on index 1
  

  short temp_intA = short(10*tempA); //cast to save bits
  short temp_intB = short(10*tempB);
  
   
  short humidite = (short)(10*dht1.readHumidity()); //humidity cast to save bits and get wanted resolution
  
  short temperature = (short)10*dht1.readTemperature();
  
  short temperature2 = (short)(10*dht2.readTemperature());
  
  short humidite2 = (short)(10*dht2.readHumidity());
     

  short weight = short(getWeight() );
   
  short batterie= getBattery();

  short lumiere = getLum();

  short test = 27;

  while (!connected) { //to connect to the lora network
    
    int ret = modem.joinOTAA(appEui, appKey);
    if (ret) {
      connected = true;
      modem.minPollInterval(60);
      modem.dataRate(5);  // switch to SF7
      delay(100);         // because ... more stable
      err_count = 0;
    }
  }

  
  if (connected) { // send the data packet
    
    int err = 0;
    
    modem.beginPacket();
    modem.write(humidite);
  
    modem.write(temperature);
  
      modem.write(weight);

      modem.write(temp_intA); 

   modem.write(lumiere);

    modem.write(batterie);
 
    modem.write(s_bin098_146Hz);


    modem.write(s_bin146_195Hz);


    modem.write(s_bin195_244Hz);


    modem.write(s_bin244_293Hz);

    modem.write(s_bin293_342Hz);


    modem.write(s_bin342_391Hz);

    modem.write(s_bin391_439Hz);
 
    modem.write(s_bin439_488Hz);


    modem.write(humidite2);

    modem.write(temperature2);

    modem.write(temp_intB);


    
    err = modem.endPacket();



    s_bin098_146Hz = 0; // reset the values measured with former fft
    s_bin146_195Hz = 0; 
    s_bin195_244Hz = 0;
    s_bin244_293Hz = 0; 
    s_bin293_342Hz = 0;
    s_bin342_391Hz = 0;
    s_bin391_439Hz = 0;
    s_bin439_488Hz = 0;




    if (err <= 0) {
     
      err_count++;
      if (err_count > 50) {
        connected = false;
      }
      // wait for 2min for duty cycle with SF12 - 1.5s frame
      for (int i = 0; i < 120; i++) {
        delay(1000); //1000
      }
    } else {
      err_count = 0;
     
      // Demonstration of decodeBytes function
      byte receivedBytes[] = { 72, 101, 108, 108, 111 };  // Represents the string "Hello"
      String decodedString = decodeBytes(receivedBytes, 5);
    
    } if (!modem.available()) { // downlink code
    //Serial.println("No downlink message received at this time.");
    delay(10000);
    //return;
  }
  else{
  char rcv[64]; 
  int i = 0;
  while (modem.available()) {//downlink received
    rcv[i++] = (char)modem.read(); 
  }
  //Serial.print("Received: ");
  for (unsigned int j = 0; j < i; j++) {
    //Serial.print(rcv[j] >> 4, HEX);
    //Serial.print(rcv[j] & 0xF, HEX);
    //Serial.print(" ");
  }
  int frequency = rcv[1] | (rcv[0] << 8); //get the value from the byte vector
  //Serial.print("Frequence envoi: ");
  //Serial.println(frequency);
  }


 
 }
 
  
  //desactive le TPL
  //delay(frequency);
digitalWrite(DELAY, LOW); // cut the power on sensors
  digitalWrite(DONEPIN,HIGH);
  
  LowPower.sleep(frequency); //sleep the mkrwan 1310 for 10 minutes
  }

Uplink The Things Network

JavaScript
This code allows you to read the data send by the arduino code in the right type (short), and the right sequence.
The "key" must be changed according to your configuration.
function decodeUplink(input) {
 var data = {};

 
data.h = (input.bytes[1] << 8 | (input.bytes[0]))/10.0;
data.t_i = (input.bytes[3] << 8 | (input.bytes[2]))/10.0;
data.weight_kg = (input.bytes[5] << 8 | (input.bytes[4]))/100.0 ;
data.t_0 = (input.bytes[7]) << 8 | (input.bytes[6])/10.0;
// data.l = ((input.bytes[9]) << 8 | (input.bytes[8]))/10.0;
data.bv = ((input.bytes[11]) << 8 | (input.bytes[10]))/100.0;
data.key = "v8d1e7hghewrts33"
//data.s_bin098_146Hz = ((input.bytes[13]) << 8 | (input.bytes[12]));
//data.s_bin146_195Hz = ((input.bytes[15]) << 8 | (input.bytes[14]));
//data.s_bin195_244Hz = ((input.bytes[17]) << 8 | (input.bytes[16]));
//data.s_bin244_293Hz = ((input.bytes[19]) << 8 | (input.bytes[18]));
//data.s_bin293_342Hz = ((input.bytes[21]) << 8 | (input.bytes[20]));
//data.s_bin342_391Hz = ((input.bytes[23]) << 8 | (input.bytes[22])); 
//data.s_bin391_439Hz = ((input.bytes[25]) << 8 | (input.bytes[24]));
//data.s_bin439_488Hz = ((input.bytes[27]) << 8 | (input.bytes[26]));
//data.t_4 = ((input.bytes[29]) << 8 | (input.bytes[28]))/10.0;
//data.t_2 =  ((input.bytes[31]) << 8 | (input.bytes[30]))/10.0;
data.t_3 = ((input.bytes[33]) << 8 | (input.bytes[32]))/10.0;
 return {
 data: data,
 warnings: [],
 errors: []
 };
}

Downlink The Things Network

JavaScript
This code will allow you to change the delay between two transmission of data, which is usefull when your device is lacking in energy.
The "key" must be changed according to your configuration.
function encodeDownlink(input) {
  return {
    bytes: [],
    fPort: 1,
    warnings: [],
    errors: []
  };
}

function decodeDownlink(input) {
  return {
    data: {
       data.key = "v8d1e7hghewrts33"
        data.bytes= input.bytes 
    },
  }
}

Credits

Youssef Chaoui

Youssef Chaoui

1 project • 0 followers
Monsieur-ugur

Monsieur-ugur

1 project • 0 followers
diadji

diadji

1 project • 0 followers
Rizlène.B

Rizlène.B

1 project • 0 followers

Comments