Electronza
  • Homepage
  • Privacy
    • Privacy Policy
  • Contact
Electronza
  • Homepage
  • Privacy
    • Privacy Policy
  • Contact
Electronza
You are at:Home»Electronics projects»Arduino projects»Arduino: data logger with MySQL
Seeduino Mega
Seeduino Mega

Arduino: data logger with MySQL

4
By Electronza on November 11, 2014 Arduino projects, Electronics projects

In the previous post, I explained how to install MySQL and how to create a database for use with Arduino projects. Now it’s time to go further and to explain how to create an Arduino temperature and humidity data logger.

Part 1 – the hardware

The project uses the following parts:

– one Seeeduino Mega (or any other Arduino Mega board) – this is mandatory as the code is quite large
– one Ethernet Shield
– one SEN-08257 temperature / humidity sensor from Sparkfun (based on SHT15x)
– one BOB-12708 real time module from Sparkfun (based on DS1307 RTC)
– one breadboard
– some connecting wires

Arduino Mysql Data Logger Schematic
Arduino Mysql Data Logger Schematic

In this schematic the RTC clock uses the I2C pins SDA and SCL, which in the case of Seeeduino MEga are on a separate small connector. For the SHT15 sensor, although is I2C compatible, I preferred to use the pins 7 and 8. The Ethernet shield comes on top of the Seeeduino Mega. The SPI data lines are from the ICSP connector, and the CS signals are on pins 4 and 10. Some pictures of the completed project are presented below. Note that the Seeeduino Mega has the holes in a different placement than in the classical Arduino Uno. To install it on the Arduino holder (DEV-11235) I had to remove the original fixing pins, then fix the Seeeduino board using two layers of thick double sided tape.

Sparkfun board holder with supporting pins removed
Sparkfun board holder with supporting pins removed
Seeduino mega board
Seeduino mega board
Seeduino Mega with Ethernet shield
Seeduino Mega with Ethernet shield
MySQL Arduino Logger - top view
MySQL Arduino Logger – top view
MySQL Arduino Logger
MySQL Arduino Logger
Another view of the MySQL Arduino Logger
Another view of the MySQL Arduino Logger

Part 2 – the software

In this project we first set the RTC timer using NTP, then we monitor the RTC, and every 10 minutes we log the time, temperature and humidity into the ardulogger database. Further, we will use DBPlot to create graphs of temperature and humidity.

For this project some prerequisites are needed:

First, we need the updated time library. Just download it and extract the files in the library folder of Arduino IDE.

Next, we need the SHT1x library from https://github.com/practicalarduino/SHT1x. After extracting the files into the library folder of Arduino IDE we have to rename it from SHT1x-master to SHT1xmaster, otherwise, we will get errors when compiling.

Finally, we have to install the MySQL connector libraries, which can be downloaded from https://launchpad.net/mysql-arduino. The version I used is mysql_connector_arduino-1.0.2b.zip.

To work with MySQL a small modification is needed: in mysql.h you need to uncomment the line:

#define WITH_SELECT // Uncomment this for use without SELECT capability

