Hot water system datalogger

hey guys, I'm reposting this from the old forum (It didn't process that I'd have to move it over... d'oh). here's the link to the original: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1295845813

and here's the original text:

Hey guys, I just thought I'd post my largest sketch yet (11714 bytes :D) that I've written that both compiles and does what I want. you know, probably. I haven't tested it in the field yet, but initial reports come back good! I put it into all different tabs, so I guess I'll paste one below the other? ah well.

Also, I'll let you know that I commented the code for the first time especially for this, I wouldn't have otherwise. :slight_smile:
As I commented it, I noticed some stuff that could be better (bottom/top factoring etc) so I changed it, so no promises that it'll work. I'll also end up putting the methods' code into the loop rather than call them once each time, I just did that to keep it nice and neat.

Anyway, the purpose of this is to monitor my house's hot water system. We have some solar collectors up on the roof that heat our water with a backup regular heating element if it's cloudy for a couple days or something. I (my dad) thought it would be fun to monitor the system, see when stuff is on & off, see what temperature it is, and it would be so easy to do w/ arduino right? anyway, a year and a bit later, here's the finished code, fingers crossed. What it does is connects to a flash drive with a VDIP1 module and logs the times when two heat pumps and a heating element turn on and off and also logs the temperatures of two water pipes every five minutes. The heat pumps are both at 24VAC so I threw a diode in line with each (I might make a full wave rectifier if I feel like being productive) and voltage dividers to step it down. I'll probably end up changing it from a digitalRead to an analogRead because it'll pick up the AC better. The heating element is 240VAC so I just stuck a cell charger in there that brings it down to 5v and I'm reading that. I'm using two LM35s for the temperatures with the same setup as I wrote in a playground page a while back... Arduino Playground - LM35HigherResolution , basically just using internal analog reference.

I found that working with Strings with the VDIP1 generally saved my some headaches, so that's why they're all over the place in the code. I dunno if they actually make it better, but it gave me better results. Also, let me say something about the VDIP1. I HATE IT. IT'S THE WORST. I picked up electronics about a year and a half ago and the VDIP1 has definitely been the most infuriating part of it. If you're going to go with datalogging, I'd go with an SD card or something, just because the VDIP1 is so darn picky in my experience.

phew! Comments, questions, feedback, etc? After all this work, I'd like some sort of validation from people who know more than zip about programming, from my fam it's just "oh that's nice all those little brackets and stuff"

[edit] code to follow, I've exceeded the maximum length.

NewSoftSerial mySerial(3, 4); // serial w/ the VDIP1 module

boolean state = LOW; //State of heating element
boolean state1 = LOW; // state of heat pump 1
boolean state2 = LOW; // state of heat pump 2
boolean stateElem = LOW; //pretty sure this one is the previous state of the heating element
int previous = 0; // previous logtime, it goes every five minutes for the temperatures
boolean LED_STATE = LOW; //not used anymore I don't think but left in anyway

int pPin1 = 11; //heat pump 1
int pPin2 = 12; // heat pump 2
int tPin1 = 0; // temp 1
int tPin2 = 1; // temp 2
int elementPin = 10; //you can guess this one

//int RTSpin = 9;
// RTS may be implemented later when it screws up for lack of handshaking :)

void setup()
{
  pinMode(pPin1, INPUT); //you can guess these
  pinMode(pPin2, INPUT);
  pinMode(elementPin, INPUT);  
  pinMode(13, OUTPUT); //LED pin if I want it
  
  Serial.begin(9600); //for debugging/monitoring
  
  mySerial.begin(9600); //connection to the VDIP1 module
  mySerial.print("IPA"); //tell it I want to work in ASCII
  mySerial.print(13, BYTE);
  Serial.println("Setupdone"); //the standard feedback line
  analogReference(INTERNAL); // I use the internal for higher resolution w/ the LM35s, see my playground page
}

void loop()
{
  int incoming = 0;
  if (Serial.available()) {incoming = Serial.read();} // receive incoming data from the computer
  
  if (incoming =='1')
  {
    mySerial.print("DIR"); //tell the VDIP1 to spit out everything on the usb disk
    mySerial.print(13, BYTE);
    incoming = '0';
  }  

if(incoming == '2') // print out all the states of the pins
{

  Serial.print(digitalRead(pPin1));
  Serial.print(",");
  Serial.print(digitalRead(pPin2));
  Serial.print(",");
  Serial.print(digitalRead(elementPin));
  Serial.print(",");
  Serial.print(analogRead(tPin1));
  Serial.print(",");
  Serial.print(analogRead(tPin2));
  Serial.print("   ");
  Serial.println(getTime());
  incoming = '0';
  
}


  while (mySerial.available()) { // spits back responses from VDIP1 to computer.
    char letter = (char)mySerial.read();
    if(letter == '>')
    Serial.println(letter);
    else
    Serial.print(letter);
  }
  
  temps();
  element();
  heatPumps();
  
//  digitalWrite(13, LED_STATE);

}

String getTemp(int pin)
{
  int reading;
  for(int i = 0;i<10;i++) // average the readings to get rid of noise
  {
    reading += analogRead(pin);
  }
  reading = (float)reading / 93.1;
  String temp = String(reading, DEC);
  return temp;
}

String getTime() // Strings FTW
{
  String time = String(month());
  time = time.concat("/");
  time = time.concat(day());
  time = time.concat("/");
  time = time.concat(year());
  time = time.concat(" ");
  time = time.concat(hour());
  time = time.concat(":");
  if(minute() < 10)
  {
    time = time.concat("0"); // for format like 9:05 instead of 9:5
  }
  time = time.concat(minute());
  return time;
}

