Objective

The goal of this project was to measure the temperature of my swimming pool and display the result on a remote display in my kitchen. To avoid using mains power near the swimming pool I needed a battery powered sensor. It is possible to design a low powered Arduino sensor that can run on batteries for many days, but I wanted to explore the use of solar to power for this project. The full description of the project is split into two posts, with digital display of the temperature in the second post. Here are some pictures as the build progressed from prototyping board to the final assembly.

Components

At the heart of the sensor was an Arduino Nano running the mySensors library to send the temperature reading back to my Raspberry Pi via NRF24L01 wireless network which are described at length in the tutorial posts. At first I tried to use the basic NRF24L01 wirless module, but the distance back to the gateway was too far and the signal kept dropping. So I elected to go with the more powerful nRF24L01P+PA+LNA module that I purchased from MakerFocus. These modules need a reliable 3.3V power supply, and though this is available via the Arduino Nano it cant deliver the current required. To address this I used the Breakout Adapter also available from MakerFocus which takes the 5V power supply from the solar panel power module and drops it down to 3V for the transmitter.

The MakerFocus breakout module provides a standard pinout to mount NRF24L01 wireless modules. The board can be powered with 5-12V and drops this to 3.3V to supply the NRF24L01 module.

For the temperature sensor I went with A Waterproof DS18B20 device from DFRobot. (https://www.dfrobot.com/product-689.html) . This is a three wire device, powered at 5V from the solar power supply module and deliveres ±0.5°C Accuracy from -10°C to +85°C. Power is provided

For the solar panel I selected the Waveshare Mini Solar Panel (6V 5W) with 156 Monocrystalline Cell. (https://www.waveshare.com/Solar-Panel-6V-5W.htm) .

The solar panel connects to a power management module (https://www.waveshare.com/Solar-Power-Manager.htm) , which maintains a reliable 5V power output through combined use of solar panel and 1.5V Li Battery. In practice I have found that the onboard battery will keep my Arduino Nano running through most of the night, but it can run out of power about 1 hour before sunrise.

All of the electronics are stored in a waterproof IP65 box from Sunnyglade.

Coding

Below is the code listing for the Arduino Nano. A few points to call out.

  • The DS18S20 is a standard 1 wire device and requires the OneWire library to be loaded into your Arduino IDE ( see https://www.arduino.cc/reference/en/libraries/onewire/ ).
  • The body of the main program uses sleep(1200000) to cycle temperature readings every 20 mins. sleep() is a mySensors function similar to the built in Arduino function delay(). The benefit of using sleep() is that the Arduino will wake if message is received from the mySensors gateway.
//--------------------------------------- VARIABLES ------------------------------------------------------------------------

#define DS18S20_PIN     2   // Temperature sensor data pin

#define MY_NODE_ID 19
#define CHILD_ID_TEMP 0
#define MY_DEBUG
#define MY_RADIO_NRF24
#define MY_RF24_PA_LEVEL RF24_PA_HIGH

#include <MySensors.h>
#include <OneWire.h>    // Library used to read one wire type sensors. https://www.pjrc.com/teensy/td_libs_OneWire.html

extern volatile unsigned long timer0_millis;   // internal system timer. timer0_millis is returned by the millis() function.
float temperature;
 
OneWire ds(DS18S20_PIN);    // OneWire object used to read Temperature from DS18B20 temperature sensor on digital pin 2

MyMessage msgTemperature(CHILD_ID_TEMP, V_TEMP);    // mySensors object used to send Temperature readings to gatewway

//--------------------------------------- SETUP  ---------------------------------------------------------------------------

void presentation()
{
  sendSketchInfo("POOL TEMPERATURE SENSOR", "1.0");
  present(CHILD_ID_TEMP, S_TEMP);
}

void setup(void) {
    Serial.begin(115200);
    temperature = getTemp();  // take initial temperature reading to reset sensor
    wait(1000);
}

//--------------------------------------- LOOP  ----------------------------------------------------------------------------

void loop(void) {
  
  temperature = getTemp();
  Serial.println(temperature);
  send(msgTemperature.set(temperature, 1)); // send temperature reading over mySensor network to gateway
  sleep(1200000); //cycle every 20 mins to get new temperature reading

}

//--------------------------------------- getTemp() FUNTION--------------------------------------------------------------------

float getTemp(){
// returns the temperature from one DS18S20 in Degrees Fahrenheit
// for details checkout the spec. sheet https://image.dfrobot.com/image/data/DFR0198/DS18B20.pdf

  byte data[12];    // used to hold Temperature data
  byte addr[8];     // used to hold Address of Sensor

// It is possible to have more than one DS18S20 hanging off the same data wire.  
// TWe use search(addr) to cycle through successive devices.
// If a device is found, its address is returned through the addr variable.


// ----- ERROR CHECK ------

  if ( !ds.search(addr)) {   // look for next sensor on the data wire
      Serial.println("No sensor found");
      ds.reset_search();
      return -1000;
  }
  
  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return -1000;
  }

  if ( addr[0] != 0x10 &amp;&amp; addr[0] != 0x28) {
      Serial.print("Device is not recognized");
      return -1000;
  }

// ----- TELL SENSOR TO READ TEMPERATURE AND STORE IN ITS SCRATCHPAD MEMORY ------

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1); // start conversion, with parasite power on at the end

// ----- TELL SENSOR TO SEND CONTENTS OF SCRATCHPAD MEMORY ------

  byte present = ds.reset();
  ds.select(addr);
  ds.write(0xBE); //  Send Scratchpad

// ----- READ 9 BYTES OF DATA THAT SENSOR SENDS FROM ITS SCRATCHPAD MEMORY ------

  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();
  }

  ds.reset_search();  // reset so that our next use of ds.search() starts at the first device hanging off the data wire

// ----- CONVERT FIRST 2 BYTES OF SENSOR DATA TO FLOATING POINT TEMPERATURE VLAUE ---------
// ----- The remaining bytes contain config data that we do not need ----

  byte MSB = data[1];
  byte LSB = data[0];

  float tempRead = ((MSB << 8) | LSB);                   // Combine Data Bytes to create a single integer value.
  float TemperatureSum = tempRead / 16;                  // Convert Integer to Temperature. 1 = 1/16th Degree Centegrade 
        TemperatureSum = 32.0 + TemperatureSum * 9 / 5;  // Convert to Deg F

  return TemperatureSum;

}

Leave a Reply

Your email address will not be published. Required fields are marked *