Weather Station on Arduino from A to Z. Part 5
Ending. The previous part .
Table of contents:
- Part 1. Requirements. The choice of iron. General scheme
- Part 2. Software. Central unit, iron
- Part 3. Central unit, software
- Part 4. Transom Sensor
- Part 5. MySQL, PHP, WWW, Android
Window sensor. Software
Let's talk about the software behind the window sensor. After that you will have a complete system with which you can already experiment.
Let me remind you that the server is a central, home unit that can communicate with the Internet via WiFi, and the client is a remote, out-of-window sensor that transmits data to the server via radio.
The source code for both server and client is here .
Source texts are provided with detailed comments.
Almost nothing needs to be configured on the client.
The radio transmitter nRF24L01 +, or rather the RadioHead library, requires specifying the server and client addresses. Addresses are provided in case you have more than one server and client. An address is just any integer. When a client sends a packet with data to the server, it indicates for which server the packet is intended. The server, knowing its own address, in turn, determines whether this packet is intended for it.
Therefore, SERVER_ADDRESS
on the server and on the client should be the same, but CLIENT_ADDRESS
for different clients should be different. In other words, if you connect another new sensor to our system in the future, CLIENT_ADDRESS
you will need to change it.
// Адрес сервера и клиента#define SERVER_ADDRESS 10#define CLIENT_ADDRESS 20 // ИЗМЕНИТЬ для другого экземпляра !!!
The number of the radio channel RF_CHANNEL
must be the same for all. The default is 2. I changed the default number, you can choose any other.
// Номер радиоканала. Должен быть КАК И У СЕРВЕРА#define RF_CHANNEL 73
The settings of the voltmeter to measure the battery supply voltage must be changed:
// Резисторы делителя напряжения, фактические значенияconstfloat r1 = 100400; // 100Kconstfloat r2 = 9960; // 10K// Эту константу необходимо откалибровать индивидуально// как описано здесь http://localhost/arduino-secret-true-voltmeter/constfloat typVbg = 1.082; // обычно в пределах 1.0 -- 1.2 В
To save energy, the Lightweight low power library for Arduino is used .
Here are my measurements of actual consumption for the Arduino Pro Mini with this one:
- usually 25mA
- when working with DHT the same
- with radio transmission 38 mA
- with LowPower.idle 15 mA
- with LowPower.powerDown 7.5 mA
The client makes measurements of temperature, humidity and voltage, packs it all into a data structure, sends data to the server and “falls asleep”. If there were errors during the transfer, then the transfer is immediately repeated.
The server (central, home unit), in turn, receives data, acknowledges receipt and processes it.
Database, MySQL, PHP, WWW-server
After the work done, we have a fully functional construction of the weather station. But now such meteorological stations are a dime a dozen, local crafts, this is no longer fashionable. We have the internet of things.
Therefore, let's talk about how to access these your Internet sites, attach to our weather station a database and a web-face to it.
Task setting for "webcam":
- receive and store weather station data: temperature, humidity, atmospheric pressure, supply voltage
- display this data
- build graphics.
In this case, we need a hosting with support for Apache, PHP and MySQL with the module mysqli. And these conditions are satisfied by almost any hosting on planet Earth. Or, instead of hosting, your computer will play the role of a server, connected to a home network router and having Internet access.
Database creation
Let's start from the very beginning, namely from designing and creating a database.
The database is your world and you can study it for a long time, so we will only briefly touch on those things that are directly necessary for us.
All SQL scripts are in the directory. weather-station/server/php-sql/
Where does the design of the database begin? With a logical and physical representation.
Logical representation or database schema:
- table with DHT data of temperature and humidity sensor
- table with BMP data of pressure and temperature sensor
- The specified tables do not have connections among themselves, more precisely, connections are not needed.
The physical scheme is based on a specific DBMS and data types. Easier to sort on a specific example. SQL script make_tables.sql
reveals the logical and physical schema.
Each table should have a type field
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT
The field name may differ in different databases, but the meaning is the same - it is a unique identifier, a record key. For the future, if you see a database in the tables of which there is no such counter, you should know that this database was designed by a person who is very far from programming, most likely a humanist.
Data from the same type of sensors is stored in one table, for sensors of another type we create another table. This slightly complicates the database and PHP binding to it, but it simplifies the expansion or modification of the entire system in the future.
Our project has two tables. The table arduino_dht
stores data from the DHT-type sensor (s) (temperature, humidity), the table arduino_bmp
stores data from the BMP-type sensor (s) (temperature, pressure). If you want to have, for example, a gas sensor or a motion detector in the future, then create additional tables, do not be lazy. If you connect another sensor like DHT11 or DHT22, then you do not need to create an additional table, use a table arduino_dht
. I hope the principle is clear: a separate physical entity - a separate table.
If data from several sensors of the same type are stored in the table, how can they be distinguished? For this, a field is entered in each table.
idSensor INTEGER
In fact, this is CLIENT_ADDRESS
what we wrote in the file client/client.ino
for each instance of the remote sensor client and server/server.ino
for the sensor that is connected directly to the server - the central unit.
In industrial systems, there must be another table - the correspondence idSensor
and its verbal, human-readable description. For example, the sensor with idSensor
= 2 is "Temperature, humidity in the apartment" , etc. But in our project we will not complicate, just remember that:
- the sensor with
idSensor
, it isCLIENT_ADDRESS
equal to 11 - this is the home sensor on the server - the central unit, - sensor c
idSensor
,CLIENT_ADDRESS
which is equal to 20, is the first (in our project and the only) remote sensor client.
Further. The following data is stored in the tables:
- ipRemote - the IP address of the weather station (server) from which the data came from, useful for debugging and monitoring,
- dateCreate - the date the record was created,
- millis - useful for debugging, this time in milliseconds since the start of the sketch on the Arduino,
- temperature - temperature
- humidity - humidity
- voltage - supply voltage
- pressure - pressure
- errors - the number of errors (not used). Conceived to store the number of errors during transmission, etc., so that you can remotely assess the state of the entire system.
As you can see the table arduino_dht
and arduino_bmp
are very similar, the only difference is in the fields of pressure and humidity, and a desire to dump everything into one heap (a table). But the first normal form does not allow it to do so , a lot of novice programmers tried to get around it, but none of them succeeded, and we will not. This is how not to notice the law of the world, for the time being it may well turn out.
The table arduino_error_log
is useful for debugging - this is a log of errors and other system messages.
Creating a database and its user with the rights described in make_db.sql
-- см. также config.php-- создать БДCREATEDATABASEIFNOTEXISTS db_weather;
-- создать пользователяCREATEUSER'u_weather'@'localhost'IDENTIFIEDBY'***PASSWORD***';
GRANT ALL ON db_weather.* TO'u_weather'@'localhost';
This is done once, the database name and user name can come up with your own. And what exactly needs to be done is to set your password.
PHP and web server
All web interface settings are stored in config.php
. Modify it according to your database settings.
Set your time zone in PHP format
date_default_timezone_set(‘Europe/Prague’);
All available time zones are described here .
Specify your secret key for access (as a number) that must match the constant SOURCE_KEY
from the sketchserver.ino
$access_key = ‘***KEY***’;
In our web server there is no authorization, login by password, this would complicate the whole structure. For the prototype, this is not necessary. Therefore, all protection is based on the file robots.txt
, the absence index.php
and on this secret key for access.
The main PHP script weather.php
accepts a simple HTTP GET request with data and stores them in the corresponding database tables. If the key $access_key
does not match, the request will be rejected.
The script is weather-view.php
used to view data tables and contains hyperlinks to other scripts of the web interface. Call him like this
http://ваш хост/ваш путь/weather-view.php?k=ваш access_key
for example
http://yourhost/iot/weather-view.php?k=12345
weather-view.php
displays simple tables where you need to remember that:
- The sensor with id 11 is the home sensor on the server,
- The sensor with id 20 is an outside sensor.
The script function.php
contains functions common to all PHP scripts.
The script chart-dht.php
is responsible for drawing charts using Google Charts . Here, for example, is a graph of the power supply voltage of a windowed sensor. The voltage rises on a sunny day at the expense of the solar battery and then the power supply on batteries gradually discharges.
export-dht.php
exports data from MySQL database tables to a CSV file. For further import and analysis in spreadsheets.
export-voltage.php
exports power supply voltage data from a window sensor from a MySQL database to a CSV file. Useful for debugging.
truncate.php
clears all tables, i.e. deletes all our data. Useful for debugging. There are no links to this script from weather-view.php
, therefore it should be called via a direct link in the address bar of the browser with the indication $access_key
.
When receiving data, a function is used everywhere mysqli_real_escape_string()
to prevent incorrect values from getting into the database.
Do not forget to put the root of your site robots.txt
to prevent it from entering the search engines.
ESP8266, WiFi and data transfer
And now we come back to the sketch server.ino
, to the part that connects to the WiFi access point and sends the data to the web server.
As I already wrote, I could not find a normal library for Arduino to control the ESP8266 module using AT commands, I had to “collective farm” myself. Let me remind you also that you will have to flash the firmware of a certain version in ESP8266-01. And now that everything is ready, let us analyze how it works.
To access the web server in the sketch server.ino
you need to change these constants.
constString DEST_HOST = "ваш хост"; // например habr.comconstString DEST_PORT = "ваш порт"; // обычно 80constString DEST_URL = "/ваш путь/weather.php";
constString SOURCE_KEY= "ваш ключ доступа"; // должен совпадать с $access_key из config.php
In server.ino
the function void setup()
, the ESP8266 is first switched to Station mode, i.e. he starts working as a wifi client
espSendCmd(«AT+CWMODE_CUR=1», «OK», 3000);
and then follows the connection to the access point
espState = espConnectToWiFi();
If the connection does not occur, the attempt is repeated (once)
if ( espState != ESP_SUCCESS ) {
delay(5000);
Serial.println("WiFi not connected! Try again ...");
espConnectToWiFi();
}
Then select a single TCP / IP connection mode.
espSendCmd("AT+CIPMUX=0", "OK", 2000);
When sending data from DHT sensors to a web server, a function is used indicating the type of data as type=dht
espSendData( "type=dht&t=" + String(dhtData.temperature) + "&h=" + String(dhtData.humidity) + "&v=" + String(dhtData.voltage) + "&s=" + String(CLIENT_ADDRESS) );
When sending data from BMP sensors to a web server, the same function is used, indicating the type of data as type=bmp
espSendData( "type=bmp&t=" + String(temperature_bmp) + "&p=" + String(pressure_bmp) + "&s=" + String(CLIENT_ADDRESS) );
At the input, the function espSendData()
accepts the HTTP GET request string and sends it to the destination web server.
Internally, it espSendData()
checks the availability of the ESP module by sending it the “AT” command, then the WiFi connection is checked and reconnected if necessary. Then the data is sent and the TCP connection is closed.
Android app
Nowadays, when everyone can already blink an LED, no meteorological station will surprise anyone. But if the odd job is able to communicate with the server via WiFi, has a web-muzzle and a mobile application, then this is already something! The server here means of course the application server, i.e. in our case, this is PHP binding and MySQL. Not getting the cherries on the cake, namely the application for Android writing of which we now deal with.
Architecture
The architecture of the entire weather station software platform is simple:
- the server part (central unit) of the weather station collects data from remote sensor clients
- then it also sends data to the web application server, which saves this data to the database
- An application on Android (or any other remote application: iOS, browser) requests data from the web server and displays it on the screen.
On the Android device screen, we will display the current, most recent sensor readings.
HTTP GET and JSON
The question that needs to be resolved first is how the data will be transferred from the web server to the Android application.
There is no need to invent anything, everything has already been invented for us - this is HTTP GET and JSON.
In our case, a simple GET request to the web server can be compiled and debugged manually, while the Android application is not yet ready.
Java and Android have ready-made libraries for processing data in JSON format. JSON text format is readable by humans, which is useful for debugging.
In order to generate the current data from the weather station sensors, create a new PHP script last-data-to-json.php on the web server .
Calling the script:
http://<хост>/last-data-to-json.php?k=<access_key>
where <access_key>
, as we remember, is the secret key to access the database.
Sample response in JSON format:
{
"DHT 11":{
"idSensor":"11",
"dateCreate":"2016-04-20 18:06:03",
"temperature":"19",
"humidity":"26",
"voltage":"5.01"
},
"DHT 20":{
"idSensor":"20",
"dateCreate":"2016-04-18 07:36:26",
"temperature":"10",
"humidity":"26",
"voltage":"3.7"
},
"BMP 11":{
"idSensor":"11",
"dateCreate":"2016-04-20 18:06:22",
"temperature":"19",
"pressure":"987.97"
}
}
It is necessary to remind that we have 3 sensors. Their ID and type (DHT or BMP) are hard-coded throughout the weather station code. This way of hardcore coding is ideologically incorrect, but for a kneeled prototype (where a quick and easy solution is needed) this is a reasonable compromise.
$idSensor = 11; // домашний DHT датчик
$idSensor = 11; // домашний BMP датчик
$idSensor = 20; // заоконный DHT датчик
The script last-data-to-json.php
takes from the database the latest data from these different types of sensors and packs it in JSON format. A sample of data from the database "from the end" is performed in this way:
SELECT <поля> FROM <таблица> ORDERBYidDESCLIMIT1;
Android
Now we will write a simple Android application that requests, receives, decodes JSON data and displays information on the screen.
Our Android application will be as simple as possible, only the very essence of the technology. Further around this "skeleton" it will already be possible to turn various "prettiness".
Here is a screenshot of what should end up.
As you can see, the UI is just spartan, based on LinearLayout, nothing superfluous.
At the top of the TextView shows the ID of the sensors and their meteorological data. The “Refresh” button initiates a repeated request to the web server. Next, in the EditText, the only program setting is located — the request URL in the form
http://<ваш хост>/last-data-to-json.php?k=<access_key>
What should be noted?
In the manifest, add lines that allow the Internet and check the status of the network connection:
<uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permissionandroid:name="android.permission.INTERNET" />
Working with the network and receiving data from the website is as follows.
Use AsyncTask to create a background task separately from the main user interface thread. This background task takes the request URL and uses it to create HttpURLConnection
.
After the connection is established, AsyncTask loads the contents of the web page (JSON) as an InputStream. Next, the InputStream is converted to a string, which is decoded using JSONObject and displayed in the user interface method onPostExecute()
.
In MainActivity.java, change the URL to your:
privatestaticfinal String
defUrl = "http://host/dir/last-data-to-json.php?k=<ваш ключ>";
It will be used by default when you first start the Android application.
Epilogue
Well, something has already earned. Then you can optimize something, replace something, you can throw everything out, but also borrow something.
A separate big sore point is energy consumption . I recommend reading comments on posts where there are a lot of practical advice.
To infinity ... and beyond.