After few years of „JAVA lazy programming“ with IOIO board, I decided to move to the next level and try Arduino and C. And what is the most obvious „hello world“ project for Arduino? Thermometer. But just display the temperature is little boring. After seeing this beautiful example from plotly:
Real-time Graphing and Data Logging
it was clear, that I need to be online, with some charts and other things making the geek happy.
Components were
- Arduino Nano
- Ethernet shield
- pair of DHT22
- LCD screen (used in Nokia 5110/3110)
As the ethernet shield is based on ENC28J60 chip, I cannot used the default Ethernet Arduino lib, so I tried UIPEthernet, which is copy/paste replacement.
But only UIPEthernet + plotly_streaming_ethernet takes 28 066 bytes of memory! So no space for display and temperature sensor.
Another option was Ethercard which is simplier and smaller, but cannot work with plotly streaming API.
I decides to send data to my sql database first and then to the plotly service via their REST API – final complete sketch has 21 910 bytes (EtherCard + DHT + LCD5110_Basic)
Complete sketch, just replace
%WRITE_SCRIPT% and %DOMAIN% with your values.
Eventualy change pinout
#define DHTPIN 8
#define DHTPIN_OUT 9
#define BACKLIGHT = 7;
#include <EtherCard.h> #include "DHT.h" #include <LCD5110_Basic.h> #define DHTPIN 8 #define DHTPIN_OUT 9 #define DHTTYPE DHT22 #define BACKLIGHT = 7; // ethernet interface mac address, must be unique on the LAN static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; byte Ethernet::buffer[700]; char myIpString[24]; extern uint8_t MediumNumbers[]; extern uint8_t SmallFont[]; static uint32_t timer; DHT dht(DHTPIN, DHTTYPE); DHT dht_out(DHTPIN_OUT, DHTTYPE); LCD5110 myGLCD(6,5,4,2,3); const char website[] PROGMEM = "%DOMAIN%"; int dstart = 0; int dlen = 0; char tbuff[12]; char cbuff[]="serial=0&temperature=00&humidity=00&oustsidetemp=00&oustsidehum=00"; // called when the client request is complete static void my_callback (byte status, word off, word len) { Serial.println(">>>"); Ethernet::buffer[off+300] = 0; Serial.print((const char*) Ethernet::buffer + off); Serial.println("..."); memset( &tbuff, 0, sizeof(tbuff)); } void setup () { Serial.begin(57600); Serial.println(F("\n[setup]")); if (ether.begin(sizeof Ethernet::buffer, mymac,10) == 0) Serial.println(F("Failed to access Ethernet controller")); if (!ether.dhcpSetup()) Serial.println(F("DHCP failed")); ether.printIp("IP: ", ether.myip); ether.printIp("GW: ", ether.gwip); ether.printIp("DNS: ", ether.dnsip); if (!ether.dnsLookup(website)) Serial.println("DNS failed"); pinMode(7,OUTPUT); sprintf(myIpString, "%d.%d.%d.%d", ether.myip[0], ether.myip[1], ether.myip[2], ether.myip[3]); ether.printIp("SRV: ", ether.hisip); myGLCD.InitLCD(); dht.begin(); dht_out.begin(); } void loop () { ether.packetLoop(ether.packetReceive()); word len = ether.packetReceive(); word pos = ether.packetLoop(len); if(pos) { char* data = (char *) Ethernet::buffer + pos; Serial.println("----------------"); Serial.println("data received:"); Serial.println(data); Serial.println("----------------"); if (strncmp("GET /?on",data,8) == 0) { digitalWrite(7, LOW); Serial.println("LED ON:"); } if (strncmp("GET /?off",data,9) == 0) { digitalWrite(7, HIGH); Serial.println("LED OFF:"); } } if (millis() > timer) { float h = dht.readHumidity(); float ho = dht_out.readHumidity(); // Read temperature as Celsius float t = dht.readTemperature(); float to = dht_out.readTemperature(); myGLCD.clrScr(); myGLCD.setFont(SmallFont); myGLCD.print("------------", CENTER, 17); myGLCD.print("Teplota",LEFT,0); myGLCD.print("Venkovni",LEFT,15); myGLCD.print("Vlhkost",LEFT,24); myGLCD.print("Venkovni",LEFT,34); myGLCD.printNumF(t, 1, RIGHT, 0); myGLCD.printNumF(to, 1, RIGHT, 15); myGLCD.printNumI(ho, RIGHT, 34); myGLCD.printNumI(h, RIGHT, 24); timer = millis() + 50000; Serial.println(); Serial.print("<<< REQ "); dtostrf(t,2,2,tbuff); dstart = 21; //start of replace dlen = 2; for (int i=0+dstart; i <= dstart+dlen-1; i++) { cbuff[i] = tbuff[i-dstart]; } dtostrf(h,2,3,tbuff); dstart = 33; dlen = 2; for (int i=0+dstart; i <= dstart+dlen-1; i++) { cbuff[i] = tbuff[i-dstart]; } memset( &tbuff, 0, sizeof(tbuff)); // Outside values dtostrf(to,2,2,tbuff); dstart = 49; dlen = 2; for (int i=0+dstart; i <= dstart+dlen-1; i++) { cbuff[i] = tbuff[i-dstart]; } dtostrf(ho,2,3,tbuff); dstart = 64; dlen = 2; for (int i=0+dstart; i <= dstart+dlen-1; i++) { cbuff[i] = tbuff[i-dstart]; } Serial.println(); Serial.print("Buffer"); Serial.println(); Serial.print(cbuff); Serial.println(); ether.browseUrl(PSTR("/%WRITE_SCRIPT%.php?"),cbuff, website, my_callback); } myGLCD.setFont(SmallFont); myGLCD.print(myIpString, CENTER, 46); }
The „receiver“ script, saving the results to the mySQL (PoC)
<?php // Connect to MySQL include("dbconnect.php"); if(is_numeric($_GET["temperature"])&&is_numeric($_GET["humidity"])&&is_numeric($_GET["oustsidetemp"])&&is_numeric($_GET["oustsidehum"])) { // Prepare the SQL statement $SQL = "INSERT INTO temperature (sensor,celsius,humidity,oustsidetemp,oustsidehum) VALUES ('".$_GET["serial"]."', '".$_GET["temperature"]."', '".$_GET["humidity"]."', '".$_GET["oustsidetemp"]."', '".$_GET["oustsidehum"]."')"; // Execute SQL statement $result = mysql_query($SQL); if (!$result) { die('Invalid query: ' . mysql_error()); } } ?>
Very very very UGLY code for posting, just need to check the functionality
<?php // Connect to MySQL include("dbconnect.php"); $url = 'https://plot.ly/clientresp'; $result = mysql_query("SELECT * FROM temperature ORDER BY id ASC"); $x = "[" ; $y = "[" ; $h = "[" ; $yo = "[" ; $ho = "[" ; // process every record $i = 0; while( $row = mysql_fetch_array($result) ) { if($i!=0) { $x = $x."," ; $y = $y."," ; $h = $h."," ; $yo = $yo."," ; $ho = $ho."," ; } $x = $x."\"".$row["event"]."\""; $y = $y.$row["celsius"]; $h = $h.$row["humidity"]; $yo = $yo.$row["oustsidetemp"]; $ho = $ho.$row["oustsidehum"]; $i++ ; } $x = $x."]" ; $y = $y."]" ; $h = $h."]" ; $yo = $yo."]" ; $ho = $ho."]" ; // var_dump($x); $data = array('un' => '%PLOTLYNICK%', 'key' => '%PLOTLYKEY%', 'origin' => 'plot', 'platform' => 'rest', 'args' => '[{"x":'. $x .' , "y": ' .$y. ',"name": "Temperature", "type": "scatter", "mode": "lines"},{"x":'. $x .' , "y": ' .$yo. ',"name": "Temperature ouside", "type": "scatter", "mode": "lines"},{"x":'. $x .' , "y": ' .$h. ',"name": "Humidity", "type": "scatter", "mode": "lines"},{"x":'. $x .' , "y": ' .$ho. ',"name": "Humidity ouside", "type": "scatter", "mode": "lines"}]', 'kwargs' =>'{"filename": "Arduino nano test", "fileopt": "overwrite", "layout": {"title": "Temperature and Humidity", "xaxis": {"title": "Date"}, "yaxis": {"title": "Values (C) (%)"}}}'); // use key 'http' even if you send the request to https://... $options = array( 'http' => array( 'header' => "Content-type: application/x-www-form-urlencoded\r\n", 'method' => 'POST', 'content' => http_build_query($data), ), ); $context = stream_context_create($options); $result = file_get_contents($url, false, $context); var_dump($result); // $obj = json_decode($json); // $graphUrl = $obj->{"url"}; // $obj = json_decode($json); // print $obj->{'error'}; ?>

Arduino
It was working, but since ESP8266 came to the market, this is old and little overkill as now, the single ESP8266 could measure temperature and send it to thingspeak.
http://www.instructables.com/id/Low-cost-WIFI-temperature-data-logger-based-on-ESP
Its time to make it more wireless, smaller and more fancy.
The new PoC with Wifi + BMP180 Barometric Pressure/Temperature sensor is coming 🙂
Hi Roman,
you wrote „UIPEthernet + plotly_streaming_ethernet takes 28 066 bytes of memory“. I could live with that limitation but I am not able to get it working. Do you still have the code for UIPEthernet with PlotLy ?
Best regards,
Georg
I will take a look, if I still have the sketch, but as UIPEthernet is copy/paste replacement of original Ethernet library, it should be enought to open plotly_streaming_ethernet files and simply change the imports from Ethernet.h to UIPEthernet.h