
Измерение температуры с помощью 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