Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Sumit Kumar
Published © MIT

SIGFY (Sigfox Farm Yield) with Crop and Health Monitoring

Experiment with the plants and choose what's best for your plants. Keep track of plant growth. Real-time crop rates and emergency alerts.

IntermediateFull instructions provided2 days12,781

Things used in this project

Hardware components

Arduino MKR Fox 1200
Arduino MKR Fox 1200
×1
0.96" OLED 64x128 Display Module
ElectroPeak 0.96" OLED 64x128 Display Module
×1
Gravity: Analog Gas Sensor (MQ2) For Arduino
DFRobot Gravity: Analog Gas Sensor (MQ2) For Arduino
×1
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic sensors work by emitting sound waves at a frequency too high for humans to hear. They then wait for the sound to be reflected back, calculating distance based on the time required. This is similar to how radar measures the time it takes a radio wave to return after hitting an object.
×1
LDR, 5 Mohm
LDR, 5 Mohm
×1
SparkFun Soil Moisture Sensor (with Screw Terminals)
SparkFun Soil Moisture Sensor (with Screw Terminals)
×1
KY-039 heartbeat sensor
×1
Loudness Sensor
Seeed Studio Loudness Sensor
×1
9V battery (generic)
9V battery (generic)
×1
Battery Holder, AAA x 3
Battery Holder, AAA x 3
×1
Micro-USB to USB Cable (Generic)
Micro-USB to USB Cable (Generic)
×1
Antenna, Cellular/Wifi
Antenna, Cellular/Wifi
×1

Software apps and online services

Sigfox
Sigfox
Arduino IDE
Arduino IDE
The Things Stack
The Things Industries The Things Stack
Firebase
Google Firebase

Hand tools and fabrication machines

Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
Tape, Double Sided
Tape, Double Sided
Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

plantcare_7yVFtSWDJb.jpg

sound-anlysis_tcct1s0dQ8.png

farmer_health_gUYefG7hyN.jpg

SigFy v1.0

First device very efficient for farmers

SigFy v2.0

First device to easily recognize audio frequency and detect pest, good insects or heavy tools also notify in case of fire

Code

MQ2 Gas detector

Arduino
To calculate the concentration of gas in ppm
#include "Arduino.h"

class GasConcentration
{
    int MQ_PIN,                                //define which analog input channel you are going to use
        RL_VALUE = 5;                          //define the load resistance on the board, in kilo ohms
    float RO_CLEAN_AIR_FACTOR = 9.83;          //RO_CLEAR_AIR_FACTOR=(Sensor resistance in clean air)/RO,
    //which is derived from the chart in datasheet

    /***********************Software Related Macros************************************/
    int CALIBARAION_SAMPLE_TIMES = 50,                  //define how many samples you are going to take in the calibration phase
        CALIBRATION_SAMPLE_INTERVAL = 500,             //define the time interal(in milisecond) between each samples
        READ_SAMPLE_INTERVAL = 50,                      //define how many samples you are going to take in normal operation
        READ_SAMPLE_TIMES = 5;                          //define the time interal(in milisecond) between each samples in
    //normal operation

    /**********************Application Related Macros**********************************/
    const int  GAS_CO  = 1;
    const int  GAS_SMOKE = 2;

    /*****************************Globals***********************************************/
    float           MethaneCurve[3]  =  {2.3, 0.21, -0.47}; //two points are taken from the curve.
    //with these two points, a line is formed which is "approximately equivalent"
    //to the original curve.
    //data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59)
    float           COCurve[3]  =  {2.3, 0.72, -0.34};  //two points are taken from the curve.
    //with these two points, a line is formed which is "approximately equivalent"
    //to the original curve.
    //data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000,  0.15)
    float           SmokeCurve[3] = {2.3, 0.53, -0.44}; //two points are taken from the curve.
    //with these two points, a line is formed which is "approximately equivalent"
    //to the original curve.
    //data format:{ x, y, slope}; point1: (lg200, 0.53), point2: (lg10000,  -0.22)
    float           Ro           =  10;                 //Ro is initialized to 10 kilo ohms



