ESP32 Web Server (AJAX)
|Merhaba,
Bu konuda ESP32 ile bir web server oluşturacağız. Bu Web Server verilerin güncellenmesi sırasında sayfa yenilmemesi gereksinimi duymaması için XmlHttpRequest (AJAX) destekli olacaktır. AJAX XmlHttpRequest’ i kapsayan bir platformdur. İsmi daha kısa olduğu için konunun geri kalanında bu kısaltmayı kullanacağım. Benzeri bir konuyu daha önce paylaşmıştım. Bağlantıdan ulaşabilirsiniz. Ancak önceki konuda W5100 Ethernet modülü kullanılarak Web Server kurulumu yapmıştım. Bu konuda ise ESP32 kullanarak benzeri işlemleri yapacağız. Ancak ESP32 kullanırken bazı farklı işlemler yapmamız gerekli. ESP32′ de AJAX destekli Web Server kurarken Arduino ile gelen default Web Server kütüphanelerinin sorun çıkardığını gözlemledim. O sebeple “AsyncWebServer” isimli bağlantıdaki kütüphaneyi kullandım. Kullanımı çok farklı değil. Sadece callback fonksiyonlarını oluşturma kısmında bazı farklılıklar bulunmaktadır.
AJAX’ ın ne olduğuna ve temel mantığına önceki konuda değinmiştim. O sebeple burada tekrardan değinmeyeceğim. ESP32 modülünü Arduino IDE’ si kullanarak programlayacağım. ESP32 ile Arduino IDE’ sinin nasıl kullanılacağına bağlantıdaki yazıdan ulaşabilirsiniz.
Yapacağımız uygulamada LED’ leri arayüz üzerinden kontrol ederken, ESP32′ ye bağlı bir potansiyometrenin verisini Web üzerinde sayfayı yenilemeden görebileceğiz. Bir RGB LED’ in kanallarını farklı farklı kontrol edebilmek için slider’ lar olacak. Bu işlemleri sayfa yenilemeden yapmamızı AJAX’ ın sağladığını belirtmiştik. Ancak AJAX Web sitesi tarafında çalışmakta ve tek başına işlevsiz. Çünkü ESP32 tarafında AJAX üzerinden gelen istekleri yakalayıp cevap verecek bir yapı gereklidir. Bu yapıyı “AsyncWebServer” sağlamaktadır.
AsyncWebServer ile Arduino’ da bulunan WebServer arasında kullanım açısından çok fark bulunmamakta. Yapacağımız uygulamada bu iki yapı arasındaki temel farkı şu şekilde görebiliriz. Öncelikle WebServer kütüphanesi kullandığımızda Web Siteden gelen istekleri yakalayan callback fonksiyona bakalım. Verilen “…” öncesindeki ayarlamaları temsil etmek. Sadece farklı kısımları göstereceğim için onları tekrar yazmadım.
...
WebServer server(80);
void handleRoot() {
server.send(200, "text/plain", "hello from esp8266!");
}
void setup(void) {
...
server.on("/", handleRoot);
}
Şimdi AsyncWebServer kütüpahnesinin kullanımına bakalım. Bu kütüphanede callback fonksiyona parametre olarak “AsyncWebServerRequest” verilmelidir. Web sitesine geri dönüşlerde bu request üzerinden yapılmalıdır.
...
AsyncWebServer server(80);
void handleRoot(AsyncWebServerRequest *request)
{
request->send(200, "text/html", "hello from esp8266!");
}
void setup(void) {
...
server.on("/", HTTP_GET, handleRoot);
}
“server.on” fonksiyonuna verilen “HTTP_GET” parametresi hangi HTTP request meydana geldiğinde bu fonksiyonun çalışacağını belirlememizi sağlar. Parametreden de anlaşılacağı üzere Web site üzerinden “GET” request i geldiğinde fonksiyonun çalışmasını istersek bu şekilde kullanabiliriz.
Bağlantı Şeması
Yazılım detaylarına girmeden önce ESP32′ de yazılımı çalıştırmak için gerekli bağlantı şemasını verelim. Başta da belirttiğim gibi RGB LED, potansiyometre ve bir kaç normal LED kullanacağız.
Bağlantı şemamız bu şekildedir. Yazılımda gerekli değişiklikler yapıldıktan sonra pinlerde değişiklik yapabilirsiniz. Ancak potansiyometrenin bağlandığı ADC pini ADC1 pinlerinden bir tanesi olmalıdır. Çünkü yapacağımız uygulamada ESP32 ile Wi-Fi kullanacağız ve ADC2, Wi-Fi çalışırken çalışmamaktadır.
Şimdi gelelim yazılım kısmına. Oluşturacağımız yazılımda ESP32 web sitesinden gelen isteklere cevap verecek ve LED’ leri yakacak yada potansiyometre değerini Web Sitesine gönderecektir. Web sitesinden gelen istekler LED’ ler için olabileceği gibi sayfa istekleri de olabilir. Genel ayarlamalar ile başlayalım.
Yazılım
void setup()
{
...
// set callback funcitons to answer requests
server.on("/", HTTP_GET, handleRoot);
server.on("/readADC", HTTP_GET, handleADC);
server.on("/setLED", HTTP_GET, handleLED);
server.on("/setRGB", HTTP_GET, handleRGB);
server.onNotFound(handleNotFound);
//start server
server.begin();
}
Setup kısmında 5 adet request için callback ayarlaması bulunmakta. Bu request’ lerden 3 tanesi çevre birimlerinin kontrolü için diğerleri ise sayfa isteklerine verilen cevaplardır. “handleRoot” ana sayfa açıldığında çalışmasını istediğimiz fonksiyonu temsil etmektedir. Callback fonksiyonu şu şekildedir.
void handleRoot(AsyncWebServerRequest *request)
{
Serial.println("Connected");
request->send(200, "text/html", MAIN_PAGE);
}
Callback fonksiyonundaki parametre olarak gelen request’ in Web site tarafından gönderilen istekleri içerdiğini daha önce belirtmiştik. “send” fonksiyonunda bulunan “MAIN_PAGE” isimli değişken, daha önceden tanımladığımız ve ana sayfada olması gereken HTML, CSS ve JavaScript kodlarını içeren “String” biçiminde bir değişkendir. Biraz karışık olduğunun farkındayım ama aslında mantığı çok basit. AsyncWebServerRequest sınıfına ait “send” fonksiyonu, veri göndermek için “string” parametreye ihtiyaç duymakta. Bu sebeple ana sayfada görüntülemek istediğimiz kodlar uzun bir karakter dizisi şeklinde Web Siteye gönderilmelidir. Tarayıcı bu karakterleri yorumlayarak bize Web Sitesini düzgün şekilde görüntüler. Web sitesi bunların yorumlanması gerektiğini “send” fonksiyonundaki ikinci parametresinden anlar. İkinci parametrede bulunan “text/html” gönderilen bilgilerin HTML içerdiğini bildirmektedir. Bunun yerine “text/plain” yazarsak gönderdiğimiz HTML olduğu text olarak web sitesinde görüntülenir. Bu sebeple ikinci parametre de önemlidir.
Şimdi LED kontrol callback ine bakalım. Bu callbak içerisinde gelen isteğe göre hangi LED’ e işlem yapmak istediğimize ve yapmak istediğimiz işleme (açmak yada kapamak) karar vereceğiz. Web siteyi biz oluşturduğumuz ve gelecek olan istek de Web site üzerinden geleceği için gelecek isteğin formatına da biz karar verebiliriz. Basit olarak şu şekilde bir format oluşturdum.
setLed?Ledstate=1&lednum=0
Yukarıdaki satırda verilen ifade Querry String olarak tanımlanır. Querry string ifadesindeki “setLed” gönderilen HTTP request’ in ismidir. “Ledstate” ve “lednum” ise Http Request’ in parametreleridir. Gelen request ismine bakarak callbak fonksiyonunu çağıracağız. Callback fonksiyonu içerisinde request parametrelerine bakarak işlemler gerçekleştireceğiz.
Benzeri durum da RGB LED için geçerli. RGB LED kanallarını ayrı ayrı ayarlayabilmek için yine bir Querry String formatına ihtiyacımız olacak. Bunu basit olarak şu şekilde oluşturdum.
setRGB?r=10&g=20&b=30
HTTP Request ismi “setRGB” olup, her kanal için ayrı ayrı parametreler belirlenmiştir. Bu parametrelerin değerleri callback fonksiyonu için ayrılarak LED’ in renk kanallarına PWM sinyali olarak gönderilir. PWM’ in çevrim oranını değiştirerek LED kanallarının parlaklığını değiştirebiliriz. RGB LED için callback fonksiyonun içerisine bakalım.
void handleRGB(AsyncWebServerRequest *request)
{
// get RGB values from parameters
String rVal = request->arg("r");
String gVal = request->arg("g");
String bVal = request->arg("b");
// show values on serial monitor
Serial.print(rVal);
Serial.print("\t");
Serial.print(gVal);
Serial.print("\t");
Serial.println(bVal);
// set duty cycle for RGB channels
ledcWrite(ledChannel1, rVal.toInt());
ledcWrite(ledChannel2, gVal.toInt());
ledcWrite(ledChannel3, bVal.toInt());
// send answer to client
request->send(200, "text/plane", "1");
}
void setup()
{
...
server.on("/setRGB", HTTP_GET, handleRGB);
}
Yukarıdaki kod bloğunda da görüldüğü üzere “setup” fonksiyonu içerisinde ESP32′ ye gelecek isteği ve istek geldiğinde çalışacak callback fonksiyonunu ayarladık. Callback fonksiyonu içerisinde gelen request içerisindeki parametreleri ayırma işlemini gerçekleştirdik. Aslında bu ayırma işlemini fonksiyona parametre olarak gelen “AsyncWebServerRequest” sınıfı otomatik olarak yapmaktadır. Biz sadece bu sınıfın “arg” fonksiyonunu kullanmak istediğimiz parametrenin ismi ile çağırmamız yeterlidir. “arg” fonksiyonu gelen request içerisinden istediğiniz parametreyi ayırıp string formatında geri döndürüyor. Bu sebeple işlemler oldukça kolaylaşıyor.
Diğer işlemler için de bu yapı benzer şekilde olduğundan tekrar değinmeyeceğim. Ancak burada dikkat edilmesi gereken yer callback fonksiyonda işlemler biterken gelen request’ e bir cevap gönderilmesidir. Bu cevaba web sitesi tarafında ihtiyaç duymuyor olsak bile yine de bir cevap gönderilmelidir. Çünkü Web sitesinde request oluşturduğumuz AJAX karşılık olarak bir cevap bekliyor ve bu cevap uzun süre gelmezse timeout hataları vermeye başlıyor. Gönderilen request ana sayfada gönderdiğimizden farklı olarak “text/plain” tipindedir. Yukarıda da bahsettiğimiz gibi LED request’ ine gönderdiğimiz cevap HTML içermediği için bu şekilde ayarlama yaptık. Son olarak da Web sitesi üzerinde gönderme işlemini yaptığımız yapıya bir bakalım.
function sendRGB() {
//get rgb values from sliders
var redVal = document.getElementById('r').value;
var greenVal = document.getElementById('g').value;
var blueVal = document.getElementById('b').value;
// convert rgb values range from 0 - 100 to 0 - 255
var r = parseInt(redVal / 100.0 * 255).toString();
var g = parseInt(greenVal / 100.0 * 255).toString();
var b = parseInt(blueVal / 100.0 * 255).toString();
// show slider value in labels
document.getElementById('rVal').innerHTML = String(redVal);
document.getElementById('gVal').innerHTML = String(greenVal);
document.getElementById('bVal').innerHTML = String(blueVal);
// wait for answer callback
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
}
};
// create querrystring
var sendStr = "setRGB?r=" + r + "&g=" + g + "&b=" + b;
// console.log(sendStr);
// send querrystring using xmlhttprequest
xhttp.open("GET", sendStr, true);
xhttp.send();
}
Yukarıda verilen yazılım Javascript’ te yazılmış. Bu fonksiyon sayfa üzerindeki 3 slider’ dan birinin değeri her değiştiğinde çalışır. Fonksiyon içerisinde 3 slider’ ın değeri de alınıp string’ e çevrilip belirlediğimiz querrystring formatında XMLHttpRequest üzerinden gönderiliyor. Oluşturduğumuz Web sitenin görüntüsü aşağıdaki gibidir.
Bu konuda anlatacaklarımız bu kadardı. Elimden geldiğince önemli yerleri açıklamaya çalıştım. Yazılımın tamamına bağlantıdan ulaşabilirsiniz. İlerleyen zamanlarda ESP32 ile farklı uygulamalar paylaşmaya çalışacağım.