We tested each sensor separately connecting with Arduino MKR WAN 1300 board. Now is the right time to develop our final code for collecting important data from all the sensors and transmitting the data to another Arduino board using LoRa. For doing so we will combine all the tested code in a single Arduino sketch. The following is the final code for collecting and sending all the sensor data.
I am not expert in C programming. I beleive follwoing sketch can be more clean if written by an experience programmer.
#include <SPI.h>
#include <LoRa.h>
#include "DFRobot_EC.h"
#include <EEPROM.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
#define TEMPERATURE_PRECISION 9 // Lower resolution
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
int numberOfDevices; // Number of temperature devices found
DeviceAddress tempDeviceAddress; // We'll use this variable to store a found device address
#define pHSensorPin A2 //pH meter Analog output to Arduino Analog Input 0
#define Offset 41.02740741 //deviation compensate
#define samplingInterval 20
#define printInterval 800
#define ArrayLenth 40 //times of collection
#define VOLTAGE 3.30 //system voltage
#define OFFSET 0 //zero drift voltage
#define orpPin 3
int orpArray[ArrayLenth];
int orpArrayIndex=0;
#define EC_PIN A1
float voltage,ecValue,temperature = 25;
DFRobot_EC ec;
void setup() {
Serial.begin(9600);
while (!Serial);
ec.begin();
sensors.begin();
numberOfDevices = sensors.getDeviceCount();
for(int i=0;i<numberOfDevices; i++)
{
// Search the wire for address
if(sensors.getAddress(tempDeviceAddress, i))
{
// set the resolution to TEMPERATURE_PRECISION bit (Each Dallas/Maxim device is capable of several different resolutions)
sensors.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION);
}
Serial.println("LoRa Sender");
if (!LoRa.begin(915E6)) {
Serial.println("Starting LoRa failed!");
while (1);
}
}
}
void loop() {
float tempC = read_temperature();
float pH = read_ph_value();
float ec = read_ec_value();
float orp = read_orp_value();
String data = "DATA:";
data += tempC;
data += ",";
data += pH;
data += ",";
data += ec;
data += ",";
data += orp;
Serial.print("Sending packet: ");
// send packet
LoRa.beginPacket();
LoRa.print(data);
LoRa.endPacket();
data = "";
delay(60000);
}
float read_temperature(){
sensors.requestTemperatures(); // Send the command to get temperatures
sensors.getAddress(tempDeviceAddress, 0)
temperature = sensors.getTempC(tempDeviceAddress);
return temperature;
}
float read_ph_value(){
static unsigned long samplingTime = millis();
float pHValue, voltage;
if (millis() - samplingTime > samplingInterval)
{
pHArray[pHArrayIndex++] = analogRead(pHSensorPin);
if (pHArrayIndex == ArrayLenth)pHArrayIndex = 0;
voltage = avergearray(pHArray, ArrayLenth) * 3.3 / 1024;
pHValue = -19.18518519 * voltage + Offset;
samplingTime = millis();
}
return pHValue;
}
float read_orp_value(){
static unsigned long orpTimer=millis(); //analog sampling interval
if(millis() >= orpTimer)
{
orpTimer=millis()+20;
orpArray[orpArrayIndex++]=analogRead(orpPin); //read an analog value every 20ms
if (orpArrayIndex==ArrayLenth) {
orpArrayIndex=0;
}
float orpValue=((30*(double)VOLTAGE*1000)-(75*avergearray(orpArray, ArrayLenth)*VOLTAGE*1000/1024))/75-OFFSET; //convert the analog value to orp according the circuit
}
return orpValue;
}
float read_ec_value(){
static unsigned long timepoint = millis();
if(millis()-timepoint>1000U) //time interval: 1s
{
timepoint = millis();
voltage = analogRead(EC_PIN)/1024.0*3300; // read the voltage
//temperature = readTemperature(); // read your temperature sensor to execute temperature compensation
float ecValue = ec.readEC(voltage,temperature); // convert voltage to EC with temperature compensation
}
ec.calibration(voltage,temperature);
return ecValue;
}
double avergearray(int* arr, int number) {
int i;
int max, min;
double avg;
long amount = 0;
if (number <= 0) {
uart.println("Error number for the array to avraging!/n");
return 0;
}
if (number < 5) { //less than 5, calculated directly statistics
for (i = 0; i < number; i++) {
amount += arr[i];
}
avg = amount / number;
return avg;
} else {
if (arr[0] < arr[1]) {
min = arr[0]; max = arr[1];
}
else {
min = arr[1]; max = arr[0];
}
for (i = 2; i < number; i++) {
if (arr[i] < min) {
amount += min; //arr<min
min = arr[i];
} else {
if (arr[i] > max) {
amount += max; //arr>max
max = arr[i];
} else {
amount += arr[i]; //min<=arr<=max
}
}//if
}//for
avg = (double)amount / (number - 2);
}//if
return avg;
}
Connections
Enclosing inside a box
As I am going to collect data from water. So my electronics should be protected from the water. A waterproof box is required for this purpose. Thanks to Hammond Enclosures as they provided two nice environment-safe boxes. I used Water Tight ABS 200x120x90 Enclosure for my project (you can buy one from here). This box is big enough to place all the electronics inside the box including a standard size breadboard and a power bank.
Sensor drivers are placed inside the box and the sensor probes are brought out through the Hammond Cable Glands. I placed the cable glands at the bottom side of the box.
Primarily the device is powered from a power bank but finally, I will use a li-ion battery and the battery will be charged from a solar panel.