  public: GasConcentration(byte gasPin)
    {
      MQ_PIN = gasPin;
      Ro = MQCalibration(MQ_PIN);                         //Calibrating the sensor. Please make sure the sensor is in clean air
      delay(3000);
    }
  private : float MQCalibration(int mq_pin)
    {
      int i;
      float val = 0;

      for (i = 0; i < CALIBARAION_SAMPLE_TIMES; i++) {      //take multiple samples
        val += MQResistanceCalculation(analogRead(mq_pin));
        delay(CALIBRATION_SAMPLE_INTERVAL);
      }
      val = val / CALIBARAION_SAMPLE_TIMES;                 //calculate the average value
      val = val / RO_CLEAN_AIR_FACTOR;                      //divided by RO_CLEAN_AIR_FACTOR yields the Ro
      return val;                                           //according to the chart in the datasheet
    }
  private : float MQResistanceCalculation(int raw_adc)
    {
      return ( ((float)RL_VALUE * (1023 - raw_adc) / raw_adc));
    }
    float MQRead(int mq_pin)
    {
      int i;
      float rs = 0;

      for (i = 0; i < READ_SAMPLE_TIMES; i++) {
        rs += MQResistanceCalculation(analogRead(mq_pin));
        delay(READ_SAMPLE_INTERVAL);
      }

      rs = rs / READ_SAMPLE_TIMES;

      return rs;
    }
  private : long MQGetGasPercentage(float rs_ro_ratio, int gas_id)
    {
      if ( gas_id == GAS_CO )
      {
        return MQGetPercentage(rs_ro_ratio, COCurve);
      }
      else if ( gas_id == GAS_SMOKE )
      {
        return MQGetPercentage(rs_ro_ratio, SmokeCurve);
      }

      return 0;
    }
  private : long  MQGetPercentage(float rs_ro_ratio, float *pcurve)
    {
      return (pow(10, ( ((log(rs_ro_ratio) - pcurve[1]) / pcurve[2]) + pcurve[0])));
    }
  public : long COgasMeasure()
    {
      long iPPM_CO = 0;
      iPPM_CO = MQGetGasPercentage(MQRead(MQ_PIN) / Ro, GAS_CO);
      return iPPM_CO;
    }
  public : long SmokeMeasure()
    {
      long iPPM_Smoke = 0;
      iPPM_Smoke = MQGetGasPercentage(MQRead(MQ_PIN) / Ro, GAS_SMOKE);
      return iPPM_Smoke;
    }

};

Driver Arduino progam

Arduino
/****************************************************************************************************************************************************************\
  Date created: 29 October
  Author: Sumit
  Sigfox
  \****************************************************************************************************************************************************************/

#include <SigFox.h>
#include <ArduinoLowPower.h>
#include "LightMoisture.cpp"
#include "RGBIndicator.cpp"
#include "PulseRate.cpp"
#include "PlantHeight.cpp"
#include "GasConcentration.cpp"
#include <DHT.h>
#include <DHT_U.h>


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define DHTPIN 2     // Digital pin connected to the DHT sensor
#define DHTTYPE DHT11   // DHT 11

DHT dht(DHTPIN, DHTTYPE);
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

