Mini webserver NodeMCU s teploměrem DS18B20
V minulém článku jsme se seznámili s velmi zajímavým modulem NodeMCU a ukázali jsme si, jak jej uchopit pro praktické projekty. Dneska si ukážeme, jak jednoduše vytvořit malý webový server, který nám bude ukazovat teploty doma a venku.
HW s NodeMCU
Pro měření teploty použijeme známá čidla Dallas 18B20 a budeme potřebovat ještě jeden rezistor 4k7 jako pullup na OneWire sběrnici. Zde je velmi výhodné použít rezistor v pouzdru SMD 0805, protože se dá pohodlně zapájet mezi pin D4 a 3.3V, který je hned vedle přímo na modul NodeMCU. Na piny NodeMCU tak zbývá pouze připojit samotný teploměr nebo teploměry. HW je patrný z níže uvedeného obrázku:
Sketch
Sketch vychází z examplu jednoduchého serveru, který jsem doplnil o podporu sběrnice OneWire a knihovnou proobsluhu DS18B20 tak, aby implementace byla co nejjednodušší. Ve skutečnosti je sketch poměrně náročný, ale naštěstí je vše hezky zabaleno v dost dobře funkčních knihovnách ESP8266WiFi, WiFiClient, ESP8266WebServer a ESP8266mDNS, takže spoustu starostí odpadne. Tyto knihovny jsou součástí balíků, který jsme instalovali podle předešlého článku.
Snad jen drobné upozornění - ve stávajícím prostředí Arduina máte jistě knohovnu OneWire - tu bude potřeba přepsat nově dodanou knihovnou, která je rovněž součásti implementačního balíku, jinak kompilér nebude znát OneWire proNodeMCU. Stačí přepsat soubory .h a .cpp v tomto případě.
Pojďme rozebrat jednotlivé pasáže.
Nejprve provedeme základní definice a nalinkování potřebných knihoven.
#include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> #include <ESP8266mDNS.h> #include <OneWire.h> #include <DallasTemperature.h> //pro teploměr #define ONE_WIRE_BUS D4 #define TEMPERATURE_PRECISION 9 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); DeviceAddress insideThermometer, outsideThermometer; float teplota; String termOUT; String termIN; #define SCKLED 5
Zde zadejte SSID a heslo ke svému WiFi routeru
const char *ssid = "SSID"; const char *password = "*************"; MDNSResponder mdns; ESP8266WebServer server(80); const int led = 13;
Funkce pro zobrazení stránky HTML na ESP8266. Jedná se vlastně o vytištění HTML kódu na serverový pool ESP8266. Data pro HTML stránku lze buď natvrdo nakódovat přímo ve sketchi nebo vymyslet jiný způsob, jak ji do serveru vytisknout - načtením z SD karty, případně externího souboru.
//pro server void handleRoot() { digitalWrite(SCKLED, 1); char temp[450]; int sec = millis() / 1000; int min = sec / 60; int hr = min / 60; uint8 index = termOUT.indexOf('.'); int restOUT = termOUT.substring(index+1).toInt(); int temperatureOUT = termOUT.toInt(); index = termIN.indexOf('.'); int restIN = termIN.substring(index + 1).toInt(); int temperatureIN = termIN.toInt(); snprintf(temp, 450, "<html>\ <head>\ <meta http-equiv='refresh' content='5'/>\ <title>ESP8266 Demo</title>\ <style>\ body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\ </style>\ </head>\ <body>\ <h1>Teplota v Kuncicich pod Ondrejnikem</h1>\ <p>Uptime: %02d:%02d:%02d</p>\ <p>Teplota venku: %02d.%01d°C</p>\ <p>Teplota doma: %02d.%01d°C</p>\ </body>\ </html>", hr, min % 60, sec % 60, temperatureOUT,restOUT,temperatureIN,restIN ); server.send(200, "text/html", temp); digitalWrite(led, 0); } void handleNotFound() { digitalWrite(led, 1); String message = "File Not Found\n\n"; message += "URI: "; message += server.uri(); message += "\nMethod: "; message += (server.method() == HTTP_GET) ? "GET" : "POST"; message += "\nArguments: "; message += server.args(); message += "\n"; for (uint8_t i = 0; i < server.args(); i++) { message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; } server.send(404, "text/plain", message); digitalWrite(led, 0); }
Provedeme nějaké úvodní nastvovačky - LEDka na modulu ESP8266 nám bude později indikovat chod sketche, aktivujeme sériový port na rychlosti 9600 b/s, pokusíme se připojit na WiFi router s patřičným nastavením viz. výše, vypíšeme IP adresu, kterou jsme od routeru obdrželi, abychom věděli, kam budeme sahat browserem pro zobrazení stránky. Nakonec ošéfujeme teploměry - jeden jsem označil jako vnitřní a jeden jako vnější, pokusím se je najít na sběrnici a vypsat jejich aktuální teplotu.
void setup(void) { pinMode(led, OUTPUT); pinMode(SCKLED,OUTPUT); digitalWrite(SCKLED,LOW); digitalWrite(led, 0); Serial.begin(9600); WiFi.begin(ssid, password); Serial.println(""); // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); if (mdns.begin("esp8266", WiFi.localIP())) { Serial.println("MDNS responder started"); } server.on("/", handleRoot); server.on("/inline", []() { server.send(200, "text/plain", "this works as well"); }); server.onNotFound(handleNotFound); server.begin(); Serial.println("HTTP server started"); //digitalWrite(SCKLED, HIGH); //teploměry sensors.begin(); Serial.println("***************************************************"); Serial.print("Pocet teplomeru: "); Serial.println(sensors.getDeviceCount(), DEC); //zjisti adresy oneWire.reset_search(); if (!oneWire.search(insideThermometer)) Serial.println("Vnitrni teplomer nenalezen!"); if (!oneWire.search(outsideThermometer)) Serial.println("Vnejsi teplomer nenalezen!"); Serial.print("Adresa teplomeru 1: "); printAddress(insideThermometer); Serial.println(); Serial.print("Adresa teplomeru 2: "); printAddress(outsideThermometer); Serial.println(); //nastav rozlišení sensors.setResolution(insideThermometer, TEMPERATURE_PRECISION); sensors.setResolution(outsideThermometer, TEMPERATURE_PRECISION); //načti všechny teploměry sensors.requestTemperatures(); //vytiskni data na seriák printData(insideThermometer); printData(outsideThermometer); }
Hlavní smyčka je celkem primitivní - neustále dookola sbírá teploty a updatuje webovou stránku, mezi čtením vnitřního a vnějšího teploměru pak blikne LEDkou.
void loop(void) { digitalWrite(led, LOW); mdns.update(); server.handleClient(); sensors.requestTemperatures(); teplota = sensors.getTempC(insideThermometer); digitalWrite(led, HIGH); termOUT = String(teplota, 1); teplota = sensors.getTempC(outsideThermometer); termIN = String(teplota, 1); digitalWrite(led, LOW); } //pro teploměry void printAddress(DeviceAddress deviceAddress) { for (uint8_t i = 0; i < 8; i++) { // zero pad the address if necessary if (deviceAddress[i] < 16) Serial.print("0"); Serial.print(deviceAddress[i], HEX); } }
Zde ještě pár nezbytností pro obsluhu teploměrů
void printData(DeviceAddress deviceAddress) { Serial.print("Adresa teplomeru "); printAddress(deviceAddress); Serial.print(":"); printTemperature(deviceAddress); } void printTemperature(DeviceAddress deviceAddress) { float tempC = sensors.getTempC(deviceAddress); Serial.print("Teplota: "); Serial.print(tempC); Serial.write(176); Serial.println("C"); }
Pokud se Vám povedla kompilace, zaveďte sketch do NodeMCU a otevřete sériový kanál na rychosti 9600 b/s. Pokud vše proběhlo jak mělo, pak na sériovém kanálu uvidíte vypisování symbolu tečky(.), což znamená, že se ESP8266 snaží asociovat s Vaším WiFi routerem. V momentě, kdy je asociace úspěšná se vypíše následující:
...
Connected to TESTER2
IP address: 192.168.1.111
MDNS responder started
HTTP server started
***************************************************
Pocet teplomeru: 2
Adresa teplomeru 1: 28789A68000000A1
Adresa teplomeru 2: 28F55A6800000023
Adresa teplomeru 28789A68000000A1:Teplota: 21.50°C
Adresa teplomeru 28F55A6800000023:Teplota: 22.50°C
A nyní se můžeme podívat na www stránku přes libovolný browser...
Sketch je ke stažení zde. Z veřejného internetu je webová stranka dostupná zde - pakliže zrovna nějak s tímto nelaboruji a nemám jej v jiném, než on-line režimu nebo pokud se nezmění veřejná adresa u poskytovatele.
NodeMCU je dostupné v našem e-shopu v zatím omezeném množství, od konce listopadu 2015 by mělo být již standardně dostupné a více kusů skladem. NodeMCu je beze sporu významnou komponentou pro podporu IoT a budu této desce o velikosti 48x26mm věnovat patřičnou pozornost. Podobné řešení existuje ještě ve formě ala Arduino UNO - tedy v konstrukci, která umožňuje přímo využít stávající Arduino shieldy - tedy alespoň některé.
PF
Přidat komentář
Přehled komentářů
-
error: 'printAddress' was not declared in this scope
(garf, 11. 12. 2015 20:37:49)
Odpovědět
Veľmi pekný návod, mám však problém, pri kompilácií mi vyskočia hlášky:
NodeMCU_DS18B20:134: error: 'printAddress' was not declared in this scope
printAddress(insideThermometer);
Podobné ešte na riadku 149 a 185. Vie mi niekto poradiť. Ďakujem. -
arduino ide 1.6.6
(garf, 11. 12. 2015 23:11:39)
Odpovědět
Hore uvedený problém sa týka len ide 1.6.6 po inštalácií staršej verzie 1.6.5 kompilácia prebehne bez chyby.
Admin:
Trochu jsem to podrobil analýze a vypadá to takto - není to ani tak závislé na verzi Arduino IDE, ale objevil jsem takový zvláštní jev - podotýkám používám pro vývoj Visual Studio for Comunities 2015 a plugin VisualMicro - tak tedy, samotné Arduino IDE mi v obou verzích kompilovalo OK, jakmile jsem totéž zkusil ve VS, pak jsem obdržel hlášku, kterou popisujete. Vzal jsem tedy veškeré funkce, které byly napsány za hlavní smyčkou loop() a pouze je přemístil před setup(). Zjevně je někde chyba v kopiléru, resp. Visual micro pluginu. Jakmile se toto přemístění udělalo, pak se již sketch kompiluje bez chyby. -
esp
(Ivan, 21. 2. 2016 10:03:56)
Odpovědět
Perfektné. Mám ale otázku: Ako môžem dosiahnúť to, aby bola stránka dostupná z verejného internetu, teda to čo máte v predposlednom odstavci? Vopred ďakujem za odpoveď
Admin:
Dobrý den,
Musíte mít veřejnou adresu od Vašeho poskytovatele a pak si patřičným způsobem nastavit forward portu ve Vašem routeru. Protože routerů existuje mnoho, pak univerzální postup nelze popsat, princip ano - port forward a povolit si ho také na firewallu, pokud Váš router firewall má a máte ho zapnutý. Pak z vneku napíšete veřejnou IP adresu:portxy a ten portxy budete mít směrován na vnitřní adresu, kterou Vám dhcp přidělilo pro NodeMCU. Směruji většinou portxy na port 80, tam defaultně běží vnitřní web ESPčka.
PF -
Data a napajeni
(Michal, 1. 3. 2016 13:49:57)
Odpovědět
Dobrý den,
poběží to i při napajení tužkovými bateriemi vydrží to nejakou slušnou dobu?
Admin:
Dobrý den!
Ano, pokud budete slušně zacházet se spotřebou - tedy deep sleep, vzbudit, změřit, poslat data, pak pojedete na lithiovku 3V/3000mAh (CR123a) cca půl roku. Ale chce to fakt hoooodně šetřit a trochu si nastudovat Low Power záležitosti. Pokud ale hledáte něco, kde budete sypat data, počkejte ještě chvilku (2 měsíce max.) na LoRa nebo Sigfox sítě pro IoT, viz. mé články o IoT.
http://www.arduinotech.cz/inpage/lpwan-lorawan-sigfox-vitejte-v-iot-107/
PF -
re
(Leo, 28. 10. 2016 9:54:46)
Odpovědět
Kdybych chtěl nastavít penou IP?
Da se vypsat na ser.monitor sila wifi signalu? -
knihovna OneWire
(Boss, 2. 12. 2016 10:42:38)
Odpovědět
Zdravím, nějak nemůžu najít tu správnou knihovnu pro OneWire.
S tou kterou mám mi to hází error
Zdravím,
doporučoval bych používat ty knihovny, které se stáhnou s ESP8266 packem. Je totho celkem dost na netu, těžko říct, co funguje a co ne. Zkuste si přeinstalovat celé to ESP8266 repository.
PF
#define ONE_WIRE_BUS D4
'D4' was not declared in this scope
Děkuji za pomoc -
Dík
(Adam, 10. 1. 2017 11:26:33)
Odpovědět
Funguje parádně, díky!
-
Zapojeni s Dallas
(Jiří Kačmařík, 16. 1. 2017 17:52:28)
Odpovědět
Dobrý den,
podařilo se mi rozběhnout Arduino s Dallasem, dokonce s port forwarding, Mám ověřeno z Číny a Irska, že stránka teploměru je přístupná. Zjistil jsem, že je dobré dát za svou veřejnou adresu v cizině ještě číslo portu http://A.A.A.A:80, třeba můj Zyxel to potřebuje, bez toho stránku neotevře, i když v NAT má nastaveno www = č.p. 80.
Ale na některé věci jsem krátky,
1. letošní zima má i mínusové telploty ty se však na www nezobrazují, jedině seriový monitor napsal -0.50 ale na www je 00.0°C přitom venku je -3. Je to Dallasem nebo knihovnou? Oba Dallasy byli venku a svorně ukazovali na www 00.0
2. Zakomentoval jsem všechny blikaci místa ř. 156, 161, 165, 122
//pinMode(led, OUTPUT);
//pinMode(SCKLED,OUTPUT);
//digitalWrite(SCKLED,LOW);
//digitalWrite(led, 0);
//digitalWrite(led, HIGH);
//digitalWrite(SCKLED, HIGH);
a stejně Arduino vesele bliká dále. Frekvence blikání je otravná a powerbanka nevydrží ani den.
Máte někdo s tím zkušenosti?
-
Zapojeni s Dallas 2
(Jiří Kačmařík, 16. 1. 2017 18:54:07)
Odpovědět
Asi jsem na to přišel
dal jssem Dallas na port D1 podle
https://github.com/RuiSantosdotme/Random-Nerd-Tutorials/blob/master/Projects/DS18B20__ESP8266_web_server.ino
opravil řádek 9
#define ONE_WIRE_BUS D1
a přestalo to blikat a měří i pod nulou
----------------------------------------
Teplota venku: -1.0°C
Teplota doma: 22.5°C
------------------------------------
sice mi to moc nesedí neb venku je -1.9
ale aspoň nějaký pokrok, možná je to jen nastaveným rozlišením Dallasu (skáče po 0.5) -
Zapojení s Dallas 3
(Jiří Kačmařík, 17. 1. 2017 14:41:02)
Odpovědět
Ještě jedna informace k TEMPERATURE_PRECISION
// Mode Resol Conversion time
//#define TEMPERATURE_PRECISION 9 // 9 bits 0.5°C 93.75 ms
//#define TEMPERATURE_PRECISION 10 // 10 bits 0.25°C 187.5 m
//#define TEMPERATURE_PRECISION 11 // 11 bits 0.125°C 375 ms
#define TEMPERATURE_PRECISION 12 // 12 bits 0.0625°C 750 ms
-
Chyba kompilace
(Jirka, 27. 1. 2017 20:15:15)
Odpovědět
Dobrý den, pořád mi vyskakuje tato hláška:
NodeMCU-DS18B20.ino:6:31: fatal error: DallasTemperature.h: No such file or directory
compilation terminated.
Chyba kompilace.
-
3 čidla?
(reddy, 27. 3. 2017 14:00:28)
Odpovědět
snažím je tento případ pochopi zpětně, jak by vypadal kód se 3 čidly prosím?