SurfBox Aquarium Controller - opensource

Andrewalex11

Reef Technology
View Badges
Joined
Jan 27, 2017
Messages
323
Reaction score
270
Rating - 0%
0   0   0
The SurfBox Project is an old dig-up of an older project that some of you may have seen before. This time the goals are different and the power/flexibility of the project itself is much greater.

I wanted to bring to the table a semi-finished realistic project this time that showed the validity of the concepts that I will discuss in further detail about the box. So far we have completed:

1.) Designed, and created all markup files needed to run a smooth and easy to use web-app.
2.) Created all web scripts. For this, I used a combination of jQuery and PHP.
3.) Created the Application Interface (API) using JSON.
4.) Engineered the core programming used for communication from device to web-app.
5.) Created module programs and circuits for Temperature and water level.
6.) Made a mount for probes, float switches, and dosing tubes.
7.) Implemented Auto-Top Off capabilities into the water level module.
8.) Moved server from localhost using Apache to Linux based web server service.
9.) Purchased and launched web-app on domain www.surfbox.xyz

I will make a few posts following this one discussing the problems I ran into and how I fixed them along the way.

Feel free to keep yourself updated by checking out the progression of the web-app at www.surfbox.xyz
 
OP
OP
Andrewalex11

Andrewalex11

Reef Technology
View Badges
Joined
Jan 27, 2017
Messages
323
Reaction score
270
Rating - 0%
0   0   0
Components I chose to use and why.

ESP32-S
I chose to use the 32-S module over the ESP8266 or other hard-wired ethernet options not only for its powerful WiFi capabilities, but it also doubles as a Bluetooth BLE module. The 32-S is an interesting and new module recently released and there is not much publicly shared about its Bluetooth functions
yet. The fact that it is built in though offers me the ability to release a firmware update that could modify anything to use Bluetooth in the future without having to change around any components. This is the board in particular that I am using: https://www.amazon.com/HiLetgo-ESP-WROOM-32-Development-Microcontroller-Integrated/dp/B0718T232Z

ATMEGA328P-PU

The ATMEGA328 is the standard microcontroller in most DIY projects as it comes standard with the Arduino Uno microcontroller development board. The reason why this is used with the ESP is mostly that of 1.) The new ESP32-S is still very buggy and is not compatible with a good amount of hardware. and 2.) The separate controller offers more room for I/O options.

DS18B20
This is just your standard waterproof temperature sensor that you can find almost anywhere online. I'm not a huge fan of the component itself but it gets the job done and can be easily used with the OneWire library.

Peristaltic Dosing Pump Head 12VDC
It's pretty obvious what these are being used for, but I am also using it as an ATO pump on my Nano Test-Tank.

4 Switch Relay Board
The 4 Switchboard will be used for the dosing pumps, connected to a separate 12VDC power supply. 3 Relay one for each dosing pump module head and the 4th relay is to run the ATO pump.
 
OP
OP
Andrewalex11

Andrewalex11

Reef Technology
View Badges
Joined
Jan 27, 2017
Messages
323
Reaction score
270
Rating - 0%
0   0   0
Here's a few shots of the board. And yes I am always nervous about the fact that I have open circuitry next to 20 gallons of water. I'll probably be doing some fun acrylic work soon and making a custom project box.

IMG_1530.JPG
IMG_1531.JPG
IMG_1533.JPG
IMG_1534.JPG
IMG_1535.JPG
 
OP
OP
Andrewalex11

Andrewalex11

Reef Technology
View Badges
Joined
Jan 27, 2017
Messages
323
Reaction score
270
Rating - 0%
0   0   0
Auto Top Off
The ATO was originally the only function that this device was going to have. I wanted to keep it simple but just couldn't resist adding more features after having great success with this module.

I am not aware of how most companies program/engineer in their failsafe functions but the one that the SurfBox uses, as far as I know, is very different. It enables the user of the box to save tons of money by only needing to buy one single float switch. It doesn't even need to be the most reliable or accurate. The reason being behind this is the built-in pre-operational checking software interface. The SurfBox will check your water level 101 times before allowing any water to be pumped into the aquarium, while of course every 10 milliseconds rechecking the water level during the fill.

The main check:

Code:
  WATER_LEVEL = digitalRead(waterLevel); // Initial Waterlevel check

  if (WATER_LEVEL == 1) {
    fill();
  }

The fill function is packed with logic based algorithmic functions to ensure that the sensor is literally 100 times sure that it is ready to add water to the aquarium.

Code:
byte fill() {

  WATER_LEVEL = digitalRead(waterLevel);

  if (WATER_LEVEL == 1) {  // Water level is low
   
    updateJSON("/touch.php?waterlevel=SENSING...");
    digitalWrite(led, LOW);

    for (int i = 0; i < 100; i++) { // Check the water level 100 times to ensure that it is                                                         //actually low, and not a false reading
      Serial.println("SENSING..." + String(i));
      WATER_LEVEL = digitalRead(waterLevel);
      if (WATER_LEVEL == 1) {
        delay(10);
      } else {  // If the water level reads full 1 out of the 100 times the program will return back to standby mode
        Serial.println("FULL");
        updateJSON("/touch.php?waterlevel=FULL");
        digitalWrite(ato_pump, LOW);
        digitalWrite(led, LOW);
        return 0;
      }
    }

    updateJSON("/touch.php?waterlevel=FILLING");
    boolean isLOW = true;
   
    while(isLOW) { // After passing all pre-operational checks the pumps will fill

      Serial.println("FILLING...");
      digitalWrite(ato_pump, HIGH);
      digitalWrite(led, HIGH);
      WATER_LEVEL = digitalRead(waterLevel);
      if (WATER_LEVEL == 1) {
        delay(10);
      } else { // Once the waterlevel no longer reads low the condition is flagged                                 // breaking the loop and returning the program to standby mode
        isLOW = !isLOW;
      }
    }
  }

The I/O is wired for the LED and Float switch as such:

Float Switch directly from 3.3V on the ESP32-S Dev Board to pin 23.
The LED is set on pin 22
And the ATO Pump signal is set on pin 15

The pumps:

The pump required a 12VDC output to run, so I had used a 2N2222A NPN transistor, and a relay board that uses LOW input as the trigger. When the ATO signal is sent to the trigger of the transistor it sets the K1 Relay rin to low clicking it on which allows current to pass through to the pump which is what fills the aquarium.
 
Last edited:
OP
OP
Andrewalex11

Andrewalex11

Reef Technology
View Badges
Joined
Jan 27, 2017
Messages
323
Reaction score
270
Rating - 0%
0   0   0
I will discuss what the updateJSON() function is later today. It's a really fun and useful concept that allows the program to update API's using any method that you feel comfortable with.
 
OP
OP
Andrewalex11

Andrewalex11

Reef Technology
View Badges
Joined
Jan 27, 2017
Messages
323
Reaction score
270
Rating - 0%
0   0   0
Update:

I will eventually like to create a sophisticated intelligence to manage my water temperature, and pH in order to do so I have to gain the closest values I can down to a precise floating point number. I have modified the temperature to take a value such as 81.25 and send it in a packet that can be unpacked and re-read to give the web app the most amount of raw data as possible for the sensors.

1.) The DS18B20 will take the raw data in the form of a floating point number lets say 81.25 degrees F.
2.) ATMEGA328 will then multiply this number per the amount of accuracy it wants to send, in this example, it will be to the 100th's place so we multiply by 100.
3.) The data will be packaged as a whole integer to splice off any floating points on the end of the number, so now we will have a number 8,125.
4.) The data gets sent to the web app like normal, and when it is received it will be stored but upon updating the physical page jQuery will divide the data by 100 to return it back to 81.25.

Why is this important?

1.) This saves time from having to parse special characters out of the URL when it is received by our PHP script.
2.) The ESP32-S and ESP8266 sometimes become confused when sending the raw data such as "81.25" through a URL variable pass and may return errors.
3.) Depending on how you have it set up you can easily change the accuracy of the probe itself in case you wanted to control up to the 100,000th+ of a decimal place of accuracy for your temperature controls.
 
OP
OP
Andrewalex11

Andrewalex11

Reef Technology
View Badges
Joined
Jan 27, 2017
Messages
323
Reaction score
270
Rating - 0%
0   0   0
IMG_1537.JPG


Got to working on some PCB designes tonight. This board will probably be manufactured sometime within the next week or so and serve as the official sbATO module!

The two connections at the top left corner of the board are for the floatswitch. I had left this unlabeled by mistake but after a few hours of PCB designing I don't mind it since I'm almost 100% sure that it won't be long before I develop an even more compact and efficient design.

I plan on creating lots of small modules like this one. Though I have my sensors going quite well I probably won't be making a PCB for them just yet. I really want to get the dosing pump and power outlet controller developed and on PCB's next. With all that being said there's a lot more programming and sleepless nights sitting over a breadboard ahead.
 
OP
OP
Andrewalex11

Andrewalex11

Reef Technology
View Badges
Joined
Jan 27, 2017
Messages
323
Reaction score
270
Rating - 0%
0   0   0
Here's your pinout for the ATO.

[IN] Receives the signal from the main controller to turn the pumps on or off.

[OUT] Sends the float switch signals to the controllers I/O

[SIGNAL] Used to switch relays that use a LOW voltage trigger by converting the [IN] signal from positive to negative.

If you were to use a relay with a HIGH voltage trigger the [IN] pin can be connected directly to the relay board of your choice.
 
OP
OP
Andrewalex11

Andrewalex11

Reef Technology
View Badges
Joined
Jan 27, 2017
Messages
323
Reaction score
270
Rating - 0%
0   0   0
Parts:

IND - Any LED will work I choose to use an ultra bright pink LED so I can clearly see the ATOs status from across the room

R1/R2 - 330 ohm Resistor

Q1 - 2N2222A Transistor

VCC - 3.3/5 volts

Float Switch
 
OP
OP
Andrewalex11

Andrewalex11

Reef Technology
View Badges
Joined
Jan 27, 2017
Messages
323
Reaction score
270
Rating - 0%
0   0   0
IMG_1538.PNG


If anyone wants help with the source code for the web app feel free to message me directly
 

Zephrant

Active Member
View Badges
Joined
Sep 14, 2017
Messages
111
Reaction score
75
Location
Spokane, WA
Rating - 0%
0   0   0
When one acrylic boxes would be great, you might consider 3D printed enclosures. Can embed the labels and logos, and make them look pretty fancy. Printed in PETG or ABS they are reef safe too.
 
OP
OP
Andrewalex11

Andrewalex11

Reef Technology
View Badges
Joined
Jan 27, 2017
Messages
323
Reaction score
270
Rating - 0%
0   0   0
Three MAJOR Changes to the SurfBox have been made and it is really starting to all come together nicely now!

Graphics!


A new GFX display has been made, and I'm ready to share with you all how it works!

Here is a short clip of some GFX displays that the device does so far
(Sorry for poor video quality)



This is a NeoPixel Ring (12 Count) using the Adafruit NeoPixel Library and my own custom logic. In order to make it simple to call different animations depending on what state the device is in I figured it would be much simpler to create small modules of each animation and give them addresses. I will now break down the code so you too can implement this into your own personal projects if you do so wish. There are tons of different kinds of NeoPixel break-out boards other than this ring, and the best part is you can wire the DATA_OUT and the DATA_IN together with them to create your own custom designs.

Code breakdown

So in order to utilize the same Library as me, you need to include the Adafruit_NeoPixel.h library.

Code:
#include <Adafruit_NeoPixel.h>

Next, you want to declare which pin you will be used to shift data out of to the breakout board, and you also need to declare how many pixels are available.

Code:
// Graphics //
#ifdef __AVR__
  #include <avr/power.h>
#endif
#define PIN            21
#define NUMPIXELS      12
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
byte brightness = 15;

If you notice the #ifdef __AVR__ will determine what kind of microcontroller is being used so the library uses the proper power reduction registers.

So that was all of our global variables and next is our setup.

Code:
// Graphics for ATtiny85
  #if defined (__AVR_ATtiny85__)
    if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  #endif

You do NOT need to include this in the setup unless you are in fact using an ATtiny85 Microcontroller. I include it in my setup for the sake of possibly driving my display off of one in the future.

After that, you just simply call
Code:
pixels.begin();
to initiate your NeoPixels.

This is where my custom logic really comes into play now.

First I created a void function with an argument of 1 Byte. This Byte will allow me to create 255 different animations to choose from. I do not anticipate on even coming close to that number of animations so this is a good way to save memory.

Code:
void gfxShow(byte b) {

}

Now that I have the function set up with an argument that is easily used by our logic we can go ahead and set up some sort of boolean statement to utilize the incoming byte as an address for different animations.

In short a Switch Case statement.

Code:
switch(b) {

 case 1:

 break;

case 2:

break;

// 255 Possible case statements

default:

break;

}

Now we can just toy around with some animations maybe on a separate development board (if you have one) To create some code for different animations. Then just stick it into one of our case statements and label it.

Heres the code for some of the animations you see in the video

Code:
// // // Graphics // // //
byte gfxShow(byte b) {

  switch(b) {
   
    case 1: // GFX Address 1 - Standby (WiFi Connected)
      for(int i = 1; i < brightness; i++)  {
        for(int j = 0; j < NUMPIXELS; j++) {
          pixels.setPixelColor(j, pixels.Color(0,i,0));
          delay(5);
        }
        pixels.show();
      }

      for(int i = brightness; i > 1; i--)  {
        for(int j = 0; j < NUMPIXELS; j++) {
          pixels.setPixelColor(j, pixels.Color(0,i,0));
          delay(5);
        }
       pixels.show();
      }
    break;

    case 2: // GFX Address 2 - Aquarium Filling
      for (int i = 0; i < NUMPIXELS; i++) {
        (i == 0) ? pixels.setPixelColor(11, pixels.Color(0,0,0)) : pixels.setPixelColor(i - 1, pixels.Color(0,0,0));
        pixels.setPixelColor(i, pixels.Color(brightness,0,brightness));
        pixels.show();
        delay(50);
      }
    break;

    case 3: // GFX Address 2 - Standby (WiFi Not Connected)
      for (int i = 0; i < NUMPIXELS; i++) {
        pixels.setPixelColor(i, pixels.Color(brightness,0,0));
        pixels.show();
        delay(1);
      }
    break;
   }
}
// // // End Graphics // // //

Last but not least to call a new animation is now very simple!

Let's say your Aquarium detected the water level was low and is now filling. We can just include the following code in whatever loop you have that fills and checks the water level to spin a single purple NeoPixel.

Code:
gfxShow(2);

Heres how I have it sitting in my code for reference

Code:
while(isLOW) {
      gfxShow(2);
      digitalWrite(ATO_PUMP, HIGH);
      if (digitalRead(FLOAT_SW) == 1) {
        delay(10);
      } else { 
        digitalWrite(ATO_PUMP, LOW);
        isLOW = !isLOW;
      }
}
 
OP
OP
Andrewalex11

Andrewalex11

Reef Technology
View Badges
Joined
Jan 27, 2017
Messages
323
Reaction score
270
Rating - 0%
0   0   0
Bug fixes!

I had a major bug that for some reason I was putting off for about almost 2 weeks now, but I finally got around to fixing it!

Issue #1: Failure to re-connect after a loss of connectivity.

When the module originally started it had connected to the network in the setup stage of the program, but this proved to be an issue as the connection was not volatile. If the internet had gone out for some reason then the device would have no way of knowing and the connection code was a run once type of deal. So, in the end, the slightest flicker of power to the router or internet, in general, that would cause a failure to connect initially would leave the device in an unstable mode of constantly timing out while attempting to reach the server.

The Fix!

The fix was simple I included a new byte value (Which probably should be boolean for memory saving) and called it netStatus. After that, I had removed the WiFi connection from the setup and created its own void function.

Here is the code:
Code:
// // // WiFi Connection Begin // // //
void netConnect() {
    int timeout = 30;
    Serial.println("Connecting to" + String(ssid));
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        gfxShow(4);
        --timeout;
        Serial.println(timeout);
        if (timeout == 0) {
          break;
        }
    }
    if (WiFi.status() == WL_CONNECTED) {
      netStatus = 1;
      Serial.println("Connected!");
    }
}
// // // WiFi Connection End // // //

I have also programmed a timeout into the WiFi connection, and I utilized the new GFX function to time it. 30 Spins at 600 milliseconds a piece leaves us with a total timeout time of 18,000 milliseconds, or 18 Seconds. This seems to be a good amount of time for a connection to take place, though if your internet is slower you could always adjust the timeout variable in the code to a higher number. Every single increment as discussed will add on another 600 milliseconds.

If the connection succeeds it will set the netStatus to TRUE or 1 which we can use later in a boolean statement. If it fails then FALSE or 0.

This is the main loop of the program and by saying if (netStatus) means if 1 it is true so execute the code inside, otherwise execute the else block.

Code:
void loop()
{
  if (netStatus) {
    gfxShow(1);
    atoPrgm();
    tempRead();
  } else {
    netConnect();
    atoPrgm();
    tempRead();
    gfxShow(3);
    delay(500);
  }
}

So now we can see that if it is connected then carry out the normal business that the SurfBox is programmed to do.

If it is not connected it will run in offline mode constantly taking 18 seconds out of its time to check and see if it can re-connect.

Conclusion: The SurfBox is now smart enough to know when the internet is on or off in the home and will run offline if needed. Without having to touch anything it will automatically connect itself to the network and resume updating the WebApp all on its own.

One less thing to worry about during a power failure :)
 
OP
OP
Andrewalex11

Andrewalex11

Reef Technology
View Badges
Joined
Jan 27, 2017
Messages
323
Reaction score
270
Rating - 0%
0   0   0
I just want to share with all of you my entire code for the physical device itself. There are PHP, HTML, jQuery, and CSS files to be shared as well and I will post those when I update the WebApp's API and dashboard.

Code for the SurfBox32 - ESP32-S DEV Module

Code:
/* SurfBox Project */
#include <Adafruit_NeoPixel.h>
#include <WiFi.h>

// Graphics //
#ifdef __AVR__
  #include <avr/power.h>
#endif
#define PIN            21
#define NUMPIXELS      12
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
byte brightness = 15;

// Declare Inputs / Outputs
#define INDICATOR 22
#define FLOAT_SW 23
#define ATO_PUMP 15

// WiFi & WebApp Parameters
char* ssid     = "FiOS-N9RHQ"; // SSID
char* password = "wig6182mend4950ann"; // Password
const char* host = "surfbox.xyz"; // WebApp DNS Name
byte netStatus = 0;

// Serial Data Variables
String readString;

void setup()
{
  // Graphics for ATtiny85
  #if defined (__AVR_ATtiny85__)
    if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  #endif

    // Initiate Graphics
    pixels.begin();
 
    // Initiate Outputs
    pinMode(INDICATOR, OUTPUT);
    pinMode(ATO_PUMP, OUTPUT);

    // Initiate Inputs
    pinMode(FLOAT_SW, INPUT);

    // Set All pumps to OFF
    digitalWrite(ATO_PUMP, LOW);

    // Connect to WiFi Network with ESP32S
    Serial.begin(115200);
}

// // // Graphics // // //
byte gfxShow(byte b) {

  switch(b) {
    
    case 1: // GFX Address 1 - Standby (WiFi Connected)
      for(int i = 1; i < brightness; i++)  {
        for(int j = 0; j < NUMPIXELS; j++) {
          pixels.setPixelColor(j, pixels.Color(0,i,0));
          delay(5);
        }
        pixels.show();
      }

      for(int i = brightness; i > 1; i--)  {
        for(int j = 0; j < NUMPIXELS; j++) {
          pixels.setPixelColor(j, pixels.Color(0,i,0));
          delay(5);
        }
       pixels.show();
      }
    break;

    case 2: // GFX Address 2 - Aquarium Filling
      for (int i = 0; i < NUMPIXELS; i++) {
        (i == 0) ? pixels.setPixelColor(11, pixels.Color(0,0,0)) : pixels.setPixelColor(i - 1, pixels.Color(0,0,0));
        pixels.setPixelColor(i, pixels.Color(brightness,0,brightness));
        pixels.show();
        delay(50);
      }
    break;

    case 3: // GFX Address 3 - Standby (WiFi Not Connected)
      for (int i = 0; i < NUMPIXELS; i++) {
        pixels.setPixelColor(i, pixels.Color(brightness,0,0));
        pixels.show();
        delay(1);
      }
    break;

    case 4: // GFX Address 4 - WiFi Attempting to connect
      for(int i=0;i<NUMPIXELS;i++)  {
        pixels.setPixelColor(i, pixels.Color(0,0,brightness));
        (i == 0) ? pixels.setPixelColor(11, pixels.Color(brightness,0,0)) : pixels.setPixelColor(i-1, pixels.Color(brightness,0,0));
        pixels.show();
        delay(50);
       }
    break;
   }
}
// // // End Graphics // // //

// // // WiFi Connection Begin // // //
void netConnect() {
    int timeout = 30;
    Serial.println("Connecting to" + String(ssid));
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        gfxShow(4);
        --timeout;
        Serial.println(timeout);
        if (timeout == 0) {
          break;
          Serial.println("Broken");
        }
    }
    if (WiFi.status() == WL_CONNECTED) {
      netStatus = 1;
      Serial.println("Connected!");
    }
}
// // // WiFi Connection End // // //

// // // API Update Program Begin // // //
void updateJSON(String phpPOST) {
  Serial.print("connecting to ");
  Serial.println(host);
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {
      Serial.println("connection failed");
      netStatus = 0;
      return;
  }
  String url = phpPOST;
  Serial.print("Requesting URL: ");
  Serial.println(url);
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                                      "Host: " + host + "\r\n" +
                                      "Connection: close\r\n\r\n");
  unsigned long timeout = millis();
  while (client.available() == 0) {
      if (millis() - timeout > 5000) { 
          Serial.println(">>> Client Timeout !");
          netStatus = 0;
          client.stop();
          return;
      }
  }
  while(client.available()) {
      String line = client.readStringUntil('\r');
      Serial.print(line);
  }
  Serial.println();
  Serial.println("closing connection");
}
// // // API Update Program End // // //

// // // Auto Top Off Program Begin // // //
byte atoPrgm() {
  if (digitalRead(FLOAT_SW) == 1) {
    updateJSON("/touch.php?waterlevel=SENSING...");
    digitalWrite(INDICATOR, LOW);

    for (int i = 0; i < 100; i++) {
      Serial.println("SENSING..." + String(i));
      if (digitalRead(FLOAT_SW) == 1) {
        delay(10);
      } else {
        updateJSON("/touch.php?waterlevel=FULL");
        digitalWrite(ATO_PUMP, LOW);
        digitalWrite(INDICATOR, LOW);
        return 0;
      }
    }
    updateJSON("/touch.php?waterlevel=FILLING");
    boolean isLOW = true;
    while(isLOW) {
      gfxShow(2);
      Serial.println("FILLING...");
      digitalWrite(ATO_PUMP, HIGH);
      digitalWrite(INDICATOR, HIGH);
      if (digitalRead(FLOAT_SW) == 1) {
        delay(10);
      } else {
        updateJSON("/touch.php?waterlevel=FULL");
        digitalWrite(ATO_PUMP, LOW);
        digitalWrite(INDICATOR, LOW);
        isLOW = !isLOW;
      }
    }
  }
}
// // // Auto Top Off Program End // // //

// // // Temperature Probe Program Begin // // //
byte tempRead() {
    while (Serial.available()) {
    delay(2);
    char c = Serial.read();
    readString += c;
  }
  if (readString.length() >0) {
    Serial.println(readString);
    int temp = readString.toInt();
    updateJSON("/touch.php?temps="+ String(temp));
    readString="";
    return 0;
  }
}
// // // Temperature Probe Program End // // //

void loop()
{
  if (netStatus) {
    gfxShow(1);
    atoPrgm();
    tempRead();
  } else {
    netConnect();
    atoPrgm();
    tempRead();
    gfxShow(3);
    delay(500);
  }
}

SurfBox Probes: Atmega328P-PU Micro-chip (Just modified version of OneWire DS18B20)

Code:
#include <OneWire.h>

OneWire  ds(6);

void setup(void) {
  Serial.begin(115200);
}

void loop(void) {
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius, fahrenheit;
 
  if ( !ds.search(addr)) {
    ds.reset_search();
    delay(250);
    return;
  }
  for( i = 0; i < 8; i++) {
  }

  if (OneWire::crc8(addr, 7) != addr[7]) {
      return;
  }
  switch (addr[0]) {
    case 0x10:
      type_s = 1;
      break;
    case 0x28:
      type_s = 0;
      break;
    case 0x22:
      type_s = 0;
      break;
    default:
      return;
  } 

  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1);
  delay(1000);
 
  present = ds.reset();
  ds.select(addr);   
  ds.write(0xBE);
  for ( i = 0; i < 9; i++) { 
    data[i] = ds.read();
  }
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3;
    if (data[7] == 0x10) {
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    if (cfg == 0x00) raw = raw & ~7;
    else if (cfg == 0x20) raw = raw & ~3;
    else if (cfg == 0x40) raw = raw & ~1;
  }
  celsius = (float)raw / 16.0;
  fahrenheit = celsius * 1.8 + 32.0;
  int toSend = fahrenheit * 100;
  Serial.println(int(fahrenheit * 100));
  delay(2000);
}
 

JackOMalley

Community Member
View Badges
Joined
Sep 2, 2018
Messages
33
Reaction score
74
Rating - 0%
0   0   0
This project looks awesome! (actually awesome enough to get me to finally make an account to respond)

I'm a controls engineer (10yrs) and saltwater enthusiast (6mo.) and I've been tinkering around with a similar idea.

Have you looked into integrating pH, Alk, ORP, or Ca monitoring to the platform? Either via an arduino shield or some fieldbus/network based interface?

Great job!
 
OP
OP
Andrewalex11

Andrewalex11

Reef Technology
View Badges
Joined
Jan 27, 2017
Messages
323
Reaction score
270
Rating - 0%
0   0   0
Yeah I will eventually be bringing this project back to life. It went offline when I had moved, some of the SurfBox didn’t survive unfortunately. Also I am a Computer Science / Math major going for a B.S. and I’m coming to the end of my degree program within the next 9-12 months so my workload has increased to the point where I’ve had to give up a lot of my spare time to my school work/internship work.

I’d say to expect an improved SurfBox to emerge sometime between February and March of next year.

Thanks for showing support for the project, I love the reef-pi a whole lot and lurk around reading about it all the time. Maybe we could link up and collaborate sometime in the future !
 

Ranjib

7500 Club Member
View Badges
Joined
Apr 16, 2016
Messages
9,843
Reaction score
17,058
Location
Pleasant Hill, Concord
Rating - 0%
0   0   0
Yeah I will eventually be bringing this project back to life. It went offline when I had moved, some of the SurfBox didn’t survive unfortunately. Also I am a Computer Science / Math major going for a B.S. and I’m coming to the end of my degree program within the next 9-12 months so my workload has increased to the point where I’ve had to give up a lot of my spare time to my school work/internship work.

I’d say to expect an improved SurfBox to emerge sometime between February and March of next year.

Thanks for showing support for the project, I love the reef-pi a whole lot and lurk around reading about it all the time. Maybe we could link up and collaborate sometime in the future !
Anytime :) send me pm and I’ll sync up with you . We have couple of other devs (mostly frontend) joined the maintainer group recently
 

High pressure shells: Do you look for signs of stress in the invertebrates in your reef tank?

  • I regularly look for signs of invertebrate stress in my reef tank.

    Votes: 42 32.6%
  • I occasionally look for signs of invertebrate stress in my reef tank.

    Votes: 29 22.5%
  • I rarely look for signs of invertebrate stress in my reef tank.

    Votes: 25 19.4%
  • I never look for signs of invertebrate stress in my reef tank.

    Votes: 33 25.6%
  • Other.

    Votes: 0 0.0%
Back
Top