#define  testSet 10
//creating and initializing class objects
LightMoisture sense(A1, A3);
RGBIndicator rgb(3, 2, 4);
PulseRate pulse(A4);
PlantHeight height(1,2);
GasConcentration gasLevel(A2);
// 'SigFox Logo', 128x64px
const unsigned char myBitmap [] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x01, 0xf8, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x03, 0xfe, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x03, 0xff, 0x80, 0x00, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x03, 0xff, 0xe0, 0x00, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x01, 0xff, 0xf0, 0x03, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x01, 0xff, 0xf8, 0x07, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x01, 0xff, 0xfc, 0x0f, 0xff, 0xe0, 0x00, 0x1e, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0xff, 0xff, 0x1f, 0xff, 0xe0, 0x00, 0x1e, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0xff, 0xff, 0xbf, 0xff, 0xc0, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x80, 0x0f, 0x8c, 0x1f, 0x8f, 0xc7, 0xc7, 0x8e, 0x00, 0x00,
  0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x1f, 0x8c, 0x7f, 0x8f, 0xcf, 0xf3, 0x9c, 0x00, 0x00,
  0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x00, 0x38, 0x8c, 0x71, 0x8f, 0xde, 0x71, 0xdc, 0x00, 0x00,
  0x00, 0x00, 0x1f, 0xff, 0xff, 0xfe, 0x00, 0x38, 0x0c, 0xe1, 0x8e, 0x1c, 0x38, 0xf8, 0x00, 0x00,
  0x00, 0x00, 0x0f, 0xff, 0xff, 0xfc, 0x00, 0x1f, 0x0c, 0xe1, 0x8e, 0x1c, 0x38, 0xf0, 0x00, 0x00,
  0x00, 0x00, 0x07, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0x8c, 0xe1, 0x8e, 0x1c, 0x38, 0x70, 0x00, 0x00,
  0x00, 0x00, 0x03, 0xff, 0xff, 0xf8, 0x00, 0x03, 0xcc, 0xe1, 0x8e, 0x1c, 0x38, 0xf8, 0x00, 0x00,
  0x00, 0x00, 0x01, 0xff, 0xff, 0xf0, 0x00, 0x01, 0xcc, 0x7f, 0x8e, 0x1c, 0x71, 0xf8, 0x00, 0x00,
  0x00, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xcc, 0x3f, 0x8e, 0x0f, 0xf3, 0x9c, 0x00, 0x00,
  0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x3f, 0x8c, 0x09, 0x8e, 0x07, 0xe3, 0x8e, 0x00, 0x00,
  0x00, 0x00, 0x01, 0xff, 0xff, 0xe0, 0x00, 0x04, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x01, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x7f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x03, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x03, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x07, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x07, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x07, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x07, 0xff, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x07, 0xfe, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x07, 0xf8, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x03, 0xc0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

byte PIR = 3;
byte Heartbeat = A4;
int debug = true;
volatile int user = 0;
volatile int motion = 0;
String s;
int t, h, dp, hi;

struct SigfoxPlantData
{
  String plantHeight;            // 2 bytes , ideal for small garden plants
  String moisture;              // 2 bytes
  String heartBeat;            //  3 bytes
  String gas;                  // 3 bytes between 0-999 ppm
};
struct SigfoxAreaData
{
  String dewPoint;               // 2 bytes
  String heatIndex;              // 2 bytes
  String temperature;           // 2 bytes
  String humidity;              // 2 bytes
  String light;                 // 2 bytes

};
SigfoxPlantData pdata;
SigfoxAreaData data;

void setup()
{
  Serial.begin(9600);
    if (!SigFox.begin()) {
    // Something is really wrong, try rebooting
    // Reboot is useful if we are powering the board using an unreliable power source
    // (eg. solar panels or other energy harvesting methods)
    reboot();
  }
   if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
 /** LowPower.attachInterruptWakeup(PIR, motionDetect, RISING);
  LowPower.attachInterruptWakeup(Heartbeat, detectRise, RISING);**/ // This feature is requires uplink but I was facing some issues with SDR dongle 
  // I need time to implement this feature
  dht.begin();
  display.clearDisplay(); //for Clearing the display
  display.drawBitmap(0, 0, myBitmap, 128, 64, WHITE); // display.drawBitmap(x position, y position, bitmap data, bitmap width, bitmap height, color) draw logo
  display.display();
  SigFox.end();
   delay(2000);
}
void reboot()
{
  NVIC_SystemReset();
  while (1);
}

