Arduino Aquarium Controller

joopie

New member
I thought i would share what i have going so far for my aquarium. A few months back i purchased a 90 gallon tank with built in over flow. Since then i have been working on building the stand, canopy, and sump. Most of it is complete, i have been working with arduino and web server to setup the automation and control processes of the tank. Here is what i have so far...

http://www.rareglitch.net/overview.htm

Lets not try to break it or guess the password =)

So currently i have:
-automated control for the heater, with set point of 77.80 decreasing, resets at 78.20.
-auto top off via a solenoid and ultrasonic range finder.
-automated lights that get brighter/dimmer depending on the schedule i have set.
-cooling fans for LEDs will kick on at 85 and off at 80.
-ph probe

i am able to track and trend whatever i want on the web site.i am also able to control every process after inputting a password.
A quick explanation of how it works:

Inputs are provided to the arduino which processes the data and provides any outputs(relays,solenoids). The inputs/outputs are also sent to the web server via HTML get requests. The server process any incoming data with a php script and stores the data in a mysql database. The overview page pulls the data from the database and is displayed in tables and charts(charts from highcarts.com)

If anyone would like any more info or would like to see some code then let me know! i have had blast designing and building everything and cant wait to start filling up the tank/sump.
 

Attachments

  • IMG_20131027_194616_309.jpg
    IMG_20131027_194616_309.jpg
    38.9 KB · Views: 7
  • IMG_20131103_191033_573.jpg
    IMG_20131103_191033_573.jpg
    43.6 KB · Views: 7
  • IMG_20131103_191105_354.jpg
    IMG_20131103_191105_354.jpg
    47.3 KB · Views: 7
wow looks great would you share the code that makes all that happen for the website and the arduino
 
here is the arduino code... i have added a blocked=) to areas that i thought may compromise security of my fish tank. there are still plenty of ideas i'd like to add/fix, but here is what i have so far.


PHP:
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SPI.h>
#include <Ethernet.h>
#include <HttpClient.h>
#include <Time.h>  
#include <EthernetUdp.h>
#include <NewPing.h>

//PINS
#define PIN_TEMP 3 //Temp Probes 01,02,03+
#define PIN_RY_HEATER 22 //Relay for heater
#define PIN_RY_FAN_LEFT 24 //Relay for left fan
#define PIN_RY_FAN_RIGHT 26 //Relay for right fan
#define PIN_RY_LEVEL 28 //level relay
#define PIN_RY_DRAIN 30 //drain relay
#define PIN_RY_AUX 32 //aux relay
#define PIN_LED_WHITE 9 //LED_WHITE
#define PIN_LED_BLUE 8 //LED_BLUE
#define TRIGGER_PIN  11
#define ECHO_PIN     10
#define MAX_DISTANCE 200
#define amt 30
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); 



const int chipSelect = 4;

byte mac[] = { 
  0xDA, 0xAD, 0xBF, 0xEF, 0xFE, 0xED };
byte ip[] = {
  192,168,1,120};

OneWire oneWire(PIN_TEMP);
DallasTemperature sensors(&oneWire);

DeviceAddress Probe01 = { 
  0x28, 0x48, 0xA1, 0x5C, 0x04, 0x00, 0x00, 0x60 }; 
DeviceAddress Probe02 = { 
  0x28, 0xB3, 0x6B, 0x5C, 0x04, 0x00, 0x00, 0x75 };
DeviceAddress Probe03 = { 
  0x28, 0xF3, 0x14, 0x98, 0x04, 0x00, 0x00, 0x35 };
DeviceAddress Probe04 = { 
  0x28, 0x30, 0xE8, 0x1D, 0x05, 0x00, 0x00, 0x87 };
DeviceAddress Probe05 = { 
  0x28, 0x8E, 0xB2, 0xEF, 0x04, 0x00, 0x00, 0x66  };
DeviceAddress Probe06 = { 
  0x28, 0xAA, 0x1D, 0xEF, 0x04, 0x00, 0x00, 0x50  };
DeviceAddress Probe07 = { 
  0x28, 0x6D, 0x64, 0xEF, 0x04, 0x00, 0x00, 0xD4  };

//Time
IPAddress timeServer(132, 163, 4, 101); // time-a.timefreq.bldrdoc.gov
const int timeZone = -4;
EthernetUDP Udp;
unsigned int localPort = blocked=);
unsigned long CUR_MILLIS;
//String webServer = "blocked=)";
EthernetClient client;


//Alarms
boolean ALARM_LEVEL_HIGH = false;
boolean ALARM_LEVEL_LOW = false;
boolean ALARM_PH_HIGH = false;
boolean ALARM_PH_LOW = false;
boolean ALARM_TEMP_AVG_HIGH = false;
boolean ALARM_TEMP_AVG_LOW = false;

//Input Vars
float IN_TEMP_HEATER;  //probe 1
float IN_TEMP_RETURN;  //probe 2
float IN_TEMP_OVERFLOW; //probe 3
float IN_TEMP_ROOM; //probe 4
float IN_TEMP_TANK; //probe 7

float IN_LED_TEMP_LEFT; //probe 5
float IN_LED_TEMP_RIGHT; //probe 6

float IN_LED_BLUE = 5;
float IN_LED_WHITE = 5;

float IN_LEVEL_SUMP; //Sump water level
float IN_LEVEL_PH;

