Термометр на DS18B20 с отправкой данных на сервер БД MySQL

Измерение температуры с помощью DS18B20 - это проект по уровню сложности в одном ряду с 'print "Hello, world!"' и мигание светодиодом. Но в данном случае возникла потребность в сохранении полученных данных для последующего анализа, статистики и прочей ерунды. Желательно в базе данных, например MySQL. На момент реализации проекта, автор не догадывался, что есть библиотека для работы с MySQL напрямую, так что получилось вот так, как получилось :)

Основной рабочей лошадкой выбран ESP8266 Mini. Он умеет Wi-Fi, а GPIO нам нужно всего один штук.
Схема простая, все как по учебнику:

МК опрашивает датчик DS18B20 и раз в 5 минут шлет HTTP GET запрос на сервер, где php-скрипт его обрабатывает и складывает полученное в базу данных MySQL. Сам ESP одновременно выступает в качестве Web-сервера, на него можно зайти, посмотреть текущее значение температуры или получить эти данные как json-строку, для каких-то своих нужд.


            /*
            В строке 67 заменить: 192.168.181.5/001.php
            на реальный URL
            */
            #include <ESP8266WiFi.h>
            #include <ESP8266WebServer.h>
            #include <ESP8266HTTPClient.h>
            #include <microDS18B20.h>        // AlexGyver lib

            #define WIFI_SSID "WOKWI-Guest"
            #define WIFI_PASS ""

            MicroDS18B20<D4> sensor1;

            WiFiClient espClient;
            ESP8266WebServer myWWW(80);
            HTTPClient http;

            int curTemp=24;
            unsigned long lastDS1820=0;  // время последнего запуска измерений температуры
            unsigned long lastT4=0;      // время последнего отправления данных на сервер
            char wwwbuff[200];           // буфер для формирования строки
            String webpage;              // для формирования содержимого www-страницы 
            char myMAC[17], myIP[15];    // \
            uint8_t macAddr[6];          //  > хранение данных о полученном IP, MAC-адресе
            IPAddress ipAddr;            // /

            void setup()
            {

               WiFi.mode(WIFI_STA);
               //WiFi.hostname("S001");
               WiFi.begin(WIFI_SSID, WIFI_PASS);
               while(WiFi.status() != WL_CONNECTED)
                  delay(200);

               ipAddr = WiFi.localIP();
               sprintf(myIP,"%d.%d.%d.%d",ipAddr[0],ipAddr[1],ipAddr[2],ipAddr[3]);
               WiFi.macAddress(macAddr);
               sprintf(myMAC,"%02X:%02X:%02X:%02X:%02X:%02X", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);

               sensor1.requestTemp();
               lastDS1820 = millis();
               lastT4 = lastDS1820;
              
               myWWW.on("/json/", doJSON);   // вдруг кому-то приспичит запросить данные о температуре. Отдадим, не жалко
               myWWW.on("/", doHttp);
               myWWW.begin();
            }

            void loop()
            {
               // если прошло более 1.2 секунды с момента запуска измерения температуры, можно получить значение
               // вообще-то данные готовы и раньше, но мало ли кто датчик отвлек и он зазевался :)
               if(millis()-lastDS1820>1200)
               {
                  curTemp = sensor1.getTemp();
               }

               // если прошло более 6 секунд с момента запуска измерения температуры, 
               // запустить измерение снова. Почему 6 секунд - хрен его знает, так захотелось 
               if(millis()-lastDS1820>6000)
               {
                  sensor1.requestTemp();
                  lastDS1820 = millis();
               }

               // Если не отправляли данные на сервер уже 5 минут
               if(millis()-lastT4>300000)
               {
                  sprintf(wwwbuff,"http://192.168.181.5/001.php?devID=%s&curT=%d&host=S001",myMAC,curTemp);
                  http.begin(espClient, wwwbuff);
                  http.GET();
                  lastT4=millis();
               }
               myWWW.handleClient();
            }

            void doHttp()
            {
               unsigned int Secs;
               int jDD, jHH, jMM, jSS;
               /*
               if(myWWW.argName(0)=="reset")
               {
                  sprintf(wwwbuff,"<script>window.location='http://%s';</script>",myIP);
                  webpage = wwwbuff;
                  myWWW.send(200, "text/html", webpage);
                  return;
               }
               */
               webpage = "<html><head><title>ESP8266 Mini WWW</title>\n<meta http-equiv='Content-Type' content='text/html; charset=utf-8'></head>\n";
               webpage += "<body><h1>Welcome to " + WiFi.hostname() + " (ESP8266) webserver!</h1>";
               sprintf(wwwbuff,"Температура на датчике DS18B20: <b>%d</b>°C<br>\n",curTemp);
               webpage += wwwbuff;
               Secs = (int)(millis()/1000);
               jDD = (int)(Secs/86400);
               Secs -= jDD*86400;
               jHH = (int)(Secs/3600);
               Secs -= jHH*3600;
               jMM = (int)(Secs/60);
               Secs -= jMM*60;
               sprintf(wwwbuff,"Uptime: %d days %d hours %d minutes %d secunds<br>",jDD,jHH,jMM,Secs);
               webpage += wwwbuff;
               sprintf(wwwbuff,"ipAddr: %s<br>devID: %s<br>",myIP, myMAC);
               webpage += wwwbuff;
               webpage += "</body></html>";
               myWWW.send(200, "text/html", webpage);
            }

            void doJSON()
            {
               sprintf(wwwbuff,"{\"devID\":\"%s\",\"curTemp\":\"%d\"}",myMAC,curTemp);
               myWWW.send(200, "text/plain", wwwbuff);
            }

            

Скрипт 001.php, который получает данные от ESP и пишет их в БД MySQL.
Совершенно примитивный, отсутствуют какие-либо проверки на адекватность данных


            <?php
               $DB = mysqli_connect('localhost','UserName','UserPassword','DatabaseName',3306) or die("Can't connect to MySQL server");
               mysqli_set_charset($DB,"utf8");

               $query = "INSERT INTO tempera SET id=0,dt=NOW(),dev_id='{$_REQUEST['devID']}',temperature='{$_REQUEST['curT']}',hostname='{$_REQUEST['host']}'";
               mysqli_query($DB,$query);
               print "devID:{$_REQUEST['devID']} curTemp:{$_REQUEST['curT']} minTemp:{$_REQUEST['minT']} maxTemp:{$_REQUEST['maxT']}";
            ?>

            

Ну и в финале, собственно для чего это всё затевалось: 002.php - отображение данных в разных позах.
В теле скрипта будут сылки на него самого, надо будет там подкорректировать, заменить 002.php на свое


            <HTML>
            <head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
            <title>Температурная следилка</title>
            <link href="style.css" rel="stylesheet" type="text/css">
            </head>

            <body>

            <?
               $DB = mysqli_connect('localhost','UserName','UserPassword','DatabaseName',3306) or die("Can't connect to MySQL server");
               mysqli_set_charset($DB,"utf8");

               if(isset($_REQUEST['json']))
               {
                  $res = mysqli_query($DB, "SELECT * FROM tempera ORDER BY id DESC LIMIT 1");
                  $row = mysqli_fetch_array($res);
                  print "{\"dev_id\":\"{$row['dev_id']}\",\"datetime\":\"{$row['dt']}\",\"temperature\":\"{$row['temperature']}\",\"hostname\":\"{$row['hostname']}\"}";
                  exit;
               }

               print "<h1Температура на объекте 51/h1>\n";
               if(!isset($_REQUEST['dt1']))
               {
                  $res = mysqli_query($DB, "SELECT * FROM tempera ORDER BY id DESC LIMIT 1");
                  $row = mysqli_fetch_array($res);

                  if($row['temperature']<-20)
                     $fcolor = '#1909C8';
                  if($row['temperature']<-10 && $row['temperature']>=-20)
                     $fcolor = '#7063F8';
                  if($row['temperature']<0 && $row['temperature']>=-10)
                     $fcolor = '#9BA9ED';
                  if($row['temperature']<10 && $row['temperature']>=0)
                     $fcolor = '#5B5D69';
                  if($row['temperature']<20 && $row['temperature']>=10)
                     $fcolor = '#D99D54';
                  if($row['temperature']<25 && $row['temperature']>=20)
                     $fcolor = '#C7502C';
                  if($row['temperature']>=25)
                     $fcolor = 'E62C09';

                  print "Данные получены:<br><b>{$row['dt']}</b><br>";

                  $dttm = preg_split("/[\s-:]/",$row['dt']);
                  $lastDate = mktime($dttm[3],$dttm[4],$dttm[5],$dttm[1],$dttm[2],$dttm[0]);

                  print "<br><b><font size=+20 color=$fcolor>{$row['temperature']}</font></b>";
                  $dt1 = date("Y-m-d");
                  $dt2 = $dt1;
                  print "<br><br><a href=002.php?dt1=$dt1&dt2=$dt2 class=grBTN>Подробнее</a>";
               }
               else
               {
                  if(isset($_REQUEST['dt1']))
                     $dt1 = $_REQUEST['dt1'];
                  else
                     $dt1 = date("Y-m-d");

                  if(isset($_REQUEST['dt2']))
                     $dt2 = $_REQUEST['dt2'];
                  else
                     $dt2 = date("Y-m-d");

                  if($dt2<$dt1)
                     $dt2 = $dt1;

                  if(isset($_REQUEST['tm']))
                     $tm = $_REQUEST['tm'];
                  else
                     $tm = 99;

                  print "<form method=post name=chose>Период с <input type=date name=dt1 value='$dt1'> по <input type=date name=dt2 value='$dt2'> <input type=submit value='Выбрать'></form><br><br>\n";
                  print "<table id=mainT><tr><td size=15>Дата</dt><td>Время</td>";
                  if($tm!=99)
                  {
                     print "<td>Показания ds18b20</td></tr>\n";
                     $res = mysqli_query($DB, "SELECT DATE(dt) AS sDate,HOUR(dt) AS sHour,MINUTE(dt) AS sMin, temperature as sTempera FROM tempera WHERE DATE(dt)>='$dt1' AND DATE(dt)<='$dt2' AND HOUR(dt)='$tm' ORDER BY dt");
                  }
                  else
                  {
                     print "<td>Средняя температура</td></tr>\n";
                     $res = mysqli_query($DB, "SELECT DATE(dt) AS sDate,HOUR(dt) AS sHour, AVG(temperature) as sTempera FROM tempera WHERE DATE(dt)>='$dt1' AND DATE(dt)<='$dt2' GROUP BY DATE(dt),HOUR(dt)");
                  }
                  while($row = mysqli_fetch_array($res))
                  {
                     if($tm!=99)
                        print "<tr class=w><td>{$row['sDate']}</td><td>".sprintf("%02d:%02d",$row['sHour'],$row['sMin'])."</td><td align=right>".sprintf("%6.2f",$row['sTempera'])."</td></tr>\n";
                     else
                        print "<tr class=w><td onclick=\"window.location='?dt1={$row['sDate']}&dt2={$row['sDate']}'\">{$row['sDate']}</td><td onclick=\"window.location='?dt1={$row['sDate']}&dt2={$row['sDate']}&tm={$row['sHour']}'\">".sprintf("%02d:00-%02d:59",$row['sHour'],$row['sHour'])."</td><td align=right>".sprintf("%6.2f",$row['sTempera'])."</td></tr>\n";
                  }
                  print "</table>";
                  print "<br>Клик по дате покажет только эту дату<br>Клик по интервалу времени - развернет время по снятым точкам показаний";
                  print "<br><br><a href=002.php class=grBTN>Вернутся к началу</a><br>";
               }
            ?>
            </body>
            </HTML>

            

Тут архив с 001.ino, 001.php, 002.php, create_table.sql и style.css - Скачать архив 001.zip