This Blog is about sending your data to the "cloud", this means we will be sending our data logs onto someone else's server running at some place.
SparkFun have been nice enough to host a free database for sending logs to:
Here is a quick view of what it looks like
Even better you can make your data public, that way anyone can pull a copy of the data while you have a separate key for editing the data.
So Drop a link like this to your project: https://data.sparkfun.com/adapted_greenhouse
Setting up your free account
Go to https://data.sparkfun.com/
Click on the links to set up your data stream
Make a note of your public key and private key [you will understand when you make an account]
Set up what data fields you want to send, no caps and keep an eye on spelling]
Adapt the code below by plugging in your public and private key and the number of data points you want to log [rember the website and your code must match]
Limitations:
>300 data strings per 15 minutes [Much more than we need]
>50mb limit then it will start to write over the oldest data
<If you need to add extra data points for logging you will need to delete your current log, I recommend adding one or two extra empty columns for any extra data as your project develops.
These are maximum limits imposed by sparkfun, not bad for free!
Here is a screen shot of how the spark fun account should be set up for the code below:
[You will need to put your own alias, I will be keeping hold of adapted_greenhouse]
The Code
The code below is a example of how to log your data to data.sparkfun.
We have three types of data to log usually, Averaged logs, logs of maximum values and the last upto date reading.
We have simulated these readings in this code,
Header 1 |
---|
/***************************************************************** This script measures the enviroment withing a greenhouse
Sends data to we sever to display enviroment
Michael Ratcliffe mike@michaelratcliffe.com
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
>Arduino >Ethernet shield Arduino Ethernet shield R3 with micro SD connector >data.sparkfun account
Much of this code is largely based on David Mellis' WebClient example in the Ethernet library and further work by the sparkfun team. Thanks for the great work!
*/
//***************************Declaring Libraries **************************************/ #include <SPI.h> // Required to use Ethernet #include <Ethernet.h> // The Ethernet library includes the client //#include <SD.h>
//************************User Defined Variables *************************************// const int Spacing=10; //how long in sconds to wait between logging data
// Ethernet Settings // Enter a MAC address for your controller below. byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress server(54,86,132,254); // numeric IP for data.sparkfun.com //char server[] = "data.sparkfun.com"; // name address for data.sparkFun (using DNS) // Set the static IP address to use if the DHCP fails to assign IPAddress ip(192,168,9,10);
// Initialize the Ethernet client library that you want to connect to (port 80 is default for HTTP): EthernetClient client;
//*** Your data.sparkfun account [you need your own keys here, the ones below wont work] const String publicKey = "4JxLXZXXXXXXXXXXXX"; const String privateKey = "b5bJ2XXXXXXXXXXXX";
//********* How Many colums you want to log const byte NUM_FIELDS = 3; //The Names for the collum headers, make sure its the same order, spelling and no capitals as your data.sparkfun accunt const String fieldNames[NUM_FIELDS] = {"analog","ram","seconds"}; String fieldData[NUM_FIELDS];
//************************* Change Value Below For Board Of Choice ***********************// /* ATMega168 ATMega328P ATmega1280 ATmega2560 SRAM 1024 bytes 2048 bytes 8192 Bytes 8192 Bytes */
const int Total_Ram = 2048 ; //change this value for the correct one from above data
//***************************** End Of Recomened Changes *********************************************// //We will be using this later on with backup sd logging #define SS_SD_CARD 4 #define SS_ETHERNET 10
float Analog_Value=0; unsigned long Second=0; unsigned long Last_Send= 0;
//Some stuff for making second readings long Last_Second=0; int Reading=0;
//****************************Seting up the Ram check**************************************// int freeRam () { extern int __heap_start, *__brkval; int v; return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); };
//********Just Some variables we use to convert to % ************// float Ram=3; float Ram_Ussage=0; int Ram_error=0;
//************************************Setup Loop ******************************************// void setup() { Serial.begin(9600); //calls the function to initiate ethernet, check below code setupEthernet();
}
//************************************End Of Setup ****************************************//
//****************************************Main Loop ****************************************// void loop() {
//Taking a reading every second ish Second=millis()/1000; if(Second!=Last_Second){ Analog_Value=(analogRead(A0)+ Analog_Value); Last_Second=Second; Reading++ ; }
Max_Ram(); // We need to call this at multiple points in the main loop, Sram Ussage will change thru the loop
//Updating to data.sparkfun at the interval you selected at the top of code if(Second%Spacing==0 && Second!=Last_Send){ Last_Send= Second; Analog_Value=Analog_Value/Reading; Reading=0; //setting things back ready for more readigs //reading analog value and calculating seconds since start Second=millis()/1000; // Gather data, dont forget you specified the number of data points at the top of the code fieldData[0] = String(Analog_Value); fieldData[1] = String(Ram_Ussage); fieldData[2] = String(Second);
Serial.println("Posting!"); // Calling the postData() function does all the work, postData();
//Sending it to serial too Serial.println("Posting!"); Serial.print("Analog_Average: "); Serial.println(Analog_Value); Serial.print("Max_Ram: "); Serial.println(Ram_Ussage); Serial.print("Seconds: "); Serial.println(Second); Analog_Value=0;
}
} //*****************************END OF MAIN ***********************************************//
//********************* Function to push data to server ******************// void postData() { // Make a TCP connection to remote host if (client.connect(server, 80)) { // Post the data! Request should look a little something like: // GET /input/publicKey?private_key=privateKey&light=1024&switch=0&name=Jim HTTP/1.1\n // Host: data.sparkfun.com\n // Connection: close\n // \n client.print("GET /input/"); client.print(publicKey); client.print("?private_key="); client.print(privateKey); for (int i=0; i<NUM_FIELDS; i++) { client.print("&"); client.print(fieldNames[i]); client.print("="); client.print(fieldData[i]); } client.println(" HTTP/1.1"); client.print("Host: "); client.println(server); client.println("Connection: close"); client.println(); } else { Serial.println(F("Connection failed")); }
// Check for a response from the server, and route it
while (client.connected()) { if ( client.available() ) { char c = client.read(); Serial.print(c); } } Serial.println(); client.stop(); }
//*********** Function to setup Ethernet *********************// void setupEthernet() { Serial.println("Setting up Ethernet..."); // start the Ethernet connection: if (Ethernet.begin(mac) == 0) { Serial.println(F("Failed to configure Ethernet using DHCP")); // no point in carrying on, so do nothing forevermore: // try to congifure using IP address instead of DHCP: Ethernet.begin(mac, ip); } Serial.print("My IP address: "); Serial.println(Ethernet.localIP()); // give the Ethernet shield a second to initialize: delay(1000); }
//************* Loop for calculating Ram Ussage, called from main loop***//
void Max_Ram(){
if(freeRam()>=Ram){ Ram=(freeRam()); Ram_Ussage=(((Total_Ram-Ram)/Total_Ram)*100); };
if(Ram_Ussage>=70){ Ram_error=1; // Use this set flag to warn the user of a potential Ram ussage problem, or reset the arduino if it becomes true };
}; |
Debugging
It would be hard to debug this code as there are many areas for failure, I recommend trying these steps if you have a problem:
>Upload WebServer script [its in the arduino IDE examples] see that you can access the arduino via its ip address
>Check you have the same number of columns in your data.sparkfun page as you do in your arduino code, same order, same spelling no caps.
>Make sure you are not sending updates too often to sparkfun, they limit you to 300 per 15 minutes
>Open Serial for more info, below is a screenshot from a good upload
Keep watching for a blog on storing data on a sd card and a link to the data log from the Adapted_Greenhouse. The data from grows like this is quite valuable and useful in evolving your system into something better.