element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Just Encase
  • Challenges & Projects
  • Design Challenges
  • Just Encase
  • More
  • Cancel
Just Encase
Blog [Pool Water Monitoring] #24 - Project Liftoff | Data collecting #2
  • Blog
  • Forum
  • Documents
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Just Encase to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: feiticeir0
  • Date Created: 26 Feb 2022 2:36 PM Date Created
  • Views 751 views
  • Likes 5 likes
  • Comments 0 comments
  • Arduino MKR WAN 1300
  • pool_water_monitoring
  • pool water monitoring
  • arduino mkr 1300 wan deepsleep
  • just_encase
  • deepsleep
  • just encase
Related
Recommended

[Pool Water Monitoring] #24 - Project Liftoff | Data collecting #2

feiticeir0
feiticeir0
26 Feb 2022
[Pool Water Monitoring] #24 - Project Liftoff | Data collecting #2

image

Hi all !

Hope everyone is safe and well.

In my last post about the data collecting, I've spoken about the battery issues and wonder why it only lasts half a day.

I then wonder if using a MOSFET could solve the problem, by putting all the sensors in a subcircuit and activate it - letting the current on and off to the sensors by means of a MOSFET.

I did try it. Here are some photos of the testing:

imageimage

But, because my electronic skills are limited and even with some google searches, I ended up losing the AM2302 sensor - not enough current for it, I guess. I did try with a TIP120 and a 1K resistor to the Arduino PIN, but no luck.

So, I've ended up with the same circuit I had before, already discussed here.

Code

The code is very straightforward, being mostly collecting data from the sensors, creating a package and sending it away, to the wind.

#include <SPI.h>
#include <LoRa.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <pins_arduino.h>
#include "DHT.h"
#include "ArduinoLowPower.h"

#define debug 0


/*
 * DS18B20 probe
 */
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature ds18b20sensor(&oneWire);


/*
 * AM2302
 */
#define DHTPIN 5
#define DHTTYPE DHT22 //AM2302
DHT dht(DHTPIN, DHTTYPE);

/*
 * TDS
 */

#define TdsSensorPin A2
#define VREF 3.3
#define SCOUNT 30       //sum of sample point
int analogBuffer[SCOUNT];    // store the analog value in the array, read from ADC
int analogBufferTemp[SCOUNT];
int analogBufferIndex = 0,copyIndex = 0;
float averageVoltage = 0, tdsValue = 0, temperature = 14.20; //temperature will be dynamic


/*
 * Battery
 */
float battery_voltage = 3.037; // use multimeter


/* remove all references to Serial */

void setup() {
  if (debug) {
    Serial.begin(115200);  
  }
  
  ds18b20sensor.begin();
  dht.begin();
  pinMode (TdsSensorPin, INPUT);

  if (!LoRa.begin (868E6)) {
    if (debug) {
      Serial.println("Starting LoRa failed!");
    }
    while (1);
  }
  delay (3000); 
  //we'll have the LED on when sending and off after
  pinMode(LED_BUILTIN, OUTPUT);
  //saving battery

  USBDevice.detach();
}

/*
 * Get AM2302 temperature
 */
float *getInsideTemperature() {
  static float measurements[2];
  
  measurements[0] = dht.readHumidity();
  measurements[1] = dht.readTemperature();

  return measurements;
}

/*
 * DS18b20 values
 */
float getOutsideTemperature() {
  //static float waterTemperature;
  ds18b20sensor.requestTemperatures();
  return ds18b20sensor.getTempCByIndex(0);  //default value is celcius
  
}

/*
 * get battery values
 */

float getBatteryStatus() {
  analogReadResolution(10);
  analogReference(AR_INTERNAL1V0);
  // put your main code here, to run repeatedly:
  int batteryLevel = analogRead(ADC_BATTERY);
  float voltage = batteryLevel * (battery_voltage / 1023.0);
  
  return ((voltage * 100) / battery_voltage);
}

/*
 * Get TDS values
 */
int getTDSmeasurement(float temp) {
  /*
   * There's a need to define the analogReference because
   * this is the default - 3.3v and the TDS sensor depends on it
   * On the function above, we're changing the reference to be able to, 
   * accurately, measure the battery voltage. A pain this was to find out
   * what was going on with the TDS values almost 500ppm
   */
  analogReference(AR_DEFAULT); 
  int toExit = 0;
  while (1) {
    static unsigned long analogSampleTimepoint = millis();
    if (millis()-analogSampleTimepoint > 40U) { //every 40 milliseconds,read the analog value from the ADC
      analogSampleTimepoint = millis();
      analogBuffer[analogBufferIndex] = analogRead(TdsSensorPin);    //read the analog value and store into the buffer
      analogBufferIndex++;
      if (analogBufferIndex == SCOUNT)
        analogBufferIndex = 0;
    }
    
    static unsigned long printTimepoint = millis();
    if (millis()-printTimepoint > 800U) {
      printTimepoint = millis();
      for (copyIndex=0;copyIndex<SCOUNT;copyIndex++)
        analogBufferTemp[copyIndex]= analogBuffer[copyIndex];
      averageVoltage = getMedianNum(analogBufferTemp,SCOUNT) * (float)VREF / 1024.0; // read the analog value more stable by the median filtering algorithm, and convert to voltage value
      float compensationCoefficient=1.0+0.02*(temp-25.0);    //temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.02*(fTP-25.0));
      float compensationVolatge=averageVoltage/compensationCoefficient;  //temperature compensation
      tdsValue = (133.42*compensationVolatge*compensationVolatge*compensationVolatge - 255.86*compensationVolatge*compensationVolatge + 857.39*compensationVolatge)*0.5; //convert voltage value to tds value
      if (toExit == 3) { //we need this because we must wait for values to setle.. 
          return tdsValue; 
      }
      toExit++;
    }
  }
}

int getMedianNum(int bArray[], int iFilterLen) {
  int bTab[iFilterLen];
  for (byte i = 0; i<iFilterLen; i++)
    bTab[i] = bArray[i];
  int i, j, bTemp;
  for (j = 0; j < iFilterLen - 1; j++) {
    for (i = 0; i < iFilterLen - j - 1; i++) {
        if (bTab[i] > bTab[i + 1]) {
          bTemp = bTab[i];
          bTab[i] = bTab[i + 1];
          bTab[i + 1] = bTemp;
        }
    }
  }
  if ((iFilterLen & 1) > 0)
    bTemp = bTab[(iFilterLen - 1) / 2];
  else
    bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
  return bTemp;
}


void loop() {
  // turn the LED on when awake:
  digitalWrite(LED_BUILTIN, HIGH);
  float *insideValues;                    //hold am2302 values
  float outsideValues;                    //Water temperature
  float batteryVoltage;                   //battery
  float tdsValues;
  
  insideValues = getInsideTemperature();
  if (debug) {
    Serial.println ("Inside Temperatures");
    Serial.print ("Humidity: ");
    Serial.println (insideValues[0]);

    Serial.print ("Temperature: ");
    Serial.println (insideValues[1]);
  }
  
  outsideValues = getOutsideTemperature();
  if (debug) {
    Serial.print ("Water Temperature: ");
    Serial.println (outsideValues);
  }

  tdsValues = getTDSmeasurement (float(outsideValues));
  if (debug) {
    Serial.print ("TDS: ");
    Serial.println (tdsValues);
  }

  batteryVoltage = getBatteryStatus();
  if (debug) {
    Serial.print("Batery Percentage: ");
    Serial.println (batteryVoltage);
  }
  //let's create the string to send via LoRa
  /*
   * It will be like this
   * insideTemp | insideHum | outsideTemp | TDS values | batteryVoltage
   */
  String LoRaPacket = String(insideValues[1]) + "|" 
                  + String(insideValues[0]) + "|"
                  + String(outsideValues) + "|" 
                  + String(tdsValues) + "|"
                  + String(batteryVoltage);
  //send package
  if (debug) {
    Serial.println("Sending package...");
  }
  LoRa.beginPacket();
  LoRa.print(LoRaPacket);
  LoRa.endPacket();
  // turn the LED off:
  digitalWrite(LED_BUILTIN, LOW);
  
  //for testing, just 5 minutes
  //LowPower.sleep (20000);
  LowPower.deepSleep (1800000);
}

