Project tutorial
SIGFY (Sigfox Farm Yield) with Crop and Health Monitoring

SIGFY (Sigfox Farm Yield) with Crop and Health Monitoring © GPL3+

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

  • 2,627 views
  • 3 comments
  • 22 respects

Components and supplies

Abx00014 featured xjsqphgdlv
Arduino MKR Fox 1200
×1
Oled lcd 128x64 1
ElectroPeak 0.96" OLED 64x128 Display Module
×1
Img 1167 450x300
DFRobot Gravity: Analog Gas Sensor (MQ2) For Arduino
×1
51gzz5eu9pl. sx425
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
4767222
LDR, 5 Mohm
×1
13637 01
SparkFun Soil Moisture Sensor (with Screw Terminals)
×1
KY-039 heartbeat sensor
×1
Httpsstatics3 seeedstudio comimagesproductloudness20sensor tp0aqldtni
Seeed Loudness Sensor
×1
Tens70
9V battery (generic)
×1
17c7357 40
Battery Holder, AAA x 3
×1
Usbcable
Micro-USB to USB Cable (Generic)
×1
33ac7801 40
Antenna, Cellular/Wifi
×1

Necessary tools and machines

Apps and online services

About this project

Overview:

This project demonstrates how to build a SigFox connected,SigFy v1 and v2, an agricultural tool that continuously measures farm data like temperature, humidity, gas levels, moisture, light intensity, plant height and also detects disease causing pests or activities like cutting trees and makes real-time data available to users online. It can also be used to keep a check on farmer's or individuals health. It also makes current crop rates and seed rates available to farmers through the dashboard.

The system can be deployed to remote villages with a one-time setup, and can be left to run on its own, automatically collecting data without the need for users to be present. Multiple SigFy devices can be placed throughout a village to collect many points of data eventually creating a star mesh topology with Sigfox base stations to analyse complex data.

Measurement data is pushed to the thethings.io cloud through the Sigfox network connectivity, enabled by ATA8520 module on Arduino MKRFOX1200, and can be viewed online through thethings.io IoT dashboard and other services are used to send email notifications to users when the values reaches a critical level.

Technical Overview:

While I was daydreaming I thought of an idea to use sensors to record height of the crops as well as detect early sign of diseases and that too without using 3G, 4G or 5G, so almost no carbon footprint.

I got to know about SigFox networking, a 0G standard radio communication protocol, though speed and data transmission capacity is still it's limitation but that what makes it reliable and perfect for IoT appliances. It has currently 12 bytespayload limit for each message and each day there can be up to 140 messages. Take note, you can use 140 messages per day, if you permute, it means that you can have send many different sensors data at frequent intervals, for example you want to send 6 sensors data and each data to be send after an interval of 10 minutes so you can make your device use an iteration technique to send first three sensor data and then second time send rest five sensor data. So you can have multiple combinations to send all sensor data at frequent intervals. I am too using the same technique.

Background :

Theme : Biodiversity and positive impact, by Sigfox Foundation

Theme : Social impact, by SqwidNet

1)Sustainable agriculture :

With increasing population a sustainable method of farming is important. It is very important to analyse what's going on in the farm, if a farmer would have means to know how is the growth of plant affected if he uses different techniques to grow crops then he might also predict what kinda safe methods and chemicals and right amount of water is required for maximum yield. Also it is very necessary to make farmers farm scientists so that they get maximum yield and restore the thriving quality of nature.In my country, India, farmers suffer due to lack of use of IoT devices in farming, refer to this website for more details on problems with Indian farmers, https://www.mckinsey.com/industries/agriculture/our-insights/harvesting-golden-opportunities-in-indian-agriculture

2) Detection of certain beneficial andharmful organisms using sound analysis :

Flowers can hear buzzing bees—and it makes their nectar sweeter

https://www.nationalgeographic.com/science/2019/01/flowers-can-hear-bees-and-make-their-nectar-sweeter/

Farmers are using lots of chemicals to boost their farm yield but we tend to forget that due to excessive use of those pesticides, insecticides and inorganic manures, cross pollinating agents, the arthropods( 90% of living organisms found on earth are insects) don't get attracted to those plants or otherwise die due to excessive chemical exposure and pollution. More than 2, 000 pollinating insects are extinct by now and only 500 are left to extinct if not protected. We also need to detect diseases in crops as early as possible to stop it from spreading in farm. To solve this problem I thought why not to tell farmer to use chemicals only if there are any bad growth patterns or harmful pests, nowadays even if there is no disease farmers uselessly spray chemicals and kill useful insects like honeybees. It will also detect for certain pollinating agents and how frequently they are there on fields also it can detect big animals who destroy the crop just by their voice and frequency.

3) Health monitoring of farmersand village :

Indian farmers do a heavy toil on their farm, with this device they can even keep a check on their pulse rate and health related issues. The device would also detect harmful insects like mosquitoes and make villagers aware of breeding of deadly insects, the same sound analysis technique would solve this problem. In case of fire or nearby gas leak the device would alert everyone.

4) Stopping deforestation :

There are many illegal cutting of trees so my device would make the concerned authorities aware of the cutting of trees using sound analysis technique, particularly it would detect the tone and frequency of wood cutting tools being operated.

Let's go!

Since I cannot perform all these functionalities using one single device so I developed the project into two parts, SigFy v1.0 and SigFy v2.0.

SigFy v1.0 (version 1.0):

Sustainable agriculture :

I am using ultrasonic distance sensor to detect the height of the crops from the ground. So whenever the device is started, the distance sensor calibrates itself and set the device distance from ground for plant growth measurements and use this value for find relative height of plant from the ground (so you can fix this device when you sow the seeds). Here's the code for plant height measurement.

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

Other sensors like DHT11 is used to measure temperature and humidity, LDR to detect light intensity and moisture sensor to detect water percentage in ground (a very fundamental thing in every farm).