void timeStamp(String time) // used for timestamping data sent to VDIP1
{
  mySerial.print("WRF ");
  mySerial.print(time.length() + 2);
  mySerial.print(13, BYTE);
  mySerial.print(" ");
  mySerial.print(time);
  mySerial.print(13, BYTE);
}
boolean readAC(int pin) // I have to see if a half-rectified AC wave is present
{
  for(int i = 0;i< 20;i++)
  {
    if(digitalRead(pin) == HIGH)
    {
      return HIGH;
    }
    else
    {
      delay(1);
    }
  }
  return LOW;
}

String dToS(double x) // changing a double to a string
{
  int y = ((int)x)*10000; // I probably could have used % here but I didn't know it when I wrote this
  int z = (10000*x) - y;
  String foo = String(y/10000);
  foo = foo.concat(".");
  foo = foo.concat(z);
  return foo;
}

boolean readDigital(int pin) // make sure it's not noise, I KNOW THIS IS A BAD NAME I DON'T CARE
{
  boolean vals[10]; // I did this because it would register when I just touched the arduino for some reason.
  for(int i = 0; i < 10; i++)
  {
    vals[i] = digitalRead(pin);
    delay(100);
  }
  for(int i = 0;i < 10; i++)
  {
    if(vals[i] == LOW)
    {
      return LOW;
    }
  }
  return HIGH; // only return high if all of the readings over a second are high
}

void element()
{
  state = readDigital(elementPin); // note the readDigital, not digitalRead
  if(state != stateElem) // if the state changed from before
  {
    // LED_STATE = !LED_STATE;
    mySerial.print("OPW ELEMENT.TXT"); //logging data
    mySerial.print(13, BYTE);
    if(state == HIGH)
    {
      mySerial.print("WRF 5");
      mySerial.print("On at");
      timeStamp(getTime());
      stateElem = true;
     }
  
    if(state == LOW)
    {
      mySerial.print("WRF 6");
      mySerial.print("Off at");
      timeStamp(getTime());
      stateElem = false;
     }
     mySerial.print("CLF ELEMENT.TXT");
     mySerial.print(13, BYTE);
     Serial.print("element!   ");
     Serial.println(minute());
  }
}


void heatPumps()
{
  
  state = readAC(pPin1);
  
  if(state != state1)
  {
 //   LED_STATE = !LED_STATE;
  mySerial.print("OPW HEATPUMP1.TXT");
  mySerial.print(13, BYTE);
  
  if(state == HIGH)
  {
    mySerial.print("WRF 5");
    mySerial.print("On at");
    timeStamp(getTime());
    state1 = true;
  }

  if(state == LOW)
  {
    mySerial.print("WRF 6");
    mySerial.print("Off at");
    timeStamp(getTime());
    state1 = false;
   }
  
   mySerial.print("CLF HEATPUMP1.TXT");
   mySerial.print(13, BYTE);
  
   Serial.print("heatpumps!   ");
   Serial.println(minute());

  }
  
  state = readAC(pPin2);

  if(state != state2)
  {
  //  LED_STATE = !LED_STATE;
    mySerial.print("OPW HEATPUMP2.TXT");
    mySerial.print(13, BYTE);
    
    if(state == HIGH)
    {
      mySerial.print("WRF 5");
      mySerial.print("On at");
      timeStamp(getTime());
      state2 = true;
    }
    if(state == LOW)
    {
     mySerial.print("WRF 6");
     mySerial.print("Off at");
     timeStamp(getTime());
     state2 = false;
     }
     mySerial.print("CLF HEATPUMP2.TXT");
     mySerial.print(13, BYTE);
    
     Serial.print("heatpumps!   ");
     Serial.println(minute());
  }
}

void temps()
{
  if(minute() - previous >=5)
  {
   String temp1= dToS(analogRead(tPin1) / 9.31); // convert voltage to temperature
   String temp2= dToS(analogRead(tPin2) / 9.31); // see my playground page

   mySerial.print("OPW TEMPS.TXT");
   mySerial.print(13, BYTE);
   mySerial.print("WRF ");
   mySerial.print(temp1.length()+temp2.length()+1);
   mySerial.print(13, BYTE);
   mySerial.print(temp1);
   mySerial.print(",");
   mySerial.print(temp2);
   previous = minute();
   timeStamp(getTime());
   mySerial.print("CLF TEMPS.TXT");
   mySerial.print(13, BYTE);
   Serial.print("temps!   ");
   Serial.println(String(minute()));
  }

G'Day Kevinsa5
If you only got started in electronics 18 months ago I am impressed. Some time back you asked about VDIP1 / VDRIVE2. I have used VDRIVE2 and found it more or less easy after I had stopped making stupid errors. Did you have a particular reason for using the VDIP1?
It seems there is now a dedicated SD device available but I'm not too sure I would trust it in the real world.
Keep up the good work.
Peter

Thanks!

Did you have a particular reason for using the VDIP1?

nope. XD I think there might have been more information on the internet at the time regarding the VDIP1, but I'm not sure.

I've seen a lot of SD card projects, but the datalogger wasn't for me and the flashdrive was considered more user-friendly. I wish I had gone with it now, but it's no big deal. I guess if I ever use USB storage in a future project I'll go with the VDRIVE2.

I'd actually like to clarify, once I found a bit of code that worked, it was very consistent as long as you gave it adequate time to boot up (which varies for some reason). It was just getting the code to work and then adapting it to my project that took a lot of effort. Sometimes it seemed like making a change in the code completely unrelated to the flash drive would cause it to lock up and I'd have to go through the process of unplugging power, transfer the flashdrive to the computer, look and see if it worked, and then reverse it all.

Thanks again!