A magyar webshopok általában ugyanarra az alaplapra épülő megoldást árulják, csak más (szabvány) dobozba csomagolva, bruttó 30-60eFt közötti áron. Sok esetben a szenzorokat még külön kell megvenni, ami sorkapcson (alföldiesen: csoki), RJ11 vagy RJ45 aljzaton keresztül kapcsolódnak.
A feladat a megvásárolható termékek alapján:
- DHCP kliens, esetleg statikus IP (állítási lehetőség)
- hőmérséklet és páratartalom mérés (informatív és nem OMH pontossággal)
- SNMP és/vagy web szerver (Cacti, Munin, stb plugin gyártáshoz)
- IP-s elérhetőség dróton vagy WiFin
A felhasznált kütyük
- NodeMCU (930Ft-tól Kínából, kb. 2300Ft-tól Magyarországról)
- 1.8″ SPI/I2C TFT kijelző 3.3V! (970Ft-tól Kínából, kb. 2300Ft-tól Magyarországról)
- hőmérséklet modul, pl. DTH11, amiből érdemes 3 lábút keresni, mert abban a felhúzó-ellenállás integrálva van (320Ft-tól, a csillagos égig Kínából, kb. 590Ft Magyarországról )
Első lépések
Az ilyen TFT kijelzők szerencsére 3.3V és 5V-os működésre is képesek. De az ezek közötti váltás sokszor egy forrasztást igényel. Az én kijelzőm alapból 3.3V-os, ami a NodeMCU számára ideális, de az Uno tönkreteszi. A 3.3V-os üzemmódhoz nálam a J1 forrpontokat rövidre kell zárni. Olvassuk el az eladó leírását vásárlás előtt!
A szoftveres alapok
Az 1.8″-os TFT meghajtásához kell pár dolog: ST7735_ESP8266, Adafruit_GFX, Adafruit_ST7735 . Az első kivételével telepíthető az Arduino környezetből (Vázlat-> Könyvtár tartalmazása -> Könyvtárak kezelése). A NodeMCU-hoz az ESP8266, a DHT11-hez pedig Adafruit DHT. A kézi telepítéshez a Program Files(86)\Arduino\Library mappába kell másolni, valamint az Arduino programot újraindítani.
Vezetékelés
1.8″ SPI 128×160 TFT | NodeMCU | DTH11 |
---|---|---|
D0 | ||
RESET | D1 | |
D2 | S | |
D3 | ||
A0 | D4 | |
SCK | D5 | |
D6 | ||
SDA | D7 | |
CS | D8 | |
Vcc, LED | 3.3V | + (Vcc) |
GND | GND | GND (-) |
Munin plugin (PHP-vel)
Nem valami elegáns plugin, de mutiba’ jó lesz.
#!/usr/bin/php <?php if ( count($argv) == 2 && $argv[1] == 'autoconf' ) { exit('yes'); } if ( count($argv) ==2 && $argv[1] == 'config' ) { echo 'graph_title Temperature and humidity'.PHP_EOL; echo 'graph_vlabel Celsius and percent'.PHP_EOL; echo 'graph_category Sensors'.PHP_EOL; echo 'temperature.label Temperature'.PHP_EOL; echo 'temperature.type GAUGE'.PHP_EOL; echo 'temperature.colour COLOUR0'.PHP_EOL; echo 'humidity.label Humidity'.PHP_EOL; echo 'humidity.type GAUGE'.PHP_EOL; echo 'humidity.colour COLOUR1'.PHP_EOL; exit(); } $json = file_get_contents('http://192.168.11.214'); $j = @json_decode( $json ); if ( isset( $j->temperature ) ) { echo 'temperature.value '.$j->temperature.PHP_EOL; echo 'humidity.value '.$j->humidity.PHP_EOL; } ?>
Arduino forráskód (még alakítás alatt)
// License things /*************************************************** This is a library for the Adafruit 1.8" SPI display. This library works with the Adafruit 1.8" TFT Breakout w/SD card ----> http://www.adafruit.com/products/358 The 1.8" TFT shield ----> https://www.adafruit.com/product/802 The 1.44" TFT breakout ----> https://www.adafruit.com/product/2088 as well as Adafruit raw 1.8" TFT display ----> http://www.adafruit.com/products/618 Check out the links above for our tutorials and wiring diagrams These displays use SPI to communicate, 4 or 5 pins are required to interface (RST is optional) Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! Written by Limor Fried/Ladyada for Adafruit Industries. MIT license, all text above must be included in any redistribution ****************************************************/ /* * ESP8266-12 HY-1.8 SPI * GPIO5 D1 Pin 06 (RESET) * GPIO2 D4 Pin 07 (A0) * GPIO13 D7 (HSPID) Pin 08 (SDA) * GPIO14 D5 (HSPICLK) Pin 09 (SCK) * GPIO15 D8 (HSPICS) Pin 10 (CS) */ /* #define TFT_PIN_CS 15 #define TFT_PIN_DC 2 #define TFT_PIN_RST 5 - See more at: http://www.esp8266.com/viewtopic.php?f=32&t=3668#sthash.ueG2ptmV.dpuf src: http://www.esp8266.com/viewtopic.php?f=32&t=3668 */ // Libraries #include <Adafruit_GFX.h> // Core graphics library #include <Adafruit_ST7735.h> // Hardware-specific library #include <SPI.h> #include <ESP8266WiFi.h> //#include <ESP8266WiFiMulti.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> #include <ESP8266mDNS.h> #include "DHT.h" // DTH11 #define DHTPIN 4 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); int readyDTH = 0; float lastTemperature = 0; char lastTemperatureStr[4] = "---"; char lastHumidityStr[4] = "---"; float lastHumidity = 0; int delaySensorRefresh = 0; // WiFi const char* ssid = "LegyesHome"; const char* password = "12345678"; ESP8266WebServer server(80); #define TFT_CS 15 #define TFT_RST 5 #define TFT_DC 2 Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); #define TFT_SCLK 13 // set these to be whatever pins you like! #define TFT_MOSI 11 // set these to be whatever pins you like! //Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); void setup(void) { Serial.begin(9600); // DTH dht.begin(); // LCD tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab, // Use this initializer if you're using a 1.8" TFT uint16_t time = millis(); tft.fillScreen(ST7735_BLACK); time = millis() - time; Serial.println("Initialized"); Serial.println(time, DEC); // WiFi printStatus("WiFi connecting..."); WiFi.begin(ssid, password); Serial.println(""); while (WiFi.status() != 6) { delay(500); Serial.print("."); printStatus("WiFi retry..."); } printStatus("WiFi connected"); printIP( WiFi.localIP() ); if (MDNS.begin("esp8266")) { Serial.println("MDNS responder started"); } server.on("/", handleRoot); server.onNotFound(handleNotFound); server.begin(); readyDTH = dht.read(DHTPIN); } void loop() { if ( delaySensorRefresh < 1 ) { delaySensorRefresh = 60; printStatus("Updating sensors..."); readyDTH = dht.read(DHTPIN); Serial.println( readyDTH ); if ( readyDTH == 1 ) { printTemperature(); printHumidity(); printStatus("Sensors updated"); } else { printStatus("DHT not ready, retry"); } printRSSI( WiFi.RSSI() ); printSSID( WiFi.SSID() ); } printSensorDelay(); delaySensorRefresh--; delay(500); server.handleClient(); } // LCD based functions void printSensorDelay() { char stringSensorDelayStr[3]; tft.fillRect(0, 10, 50, 10, ST7735_BLACK); itoa(delaySensorRefresh, stringSensorDelayStr, 10); tft.setCursor(0, 10); tft.setTextColor(ST7735_YELLOW); tft.setTextWrap(false); tft.setTextSize(1); tft.print(stringSensorDelayStr); } void printTemperature() { float ft = dht.readTemperature(); if( lastTemperature != ft ) { tft.fillRect(0, 20, 127, 42, ST7735_BLACK); char temperatureStr[15]; dtostrf(ft,2, 0, temperatureStr); tft.setCursor(0, 20); tft.setTextSize(1); tft.setTextColor(ST7735_GREEN); tft.setTextWrap(false); tft.print("Temperature (Celsius):"); tft.setCursor(50, 40); tft.setTextSize(3); char temperatureStrConcat[4]; strcpy( temperatureStrConcat, temperatureStr ); strcat( temperatureStrConcat, "C" ); tft.print(temperatureStrConcat); dtostrf(ft, 0, 0, lastTemperatureStr); } lastTemperature = ft; } void printHumidity() { float fh = dht.readHumidity(); if ( lastHumidity != fh) { tft.fillRect(0, 70, 127, 42, ST7735_BLACK); char humidityStr[15]; dtostrf(fh,2, 0, humidityStr); tft.setCursor(0, 70); tft.setTextSize(1); tft.setTextColor(ST7735_CYAN); tft.setTextWrap(false); tft.print("Humidity (percent):"); tft.setCursor(50, 90); tft.setTextSize(3); char humidityStrConcat[4]; strcpy( humidityStrConcat, humidityStr ); strcat( humidityStrConcat, "%" ); tft.print(humidityStrConcat); dtostrf(fh, 0, 0, lastHumidityStr); } lastHumidity = fh; } void printIP(IPAddress ip) { static char stringIP[20]; String labelIP = "IP:"; String IP = ip.toString(); labelIP.concat(IP); labelIP.toCharArray(stringIP, 20); tft.setCursor(0, 140); tft.setTextColor(ST7735_BLUE); tft.setTextWrap(false); tft.setTextSize(1); tft.print(stringIP); } void printSSID(String ssid) { tft.fillRect(0, 150, 80, 10, ST7735_BLACK); tft.setCursor(0, 150); tft.setTextColor(ST7735_MAGENTA); tft.setTextWrap(false); tft.setTextSize(1); tft.print(ssid); } void printRSSI(int rssi) { tft.fillRect(90, 150, 28, 10, ST7735_BLACK); char stringRSSI[3]; dtostrf(rssi,3, 0, stringRSSI); //itoa(int, str, int length); tft.setCursor(90, 150); tft.setTextColor(ST7735_MAGENTA); tft.setTextWrap(false); char RSSIStrConcat[8]; strcpy( RSSIStrConcat, stringRSSI ); strcat( RSSIStrConcat, "dBm" ); tft.setTextSize(1); tft.print(RSSIStrConcat); } void printStatus(char *text) { tft.fillRect(0, 0, 127, 19, ST7735_BLACK); tft.setCursor(0, 0); tft.setTextColor(ST7735_WHITE); tft.setTextWrap(true); tft.setTextSize(1); tft.print(text); } // WiFI server based functions void handleRoot() { String s = "{\"temperature\":"; s += lastTemperatureStr; s += ",\"humidity\":"; s += lastHumidityStr; s +="}"; server.send(200, "application/json", s); } void handleNotFound(){ String s = "{\"temperature\":"; s += lastTemperatureStr; s += ",\"humidity\":"; s += lastHumidityStr; s +="}"; server.send(200, "application/json", s); }
#Update1:
A DTH11 meglehetősen érdekes viselkedése miatt később módosítanom kell a kódot, mert tüskéket csinál a grafikonon. Valószínűleg az lesz a megoldás, hogy 5 sikeres mérést fogok átlagolni. A páratartalomnál ez még szembetűnőbb. A DS18B20-szal ilyen gond nincs, szépen karcol és 1°C-ot ugrik. A DTH11 hülyeségeire már korábban is felfigyeltem. Nagyon sok fórumban írtak hasonlókat. Az is közrejátszhat, hogy csak a kínaiak tudják mi is van valójában a kis, kék dobozkában – lehet csak valami gagyi klónt fogtam ki. Az átlagolással minden bizonnyal jó lesz mindkét mért érték. Folytatás hétvégén…
Update #2
A DHT szenzor hülyéskedései miatt kicsit módosítottam a kódon. Tudom, hogy nem szép, de az egész úgyis csak az amatőrködésről szól 😛
Letölthető a módosított (és csúnyább) kód innen: NodeMCU_18_TFT_DHT11.ino