Project showcase
Solar Water Tank Regulator

Solar Water Tank Regulator © GPL3+

I use an electric valve, temperature sensors with WiFi connectivity to control and monitor optimal usage of solar energy.

  • 3,490 views
  • 8 comments
  • 11 respects

Components and supplies

A000066 iso both
Arduino UNO & Genuino UNO
×1
Ed01 09 0049 a 600x6001  23921.1539128511
Maxim Integrated DS18B20 Programmable Resolution 1-Wire Digital Thermometer
×1
Esp12e
Espressif ESP8266 ESP-12E
OEM module; https://www.aliexpress.com/item/ESP8266-ESP-12E-UART-WIFI-Wireless-Shield-Development-Board-Module-For-Arduino-UNO-R3-Mega-3/32657998941.html?spm=a2g0s.9042311.0.0.8VdeO5
×1
Relay (generic)
generic 2 way relay
×1
motorized ball valve
×1

Apps and online services

About this project

I have a water tank that is heated by solar energy. I found out that as the tank is filled with hot water during day light, it looses energy and getting cold during the night.

I have connected a 3 temperature sensors:

  • measure incoming water
  • measure outgoing water
  • measure water tank water

If incoming water are hotter than outgoing water - the tank is getting hotter - the valve should open. If outgoing water are hotter than incoming water - the tank is getting cooler - the valve should close. The valve should be closed anyway during the night.

The ESP module is used for for time synchronization with NTP and to monitor the system state - temperature and valve state. The Esp module is powered by the Arduino though best practices advice external power. Anyway - narduino power worked well and stable for me.

Code

ValveControl_0.4_BetaC/C++
the whole code. you should add WiFiEsp.h, OneWire.h, DallasTemperature.h libraries.
#include <WiFiEsp.h>
#include <WiFiEspClient.h>
#include <WiFiEspUdp.h>

/********************************************************************/
// First we include the libraries
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into pin 2 on the Arduino
#define ONE_WIRE_BUS 2
// 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);
/********************************************************************/


/********************************************************************/
/*wifi configuration*/
// Emulate Serial1 on pins 6/7 if not present
#ifndef HAVE_HWSERIAL1
#include "SoftwareSerial.h"
SoftwareSerial Serial1(6, 7); // RX, TX
#endif
char ssid[] = "amar";            // your network SSID (name)
char pass[] = "asafnoa15";        // your network password
int status = WL_IDLE_STATUS;     // the Wifi radio's status
String apiKey = "P7GPWQYR14DXAOWU";
char server[] = "api.thingspeak.com";

char timeServer[] = "asia.pool.ntp.org";  // NTP server - time.nist.gov
unsigned int localPort = 2390;        // local port to listen for UDP packets

const int NTP_PACKET_SIZE = 48;  // NTP timestamp is in the first 48 bytes of the message
const int UDP_TIMEOUT = 5000;    // timeout in miliseconds to wait for an UDP packet to arrive

byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets



// A UDP instance to let us send and receive packets over UDP
WiFiEspUDP Udp;
/********************************************************************/
WiFiEspClient client;

/*valve configuraiton:*/
//int8_t valve_open_pin = 10; //in1 in the relay
//int8_t valve_close_pin = 11; //in2 in the relay
//int8_t is_closed_pin = 12; //red
//int8_t is_open_pin = 9; //green
#define valve_open_pin  (10UL) //in1 in the relay, YELLOW
#define valve_close_pin  (11UL) //in2 in the relay, BLUE
#define is_closed_pin  (12UL) //red
#define is_open_pin  (9UL) //green
/*black to GND*/
#define close_time (18UL)
#define open_time (7UL)
/*******************/

/*datetime configuration:*/
unsigned  long update_timestamp = 0;
unsigned  long new_time = 0;
int years = 0;
int8_t month = 0;
int8_t day = 0;
int8_t hours = 0;
int8_t minutes = 0   ;
int8_t seconds = 0;
// macros from DateTime.h


/*function declartion*/
//bool led_flag = false;
void rotateValve(bool state);
void    writeTime();
void   updateValveIndicator ();
int checkValveState();
void calculateValveState ();
void time(long val);
void sendNTPpacket(char *ntpSrv);
void print_temp ();
unsigned long update_time();
void send_temp ();
void send_data (String data);
/********************/