String parsePlantData()
{
  pdata.plantHeight = height.relativHeight();
  pdata.moisture = sense.moistureValue();
  pdata.heartBeat = pulse.measurePulse();
  pdata.gas = gasLevel.COgasMeasure();

  if (pdata.moisture.length() < 2)
    pdata.moisture = 0 + pdata.moisture;
  if (pdata.plantHeight.length() < 2)
    pdata.plantHeight = 0 + pdata.plantHeight;
  if (pdata.heartBeat.length() < 2)
    pdata.heartBeat = "00";           // heartBeat cannot be in a single digit, it means that there is no user;
  if (pdata.gas.length() == 2)
    pdata.gas = "0" + pdata.gas;
  if (pdata.gas.length() < 2)
    pdata.gas = "00" + pdata.gas;

  String str =  "PD" + pdata.moisture + pdata.plantHeight + pdata.heartBeat + pdata.gas ;
  int l = str.length();

  return str;
}
String parseEnvironmentData()
{
  checkTemperature();
  data.dewPoint = dp;
  data.temperature = t;
  data.humidity = h;
  data.light = sense.lightIntensity();
  data.heatIndex = hi;

  if (data.dewPoint.length() < 2)
    data.dewPoint = 0 + data.dewPoint;
  if (data.temperature.length() < 2)
    data.temperature = 0 + data.temperature;
  if (data.humidity.length() < 2)
    data.humidity = 0 + data.humidity;
  if (data.light.length() < 2)
    data.light = 0 + data.light;
  if (data.heatIndex.length() < 2)
    data.heatIndex = 0 + data.heatIndex;
  String str = "SD" + data.dewPoint + data.temperature +  data.humidity +  data.light +  data.heatIndex;
  return str;
}
void loop()
{
 sendString(parseEnvironmentData());
 LowPower.sleep(10 * 60 * 1000);                       // going to sleep for 10 minutes
 sendString(parsePlantData());
 LowPower.sleep(10 * 60 * 1000);                       // going to sleep for 10 minutes
}
void sendString(String str)
{
  // Start the module
  SigFox.begin();
  // Wait at least 30mS after first configuration (100mS before)
  delay(100);
  // Clears all pending interrupts
  SigFox.status();
  delay(1);

  SigFox.beginPacket();
  SigFox.print(str);

  int ret = SigFox.endPacket();  // send buffer to SIGFOX network
  if (ret > 0) {
    Serial.println("No transmission");
  } else {
    Serial.println("Transmission ok");
  }

  Serial.println(SigFox.status(SIGFOX));
  Serial.println(SigFox.status(ATMEL));
  SigFox.end();
}


/**void motionDetect()
{
  motion = 1;
}
void detectRise()
{
  user = 1;
}**/

void checkTemperature()
{
  // Wait a few seconds between measurements.
  delay(2000);

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  h = (int) dht.readHumidity();
  // Read temperature as Celsius (the default)
  t = (int) dht.readTemperature();

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) )
  {
    Serial.println(F("Failed to read from DHT sensor!"));
    checkTemperature();
  }
  dp = (int) dewPoint(t, h)  ;
  // Compute heat index in Celsius (isFahreheit = false)
  hi = (int)dht.computeHeatIndex(t, h, false);


}

double dewPoint(double celsius, double humidity)
{
  // (1) Saturation Vapor Pressure = ESGG(T)
  double RATIO = 373.15 / (273.15 + celsius);
  double RHS = -7.90298 * (RATIO - 1);
  RHS += 5.02808 * log10(RATIO);
  RHS += -1.3816e-7 * (pow(10, (11.344 * (1 - 1 / RATIO ))) - 1) ;
  RHS += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ;
  RHS += log10(1013.246);

  // factor -3 is to adjust units - Vapor Pressure SVP * humidity
  double VP = pow(10, RHS - 3) * humidity;

  // (2) DEWPOINT = F(Vapor Pressure)
  double T = log(VP / 0.61078); // temp var
  return (241.88 * T) / (17.558 - T);
}

Heart Beat sensing

Arduino
To record the heart beat of the user
#include "Arduino.h"

class PulseRate
{
  public:
    const byte rise_threshold = 4, samp_siz = 4;
    byte  _Sensor;

  public : PulseRate(byte sensorPin)
    {
      _Sensor = sensorPin;
      pinMode(_Sensor, INPUT);
    }

