Upload
lammien
View
216
Download
0
Embed Size (px)
Citation preview
Distributed Rain Sensing Network
Senior Capstone Design Final Report
Professor Pompili
Denis Poznykov Orestis Kotzias Walid Al Jabowbi Vladimir Samokhin May 9, 2012
Project Description. This project is collaboration between department of electrical engineering and civil and environmental engineering on sensing and modeling extreme weather events. Such events have profound effects on the sustainability of urban centers. At the same time human activities are increasing the variability of the climate and increasing the frequency of these events; driving the need for more dynamic decision-making tools. The overall objective of this research is to address urban sustainability through the development of modeling methods suitable for forecasting environmental phenomena in a changing world, and through the development of technology that can enable autonomous infrastructure to adapt to rapidly evolving environmental conditions. This research will focus on rainfall estimation and measure success by the ability to provide accurate rainfall estimates at high resolutions. Professor David Hill from Civil and Environmental Engineering has proposed the research. We worked closely with the graduate student – Cagdas Karatas and were supervised by Dr. Dario Pompili. Motivation Currently all of the rainfall data is acquired either by radar or by satellite. The satellite presents an estimated precipitation by measuring the area of the cloud. Radar, on the contrary measures the falling rain dynamically. This technique has been successfully used for many years. However, both radar and satellite predict rainfall over large areas, and quite often the actual precipitation varies largely over that area. This low spatial resolution estimation does not provide the data necessary for flood predictions. One way to solve that problem and get an accurate data about precipitation is to develop portable and mobile rain gauges that are cost efficient and can operate for years with minimum maintenance. (Figure 1) Those rain sensors can provide very accurate high-resolution rainfall estimation and help in the early detections of flooding. They can also be utilized to dynamically calibrate the radar readings. Unfortunately with quality comes a high price tag. The proposed solution is to take advantage of ubiquitous rain sensors being used in every-day consumer products. Since 2006, many vehicles began integrating simple precipitation sensors to automatically turn on the wipers. Those sensors are cheap, however they are not very accurate. The idea however is to take advantage of the multitude of those sensors, being implemented on more and more vehicles every year. The high density of the sensors is expected to compensate for lack of precision, and still deliver useful data. Figure 1: Different methods of determining precipitation. As can be seen Satellite and Radar provide estimation, while rain sensors provide more accurate data.
Team’s Contributions The project consisted of three stages: Building a network, testing the network and modeling data, and utilizing the network to be more efficient. We have completed the first two stages of the project in which we have built a network of sensors. Each one includes an independent power source using solar cells and power storage. Each sensor will be able to collect, compute, and send data to its parent router, which is then sent up the hierarchy on the network for further processing. (Figure 2) We have tested 4 sensors on the initial stage and they are fully operational. The second stage of the project was to build a database for the data and a website to be able to model data. The website’s main interface consists of a map with locations of each sensor and a link to a graph of the data collected by that sensor. The current implementation uses Google maps to achieve this functionality. The third stage is to expand the network to more than 10 sensors and optimize the data collection algorithms by implementing the proposed SILENCE paper. This paper presents a data-centric approach to distributed adaptive sampling aimed at minimizing the communication and processing overhead in autonomic networked sensor- based systems. The proposed solution exploits the spatiotemporal correlation in sensed data and eliminates redundancy in transmitted data through selective representation without compromising on accuracy of reconstruction of the monitored phenomenon at a remote monitor node. In addition, the solution also exploits the same correlations for adaptive sleep scheduling aimed at saving energy in Wireless Sensor Networks (WSNs) while also providing a mechanism for ensuring connectivity to the monitor node. In order to Implement Silence, the network structure has to be reconstructed to utilize the Xbee MESH standard. This means more efficient power use and data collection algorithms.
Figure 2. Jennet Network follows a tree topology, which we utilize with our sensors.
Jennet framework modifications In this project we have been using rain sensors combined with Jennet JN5148 model microcontrollers. Those microcontrollers are highly adequate for the job due to their wireless communication and ability to control it. Another reason why those microcontrollers are optimal is because of their low power consumption. Those chips can operate with less than 3.6V using less than 32mA, not to mention this is in operation mode with wireless transmission and receiving. In sleep mode, the current use drops to less than 3µA. Using those nodes, allowed us for the initial acquisition and analysis of data. Jennet modules are run on Jennet Framework. This framework allows you to program all the end devices, routers and the coordinator. The original framework which was available at the Jennet website took care of most of our needs, however we still needed to add some changes to the code. After making some initial changes to the code, we were able to receive the readings from all the sensors, which include tick count from the rain sensor, humidity, temperature, and light data. Special hot keys were implemented which allows the user to easily turn on/off the needed sensor, for example turning off just the light sensor and keeping the rest on. Furthermore, the incoming data is now parsed to separate the reading from different sensors. This parsing is very helpful for visualizing data on the website. After the initial functions of our sensor network were met, we started thinking of ways to decrease power consumptions. Currently we are utilizing 6-volt batteries to
power the end devices. Each end device is also equipped with a solar panel mounted on top of the enclosure. Even though the solar panel should provide enough charge to keep the battery live for weeks, we realized that that was not the case in practice. Due to modules being constantly turned on, they would quickly drain the batteries, causing us to loose transmission when it was most needed. To solve this problem we added a sleeping function to the Jennet framework. The sleeping function allows the end devices to go to sleep and therefore conserve energy while data is not being collected. We found multiple ways to implement that function. A user can customize both the length and the frequency when the device goes to sleep. However, if the device is put to sleep for over 7 seconds, it needs to boot in cold start mode. Cold start means that once the device is turned on it needs to search for local router and coordinator and send requests to connect before it can initiate the data transfer. On the other hand if the device is only asleep for 7 seconds, it can boot in Warm Start Mode, allowing it instantaneously receive and send data packets to router/coordinator. Other than implementing the sleeping function, we also plan to decrease the frequency at which the end devices transmit data. Currently they transmit data every 2 seconds. That will be changed to transmitting once every 5 min, which should be sufficient to collect accurate data, while decreasing the power consumption significantly. Finally, we began work on implementing the SILENCE. After reading the paper and talking to the graduate students, the algorithm seems fairly simple. Basically, nodes will be able to communicate with each other, sending local control messages. Those messages will contain the actual data collected by individual node. Then, this data will be compared and each node will be able to decide its state and sleeping schedule independently based on correlation and similarity of its own sampled data with that of the neighbor nodes. If the correlation and similarity is within user specified parameters, only one of the nodes will be assigned as a Representative, while the rest will become Associates. Representative will collect and report data on behalf of the group, while associates will be able to go sleep, preserving their power. Associates would still wake up periodically to check if the correlation is still within the parameters. Figure 3 displays the sample network of 13 modules, as they will be distributed on Busch Campus. In an example of SILENCE concept, only the 3 magnified nodes are transmitting the data, while the neighboring nodes are sleeping. This protocol will be essential in allowing the nodes to be self sustained for prolonged periods of time, as it will be able to reduce power consumption without compromising the accuracy. However, one thing that is needed in order to write it and test it is a larger network, of perhaps 10 or so nodes, collecting actual data. Therefore, unfortunately we will not be able to complete that before the end of the semester. Figure 3. A proposed network of modules on Busch Campus
Encapsulation of hardware One of the initial problems that we ran into was not having proper encapsulation for our end device modules. The encapsulation had to be completely airtight to prevent any water from leaking in or humidifying inside. The box had to be big enough to fit the module itself (Figure 4), as well as the battery. The rain sensor and the solar panel were to be mounted outside the box. A tipping bucket sensor is used in this project. It works on a very simple principle. As the rain falls down, it is being caught in the head of the bucket and funneled onto a tipping scale. As one side of the scale fills up with liquid, it tips down and pours the water out, at the same time raising the other side of the scale. As that happens, a proximity sensor registers a tick, which the module records. (Figure 5) Each tick is equivalent to 0.01 inches of precipitation. The rain gauge being used is one of the most accurate ones available on the market. It can register precipitation on the scale from 0.01 to 100 inches per hour, and is ready to withstand prolonged exposure to the elements without corroding or malfunctioning. We were determined to find a proper enclosure for the module, which would be able to last as long as the rain gauge, once it is deployed. In the beginning we did not give much thought to this seemingly trivial problem and used simple plastic enclosures. After initial tests, and sad realization that the boxes were leaking, we decided to reinforce them with duck plaster, hot glue, and large amounts of tape. This process proved to be both inefficient, as it took hours to seal the box, and ineffective, as the box would still leak. Finally we were able to find and
purchase industrial airtight boxes, which, once we tested them proved to be completely water resistant! Another issue that we were faced with was the lack of consistent transmission. The Jennet devices come with 3 different wireless networking modules. Two of them are short-range modules, rated to have radius of 1 km, and long range modules designed for 4 km transmission. However, after testing the modules ourselves. We saw that the short-range modules work well only up to 200 m, while the long-range module was tested up to 700m. Even though those parameters are less than those advertised, that is not a problem, as we should still be able to cover our initial are of Busch Campus. The problem arises when the line of sight between router/coordinator and the end device is obstructed. Any small obstruction, such as tree branches, causes the signal to be lost. Initially, as the end devices will only be installed on rooftops, this should not pose any problems, but if those sensors will someday be deployed on the ground, this transmission issue would need to resolved. Figure 4. Jennet board with a long-range networking module
Visualization
The visualization of the rain sensors is web based allowing anyone with an Internet connection device to view the data acquired by the rain sensors and do their own analysis. The website – www.rurainnet.com is stored on and ran from a dedicated server. The home page of the web site is an interactive Google map which displays a marker for each sensor that are color coded based on the current rainfall at that location. (Figure 3) The user can scroll around the map, zoom in and out, and even see satellite imagery for the location. When the user clicks on one of the markers an information bubble pops up containing information about the sensor. (Figure 4) Precipitation rate, temperature, light intensity, and humidity from the last sample are displayed along with the time the sample was taken. Additionally the user can click the “historical data” link to go to a web page containing a graph of historical data at that sensor. The data is displayed using an interactive time line using Google Charts. The user can zoom in on a specific time period to study patterns. (Figure 5) Additionally the user can download a file containing the data, which can be imported into many programs such as Microsoft Excel and Mathworks Matlab to perform further analysis. Figure 6. The home page of the visualization website uses an interactive Google map which displays active sensors.
Figure 7. Clicking on the desired rain sensor can pull up the information bubble.
There are 3 modules for visualization: The data collector which interacts with the sensor network, a MySQL database which stores the data, the web-server which hosts the website, and, to a lesser extent, the end client's computer which renders data. These modules can all run on separate machines as long as they are all networked (either on a local network or even via the internet). The data collector module is a C program, which can be compiled for many different architectures in the Linux environment. If at any time, the user is allowed to add more sensors to the network. The script will prompt the user as it checks for additional sensors. It will also report an error back to the user if no additional sensor is found. This process can be reversed to remove any sensor desired by the user. The sensor network sends data to the collector using a RS 232 serial port and the data collector puts it into the MySQL database. It requires very little processor time and about 1kB of memory so any modern machine will be able to run it. The MySQL database keeps a record of all of the sensors and keeps track of every report generated by the sensors. The web-server is structure in PHP it gathers data from the database and sends a script to the client, which uses Google Maps and Google Charts to visualize data. As an error-checking feature, the web-server checks if variables exist or not whenever a function is executed. This is important so the web-server doesn’t freeze and notifies the user for errors. Only the last 3 weeks of data are visualized in order to keep server load
down. If desired the user can download all of the data in a file. Data files are generated on request by the server and deleted when the download completes.
Figure 8. Data displaying previous rainfalls can be accessed online and downloaded per user’s request.
Another step approaching serial communication is with Visual C-Sharp. With this, Visual creates windows based boxes and functions are that can control serial communication settings. Settings such as baud rate, stop bit, and data bits are set that control the incoming data’s structure. The baud rate is one of the most important, in which it controls the speed of serial communication. Less transmits essentially can use less energy. The stop bit is a bit that disconnects the communication from the network. The data bits the number of bits used to represent a character of data. This should vary for our tick sensor, which should be allowed to count a number in the thousands for precipitation rate. As for temperature, humidity, and light intensity these data bits can be set low because the incoming data should be a common scaled values. With Visual, the user can easily setup settings within seconds and save. Once done, the user is allowed to read in incoming data on a text screen and vice versa send data with only clicking buttons.
Future implementations For now, a larger network of modules needs to be constructed and deployed on Busch campus. Collecting more data will allow to work out all the challenges that we are still facing. Those include data loss due to obstruction in the line of sight, as well as preserving the battery power by decreasing transmission frequency and redundant data transfers. Once this test bed is fully operational, it can be easily scaled up as modules can be installed in different locations. The locations can be stationary, such as rooftops, or moving, such as on top of Rutgers’ busses. This would allow for collecting dynamic precipitation data of a high spatial resolution. Furthermore, this research can be then used to utilize new advances in ubiquitous sensing in order to improve our capability to monitor the weather. Small, low cost sensors that are being embedded in every-day consumer products, specifically automobile wipers, can be repurposed to provide information regarding the weather at the location of the sensor. Those sensors are not nearly as accurate as our tipping bucket rain gauge, as they only have 3-5 different levels of precipitation measurements. Even so, it seems very feasible to compensate for that lack of accuracy with very high density of deployment of the sensors. Hopefully this research can demonstrate feasibility and benefits of such systems and will entice both government interest and outside investors. We strongly believe that utilizing ubiquitous sensors will be very beneficial, cost efficient way of flood prediction and rain data accumulation! Summary This has a very interesting topic and research. We believe each one of us has worked hard and learned a lot! It gives us a great pleasure to actually have something tangible to show for our final semester as undergraduates. We have a number of working modules, which hopefully will be installed all over Busch campus and will help in continuation of this research. We also have a functioning website, which serves as a great demonstration of the capabilities of the rain sensing network. We are sure that this research will be carried on by other students, as there is still a lot to do, but we are very thankful for having had the opportunity to be the initial contributors! Project Personnel Denis Poznykov – [email protected] Walid Al Jabowbi – [email protected] Orestis Kotzias – [email protected] Vladimir Samokhin – [email protected] Capstone Section Ranking Sensor, Control and DSP Systems (Pompili -- 332:418) Teammate Qualifications Denis Poznykov 332:417, 332: 463, 332:472, 332:423 Walid Al Jabowbi 332:437 Orestis Kotzias 332:417, 332: 463, 332:472
Vladimir Samokhin - 198:214, 198:352, 332:351, 332:343, 198:416, 332:452, 332:437 Bibliography SILENCE: Distributed Adaptive Sampling for Sensor-based Autonomic Systems, Eun Kyung Lee, Hariharasudhan Viswanathan, and Dario Pompili JenNet Stack User Guide, JN-UG-3041, Revision 2.0, 28 September 2010 Downscaling Radar-Rainfall Data via Ubiquitous Sensing and Data Fusion, D.J. Hill and F. Farzan
Appendix / Codes Developed
Add / Remove Sensor ( C ) add_sensor.c * add_sensor.c * * A short program to add information about another sensor to * the sql database. Requires user to be precise with requests * in order to preserve database integrity. */ #include <mysql/mysql.h> #include <stdlib.h> #include <stdio.h> #define SQL_HOST "mysql.sadionline.com" #define SQL_USR "waleed25" #define SQL_PASSWORD "Walid234" #define SQL_PORT 0 int main(int argc, char **argv) { int addr; MYSQL *mysql; MYSQL_RES *result; double latt, longe, conv; char MODIFY=0; char query_str[512]; if(argc!=5 && argc!=6) { printf("invocation: add_sensor <address(hex)> <latitude> <longitude> <conversion> <-‐m(modify, optional)\n"); exit(0); } if(argc==6 && argv[5][0]=='-‐' && argv[5][1]=='m') { MODIFY=1; } else if(argc==6) {
printf("invocation: add_sensor <address(hex)> <latitude> <longitude> <conversion> <-‐m(modify, optional)\n"); exit(0); } //scan arguments if(sscanf(argv[1], "%x", &addr)!=1 || sscanf(argv[2], "%lf", &latt)!=1 || sscanf(argv[3], "%lf", &longe)!=1 || sscanf(argv[4], "%lf", &conv)!=1) { printf("invocation: add_sensor <address(hex)> <latitude> <longitude> <conversion> <-‐m(modify, optional)\n"); exit(0); } //initialize connection mysql=mysql_init(0); if(mysql_real_connect(mysql, SQL_HOST, SQL_USR, SQL_PASSWORD, "rain_sensors", SQL_PORT, 0, 0)==0) { printf("%s: error connecting to database\n", argv[0]); exit(1); } //if modify remove the row if(MODIFY==1) { sprintf(query_str, "SELECT * FROM nodes WHERE addr=%d;", addr); mysql_query(mysql, query_str); result=mysql_store_result(mysql); //See if result is already stored if(mysql_num_rows(result)==0) { printf("%s: Sensor %x not found. Retry without -‐m flag\n", argv[0], addr); exit(0); } //Idiot check to see if more than one entry for address exists(should't happen) else if(mysql_num_rows(result)>1) { sprintf(query_str, "DELETE FROM nodes WHERE addr=%d;", addr); mysql_query(mysql, query_str);
sprintf(query_str, "INSERT INTO nodes (addr, lat, longi, tick_conversion) VALUES (%d, %lf, %lf, %lf);", addr, latt, longe, conv); mysql_query(mysql, query_str); } //Otherwise update the entry else { sprintf(query_str, "UPDATE nodes SET lat=%lf, longi=%lf, tick_conversion=%lf WHERE addr=%d;", latt, longe, conv, addr); mysql_query(mysql, query_str); } } else { sprintf(query_str, "SELECT * FROM nodes WHERE addr=%d;", addr); mysql_query(mysql, query_str); result=mysql_store_result(mysql); //See if result is already stored if(mysql_num_rows(result)==0) { sprintf(query_str, "INSERT INTO nodes (addr, lat, longi, tick_conversion) VALUES (%d, %lf, %lf, %lf);", addr, latt, longe, conv); mysql_query(mysql, query_str); } else { printf("%s: Sensor %x already exists. Retry with -‐m flag\n", argv[0], addr); exit(0); } } mysql_close(mysql); printf("%s: Operation successful! Restart data_collector to enact changes.\n", argv[0]); } makefile # makefile for add/remove sensor tools CC=gcc all:add_sensor remove_sensor add_sensor:add_sensor.c
sh -‐c "$(CC) -‐o add_sensor `mysql_config -‐-‐cflags` add_sensor.c `mysql_config -‐-‐libs`" add_sensor.c remove_sensor:remove_sensor.c sh -‐c "$(CC) -‐o remove_sensor `mysql_config -‐-‐cflags` remove_sensor.c `mysql_config -‐-‐libs`" remove_sensor.c
remove_sensor.c * remove_sensor.c * * This will remove the record of a rain sensor from the * sql database */ #include <mysql/mysql.h> #include <stdlib.h> #include <stdio.h> #define SQL_HOST "mysql.sadionline.com" #define SQL_USR "waleed25" #define SQL_PASSWORD "Walid234" #define SQL_PORT 0 int main(int argc, char **argv) { char PURGE=0; //a control variable int addr; MYSQL *mysql; MYSQL_RES *result; char query_str[512]; //argument check if((argc!=2 && argc!=3) || sscanf(argv[1], "%x", &addr)!=1) { printf("invocation: remove_sensor <address(hex)> <-‐purge(optional)>\n"); exit(1); } if(argc==3 && strcmp("-‐purge", argv[2])!=0)
{ printf("invocation: remove_sensor <address(hex)> <-‐purge(optional)>\n"); exit(1); } if(argc==3) { printf("%s: All data associated with %x will be removed(ctrl-‐c to abort).\n", argv[0], addr); int i; for(i=5; i>0; i-‐-‐) { printf("\r%d", i); sleep(1); } PURGE=1; } //initialize connection mysql=mysql_init(0); if(mysql_real_connect(mysql, SQL_HOST, SQL_USR, SQL_PASSWORD, "rain_sensors", SQL_PORT, 0, 0)==0) { printf("%s: error connecting to database\n", argv[0]); exit(1); } sprintf(query_str, "SELECT * FROM nodes WHERE addr=%d;", addr); mysql_query(mysql, query_str); result=mysql_store_result(mysql); //See if result is already stored if(mysql_num_rows(result)==0) { printf("%s: Sensor %x not found\n", argv[0], addr); exit(0); } else { sprintf(query_str, "DELETE FROM nodes WHERE addr=%d;", addr); mysql_query(mysql, query_str); printf("%s: Record deleted sucessfully! Restart data_collector to enable changes.\n", argv[0]); } if(PURGE==1)
{ sprintf(query_str, "DELETE FROM data WHERE addr=%d;", addr); mysql_query(mysql, query_str); printf("%s: Succesfully purged data!\n", argv[0]); } mysql_close(mysql); }
Data collector data_collector.c * data_collector.c * This is the main file in the data collector module. It reads data from the specified * serial port, analyzes the data, and forks to create a new process to store the data in * a sql database. */ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <termios.h> #include <string.h> #include <pthread.h> #include "sensor_data.h" #include "write_data.h" #define BAUDRATE B115200 int main(int argc, char **argv) { int serial; //serial port file descriptor unsigned int data[5]; //scanned data unsigned int address; //address of the sensor char mode; char buff[50]; //buffer for data int numread; sensor_data_t *data_st;
write_data_t *wr_data; pthread_t tid; struct termios tio; //serial port configuration memset(&tio, 1, sizeof(tio)); //get serial port from command line arguments if(argc!=2) { printf("%s: Invoke as ./data_collectormake <serial port>\n", argv[0]); exit(1); } //open serial port if((serial = open(argv[1], O_RDONLY | O_NOCTTY))<0) { printf("%s: error opening serial port\n", argv[0]); exit(1); } //configure port tio.c_cflag = BAUDRATE | CRTSCTS | CS8 |CLOCAL | CREAD; tio.c_iflag = IGNPAR | ICRNL; tio.c_oflag = 0; tio.c_lflag = ICANON; tcflush(serial, TCIFLUSH); tcsetattr(serial,TCSANOW,&tio); //Get list of sensors init_sensor_data(data_st); for(;;) { //read from serial port and use first char to classify message numread = read(serial, &buff, sizeof(buff)); switch(buff[0]) { //data message case 'D': //scan in the message if(sscanf(buff, "D:%x:%d:%d:%d:%d:%d\n", &address, &data[0], &data[1], &data[2], &data[3], &data[4])<6) {
printf("%s: Bad data\n", argv[0]); break; } //create the write data struct wr_data=(write_data_t*)malloc(sizeof(write_data_t)); data[1]=(data[1]<<8)+data[0]; wr_data-‐>addr=address; wr_data-‐>ticks=data[1]; wr_data-‐>light=data[2]; wr_data-‐>humidity=data[3]; wr_data-‐>temp=data[4]; wr_data-‐>data=data_st; //process the data write_data((void*)wr_data); //pthread_create(&tid, 0, write_data, (void*)wr_data); //pthread_detach(tid); break; case 'R': if(sscanf(buff, "R:%d\n", &data[0])<1) { perror("data_collector: Bad data\n"); break; } printf("SVC_RSP:%d\n", data[0]); break; case 'Q': if(sscanf(buff, "Q:%d\n", &data[0])<1) { perror("data_collector: Bad data\n"); break; } printf("REQ_RSP:%d\n", data[0]); break; case 'U': if(sscanf(buff, "U:%d\n", &data[0])<1) { perror("data_collector: Bad data\n"); break; } printf("NETWORK_UP:%d\n", data[0]); break; case 'J': if(sscanf(buff, "J:%x:%d\n", &data[0], &data[1])<2) {
perror("data_collector: Bad data\n"); break; } printf("Child joined:%x, %d\n", data[0], data[1]); break; case 'L': if(sscanf(buff, "L:%x:%d\n", &data[0], &data[1])<2) { perror("data_collector: Bad data\n"); break; } printf("Child left:%x, %d\n", data[0], data[1]); break; case 'T': if(sscanf(buff, "T:%d\n", &data[0])<1) { perror("data_collector: Bad data\n"); break; } printf("Ticks:%d\n", data[0]); break; default: perror("data_collector: invalid message type\n"); } } return 0; } makefile CC=gcc CFLAGS=-‐c EXEC=data_collector $(EXEC):data_collector.o sensor_data.o write_data.o sh -‐c "$(CC) -‐o $(EXEC) -‐pthread `mysql_config -‐-‐cflags` data_collector.o sensor_data.o write_data.o `mysql_config -‐-‐libs`" data_collector.o:data_collector.c sensor_data.h $(CC) $(CFLAGS) data_collector.c -‐pthread sensor_data.o:sensor_data.c sensor_data.h $(CC) $(CFLAGS) sensor_data.c write_data.o:write_data.c write_data.h
$(CC) $(CFLAGS) write_data.c sensor_data.c /* Vladimir Samokhin * sensor_data.c * * Gets data about the rain sensors from a database and * stores it in a linked list. */ #include "sensor_data.h" void init_sensor_data(sensor_data_t* data) { MYSQL *mysql; MYSQL_RES *result; MYSQL_ROW row; sensor_data_t *dataptr=data; //initialize connection mysql=mysql_init(0); if(mysql_real_connect(mysql, SQL_HOST, SQL_USR, SQL_PASSWORD, "rain_sensors", SQL_PORT, 0, 0)==0) { printf("sensor_data: error connecting to database\n"); exit(1); } //Get the list of sensor data mysql_query(mysql, "SELECT * FROM nodes;"); result=mysql_store_result(mysql); //verify that there are valid results if(mysql_num_rows(result)==0) { printf("sensor_data: error: no sensors in database\n"); exit(1); } if(mysql_num_fields(result)!=5) { printf("sensor_data: error: invalid database\n"); exit(1); }
//read fetched data and store it in a linked list data=(sensor_data_t*)malloc(sizeof(sensor_data_t)); memset(dataptr, 0, sizeof(sensor_data_t)); while((row=mysql_fetch_row(result))) { sscanf(row[1], "%d", &(dataptr-‐>address)); sscanf(row[4], "%lf", &(dataptr-‐>conversion)); pthread_mutex_init(&dataptr-‐>lock, 0); dataptr-‐>next=(sensor_data_t*)malloc(sizeof(sensor_data_t)); dataptr=dataptr-‐>next; memset(dataptr, 0, sizeof(sensor_data_t)); } mysql_free_result(result); mysql_close(mysql); } //Frees all alocated memory void free_sensor_data(sensor_data_t* data) { sensor_data_t* temp; while(data!=0) { temp=data; data=data-‐>next; free(temp); } } sensor_data.h * sensor_data.h * * Gets data about the rain sensors from a database and * stores it in a linked list. */ #ifndef SENSOR_DATA_H #define SENSOR_DATA_H #include <time.h> #include <mysql/mysql.h> #include <stdio.h> #include <string.h> #include <pthread.h>
#include <stdlib.h> #define SQL_HOST "mysql.sadionline.com" #define SQL_USR "waleed25" #define SQL_PASSWORD "Walid234" #define SQL_PORT 0 //a data structure to store the relevant information about active rain sensors typedef struct sensor_data { unsigned int address; double conversion; time_t last_time; pthread_mutex_t lock; struct sensor_data *next; } sensor_data_t; /* Gets the sensor data from the database and puts it in a * linked list of sensor_data_t. Allocates data into sensor_data_t. * Returns 0 on success. */ void init_sensor_data(sensor_data_t*); //Free sensor_data_t structure void free_sensor_data(sensor_data_t*); #endif write_data.c * write_data.c * * This file contains all of the functions that write * data aquired from sensors to the mysql database */ #include "write_data.h" void *write_data(void *wd) { write_data_t *wr_data=(write_data_t*)wd; MYSQL *mysql; sensor_data_t *dataptr=wr_data-‐>data; time_t ctime; char sql_query[512];
double elapsed_time=0; double precip_rate=0; double precip=0; //locate record of reporting sensor while(dataptr-‐>address!=0) { if(dataptr-‐>address==wr_data-‐>addr) { break; printf("broken\n"); } dataptr=dataptr-‐>next; } if(dataptr-‐>address==0) { printf("Write_data: error: no record of sensor %x. Try restarting data_collector.\n", wr_data-‐>addr); free(wd); return; } pthread_mutex_lock(&(dataptr-‐>lock)); //calculate time and precipitation rate precip=(double)(wr_data-‐>ticks)*dataptr-‐>conversion; time(&ctime); if(dataptr-‐>last_time!=0) { elapsed_time = difftime(ctime, dataptr-‐>last_time)/60/60; //elapsed time in hours since last report precip_rate=precip/elapsed_time; } else { elapsed_time=0; precip_rate=0; } dataptr-‐>last_time=ctime; pthread_mutex_unlock(&(dataptr-‐>lock)); //Connect to database mysql=mysql_init(0);
if(mysql_real_connect(mysql, SQL_HOST, SQL_USR, SQL_PASSWORD, "rain_sensors", SQL_PORT, 0, 0)==0) { printf("Write_data: error connecting to database\n"); mysql_close(mysql); return 0; } sprintf(sql_query, "INSERT INTO data (time, address, precip_rate, light, humidity, temp) VALUES (NOW(), %i, %lf, %i, %d, %d);", wr_data-‐>addr, precip_rate, wr_data-‐>light, wr_data-‐>humidity, wr_data-‐>temp); printf("%s\n", sql_query); mysql_query(mysql, sql_query); mysql_close(mysql); free(wd); return 0; } write_data.h * write_data.h * * This file contains all of the functions that write * data aquired from sensors to the mysql database */ #ifndef WRITE_DATA_H #define WRITE_DATA_H #include <mysql/mysql.h> #include <stdio.h> #include <pthread.h> #include "sensor_data.h" //A struct to store the data to be written to the mysql database typedef struct { sensor_data_t *data; int addr; int ticks; int light; int humidity; int temp; }write_data_t; void *write_data(void *data);
#endif
Data import dataimport.c #include <stdio.h> #include <stdlib.h> #include <mysql/mysql.h> #define SQL_HOST "mysql.sadionline.com" #define SQL_USR "waleed25" #define SQL_PASSWORD "Walid234" #define SQL_PORT 0 typedef struct data_t { char month[6]; int day; int hour; int min; float sec; int year; int address; int tick0, tick1; int light; int hum; int temp; struct data_t *next; } data; typedef struct packed_data_t { int address; int year; int month; int day; int hour, min, sec; double precip_rate; int light; int hum; int temp; struct packed_data_t *next; }packed_data;
int main(int argc, char **argv) { data *raw_data, *rd_ptr; FILE *file; if(0==(file=fopen(argv[1], "r"))) { perror("error opening file\n"); return -‐1; } raw_data=malloc(sizeof(data)); raw_data-‐>next=0; char day[6]; rd_ptr=raw_data; //read data while(1) { int ret=fscanf(file, "[%s %s %d %d:%d:%f %d] D:%x:%d:%d:%d:%d:%d\n", day, rd_ptr-‐>month, &(rd_ptr-‐>day), &(rd_ptr-‐>hour), &(rd_ptr-‐>min), &(rd_ptr-‐>sec), &(rd_ptr-‐>year), &(rd_ptr-‐>address), &(rd_ptr-‐>tick0), &(rd_ptr-‐>tick1), &(rd_ptr-‐>light), &(rd_ptr-‐>hum), &(rd_ptr-‐>temp)); if(ret==EOF) { rd_ptr-‐>address=0; break; } if(ret!=13) { while(fgetc(file)!='\n'); continue; } //hardcoded to only look for one sensor if(rd_ptr-‐>address!=0x1c7227) { continue; } rd_ptr-‐>next=malloc(sizeof(data)); rd_ptr=rd_ptr-‐>next; rd_ptr-‐>next; } rd_ptr=raw_data;
fclose(file); printf("Data imported\n"); //condense data packed_data *p_data, *pd_ptr; p_data=malloc(sizeof(packed_data)); pd_ptr=p_data; pd_ptr-‐>next=0; while(1) { int ticks=0; int start_min; int start_sec; int stop_min; start_min=rd_ptr-‐>min; start_sec=(int)(rd_ptr-‐>sec); stop_min=start_min+5; if(stop_min>59) stop_min-‐=60; while(rd_ptr-‐>min!=stop_min) { ticks+=rd_ptr-‐>tick0; if(rd_ptr-‐>next==0) { break; } rd_ptr=rd_ptr-‐>next; } double hours=0; if(start_min<rd_ptr-‐>min) { hours+=(double)(rd_ptr-‐>min-‐start_min)/60; } else { hours+=(double)((60-‐start_min)+rd_ptr-‐>min)/60; } if(start_sec<rd_ptr-‐>sec) { hours+=(double)(rd_ptr-‐>sec-‐start_sec)/60/60; } else { hours+=(double)((60-‐start_sec)+rd_ptr-‐>sec)/60/60;
} //printf("Start %d, end %d, hours %lf, ticks %d\n", start_min, rd_ptr-‐>min, hours, ticks); pd_ptr-‐>precip_rate=(double)ticks*0.01/hours; pd_ptr-‐>year=rd_ptr-‐>year; pd_ptr-‐>address=rd_ptr-‐>address; pd_ptr-‐>day=rd_ptr-‐>day; pd_ptr-‐>hour=rd_ptr-‐>hour; pd_ptr-‐>min=rd_ptr-‐>min; pd_ptr-‐>month=4; pd_ptr-‐>sec=(int)rd_ptr-‐>sec; pd_ptr-‐>light=rd_ptr-‐>light; pd_ptr-‐>hum=rd_ptr-‐>hum; pd_ptr-‐>temp=rd_ptr-‐>temp; if(rd_ptr-‐>next==0) { break; } pd_ptr-‐>next=malloc(sizeof(packed_data)); pd_ptr=pd_ptr-‐>next; pd_ptr-‐>next=0; } pd_ptr=p_data; //add to mysql db. MYSQL *mysql; mysql=mysql_init(0); if(mysql_real_connect(mysql, SQL_HOST, SQL_USR, SQL_PASSWORD, "rain_sensors", SQL_PORT, 0, 0)==0) { printf("%s: error connecting to database\n", argv[0]); exit(1); } while(pd_ptr-‐>next!=0 && pd_ptr!=0) { char query_str[256]; sprintf(query_str, "INSERT INTO data (time, address, precip_rate, light, humidity, temp) VALUES (\"%d-‐%d-‐%d %d:%d:%d\", %i, %lf, %i, %d, %d);", pd_ptr-‐>year, pd_ptr-‐>month, pd_ptr-‐>day, pd_ptr-‐>hour, pd_ptr-‐>min, pd_ptr-‐>sec, pd_ptr-‐>address, pd_ptr-‐>precip_rate, pd_ptr-‐>light, pd_ptr-‐>hum, pd_ptr-‐>temp); mysql_query(mysql, query_str); pd_ptr=pd_ptr-‐>next; } return 0;
} makefile dataimport:dataimport.c sh -‐c "gcc -‐o dataimport dataimport.c `mysql_config -‐-‐cflags` `mysql_config -‐-‐libs`"
rain sensor simulate RainSensorSim.pde /* * RainSensorSim.pde * * Arduino sketch to simulate the rs232 output * of the rain sensor network */ int addr[3]; void setup() { Serial.begin(19200); addr[0]=0x123; addr[1]=0x456; addr[2]=0x789; } void loop() { delay(4000); int node = random(3); int ticks=random(50); int light = random(50); int hum=random(10); int temp=random(40)-‐10; Serial.print("D:"); Serial.print(addr[node], HEX); Serial.print(":0:"); Serial.print(ticks); Serial.print(":"); Serial.print(light); Serial.print(":"); Serial.print(hum); Serial.print(":"); Serial.print(temp); Serial.print("\n");
}
Website data.php <?php $sqlHost="localhost:7026"; //set host to $sqlUsr="rain"; //set username $sqlPwd="rain"; //set password ini_set('display_errors', '1'); //displays errors, false if failure ini_set('display_startup_errors', '1'); //displays startup errors, false if failure error_reporting(E_ALL); //reports all errors if(!isset($_GET['addr'])) //if nothing set, true & print below { echo("Error: Address not specified"); //print "" die(); //print to user & exit } $addr=$_GET['addr']; //set variable 'addr' to 'get inputs from addr' $numaddr = hexdec($addr); //set numaddr to 'addr converted into hexadecimal' if(isset($_GET['ALL'])) // check if 'ALL' is set { $all=$_GET['ALL']; // true, set 'all' to 'get inputs from ALL' } else { $all=false; //false, 0 } $con=mysql_connect($sqlHost, $sqlUsr, $sqlPwd); //set con to connect to sql if(!$con) //check if no connection { die(mysql_error()); // retrieve error text and exit } $dbSelect = mysql_selectdb("rain_sensors", $con); // set 'dbSelect' to select database 'rain_sensors' with connection from '$con' if(!$dbSelect) //if not 'dbSelect' { die(mysql_error()); //retrieve error text and exit }
if($all==true) //if 'all' is true { $result = mysql_query("SELECT * FROM data WHERE address=$addr;"); //set result to specific database } else { $result = mysql_query("SELECT * FROM data WHERE address=$addr and time>=DATE_SUB(NOW(),INTERVAL 3 week);"); //set result to specific database with time greater than previous 3 weeks to date } if(!$result) //check if results do not exit { echo("Invalid address"); //print die(); // if no 'results', then exit } $filename=tempnam("../data", "data"); //set 'filename' to create temporary filename 'data' under directory 'data'. if none made, return false $file=fopen($filename, "w"); //set 'file' to open a file 'filename'. 'w' is write only for open and clear/create new file if none exist if( $file == false ) //check if 'file' does not exit { echo ( "Error in opening file" ); exit(); // or die(), exits } fwrite($file, "timestamp; precipitation rate; light; humidity; temperature;\r\n"); //write in measurement titles into 'file' while($row = mysql_fetch_array($result)) //while 'row' is set to data from 'result' { fwrite($file, $row['time'] . ";" . $row['precip_rate'] . ";" . $row['light'] . ";" . $row['humidity'] . ";" . $row['temp'] . ";\r\n"); } fclose($file); $fname="data" . $addr . ".dat"; header("Cache-‐Control: public"); header("Content-‐Description: File Transfer"); header("Content-‐Length: ". filesize("$filename").";"); header("Content-‐Disposition: attachment; filename=$fname");
header("Content-‐Type: application/octet-‐stream; "); header("Content-‐Transfer-‐Encoding: binary"); readfile($filename); unlink($filename); ?> history.php <?php $sqlHost="localhost:7026"; $sqlUsr="rain"; $sqlPwd="rain"; ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL); require("include/HistoryHelper.php"); if(!isset($_GET['addr'])) { echo("Error: Address not specified"); die(); } $addr=$_GET['addr']; $numaddr = hexdec($addr); $con=mysql_connect($sqlHost, $sqlUsr, $sqlPwd); if(!$con) { die(mysql_error()); } $dbSelect = mysql_selectdb("rain_sensors", $con); if(!$dbSelect) { die(mysql_error()); } $HH=new HistoryHelper($numaddr); ?> <html> <head>
<title>Historical data for <?php echo($addr)?></title> <?php $HH-‐>printJS();?> </head> <body> <b>Last three weeks of historical weather data for sensor <?php echo($addr)?></b><br> <div id='chart_div' style='width: 800px; height: 500px;'></div> Precipitation rate in inches per hour, temperature in celcius, and light in kilo lumens. <br><br> Download data file:<a href="data.php?addr=<?php echo($addr)?>">last three weeks<a> -‐ <a href="data.php?addr=<?php echo($addr)?>&ALL=true">all data(warning:file may be large)<a><br> <a href="history.php?addr=<?php echo($addr)?>">Refresh</a> -‐ <a href="index.php">Return to map</a> -‐ <a href="help.html">Help</a> -‐ <a href="about.html">About</a> </body> </html> index.php <?php $sqlHost="localhost:7026"; $sqlUsr="rain"; $sqlPwd="rain"; ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL); require_once('include/GoogleMap.php'); //this was found on the internet. It interfaces with the google maps api which is in java script require('include/OverviewLoader.php'); $MAP_OBJECT = new GoogleMapAPI('map'); $MAP_OBJECT-‐>_minify_js = isset($_REQUEST["min"])?FALSE:TRUE; $MAP_OBJECT-‐>setMapType(''); $MAP_OBJECT-‐>setWidth(700); $OLoader=new OverviewLoader($MAP_OBJECT, $sqlHost, $sqlUsr, $sqlPwd); $OLoader-‐>getData(); $OLoader-‐>placeMarkers();
?> <html> <head> <title>Rainfall Sensor Data</title> <?=$MAP_OBJECT-‐>getHeaderJS();?> <?=$MAP_OBJECT-‐>getMapJS();?> </head> <body> <b>Current rainfall data</b> <?=$MAP_OBJECT-‐>printOnLoad();?> <?=$MAP_OBJECT-‐>printMap();?> <?=$MAP_OBJECT-‐>printSidebar();?> <pre>No rain:<img src="http://dl.dropbox.com/u/21246497/rainsensor/blue.gif" alt="blue" /> 0-‐2 inches/hour:<img src="http://dl.dropbox.com/u/21246497/rainsensor/green.gif" alt="green" /> 2-‐4 inches/hour:<img src="http://dl.dropbox.com/u/21246497/rainsensor/yellow.gif" alt="yellow" /> >4 inches/hour:<img src="http://dl.dropbox.com/u/21246497/rainsensor/red.gif" alt="red" /> No data:<img src="http://dl.dropbox.com/u/21246497/rainsensor/no_data.gif" alt="white" /> </pre> <a href="index.php">Refresh</a> -‐ <a href="help.html">Help</a> -‐ <a href="about.html">About</a> </body> </html>
Outside Included resources GoogleMap.php HistoryHelper/php JSMin.php OverviewLoader.php
Sql database databasestructure.sql -‐-‐ phpMyAdmin SQL Dump -‐-‐ version 3.3.10.4 -‐-‐ http://www.phpmyadmin.net -‐-‐ -‐-‐ Host: mysql.sadionline.com -‐-‐ Generation Time: May 02, 2012 at 07:37 PM
-‐-‐ Server version: 5.1.39 -‐-‐ PHP Version: 5.2.17 SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; -‐-‐ -‐-‐ Database: `rain_sensors` -‐-‐ -‐-‐ -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ -‐-‐ -‐-‐ Table structure for table `data` -‐-‐ CREATE TABLE IF NOT EXISTS `data` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `time` datetime NOT NULL, `address` int(10) unsigned NOT NULL, `precip_rate` double unsigned NOT NULL, `light` float NOT NULL, `humidity` float NOT NULL, `temp` float NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=12785 ; -‐-‐ -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ -‐-‐ -‐-‐ Table structure for table `nodes` -‐-‐ CREATE TABLE IF NOT EXISTS `nodes` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `addr` int(10) unsigned DEFAULT NULL, `lat` double DEFAULT NULL, `longi` double DEFAULT NULL, `tick_conversion` double NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ; dump.sql -‐-‐ MySQL Administrator dump 1.4 -‐-‐
-‐-‐ -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ -‐-‐ Server version 5.1.61-‐0ubuntu0.11.10.1 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -‐-‐ -‐-‐ Create schema rain_sensors -‐-‐ CREATE DATABASE IF NOT EXISTS rain_sensors; USE rain_sensors; CREATE TABLE `rain_sensors`.`data` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `time` datetime NOT NULL, `address` int(10) unsigned NOT NULL, `precip_rate` double unsigned NOT NULL, `light` float NOT NULL, `humidity` float NOT NULL, `temp` float NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=52 DEFAULT CHARSET=latin1; INSERT INTO `rain_sensors`.`data` VALUES (1,'2012-‐03-‐21 16:33:22',1342408,0,6,47,25), (2,'2012-‐03-‐21 16:33:24',1342408,0,6,47,25), (3,'2012-‐03-‐21 16:33:26',1342408,0,6,47,25), (4,'2012-‐03-‐21 16:33:28',1342408,0,6,47,25), (5,'2012-‐03-‐21 16:33:30',1342408,0,6,47,25), (6,'2012-‐03-‐21 16:33:32',1342408,0,6,47,25), (7,'2012-‐03-‐21 16:33:34',1342408,0,6,47,25), (8,'2012-‐03-‐21 16:33:36',1342408,0,6,47,25), (9,'2012-‐03-‐21 16:33:38',1342408,0,6,47,25), (10,'2012-‐03-‐21 16:33:40',1342408,0,6,47,25), (11,'2012-‐03-‐21 16:33:42',1342408,0,6,47,25), (12,'2012-‐03-‐21 16:33:44',1342408,0,6,46,25),
(13,'2012-‐03-‐21 16:33:46',1342408,0,6,46,25), (14,'2012-‐03-‐21 16:33:48',1342408,0,6,46,25), (15,'2012-‐03-‐21 16:33:50',1342408,0,6,46,25), (16,'2012-‐03-‐21 16:33:52',1342408,0,6,46,25), (17,'2012-‐03-‐21 16:33:54',1342408,0,6,46,25), (18,'2012-‐03-‐21 16:33:56',1342408,0,6,46,25), (19,'2012-‐03-‐21 16:33:58',1342408,0,6,46,25), (20,'2012-‐03-‐21 16:34:00',1342408,0,6,46,25), (21,'2012-‐03-‐21 16:34:02',1342408,0,6,46,25), (22,'2012-‐03-‐21 16:34:04',1342408,0,6,46,25), (23,'2012-‐03-‐21 16:34:06',1342408,0,6,46,25), (24,'2012-‐03-‐21 16:34:08',1342408,0,6,46,25), (25,'2012-‐03-‐21 16:34:10',1342408,0,6,46,25), (26,'2012-‐03-‐21 16:34:12',1342408,0,6,46,25), (27,'2012-‐03-‐21 16:34:14',1342408,0,6,46,25), (28,'2012-‐03-‐21 16:34:16',1342408,0,6,46,25), (29,'2012-‐03-‐21 16:34:18',1342408,0,6,46,25), (30,'2012-‐03-‐21 16:34:20',1342408,0,6,46,25), (31,'2012-‐03-‐21 16:34:22',1342408,0,6,46,25), (32,'2012-‐03-‐21 16:34:24',1342408,0,6,46,25), (33,'2012-‐03-‐21 16:34:25',1342408,0,6,46,25), (34,'2012-‐03-‐21 16:34:28',1342408,0,6,46,25), (35,'2012-‐03-‐21 16:34:30',1342408,0,6,46,25), (36,'2012-‐03-‐21 16:34:32',1342408,0,6,46,25), (37,'2012-‐03-‐21 16:34:34',1342408,0,6,46,25), (38,'2012-‐03-‐21 16:34:36',1342408,0,6,46,25), (39,'2012-‐03-‐21 16:34:38',1342408,0,6,46,25), (40,'2012-‐03-‐21 16:34:40',1342408,0,6,46,25), (41,'2012-‐03-‐21 16:34:42',1342408,0,6,46,25), (42,'2012-‐03-‐21 16:34:44',1342408,0,6,46,25), (43,'2012-‐03-‐21 16:34:46',1342408,0,6,46,25), (44,'2012-‐03-‐21 16:34:48',1342408,0,6,46,25), (45,'2012-‐03-‐21 16:34:51',1342408,0,6,46,25), (46,'2012-‐03-‐21 16:34:53',1342408,0,6,46,25), (47,'2012-‐03-‐21 16:34:55',1342408,0,6,46,25), (48,'2012-‐03-‐21 16:34:57',1342408,0,6,46,25), (49,'2012-‐03-‐21 16:34:59',1342408,0,6,46,25), (50,'2012-‐03-‐21 16:35:01',1342408,0,6,46,25), (51,'2012-‐03-‐21 16:35:03',1342408,0,6,46,25); CREATE TABLE `rain_sensors`.`nodes` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `addr` int(10) unsigned DEFAULT NULL, `lat` double DEFAULT NULL, `longi` double DEFAULT NULL,
`tick_conversion` double NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1; INSERT INTO `rain_sensors`.`nodes` VALUES (2,1342408,1,1,1); /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; makefile # a makefile for the entire project all:data_collector add_remove_sensor add_remove_sensor: cd add_remove_sensor/ make cd ../ data_collector: cd data_collector/ make cd ../