We start by including all the libraries needed .

Setting the debug flag - testing

#define debug 0

Next, it's declaring all the sensors variables and definitions needed .

Adafruit's High temperature probe

/*
 * DS18B20 probe
 */
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature ds18b20sensor(&oneWire);

AM2302 sensor (DHT22)

/*
 * AM2302
 */
#define DHTPIN 5
#define DHTTYPE DHT22 //AM2302
DHT dht(DHTPIN, DHTTYPE);

TDS sensor

/*
 * TDS
 */

#define TdsSensorPin A2
#define VREF 3.3
#define SCOUNT 30       //sum of sample point
int analogBuffer[SCOUNT];    // store the analog value in the array, read from ADC
int analogBufferTemp[SCOUNT];
int analogBufferIndex = 0,copyIndex = 0;
float averageVoltage = 0, tdsValue = 0, temperature = 14.20; //temperature will be dynamic

And the battery voltage. This one is the be able to accurately measure the percentage left.

/*
 * Battery
 */
float battery_voltage = 3.037; // use multimeter

setup()

The setup() function will run once, every time the Arduino boots

Only start the serial console if debuging

if (debug) {
    Serial.begin(115200);  
  }

Initialize the high temperature probe, the DHT22 sensor and the TDS sensor pin to input

  ds18b20sensor.begin();
  dht.begin();
  pinMode (TdsSensorPin, INPUT);

Next we start the LoRa communications. If not, it just hangs there.

if (!LoRa.begin (868E6)) {
    if (debug) {
      Serial.println("Starting LoRa failed!");
    }
    while (1);
  }

We wait 3s for things to settle.

We define the BUILT IN LED PIN to output. We will use it to indicate that we are collecting data and sending it.

pinMode(LED_BUILTIN, OUTPUT);

In an effort to save battery, I detach the USB device. Remotely, I don't need it and it saves battery.

  USBDevice.detach();

Next, are the functions definitions used to gather all the sensors data.

AM2302

This function will read the sensor and return the data in an array

float *getInsideTemperature() {
  static float measurements[2];
 
  measurements[0] = dht.readHumidity();
  measurements[1] = dht.readTemperature();

  return measurements;
}

DS18b20

This one will read the high temperature probe and return it's value

float getOutsideTemperature() {
  //static float waterTemperature;
  ds18b20sensor.requestTemperatures();
  return ds18b20sensor.getTempCByIndex(0);  //default value is celcius
}

Battery

Now, we have a function to read the battery values. This is read the 2xAA batteries connected to the Arduino.

float getBatteryStatus() {
  analogReadResolution(10);
  analogReference(AR_INTERNAL1V0);
  // put your main code here, to run repeatedly:
  int batteryLevel = analogRead(ADC_BATTERY);
  float voltage = batteryLevel * (battery_voltage / 1023.0);
 
  return ((voltage * 100) / battery_voltage);
}

I've already discussed this one here (battery voltage reading). It was a tricky one, because how the analogReference can mess up the readings of the other sensors. Solution here. It will return the battery voltage percentage.

TDS values

This function will read the TDS values of the water. This was returning crazy values because of the changes on the analogReference. Had to be defined here to work.

/*
 * Get TDS values
 */