  public : int measurePulse()
    {
      int readingTime = 10000;
      int startTime = millis();
      float reads[samp_siz], sum;
      long int now, ptr;
      float last, reader, start;
      float first, second, third, before, print_value;
      bool rising;
      int rise_count;
      int n;
      long int last_beat;

      do
      {
        for (int i = 0; i < samp_siz; i++)
          reads[i] = 0;
        sum = 0;
        ptr = 0;

        while (1)
        {
          // calculate an average of the sensor
          // during a 20 ms period (this will eliminate
          // the 50 Hz noise caused by electric light
          n = 0;
          start = millis();
          reader = 0.;
          do
          {
            reader += analogRead (_Sensor);
            n++;
            now = millis();
          }
          while (now < start + 20);
          reader /= n;  // we got an average

          // Add the newest measurement to an array
          // and subtract the oldest measurement from the array
          // to maintain a sum of last measurements
          sum -= reads[ptr];
          sum += reader;
          reads[ptr] = reader;
          last = sum / samp_siz;
          // now last holds the average of the values in the array
          // check for a rising curve (= a heart beat)
          if (last > before)
          {
            rise_count++;
            if (!rising && rise_count > rise_threshold)
            {
              // Ok, we have detected a rising curve, which implies a heartbeat.
              // Record the time since last beat, keep track of the two previous
              // times (first, second, third) to get a weighed average.
              // The rising flag prevents us from detecting the same rise more than once.
              rising = true;
              first = millis() - last_beat;
              last_beat = millis();

              // Calculate the weighed average of heartbeat rate
              // according to the three last beats
              print_value = 60000. / (0.4 * first + 0.3 * second + 0.3 * third);

              Serial.print(print_value);
              Serial.print('\n');

              third = second;
              second = first;

            }
          }
          else
          {
            // Ok, the curve is falling
            rising = false;
            rise_count = 0;
          }
          before = last;


          ptr++;
          ptr %= samp_siz;

        }
      } while (millis() - startTime <= readingTime);


      return print_value;
    }
};

Environmentenal sensors

Arduino
Record temperature, light and moisture
/*****************************************************************************************************************************************************************\
 Smart Sensing with Arduino MKRFOX1200 and SigFox networks. Measuring environmental  factors like humidity, temperature, gas concentration, light intensity, air
 quality,noise levels. Test set determines the total number of times the readings are to be taken for calculating the mean value, since these cheap sensors are not
 very accurate, this step might increase their efficiency. I used different functions to handle gas sensor and sound level sensor.
\*****************************************************************************************************************************************************************/
#include "Arduino.h"

class LightMoisture
{
  private: byte _Moisture, _Ldr;

    // Constructor to assign IO pins for individual environmental sensors
  public : LightMoisture(byte moisturePin, byte lightPin)
    {
      _Moisture = moisturePin;
      _Ldr = lightPin;
      pinMode(_Moisture, INPUT);
      pinMode(_Ldr, INPUT);
    }
    //Calculating light intensity % through ldr sensor
  public : int lightIntensity()
    {
      // we will calculate the mean value of the 20 times sensor readings and calculate the percentage
      return mean(_Ldr);
      delay(2000);
    }
    //Calculating moisture %
  public : int moistureValue()
    {
      // we will calculate the mean value of the 20 times sensor readings and calculate the percentage
      return mean(_Moisture);
      delay(2000);
    }
    //A function for finding average sensor readings
  private : int mean(byte sensor)
    {
      int s = 0, m = 0;
      for (byte i = 1; i <= 20; i++)
      {
        s += (analogRead(sensor));
      }
      m = (int) ((s / 20) / 1023) * 100; // converting the sensor mean value to %
      if(m==100)
      return 99;
      else
      return m;
    }
};

Plant height measurement

Arduino
To detect the height of the plant
#include "Arduino.h"

class PlantHeight
{
  private : long duration;
    int deviceHeight;
    byte trigPin, echoPin;

    //Constructor to initialize HCS04 ultrasonic sensor pin and set the height read for the first time as a control or test value height
    //or device height from the ground for comparisons in further readings
  public: PlantHeight(byte t, byte e)
    {
      trigPin = t;
      echoPin = e;
      
      // Running a 20 round loop and get an average to make sure that I get a correct value, 
      // I found while testing the ultrasonic sensor that it gives 0 values for first 2 times(it might be due to no delay when I start the sensor)
      delay(1000);
      for (int i = 1; i <= 20; i++)
      {
        pinMode(trigPin, OUTPUT);
        digitalWrite(trigPin, LOW);
        delayMicroseconds(2);
        digitalWrite(trigPin, HIGH);
        delayMicroseconds(10);
        digitalWrite(trigPin, LOW);
        pinMode(echoPin, INPUT);
        duration = pulseIn(echoPin, HIGH);
        deviceHeight += microsecondsToCentimeters(duration); //height of device installed from ground
        delay(1000);
      }
      deviceHeight = deviceHeight/20;
    }
    // Calculating plant relative height from the ground
  public: int relativHeight()
    {
      int readings;
      for (int i = 1; i <= 20; i++)
      {
        pinMode(trigPin, OUTPUT);
        digitalWrite(trigPin, LOW);
        delayMicroseconds(2);
        digitalWrite(trigPin, HIGH);
        delayMicroseconds(10);
        digitalWrite(trigPin, LOW);
        pinMode(echoPin, INPUT);

        duration = pulseIn(echoPin, HIGH);
        readings += microsecondsToCentimeters(duration);
        delay(1000);
      }
      //the updated value of sensor reading is going to be sent
      readings = readings/20;
      return deviceHeight - readings ;
    }

