From e817292eeea1cc98742b237d23fe9ea1ff6c1343 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Tue, 12 Apr 2016 10:20:00 +0000 Subject: [PATCH] Add an example which stores data into a MySQL database --- Makefile | 15 ++++- README | 20 ++++++- test_mysql.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 test_mysql.c diff --git a/Makefile b/Makefile index 431c1ee..5fcb60c 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,25 @@ CC=gcc CFLAGS=-I. -Werror -pthread -g +LDFLAGS=-lm -lpthread + +MYSQL_CFLAGS=`mysql_config --cflags` +MYSQL_LDFLAGS=`mysql_config --libs` + DEPS = lngpio.h air_utils.h OBJ = lngpio.o air_utils.o test.o OBJ_ASYNC = lngpio.o air_utils.o test_async.o +OBJ_MYSQL = lngpio.o air_utils.o test_mysql.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) test: $(OBJ) - gcc -o $@ $^ $(CFLAGS) -lm -lpthread + gcc -o $@ $^ $(CFLAGS) $(LDFLAGS) test_async: $(OBJ_ASYNC) - gcc -o $@ $^ $(CFLAGS) -lm -lpthread + gcc -o $@ $^ $(CFLAGS) $(LDFLAGS) + +test_mysql: CFLAGS := $(MYSQL_CFLAGS) +test_mysql: LDFLAGS := $(MYSQL_LDFLAGS) +test_mysql: $(OBJ_MYSQL) + gcc -o $@ $^ $(CFLAGS) $(LDFLAGS) diff --git a/README b/README index 0703d4e..1be7041 100644 --- a/README +++ b/README @@ -22,7 +22,25 @@ OR make test_async ./test_async -lngpio provides two APIs: +OR + +make test_mysql +./test_mysql + +./test_mysql stores data into a MySQL database so that it can be later retrieved +and plotted for example. For the test app to work set up the database in the +following way: + +mysql -h localhost -u root -ppass +mysql> CREATE DATABASE AirQuality; +mysql> use AirQuality; +mysql> CREATE TABLE ParticlePM25 (concentration_pcs FLOAT, \ + concentration_ugm3 FLOAT, aqi INT, ts_created TIMESTAMP); +mysql> quit +Bye + +All test applications use lngpio which is part of the project, it provides two +APIs for reading the GPIO: 1. synchronous API with a pulseIn alike function, ./test uses that one 2. asyncronous API with callbacks, ./test_async demontrates how to use it diff --git a/test_mysql.c b/test_mysql.c new file mode 100644 index 0000000..0934847 --- /dev/null +++ b/test_mysql.c @@ -0,0 +1,160 @@ +/* + * (c) 2016 Ognyan Tonchev otonchev@gmail.com + * Example application monitoring Fine particle (PM2.5) with Grove Dust sensor + * (Shinyei PPD42NS) and a Raspberry Pi. + * The app uses lngpio's asynchronous API. + */ +#include "lngpio.h" +#include "air_utils.h" + +#include +#include +#include +#include + +/* MySQL headers */ +#include +#include + +#define LOW 0 +#define HIGH 1 + +#define PIN 17 + +/* MySQL database setup */ +#define MYSQL_DATABASE "AirQuality" +#define MYSQL_USER "root" +#define MYSQL_PASS "pass" + +static unsigned long starttime; +static unsigned long sampletime_ms = 30000; /* 30s */ +static unsigned long lowpulseoccupancy; +static struct timeval t_low, t_high; + +static long +millis () +{ + struct timeval tv; + gettimeofday (&tv, NULL); + + return (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; +} + +static void +finish_with_error (MYSQL *con) +{ + fprintf (stderr, "%s\n", mysql_error (con)); + mysql_close (con); + exit (1); +} + +static void +store_data (float concentration_pcs, float concentration_ugm3, int aqi) +{ + MYSQL *con = mysql_init (NULL); + char query[1024]; + + if (con == NULL) { + fprintf (stderr, "%s\n", mysql_error (con)); + exit (1); + } + + if (mysql_real_connect (con, "localhost", MYSQL_USER, MYSQL_PASS, + MYSQL_DATABASE, 0, NULL, 0) == NULL) { + finish_with_error (con); + } + + sprintf (query, "INSERT INTO ParticlePM25 (concentration_pcs," + " concentration_ugm3, aqi) VALUES (%f, %f, %d)", + concentration_pcs, concentration_ugm3, aqi); + + if (mysql_query (con, query)) { + finish_with_error (con); + } + + mysql_close (con); +} + +static void +pulse_detected (unsigned long pulse_duration) +{ + lowpulseoccupancy = lowpulseoccupancy + pulse_duration; + + if ((millis () - starttime) > sampletime_ms) { + float ratio; + float concentration_pcs; + float concentration_ugm3; + int aqi; + + ratio = lowpulseoccupancy / (sampletime_ms * 10.0); + concentration_pcs = + 1.1 * pow (ratio, 3) - 3.8 * pow (ratio, 2) + 520 * ratio + 0.62; + concentration_ugm3 = pm25pcs2ugm3 (concentration_pcs); + aqi = pm25ugm32aqi (concentration_ugm3); + + printf ("%f pcs/0.01cf, %f μg/m3, %d AQI\n", concentration_pcs, + concentration_ugm3, aqi); + + store_data (concentration_pcs, concentration_ugm3, aqi); + + lowpulseoccupancy = 0; + starttime = millis (); + } +} + +static void +status_changed (int pin, int status) +{ + long micros; + + if (status == 0) { + gettimeofday (&t_low, NULL); + } else if (status == 1) { + gettimeofday (&t_high, NULL); + + micros = (t_high.tv_sec - t_low.tv_sec) * 1000000L; + micros += (t_high.tv_usec - t_low.tv_usec); + + if (micros > 95000 || micros < 8500) + printf ("pulse duration out of bounds: %ld\n", micros); + + pulse_detected (micros); + } +} + +int +main (int argc, char * argv[]) +{ + LNGPIOPinMonitor *monitor; + + if (lngpio_is_exported (PIN)) + lngpio_unexport (PIN); + + if (-1 == lngpio_export (PIN)) + return (1); + + if (-1 == lngpio_wait_for_pin (PIN)) + return (1); + + if (-1 == lngpio_set_direction (PIN, LNGPIO_PIN_DIRECTION_IN)) + return (1); + + if (-1 == lngpio_set_edge (PIN, LNGPIO_PIN_EDGE_BOTH)) + return (1); + + monitor = lngpio_pin_monitor_create (PIN, status_changed); + if (NULL == monitor) + return (1); + + while (1) { + usleep (100000); + } + + if (-1 == lngpio_pin_monitor_stop (monitor)) + return (1); + + if (-1 == lngpio_unexport (PIN)) + return (1); + + return (0); +}