float TEMP_AVG;
int IN_HEATER_MODE = 2; // 0 - OFF, 1 - ON, 2 - AUTO
int IN_LED_FAN_MODE = 2; // 0 - OFF, 1 - ON, 2 - AUTO
int IN_LED_MODE = 2; // 0 - OFF, 1 - ON, 2 - AUTO
int IN_LEVEL_MODE = 2; //0 - OFF, 1 - ON, 2 - AUTO
int IN_AUX_MODE = 0; //0 - OFF, 1 - ON
int IN_LEVEL_DRAIN_MODE = 0; //0 - OFF, 1 - ON
int IN_LEVEL_PH_MODE = 1; //0 - STOP, 1 - CON,2-TEMP, 3 - CAL4, 4 - CAL7, 5 - CAL10, ...
int IN_LEVEL_PH_MODE_L = 0;

//OUTPUT Vars
boolean OUT_HEATER = false;
boolean OUT_LEFT_FAN = false;
boolean OUT_RIGHT_FAN = false;
boolean OUT_LEVEL = false;
//boolean OUT_LEVEL_DRAIN = false;
int OUT_LED_WHITE;
int OUT_LED_BLUE;
float OUT_LEVEL_SUMP;
//Setpoints
float SP_TEMP_RETURN = 77.80;
float SPR_TEMP_RETURN = 78.20;

float SP_TEMP_LED = 85.00;
float SPR_TEMP_LED = 80.00;

float SP_LEVEL = 11.00;
float SPR_LEVEL = 12.00;
//Ranges in minutes
int LED_WHITE_START = 720;
int LED_WHITE_END = 1200;
int LED_BLUE_START = 600;
int LED_BLUE_END = 1320;
int LED_MID = 960;

//led ranges
int BLUE_UP = 150;
int BLUE_LW = 19;
int WHITE_UP = 200;
int WHITE_LW = 19;
//sump ranges
float SUMP_RNG = 24;
String readString;
//frame delays
long PREV_MILLIS = 0;
long PREV_MILLIS1 = 0;
long PREV_MILLIS2 = 0;
long IN_DELAY = 1000; // 500ms framerate
long XMIT_DELAY = 5000; // 3s framerate
long REC_DELAY = 10000; // 10s framerate

boolean keep;
//ph stuff
#define avgSize 20
float phavg[avgSize];
int phRear=0;

float LVLavg[avgSize];
int LVLRear=0;

void QueueEnter(float queue[],float item,int *rear){
  if(*rear < avgSize)
  {
    queue[*rear]=item;
    *rear++;
  }else{
    *rear = 0;
  }

}
float getAVG(float queue[]){
  float avg;
  int count = 0;
  for(int i = 0;i < avgSize;i++){
    if(queue[i] != 0){
      avg += queue[i];
      count++;
    }
  }
  return avg / count;
}


void setup()
{
  Serial.begin(38400);
  Serial.println("Initializing...");
  Serial.print("PH Probe... ");
  Serial.println(startPH());
  Serial.print("Temperature Sensors... ");
  Serial.println(startTemp());
  Serial.print("Ethernet... ");
  Serial.println(startEthernet());
  Serial.print("Input/Outputs... ");
  Serial.println(startPins());
  Serial.print("Time Server... ");
  Serial.print(startTime());
  Serial.print(" ");
  Serial.println(getTime());
  Serial.print("Setting up Relays... ");
  Serial.println(startPins());
  Config("Password",blocked=));
  Config("Heater_Mode",IN_HEATER_MODE);
  Config("LED_Mode",IN_LED_MODE);
  Config("LED_Fan_Mode",IN_LED_FAN_MODE);
  Config("Level_Mode",IN_LEVEL_MODE);
  Config("Level_PH_Mode",IN_LEVEL_PH_MODE);
  Config("Level_Drain_Mode",IN_LEVEL_DRAIN_MODE);
  Config("AUX_Mode",IN_AUX_MODE);
}

void loop() 
{
  CUR_MILLIS = millis();
  if (CUR_MILLIS - PREV_MILLIS > IN_DELAY){
    PREV_MILLIS = CUR_MILLIS;
    Inputs();
    Process();
    Outputs();
  }
  if (CUR_MILLIS - PREV_MILLIS1 > XMIT_DELAY){
    PREV_MILLIS1 = CUR_MILLIS;

    XMIT();
  }
  if (CUR_MILLIS - PREV_MILLIS2 > REC_DELAY){
    PREV_MILLIS2 = CUR_MILLIS;
    RX();
  }
}

String getTime()
{
  String theTime;
  theTime.concat(month());
  theTime.concat("/");
  theTime.concat(day());
  theTime.concat("/");
  theTime.concat(year());
  theTime.concat(" ");
  theTime.concat(hour() - 1);
  theTime.concat(":");
  theTime.concat(minute());
  theTime.concat(":");
  theTime.concat(second());
  return theTime;
}

void XMIT(){
  Trender("TEMP_RETURN",IN_TEMP_RETURN);
  Trender("TEMP_HEATER",IN_TEMP_HEATER); 
  Trender("TEMP_OVERFLOW",IN_TEMP_OVERFLOW); 
  Trender("TEMP_TANK",IN_TEMP_TANK);
  Trender("TEMP_ROOM",IN_TEMP_ROOM);
  Trender("TEMP_AOUT_HEATER",OUT_HEATER?1.0f:0.0f);
  Trender("LED_ABLUE",map(OUT_LED_BLUE,BLUE_LW,BLUE_UP,0,100)); //grab in var to output in %
  Trender("LED_AWHITE",map(OUT_LED_WHITE,WHITE_LW,WHITE_UP,0,100)); //grab in var to output in %
  Trender("LED_XTEMP_LEFT",IN_LED_TEMP_LEFT);
  Trender("LED_XTEMP_RIGHT",IN_LED_TEMP_RIGHT);
  Trender("LED_FAN_LEFT",OUT_LEFT_FAN);
  Trender("LED_FAN_RIGHT",OUT_RIGHT_FAN);
  Trender("LEVEL_SUMP",IN_LEVEL_SUMP);
  Trender("LEVEL_FILL",OUT_LEVEL);
  Trender("LEVEL_XPH",IN_LEVEL_PH);
  Trender("LEVEL_DRAIN",IN_LEVEL_DRAIN_MODE);
  //Trender("LEVEL_AUX_MODE",IN_AUX_MODE);
  Trender("ALARM_LEVEL_HIGH",ALARM_LEVEL_HIGH);
  Trender("ALARM_LEVEL_LOW",ALARM_LEVEL_LOW);
  Trender("ALARM_PH_HIGH",ALARM_PH_HIGH);
  Trender("ALARM_PH_LOW",ALARM_PH_LOW);
  Trender("ALARM_TEMP_AVG_HIGH",ALARM_TEMP_AVG_HIGH);
  Trender("ALARM_TEMP_AVG_LOW",ALARM_TEMP_AVG_LOW);
}
void Trender(String table,float value){
  if (client.connect("blocked=)", blocked=)))
  {
    client.print("GET /blocked=)");
    client.print(table);
    client.print("&value=");
    client.println(value);

  }
  client.flush();
  client.stop();
  client.flush();
}
void RX(){
  if (client.connect("blocked=)",blocked=)))
  {
    client.println("GET /blocked=)");
    client.println();
  }
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (c == '!') {
          client.stop();
        }
        readString += c; 
      }
    }
    parseString(readString);
    readString = "";
  }
  client.flush();
  client.stop();
  client.flush();
}
void parseString(String str){
  keep = true;
  int offset = 0;
  while(keep){
    int start = str.indexOf('#',offset) + 1;
    int mid = str.indexOf('@',offset);
    int finish = str.indexOf('$',offset);
    int endloop = str.indexOf('!');
    offset = finish + 1;
    String name = str.substring(start,mid);
    float value = strTofloat(str.length(),str.substring(mid + 1,finish));
    setInput(name,value);
    if(offset == endloop){
      str = "";
      keep = false; 
    }
  }

}
void setInput(String name,float value){
  if(name == "Heater_Mode"){
    IN_HEATER_MODE = (int)(value);
  }
  else if(name == "LED_Mode"){
    IN_LED_MODE = (int)(value);
  }
  else if(name == "LED_Fan_Mode"){
    IN_LED_FAN_MODE = (int)(value);
  }
  else if(name == "LED_Blue"){
    IN_LED_BLUE = (int)(value);
  }
  else if(name == "LED_White"){
    IN_LED_WHITE = (int)(value);
  }
  else if(name == "Password"){

  }
  else if(name == "Level_Mode"){
    IN_LEVEL_MODE = (int)(value);
  }
  else if(name == "Level_PH_Mode"){
    IN_LEVEL_PH_MODE = (int)(value);
  }
  else if(name == "Level_Drain_Mode"){
    IN_LEVEL_DRAIN_MODE = (int)(value);
  }
  else if(name == "AUX_Mode"){
    IN_AUX_MODE = (int)(value);
  }
  else{
    Serial.println("INVALID ARGS PASSED TO SETINPUT");
    keep = false;
  }
}
void Config(String setting,float value){
  if (client.connect("blocked=)",blocked=)))
  {
    client.print("GET /blocked=)");
    client.print(setting);
    client.print("&value=");
    client.println(value);

  }
  client.flush();
  client.stop();
  client.flush();
}
boolean startTime()
{
  Udp.begin(localPort);
  setSyncProvider(getNtpTime);
  return true;
}
boolean startPH(){
  Serial3.begin(38400);
  delay(2000);
  return true;
}

boolean startPins()
{
  pinMode(PIN_RY_HEATER,OUTPUT);
  digitalWrite(PIN_RY_HEATER,HIGH); //off
  pinMode(PIN_RY_FAN_LEFT,OUTPUT);
  digitalWrite(PIN_RY_FAN_LEFT,HIGH); //off
  pinMode(PIN_RY_FAN_RIGHT,OUTPUT);
  digitalWrite(PIN_RY_FAN_RIGHT,HIGH); //off
  pinMode(PIN_RY_LEVEL,OUTPUT);
  digitalWrite(PIN_RY_LEVEL,HIGH); //off
  pinMode(PIN_LED_WHITE,OUTPUT);
  pinMode(PIN_LED_BLUE,OUTPUT);
  pinMode(PIN_RY_DRAIN,OUTPUT);
  digitalWrite(PIN_RY_DRAIN,HIGH); //off
  pinMode(PIN_RY_AUX,OUTPUT);
  digitalWrite(PIN_RY_AUX,HIGH); //off
  return true;
}
boolean startTemp()
{
  sensors.begin();
  
  sensors.setResolution(Probe01, 12);
  sensors.setResolution(Probe02, 12);
  sensors.setResolution(Probe03, 12);
  sensors.setResolution(Probe04, 12);
  sensors.setResolution(Probe05, 12);//left led
  sensors.setResolution(Probe06, 12);//right led
  sensors.setResolution(Probe07, 12);//tank
  if (sensors.getDeviceCount() > 0){
    return sensors.getDeviceCount();
  }
  else{
    return false;
  }
}

boolean startEthernet(){
  Ethernet.begin(mac,ip);

  server.begin();
  return true;
}
void Alarms(){
  if(IN_LEVEL_SUMP > 15){
    ALARM_LEVEL_HIGH = true;
  }else{
    ALARM_LEVEL_HIGH = false;
  }
  
  if(IN_LEVEL_SUMP < 8){
    ALARM_LEVEL_LOW = true;
  }else{
    ALARM_LEVEL_LOW = false;
  }
  
  if(IN_LEVEL_PH > 9){
    ALARM_PH_HIGH = true;
  }else{
    ALARM_PH_HIGH = false;
  }
  
  if(IN_LEVEL_PH < 7.6){
    ALARM_PH_LOW = true;
  }else{
    ALARM_PH_LOW = false;
  }
  
  if(TEMP_AVG > 82){
    ALARM_TEMP_AVG_HIGH = true;
  }else{
    ALARM_TEMP_AVG_HIGH = false;
  }
  
  if(TEMP_AVG < 76){
    ALARM_TEMP_AVG_LOW = true;
  }else{
    ALARM_TEMP_AVG_LOW = false;
  }
}

void Inputs()
{
  sensors.requestTemperatures();
  IN_TEMP_HEATER = getTemp(IN_TEMP_HEATER,Probe01);
  IN_TEMP_RETURN = getTemp(IN_TEMP_RETURN,Probe02);
  IN_TEMP_OVERFLOW = getTemp(IN_TEMP_OVERFLOW,Probe03);
  IN_TEMP_ROOM = getTemp(IN_TEMP_ROOM,Probe04);
  IN_LED_TEMP_LEFT = getTemp(IN_LED_TEMP_LEFT,Probe05);
  IN_LED_TEMP_RIGHT = getTemp(IN_LED_TEMP_RIGHT,Probe06);
  IN_TEMP_TANK = getTemp(IN_TEMP_TANK,Probe07);
  IN_LEVEL_SUMP = readLevel();
  IN_LEVEL_PH = PHProcess(IN_LEVEL_PH_MODE);
}

void Process()
{
  OUT_HEATER = Controller(IN_TEMP_RETURN,SP_TEMP_RETURN,SPR_TEMP_RETURN,true,IN_HEATER_MODE,OUT_HEATER); //Heater controller 
  OUT_LEFT_FAN = Controller(IN_LED_TEMP_LEFT,SP_TEMP_LED,SPR_TEMP_LED,false,IN_LED_FAN_MODE,OUT_LEFT_FAN); //Left LED Fan
  OUT_RIGHT_FAN = Controller(IN_LED_TEMP_RIGHT,SP_TEMP_LED,SPR_TEMP_LED,false,IN_LED_FAN_MODE,OUT_RIGHT_FAN); //Right LED Fan
  OUT_LED_WHITE = LEDController(map(IN_LED_WHITE,0,100,WHITE_LW,WHITE_UP),IN_LED_MODE,"white"); // white led controller
  OUT_LED_BLUE = LEDController(map(IN_LED_BLUE,0,100,BLUE_LW,BLUE_UP),IN_LED_MODE,"blue"); //blue led controller
  OUT_LEVEL = Controller(IN_LEVEL_SUMP,SP_LEVEL,SPR_LEVEL,true,IN_LEVEL_MODE,OUT_LEVEL); //Heater controller 
  TEMP_AVG = (IN_TEMP_RETURN + IN_TEMP_OVERFLOW + IN_TEMP_TANK) / 3;
  Alarms();
}
float PHProcess(int mode){ //0 - STOP, 1 - CON,2-TEMP, 3 - CAL4, 4 - CAL7, 5 - CAL10, 6 - CALD4,7 - CALD7,8 - CALD10
  if(mode != IN_LEVEL_PH_MODE_L){
    switch(mode){
    case 0:
      Serial3.print("E\r\r");
      delay(1000);
      break;
    case 1:
      Serial3.print("C\r\r");
      delay(1000);
      break;
    case 2:
      Serial3.print(toC(IN_TEMP_RETURN));
      Serial3.print("\r\r");
      delay(1000);
      break;
    case 3:  //ph 4 
      Serial3.print("F\r\r");
      Config("LEVEL_PH_MODE",6);
      break;
    case 4: //ph 7
      Serial3.print("S\r\r");
      Config("LEVEL_PH_MODE",7);
      break;
    case 5: //ph 10
      Serial3.print("T\r\r");
      Config("LEVEL_PH_MODE",8);
      break;
    }
  }
  IN_LEVEL_PH_MODE_L = mode;
  return readPH();
}


int LEDController(int IN_LED,int mode,String color){
  if (mode == 0){  //Off
    return 0;
  }
  else if(mode == 1){  //On
    return IN_LED;
  }
  else{ //auto
    int minNow = ((hour() - 1) * 60) + minute();
    if(minNow <= LED_BLUE_START){ //0-10
      return 0; 
    }
    else if(minNow >= LED_BLUE_END){//22-24
      return 0;
    }
    else if(minNow >= LED_BLUE_START && minNow <= LED_WHITE_START && color == "blue"){ //10-12 blue only
      return map(minNow,LED_BLUE_START,LED_WHITE_START,BLUE_LW,BLUE_UP);
    }
    else if(minNow >= LED_BLUE_START && minNow <= LED_WHITE_START && color == "white"){ //10-12 white
      return 0; 
    }
    else if(minNow >= LED_WHITE_START && minNow <= LED_MID && color == "blue"){ //12-16 blue
      return map(minNow,LED_WHITE_START,LED_MID,BLUE_UP,BLUE_LW);
    }
    else if(minNow >= LED_WHITE_START && minNow <= LED_MID && color == "white"){ //12-16 white
      return map(minNow,LED_WHITE_START,LED_MID,WHITE_LW,WHITE_UP);
    }
    else if(minNow >= LED_MID && minNow <= LED_WHITE_END && color == "blue"){ //16-20 blue
      return map(minNow,LED_MID,LED_WHITE_END,BLUE_LW,BLUE_UP);
    }
    else if(minNow >= LED_MID && minNow <= LED_WHITE_END && color == "white"){ //16-29 white
      return map(minNow,LED_MID,LED_WHITE_END,WHITE_UP,WHITE_LW);
    }
    else if(minNow >= LED_WHITE_END && minNow <= LED_BLUE_END && color == "blue"){ // 20-22 blue
      return map(minNow,LED_WHITE_END,LED_BLUE_END,BLUE_UP,BLUE_LW);
    }
    else if(minNow >= LED_WHITE_END && minNow <= LED_BLUE_END && color == "white"){ // 20-22 blue
      return 0;
    }
    else{
      return 0;
    }
  }
}

boolean Controller(float input,float sp,float rst,boolean dec,int mode,boolean output){ 

  if (mode == 0){  //Off
    return false;
  }
  else if(mode == 1){  //On
    return true;
  }
  else{  //Auto
    if(dec){
      if(input < sp){
        return true;
      }
      else if(input > rst){
        return false;
      }
      else{
        return output;
      }

    }
    else{
      if(input > sp){
        return true;
      }
      else if(input < rst){
        return false;
      }
      else{
        return output;
      }
    }

  }
}
void Outputs(){
  digitalWrite(PIN_RY_HEATER,!OUT_HEATER); //Invert output for relay
  digitalWrite(PIN_RY_FAN_LEFT,!OUT_LEFT_FAN);
  digitalWrite(PIN_RY_FAN_RIGHT,!OUT_RIGHT_FAN);
  digitalWrite(PIN_RY_LEVEL,!OUT_LEVEL);
  digitalWrite(PIN_RY_DRAIN,!IN_LEVEL_DRAIN_MODE);
  digitalWrite(PIN_RY_AUX,!IN_AUX_MODE);
  analogWrite(PIN_LED_WHITE,OUT_LED_WHITE);
  analogWrite(PIN_LED_BLUE,OUT_LED_BLUE);
}

float getTemp(float last,DeviceAddress deviceAddress)
{
  float temp = sensors.getTempF(deviceAddress);
  if(temp < 0){
    return last;
  }
  else{
    return temp;
  }
}


float readLevel(){
  float average;
  float samples[amt];
  for (int i=0; i< amt; i++) {
    float uS = sonar.ping();
    float dist = uS / US_ROUNDTRIP_IN;
    samples[i] = dist;
    delay(30);
  }
  average = 0;
  for (int i=0; i< amt; i++) {
    average += samples[i];
  }
  
  average /= amt;
  QueueEnter(LVLavg,SUMP_RNG - average,&LVLRear);
  return getAVG(LVLavg);
}
float lastPH;
float readPH(){
  String PHSTR = "";
  while(Serial3.available()){
    char inchar = (char)Serial3.read();                            
    PHSTR += inchar;                                         
    if(inchar == '\r') {
      float phCheck = strTofloat(PHSTR.length(),PHSTR);
      if(phCheck > 14 || phCheck < 0){
        return lastPH;
      }
      else{
        float phCorrected;
        if(phCheck >= 7){
          phCorrected = mapfloat(phCheck,7.00,10.20,7.00,10.00);
        }
        else{
          phCorrected = mapfloat(phCheck,3.70,7.00,4.00,6.99);
        }
        lastPH = phCorrected; 
        QueueEnter(phavg,phCorrected,&phRear);
        Serial.println("");
        Serial.println(phCorrected);
        Serial.println(getAVG(phavg));
        return getAVG(phavg);
      }
    }       
  }
}
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
float strTofloat(int chars,String str){
  char floatbuf[chars];
  str.toCharArray(floatbuf,sizeof(floatbuf));
  float value = atof(floatbuf);  
}
float toC(float temp){
  return (temp - 32) * (5/9);
}

/*-------- NTP code ----------*/

const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets

time_t getNtpTime()
{
  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  // Serial.println("Transmit NTP Request");
  sendNTPpacket(timeServer);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      // Serial.println("Receive NTP Response");
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
    }
  }
  Serial.println("No NTP Response :-(");
  return 0; // return 0 if unable to get the time
}

// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address)
{
  // 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(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}
 
would you please share the html files?? or email them to me I would like to start using this very soon
 
you replaced your local ip and password with blocked=) did you also replace a FQDN also with blocked=)
 
i don't believe i replaced a FQDN with blocked... I block out some URLs for the get requests. Showing the way i have the get request set up for the trender function would allow anyone to insert data into my data tables. I'm sure what i have going is not very secure but seems to be ok so far... I am going to add interlocks so that if someone was able to gain access they wouldn't be able to do much. I just hard code it so that the sump level will never drain below x inches, or fill over x inches. same with heater, and lighting. So the main page is generated from a couple of php files and javascript for the charts.AJAX makes server calls to update the server without refreshing. here are some example links of how i get the tables:

http://www.rareglitch.net/getTables.php?tables=TEMP_%
http://www.rareglitch.net/getTables.php?tables=LED_%
http://www.rareglitch.net/getTables.php?tables=LEVEL_%

if you guys know of,or find any vulnerabilities id hope you would let me know =). i hope my code will help, and i will try to answer any questions. I am no web developer, i just took the time to learn and understand what to do and piece it all together. as far as charting please see http://www.highcharts.com/. i used the highstock for plotting my points. It needs a json output to load the points. here is the json output of the temp_return table: http://www.rareglitch.net/get_json.php?&table=TEMP_RETURN



php file to generate the tables and format the table names and data to be more appealing:

PHP:
<?php
include_once('connect.php');
$tables = $_GET['tables'];
$query = "SHOW TABLES LIKE '".$tables."'";
$result = mysql_query($query,$connect);
$out = "<table border='.5'>";
$out .= "<tr bgcolor='#9ACDFD'>";
$out .= "<td>Last Update:</td>";
$first = mysql_fetch_row($result);
$result = mysql_query($query,$connect);
while($row = mysql_fetch_row($result)){
	$out .= "<td bgcolor='".getColor($row[0])."'>".getName($row[0])."</td>";
}
$out .= "</tr>";
$out .= "<tr>";
$dateQRY = "SELECT Date FROM ".$first[0]." ORDER BY Date DESC LIMIT 1";
$dateResult = mysql_query($dateQRY,$connect);
$out .= "<td>" .mysql_fetch_array($dateResult)[0] . "</td>";

$query = "SHOW TABLES LIKE '".$tables."'";
$result = mysql_query($query,$connect);
while($row = mysql_fetch_row($result)){
	$iquery = "SELECT Value FROM ".$row[0]." ORDER BY Date DESC LIMIT 1";
	$iresult = mysql_query($iquery,$connect);
	$out .= "<td>" . formatData($row[0],mysql_fetch_array($iresult)[0]) . "</td>";
}
$out .= "</tr>";
$out .= "</table>";
echo $out;

function getColor($tablename){

	switch($tablename){
	case "TEMP_AOUT_HEATER":
		return "red";
		break;
	case "TEMP_HEATER":
		return "royalblue";
		break;
	case "TEMP_OVERFLOW":
		return "green";
		break;
	case "TEMP_RETURN":
		return "yellow";
		break;
	case "TEMP_ROOM":
		return "cyan";
		break;
	case "LED_ABLUE":
		return "royalblue";
		break;
	case "LED_XTEMP_LEFT":
		return "lightgray";
		break;
	case "LED_XTEMP_RIGHT":
		return "lightgray";
		break;
	case "TEMP_TANK":
		return "pink";
		break;

	default:
		return "white";
		break;
	}
}
function getName($tablename){

	switch($tablename){
	case "TEMP_AOUT_HEATER":
		return "Heater Status";
		break;
	case "TEMP_HEATER":
		return "Heater Temp";
		break;
	case "TEMP_OVERFLOW":
		return "Overflow Temp";
		break;
	case "TEMP_RETURN":
		return "Return Temp";
		break;
	case "TEMP_ROOM":
		return "Room Temp";
		break;
	case "LED_ABLUE":
		return "Blue LEDs";
		break;
	case "LED_AWHITE":
		return "White LEDs";
		break;
	case "LED_XTEMP_LEFT":
		return "Left LEDs";
		break;
	case "LED_XTEMP_RIGHT":
		return "Right LEDs";
		break;
	case "TEMP_TANK":
		return "Tank Temp";
		break;
	case "LED_FAN_LEFT":
		return "Left Fan";
		break;
	case "LED_FAN_RIGHT":
		return "Right Fan";
		break;
	case "LEVEL_FILL":
		return "Fill Status";
		break;
	case "LEVEL_SUMP":
		return "Sump Level";
		break;
	case "LEVEL_XPH":
		return "PH Level";
		break;
	case "LEVEL_DRAIN":
		return "Drain Status";
		break;
	case "ALARM_LEVEL_HIGH":
		return "Level High Alarm";
		break;
	case "ALARM_LEVEL_LOW":
		return "Level Low Alarm";
		break;
	case "ALARM_PH_HIGH":
		return "PH High";
		break;
	case "ALARM_PH_LOW":
		return "PH Low";
		break;
	case "ALARM_TEMP_AVG_HIGH":
		return "AVG Temp High";
		break;
	case "ALARM_TEMP_AVG_LOW":
		return "AVG Temp Low";
		break;
	default:
		return $tablename;
		break;
	}
}
function formatData($table,$data){
	switch($table){
	case "LED_FAN_RIGHT":
	case "LED_FAN_LEFT":
	case "LEVEL_FILL":
	case "TEMP_AOUT_HEATER":
	case "LEVEL_DRAIN":
		switch($data){
		case 1:
			return "On";
			break;
		case 0:
			return "Off";
			break;
		default:
			return $data;
			break;
		}
		break;
	case "LED_AWHITE":
	case "LED_ABLUE":
		if($data <= 0){
			return "Off";
			break;
		}else{
			return $data . "%";
			break;
		}
	case "ALARM_LEVEL_HIGH":
	case "ALARM_LEVEL_LOW":
	case "ALARM_PH_HIGH":
	case "ALARM_PH_LOW":
	case "ALARM_TEMP_AVG_HIGH":
	case "ALARM_TEMP_AVG_LOW":
		switch($data){
		case 1:
			return "<center>ALARM</center>";
			break;
		case 0:
			return "<center>GOOD</center>";
			break;
		default:
			return $data;
			break;
		}
	default:
		return $data;
		break;
	}
}

