Термометр на датчиках DS18B20 и контроллере ESP8622 NodeMCU V3 с отображением данных в браузере и записью в базу данных MySQL.

Всем привет. Заинтересовала меня тема интересных поделок на базе Arduino и Arduino подобных контроллерах. Arduino — это популярный открытый проект в котором тысячи пытливых умов, используя различные датчики и исполнительные устройства, создают невероятные вещи и делятся этим с аудиторией! Невысокая цена на контроллеры и различные сенсоры делает мир Arduino доступным для каждого!

В этой статье постараюсь подробно рассказать о том, как вывести данные с трех температурных датчиков DS18B20 в WEB браузер и для истории отправлять эти показания в базу данных MySQL. Информацию черпал в основном с офигительного ресурса https://randomnerdtutorials.com .

Начнем с процесса создания серверной части этого проекта, то есть создадим новую таблицу в базе данных MySQL, PHP скрипт, который будет передавать в БД полученные значения с NodeMCU и WEB страничку для отображения данных из БД. Подразумевается, что у вас уже есть сервак с поддержкой php и базой данных MySQL. Я воспользовался услугами хостинг-провайдера.

1. Создадим новую БД с названием «temp» .

База данных и новый пользователь успешно созданы, запоминаем эти данные, позже они нам понадобятся:

  • Имя базы данных: temp;
  • Имя пользователя: user;
  • Пароль: ваш пароль.

2. Создадим таблицу «SensorData» в базе данных «temp»:

Зайдем в phpMyAdmin и за три простых шага создадим новую таблицу в базе данных:

Жмем на нашу базу «temp» (шаг 1), идем во вкладку SQL (шаг 2) и вставляем текст SQL-запроса:

CREATE TABLE SensorData(
     id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
     sensor VARCHAR(10),
     location VARCHAR(30),
     temp1 VARCHAR(10),
     temp2 VARCHAR(10),
     temp3 VARCHAR(10),
     client_ip VARCHAR(20),
     reading_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
 )

нажимаем «вперед» (шаг 3). В результате видим новую таблицу SensorData:

3. Сделаем PHP HTTP POST скрипт для добавления данных в MySQL.

Для этого нужно зайти в файловый менеджер и в домашней папке вашего сайта создать новый файл, например «post_temp.php» и наполнить его следующим содержимым:

<?php

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-esp8266-mysql-database-php/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

$servername = "localhost";

// ЗАМЕНИТЕ НА НАЗВАНИЕ ВАШЕЙ БД
$dbname = "ИМЯ-ВАШЕЙ-БД";
// ЗАМЕНИТЕ НА ВАШЕ ИМЯ ПОЛЬЗОВАТЕЛЯ
$username = "ИМЯ-ПОЛЬЗОВАТЕЛЯ";
// ЗАМЕНИТЕ НА ПАРОЛЬ ОТ ПОЛЬЗОВАТЕЛЯ ВАШЕЙ БД
$password = "ПАРОЛЬ-ПОЛЬЗОВАТЕЛЯ";

$client_ip = $_SERVER['REMOTE_ADDR'];
// Keep this API Key value to be compatible with the ESP32 code provided in the project page. 
// Меняя значения в этой части скрипта, не забывайте изменить скетч //ESP8622
$api_key_value = "myApiKey";

$api_key= $sensor = $location = $temp1 = $temp2 = $temp3 = "";

if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $api_key = test_input($_POST["api_key"]);
    if($api_key == $api_key_value) {
        $sensor = test_input($_POST["sensor"]);
        $location = test_input($_POST["location"]);
        $temp1 = test_input($_POST["temp1"]);
        $temp2 = test_input($_POST["temp2"]);
        $temp3 = test_input($_POST["temp3"]);
        
        // Create connection
        $conn = new mysqli($servername, $username, $password, $dbname);
        // Check connection
        if ($conn->connect_error) {
            die("Connection failed: " . $conn->connect_error);
        } 
        
        $sql = "INSERT INTO SensorData (sensor, location, temp1, temp2, temp3, client_ip)
        VALUES ('" . $sensor . "', '" . $location . "', '" . $temp1 . "', '" . $temp2 . "', '" . $temp3 . "', '" . $client_ip . "')";
        
        if ($conn->query($sql) === TRUE) {
            echo "New record created successfully";
        } 
        else {
            echo "Error: " . $sql . "<br>" . $conn->error;
        }
    
        $conn->close();
    }
    else {
        echo "Wrong API Key provided.";
    }

}
else {
    echo "No data posted with HTTP POST.";
}