Try to compile the example files. Apply any diff files in the sha1 library if needed (I highly recommend http://winmerge.org/ to do this). If something goes wrong, you may take a look on Chuck’s blog, which gives a very good introduction to the MySQL connector. All we care about in this step is to be sure that the examples compile with no errors.

The code is as follows:


/*******************************************************************
____ __ ____ ___ ____ ____ __ __ _ ____ __
( __)( ) ( __)/ __)(_ _)( _ \ / \ ( ( \(__ ) / _\
) _) / (_/\ ) _)( (__ )( ) /( O )/ / / _/ / \
(____)\____/(____)\___) (__) (__\_) \__/ \_)__)(____)\_/\_/
Project name: Arduino: data logger with MySQL
Project page: https://electronza.com/arduino-data-logger-mysql/
********************************************************************/
#include <SPI.h>
#include <Ethernet.h>
#include <Dns.h>
#include <Time.h>
#include <Wire.h>
#include <DS1307RTC.h>
#include <SHT1x.h>
#include <sha1.h>
#include <mysql.h>
#include <string.h>
/* ******** Ethernet Card Settings ******** */
// Set this to your Ethernet Card Mac Address
byte mac[] = {0x90, 0xA2, 0xDA, 0x0D, 0xFE, 0x43 };
/* ******** NTP Server Settings ******** */
/* us.pool.ntp.org NTP server
(Set to your time server of choice) */
IPAddress timeServer;
/* Set this to the offset (in seconds) to your local time
This example is GMT + 2 */
const long timeZoneOffset = 7200L;
/* Syncs to NTP server every 15 seconds for testing,
set to 1 hour or more to be reasonable */
unsigned int ntpSyncTime = 15;
/* ALTER THESE VARIABLES AT YOUR OWN RISK */
// local port to listen for UDP packets
unsigned int localPort = 8888;
// NTP time stamp is in the first 48 bytes of the message
const int NTP_PACKET_SIZE= 48;
// Buffer to hold incoming and outgoing packets
byte packetBuffer[NTP_PACKET_SIZE];
// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
/* ********** RTC Time settings ********* */
tmElements_t tm;
int minutes_now;
int minutes_next;
/* ******* Settings for the SHT1x sensor */
#define dataPin 9
#define clockPin 8
SHT1x sht1x(dataPin, clockPin);
float temp_c;
float humidity;
/* ***** MySQl Server settings ********** */
Connector my_conn; // The Connector/Arduino reference
IPAddress server_addr(192, 168, 1, 133); // IP address of MySQL server
char user[] = "arduino";
char password[] = "arduino";
// maximum tries to connect
int num_fails;
#define MAX_FAILED_CONNECTS 5
// We define some strings
char myquery[150]; // more than enough; stores command to print table content
char insquery[200]; // more than enough; stores command to insert new data
const char testselect[] ={"SELECT * FROM ardulogger.ardudata ORDER BY id DESC LIMIT %s"};
// general format to insert data is:
//const char insertdata[] = "INSERT INTO ardulogger.ardudata (date,time,temp,humi) VALUES ('2014-11-11','11:45:11', 25.8 , 31.21)";
//const char insertdata[] = {"INSERT INTO ardulogger.ardudata (date,time,temp,humi) VALUES ('%s-%s-%s','%s:%s:%s', %s , %s)"};
const char insertdata[] = {"INSERT INTO ardulogger.ardudata (date,time,temp,humi) VALUES ('%s-%s-%s','%s:%s:%s', %s , %s)"};
// buffer for number to character conversion
char yearbuf[5];
char monthbuf[3];
char daybuf[3];
char hourbuf[3];
char minutebuf[3];
String temp_buf;
char secbuf[3];
char tempbuf[6];
char humibuf[5];
int timebuf;
void setup() {
Serial.begin(9600);
// Ethernet shield and NTP setup
int i = 0;
int DHCP = 0;
DHCP = Ethernet.begin(mac);
//Try to get dhcp settings 30 times before giving up
while( DHCP == 0 && i < 30){
delay(1000);
DHCP = Ethernet.begin(mac);
i++;
}
if(!DHCP){
Serial.println("DHCP FAILED");
for(;;); //Infinite loop because DHCP Failed
}
Serial.println("DHCP Success");
//Just for testing we print the obtained IP address
Serial.print("My IP address: ");
for (byte thisByte = 0; thisByte < 4; thisByte++) {
// print the value of each byte of the IP address:
Serial.print(Ethernet.localIP()[thisByte], DEC);
Serial.print(".");
}
Serial.println();
// We get the address of a NTP server from NTP pool
DNSClient dns;
dns.begin(Ethernet.dnsServerIP());
dns.getHostByName("ro.pool.ntp.org",timeServer);
Serial.print("NTP IP from the pool: ");
Serial.println(timeServer);
// Now we get the time
Serial.println("trying to get the time");
int trys=0;
while(!getTimeAndDate() && trys<10){
trys++;
}
if(trys<10){
Serial.println("Ntp server update success");
}
else{
Serial.println("Ntp server update failed");
}
// Print the time
clockDisplay();
// We have the right time, now we set the RTC clock
if (RTC.read(tm)) {
Serial.println("The DS1307 is running.");
Serial.println("Updating the RTC time.");
Serial.println();
tm.Day = day();
tm.Month = month();
tm.Year = year()-1970;
tm.Hour = hour();
tm.Minute = minute();
tm.Second = second();
RTC.write(tm); //update the time
} else if (RTC.chipPresent()) {
Serial.println("The DS1307 stopped.");
Serial.println("Setting the RTC time.");
Serial.println();
tm.Day = day();
tm.Month = month();
tm.Year = year()-1970;
tm.Hour = hour();
tm.Minute = minute();
tm.Second = second();
RTC.write(tm); //update the time
}
else {
Serial.println("DS1307 read error! Please check the circuitry.");
Serial.println();
}
// Just in case we read the RTC time for debugging purposes
// Serial.println("Computing the next DB access time");
RTC.read(tm);
minutes_now=tm.Minute;
// minutes_next=floor(tm.Minute/10)*10+10;
minutes_next=minutes_now+1; //debgging – write every minute to DB
if (minutes_next==60)
minutes_next=0;
Serial.print("Current minute: ");
Serial.print(minutes_now);
Serial.println();
Serial.print("Minute for the next database write: ");
Serial.print(minutes_next);
Serial.println();
} //end of setup
// functions for NTP server
// Do not alter this function, it is used by the system
int getTimeAndDate() {
int flag=0;
Udp.begin(localPort);
sendNTPpacket(timeServer);
delay(1000);
if (Udp.parsePacket()){
Udp.read(packetBuffer,NTP_PACKET_SIZE); // read the packet into the buffer
unsigned long highWord, lowWord, epoch;
highWord = word(packetBuffer[40], packetBuffer[41]);
lowWord = word(packetBuffer[42], packetBuffer[43]);
epoch = highWord << 16 | lowWord;
epoch = epoch – 2208988800 + timeZoneOffset;
flag=1;
setTime(epoch);
//ntpLastUpdate = now(); not needed anymore as we update the time only once
}
return flag;
}
// Do not alter this function, it is used by the system
unsigned long sendNTPpacket(IPAddress& address)
{
memset(packetBuffer, 0, NTP_PACKET_SIZE);
packetBuffer[0] = 0b11100011;
packetBuffer[1] = 0;
packetBuffer[2] = 6;
packetBuffer[3] = 0xEC;
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
Udp.beginPacket(address, 123);
Udp.write(packetBuffer,NTP_PACKET_SIZE);
Udp.endPacket();
}
// Clock display of the time and date (Basic)
void clockDisplay(){
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.print(" ");
Serial.print(day());
Serial.print(" ");
Serial.print(month());
Serial.print(" ");
Serial.print(year());
Serial.println();
}
// Utility function for clock display: prints preceding colon and leading 0
void printDigits(int digits){
Serial.print(":");
if(digits < 10)
Serial.print('0');
Serial.print(digits);
}
// End of NTP functions
void print2digits(int number) {
if (number >= 0 && number < 10) {
Serial.write('0');
}
Serial.print(number);
}
void loop(){
RTC.read(tm);
minutes_now=tm.Minute;
if (minutes_now==minutes_next){
//if (time_now.Minute==minutes_next){
// compute the next time for write
//minutes_next=floor(tm.Minute/10)*10+10; // write every 10 minutes – normal mode
minutes_next=minutes_now+1; // write every minute – debug mode
if (minutes_next==60)
minutes_next=0;
temp_c = sht1x.readTemperatureC();
humidity = sht1x.readHumidity();
// we construct the INSERT code here
// first we initialize the buffers
temp_buf=String(tm.Year+1970);
temp_buf.trim();
temp_buf.toCharArray(yearbuf,5);
temp_buf=String(tm.Month);
temp_buf.trim();
temp_buf.toCharArray(monthbuf,3);
temp_buf=String(tm.Day);
temp_buf.trim();
temp_buf.toCharArray(daybuf,3);
temp_buf=String(tm.Hour);
temp_buf.trim();
temp_buf.toCharArray(hourbuf,3);
temp_buf=String(tm.Minute);
temp_buf.trim();
temp_buf.toCharArray(minutebuf,3);
temp_buf=String(tm.Second);
temp_buf.trim();
temp_buf.toCharArray(secbuf,3);
// float to char conversion
dtostrf(temp_c, 5 , 2, tempbuf);
dtostrf(humidity, 5, 2, humibuf);
// now we build the command for data insertion
sprintf(insquery,insertdata,yearbuf,monthbuf,daybuf,hourbuf,minutebuf,secbuf,tempbuf,humibuf);
//ready to work with the database
Serial.println("DB write: ");
// Here comes the MySQL data code
if (my_conn.mysql_connect(server_addr, 3306, user, password)) {
// check for connection
if (my_conn.is_connected()) {
Serial.println("Last 5 DB entries!");
sprintf(myquery,testselect,"5");
Serial.println(myquery);
my_conn.cmd_query(myquery);
delay(250); // small delay to wait for MySQl server to respond
my_conn.show_results();
delay(1000);
Serial.println("Inserting new data!");
Serial.println(insquery);
my_conn.cmd_query(insquery);
delay(1500); // small delay to wait for MySQl server to respond
// We verify the last entered data
Serial.println("New data entered!");
sprintf(myquery,testselect,"1");
Serial.println(myquery);
my_conn.cmd_query(myquery);
delay(250); // small delay to wait for MySQl server to respond
my_conn.show_results();
num_fails = 0;
} else {
//my_conn.disconnect();
Serial.println("Connecting again…");
if (my_conn.mysql_connect(server_addr, 3306, user, password)) {
delay(500);
Serial.println("Success!");
} else {
num_fails++;
Serial.println("Connect failed!");
if (num_fails == MAX_FAILED_CONNECTS) {
Serial.println("No MySQL server available…");
delay(2000);
}
}
}
// close the database connection
my_conn.disconnect();
}
}
// Just prints the time so we know we are not stuck
Serial.print("Current time is ");
print2digits(tm.Hour);
Serial.write(':');
print2digits(tm.Minute);
Serial.write(':');
print2digits(tm.Second);
Serial.println();
// Basically we check the time every 5 seconds. You can increase this
delay(5000);
}

view raw

mysql.ino

hosted with ❤ by GitHub

Some explanations:

First, we try to obtain an IP address for our Arduino project using DHCP. If everything is OK we then go to a Network Time Protocol server to obtain the current time and date. This is done only once, when the power is applied, to avoid overloading the NTP server, as this is a very important issue. You can read more about the problems related to abusing NTP servers in the Arduino forums.

The NTP routine first resolves ro.pool.ntp.org to obtain the IP address of an NTP server. Please observe that I’m using the national pool of NTP servers instead of the global one. More information on NTP servers can be found on http://www.pool.ntp.org/en/.

Once we have the IP address of a working NTP server we get the time. For this I used a slightly modified version of the NTP code provided by OpenReefs.

The DS1307RTC library requires the time to be stored in the tm structure. Most important, the years are measured starting with 1970 – thus the need to subtract this from the value returned by the year() function. We then call the RTC.write() function to update the RTC timer.

We wish to write into the MySQL database every 10 minutes. For this, we use two variables of integer type, minutes_now which store the current minute and minutes_next which stores the time for the next database operation. We read the RTC time every 5 seconds. If minutes_now equals minutes_next we first compute the next value for minutes_next, then we measure the temperature and humidity, and we write the time and the recorded values into the MySQL database.

To insert the data into the database we first connect to the MySQL database. Just for testing we show the last 5 entries. To insert the data we have to construct the query string. Special attention must be given to the time and date fields. Insert a space into the wrong position and you will have a MySQL error. The workaround was to convert the date and time to a string, then I used the trim() function to remove the spaces. Further, I converted the strings into character arrays, which are later used to construct the query. The temperature and humidity data are truncated to two decimal places, thus precision of the recorded data is around 1%.

We then run the query and we check the result by reading the last entry from the database. Finally, we close the database connection – this is useful if you log the data at large intervals.

The final code is quite large, occupying a huge area of both ROM and RAM memories. In the future I intend to create a smaller version of this code, to run on Arduino Uno boards.

RTC Arduino Mega MySQL data logger SHT15x NTP
Share. Facebook Twitter Pinterest LinkedIn Tumblr Email

Related Posts

H2S IoT node with ESP8266 Thing Dev

H2S IoT node with ESP8266 and openSenseMap

ESP8266 Thing Dev from Sparkfun

ESP8266 – running on battery power

SDS011 - HPMA115S0 - Arduino Due

A comparative test of two particle sensors

4 Comments

  1. Hamdaan on December 3, 2016 1:05 pm

    Can you tell me what is a data logger?

    Reply
    • Teodor on December 3, 2016 3:27 pm

      https://en.m.wikipedia.org/wiki/Data_logger

      Reply
  2. wei-gian on August 1, 2017 5:41 am

    This is very interesting and useful project. Is that running MySQL the reason for so much memory demanding?

    Reply
    • Teodor on August 1, 2017 9:26 am

      Hi!

      The Ethernet library takes a lot of space, and the MySQL connector requires that library.

      Furthermore, I don’t how much optimization was done in the MySQL code. I was happy that it works, and it’s simpler for me to move to an Arduino Mega if I need more memory 🙂

      Reply

Leave A Reply Cancel Reply

Latest posts
January 15, 2023

A pretty text box for Blogger posts

January 15, 2023

New blog section: beginners’ corner

January 15, 2023

Cleaning unused images from blogs hosted on Blogger

Categories
  • Beginners' corner
  • Electronics projects
    • ESP8266
    • Arduino projects
    • IoT
    • 8-bit PIC projects
    • Raspberry PI
    • PIC32 projects
    • Robots
  • Arduino libraries
  • Reviews
    • Tools & equipment
    • Development boards
    • IoT
    • Industrial Arduino
  • Blogger / Blogspot
  • Tutorials
  • Casual stuff
Popular posts
Arduino Uno 4-20mA communication using 4-20mA R click and 4-20mA T click boards from MikroElektronika: MIKROE-1296, MIKROE-1387, Uno Click Shield
August 17, 2016

4-20mA current loop Arduino tutorial Part I: hardware

ESP8266 Thing Dev from Sparkfun
May 15, 2019

ESP8266 – running on battery power

ECG click on Arduino Uno
December 5, 2016

ECG click: Arduino IDE code examples

WiFi3 Click - esp8266 in click board format
March 15, 2017

ESP8266: AT mode webserver tutorial

Honeywell HPMA115S0-XXX particle sensor
November 23, 2017

Arduino: measuring PM2.5 and PM10 with Honeywell HPMA115S0

Copyright © 2023 Teodor Costachioiu

Type above and press Enter to search. Press Esc to cancel.