Story
Introduction
In France there is about 1 million beehives.
The objective is to monitor the gain/loss in beehive weight for:
- bee health,
- honey production,
- swarming bees
- winter provision control
- diseases
- pesticides influence
- beehive stealing,...
Mindmap
![](https://cdn.hackaday.io/images/8835441666115927767.jpg)
Acquisition system
- Weight measurement: deformation gauge glued to an aluminium bar mounted in flexion. Half bridge wired for avoiding temperature variaiton. Measurement sensitivity is about 10g. Signal numerization done using HX711 module (analog to digital converter 24bits)
- Temperature measurement: 2 sensors: one insid the beehive, the other outside. Measurement using OneWire DS18S20 (±0.5°C accuracy, range is from -10°C to +85°C) One can monitor the bee brood presence or not.
Remarks: Bee weight is between 60 to 80 mg, so 1g = 14 bees approximately. The average honey consumption during winter (in center of France) is from 12 to 15 kg.
Prerequisites
- the box must be waterproof, because it will be outside during all day and night for a long time period.
- the electrical power supply is a key parameter, it has to be autonomous for a long time period (one year), among solutions we can have solar panel or sufficient battery power (and optimized consumption).
- the data transfer to end-user, must be wireless and accessible in non internet connected regions, low cost and allow data transfer at regular interval (for example every 2 hours)
Possible additional measurements
- GPS position of beehive,
- Sun light
- Rain
Global costs,
- Estimated to about 100€
http://stephane.gouttebroze.free.fr/gruche/gruche.html
Recording examples:
![](https://cdn.hackaday.io/images/6475571661948268356.jpg)
Internal and external temperature can be monitored,
Example herefater show bee brood temperature (around 35°C) as constant even if external temperature is varying.
![](https://cdn.hackaday.io/images/2692441661948028542.jpg)
Additional measurement is beehive internal humidity using DHT22 sensor.
All the datas have to be sent to network using Sigfox facility for example.
![](https://cdn.hackaday.io/images/4587791661948164656.jpg)
Schematics
![](https://cdn.hackaday.io/images/7332901666110564599.jpg)
Code example. (see files for additional versions)
//*******************************************
//
// Systme eruche installe au Joug
//
// S.GOUTTEBROZE (c) 01.2017
//*******************************************
#include "HX711.h"
#include <OneWire.h>
#include <DHT.h>;
//Constants
#define DHTPIN 4 // what pin we're connected to = D2
#define DHTTYPE DHT22 // DHT 22 (AM2302)
DHT dht(DHTPIN, DHTTYPE); //// Initialize DHT sensor for normal 16mhz Arduino
// DS18S20 Temperature chip i/o
OneWire ds(2); // on pin 4
//Variables
int chk,cpt;
float hum; //Stores humidity value
float temp; //Stores temperature value
// the setup function runs once when you press reset or power the board
unsigned long Weight = 0;
unsigned long AverageWeight = 0;
unsigned long AverageWeightot = 0;
unsigned long AverageWeightold = 0;
int ini(0);
int Clock = 7; //3 on board
int Dout = 6; //2 on board
float poidsD(0);
float Tc_100_A,Tc_100_B;
byte i;
byte type_s;
byte present = 0;
byte data[12];
byte addr[8];
char *msg ;
void lire_scaleD() {
//Serial.println("Lire D...");
// wait for the chip to become ready
while (digitalRead(Dout) == HIGH);
AverageWeight = 0;
for (char j = 0; j<100; j++)
{
Weight =0;
// pulse the clock pin 24 times to read the data
for (char i = 0; i<24; i++)
{
digitalWrite(Clock, HIGH);
delayMicroseconds(2);
Weight = Weight <<1;
if (digitalRead(Dout)==HIGH) Weight++;
digitalWrite(Clock, LOW);
}
// set the channel and the gain factor (A 128) for the next reading using the clock pin (one pulse)
digitalWrite(Clock, HIGH);
Weight = Weight ^ 0x800000;
digitalWrite(Clock, LOW);
AverageWeight += Weight;
delayMicroseconds(60);
}
AverageWeight = AverageWeight/100;
//Serial.print("PoidsDnew=");
//Serial.println(AverageWeight);
}
void setup() {
Serial.begin(9600);
//intialize HX711 "Module 4" SCALE D
pinMode(Clock, OUTPUT); // initialize digital pin 4 as an output.(clock)
digitalWrite(Clock, HIGH);
delayMicroseconds(100); //be sure to go into sleep mode if > 60s
digitalWrite(Clock, LOW); //exit sleep mode*/
pinMode(Dout, INPUT); // initialize digital pin 5 as an input.(data Out)
dht.begin();
Serial.println("ready");
ini=1;
// Initialisation...
lire_scaleD();
//poidsD=AverageWeight*0.8774529-7360044.76;
//Serial.println(poidsD);
}
void loop() {
// Pour les tests sans Bluetooth,
lecture_data();
envoi_msg();
// Pause entre 2mesures...
delay(3000);
delay(1000);
// pour 10secondes de dlai
delay(20000);
// on ajoute 20sec
delay(90054);
// on ajoute 90sec --> lecture toutes les 2min
delay(3000); // ajustement pour atteindre 2min
delay(500);
}
void lecture_data() {
//Serial.println("Loop Readings:...");
// Temperature #A capteur interne boitier
ds.reset();
addr[0]=16;
addr[1]=71;
addr[2]=193;
addr[3]=37;
addr[4]=1;
addr[5]=8;
addr[6]=0;
addr[7]=200;
// the first ROM byte indicates which chip
switch (addr[0]) {
case 0x10:
//Serial.println(" Chip = DS18S20"); // or old DS1820
type_s = 1;
break;
case 0x28:
//Serial.println(" Chip = DS18B20");
type_s = 0;
break;
case 0x22:
//Serial.println(" Chip = DS1822");
type_s = 0;
break;
default:
Serial.println("Device is not a DS18x20 family device.");
return;
}
ds.select(addr);
ds.write(0x44, 1); // start conversion, with parasite power on at the end
delay(1000); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
}
// Convert the data to actual temperature
// because the result is a 16 bit signed integer, it should
// be stored to an "int16_t" type, which is always 16 bits
// even when compiled on a 32 bit processor.
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// "count remain" gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x60);
// at lower res, the low bits are undefined, so let's zero them
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
//// default is 12 bit resolution, 750 ms conversion time
}
Tc_100_A = (float)raw / 16.0;
// Temperature #B capteur volant
ds.reset();
addr[0]=16;
addr[1]=228;
addr[2]=224;
addr[3]=37;
addr[4]=1;
addr[5]=8;
addr[6]=0;
addr[7]=248;
// the first ROM byte indicates which chip
switch (addr[0]) {
case 0x10:
//Serial.println(" Chip = DS18S20"); // or old DS1820
type_s = 1;
break;
case 0x28:
//Serial.println(" Chip = DS18B20");
type_s = 0;
break;
case 0x22:
//Serial.println(" Chip = DS1822");
type_s = 0;
break;
default:
Serial.println("Device is not a DS18x20 family device.");
return;
}
ds.select(addr);
ds.write(0x44, 1); // start conversion, with parasite power on at the end
delay(1000); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
}
// Convert the data to actual temperature
// because the result is a 16 bit signed integer, it should
// be stored to an "int16_t" type, which is always 16 bits
// even when compiled on a 32 bit processor.
raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// "count remain" gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x60);
// at lower res, the low bits are undefined, so let's zero them
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
//// default is 12 bit resolution, 750 ms conversion time
}
Tc_100_B = (float)raw / 16.0;
// Lecture du quatrime module connect sur Digital PIN
//Serial.print("PoidsD_old=");
//Serial.println(AverageWeightold);
lire_scaleD();
//Serial.print("PoidsDnew=");
//Serial.println(AverageWeight);
while (AverageWeightold-AverageWeight>5) {
lire_scaleD();
if (ini==1) {
AverageWeightold=AverageWeight;
ini=0;
}
AverageWeightold=AverageWeight;
//Serial.print(".");
}
AverageWeightold=AverageWeight;
poidsD=AverageWeight*4.6645331632-4605.0-39148787.5+16000.0; // capteur de 200kg
//Read data and store it to variables hum and temp from DHT22 on pin #D2
hum = dht.readHumidity();
temp= dht.readTemperature();
}
void envoi_msg() {
//Serial.println("envoi ok ");
char str_tempa[10];
dtostrf(Tc_100_A, 4, 2, str_tempa);
char str_tempb[10];
dtostrf(Tc_100_B, 4, 2, str_tempb);
char str_poids[20];
dtostrf(poidsD, 4, 2, str_poids);
char str_tempc[10];
dtostrf(temp, 4, 2, str_tempc);
char str_hum[10];
dtostrf(hum, 4, 2, str_hum);
char message[100];
sprintf(message, ";GRJ;%s;%s;%s;%s;%s;0.0", str_tempa,str_tempb,str_tempc,str_hum,str_poids);
Serial.println(message);
}