
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