Hardware & Sensors - A Deep Dive Into Building a Pool Bot
Tags: iot, arduino, c
Published: 2020-04-30 11:41:38

This is second article in a multipart series. In [Part 1](https://dev.to/j4s0nc/a-deep-dive-into-building-a-pool-bot-44ib) we talked about the idea and needs for this pool bot, now lets descend into the hardware behind it.

- [Gathering the right tools](#gathering-tools)
- [Hardware / Brain](#hardware-brain)
- [Temperature Sensors](#temperature-sensors)
- [Pump Relay](#pump-relay)
- [Water Level](#water-level)
- [pH Sensor](#ph-sensor)
- [Pressure Sensor / Transducer](#pressure-sensor-transducer)
- [Sensor Installation](#sensor-installation)


## Gathering the right tools <a name="gathering-tools"></a>

Before starting a hardware project like this, I had to get a few new ~~toys~~ tools. 

I found a nice [Soldering Iron Kit] (https://www.amazon.com/gp/product/B071VLFGXL/ref=ppx_od_dt_b_asin_title_s00?ie=UTF8&psc=1) on amazon for about $21. I was skeptical since it seems really cheap, but I was pleasantly surprised. Not only did it have everything I needed, but they seems to be decent quality tools. ![Soldering Kit](https://dev-to-uploads.s3.amazonaws.com/i/s4gg2dr8n3ilpdvcz292.png)

I also knew I needed a [Digital Multimeter](https://www.amazon.com/gp/product/B000EVYGZA/ref=ppx_yo_dt_b_asin_title_o05_s00?ie=UTF8&psc=1) and found one for $20! The auto-ranging feature was a nice touch for a budget meter. ![Multimeter](https://dev-to-uploads.s3.amazonaws.com/i/a5c4k3tlsw2apjyyd2z0.png)

Since Amazon knew I was getting into hardware, it suggested this [Lighted Helping Hands Magnifier](https://www.amazon.com/gp/product/B00K9XPMK6/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1) for $19. It works ok, but it's very topheavy, I should've read the reviews first. ![Helping Hands](https://dev-to-uploads.s3.amazonaws.com/i/0c873vnj06aaqjwunxaz.png)



## Hardware / Brain <a name="hardware-brain"></a>

The main pieces of hardware used in the project are an [Arduino](https://www.arduino.cc/) to read sensor values, and a [Particle Photon](https://particle.io/) to connect to the cloud. 

I started out prototyping this project using an [Arduino Mega 2560](https://store.arduino.cc/usa/mega-2560-r3), but switched it out for a [Nano](https://usa.banggood.com/ATmega328P-Nano-V3-Module-Improved-Version-No-Cable-Development-Board-p-959231.html) since you can find Nano's for around $2 a piece vs $30+ for a Mega. Plus the form factor of the Nano is much smaller and easier to house. 
![Mega](https://dev-to-uploads.s3.amazonaws.com/i/ufzsww6k2oti6a5auh6s.png)
![Nano](https://dev-to-uploads.s3.amazonaws.com/i/84lge2jewper9te7e0iv.png)

One small issue I ran into after switching was power. Both are 5v and have a 3.3v out pin. Originally I was using this 3.3v out to power the Photon. When connected to the Mega there was no issue, but when connected to the Nano the board just couldn't supply the power needed. The work around was simple, I just power them both separately. 
![Photon](https://dev-to-uploads.s3.amazonaws.com/i/ftt8vunlyveuiis3qj4p.png)

## Temperature Sensors <a name="temperature-sensors"></a>

There are three different temperatures I care about around my pool:

- The Water in the pool 
- The Water coming out of my solar heat panels
- The Air/Ground temperature

I picked up a 5 pack of [DS18B20 Waterproof Temperature Sensors](https://www.amazon.com/gp/product/B01JKVRVNI/ref=ppx_yo_dt_b_asin_title_o05_s01?ie=UTF8&psc=1) for $12. ![DS18B20 Waterproof Temperature Sensors](https://dev-to-uploads.s3.amazonaws.com/i/godbob3dcz1rtma9oeth.png)

These appeared to be very simple to wire, but do require a 5k resistor. 
![temp Wiring](https://dev-to-uploads.s3.amazonaws.com/i/ky13pcaa2dqy0pmos945.png)

Through the magic of the [OneWire Library](https://www.pjrc.com/teensy/td_libs_OneWire.html), I didn't need a pin for each temp sensor, it can read all three on one pin! ![One Wire Bus](https://dev-to-uploads.s3.amazonaws.com/i/ccorgxjb1pltv58j54lr.png)

The code to read all three from one pin is pretty straightforward: 
```c
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 4 //temp sensors pin

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress T1, T2, T3; // arrays to hold device addresses (can be up to 8 on bus T4, T5, T6, T7, T8)

float temp1;
float temp2;
float temp3;

void setup()
{
  //get address of each temp sensor so we can read it in the loop
  int count = sensors.getDeviceCount();
  Serial.print("Found: ");
  Serial.print(count, DEC);
  Serial.println(" Devices.");
  if (sensors.getAddress(T1, 0))
    Serial.println("Found Sensor 1");
  if (sensors.getAddress(T2, 1))
    Serial.println("Found Sensor 2");
  if (sensors.getAddress(T3, 2))
    Serial.println("Found Sensor 3");
}


void loop()
{
    //read temp sensors
    sensors.requestTemperatures();
    for (int k = 0; k < sensors.getDeviceCount(); k++)
    {
      if (k == 0)
      {
        temp1 = sensors.getTempF(T1);
      }
      else if (k == 1)
      {
        temp2 = sensors.getTempF(T2);
      }
      else if (k == 2)
      {
        temp3 = sensors.getTempF(T3);
      }
    }
}
```

## Pump Relay <a name="pump-relay"></a>

A relay is basically a controllable switch. There are a lot different types and it can be confusing to figure out what you need. In my case, I needed a relay that can be controlled by 5 volts DC coming from my Arduino and switch my pool pump which is running on 120 volts AC at 20 amps. 

Knowing this I looked for relay with a 5VDC coil and a rating of at least 20A at 120VAC or higher. I was able to find the GU-SH-105D-5 relay that matched my needs. It costs about $1 for the relay, and $5 to ship it from China. 
![relay packaging](https://dev-to-uploads.s3.amazonaws.com/i/nwxq9pqfetrnxzs3zs9p.png)
![Relay](https://dev-to-uploads.s3.amazonaws.com/i/hng36s46140ei9p3dsr4.png)

The only problem, this is a *just* the relay. In order to use it, we will have to build a Relay Module. If you are dealing with lower amps you might be able to pick a full module and save yourself this hassle. But finding a 20 amp module seemed impossible at the time. ![relay-schematic](https://dev-to-uploads.s3.amazonaws.com/i/wuo3virrk2br0hno573v.png)

I didn't design this circuit, but it seemed common for what I was trying to do. I ended up using a 1N4148 Diode (DP in the schematic) to control one way voltage flow from the coil and stop leak back. I also used a 2N2222A NPN transistor (QS) to amplify the signal to the coil, this helps provide a solid 5 volts. 

![Relay breadboard](https://dev-to-uploads.s3.amazonaws.com/i/sq38u068r4rpmsmntwew.png)

After testing on the breadboard, I soldered and heat wrapped this to the relay, and my module was complete! 

![Relay wiring](https://dev-to-uploads.s3.amazonaws.com/i/uu7vchce27wqm57npiew.png)

I wired a 120 volt outlet to the relay and tested it with a lamp.

![Relay Light test](https://dev-to-uploads.s3.amazonaws.com/i/f18220bca35tomse9kxa.png)

Here is all the code needed to control the relay:
```c
#define RELAY_PIN 2 //connected to digital pin 2

void setup()
{
  //set relay as output send we will be sending voltage to the coil
  pinMode(RELAY_PIN, OUTPUT);
}

//... inside loop when we want to trigger the raley ...
// mode = HIGH will turn relay on, LOW will turn it off
digitalWrite(RELAY_PIN, mode);

```

## Water Level <a name="water-level"></a>

The main reason I want to monitor the water level inside the pool skimmer is to control the pump. If the water level is too low the pump may be sucking air. Which isn't good; pumps are expensive!!

My first thought was to use a Horizontal Liquid Float Switch, I found them on amazon for $12 a 6 pack. But while testing these weren't reliable. They only reported a digital 1 or 0 but they aren't consistent about the angel that triggers open vs close. I would also have to modify the skimmer box to use these, and I'm not sure I want to go down that path. 
![Level Switch](https://dev-to-uploads.s3.amazonaws.com/i/npiop96o7vk6wbq4pqw0.png)

After doing some more research I found the [XKC-Y25-NPN Waterproof Non-Contact Liquid Level Sensor](https://www.amazon.com/gp/product/B074PVF341/) for $13, a bit expensive, but much cheaper than a new pump! These are designed to read liquid through a pipe or other plastic surface and don't need to physically touch the water. It worked well tapped to the outside of my skimmer box. 
![XKC-Y25-NPN non-contact liquid level](https://dev-to-uploads.s3.amazonaws.com/i/21njb3292rmbib56iiv6.png)

Now I can write a function to control the pump based on the water level! 

Since this sensor is pinged every second, We may not want to switch the pump just because kids are playing in the pool and they make waves in the skimmer box. It could cause a low read once or twice in a row. We'll track the count and only switch the relay if the status changes after a given tolerance (10 seconds). 

I also added an override feature for times I want to control the pump manually (more on that when we talk about cloud control). 

```c

/* This function takes in the current water level: 1 = water, 0 = no water
 It returns the resulting pump status: 
 -1 Pump off due to manual override
  0 Pump off due to no water
  1 Pump On since water level is OK
  2 Pump On due to manual override
 */
int controlPump(int currentLevel)
{
  if (pumpOverride) {
    return PumpStatus == LOW ? -1 : 2;
  }

  if (currentLevel == LOW && PumpStatus == HIGH) //no water and pump is on!!
  {
    if (--PumpChangeCount < 1) //max loops hit, turn off the pump
    {
      Serial.println("ALERT Low water! Turning pump OFF");
      setPump(LOW);
    } else {
      Serial.print("Water level low! Pump OFF in ");
      Serial.println(PumpChangeCount);
    }
  }
  else if (currentLevel == HIGH && PumpStatus == LOW) //has water and pump is off
  {
    if (++PumpChangeCount >= WATER_CHANGE_COUNT) //max loops hit, turn on the pump
    {
      Serial.println("Water level OK. Turning pump ON");
      setPump(HIGH);
    } else {
      Serial.print("Water level Up. Pump ON in ");
      Serial.println(WATER_CHANGE_COUNT - PumpChangeCount);
    }
  }
  else if (currentLevel == HIGH && PumpStatus == HIGH) //level ok and pump is on
  {
    if (PumpChangeCount < WATER_CHANGE_COUNT)
      PumpChangeCount++;
  }
  else if (currentLevel == LOW && PumpStatus == LOW) //level low and pump is off
  {
    if (PumpChangeCount > 0)
      PumpChangeCount--;
  }

  return PumpStatus;
}

//helper function to control pump and pump power LED 
void setPump(uint8_t mode) {
  PumpStatus = mode;
  digitalWrite(RELAY_PIN, mode);
  digitalWrite(GRN_LED, mode);
}
```

## pH Sensor <a name="ph-sensor"></a>

Anyone that has ever owned a pool will tell you, the most important thing to do is get your water chemistry level correct. But getting that perfect pH, chlorine, alkalinity, and other levels inline can be like balancing spinning plates on sticks. 

Once you get a good balance, you really only need to take pH and chlorine levels weekly, but if they start to get off balance you could have days of chemical adjustments ahead of you to fix it. 

I wanted to automate as much of this as I could. I did some research and quickly found that chlorine probes are expensive! Entry level units are hundreds of dollars and had a lifespan of six months to a year! Looks like I'll be testing that part manually for now. 

Then I stumbled across this [Liquid PH Value Detection detect Sensor Module](https://www.amazon.com/gp/product/B07K8TBBFH) for $15. ![PH](https://dev-to-uploads.s3.amazonaws.com/i/f1fzonchzlofgwlet8vb.png)

It seemed too cheap to pass up, turns out it performs that way too. You have to zero it out before use and adjust it to both low and high known pH solutions. This was a pain to say the least. 

I modified my pool plumbing and built a custom housing out of 3/4" pvc to 1/2" pvc couplers and a bunch of o-rings. I added some two part epoxy for good measure . ![pH installed](https://dev-to-uploads.s3.amazonaws.com/i/fu2ogh3vmomb3w3vifos.jpg)

I found what looks like hackly math to calculate the sensors analog voltage readings to a pH value. First we divide the voltage (5v) by the max reading value (1023). We then multiply the voltage to convert it to a know pH range (this sensor has a max range of ph from 14 to just over 3). This math "worked" during bench testing. 

```c
//read Ph
float voltage = analogRead(PH_PIN) * (5.0 / 1023.0);
float ph = voltage * (14.000 / 3.148);
```

After doing all this, I was very disappointed to find it would give randomly readings from time to time. Everything would be fine, and my manual testing would show a pH of 7.2ish, but one day this sensor shows 5 or 6 and the next day show 8. Maybe I have inconsistent voltage, maybe you get what you pay for! 


## Pressure Sensor / Transducer <a name="pressure-sensor-transducer"></a>

Another step in my pool maintenance routine is backwashing my sand filter. It's not a hard step, but it can waste water if you do it too often. One common way to know when it's time to backwash is to check the pressure gauge on the sand filter.  
![pressure gauge](https://dev-to-uploads.s3.amazonaws.com/i/zobe5fbhun2drdswqytg.jpg)

We want to run at around 10-25 pounds per square inch (PSI). I typically want to backwash when the PSI reaches above 20. I found this [1/4" inch 5V 0-1.2 MPa Pressure Transducer Sensor](https://www.amazon.com/gp/product/B01IR2MANC) for $15 and decided to try it out. ![pressure transducer](https://dev-to-uploads.s3.amazonaws.com/i/22ucbquiuq272d6b5w2e.png)

One of the first things I had to figure out was converting Megapascal (MPa) to PSI, it's actually simple, there are 145 PSI in a MPa. Knowing this helped confirm that i got a transducer big enough to measure the pressures I'd see in my filter. If it ever hit a 60 PSI we have big problems, let alone a 170!

This sensor is analog, so each read will produce a number between 0 and 1023. First step we will convert that number to the known voltage range. Based on the datasheet, this device has a output voltage of 0.5-4.5 VDC. Next, convert from MPa to PSI. 
```
//read pressure
float voltage = (analogRead(PRESSURE_PIN) - 120) / 963; // convert voltage to known output range
float mpa = voltage * 1.2;
float pressure = mpa * 145; // convert mpa to psi
```

## Sensor Installation <a name="sensor-installation"></a>

Now that we have all of these cool sensors bench tested it's time to install them in their final home. 

![empty box](https://dev-to-uploads.s3.amazonaws.com/i/trqj9h2w9gn6hickk2xk.png)
This bot will be mounted in the wall of my barn next to the pool, so I just used a 3 gang electrical box. I also went this route since there is a 120 volt relay and this should be a safe enclosure for that. ![stuffed box](https://dev-to-uploads.s3.amazonaws.com/i/ob93uoj4o4zurojakh78.png)

Even though the end goal is to push all this information to the cloud and view it on my phone, I thought it would be nice to also have an LCD and a few LEDs in the barn to get a quick status. ![LCD](https://dev-to-uploads.s3.amazonaws.com/i/fxfhu3jxrgs3tsjeqh2k.png)

Wiring the LCD became a bit tricky since I was running low on Arduino pins. I ended up powering the LCD from the Arduino (since it needs 5V), but the data pins are connected to the Photon and it handles writing out the information. ![LCD wiring](https://dev-to-uploads.s3.amazonaws.com/i/kogx1r9a17f1p2uvjns1.png)

Since the sensors will be connected outside near the pool plumbing, I picked up a ten pack of [3 Pin Waterproof Electrical Connector Plugs](https://www.amazon.com/gp/product/B07BDK9FPT/) for $13. I also put waterproof heat shrink around the sensors and wires.  

In order to connect these to the main housing I mounted another outlet box outside of the barn and used CAT5 between the two boxes.![wiring ends](https://dev-to-uploads.s3.amazonaws.com/i/z5q3oiy133bxt5ellkr9.png)

The [temperature sensors](#temperature-sensors) need to be in contact with the water, so I drilled small holes and used two part epoxy. 
![temp holes](https://dev-to-uploads.s3.amazonaws.com/i/0nysgwhft7ukwzzuk1h7.jpg)
![temp epoxy](https://dev-to-uploads.s3.amazonaws.com/i/wjapj75749kvjk0pel5s.jpg)

The [pH sensor](#ph-sensor) was a bit tricker, I added a PVC elbow, a few PVC reducers and some couplers. And of course, two part epoxy for good measure. 
![ph](https://dev-to-uploads.s3.amazonaws.com/i/du5revh4zhrbw1h3uojg.jpg)

As for the [pressure sensor](#pressure-sensor-transducer), I just unscrewed the old gauge and screwed this in it's place on the sand filter. 

---

Now let's go to [Part 3 and put this pool on the internet!](https://dev.to/j4s0nc/putting-my-swimming-pool-on-the-internet-a-deep-dive-into-building-a-pool-bot-7o1)