  private: long microsecondsToCentimeters(long microseconds)
    {
      return microseconds / 29 / 2;
    }
};

Audio frequency mesurement

Arduino
Using arduino uno to measure the frequncy of sound
#include <FreqMeasure.h>//https://github.com/PaulStoffregen/FreqMeasure

void setup() {
  Serial.begin(57600);
  Serial.println("hi");
  FreqMeasure.begin(); //Measures on pin 8 by default
  pinMode(LED_BUILTIN, OUTPUT);
}

double sum = 0;
int count = 0;
bool state = true;
float frequency;
int continuity = 0;
int id = 0;

void loop()
{
  if (FreqMeasure.available()) {
    // average several reading together
    sum = sum + FreqMeasure.read();
    count = count + 1;
    if (count > 30) {
      frequency = FreqMeasure.countToFrequency(sum / count);
      //Serial.println(frequency); we were using this during the testing phase
      sum = 0;
      count = 0;
    }
  }

  if (frequency > 6800 && frequency < 7200)
  {
    id = 1;
    continuity++;
    // Serial.print("Continuity -> ");
    // Serial.println(continuity);
    frequency = 0;
  }
  if (frequency > 145 && frequency < 375)
  {
    id = 2;
    continuity++;
    //Serial.print("Continuity -> ");
    //Serial.println(continuity);
    frequency = 0;
  }
  if (frequency > 800 && frequency < 1200)
  {
    id = 3;
    continuity++;
    //Serial.print("Continuity -> ");
    //Serial.println(continuity);
    frequency = 0;
  }
  if (frequency > 5000 && frequency < 6500)
  {
    id = 4;
    continuity++;
    //Serial.print("Continuity -> ");
    //Serial.println(continuity);
    frequency = 0;
  }
  if (continuity >= 3)
  {
    continuity = 0;
    switch (id)
    {
      case 1: Serial.print(id);   // noisy cricket
        break;
      case 2: Serial.print(id);   // mosquito
        break;
      case 3: Serial.print(id);   // honeybee
        break;
      case 4: Serial.print(id);   // chain saw
        break;
      default: Serial.print(0);
    }
    id = 0;
    delay(2000);
  }
  digitalWrite(LED_BUILTIN, state);
}

Sigfox MKRFox1200 serial communication with arduino uno

Arduino
Send the commands from uno to sigfox
#include <ArduinoLowPower.h>
#include <SigFox.h>

int FirePin = 5;
int firevalue;
volatile int fireStatus;
String str;                          // String to store message

struct SigFoxData
{
  int fireData;
  int serialData;
};

SigFoxData data;

void setup()
{
  Serial.begin(57600);

  while (!Serial) {}

  if (!SigFox.begin()) {
    // Something is really wrong, try rebooting
    // Reboot is useful if we are powering the board using an unreliable power source
    // (eg. solar panels or other energy harvesting methods)
    reboot();
  }
  LowPower.attachInterruptWakeup(FirePin, fireDetect, RISING);
  //Send module to standby until we need to send a message
  SigFox.end();
}

void fireDetect()
{
  fireStatus = 1;
}

void loop()
{
  if (fireStatus == 1)
  {
    data.fireData = fireStatus;
    fireStatus = 0;
  }
  else
  {
    data.fireData = 0;
  }
  int x;
  while (Serial.available() > 0)
  {
    x = Serial.read();
    data.serialData = x;
    delay(2000);
  }
  parseData();
  sendSigfoxData();
  LowPower.sleep(10 * 60 * 1000);                       // going to sleep for 10 minutes
}

void parseData()
{
  str = "SA" + 0 + data.serialData +0+ data.fireData;       // SA refers to sound analysis, we will use these keys to identify the type of message in thethings.io dashboard
}