/*****************************************************************************************************************************************************************\
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 moisturePercentage()
{
// 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;
}
};

I am using MQ2 gas sensor to detect smoke and carbon monoxide (you can use some good CO2 detection sensors it is more useful to measure CO2 than CO for photosynthesis rate determination, I ordered one but it didn't arrive on time anyway the working is same for any sensor you use). Since the MQ2 sensor cannot directly calculate the concentration of gases in air as the datasheet provides a non-linear graph which makes any formula undefined for it. There are other sensors which gives accurate readings.

https://www.instructables.com/id/How-to-Detect-Concentration-of-Gas-by-Using-MQ2-Se/

The above tutorial helped me a lot to know how the formula [ pow(10, ( ((log(rs_ro_ratio)-pcurve[1])/pcurve[2]) + pcurve[0])) ] is going to give me ppm. Since it is a log graph finding the slope of it is not accurate and easy. To find slope first take 2 points from the graph, find y axis co-ordinate and x-axis co-ordinate, since it is log-log graph, find respective log values of each co-ordinate with base 10, then substitute in (y2-y1)=m(x2-x1), where "m" is slope, but this is not going to be correct because it is a log graph. There are many accurate sensors in the market so we don't need to bother too much here because when we make final product we will choose the most reliable one(it's just a prototype).

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

So you can now have graph on dashboard and can visualize any combination of factors leading to growth of plants and experiment with your plants. So you become the master of your plants. The gas sensor would also take note of fire(smoke) in the field.

Health monitoring of farmers and village :

With this device farmer can not only record plant health but also maintain his own health, I used KY-039, a cheap heart beat rate counter module. While playing with it I found that it is not so accurate and the analog values rise when we place our finger on it. It is quite effective for my project. I made an interrupt in arduino code to store the heartbeat data only when a rise in analog value is detected indicating that the user wants to check his heart beat. Afterwards this data would be sent to dashboard for user to see later on (all data will be displayed on OLED screen of device also). Whenever a farmer does not feel well he can use this feature to check whether his pulse rate is normal or not.

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

SigFy v2.0 (Version 2.0)

Detection of certain beneficial and harmful organisms using sound analysis :

Since the memory and ram of MKRFOX 1200 is limited we cannot perform complex sound analysis techniques, raspberry pi and FFT (Fast Fourier Transformation) algorithms can do this work more efficiently but I don't have necessary SigFox modules for raspberry pi. However the principle remains same and for demonstration purpose my project fits perfectly. I am using FreqMeasure.h library, it does not work with MKR boards if I want to make it work I need to make timer and counter methods for on-board interrupts and timers ( I am only 15 years old I haven't learned so much about microcontroller, I posted help on arduino forum but didn't get any reply for it), but I will make it work anyhow. https://github.com/PaulStoffregen/FreqMeasure. So to make it work I am going to make use of Arduino UNO to calculate the audio frequency from the sound sensor (I am using a descent sound sensor module to detect frequencies however you can buy an audio analyser module like MAX4466 to detect more precisely, it can detect some very prominent frequencies very easily and with less codes) and then using serial communication between the two (Arduino UNO and MKRFOX 1200) I am going to receive the response like which object made that sound along with received frequency. So my job is done, Arduino UNO will act as a slave device and MKRFox as a master device. If anyone would help me to make use of library directly rather than using serial communication please message me or do post here. Here is the Arduino UNO code to detect the audio frequency and send to MKFOX1200 using serial communication.

#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);
}

On MKRFOX1200 we will use the serial communication to receive the above messages and send to SigFox cloud.

#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);
}

Hardware setup:

For the SigFy v1.0 I used the case of a digital alarm clock. Take a look at the wiring, we are powering the sesnors externally.

SigFy v2.0

The version two only consists of sound sensor and fire sensor.

SigFox setup:

I live in India and we don't have a SigFox base station here so I am going to use a SDR dongle for using callbacks in my project. Download the Sigfox network emulator from here https://build.sigfox.com/sdr-dongle also read the documents thoroughly.

Configuration for SDR dongle:

Step 1: Plug in the hardware and configure the callbacks.

Step 2:Configuring thethings.io

Please see this and follow the steps.

If you have configured your device well then it should show green up arrow for success.

Go to cloud code in thethings.io menu. This is the function which converts our data from HEX to ASCII and then set to value fields to display on the graph or dashboard.

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

And now we are going to make parse function in thethings.io to recognise the data members:

This is the first sensor readings, I used identifier "SD" to make myself understand that this is only surrounding areas data.

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)
}

After that I am reading plant data along with heart beat, "PD" is used to differentiate this function from other data.

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,20))
},
{
"key" : "smoke",
"value" : hex_to_ascii(params.data.substring(20,24))
}
]
callback(null, result)
}

This is the last data in which we are going to check for data and detect whether it is mosquito sound or of what frequency also check fire status.

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)
{
// just calculating average frequency
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"
}

The final code is attached at the end. If you were able to follow me then you should get you dashboard like this on configuration.

SigFy v1.0 is working flawlessly. Since I had only one MKRFOX so I had to dismantle the v1.0 to make v2.0. So with this we have completed the project, we can work more upon this, since I was facing some problems while using SDR dongle I ran out of time to add more features like handling data and ML algorithms in thethings.io and notifications, however I will add it later, but I think that I was able to clearly demonstrate how we can use tiny sensors to collect such important data. It is also an urge to Sigfox to please add India also to it's list so that we also enjoy such cool IoT tool.

JOB DONE: Enjoy this project and congratulate yourself that you made your own flexible environmental kit for you neighborhood (hint: use the SigFy v2.0 kit to monitor mosquito breeding in your locality and.SigFy v1.0 kit for your garden).

Sustainable Development Goals:

My whole project from beginning focuses on sustainable development goals and high standards. I was able to tackle some social problems also like health related issues by detecting pests, mosquitoes, farmer's heart beat and also notify in case of fire.

Code

MQ2 Gas detectorArduino
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 progamArduino
/****************************************************************************************************************************************************************\
  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 sensingArduino
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 sensorsArduino
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 measurementArduino
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 mesurementArduino
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 unoArduino
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 codeJavaScript
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"
}

Schematics

plantcare_7yVFtSWDJb.jpg
Plantcare 7yvftswdjb
sound-anlysis_tcct1s0dQ8.png
Sound anlysis tcct1s0dq8
farmer_health_gUYefG7hyN.jpg
Farmer health guyefg7hyn
SigFy v1.0
First device very efficient for farmers
Wiring bb 0deldgvgwe
SigFy v2.0
First device to easily recognize audio frequency and detect pest, good insects or heavy tools also notify in case of fire
V2 r9odwxbpcq

Comments

Add projectSign up / Login