void setup() {
  // put your setup code here, to run once:

  client.flush();
  Serial.begin(9600); // Start up the dallas library
  sensors.begin(); // initialize serial for ESP module
  Serial1.begin(9600); // initialize ESP module
  WiFi.init(&Serial1);
  if (WiFi.status() == WL_NO_SHIELD) {//Serial.println("WiFi shield not present");
  }

  // attempt to connect to WiFi network
  while ( status != WL_CONNECTED) {
    //Serial.print("connect to WPA SSID: ");
    //Serial.println(ssid);
    // Connect to WPA/WPA2 network
    status = WiFi.begin(ssid, pass);
  }

  // you're connected now, so print out the data
  //Serial.println("You're connected to the network");
  //setup pins states
  pinMode(valve_open_pin, OUTPUT);
  pinMode(valve_close_pin, OUTPUT);
  digitalWrite(valve_open_pin, HIGH); //LOW
  digitalWrite(valve_close_pin, HIGH); //LOW
  pinMode(is_closed_pin, INPUT_PULLUP);
  pinMode(is_open_pin, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
  /***************************/

}

void loop()
{
  Udp.begin(localPort);
  Serial.println("loop...");
  Udp.flush();
  
  unsigned  long ntptime = update_time ();
  Serial.print("ntptime:");
  Serial.println(ntptime);

  if (ntptime > 0)
  { update_timestamp = millis();
    new_time = ntptime;
    time(new_time) ;
  }
  else {
    time(new_time + (millis() - update_timestamp) / 1000  ) ;
  }
  delay (5000);

  Udp.stop();

  calculateValveState();

  String data ="field6=";
  data += checkValveState();
  send_data (data);
  
delay(15000);
  //writeTime();
  send_temp ();
  //print_temp ();
  delay(10000);
}


void rotateValve(bool state)
{
  long start_at = millis();
  if (state == 1)
  { digitalWrite (valve_close_pin, HIGH); //LOW
    while (checkValveState() != 1) { //valve is not fully open
      digitalWrite (valve_open_pin, LOW); //HIGH
      if (start_at < millis() - 6000) break;
    }
    
    digitalWrite (valve_open_pin, HIGH); //LOW
  }
  else if (state == 0)
  {
    { digitalWrite (valve_open_pin, HIGH); //LOW

      while (checkValveState() != 2) { //valve is not fully closed
        digitalWrite (valve_close_pin, LOW); //HIGH
        if (start_at < millis() - 6000) break;
      }
 
      digitalWrite (valve_close_pin, HIGH); //LOW
    }
  }

}


/*void  updateValveIndicator ()
{
  if ( checkValveState() == 1 && (seconds % 2) == 0 ) ////valve is fully opened
  {
    digitalWrite (LED_BUILTIN, HIGH);
  }
  else if (checkValveState() == 2 && (seconds % 4) == 0 ) //valve is closed
  {
    digitalWrite (LED_BUILTIN, HIGH);
  }
  else {
    digitalWrite (LED_BUILTIN, LOW); //valve is half opened
  }
}*/

int checkValveState()
{

  int is_open = digitalRead(is_open_pin) ;
  int is_closed = digitalRead(is_closed_pin) ;

  if (is_open == LOW && is_closed == HIGH) ////valve is fully opened
  { //Serial.println("valve is fully opened");
    return 1;
  }
  else if (is_open == HIGH && is_closed == LOW) //valve is closed
  { //Serial.println("valve is fully closed");
    return 2;
  }
  else {
    //Serial.println("valve is in the middle");
    return 0; //valve is half opened
  }

}


void calculateValveState ()
{ Serial.println("calculateValveState");
  writeTime();
  Serial.print("valve state:");
  Serial.println(checkValveState());

print_temp ();
if (years < 2018 || sensors.getTempCByIndex(0) == - 127.00 || sensors.getTempCByIndex(0) == 85.00 || sensors.getTempCByIndex(1) == - 127.00 || sensors.getTempCByIndex(1) == 85.00 || sensors.getTempCByIndex(2) == - 127.00 || sensors.getTempCByIndex(2) == 85.00) //clock or temp is misscalcultaed
{ Serial.println ("misscalculatoin"); rotateValve(1);} //open valve

  else
  {
  if (checkValveState() != 1 && ((sensors.getTempCByIndex(0) > sensors.getTempCByIndex(1) -5 ) && (hours < close_time && hours > open_time )))
  { Serial.print(" valve is openging...");
    rotateValve(1); //open valve
  }
  else if (checkValveState() != 2  && ((sensors.getTempCByIndex(1) > sensors.getTempCByIndex(0)+5) || (hours > close_time|| hours < open_time)))
  { Serial.print(" valve is closing...");
    rotateValve(0);//close valve
  }
}

  
}


void time(unsigned long val) {
  //Serial.print ("the val in time:");
  //Serial.println (val);
  hours = (val  % 86400L) / 3600 + 3; //the +3 for IL time
  minutes = (val % 3600) / 60;
  seconds  = val % 60;
  years = (val / 31536000UL) +1970 ;
  //month = val % 31536000UL / (60*60*24);
  
}

void writeTime()
{

  Serial.print("arduino time:");
  Serial.print(hours);
  Serial.write(":");
  Serial.print(minutes);
  Serial.write(":");
  Serial.print(seconds);
  Serial.write(",");
  Serial.print(years);
  Serial.write(",");  
  Serial.print(month);
  Serial.write(",");  
    Serial.print(day);
  Serial.write(",");  
  Serial.print(checkValveState());
  Serial.write(",");
}

// send an NTP request to the time server at the given address
void sendNTPpacket(char *ntpSrv)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)

  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(ntpSrv, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();

}