void sendSigfoxData()
{
  // Start the module
  SigFox.begin();
  // Wait at least 30mS after first configuration (100mS before)
  delay(100);
  // Clears all pending interrupts
  SigFox.status();
  delay(1);

  SigFox.beginPacket();
  SigFox.print(str);

  int ret = SigFox.endPacket();  // send buffer to SIGFOX network
  if (ret > 0)
  {
    Serial.println("No transmission");
  }
  else
  {
    Serial.println("Transmission ok");
  }
  Serial.println(SigFox.status(SIGFOX));
  Serial.println(SigFox.status(ATMEL));
  SigFox.end();
}

void reboot()
{
  NVIC_SystemReset();
  while (1);
}

thethings.io functions code

JavaScript
to visualize data
function hex_to_ascii(str1)
 {
	var hex  = str1.toString();
	var str = '';
	for (var n = 0; n < hex.length; n += 2) {
		str += String.fromCharCode(parseInt(hex.substr(n, 2), 16));
	}
	return str;
 }
function main(params, callback)
{
    if(hex_to_ascii(params.data.substring(0,4)) == "SD")
    {
      //Replace with your own payload parse
      var result = [        
      { 
         "key":"identifier",
         "value":hex_to_ascii(params.data.substring(0,4))
      },
      {  
          "key": "temperature",
          "value": hex_to_ascii(params.data.substring(4,8))
       },
      {
          "key": "humidity",
          "value": hex_to_ascii(params.data.substring(8,12))
      },
      {
          "key": "light",
          "value": hex_to_ascii(params.data.substring(12,16))
      },
      {
          "key" : "dewPoint",
          "value" : hex_to_ascii(params.data.substring(16,20))
      },
      {
          "key" : "heatIndex",
          "value" : hex_to_ascii(params.data.substring(20,24))
      }  
     ]
      callback(null, result)
   }
  
  if(hex_to_ascii(params.data.substring(0,4)) == "PD")
  {
    //Replace with your own payload parse
    var result = [
      { 
         "key":"identifier",
         "value":hex_to_ascii(params.data.substring(0,4))
      },
      
      {   
          "key": "moisture",
          "value": hex_to_ascii(params.data.substring(4,8))
       },
      {
          "key": "plantHeight",
          "value": hex_to_ascii(params.data.substring(8,12))
      },
      {
          "key": "heartBeat",
          "value": hex_to_ascii(params.data.substring(12,16))
      },
      {
          "key" : "carbonDioxide",
          "value" : hex_to_ascii(params.data.substring(16,24))
      }
     
     ]
    callback(null, result)
  }
  
   if(hex_to_ascii(params.data.substring(0,4)) == "SA")
  {
    //Replace with your own payload parse
    var result = [      
      { 
         "key":"identifier",
         "value":hex_to_ascii(params.data.substring(0,4))
      },
      {   
          "key": "object",
          "value": object(hex_to_ascii(params.data.substring(6,8)) )
      },    
      
      {   
          "key": "audiofrequency",
          "value": frequency(hex_to_ascii(params.data.substring(6,8)) )
      },
      {
          "key": "fireStatus",
          "value": fire(hex_to_ascii(params.data.substring(10,12)))
      }
     ]
    callback(null, result)
  }
 
 }
function object(str)
{
  var str1=str;
  if(str1 == "1")
    return "cricket"
  if(str1=="2")
    return "mosquito"
  if(str1=="3")
    return "honeybees"
  if(str1=="4")
    return "chainsaw"
}
function frequency(str)
{
  var str1=str;
  if(str1 == "1")
    return ((6800+7200)/2)
  if(str1=="2")
    return ((145+375)/2)
  if(str1=="3")
    return ((800+1200)/2)
  if(str1=="4")
    return ((5000+6500)/2)
}
function fire(str)
{
  var str1=str
  if(str1=="1")
    return "Fire"
  if(str1=="0")
    return "Normal"
}

Credits

Sumit Kumar

Sumit Kumar

32 projects • 98 followers
21 y/o | Computer Vision Engineer(R&D) @VisAI Labs | Image Processing @e-conSystems | Ex-Embedded AI Engineer @Neuton.ai

Comments