This code example has been tested and improved to be executed in Meshlium with the data coming from a Wireless Sensor Network created with Waspmote.
This example will define a simple trigger based on an arbitrary value. Values over the trigger will be considered an alert and a SMS message will be sent.
Note that on real applications each sensor usage has it's own alert parameters, and several alerts can be launched over different sensors.
For this example the frame will have the same structure used in previous tutorials
ID_<mote>#Sensor_value
A valid frame can be:
ID_12#239
The database to store data will store the following values: ID of the mote, sensor value recived, and the time of the received frame will be stored.
First we need to create the database for the example.
create database sensordemo; use sensordemo;
Add a user that can access the database.
GRANT ALL PRIVILEGES ON sensordemo.* TO 'sdemo'@'localhost' IDENTIFIED BY 'sdemopass' WITH GRANT OPTION; flush privileges;
Finally create the database.
CREATE TABLE sensor_data ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, date timestamp not null, mote_id INT UNSIGNED NOT NULL, sensor_value INT UNSIGNED NOT NULL, PRIMARY KEY (id) );
This program reads frames received through a Bluetooth Serial Port or a XBee module and store it on a MySQL database. If a detected value if greater that alert_value, an alarm is processed and a SMS message is sent.
File:
"sniffer_ddbb_sms_alarm.c"
Compilation on Meshlium:
gcc -o sniffer_ddbb_sms_alarm -I/usr/include/mysql sniffer_ddbb_sms_alarm.c -L/usr/lib/mysql -lmysqlclient -Wall
Usage:
sniffer_ddbb_sms_alarm S0 localhost
Note:
Serial port speed should be set on sniffer execution.
/*
* Copyright (C) 2008 Libelium Comunicaciones Distribuidas S.L.
* http://www.libelium.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 2 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/>.
*
* Version 0.1
* Author: Octavio Benedi Sanchez
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <termios.h> /* Terminal control library (POSIX) */
#include <ctype.h>
#include <mysql.h>
#define MAX 500
#define MAX_SQL 700
int main(int argc, char *argv[]) {
int sd = 3;
char *serialPort = "";
char *serialPort0 = "/dev/ttyS0";
char *serialPort1 = "/dev/ttyS1";
char *USBserialPort0 = "/dev/ttyUSB0";
char *USBserialPort1 = "/dev/ttyUSB1";
char *USBserialPort2 = "/dev/ttyUSB2";
char *USBserialPort3 = "/dev/ttyUSB3";
char *USBserialPort4 = "/dev/ttyUSB4";
char *USBserialPort5 = "/dev/ttyUSB5";
char *BTserialPort0 = "/dev/rfcomm0";
char *BTserialPort1 = "/dev/rfcomm1";
char *BTserialPort2 = "/dev/rfcomm2";
char valor[MAX] = "";
char c;
struct termios opciones;
char *s0 = "S0";
char *s1 = "S1";
char *u0 = "USB0";
char *u1 = "USB1";
char *u2 = "USB2";
char *u3 = "USB3";
char *u4 = "USB4";
char *u5 = "USB5";
char *bt0 = "rfcomm0";
char *bt1 = "rfcomm1";
char *bt2 = "rfcomm2";
int speed = B19200;
typedef struct {
char *name;
int flag;
} speed_spec;
speed_spec speeds[] ={
{"1200", B1200},
{"2400", B2400},
{"4800", B4800},
{"9600", B9600},
{"19200", B19200},
{"38400", B38400},
{"57600", B57600},
{"115200", B115200},
{NULL, 0}
};
/**************************************
* Defines for MYSQL
*************************************/
char sql[MAX_SQL] = "";
MYSQL mysql;
/**************************************
* Alarm values
*************************************/
int alarm_value = 612;
/* STARTING MAIN */
if (argc != 4) {
fprintf(stderr, "Usage: %s port speed bbdd_ip\n", argv[0]);
exit(0);
}
if (argc == 4) {
speed_spec *s;
for (s = speeds; s->name; s++) {
if (strcmp(s->name, argv[2]) == 0) {
speed = s->flag;
fprintf(stderr, "setting speed %s\n", s->name);
break;
}
}
}
if (!strcmp(argv[1], s0)) {
//fprintf(stderr,"ttyS0 chosen\n...");
serialPort = serialPort0;
}
if (!strcmp(argv[1], s1)) {
//fprintf(stderr,"ttyS1 chosen\n...");
serialPort = serialPort1;
}
if (!strcmp(argv[1], u0)) {
//fprintf(stderr,"ttyUSB0 chosen\n...");
serialPort = USBserialPort0;
}
if (!strcmp(argv[1], u1)) {
//fprintf(stderr,"ttyUSB1 chosen\n...");
serialPort = USBserialPort1;
}
if (!strcmp(argv[1], u2)) {
//fprintf(stderr,"ttyUSB2 chosen\n...");
serialPort = USBserialPort2;
}
if (!strcmp(argv[1], u3)) {
//fprintf(stderr,"ttyUSB3 chosen\n...");
serialPort = USBserialPort3;
}
if (!strcmp(argv[1], u4)) {
//fprintf(stderr,"ttyUSB4 chosen\n...");
serialPort = USBserialPort4;
}
if (!strcmp(argv[1], u5)) {
//fprintf(stderr,"ttyUSB5 chosen\n...");
serialPort = USBserialPort5;
}
if (!strcmp(argv[1], bt0)) {
//fprintf(stderr,"rfcomm0 chosen\n...");
serialPort = BTserialPort0;
}
if (!strcmp(argv[1], bt1)) {
//fprintf(stderr,"rfcomm1 chosen\n...");
serialPort = BTserialPort1;
}
if (!strcmp(argv[1], bt2)) {
//fprintf(stderr,"rfcomm2 chosen\n...");
serialPort = BTserialPort2;
}
if (!strcmp(serialPort, "")) {
fprintf(stderr, "Choose a valid port (S0, S1, USB0, USB1, USB2, USB3, USB4, USB5, rfcomm0, rfcomm1, rfcomm2)\n");
exit(0);
}
if ((sd = open(serialPort, O_RDWR | O_NOCTTY | O_NONBLOCK)) == -1) {
fprintf(stderr, "Unable to open the serial port %s - \n", serialPort);
exit(-1);
} else {
if (!sd) {
/*Sometimes the first time you call open it does not return the
* right value (3) of the free file descriptor to use, for this
* reason you can set manually the sd value to 3 or call again
* the open function (normally returning 4 to sd), advised!*/
sd = open(serialPort, O_RDWR | O_NOCTTY | O_NONBLOCK);
}
//fprintf(stderr,"Serial Port open at: %i\n", sd);
fcntl(sd, F_SETFL, 0);
}
tcgetattr(sd, &opciones);
cfsetispeed(&opciones, speed);
cfsetospeed(&opciones, speed);
opciones.c_cflag |= (CLOCAL | CREAD);
/*No parity*/
opciones.c_cflag &= ~PARENB;
opciones.c_cflag &= ~CSTOPB;
opciones.c_cflag &= ~CSIZE;
opciones.c_cflag |= CS8;
/*raw input:
* making the applycation ready to receive*/
opciones.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
/*Ignore parity errors*/
opciones.c_iflag |= ~(INPCK | ISTRIP | PARMRK);
opciones.c_iflag |= IGNPAR;
opciones.c_iflag &= ~(IXON | IXOFF | IXANY | IGNCR | IGNBRK);
opciones.c_iflag |= BRKINT;
/*raw output
* making the applycation ready to transmit*/
opciones.c_oflag &= ~OPOST;
/*aply*/
tcsetattr(sd, TCSANOW, &opciones);
int j = 0;
int ret;
int mote_id;
int sensor_value;
mysql_init(&mysql);
mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "your_prog_name");
if (!mysql_real_connect(&mysql, argv[3], "sdemo", "sdemopass", "sensordemo", 0, NULL, 0)) {
fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(&mysql));
exit(-1);
}
else {
fprintf(stderr, "Connected to database: return: %s\n", mysql_error(&mysql));
}
while (1) {
read(sd, &c, 1);
valor[j] = c;
j++;
if ((c == '\n') || (j == (MAX - 1))) {
valor[j] = '\0';
ret = sscanf(valor, "ID_%d#%d", &mote_id, &sensor_value);
if (ret == 2) {
sprintf(sql, "insert into sensor_data values(NULL,NULL,'%d','%d');", mote_id, sensor_value);
if (mysql_query(&mysql, sql) != 0) {
fprintf(stderr, "BBDDFailed:%s\n", sql);
}
else {
fprintf(stdout, "BBDDSucceeded:%s\n", sql);
}
if (sensor_value > alarm_value) {
// send an alarm sms
int pid;
char *message = "Alert from meshlium, detected sensor value:";
char *tlf_number = "555555555";
pid = fork();
if (pid == 0) {
// This is the child. Should exec and die.
char order[255];
sprintf(order, "sms-send USB0 %s \"%s %d\"", tlf_number, message, sensor_value);
system(order);
return (0);
}
}
}
else {
fprintf(stderr, "Bad frame received\n");
}
j = 0;
valor[j] = '\0';
}
}
mysql_close(&mysql);
close(sd);
exit(0);
}
You can download the code of this tutorial.