Solar hot water differential controller.

I am building a drainback solar hot water heater, and have built a differential temperature controller that turns on a circulator pump via a relay circuit. As this is the first project I have built that will actually do something useful, I would like opinions before putting it into production.

I’m using Dallas OneWire for my sensors.


/*Solar hot water differential controller. Uses Dallas Onewire bus for the temperature
sensors. Turns on pump via digital output hooked to a relay for high voltage switching of circulator pump.


#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal.h>

//These first three variables are where the adjustments are made.

//set maximum tank temperature in F
int tankmax = 140;

//set how much higher collector temperature should be, in F, before turning on pump
int diff = 15;

//Turn off pump whan temp is within this many degrees of the collector
float werethere = 1.5;

//set up pins for lcd display
LiquidCrystal lcd (7, 8, 9, 10, 5, 6);

// Set input pin for onewire bus
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

//The thermometers are identified by their unique identifier

byte tanktopThermometer[8] = {0x28, 0x74, 0x28, 0xe3, 0x02, 0x00, 0x00, 0x12};

byte collectorThermometer[8] = {0x28, 0x95, 0x59, 0xe3, 0x02, 0x00, 0x00, 0xAc};

//set pin for pump relay
int pump = 3;

//set pin for led pump indicator
int pumpLed = 4;

int pumpstate;


void setup ()
//start serial port
Serial.println (“Solar hot water Differential Controller”);

// Start up the onewire library

// locate devices on the bus
Serial.print(“Locating devices…”);
Serial.print(“Found “);
Serial.print(sensors.getDeviceCount(), DEC);
Serial.println(” devices.”);

// report parasite power requirements
Serial.print("Parasite power is: ");
if (sensors.isParasitePowerMode()) Serial.println(“ON”);
else Serial.println(“OFF”);

// set the sensor resolution from 9 to 12 bit
sensors.setResolution(tanktopThermometer, 10);
sensors.setResolution(collectorThermometer, 10);

//initialize lcd
lcd.setCursor (0,0);
lcd.print (“CL”);
lcd.setCursor (0,1);
lcd.print (“TT”);

//set pins to output
pinMode (pump, OUTPUT);
pinMode (pumpLed, OUTPUT);



//functions that reads temp from sensors and returns as floating point value.

float sensorValue (byte deviceAddress)
float tempC = sensors.getTempC (deviceAddress);
float temp = (DallasTemperature::toFahrenheit(tempC));
return temp;


void loop ()

//get all sensor values

//set variables
float tank = (sensorValue(tanktopThermometer));
float collector = (sensorValue(collectorThermometer));

//prints temperature values to serial port and lcd
Serial.print ("tank ");
Serial.println (tank);
Serial.print ("collector ");
Serial.println (collector);
lcd.setCursor (2,0);
lcd.print (collector);
lcd.setCursor (2,1);
lcd.print (tank);
Serial.print (“pump state “);
Serial.println (pumpstate);
Serial.println (””);

/turns on pump when collector is (diff) degrees above tank.
and tank is below (tankmax) temperature.
once pump turns on, pumpstate variable turns to “1” and causes pump to remain
on as long as collector temp is higher than tank temp.
If max tank temp is reached, pump always turns off.

if ( ( (collector - diff) > tank ) && ( tank < tankmax ) )
{digitalWrite (pump, HIGH); digitalWrite (pumpLed, HIGH); pumpstate = 1; }

{if (pumpstate == 1)
{ if ( ( (collector - werethere) >= tank) && (tank < tankmax) )
{digitalWrite (pump, HIGH); digitalWrite (pumpLed, HIGH); }

else {digitalWrite (pump, LOW); digitalWrite (pumpLed, LOW); pumpstate = 0;}



This also works. I’m sure I’m not doing this the most elegant way, but it does seem to work. What are some other ways I could code this? The idea is to turn the pump on when the collector is hot enough (differential) , and leave it on until tank reaches collector temperature.

if ( ( (collector - diff) > tank ) && ( tank < tankmax ) )
{digitalWrite (pump, HIGH); digitalWrite (pumpLed, HIGH); pumpstate = 1; }

{if ( (pumpstate == 1) && ( (collector - werethere) >= tank ) && (tank < tankmax) ) { }

else {digitalWrite (pump, LOW); digitalWrite (pumpLed, LOW); pumpstate = 0;}

Little bit cleaner:

static bool pumpOn=false;
if ( pumpOn)
  if ((collector - werethere) < tank ) || (tank >= tankmax) ) 
    digitalWrite (pump, LOW); 
    digitalWrite (pumpLed, LOW); 
    pumpOn =false;
  if (((collector - diff) > tank ) && ( tank < tankmax ) )       
    digitalWrite (pump, HIGH); 
    digitalWrite (pumpLed, HIGH); 
    pumpOn = true;  

Very cool! I think you forgot a “(” though. Should be:

if ( ( (collector - werethere) < tank) || (tank >= tankmax) )

That works good! Thanks.

Is there a reason to initially set the bool to pumpOn=false rather than just declaring : "static bool pumpOn;" ?

It's not necessary, as you observe, but it makes your intent clearer. Without it, the reader of the code (you in a years time perhaps) is in doubt as to whether you forgot to initialize it or are actually taking advantage of the fact that compiler will do it for you. Of course, you could just clarify with a comment.

Are you pumping hot water or an antifreeze solution? Does hot water effect the life of a pump? Just for fun I ran 100' of pvc pipe from a faucet to the inlet of my hot water heater. I get enough hot water for a fairly good shower but it would work better if I could recirculate the water based on tank temperature. I was wondering how fancy you had to get with a pump.

I am basing my solar project on the "$1000 Solar hot water" at It is a drainback system, which means when water is not circulating, it all drains back to the tank (which of course must be lower than the collector). This means that normal water can be used, as no water remains in the collector if no heat is available, thus no risk of freezing. The pump I will be using is a Grundfos pump, which is a common pump for radiant floor heat, etc.

The pump I will be using is a Grundfos pump, which is a common pump for radiant floor heat, etc.

Ah, I see they use some exotic materials for the impeller which protects from corrosion. Thanks for the information.

I have completed my solar hot water project, and my arduino differential controller has been working great so far. Check out my system at

Now that your project is complete you might want put it in the Exhibition / Gallery section. You probably should mention this thread to avoid accusations of cross posting.