int getTDSmeasurement(float temp) {
  /*
   * There's a need to define the analogReference because
   * this is the default - 3.3v and the TDS sensor depends on it
   * On the function above, we're changing the reference to be able to,
   * accurately, measure the battery voltage. A pain this was to find out
   * what was going on with the TDS values almost 500ppm
   */
  analogReference(AR_DEFAULT);
  int toExit = 0;
  while (1) {
    static unsigned long analogSampleTimepoint = millis();
    if (millis()-analogSampleTimepoint > 40U) { //every 40 milliseconds,read the analog value from the ADC
      analogSampleTimepoint = millis();
      analogBuffer[analogBufferIndex] = analogRead(TdsSensorPin);    //read the analog value and store into the buffer
      analogBufferIndex++;
      if (analogBufferIndex == SCOUNT)
        analogBufferIndex = 0;
    }
    
    static unsigned long printTimepoint = millis();
    if (millis()-printTimepoint > 800U) {
      printTimepoint = millis();
      for (copyIndex=0;copyIndex<SCOUNT;copyIndex++)
        analogBufferTemp[copyIndex]= analogBuffer[copyIndex];
      averageVoltage = getMedianNum(analogBufferTemp,SCOUNT) * (float)VREF / 1024.0; // read the analog value more stable by the median filtering algorithm, and convert to voltage value
      float compensationCoefficient=1.0+0.02*(temp-25.0);    //temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.02*(fTP-25.0));
      float compensationVolatge=averageVoltage/compensationCoefficient;  //temperature compensation
      tdsValue = (133.42*compensationVolatge*compensationVolatge*compensationVolatge - 255.86*compensationVolatge*compensationVolatge + 857.39*compensationVolatge)*0.5; //convert voltage value to tds value
      if (toExit == 3) { //we need this because we must wait for values to setle..
          return tdsValue;
      }
      toExit++;
    }
  }
}

This function will take several measurements of the TDS and return the average value. Because the temperature also has influence in the TDS values, this function is called after the water temperature value is taken.

This function uses another one for the average.

Now, we get to the loop function.

loop()

This function will run forever, when the Arduino is running.

First, we turn the BUILT INT LED on to indicate that we're going to start measuring and sending.

  digitalWrite(LED_BUILTIN, HIGH);

Next, set some local variables to hold the return values from the several functions.

 float *insideValues;                    //hold am2302 values
  float outsideValues;                    //Water temperature
  float batteryVoltage;                   //battery
  float tdsValues;
 

We start by measuring the enclosure ambience and store them the variable insideValues

If we have debugging active, we show them

 insideValues = getInsideTemperature();
  if (debug) {
    Serial.println ("Inside Temperatures");
    Serial.print ("Humidity: ");
    Serial.println (insideValues[0]);

    Serial.print ("Temperature: ");
    Serial.println (insideValues[1]);
  }

Next, the water temperature - Adafruit's ds18b20

  outsideValues = getOutsideTemperature();
  if (debug) {
    Serial.print ("Water Temperature: ");
    Serial.println (outsideValues);
  }

The TDS values and battery voltage

tdsValues = getTDSmeasurement (float(outsideValues));
  if (debug) {
    Serial.print ("TDS: ");
    Serial.println (tdsValues);
  }

  batteryVoltage = getBatteryStatus();
  if (debug) {
    Serial.print("Batery Percentage: ");
    Serial.println (batteryVoltage);
  }

After we have all the values, let's construct the package (a string) to send to the other Arduino MKR 1300 WAN.

We will create a string by concatnating all the values, with the vertical bar - | - as a seperator.

/*
   * It will be like this
   * insideTemp | insideHum | outsideTemp | TDS values | batteryVoltage
   */
  String LoRaPacket = String(insideValues[1]) + "|"
                  + String(insideValues[0]) + "|"
                  + String(outsideValues) + "|"
                  + String(tdsValues) + "|"
                  + String(batteryVoltage);

Next, we send the packet.

We start the sequence by using beginPackaget().

LoRa.beginPacket();

We send the string

 LoRa.print(LoRaPacket);

And we signal the end of it by using endPacket().

LoRa.endPacket();

We turn the BUILT IN LED off

digitalWrite(LED_BUILTIN, LOW);

and sleep for 30minutes. The deepSleep function with turn everything off, except RTC. The trade off is that it takes the most time to wake up.

LowPower.deepSleep (1800000);

And here we have it. This is the remote MKR 1300 WAN that collects and sends the data.

Next post, my conclusions

  • Sign in to reply
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube