Showing posts with label Technical. Show all posts
Showing posts with label Technical. Show all posts

Grow Bed Controller Coming to Tracker

You asked and we delivered - the first of the new distributed controllers is coming to Tracker:  the Grow Bed Controller.  Unlike the Aquaponics Controller, where the grow beds needed to be above the fish tank, the new Tank Controller and Grow Bed Controllers are intended for distributed systems, where the grow beds are a distance away.


Arduino Aquaponics: Grow Bed Controller
Grow Bed Shield.

A number of enhancements have been made.
  • The new ambient light sensor can calculate LUX to a high degree of accuracy with functions to prevent sensor saturation.
  • A new Ethernet board has been integrated to reduce costs and footprint of the original Ethernet Shield.  It uses the same chip as the Arduino Ethernet Shield means you can use the standard Ethernet library, thus no software change.
  • The on-board real-time clock now uses a bigger battery that can last around 20 years.
In addition, the kit itself has changed.  This will be a shield kit only (it comes with all sensors); you will need to provide your own Arduino Mega/ Mega equivalent - a highly demanded feature considering the price difference between official Megas vs SainSmarts and others.  Additionally, there will not be any mains electrical wiring & outlet combo for the 20-amp relay, in order to both extend to international client requirements and to not limit your wiring options (15-amp vs 20-amp wiring and outlets).

Grow Bed Controller features:

  • Tracker key
  • Ethernet
  • Grow Light control, 20-amp relay
  • Ambient Light (LUX)
  • Air Temperature
  • Relative Humidity
  • Waterproof Root Temperature
  • On-board real-time-clock (RTC) with battery backup to keep time if power is lost.






Staggered Growth


A square foot garden can produce a surprising amount in a small space and those growing the ingredients for the secret family spaghetti sauce will naturally plant the box so they can harvest everything at once.   This a great practice when canning or preserving, but it does not translate so well to aquaponics.   After all, aquaponic plants aren't just a delight on the senses (I'm eyeing you dill), but also contribute to solid filtration and, of course, nitrate absorption;   in other words, they serve a critical role in the balance of the ecosystem.

Seeking to maximize the growing season, gardener's will already have seedlings ready to transplant in empty garden cells.   While you may view this as a bit zealous, this practive of staggered growth, alternating the timing of your transplants, is almost a necessity to maintaining balance in your aquaponics system.   As your fish age, ammonia production steadily increases, requiring an equally increasing ability to remove nitrate.   Look at the example below, where there is a small grow bed with three large plants and one small spinach, all of which are assumed to be fully mature.   Please note that these scenarios and their corresponding data are entirely fictitious and were chosen for conceptual purposes.














The nitrate data shows that over the course of 10 days, the four plants are keeping the nitrates relatively in check.




Shift the slider above to the right to simulate the removal of a spinach plant.   You will see that in the days after the removal of the spinach, you get get a small, yet perceptible, bump in the nitrate levels.   This is as you would expect from a small plant, despite the spinach being a nitrogen hog.   What is important to note is that the remaining plants are still holding the nitrate levels reasonably steady.

If you replay the scenario, but instead harvest the tomato, squash and cucumber, you are left with a lowly spinach to handle the volume of nitrate produced.   Again, slide the toggle below the red chart to the right.




As expected, the change in the nitrate readings is more dramatic.   Not only is the spinach unable to make up for the loss of its companions, but the difference begins to compound on itself.   The excess nitrates from yesterday are added to the new batch produced today and so on.

Staggered planting and maintaining a good ratio of small to large plants is key to avoiding this situation and is easily done by tracking plant ages.   The grow bed below is much like the situation above, where the tomato, squash and cucumber are all nearing their harvest date together, eventually leaving a small spinach to pick up the nitrate absorption slack.   In this case, I paid attention to staggering when I planted my grow bed, but I did not account for the growing cycle of each plant, hence all of my large plants are done around the same time.


Managing staggered growth is critical to maintaining a system balance and is easy to do when you account for harvest periods and plant sizes.


Interactive Lessons


It seems every introduction to aquaponics begins the same way:   stating the environment of an aquaponics system is a compromise between the ideal preferences of the plants, fish and nitrifying bacteria.   While the statement is factually correct, it is nearly useless for people new to this unique growing method.   Inevitably, to backup our statement, we pour on the detail.   For example (using wide ranges here for emphasis), fish prefer a pH of 6.5-7.5, plants a range of 5.5-6.5 and bacteria from 6.5-8.0.   That's when the glassy-eyed look of someone suffering from information overload sets in.  Can't you picture them trying to mentally map the overlaps?

Outside of the startup price, this phenomenon of information overload is the primary barrier to entry in aquaponics.   The irony is that the information is all readily available, but all too often in a format difficult to process.   Professional Commercial courses attempt to solve this barrier in three ways:

  • Whiteboards / shiny slideshows with a ton of dry statistics and cute pictures.
  • People to read the slideshow to you in the voice of Professor Binns (that's right, I made a Harry Potter reference)
  • Hands-on training

Lets face it, the hands-on training is by far the most valuable, giving you a visual and tactile connection to the data, i.e., providing context.

With today's modern technology, it's time for a modern approach, so we've been putting together a series of lessons where you get the horribly dry statistics (sans Professor Binns) paired with interactive widgets  that you can revisit over and over without the $1,000+ price tag.

To give you a sense of what these lessons are like, take the case of pH, which is a great starting point when teaching the concept of the system as a compromise.   In our example, we'll assign an ideal range to each component of the system, and to the system overall.

  • Overall system:  6.7 - 7.1
  • Plants:  5.5 - 7.0
  • Fish:  6.5 - 8.0
  • Bacteria:  6.7 - 8.0

Start with a neutral pH and slide the toggle button up to simulate an alkaline system.   Notice how quickly the plants are outside of their range.   Slide the toggle the other way and the system shifts towards an acidic enviornment, which is great for the plants but not the fish or bacteria.   You can see from the System gauge the narrow window you have to work in, while at the same time you can get a sense how the pH shifts affect the individual system components.




This is a simplistic example; it gets more complicated when you factor in each type of plant and fish with their own preferences.   When they are posted, you will be able to find these lessons in Learn, but hopefully this gives you a sense of where we are going with these and the scope they entail:

  • Water quality
  • Environment
  • System design
  • Fish and plant disease occurrence and progression

This concept of giving data immediate context is the principle behind Tracker.

Real-Time Clock - Part II: Grow Light Controller

In Part I of this tutorial, you learned how to set up the ChronoDot  with the Arduino and use it to track time.  Part II continues the discussion by creating a timer that can be used to control grow lights.

In a previous post we talked about the importance of light for plants and the role grow lights play in Controlled Environment Agriculture either by monitoring current light levels and providing supplemental light, or by providing all of the light for a fixed time every day.  Part II focuses on the latter, creating a timer which toggles a light on at a certain time of day, toggles it off at another and uses the ChronoDot to track the time.


Parts List
1 x Arduino Uno R3 (IDE 1.0.3)
1 x ChronoDot
1 x PowerSwitch Tail II Relay
6 x Jumper wires


Fritzing Diagram


Figure 1.  Grow Light Timer diagram.

Arduino Libraries
In addition to the libraries from Part I, you will need two new libraries for this sketch:  Time and TimeAlarms.  The Time library is used to set the Arduino's system time as well as to compare times during the initial setup.

TimeAlarms is used to create two alarms, one for the time each day the light is turned on, and a second alarm for the time of day the light is turned off.

Download both zip files, extract them and move a copy into your Arduino's libraries directory.


Arduino Sketch
This sketch takes two times, given as hour, minute and second and creates an alarm for each.  When you first launch the script, the start time and end time are compared to the current time.  If the current time is between the two times, the relay is toggled ON.

During each operational loop, the current time is retrieved from the ChronoDot, the system time is reset and the current time is displayed.


Real-Time Clock - Part I

A fundamental necessity of any controls system is the ability to track time.  As far as we are aware, the Arduino has three methods it can employ:
  1. Serial.  Repeatedly get the time over the Serial connection.
  2. External Hardware.  Real-time clocks, like the ChronoDot from Macetech, establish a base time when the Arduino sketch is compiled.  When you request the current time in the sketch you actually receive a time based on the time that has elapsed since compilation.
  3. Ethernet.  Access time using the internet NTP service.
This tutorial set focuses on option 2.  In Part I we explain the basics of getting the ChronoDot set up and displaying the current time over serial.

The ChronoDot

The ChronoDot is a high precision real-time-clock (RTC) and boasts a number of features needed for Aquaponics. The V2.1 release introduced the DS3231SN chip, which has an industrial temperature range of -40C to +85C and outputs a temperature compensated time - important for aquaponic control systems that reside outdoors in the heat and direct sun.  
Figure 1.  The ChronoDot V2.1, credit Macetech.

The ChronoDot includes an onboard battery cell for a CR1632 battery, allowing the clock to keep track of time should the Arduino lose power, regain power and restart. Anyone in aquaponics can appreciate the ability of a control system to automatically reboot and resume operation in the event of a power glitch. The disadvantage of the ChronoDot, and RTCs in general is the inability to handle Daylight Savings Time.

The Environment DAQ can be configured with the ChronoDot using the prototyping area, which is exactly wide enough to handle the RTC (coincidence?). If mounting to the shield, you can access the pins from the bottom.
Figure 2.  Environment DAQ Shield with ChronoDot.

Parts List
1 x ChronoDot
1 x Arduino Uno R3
4 x Jumper Wires

Mounting the ChronoDot
The Fritzing diagram below shows how to connect the ChronoDot to the Arduino. Note that the RTC connections are on the right-hand side - the pins on the other side are not used.


Figure 2.  Connecting the ChronoDot.

Arduino Library
The ChronoDot requires two libraries
  1. Wire.h - Included with the Arduino
  2. RTClib.h - Download here.
Download the zip file and extract it. If necessary, rename the extracted folder "RTClib", and then move a copy into your Arduino libraries directory.

Arduino Sketch
Part I of this tutorial simply outputs the current time from the RTC to Serial; part two shows how to set create a toggle time.


Environment DAQ Update 2.2

Version 2.2 brings the new overview container as well as some updates to the CSS files for Firefox.


You can download Version 2.2 here.

Arduino Aquaponics: EnvDAQ with Water Temperature Sensor

Introduction
The Environment DAQ is an open source Arduino shield used to track air temperature, relative humidity and light in aquaponic and hydroponic grow beds.  An equally important parameter to track is root temperature and with the new prototyping area on the v2 Environment DAQ boards, it is easy to add a new sensor.

The goal is to add the water temperature sensor to the other sensors on the Arduino  shield.

This tutorial requires that you have already completed the tutorials: Environment DAQ and Water Temperature.  You can download the complete source code here.

Part I:  Arduino
In Figures A and B you can see the Fritzing diagrams.  Figure A shows the full Environment DAQ with the DS18B20 integrated in and Figure B shows it solo.

Figure A.  Full EnvDAQ with DS18B20 to digital pin 5.

Figure B.  DS18B20 solo to digital pin 5.

To start upgrading the Arduino sketch, include the one-wire libraries and the sensor information.

Figure C.  Include statements and assignments.
The DS18B20 is a one-wire sensor, meaning you could run more than one sensor to the same digital port and differentiate the values using the device address.  At the bottom of the highlighted code in Figure C you will find the device address for our DS18B20 used for the this tutorial.  The link above it is a tutorial for finding the address of your specific sensor.

 Figure D shows a miscellaneous string used to temporarily hold the water temperature reading.

Figure D.  Temporary string for holding the water temperature reading.

In setup(), we need to add the commands to begin the sensor and set the resolution - Figure E.

Figure E.  setup() commands for the DS18B20

Each sensor in the main loop resets a string to blank, requests the data string from its function and outputs the new string to Serial.  You can comment out the Serial when you put this into operation.

Figure F.  DS18B20 loop() code.

 Next, add the string from Figure F to the end of the GAE request - Figure G.

Figure G.  Add the water temp string to the end of the web request.

Finally, create the function that gets the root temperature and converts it from Celsius to Fahrenheit and finally, to the string the web request uses.





Part II: App Engine
To make this process as easy as possible, cut and paste the temperature code and add a "w" or "W" in the places shown.  This will dramatically decrease the chances of typo errors and the time this upgrade takes.

UserPrefs Model & Settings Template
Open settings.py and edit the UserPrefs model.  Add in the properties for water temperature minimum and water temperature maximum preferences - Figure 1.  This is the first example of the suggestion above about copy and pasting the temperature property data; here, copy and paste and a "w" to the beginning.


Figure 1.  Water temperature min and max preferences.

Scroll down settings.py and add the form variables below the light properties.

Figure 2.  Water temperature variables for settings form.

The water temperature preferences are in a template (which we will create in a minute).  First, add the code from Figure 3 to render the (yet-to-be-created) water temperature template and pass in the preferences.

Figure 3.  Render the water temperature template.

The water temperature template is loaded into the /templates/settings/content.html template - the main settings template.  Edit the template rendering code to pass in the water temperature template - Figure 4.

Figure 4.  Pass the water temperature template into the main template.

Next, edit /templates/settings/content.html by adding in the template variable for the water temperature template from Figure 4.

Figure 5.  Edit content.html for the new water temperature template.

Finally, create the water temperature template: water_temp.html.  Again, this is easily done by copying and pasting the original temperature.html code and add the "w" in places.  The full template is in Figure 6.

Figure 6.  Water temperature template.

Launch the web application in the sandbox and go to Settings to check the templates are loading correctly.

Figure 7.  Water temperature template rendered in Settings tab.

Saving Water Temperature Preferences
To save the preferences for water temperature, start by creating the onclick handler in javascript.  Open settings.js, copy the original saveTempSettings() function and edit for water temperature - Figure 8.

Figure 8.  Onclick handler for water temperature save button.

The onclick handler makes an asynchronous request to the server, so we need a request handler to process the request.

Figure 9.  Request handler for water temperature form.

Add the new request handler to the bottom so the request is properly routed.

Figure 10.  Request handler link.

Finally, reload the settings page in the sandbox and save water temperature settings.

Environment.py:  EnvData Model
In environment.py, amend the data model to include the water temperature parameter.


Figure 11.  EnvData water temperature property.

Adacs.py:  Arduino Request Handler
The request handler for the Arduino is in adacs.py.  Start by getting the water temperature argument passed from the Arduino and assigning it to WTemp.  Optionally, you can add a logging command to spit out the data that is passed.

Figure 12.  Arduino argument.

Next, assign the WTemp argument to the WTemp property of the EnvData model created in Figure 11.

Figure 13.  Assign the new argument to the WTemp property  of the EnvData entity.

One of the major upgrades to the EnvDAQ cloud application is the use of memcache.  Memcache stores data in system memory for a limited time and is specifically used here to hold the current parameters sent by the Arduino in order to reduce datastore read operations.  The original ~17,000+ read operations have been cut by a third, reducing the system load (and the potential for the server to instantiate new instances) and speeds up response times from the browser to the server.  Similarly, user preferences are stored in memcache.

Append the EnvNow assignment to include WTemp, before it is put in memcache.


Figure 14.  EnvNow with water temperature reading.

Test the Arduino request handler by typing in the following url in your browser

localhost:8080/adacs/arduino?Temp=84.1&Humidity=69.8&AmbientLDR=850&WaterTemp=75.0

If everything is working, the application will return "Connected".  To confirm the data was saved, open the Admin Console (localhost:8000/)  and then open Datastore Viewer.


water_temp.js
Just as we have JavaScript files for temperature, relative humidity and light, we need one for water temperature.  Create a new file: /static/scripts/water_temp.js and add the following

// Shared Aspects
var WTData = [['Time', 'WaterTemp', 'Min', 'Max']];       // Data for all water temp visualizations
var wtempChartData;

// Main Table
var wtempTable;

// Chart
var wtempChart;
var wtempChartOptions;

// Gauge
var wtempGauge;
var wtempGaugeData;
var wtempGaugeOptions;



function drawWTempTable() {
     // Chart data
     wtempChartData = google.visualization.arrayToDataTable(WTData);
     
     // Assign new visualization to DOM element
     wtempTable = new google.visualization.Table(document.getElementById('wtempTable'));
     
     // Draw Table
     wtempTable.draw(wtempChartData);
}     

function updateWTempTable(Time, TempValue, MinTemp, MaxTemp) {
     // Get the last row number
     var lastRow = wtempChartData.getNumberOfRows();
     
     // Get the value of the last row
     var timeStamp = wtempChartData.getValue(lastRow - 1, 0);
     
     //alert(timeStamp + ' ' + TempValue);
     if (timeStamp == 'Now') {
          wtempChartData.removeRow(0);
     }
     
     
     wtempChartData.addRow([Time, TempValue, MinTemp, MaxTemp]);
     wtempTable.draw(wtempChartData);     
     
}

/////////////////////////////////////////////////////////////////////////////////////////////////

function drawWTempChart() {
     wtempChart = new google.visualization.LineChart(document.getElementById('wtempChart'));
     wtempChartOptions = {         
       animation: {duration: 1000, easing: 'out'},
       backgroundColor: { fill: "none" }
     };
     wtempChart.draw(wtempChartData, wtempChartOptions);          
}


function updateWTempChart() {
     wtempChart.draw(wtempChartData, wtempChartOptions);
}



///////////////////////////////////////////////////////////////////////////////////////////////
/* Draws Water Temperature Gauge Using Water Temperature Chart Data */
function drawWTempGauge() {    
     var lastRow = wtempChartData.getNumberOfRows();
     var lastTemp = wtempChartData.getValue(lastRow - 1, 1);
     var minTemp = wtempChartData.getValue(lastRow - 1, 2);
     var maxTemp = wtempChartData.getValue(lastRow - 1, 3);
     
     //alert('MinTemp: ' + String(minTemp) + ' ' + 'MaxTemp: ' + String(maxTemp));
     
     
     wtempGaugeData = google.visualization.arrayToDataTable([
       ['Water'],
       [lastTemp]
     ]);
     
     wtempGauge = new google.visualization.Gauge(document.getElementById('wtempGauge'));
     wtempGaugeOptions = {          
       min: 0,
       max: 100,
       redFrom: 0, redTo: minTemp,
       greenFrom: minTemp, greenTo: maxTemp,
       yellowFrom: maxTemp, yellowTo: 100,        
       minorTicks: 5       
     };
     wtempGauge.draw(wtempGaugeData, wtempGaugeOptions);
}

function updateWTempGauge(TempValue, Threshold) {
     wtempGaugeData.setValue(0, 0, TempValue, Threshold);           
     wtempGauge.draw(wtempGaugeData, wtempGaugeOptions);
     
}

The new script needs to be loaded with the others.  Open /templates/main/scripts.html and insert the new script below light.  Do not put this script first - temp.js must be first.


Figure 15.  Include water_temp.js with the other JavaScript  for main.

Next, add the GCT elements referenced in water_temp.js to /templates/main/content.html.

Figure 16.  Div elements for water temperature GCT.


Main.js:  getChartData()
The AJAX request to the server to get the chart data on load is in /static/scripts/main.js. The function getChartData needs to amended in two places.  The first creates dummy data in the event the Arduino has not uploaded any data from the aquaponic/hydroponic system.

Figure 17.  Dummy placement data.

The second place pushes data to the WTData array created at the top of /static/scripts/water_temp.js.

Figure 18.  Add data to WTData array.

Finally, edit drawCharts() to include calls to water temperature.

Figure 19.  drawCharts with new water temperature function calls.


Environment.py:  GetChartData
The request handler for getting chart data is in environment.py.  Edit GetChartData so that it returns the water temperature data and preferences.

Figure 20.  GetChartData returning water temperature data and preferences.

Test
At this point you should be able to reload the main page of the webapp and be presented with the new charts for water temperature.

Figure 21.  New water temperature container.

Main.js:  UpdateChart
The second to last App Engine upgrade is getting the chart data for real-time graphing.  There are four places we need to edit /static/scripts/main.js.  First, add the lines from Figure 22 to include the new water temperature data from the JSON object.

Figure 22.  Get water temp data from JSON.

The next edit deals with resetting the charts should a new day roll over - this way, you are always view the current day's data and reducing the browser load.

Figure 23.  Reset charts if a new day is detected.

The code in Figure 24 adds the data to the original data array as a redundant measure should your browser window change size and automatically redraw the charts.

Figure 24.  Add new data to original data array.

Finally, add the function calls that update the water temperature charts.

Figure 25.  Update water temperature charts.

Environment.py: UpdateChart
In environment.py we need to edit updateChartData().  The request handler is a conditional that tries to get the EnvNow data (as Environment) from memcache.  The first condition occurs if the memcache has expired.


Figure 26.  No memcache of current data.

The second condition returns evaluates the timestamp against the current data in memcache and returns the data only if the timestamps are different.

Figure 27.  Memcache is present and timestamps are different.

That's it!  The DS18B20 in this tutorial is meant for the grow beds, but the code would work if you put it in the stock tank as well.  If you want to take this a step further, you can plot both air temperature and water (root) temperature on the same chart for comparison.

Related Projects:
Environment DAQ
Pump Controller

Related Parts:
Water Temperature
Temp and Humidity
Light
pH
Dissolved Oxygen