Hiçbir grup cihazın birbirleriyle kablosuz olarak konuşmasını istediniz mi? Ancak belki de kulağa çok karmaşık geldi veya donanımın çok pahalı olacağını düşündünüz. Bu durumda ESP-NOW yardımımıza koşuyor. Yine de hayal ettiğimiz zaman bir veya birden fazla cihaz havaya 2.4GHz bandında veri basıyor ve sadece tutmasını istediğimiz cihazlar o verileri alıyor. Yine de karmaşık geliyorsa inanın ESP-NOW protokolünü kullanmak düşündüğünüz kadar zor değil. Bu yazımızda ESP-NOW ’a başlamanın en basit yolunu inceleyeceğiz.
Eğer bloğumdaki önceki yazıları okuyan birisiyseniz ESP32 ve ESP8266 kartlarına aşina olabilirsiniz. Yine de benimle bu yazımda tanışıyorsanız diğer blog yazılarımı da incelemenizi tavsiye ederim.
ESP kartları gerek Wi-Fi modülü, gerek Bluetooth modülüne sahip olup ayrıca 32 bit işlemcileri sayesinde IOT projeleri ve haberleşme projeleri için süper ucuz ve çok kullanışlı kartlardır. Peki nedir bu ESP-NOW protokolü?
ESP-NOW, bir çok ESP cihazının Wi-Fi kullanmadan birbirleriyle iletişim kurmaların sağlayan bir protokoldür. Bu kablosuz mouse cihazlarında kullandığımız 2.4GHz kablosuz bağlantısına benzer bir protokoldür. ESP-NOW’da tüm cihazlar birbirleriyle senkron bir şekilde de çalışabildikleri için bir kablosuz sensör ağı kurmak istiyorsanız muhteşem cihazlardır. Şimdilik bir cihazdan diğer cihaza gönderebileceğiniz verinin boyutu 250 Byte’tır. Yani bir ESP cihazından diğerine ses dosyası veya bir video akışı yapamazsınız. Ancak sensör okumak istiyorsanız veya küçük bir pakete sığacak bir veri göndermek istiyorsanız 250 byte oldukça yeterli. Tüm bu bilgileri anladığımıza göre şimdi ESP-NOW’u olabildiğince hızlı kullanmanızı sağlayacak adımlara geçelim.
1. Adım: İhtiyaç Listesi
ESP-NOW protokolünü kullanmak istiyorsanız en az 2 adet ESP geliştirme cihazına ihtiyacınız var. Ben bu yazımda iki adet ESP32 kartını kullanacağım. Aşağıdaki linkten ESP32 veya ESP8266 kartlarına ulaşabilirsiniz.
ESP32-Wroom-32 Wifi ve Bluetooth Geliştirme Kartı: https://www.robo90.com/esp32-wroom-32-wifi-ve-bluetooth-gelistirme-karti
Nodemcu V3 – ESP8266 Geliştirme Kartı – CH340G: https://www.robo90.com/nodemcu-v3-esp8266-gelistirme-karti-ch340g
2. Adım: Nasıl Kodlarız?
ESP32 kartını kullanabilmek için Arduino IDE uygulamasına doğru kütüphaneyi indirmemiz ve birkaç önemli işleme dikkat etmemiz gerekir. Bu yazımda ESP32 kartlarına nasıl kod yükleyebileceğimizden bahsetmeyeceğim. Eğer ESP kartlarına nasıl yazılım yükleneceğini merak ediyorsanız aşağıdaki blog yazımı inceleyebilirsiniz.
Bu yazımızda ESP32 ’ ye Arduino IDE kullanarak ESP32’ye nasıl yazılım yükleneceğini ve örnek bir kod olarak ESP32’ye blink kodunu yükleyeceğiz.
Eğer ESP kartlarından birisini ilk defa kullanacaksanız yukarıdaki yazımdaki aşamaları sırasıyla inceleyip kartınızda basit bir blink programı çalıştırmanızı tavsiye ederim. Bu sayede kartınızı hızlı bir şekilde test edip yazılım yüklenebildiğini görmüş olursunuz.
3. Adım: Yazılım Kısmı.
kodu incelerken kodun en ama en basite indirgenmiş halini teker teker açıklayıp hangi kodun ne işe yaradığından bahsedeceğim. Bu sayede ezbere bir sistem çalıştırmaktansa hangi kodun ne işe yaradığını biliyor olacağız. Bana sorarsanız bunu bilmek önemli. Çünkü her yeni bir proje yaptığımızda önceki bilgilerimizi kullanıp üstüne koyarak ilerliyor, hataları bu sayede görüp sorunları olabildiğince hızlı çözüyoruz. Şimdi gelin projenin kodlarını incelemeye başlayalım.
Proje iki ayrı koddan oluşuyor olacak. Birisi Transmitter Device veya Master Device ( İleten cihaz veya Master Cihaz ), diğer cihaz ise Receiver device veya Slave Device ( Alıcı Cihaz veya Köle Cihaz ). Bu isimler karmaşık geliyorsa olaya sadece ileten ve dinleyen cihaz gözüyle bakabilirsiniz. Kod ESP-NOW protokolünün çalışması için minimum gereken koda sahiptir.
Daha fazla bilgiye Espressif API referans sayfasından ulaşabilirsiniz. Kodumuzu incelerken şu kod şu işlevi gerçekleştirir dediğimizde hepsi aşağıdaki sitede belgelenmiştir. Belgeyi incelediğimizde 18 adet işlev var gibi görünüyor ve gerçekten fazla değil.
https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-reference/network/esp_now.html
Verici Kodu
#include <esp_now.h>
#include <WiFi.h>
//kanal belirliyoruz alıcı ve verici aynı kanalda olmalı
#defie CHANNEL 1
esp_now_peer_info_t slave;
Kodumuzun başlangıcına bakacak olursak önce kütüphanelerimizi tanımlamışız. Daha sonrasında ise ESP cihazlarımızın konuşacakları kanalı “ #defie CHANNEL 1 ” kodu ile 1. kanala atıyorum. Aslında varsayılan olarak 1. kanal olarak tanımlanmıştır ancak biz bu kısımda kanalımızı belirleyeceğiz.
Burada bir diğer dikkat etmemiz gereken kısım ise MAC adresidir. Eğer cihazınız verici ( Transmitter ) konumunda ise alıcı hakkında bazı bilgilere sahip olması gerekir. Özellikle bilmemiz gereken bilgi alıcının MAC adresidir. MAC adresi donanıma atanmış benzeri olmayan, her cihazın farklı olduğu benzersiz bir ağ adresidir. Bu bizim belirlediğimiz bir şey değil zaten donanımda olan bir şeydir. Bu MAC adresi vericiyle birlikte kaydedilir. Kodumuzdaki “ esp_now_peer_info_t ” alıcı cihazın MAC adresinin eşlenildiği kısımdır. “ esp_now_peer_info_t ” veri türünde “ slave ” adlı bir değişken oluştururuz.
Espressif firmasının belgelerini incelersek eğer aslında bu kodun bir Structures ( Yapı ) olduğunu da anlarız. ( Fotoğraf 1.0 ) Ancak fotoğraftaki peer_addr alıcının MAC adresini bu yapıya kaydettiğimiz kısımdır. Kodun devamına bakacak olursak;
uint8_t data=0;
void ()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
esp_now_init();
esp_now_register_send_cb(OnDataSent);
ScanForSlave();
esp_now_add_peer(&slave);
}
Kodumuzun bu kısmında ise göndereceğimiz int formunda bir data değişkeni tanımlıyoruz. formatın int ( integer, sayısal ) formunda olması zorunlu değil. Sensör verilerini içerisinde tuttuğumuz bir dizi veya başka bir veri türü olabilir. Buradaki tek kıstas verinin 250 byte boyutundan düşük olması gerekmesi.
Sonrasında ise “ Serial.begin(115200); ” kodu ile seri monitörümüzü kartımızda 115200 baudrate hızıyla haberleşebileceği şekilde ayarlıyoruz. ESP-NOW için gerekli değil ama bazı verileri bilgisayar ekranımızda görmek istiyoruz.
Vericinin modunu “ Wifi.mode(WIFI_STA); ” kodu sayesinde istasyon moduna alıyoruz. Sonrasında ise ESP-NOW protokolünü başlatacak olan “ esp_now_init(); ” fonksiyonunu çağırıyoruz.
Sonrasında ise “ esp_now_register_send_cb(OnDataSent); ” fonksiyonu ile bir Callback Function ( Geri arama fonksiyonu ) başlatmamız ve ona bir isim vermemiz gerekiyor. Biz OnDataSent ismini verdik. Daha sonra OnDataSent fonksiyonunu ayrıca tanımlamamız ve ne iş yapacağını fonksiyonun içerisine yazmamız gerekir. Bu kısma sonradan tekrar değineceğiz. Şimdi Callback fonksiyonumuzu inceleyelim.
//CallBack fonksiyonu
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status ) {
Serial.print("Datayı gönderdim->");
Serial.println(data);
}
CallBack fonksiyonu oluşturduğumuzda 2 parametre gerekecek, bir EROR( hata ) durum kodu ve MAC adresi işaretçisi.
Sonrasında önceki kod satırındaki “ ScanForSlave(); ” fonksiyonunu anlamamız gerek. Bu fonksiyon açık ara koddaki en karmaşık fonksiyon. Şimdi fonksiyonu inceleyelim.
ScanForSlave() Fonksiyonu
void ScanForSlave()
{
int16_t scanResults = WiFi.scanNetworks();
for (int i = 0; i < scanResults; ++i)
{
String SSID = WiFi.SSID(i);
String BSSIDstr = WiFi.BSSIDstr(i);
if (SSID.indexOf("RX") == 0)
{
int mac[6];
if ( 6 == sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5] ) ) {
for (int ii = 0; ii < 6; ++ii ) {
slave.peer_addr[ii] = (uint8_t) mac[ii];
}
}
slave.channel = CHANNEL;
slave.encrypt = 0;
break;
}
}
}
Bu kodun çalışma mantığını derinlemesine incelemeyeceğiz ama temel olarak ne yaptığından bahsedeceğim. Yaptığı şey aslında WiFi ismi RX ile başlayan cihazları bulmak. Sonrasında onların MAC adreslerini almak. İstersek sabit kullanacağımız cihazların MAC adreslerine ulaşıp kodumuzun içerisine direk de yazabiliriz. Ancak bu yolla yeni bir cihaz eklemek istediğimizde sadece WiFi ismini RX ile başlayan bir isim koymamız yeterli. Master cihaz çevreyi tarayıp otomatik o cihazın MAC adresini alacaktır.
Alt Yazı
Eğer bu tarama işlemindense direk slave ( alıcı ) cihazımızın MAC adresini kodumuzun içine sabitlemek istiyorsak tek yapmamız gereken şey ” WiFi.macAddress(); “ kodunu alıcı cihazımızda çalıştırıp sonucunu seri monitöre yazdırmaktır. Bu sayede alıcı cihazımızın MAC adresini elde etmiş oluruz. Sonrasında o adresi “ esp_now_peer_info_t slave; ” kodunda slave değişkenine kaydedip yazarsak verici cihazımıza alıcı cihazın MAC adresini kaydetmiş oluruz.
Sonrasında “ esp_now_add_peer(&slave); ” koduna bakacak olursak burada da elde edip slave değişkenine kaydettiğimiz tüm alıcı bilgilerini bu komut ile ESP ağımızın içerisine entegre ediyoruz.
void loop(){
esp_now_send(slave.peer_addr, &data, sizeof(data));
data++;
delay(1000);
}
“ esp_now_send ” fonksiyonu gerçekten göndermek istediğimiz verileri alıcıya gönderir. Bu yüzden ona “ slave.peer_addr ” kodu ile MAC adresini ve “ &data, sizeof(data) ” kodu ile de göndereceğimiz datayı ve datanın boyutunu vermemiz gerekir. Sonrasında “ data++; ” komutu ile data verisini “ delay( 1000 ); “ komutu ile bir bir arttıracağız.
Verici Kodunun Tamamı
#include <esp_now.h>
#include <WiFi.h>
//kanal belirliyoruz alıcı ve verici aynı kanalda olmalı
#define CHANNEL 1
//Alıcının MAC adresini esp_now_peer_info yapısına tanıttığımız kod
esp_now_peer_info_t slave;
//göndermek istediğimiz veri
uint8_t data=0;
void setup ()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
esp_now_init();
esp_now_register_send_cb(OnDataSent);
ScanForSlave();
esp_now_add_peer(&slave);
}
void loop(){
esp_now_send(slave.peer_addr, &data, sizeof(data));
data++;
delay(1000);
}
//CallBack fonksiyonu
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status ) {
Serial.print("Datayı gönderdim->");
Serial.println(data);
}
void ScanForSlave()
{
int16_t scanResults = WiFi.scanNetworks(); // Scan only on one channel
for (int i = 0; i < scanResults; ++i)
{
// Print SSID and RSSI for each device found
String SSID = WiFi.SSID(i);
String BSSIDstr = WiFi.BSSIDstr(i);
// Check if the current device starts with `Slave`
if (SSID.indexOf("RX") == 0)
{
int mac[6];
if ( 6 == sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5] ) ) {
for (int ii = 0; ii < 6; ++ii ) {
slave.peer_addr[ii] = (uint8_t) mac[ii];
}
}
slave.channel = CHANNEL; // pick a channel
slave.encrypt = 0; // no encryption
break;
}
}
}
Evet. Master kodumuzun sonuna geldik. Çok şey oluyormuş gibi duruyor ama gördüğünüz üzere anlaşılmayacak bir kod değil. Şimdi alıcı kodunu inceleye başlayalım.
Alıcı Kodu
Alıcı kodunun tamamı
#include <esp_now.h>
#include <WiFi.h>
#define CHANNEL 1
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_AP);
WiFi.softAP("RX_1","RX_1_Password",CHANNEL, 0);
esp_now_init();
esp_now_register_recv_cb(OnDataRecv);
}
void loop() {
}
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len){
Serial.print("Bir veri aldım->");
Serial.println(*data);
}
İşte alıcı kodumuz. Ne kadar kısa değil mi? Hepsi bu kadar. Kodumuzun başlangıcında tıpkı vericideki gibi sonrasında alıcımızı vericimizdeki gibi “ #define CHANNEL 1 ” kodu ile aynı kanada ayarlıyoruz.
Sonrasında Setup fonksiyonundaki “ WiFi.mode(WIFI_AP); ” fonksiyonu ile alıcımızı AP moduna alıyoruz.
Sonrasında “ WiFi.softAP(“RX_1″,”RX_1_Password”,CHANNEL 0); ” kodu ile AP modunu yapılandırıyoruz. Kodumuzun içerisindeki “RX_1” kısmını vericimizin arayacağı bir şeye ayarlamamız gerekiyor. Hatırlarsanız vericimizdeki “ ScanForSlave() ” kodu sayesinde alıcıların MAC adresini almadan sadece WiFi isimlerinin ilk karakterleri ile alıcılarımızın MAC adreslerini elde edebiliyorduk. Verici baş harfleri RX olan isimleri arayacak. Biz de alıcımızın ismini RX_1 koyduk. Bu sayede verici alıcıyı kolay bir şekilde bulabiliyor.
Sonrasında ise “ esp_now_init(); ” kodu ile ESP-NOW protokolünü başlatıyoruz.
Sonrasında ise “ esp_now_register_recv_cb(OnDataRecv) ” fonksiyonu ile bir Receive Callback ( alıcı geri arama ) fonksiyonu başlatıyoruz. Bu kod alıcı her vericiden veri aldığında çalışacaktır. Bu yüzden OnDataReceive fonksiyonuna bir göz atalım.
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len){
Serial.print("Bir veri aldım->")
Serial.print(*data);
}
OnDataRecv fonksiyonuna baktığımızda üç parametre görmekteyiz. İlki “ const uint8_t*mac_addr ” kodu. Bu kod sayesinde fonksiyona alıcımızın MAC adresini tanımlıyoruz. Sonrasında bir data değişkeni tanımlayıp içerisine gelen verilerimizi yazdırıyoruz.
Evet, Kod kısmını bitirdik. Şimdi ise test edelim.
4. Test Kısmı
Bir cihazımızı alıcı, diğer cihazımızı verici olarak seçiyoruz. Daha sonrasında yazdığımız alıcı kodunu seçtiğimiz alıcı cihazına, verici kodunu ise seçtiğimiz verici cihazına yüklüyoruz.
Daha sonra alıcı kodunu ise alıcı cihaza yüklüyoruz. ( Fotoğraf 1.1 )
Sonrasında iki ESP32 kartına da Reset attıktan sonra ayrı Arduino IDE programlarında kartları seri monitöre bağlıyoruz. ( Fotoğraf 1.3 )
Ve evet ! Gördüğünüz gibi verici cihazımız saniyede bir data verisini gönderirken alıcı cihazımız ise o veriyi alıyor. Bugünkü yazımızda ESP-NOW protokolünü inceledik ve kullanabileceğimiz minimum gereklilikteki kodları kullanarak basitçe ESP-NOW arayüzünü inceledik. Bir sonraki yazımızda bu kodumuzu geliştirerek basit bir haberleşme projesi gerçekleştireceğiz. Aşağıdaki linkten o yazıma ulaşabilirsiniz.
2 yorum
dosum eli,ne sağlık harika anlatmışsın. türkçe daha iyi anlatanı görmedim henüz. tek verici birden fazla verici olması durumunda naısl bir yol izlenebilir. rgb uygulamasındaki gibi1. buton 1.cihaz 2. buton 2 cihaz gibi
Selam Faruk. Değerli yorumun için teşekkür ederim iltifatın beni çok mutlu etti. ESP-NOW teknolojisinde tüm modüller zaten senkron bir şekilde haberleşebildiği için bütün modüller hem verici hem de alıcı olabilmektedirler. Detaylı bir araştırma ile kolaylıkla bu konuda yapılmış bir çok projeye ulaşabilirsin. Yapılmış projelerdeki kodda gönderilen ve alınan verileri basit if-else bloklarına koyup istenilen işi yapabilirsin. ESP32 güçlü bir işlemciye sahip yani istediğin kadar if-else bloğunu saniyede milyonlarca kez taratıp senkron çalışabilen bir kod tasarlayabilirsin. Umarım yorumum sana yardımcı olur. Günün güzel olsun.