connect.php
PHP:
<?php
//CONNECT.PHP

$hostname = "blocked";
$database = "blocked";
$username = "blocked";
$password = "blocked";

if(!$connect = mysql_connect($hostname,$username,$password,$database)){
	die('FAILED TO CONNECT' . mysql_error());
}
$bool = mysql_select_db($database,$connect);
if(!$bool){
 die('FAILED DB SELECT' . mysql_error());
}
?>

json file to convert mysql table into json for charting:
PHP:
<?php
include_once('connect.php');
$table = $_GET['table'];

if($table == "blocked"){
	$qry = "SELECT * FROM ".$table;
	$result = mysql_query($qry,$connect);
	while($row = mysql_fetch_array($result)){
		if($row['Setting'] == "blocked"){

		}else{

		
		echo "#" . $row['Setting'];
		echo  "@" . $row['Value'] . "$";
	}
	}
	echo "!";

}else{
	$shorten = false;
	$count = 3;
	$start = 0;
	$qry = "SELECT * FROM ".$table." ORDER BY Date ASC";
	$result = mysql_query($qry,$connect);
	if(mysql_num_rows($result) > 100000 & mysql_num_rows($result) < 200000){
		$shorten = true;
		$count = 5;
	}elseif(mysql_num_rows($result) > 200000){
		$shorten = true;
		$count = 10;
	}else{
		$shorten = false;
	}
	while($row = mysql_fetch_array($result)){
		$dates = strtotime($row['Date']) * 1000;
		switch($table){
			case "TEMP_AOUT_HEATER":
				$values = ((float)$row['Value'] * 5) + 85.00;
				break;
			case "LED_FAN_LEFT":
			case "LED_FAN_RIGHT":
				$values = ((float)$row['Value'] * 5) + 80.00;
				break;
			case "LEVEL_FILL":
				$values = ((float)$row['Value'] * 5) + 5.00;
				break;
			case "LED_ABlUE":
			case "LED_AWHITE":
				$values = ((float)$row['Value'] * .1) + 0.00;
			default:
				$values = (float)$row['Value'];
				break;
		}
		if($shorten){
			if($start == $count){
				$array[] = array($dates,$values);
				$start = 0;
			}else{
				$start++;
			}
		}else{
			$array[] = array($dates,$values);
		}
	}
	echo json_encode($array);
}
?>
overview site:
PHP:
<!DOCTYPE HTML>
<html>
	<head>
		<meta ***********="Content-Type" content="text/html; charset=utf-8">
		<link rel="icon" type="icon" href="1_fish.ico"/>
		<link rel="shortcut icon" type="icon" href="1_fish.ico"/>
		<title>Fish Tank</title>
		
		
	</head>
	<body bgcolor="grey">

******** type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
******** type="text/javascript">
<!-- 
//Browser Support Code
if(screen.width <=699){
   document.location = "http://www.rareglitch.net/lite.htm";
}
function ajaxAlarm(){
   var ajaxRequest;  // The variable that makes Ajax possible!
   
   try{
      // Opera 8.0+, Firefox, Safari
      ajaxRequest = new XMLHttpRequest();
   } catch (e){
      // Internet Explorer Browsers
      try{
         ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
      } catch (e) {
         try{
            ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
         } catch (e){
            // Something went wrong
            alert("Your browser broke!");
            return false;
         }
      }
   }
   // Create a function that will receive data sent from the server
   ajaxRequest.onreadystatechange = function(){
      if(ajaxRequest.readyState == 4){
         var ajaxDisplay = document.getElementById('ajaxAlarm');
         ajaxDisplay.innerHTML = ajaxRequest.responseText;
      }
   }
   ajaxRequest.open("GET", "getTables.php?&tables=ALARM_%", true);
   ajaxRequest.send(null); 
}
function ajaxLED(){
	var ajaxRequest;  // The variable that makes Ajax possible!
	
	try{
		// Opera 8.0+, Firefox, Safari
		ajaxRequest = new XMLHttpRequest();
	} catch (e){
		// Internet Explorer Browsers
		try{
			ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try{
				ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e){
				// Something went wrong
				alert("Your browser broke!");
				return false;
			}
		}
	}
	// Create a function that will receive data sent from the server
	ajaxRequest.onreadystatechange = function(){
		if(ajaxRequest.readyState == 4){
			var ajaxDisplay = document.getElementById('ajaxLED');
			ajaxDisplay.innerHTML = ajaxRequest.responseText;
		}
	}
	ajaxRequest.open("GET", "getTables.php?tables=LED_%", true);
	ajaxRequest.send(null); 
}
function ajaxTemp(){
	var ajaxRequest;  // The variable that makes Ajax possible!
	
	try{
		// Opera 8.0+, Firefox, Safari
		ajaxRequest = new XMLHttpRequest();
	} catch (e){
		// Internet Explorer Browsers
		try{
			ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try{
				ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e){
				// Something went wrong
				alert("Your browser broke!");
				return false;
			}
		}
	}
	// Create a function that will receive data sent from the server
	ajaxRequest.onreadystatechange = function(){
		if(ajaxRequest.readyState == 4){
			var ajaxDisplay = document.getElementById('ajaxTemp');
			ajaxDisplay.innerHTML = ajaxRequest.responseText;
		}
	}
	ajaxRequest.open("GET", "getTables.php?tables=TEMP_%", true);
	ajaxRequest.send(null); 
}
function ajaxLevel(){
   var ajaxRequest;  // The variable that makes Ajax possible!
   
   try{
      // Opera 8.0+, Firefox, Safari
      ajaxRequest = new XMLHttpRequest();
   } catch (e){
      // Internet Explorer Browsers
      try{
         ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
      } catch (e) {
         try{
            ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
         } catch (e){
            // Something went wrong
            alert("Your browser broke!");
            return false;
         }
      }
   }
   // Create a function that will receive data sent from the server
   ajaxRequest.onreadystatechange = function(){
      if(ajaxRequest.readyState == 4){
         var ajaxDisplay = document.getElementById('ajaxLevel');
         ajaxDisplay.innerHTML = ajaxRequest.responseText;
      }
   }
   ajaxRequest.open("GET", "getTables.php?tables=LEVEL_%", true);
   ajaxRequest.send(null); 
}
function ajaxCFG(password){
	var ajaxRequest;  // The variable that makes Ajax possible!
	
	try{
		// Opera 8.0+, Firefox, Safari
		ajaxRequest = new XMLHttpRequest();
	} catch (e){
		// Internet Explorer Browsers
		try{
			ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try{
				ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e){
				// Something went wrong
				alert("Your browser broke!");
				return false;
			}
		}
	}
	// Create a function that will receive data sent from the server
	ajaxRequest.onreadystatechange = function(){
		if(ajaxRequest.readyState == 4){
			var ajaxDisplay = document.getElementById('ajaxCFG');
			ajaxDisplay.innerHTML = ajaxRequest.responseText;
			
		}
	}
	//var pass = document.getElementById("pass").value;
	ajaxRequest.open("GET", "blocked, true);
	ajaxRequest.send(); 


}
function updateConfig(name,value){
	var ajaxRequest;  // The variable that makes Ajax possible!
	
	try{
		// Opera 8.0+, Firefox, Safari
		ajaxRequest = new XMLHttpRequest();
	} catch (e){
		// Internet Explorer Browsers
		try{
			ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try{
				ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e){
				// Something went wrong
				alert("Your browser broke!");
				return false;
			}
		}
	}
	// Create a function that will receive data sent from the server
	//ajaxRequest.onreadystatechange = function(){
	//	if(ajaxRequest.readyState == 4){
	//		var ajaxDisplay = document.getElementById('ajaxCFG');
	//		ajaxDisplay.innerHTML = ajaxRequest.responseText;
	//	}
	//}
	ajaxRequest.open("GET","blocked, true);
	ajaxRequest.send(null); 
}
ajaxAlarm();
ajaxLevel();
ajaxTemp();
ajaxLED();

ajaxCFG(document.getElementById("pass"));

//window.setInterval("loadChart()",3000);
window.setInterval("ajaxTemp()",5000);
window.setInterval("ajaxLED()",5000);
window.setInterval("ajaxLevel()",5000);
window.setInterval("ajaxAlarm()",5000);
window.setInterval("ajaxCFG(document.getElementById('pass').value)",5000);
</script>
<table border="0" width="100%">
<tr align="center"><td><div id ='ajaxAlarm'></div></td></tr>
</table>
<table border="0" width="100%">

<tr align="center"><td><div id ='ajaxTemp'></div></td><td><div id ='ajaxLED'></div></td></tr>
<tr align="center"><td><iframe src="chart_Temp.htm" frameborder="0" width="100%" height="320"></iframe></td><td><iframe src="chart_LED.htm" frameborder="0" width="100%" height="320"></iframe></td></tr>
<tr align="center"><td valign="bottom"><form>Password:<input type="password" id="pass"></form></td><td><div id ='ajaxLevel'></div></td></tr>
<tr align="center"><td valign="top"><div id ='ajaxCFG'></div></td><td><iframe src="chart_Level.htm" frameborder="0" width="100%" height="320"></iframe></td></tr></table>



</div>	</body>
</html>
 
Joopie, thanks for sharing your code and actual internet view of your program! It has given me a lot of ideas for my new project!
 
Wow, this is awesome! Thanks for sharing!

Glancing at your code, it seems that you are using an analog output instead of PWM. Is that correct? If so, what is the max output voltage, and what drivers are you using with it? Also, which Arduino board are you using?
 
I'm using an arduino mega. The analogwrite is outputing a 0-5v pwm, see http://arduino.cc/en/Reference/analogWrite

im using a transistor and seperate 10v power source to up it to 0-10v pwm.
here is a good example:http://arduino-for-beginners.blogspot.com/2011/04/controlling-12v-fan-speed-with-pwm.html

the led drivers i have are the Mean Well ELN-60-48P dimmable driver:
http://www.rapidled.com/mean-well-eln-60-48p-dimmable-driver/

they are nice but they cut out at ~15%, so i recommend going with the Mean Well ELN-60-48D dimmable driver that cut out around 5%.
 
Good to know. I'm planning to use the LDD-L drivers, which allow a 0~2.5V analog input for dimming OR a 0~2.6+V PWM input. When using the analog dimming mode, the LED's dim range is something like 20%-100%, so thinking about using PWM for the high power LED strings, and analog for the low power LED strings.
 
I'm sure there is a better way but this works well for me since i'm usually loading the site off the lan.
 
Back
Top