unsigned long update_time()
{
  //calculate time
  //Serial.println("updateingTime");
  sendNTPpacket(timeServer); // send an NTP packet to a time server
  // wait for a reply for UDP_TIMEOUT miliseconds
  unsigned long startMs = millis();
  while (!Udp.available() && (millis() - startMs) < UDP_TIMEOUT) {}
  //Serial.println(Udp.parsePacket());
  if (Udp.parsePacket()) {
    //Serial.println("update_time.packet received");
    // We've received a packet, read the data from it into the buffer
    Udp.read(packetBuffer, NTP_PACKET_SIZE);

    // the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, esxtract the two words:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    //Serial.print("Seconds since Jan 1 1900 = ");
    //Serial.println(secsSince1900);

    // now convert NTP time into everyday time:
    Serial.print("Unix time = ");
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL;
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;
    // print Unix time:
    //Serial.println(epoch);

    return epoch;
  }

  return 0;
}

void print_temp () {
  // call sensors.requestTemperatures() to issue a global temperature
  // request to all devices on the bus
  Serial.print("Request temp.");
  sensors.requestTemperatures(); // Send the command to get temperature readings
  //Serial.println("DONE");
  Serial.print("Tempe0: ");
  Serial.println(sensors.getTempCByIndex(0)); //intake
  Serial.print("Tempe1: ");
  Serial.println(sensors.getTempCByIndex(1)); //outtake
  Serial.print("Tempe2: ");
  Serial.println(sensors.getTempCByIndex(2)); //tank
  /********************************************************************/
}

void send_temp () {
    String data = "";
    for (int i = 0; i < 3; i++) {
      data += "field";
      data += i + 1;
      data += "=";
      data += sensors.getTempCByIndex(i);
      if (i < 2) {
        data += "&";
      }
    }
    data += "&field4=";
    data += hours;
    data += "&field5=";
    data += minutes;
    Serial.println (data);
    send_data (data);
  }


void send_data (String data) {
  //Serial.println("Starting connection to thingspeak...");
      //Serial.print("\ndata in send_data:");
    //Serial.println(data);
  // if you get a connection, report back via serial
  if (client.connect(server, 80)) {
    //Serial.println("Connection to thingspeak succeed");
    String postStr = apiKey;
    postStr += "&";
    postStr += data;
      //Serial.print("/npostStr in send_data:");
    //Serial.println(postStr);
    client.print("POST /update HTTP/1.1\nHost: api.thingspeak.com\nConnection: close\nX-THINGSPEAKAPIKEY: " + apiKey + "\nContent-Type: application/x-www-form-urlencoded\nContent-Length: ");
    client.print(postStr.length());
    client.print("\n\n");
    client.print(postStr);

  }
  //Serial.println("printing response--------------------");
  while (client.available()) {
    char c = client.read();
    Serial.write(c);
  }
  //Serial.println("end of printing response--------------------");

  delay (3000);
  client.flush();
  client.stop();

  //Serial.println("client stopped");

}

Schematics

circuit diagram
wire t up
valve_control_rD92oyNxYC.fzz

Comments

Similar projects you might like

Arduino Controlled Smart Hydroponic Modular System

Project in progress by Luis Antonio Martin Nuez

  • 9,103 views
  • 2 comments
  • 61 respects

Easy IOT Water Leakage Indicator

Project tutorial by Patel Darshil

  • 9,183 views
  • 2 comments
  • 13 respects

How To Use DS18B20 Water Proof Temperature Sensor

Project showcase by Team IoTBoys

  • 35,608 views
  • 11 comments
  • 15 respects

Hot Water Solar Boiler Project

Project in progress by Pleemans

  • 5,626 views
  • 2 comments
  • 25 respects

Solar Charged Battery Powered Arduino Uno

Project in progress by Igor Fonseca Albuquerque

  • 60,674 views
  • 46 comments
  • 124 respects

Water Quality Monitoring and Notification System

Project showcase by emmanuel ani

  • 50,629 views
  • 38 comments
  • 112 respects
Add projectSign up / Login