function test_input($data) {
    $data = trim($data);
    $data = stripslashes($data);
    $data = htmlspecialchars($data);
    return $data;
}

Прежде чем сохранить страницу, не забудьте измените данные для подключения к БД, в нашем случае:

$dbname = "test";
$username = "user";
$password = "нашпароль))";

Сохраняем страницу, открываем браузер и вводим адрес страницы:

http://yoursite.ru/post_temp.php

Если скрипт успешно подключается к нашей базе данных, то мы увидим ответ:

4. Создадим PHP скрипт для отображения значений температуры из базы данных:

заходим в файловый менеджер и в корневой папке вашего сайта создадим файл temp.php и наполним его следующим содержимым:

<!DOCTYPE html>
<html><body>

	
	<?php
/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-esp8266-mysql-database-php/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

	
$servername = "localhost";

// ЗАМЕНИТЬ НА ИМЯ ВАШЕЙ бд
$dbname = "ИМЯ_БД";
// ЗАМЕНИТЬ НА ИМЯ ВАШЕ ИМЯ ПОЛЬЗОВАТЕЛЯ
$username = "ИМЯ_ПОЛЬЗОВАТЕЛЯ";
// ВАШ ПАРОЛЬ
$password = "ПАРОЛЬ";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
} 

$sql = "SELECT id, sensor, location, temp1, temp2, temp3, reading_time FROM SensorData ORDER BY id DESC limit 30";

echo '<table cellspacing="5" cellpadding="5">
      <tr align="center"> 
        <td>ID</td> 
		<td>Сенсор</td>
		<td>Локация</td>
        <td>t воздуха &#8451</td> 
		<td>t на веранде &#8451</td>
		<td>t в доме &#8451</td>
        <td>Время регистрации, <br>
		UTC +5</td> 
      </tr>';
 
if ($result = $conn->query($sql)) {
    while ($row = $result->fetch_assoc()) {
        $row_id = $row["id"];
        $row_sensor = $row["sensor"];
		$row_location = $row["location"];
		$row_temp1 = $row["temp1"];
		$row_temp2 = $row["temp2"];
		$row_temp3 = $row["temp3"];
        $row_reading_time = $row["reading_time"];
        // Uncomment to set timezone to - 2 hour (you can change 2 to any number)
        $row_reading_time = date("Y-m-d H:i:s", strtotime("$row_reading_time + 2 hours"));
      
        // Uncomment to set timezone to + 4 hours (you can change 4 to any number)
        //$row_reading_time = date("Y-m-d H:i:s", strtotime("$row_reading_time + 4 hours"));
      
        echo '<tr align="center"> 
                <td>' . $row_id . '</td> 
				<td>' . $row_sensor . '</td>
				<td>' . $row_location . '</td>
                <td>' . $row_temp1 . '</td> 
				<td>' . $row_temp2 . '</td> 
				<td>' . $row_temp3 . '</td> 
                <td>' . $row_reading_time . '</td> 
              </tr>';
    }
    $result->free();
}

$conn->close();
?> 
</table>
</body>
</html>

Прежде чем сохранить страницу, не забудьте измените данные для подключения к БД, в нашем случае:

$dbname = "test";
$username = "user";
$password = "нашпароль))";

Сохраняем файл, открываем браузер и заходим на страничку temp.php сайта. Если все сделали правильно, то увидим страничку с таким содержанием:

5. Подготовка ESP8622 NodeMCU V3.

Нам понадобятся следующие комплектующие, которые можно найти на aliexpress:

  1. Плата ESP8622 NodeMCU V3;
  2. датчики температуры DS18B20;
  3. макетная плата (по желанию);
  4. провода;
  5. резистор номиналом 4,7 КОм.

Датчики температуры DS18B20 подключим к контакту D4 контроллера через резистор 4,7 КОм. Схема подключения датчиков к контроллеру проста, при использовании макетной платы будет выглядеть следующим образом:

ПОдключаем датчики температуры DS18B20 к ESP8622 NodeMCU
ПОдключаем датчики температуры DS18B20 к ESP8622 NodeMCU
Схема подключения трех датчиков температуры DS18B20 к плате NodeMCU ESP8622.

Контроллер будем программировать в среде разработки Arduino IDE, скачать ее можно с официального сайта проекта arduino.cc. Чтобы работать с платой ESP8622 NodeMCU в данной среде, нужно ее туда добавить с помощью менеджера плат. Также нужно будет установить необходимые библиотеки для работы с датчиками и узнать их адреса. Об этом отдельная статья. В этом проекте отправка данных в базу MySQL осуществляется через определенный интервал времени, отправка данных в WEB браузер клиенту — по запросу клиента. Для этого выделено два потока при помощи библиотеки «ArduinoThread». Найти ее и установить можно через Менеджер библиотек Arduino IDE. Добавлено 27.01.2020: Как же тогда я был далек от того что такое millis() =)))

Завершающим этапом этой работы будет редактирование скетча и его загрузка в контроллер. В программировании я не силен, поэтому подробно описывать программу не берусь, лишь поясню некоторые моменты в коде самого скетча:

#include <OneWire.h>
#include <DallasTemperature.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <Thread.h>


// Пин, к которому подключена шина данных датчиков
#define ONE_WIRE_BUS D4

// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
Thread MysqlThread = Thread(); // создаём поток для задачи "Mysql"
Thread WebThread = Thread(); // создаём поток для задачи "WebClient"

float tempSensor1, tempSensor2, tempSensor3;
uint8_t sensor1[8] = { 0x28, 0x2A, 0xE5, 0xBB, 0x5D, 0x14, 0x1, 0x88 };
uint8_t sensor2[8] = { 0x28, 0xAB, 0xA6, 0xDA, 0x5D, 0x14, 0x1, 0xED };
uint8_t sensor3[8] = { 0x28, 0x19, 0x33, 0x37, 0x5D, 0x14, 0x1, 0x35 };

//Задаем путь к PHP HTTP Post скрипту-обработчику 
const char* serverName = "http://yoursite.ru/post_temp.php";

//Прописываем ключ, который указан в файле скрипта-обработчика 
String apiKeyValue = "MyApiKey";

//SSID и Password для доступа к вашей wifi сети
const char* ssid = "ИмяВашейСети";  // Enter SSID here
const char* password = "Пароль";  //Enter Password here

// Задаем 80ый порт WEB серверу
WiFiServer server(80);

// Variable to store the HTTP request
String header;
// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0; 
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;


void setup() {
  Serial.begin(115200);
  delay(100);
  sensors.begin();
 // снижаем разрешение температурного преобразователя
  sensors.setResolution(sensor1, 9);
  sensors.setResolution(sensor2, 9);
  sensors.setResolution(sensor3, 9);
  sensors.setResolution(sensor4, 9);
   
  //подключаемся к локальной wi-fi сети             
  Serial.println("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  //проверяем подключение к wi-fi сети
  while (WiFi.status() != WL_CONNECTED) {
  delay(1000);
  Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected..!");
  Serial.print("Got IP: ");  Serial.println(WiFi.localIP());

  server.begin();
  
  MysqlThread.onRun(MysqlSend);  // назначаем потоку задачу
  MysqlThread.setInterval(10000); // задаём интервал срабатывания задачи, мсек
  
  WebThread.onRun(WebClient);  // назначаем потоку задачу
  WebThread.setInterval(0); // задаём интервал срабатывания задачи, мсек

 
}
void loop()
 
{
    // Проверим, пришло ли время выполнения потока MySQL:
    if (MysqlThread.shouldRun())
        MysqlThread.run(); // запускаем поток
    // Проверим, пришло ли время выполнения потока WebClient:
    if (WebThread.shouldRun())
        WebThread.run(); // запускаем поток
        
}

void MysqlSend() { 
      
  HTTPClient http;
  
  //получаем значения температуры с датчиков
  sensors.requestTemperatures();
  tempSensor1 = sensors.getTempC(sensor1);
  tempSensor2 = sensors.getTempC(sensor2);
  tempSensor3 = sensors.getTempC(sensor3);
  
  //Задаем название местоположения и название сенсора
  String location = "TimVill";
  String sensor = "DS18B20";
  
  //Отправляем данные на страницу PHP HTTP Post
  http.begin(serverName);
  //http.addHeader("content-Type", "text.plain");
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  String httpRequestData = "api_key=" + String(apiKeyValue) + "&sensor=" + String(sensor) + "&location=" + String(location) + "&temp1=" + String(tempSensor1) + "&temp2=" + String(tempSensor2) + "&temp3=" + String(tempSensor3);
  Serial.print("httpRequestData: ");
  Serial.println(httpRequestData);
  int httpResponseCode = http.POST(httpRequestData);
  if (httpResponseCode>0) {
      Serial.print("HTTP Response code: ");
      Serial.println(httpResponseCode);
    }
    else {
      Serial.print("Error code: ");
      Serial.println(httpResponseCode);
    }
 http.end();
  }

void WebClient() {

  WiFiClient client = server.available();   // Listen for incoming clients
  if (client) {                             // If a new client connects,
  
//получаем значения температуры с датчиков
sensors.requestTemperatures();    
  tempSensor1 = sensors.getTempC(sensor1); 
  tempSensor2 = sensors.getTempC(sensor2); 
  tempSensor3 = sensors.getTempC(sensor3);
 
Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    currentTime = millis();
    previousTime = currentTime;
    while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
      currentTime = millis();         
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();
                                    
            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta charset=\"UTF-8\" name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            
            // CSS to style  
            client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}</style></head>");
                        
            // Web Page Heading
            client.println("<body><h1>Где-то на планете Земля ))</h1>");
            
            // Display current temps 
            client.println("Температура на улице:<br>" );
            client.println(tempSensor1);
            client.println("&#8451");
            client.println("<br><br>Температура на веранде:<br>" );
            client.println(tempSensor2);
            client.println("&#8451");
            client.println("<br><br>Температура в доме:<br>" );
            client.println(tempSensor3);
            client.println("&#8451");
            client.println("</body></html>");
            client.println("<br><br><a href=https://ivansmith.ru/temp.php>Массив показаний</a><br>" );
            
            // The HTTP response ends with another blank line
            client.println();
            // Break out of the while loop
            break;
          } else { // if you got a newline, then clear currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
 }

Итак, если мы все подключили правильно и скетч у нас скомпилировался и загрузился в память контроллера без ошибок, то в окне монитора COM порта будем наблюдать следующую картину:

Мы видим, что ESP8622 успешно подключился к Wi-Fi сети, получил IP адрес 192.168.0.103 и начал отправлять показания датчиков в базу MySQL, о чем свидетельствуют записи «HTTP Response code: 200».

Теперь откроем браузер на любом устройстве из той же локальной сети и введем IP адрес ESP8622 (в моем случае — 192.168.0.103), в случае успеха в мониторе COM порта видим такую картинку:

Ну а в WEB браузере:

Остается проверить накопленные в базе данных MySQL показания с датчиков температуры, откроем браузер и зайдем на страничку temp.php нашего сайта:

Рабочий пример можно наблюдать по ссылке, доступны показания только с датчика воздуха (temp1), установленного на улице: https://ivansmith.ru/offline_temp.php.

Спасибо за прочтение!

Поделиться ссылкой:

2 thoughts on “Термометр на датчиках DS18B20 и контроллере ESP8622 NodeMCU V3 с отображением данных в браузере и записью в базу данных MySQL.

  1. Сергей

    Заказал такой девайс поиграться, на днях подойдет. Почитал даташит. Есть там интересный пункт на 6 странице, что в нем есть встроенный температурный датчик. Если он есть зачем городить DS18B20, не проще научиться им пользоваться?

    1. admin Автор записи

      Чтобы ответить на ваш вопрос нужно понять что за девайс вы заказали ))

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *