Arduino ve W5100 Ethernet Modül ile Web Server (Ajax)

Merhaba,

Bu konuda Arduino ile W5100 Ethernet modülü kullanarak bir Web Server oluşturacağız. Ancak bu Web Server önceki verilen konudaki Web Server’ dan farklı olarak gösterdiği verilerin güncellenmesi için sayfa yenilemesine ihtiyaç duymayacak. Bu özelliği Web Server’ a “Asynchronous JavaScript and XML” (AJAX) kullanarak vereceğiz. AJAX, “Javascript” ve “XMLHttpRequest” kullanarak sunucu ile etkileşimli Web uygulamaları geliştirmeyi sağlayan bir yapıdır. Bu sayede sayfa yenilenmesine ihtiyaç duymadan Web sitesinde gösterilen verileri güncellenebilir yada Web sitesi ile sunucu arasında gerçek zamanlı iletişimli sağlanabilir. Örnek olarak Google arama moturunu düşünün. AJAX olmadan google size öneride bulunabilmesi için sayfayı her seferinde yenilemeniz gerekecekti. Bu da kullanışlı olmayan bir durum olarak ortaya çıkacaktı.

AJAX’ ın bileşenlerine bakacak olursak, Javascript’ in ne olduğuna daha önceki Node.Js uygulamalarında basitçe değinmiştim. Peki ya “XMLHttpRequest” nedir? “XMLHttpRequest” Javascript, XML ve CSS gibi bir çok teknolojiyi birlikte arka planda eş zamanlı olarak çalışarak Web sitesinde görüntülenmesi istenilen verilen anında görüntülenmesini sağlayan bir yapıdır. Bu yapı istemci(client) tarafında çalışır. Sunucudan gelen ve sunucuya gidecek istekler ayarlayabilir. Javasciprt ve “XMLHttpRequest” birleşerek AJAX’ ı oluşturur. AJAX’ ın çalışma prensibine örnek olarak w3schools’ daki bu resim verilebilir.

AJAX
AJAX çalışma yapısı

Resimde de görüldüğü üzere Web sayfasında oluşturulan istek sunucuya gönderiliyor ve sunucu bir cevap üretip tekrardan Web sayfasına geri gönderiyor. Oluşturulan isteklerin birer cevabı olması da bir çok sistem için AJAX’ ı kullanışlı hale getirmektedir. Çünkü oluşturduğumuz isteklerin sunucuya gidip gitmediğini kontrol edebilmemiz bu cevaplar sayesinde kolay hale gelmektedir.

AJAX’ ın en önemli avantajlarından bir tanesi asenkron olarak bir çok işlemin gerçekleşmesine olanak vermesidir. Böylece aynı anda Web sitesinde bir çok veri güncellenirken sunucuya istekler gönderilebilir. Tabi sunucu olarak Arduino kullanılınca bu isteklerin sıra ile gerçekleşeceğini unutmamakta fayda var.

Yapacağımız uygulamada Web sitesine ADC verisini göndermek ve Web sitesinde kullanılan araçlardan gelen istekleri Arduino’ da değerlerndirmek için AJAX kullanacağız. Böylece sayfa yenilenmeden her değişikliği anlık olarak gözlemleyebileceğiz. Ayrıca yapacağımız Web sitesi tasarımını “Bootstrap” kullanarak gerçekleştireceğiz. Böylece tasarlayacağımız Web sitesi cep telefonu ile görüntülemeye tam uyumlu olacak. Bootstrap, Web tasarımlarında CSS yükünü oldukça hafifleten bir framework’ dur. Bootstrap sayesinde neredeyse hiç CSS yazmadan mobil cihazlara uyumlu Web tasarımları gerçekleştirmek mümkündür. Bootstrap 3′ ün referans sayfasına bağlantıdan ulaşabilirsiniz. Web sayfası içeriği biraz fazla olması sebebi ile oluşturacağımız tasarımı RAM yerine FLASH hafızada saklamamız gerekecektir. Bu değişkenin tamınlanması ve okunmasında ufak değişikliklere sebebiyet verecektir. Yeri geldiğinde onlara da değinmeye çalışacağım.

Bağlantı Şeması

Yapacağımız uygulamada bir potansiyometre bir RGB LED ve bir normal LED kullanalım. Potansiyometreden okunan değeri düzenli aralıklar ile Web sitesine gönderirken, Web sitesinden butona basılması durumunda LED durumu değiştirilebilir. Böylece bir çok cihazı aynı Web sitesi ile gerçek zamanlı haberleştirmiş oluruz. Bu durumda devre için gerekli bağlantı şeması aşağıdaki gibi olmaktadır.

Arduino Nano – W5100 Bağlantı Şeması

Arduino Yazılımında Önemli Noktalar

Devre şemasını verdikten sonra yazılıma geçmeden önce yazılımdaki bazı püf noktalarına değinelim. Öncelikle yukarıda da değindiğim gibi oluşturacağımız Web sayfası Arduino içerisinde uzun bir String değişken olarak tutulacak. String uzun olduğu için RAM’ de depolama yapabilmek mümkün olmayacaktır ve değişkeni FLASH hafızada saklamak gerekecektir. Arduino’ da herhangi bir değişkeni FLASH hafızada saklamak için değişken tanımında değişken isminden sonra “PROGMEM” direktifi kullanılmalıdır. Böylece yükleme sırasında bu değişken FLASH hafızada boş bir bölgeye yazılacaktır. Basitçe aşağıdaki şekilde tanımlama yapılabilmektedir.

const char myHtml[] PROGMEM = "ELEKTROBOT.NET";

Arduino’ da FLASH hafızada saklanan veriyi okumak için değişkenin ismini kullanmak tek başına yeterli değildir. Arduino’ da FLASH hafızadaki değişkenleri okumak için “pgm_read_byte” isimli bir fonksiyon mevcuttur. Bu fonksiyon FLASH hafızadan byte olarak tek tek okuma yapar. Bu fonksiyonun farklı işlevi olan çeşitleri de bulunmaktadır. Bu fonksiyonlara bağlantıdan ulaşabilirsiniz. “PROGMEM” ile alakalı Arduino sayfasına bağlantıdan ulaşabilirsiniz. “pgm_read_byte” fonksiyonunu String okuma için kullanacağımızdan bir döngü içerisinde String’ in her karakteri için okuma yapmalıyız. Örnek olarak aşağıdaki yapıya bakabilirsiniz.

const char myHtml[] PROGMEM = "ELEKTROBOT.NET";
for (int i = 0; i < sizeof(myHtml); i++) {
  char c = pgm_read_byte(myHtml + i);
}

 

Yazılım konusunda önemli bir püf noktası da Raw String Literal kullanımı. Raw String Literal, C++ 11 ile gelmiş çok satırlı string tanımlanmasını kolaylaştıran bir yapıdır. String ifade R”( … )” şeklinde tanımlanır. Parantez içerisindeki ifade çok sayıda satırdan oluşabilir ve alt satıra geçmek için herhangi bir ifadeye ihtiyaç duyulmaz. Uzun String tanımını kolaylaştıran bir yapıdır. Web sitesini değişken olarak tanımlarken bu yapıyı kullanacağız. Örnek olarak aşağıdaki yapı verilebilir.

const char myHtml[] PROGMEM = R "( 
  ELEKTROBOT.NET 
  Oğuzhan BAŞER 
)";

Son olarak da Http Request’ lerden bahsedeceğim. AJAX kullanarak sunucuya gönderdiğimiz veriler sunucuda bir Http Request olarak gitmekte. Bu request’ leri sunucu tarafında doğru şekilde algılayıp işlememiz gerekiyor. Daha açık olması açısından Web sitesinde butona bastığımızda gelen istek ile RGB LED’ in rengini değiştirmek için kullandığımız Slider’ ın isteği birbirine karışmamalıdır. İkiside “GET” request olarak gelecektir. Lakin içerdiği string’ ler birbirinden farklı olacaktır. Sunucu tarafında bu String’ ler incelenip doğru şekilde ayrılmalıdırlar.

Arduino Yazılım

Artık yazılım kısmına gelebiliriz. Yazılımda ilk olarak Ethernet Server ayarlamaları yapalım. MAC adres belirlemesi, IP adress ataması ve Ethernet Modül’ un CS (Chip Select) pini için kullanacağımız dijital pinin belirlenmesi işlemlerini gerçekleştireceğiz.

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0xDE,
  0xAD,
  0xBE,
  0xEF,
  0xFE,
  0xED
};
IPAddress ip(192, 168, 1, 177);
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
int csPin = 8; // ethernet module cs pin

Burada yapılan ayarlamaları tamamen keyfi olarak belirledim. Siz de istediğiniz gibi değişiklik yapabilirsiniz. Sadece IP adresinin ağda başka bir cihaz tarafından kullanılmadığından emin olmanız yeterli olacaktır. PORT numarası olarak 80′ den farklı bir değer seçilecek olursa URL adresinin sonuna ekleme yapılması gerektiğini unutmayın. 80 PORT’ u default olduğu için ekleme yapılmadan kullanılabilir. 3000 port’ u için web tarayınıcızda kullanmanız gereken adres şu şekilde olmalıdır.

http://192.168.1.177:3000

Daha sonra setup fonksiyonu içerisindeki ayarlamaları yapalım. Bu ayarlamalar Web Server’ ı başlatmak için gerekli ayarlardır.

// ethernet module cs pin 
Ethernet.init(csPin); 
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
// Check for Ethernet hardware present
if (Ethernet.hardwareStatus() == EthernetNoHardware)
{
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true)
    {
        delay(1); // do nothing, no point running without Ethernet hardware
    }
}
if (Ethernet.linkStatus() == LinkOFF)
{
    Serial.println("Ethernet cable is not connected.");
}
// start the server
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());

Burada yapılan işlemler yorum satırlarında belirtilmiş. Ancak kısa bir özet geçecek olursam. Kullandığımız CS pinini belirledik, MAC ve adresini IP adresini module ilettik. Daha sonra Ethernet Modul’ ün kablo bağlantılarını test ettik. Her şey yolunda ise server’ ı başlattık. Server başlattıktan sonra loop içerisinde server’ a gelen istekler değerlendirilmeli. Bu değerlendirme işlemini yapmak için client’ den alınan her byte’ ı String değişkene ekleyerek saklayacağız ve daha sonra bu string içerisine bakarak Web sitesinde belirlediğimiz butona basma, yada ADC isteklerinden hangisinin geldiğine karar vereceğiz. Bu soruguyu gerçekleştirmek için veri paketinin sonu geldi mi diye kontrol ederek işleme başlayabiliriz. Daha anlaşılır olması için aşağıdaki yazılıma bakabilirsiniz.

while (client.connected())
{
    if (client.available())
    {
        char c = client.read();
        readString += c;
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n')
        {
            if (readString.indexOf("setLED") > 0)
            {
                send_header(client);
                if (readString.indexOf("LEDstate=1") > 0)
                {
                    digitalWrite(ledPin, HIGH);
                    client.println("ON");
                }
                else if (readString.indexOf("LEDstate=0") > 0)
                {
                    digitalWrite(ledPin, LOW);
                    client.println("OFF");
                }
                break;
            }
            else if (readString.indexOf("readADC") > 0)
            {
                send_header(client);
                client.println(analogRead(A0));
                break;
            }else if(readString.indexOf("setRGB") > 0)
            {
                int indx = readString.indexOf("=");
                char rgbArr[7]; rgbArr[6] = '\0';
                for(int i = 0; i < 6; i++)
                {
                    rgbArr[i] = readString.charAt(i + indx + 1);
                }
                long rgbInt = strtol(rgbArr, 0, 16);
                uint8_t rVal = (uint8_t)((rgbInt & 0xFF0000) >> 16);
                uint8_t gVal = (uint8_t)((rgbInt & 0x00FF00) >> 8);
                uint8_t bVal = (uint8_t)((rgbInt & 0x0000FF) >> 0);
                analogWrite(redPin, rVal);
                analogWrite(greenPin, gVal);
                analogWrite(bluePin, bVal);
                
                send_header(client);
                client.println("OK");
                break;
            }
            SendHTML(client);
            break;
        }
    }
}

Yazılımdan da anlaşılacağı üzere Web sitesinden Arduino’ ya 3 adet farklı istek gelmekte. Bunlardan bir tanesi ADC değeri isteği, diğer ikisi ise RGB ve normal LED için gelen isteklerdir. ADC ve normal LED istediği basit olduğu için gelen isteği karşılaştırıp doğrudan cevap gönderdik. Burada ADC’ de bir istek olarak ayarladık. Web sitesinde ADC değerini istemek için bir buton olmayacak. Bunun yerine Javascript ile bir “interval” oluşturup düzenli aralıklar ile sunucudan ADC verisini isteyeceğiz. Bu interval Web sitesi açılır açılmaz başlayacak. Böylece düzenli aralıklar ile sunucudan veri istenecektir. RGB LED istediği, R, G ve B kanalları için 8 bit olmak üzere 24 bit şeklinde hexadecimal değer olarak gönderilmektedir. Bu sebeple ayırma işleminde önce tam sayıya çevirip sonra 8′ er bitli gruplara ayırmayı tercih ettim. Web sitesinden gelen isteğin baş kısmı bu şekildedir.

GET /readADC HTTP/1.1

İstek içerisinde ilk olarak HTTP isteğin çeşidi belirtilmiş. Web sitesinden gönderirken bunu “GET” olarak belirlediğimiz için burada da bu şekilde gelmekte. Daha sonrasında ise Web site üzerinde kullanılan araca göre gönderilmesini istediğimiz istek bilgisi mevcut. Buna bakarak Web sitesinde hangi aracın kullanıldığına karar verebilmekteyiz. Web sayfası Arduino’ da index.h dosyası içerisinde mevcut. Tasarım için gerekli yazılım uzun olduğu için bunu ana yazılımdan ayırmak amacı ile bu şekilde bir yöntem tercih ettim. Son olarak da Web sitesinde Javascript ile oluşturduğumuz “XMLHttpRequest” kodlarına bakalım.

Web Javascript

// create request class
var xhttp = new XMLHttpRequest();
function sendData(led) {
    // send LED request and wait for response
    xhttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            document.getElementById("ledStat").innerHTML =
                this.responseText;
        }
    };
    xhttp.open("GET", "setLED?LEDstate=" + led, true);
    xhttp.send();
}

 

Yukarıda verilen kod örneğinde LED butonlarına basıldığında çalışan kısım verilmiş. Parametre olarak LED değeri gelmekte. Web Sitesi tasarımında iki adet buton bulunduğu için açma ve kapama butonu farklı farklı. Bu sebeple açma butonuna basınca bu fonksiyona parametre olarak 1 gönderilmekte. Bu 1 değeri fonksiyonda isteğin sonuna eklenip Arduino’ ya gönderiliyor. Ayrıca Arduino’ dan gelen isteği bekleyen bir kısım da bulunmakta. Bu kısım sayesinde LED’ i yakma butonuna bastığımızda, Arduino’ dan gelen isteğe bakarak LED durumunu yazabilmekteyiz.

Konu anlatımında elimden geldiğince çok detaya yer vermeye çalıştım. Konu içeriği aslında oldukça geniş ve konu çok uzamaması için de kısa tutmaya çalıştım. Umarım bir bilgi yanlışı yada eksiği yapmamışımdır. Oluşturudğum Web tasarımının resmi aşağıda mevcuttur. Yazılımın tamamına github üzerinden ulaşabilirsiniz.

Web Tarayıcısı

Mobil Tarayıcı

Add a Comment

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir