Bu yazımızda ESP 8266 kullanarak, biraz da güzel görünümlü bir web sunucusu oluşturmaya çalışacağız. Gördüğüm örneklerde genellikle boş bir sayfaya sıcaklık ve nem yazdırılıyor. Elbette ilk odaklandığımız kısım normal olarak elektronik bağlantılar, modülü programlama ve sensörden gelen veriyi işleme. Çünkü kalan kısım salt HTML bilgisi. Bu yazıda ESP'yi en kolay yoldan programlayıp yerel ağ zincirlerinden kurtararak internet üzerinden erişebilir hale getireceğiz. Bu yüzden tasarımımızın biraz daha yakışıklı olmasına özen göstereceğiz. :)

Önceki iki yazımda ESP 8266'yı Arduino kullanarak nasıl programlayacağımızı ve web sunucusunu kuran ESP8266WebServer kütüphanesinin nasıl kullanılacağından bahsetmiştim. Gerek görürseniz aşağıdaki yazıları okumanızı tavsiye ederim.

DHT11'in pinleri aşağıdaki şekildedir. Piyasada 2 tip DHT11 bulunmakta. 3 pinli veya 4 pinli olabiliyor. Ben gerçekte 3 pinli kullandım ancak Fritzing şemasında 4 pinli olanını çizdim.

DHT 11 pinleri
DHT 11 pinleri

Devremiz ise aşağıdaki gibi olacaktır:

ESP 8266 - DHT11 bağlantıları
ESP 8266 - DHT11 bağlantıları

8266'ya göndereceğimiz kod ise aşağıdadır:


#include <ESP8266WebServer.h>
#include "DHT.h"
#define DHTTYPE DHT11   // DHT 11

const char* ssid = "WIFI-AGIM";
const char* password = "SIFREM";
const int DHTPin = 2;

ESP8266WebServer server(80);
DHT dht(DHTPin, DHTTYPE);

static char sicaklikTemp[7];
static char sicaklikFTemp[7];
static char nemTemp[7];

String htmlSablonu(String icerik) {
    String temp = "<HTML><head>"
    "<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css'>"
    "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/>"
    "</head><body>"
    "<nav class='navbar navbar-inverse'>"
    "<div class='container-fluid'>"
      "<div class='navbar-header'>"
        "<a class='navbar-brand' href='/'>Ev Sıcaklık ve Nem Sunucusu</a>"
      "</div>"
      "<ul class='nav navbar-nav'>"
        "<li><a href='/'>Ana Sayfa</a></li>"
        "<li><a href='/hakkimizda'>Hakkımızda</a></li>"
      "</ul>"
    "</div>"
    "</nav>";
    return temp + icerik + String("</body></html>");
}

String sicaklikNemSablonu(){
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  float f = dht.readTemperature(true);
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println("Hata olustu");
    return ("Hata oluştu. Sensör değerleri okunamadı");
  }
  
  float hic = dht.computeHeatIndex(t, h, false);       
  dtostrf(hic, 6, 2, sicaklikTemp);             
  float hif = dht.computeHeatIndex(f, h);
  dtostrf(hif, 6, 2, sicaklikFTemp);         
  dtostrf(h, 6, 2, nemTemp);
  
  
  String sicaklikClass;
  String nemClass;
  if (hic<=20) sicaklikClass="info";                // mavi
  if (hic>20 && hic<=24) sicaklikClass="success";   // yesil
  if (hic>24) sicaklikClass="danger";               // kirmizi

  if (h<=55) nemClass="info";                
  if (h>55 && h<=65) nemClass="success";       
  if (h>65) nemClass="danger";                 

  String tbas = "<table class='table'><thead><tr><th>Sensör</th><th>Değer</th></tr></thead><tbody>";
  String sicaklikRow = String("<tr class='") + sicaklikClass + String("'><td>Sıcaklık</td><td>") +String(sicaklikTemp) +String (" ℃</td></tr>");
  String nemRow = String("<tr class='") + nemClass + String("'><td>Nem</td><td>%") + String(nemTemp) +String ("</td></tr>");
  String tson = "</tbody></table>";
  return tbas + sicaklikRow + nemRow + tson;
}

void ana_sayfa() {
  Serial.print("Ana sayfa");
  String sensorDegerleri = sicaklikNemSablonu();
  String ana = htmlSablonu(sensorDegerleri);
  server.send(200, "text/html", ana);
  delay(100);
}

void hakkimizda() {
  Serial.print("Hakkımızda");
  String hakkimizda = htmlSablonu("Cüneyt Aliustaoğlu @2017");
  server.send(200, "text/html", hakkimizda);
  delay(100);
}
 
void setup () {
 
  Serial.begin(115200);
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print("Bağlanıyor..");
  }
  Serial.print("Bağlandı ");
  Serial.print("IP adresi: ");
  Serial.print(WiFi.localIP());
  server.on("/", ana_sayfa);
  server.on("/hakkimizda", hakkimizda);
 
  server.begin();
  Serial.println("HTTP başlatıldı");
}
 
void loop() {
 server.handleClient();
 delay(1000);
}

Şimdi de neler yaptığımızı biraz açalım.

8266 ve DHT11 nesnelerimizi yaratıyoruz. (80) ifadesi sunucu 80 portunda çalışacak demektir. 80 varsayılan HTTP portudur. Eğer 80 dışında başka bir port kullanacaksak (örneğin 3000) sunucuyu 192.168.1.71:3000 şeklinde çağırmamız gerekir. Ama biz 80 portunu kullanıyoruz ve benim sistemimde port 192.168.1.71 olarak atandı. Sizde daha farklı olabilir.

ESP8266WebServer server(80); DHT dht(DHTPin, DHTTYPE);

Eğer atanan IP adresini bulamıyorsanız ücretsiz Advanced Port Scanner adlı yazılımı kullanabilirsiniz.

Advanced Port Scanner
Advanced Port Scanner

Birden çok adres listeleniyorsa, yalnızca HTTP(80) portunun açık olduğu adreslerden şansınızı deneyebilirsiniz.

Aşağıda sıcaklıkları atayacağımız değişkenleri tanımladık. DHT11'in döndürdüğü değerler float. Ancak HTML içinde kullanabilmemiz için string dönüşümü yapmamız gerekiyor. Bu değişkenleri kullanacağız. Burada SıcaklıkFTemp fahrenhayt cinsinden. DHT11, direk fahrenhayt değeri de gönderebiliyor isteğe bağlı olarak. Yalnız ben Fahrenhaytı kullanmadım, ancak kullanmak isteyen olursa diye de burada bulunduruyorum.
static char sicaklikTemp[7]; static char sicaklikFTemp[7]; static char nemTemp[7];

Bootstrap, Twitter'ın kendi altyapısında kullandığı bir HTML/CSS kütüphanesidir. Ancak tüm dünyada o kadar büyük kabul gördü ki neredeyse bir standard haline geldi. Yeni bir dil değil, sadece yılların deneyiminin getirdiği bir birikimle oluşturulan kurallar. Bu kütüphaneyi kullandığınızda hem masaüstü için ayrı, telefon için ayrı, tablet için ayrı kod yazmaktan kurtuluyor hem de daha okunabilir ve geliştirilebilir bir yapıya sahip oluyorsunuz. Bootstrap'e alternatif pek çok kütüphane de var, Foundation ve Skeleton gibi ancak hepsinin mantığı birbirine benzer şekilde.

Burada Bootstrap'i ESP8266 içine gömmek yerine CDN üzerinden çağıracağız. 8266 gibi kendi üzerindeki alanı sınırlı ancak internet erişimi olan bir modül için bu kütüphaneleri gömmek oldukça mantıksız.

<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css'>

Bootstrap'in navbar bileşenini kullanarak genel şablonu oluşturduktan sonra sıcaklık ve nem durumlarına göre mavi, yeşil, kırmızı renkleri bastırıyoruz.

Sıcaklık be Nem Sunucusu
Sıcaklık ve Nem Sunucusu

Sunucumuz hazır ancak localhost'a zincirlenmiş durumda. Okuldan ya da iş yerinden erişmek istediğimizde neler yapmalıyız. Bu kısım için evrensel bir çözüm yok. Çünkü uygulayacağımız adımlar evinizdeki router ve servis sağlayıcınıza göre değişiklik gösteriyor. Ancak "port yönlendirme" kavramı bir standart. Aşağı yukarı her modern router'da benzer adımlarla gerçekleştiriyor. Ben kendi modemim için açıklayacağım. Ancak yöntemler pek çok router'da benzer şekilde.

NAT>Port Mapping menüsünden port yönlendirmeye eriştim ve aşağıdaki ayarları yaptım.

Port yönlendirme
Port Yönlendirme

Burada 3391 tamamen keyfi olarak seçtiğim bir port. 80 ise ESP8266WebServer server(80); ile atadığım port. whatismyipaddress.com adresinden bulduğum adresi (örneğin 123.12.34.56) 123.12.34.56:3391 şeklinde çağırarak her yerden bağlantıya hazır hale getiriyorum.

Eğer statik IP sahibi değilseniz, IP adresiniz her 3-5 günde bir değişecektir. NOIP gibi bedava servisleri kullanarak bu duruma çözüm üretebilirsiniz. Dinamik DNS adlı yazımda bunu ayrıntılı olarak incelemiştim. Bu inceleme Orange Pi için ancak aynı adımlar her türlü sunucu için ayarlanabilir.