From : https://www.instructables.com/id/Temperature-and-Humidity-Monitor/?utm_source=FEED_EMAIL&utm_medium=email&distinctId=MJZZNDZIP49RVO1

 

Step 5: Setting Up the Server

Before uploading the firmware to the ESP8266 there is one more thing that needs to be done, which is setting up a server for logging the data received by the device. For that purpose you can use pretty much any Linux machine you want, from a Raspberry Pi on your private network to a DigitalOcean droplet. I went with the later, but the process is pretty much the same no matter what you choose.

Installing Apache, MySQL (MariaDB) and PHP

First we need to setup LAMP, or in other words install Apache, MySQL (MariaDB) and PHP on the server. For that you’ll need to use the package manager of your distro, for the sake of the example I will use apt which is the package manager used by pretty much any Debian based distro, including Raspbian.

sudo apt update
sudo apt install apache2 mysql-server mysql-client php libapache2-mod-php php-mysql

After that is done, if you put the IP address of your server to the address bar of your browser you should be able to see the default page of Apache.

Setting up the database

Now we need a database for logging the data. First, connect to MySQL as root by running,

sudo mysql

And create the database and a user with access to it as follows,

CREATE DATABASE `sensors`
USE `sensors`;
CREATE TABLE `temperature` (`id` bigint(20) NOT NULL AUTO_INCREMENT, `client_id` smallint(6) NOT NULL, `value` smallint(6) NOT NULL, `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`)) ENGINE=InnoDB;
CREATE TABLE `humidity` (`id` bigint(20) NOT NULL AUTO_INCREMENT, `client_id` smallint(6) NOT NULL, `value` smallint(6) NOT NULL, `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`)) ENGINE=InnoDB;
CREATE USER '[username]'@'localhost' IDENTIFIED BY '[password]';
GRANT ALL PRIVILEGES ON 'sensors'.* TO 'sensors'@'localhost';
EXIT

Make sure to replace [username] and [password] with the actual username and password for the MySQL user that you like. Also, keep a note of them because you’ll need them for the next step.

Configuring the logging and web interface scripts

Change to the /var/www/html directory which is the document root of the default virtual host of Apache, delete the HTML file that contains the default webpage and download the logging and web interface scripts inside it.

cd /var/www/html
sudo rm index.html
sudo wget https://raw.githubusercontent.com/magkopian/esp-arduino-temp-monitor/master/server/log.php
sudo wget https://raw.githubusercontent.com/magkopian/esp-arduino-temp-monitor/master/server/index.php

Now edit the logging script using nano,

sudo nano log.php

You'll need to replace the [username] and [password] with the username and password for the MySQL user that you created on the previous step. Also, replace the [client key] with a unique string and take a note of it. This is going to be used as a password so the monitor can authenticate itself to the server.

Finally, edit the index.php with nano,

sudo nano index.php

and replace the [username] and [password] with the username and password for the MySQL user as you did with the logging script.

Setting up HTTPS (Optional)

This may be optional, but if the connection between the ESP8266 and the server is over the Internet it is highly recommended to use some encryption.

Unfortunately, you can’t just go ahead and use something like Let’s Encrypt for obtaining a certificate. That is because at least at the time of the writing, the HTTP client library for the ESP8266 still requires the fingerprint of the certificate to be provided as a second argument when calling the http.begin(). This means that if you use something like Let’s Encrypt, you’ll have to reflash the firmware to the chip every 3 months in order to update the certificate fingerprint after each renewal.

A way around that, would be to generate a self-signed certificate that expires after a very long time (e.g. 10 years) and keep the logging script on its own virtual host with its own subdomain. That way, you can have the web interface for accessing the data on a separate subdomain, that will use a proper certificate from a trusted authority. The usage of a self-signed certificate in this case is not a security issue, as the fingerprint of the certificate which uniquely identifies it will be hardcoded into the firmware and the certificate is only going to be used by the ESP8266. 

Before we start, I will assume that you already own a domain name and you're able to create subdomains on it. So, to generate a certificate that expires after 10 years run the following command and answer the questions.

sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/ssl/private/sensors.key -out /etc/ssl/certs/sensors.crt

As this is a self-signed certificate what you answer in most questions doesn't matter too much, except for the question that asks for the Common Name. This is where you'll need to provide the full subdomain that is going to be used for this virtual host. The subdomain you'll give here will need to be the same with the ServerName that you'll set later in your virtual host configuration.

Next create a new virtual host configuration,

sudo nano /etc/apache2/sites-available/sensors-ssl.conf

with the following contents,

<VirtualHost *:443>
	ServerName [subdomain]
	DocumentRoot /var/www/sensors

	SSLEngine ON
	SSLCertificateKeyFile /etc/ssl/private/sensors.key
	SSLCertificateFile /etc/ssl/certs/sensors.crt

	<Directory /var/www/sensors/>
		Options +FollowSymlinks -Indexes
		AllowOverride All
	</Directory>

	ErrorLog ${APACHE_LOG_DIR}/sensors-error-ssl.log
	CustomLog ${APACHE_LOG_DIR}/sensors-access-ssl.log combined
</VirtualHost>

Again, be sure to replace the [subdomain] with the same subdomain that you used with the certificate. At this point you will need to disable the default virtual host of Apache,

sudo a2dissite 000-default

change the name of the document root directory,

sudo mv /var/www/html /var/www/sensors

and finally enable the new virtual host and restart Apache,

sudo a2ensite sensors-ssl
sudo systemctl restart apache2

Last thing that needs to be done is to obtain the fingerprint of the certificate, because you'll need to use it in the firmware code.

openssl x509 -noout -fingerprint -sha1 -inform pem -in /etc/ssl/certs/sensors.crt

The http.begin() expects the delimiters between the bytes of the fingerprint to be spaces, so you’ll need to replace the colons with spaces before using it in your code.

Now, if you don’t want to use a self-signed certificate for the web interface setup a new subdomain and create a new virtual host configuration,

sudo nano /etc/apache2/sites-available/sensors-web-ssl.conf

with the following contents,

<VirtualHost *:443>
	ServerName [subdomain]
	DocumentRoot /var/www/sensors
	#SSLEngine ON
	#SSLCertificateFile /etc/letsencrypt/live/[subdomain]/cert.pem
	#SSLCertificateKeyFile /etc/letsencrypt/live/[subdomain]/privkey.pem
	#SSLCertificateChainFile /etc/letsencrypt/live/[subdomain]/chain.pem

	<Directory /var/www/sensors/>
		Options +FollowSymlinks -Indexes
		AllowOverride All
	</Directory>
	ErrorLog ${APACHE_LOG_DIR}/sensors-web-error-ssl.log
	CustomLog ${APACHE_LOG_DIR}/sensors-web-access-ssl.log combined
</VirtualHost>

Be sure to replace the [subdomain] with the subdomain that you have setup for the web interface. Next enable the new virtual host, restart Apache, install certbot and obtain a certificate for the new subdomain from Let's Encrypt,

sudo a2ensite sensors-web-ssl
sudo systemctl restart apache2
sudo apt update
sudo apt install certbot
sudo certbot certonly --apache -d [subdomain]

After obtaining the certificate edit the virtual host configuration again to uncomment the SSLEngineSSLCertificateFile,  SSLCertificateKeyFile and SSLCertificateChainFile lines, and restart Apache.

And now you can use the first subdomain which uses the self-signed certificate for sending the data from the ESP8266 to the server, while using the second for accessing the web interface from your browser. Certbot will also take care of automatically renewing you Let's Encrypt certificate every 3 months, using a systemd timer which should be enabled by default.

 

Step 6: Programming the ESP8266

Finally, the only thing left to do is to load the firmware on the microcontroller. To do so, download the source code for the firmware from here and open it using the Arduino IDE. You will need to replace [SSID] and [Password] with the actual SSID and password of your WiFi network. You'll also need to replace [Client ID] and [Client Key] on the sprintf function call with the ones that you used on the PHP script on the server. Finally, you'll have to replace the [Host]with the domain name or the IP address of the server. If you're using HTTPS you will also need to supply the fingerprint of your certificate as a second argument on the function call of the http.begin(). I've explained how to obtain the fingerprint of the certificate at the "Setting Up HTTPS" section on the previous step.

Next, if you haven't already you're going to need to install the ESP8266 Community core package using the Board Manager of the Arduino IDE. Once this is done, select the NodeMCU 1.0 (ESP-12E Module) from the boardsmenu. Next, you'll need to install the the SimpleDHT library using the Library Manager. Finally, hit the Verify button on the upper left corner of your IDE window to make make sure that the code compiles without errors.

And now, it's finally time to burn the firmware to the microcontroller. To do so move the jumper JP1 on the right, so GPIO0 of the ESP8266 will be connected to ground which will enable the programming mode. Then, attach your USB to serial converter using jumper wires to the programming header that is labeled as P1. The pin 1 of the programming header is groundpin 2 is the receive pin of the ESP8266 and pin 3 the transmit. You need the receive of the ESP8266 to go to the transmit of your USB to serial converter, the transmit to the receive and of course the ground to ground.

Finally, power the device with 5V using your USB to DC jack cable and connect the USB to serial converter to your computer. You should now be able to see the virtual serial port where the ESP8266 is connected, as soon as you open the tools menu on your IDE. Now, just hit the Upload button and that's it! If everything went as expected you should be able to see the temperature and humidity readings on the LCD of the device. After the ESP8266 connects to your network and starts communicating with the server, the current date and time should also show up on the display.

After a few hours when the server will have collected a good amount data you should be able to see the temperature and humidity charts by visiting http(s)://[host]/index.php?client_id=[client id]. Where [host] is either the IP address of your server or the subdomain you're using for the web interface, and [client id] the client id of the device which if you left it to its default value it should be 1.

 

 

/*
* Copyright (c) 2017 Manolis Agkopian
* See the file LICENSE for copying permission.
*/

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <LiquidCrystal.h>
#include <SimpleDHT.h>

ESP8266WiFiMulti WiFiMulti;

const int rs = 4, en = 2, d4 = 13, d5 = 12, d6 = 14, d7 = 16;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

int DHT11 = 5;
SimpleDHT11 dht;

void setup() {
  // Configure LCD
  lcd.begin(16, 4);

  // Configure WiFi
  WiFiMulti.addAP("[SSID]", "[Password]");
}

void loop() {
  byte temperature = 0;
  byte humidity = 0;
  char postData[100] = {0};

  // Sample rate is set to 1 Hz
  delay(1000);

  // Read the sensor
  if ( dht.read(DHT11, &temperature, &humidity, NULL) != SimpleDHTErrSuccess ) {
    lcd.setCursor(0, 1);
    lcd.print("Sensor Failure"); // In case of error output sensor failure and return
    return;
  }

  // Clear the sensor failure error message
  lcd.setCursor(0, 1);
  lcd.print("              ");

  // Output the temperature
  lcd.setCursor(0, 2);
  lcd.print("Temperature: ");
  lcd.print((int) temperature);
  lcd.print("C");

  // Output the humidity
  lcd.setCursor(0, 3);
  lcd.print("Humidity: ");
  lcd.print((int) humidity);
  lcd.print("%");

  sprintf(postData, "{\"client_id\":\"[Client ID]\",\"client_key\":\"[Client Key]\",\"temperature\":\"%d\",\"humidity\":\"%d\"}", (int) temperature, (int) humidity);
  
  // If connected to the WiFi send the mesurment to the server
  if((WiFiMulti.run() == WL_CONNECTED)) {
    
    HTTPClient http;

    // Set request URL
    http.begin("http://[Host]/log.php"); // For HTTPS connection the fingerprint of the certificate needs to be supplied as a second parameter

    // Start connection and send HTTP headers
    http.addHeader("Content-Type", "application/json");
    http.addHeader("Accept", "application/json");
    int httpCode = http.POST(postData);

    if( httpCode > 0 && httpCode == HTTP_CODE_OK ) {
      String payload = http.getString();
      lcd.setCursor(0, 0);
      lcd.print(payload);
    }
    else {
      String error = http.errorToString(httpCode).c_str();
    }
    http.end(); 
  }
}