Raspberry Pi ve ESP8266 ile MQTT Smart Home

Merhaba Arkadaşlar;

Bu yazımda sizlere MQTT protokolü ile Smart home nasıl yapılır ve kendi MQTT broker ımızı nasıl yapılır anlatacağım. İlk önce MQTT nedir onun hakkında kısa bir bilgi vereyim.

MQTT(Message Queuing Telemetry Transport) protokolü, internette yaygın olarak kullanılan makinalar arası (M2M) mesaj tabanlı bir protokoldür. Lightweight oluşu ve düşük kaynak tüketmesiyle Internet of Things(IoT) ekosisteminde benimsenmiştir. Hemen hemen tüm IoT bulut platformları akıllı nesnelerden veri gönderip almak için MQTT protokolünü desteklemektedir.

Bu protokol, istek(request)-yanıt(response) yapısına dayalı HTTP’ye karşıt olarak yayın(publish)-abone(subscriber) yapısında TCP/IP bağlantısı kurulur. TCP/IP protokolünün yazılabildiği Linux, Windows, Android, iOS, MacOS işletim sistemlerinde çalışır.

MQTT Mesaj Yapısı
MQTT protokolü yayıncı-abone yapısında bir mesaj yayınlayan bir client (yayıncı) mesajı alan diğer clientlara ayıracaktır (aboneler). Ayrıca, MQTT asenkron protokoldür, bu da mesajı beklerken clientı engellemediği anlamına gelir. HTTP protokolünün aksine, esas olarak eşzamanlı bir protokoldür. MQTT protokolünün bir başka özelliği, istemcinin (abone) ve yayıncının aynı anda bağlı olmasını gerektirmemesidir.

MQTT Yayıncı-Abone Mimarisi
MQTT’deki kilit unsur MQTT brokerıdir. MQTT brokerın asıl görevi, clientlara (abonelere) mesajlar göndermektir. Yani yayıncıdan mesajlar alır ve bu mesajları abonelere gönderir. Mesaj gönderirken, MQTT broker mesajı alacak olan clientları filtrelemek için konuyu(topic) kullanır. Konu bir dizedir ve konu seviyeleri yaratan konuları birleştirmek mümkündür.

Konu(topic) bir yayıncıyı abonelerine bağlayan sanal bir kanala benzer. Bu konu MQTT brokerı tarafından yönetilmektedir. Bu sanal kanal sayesinde, yayıncı abonelerden ayrılmıştır ve istemcilerin(yayıncılar veya aboneler) birbirlerini tanıması gerekmemektedir. Bu yapısı gereği bu protokolü mesaj üreticisine(yayıncı) ve mesaj tüketicisine(abone) doğrudan bağımlılık olmadan çok ölçeklenebilir hale getirir.

MQTT mimarisi aşağıdaki şekildedir:

Nasıl çalıştığını inceledikten sonra gelelim asıl amacımıza, burada amaç ücretli yada kısıtlanmış MQTT sitelerini kullanmak yerine kendi MQTT Broker sistemini oluşturmak. Bunun en iyi ve hızlı çözüm Raspberr Pi kullanmaktır. Ben Pi3B+ kullandım siz isterseniz ZeroW da kullanabilirsiniz. Gelelim Kurulumuna:

ilk önce Pi yi güncelleyelim

sudo apt-get update
sudo apt-get upgrade

Daha sonra mosquitto paketini kuracağız.

sudo apt-get install mosquitto
sudo apt-get install mosquitto-clients

Paketi yüklemeyi tamamladığımızda sistemi yapılandırmamız gerekecek.  Mosquitto broker’ın yapılandırma dosyası /etc/mosquitto/mosquitto.conf adresinde bulunur, bunu metin editörümüzde açacağız.

sudo nano /etc/mosquitto/mosquitto.conf

Bu dosyanın en altında aşağıdaki satırı göreceksiniz.

include_dir /etc/mosquitto/conf.d

Bu satırı silip aşağıdaki satırları ekleyin.

allow_anonymous false
password_file /etc/mosquitto/pwfile
listener 1883

Dosyayı kaydedip kapatın.

Daha sonra kullanıcı adı ve şifre belirleyeceğiz.

sudo mosquitto_passwd -c /etc/mosquitto/pwfile <username>

Komutu çalıştırdığınızda size şifre soracaktır onuda belirleyin.

Son olarak pi yi yeniden  başlatalım.

sudo reboot

Buraya kadar MQTT broker programını kurmuş olduk. Eğer local Ağda çalışacaksanız Pi nin adresini kullanacaksınız. Dışarıdan da mesaj almak istiyorsanız Pi ye 1883 portundan yönlendirme yapmalısınız.

Şimdi gelelim ESP8266 ile yayın ve abone nasıl yapılır onu inceleyelim. Bunun için ben 2 tane modül üzerinden gittim, siz burada mantığı kavrayıp istediğimiz modül yada sensörü sisteme bağlayabilirsiniz.

Sık kullanmak için role ve sıcaklık sensörü kullandım. 2 Modülün programını ayrı ayrı anlatacağım.

Role Kontrol:

Burada amaç bir topic i dinleyip gelen mesaja göre rolenin konumunu değiştireceğiz. Burada ESP miz abone(subscriber) olarak çalışacak ve belirlediğimiz topic de mesaj değişikliği olduğunda bize bir callback fonksiyon döndürecek. Sonra biz bu fonksiyonun içinde mesajı yorumlayıp çıkışı High yada Low yapacağız.

Role modül programı:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

/**********Wifi Setup*********/
const char* ssid =  "XXXXX";
const char* password =  "xxxxx";

/**********MQTT Setup*********/
const char* mqttServer = "x.x.x.x";
const int mqttPort = 1883;
const char* mqttUser = "xxxxx";
const char* mqttPassword = "xxxxx";
const char* mqttClientID = "ESP8266ClientID00001";

/**********Hardware Setup*********/
#define Role 0 // GPIO0 -> D3


const String onString = "on";
const String offString = "off";

WiFiClient espClient;
PubSubClient client(espClient);

bool Wifi_connect();
bool Client_connect();
void callback(char* topic, byte* payload, unsigned int length);

void setup() 
{
  Serial.begin(115200);
  delay(10);
  pinMode(Role,OUTPUT);
  digitalWrite(Role,HIGH); //role off

  while(!Wifi_connect()){
  }
  while(!Client_connect()){
  }
}

 
void loop() 
{
  //wifi baglanti kontrol edilir
  if(WiFi.status()==WL_CONNECTION_LOST)
  {
    Serial.println("Wifi baglantisi koptu");
    while(!Wifi_connect()){
    } 
  }

  //MQTT baglanti kontrol edilir
  if (!client.connected())
  {
    Serial.println("MQTT baglantisi koptu");
    while(!Client_connect()){
    }
  }

  
  client.loop();

  delay(100);
}

//mesaj geldiginde
void callback(char* topic, byte* payload, unsigned int length) 
{
  String message = "";
  for (int i = 0; i < length; i++)
  {
    message = message + (char)payload[i];
  }
  
  if(message == onString)
  {
    digitalWrite(Role,LOW); //role on
    Serial.println("Role ON");
  }
  else if(message == offString)
  {
    digitalWrite(Role,HIGH); //role off
    Serial.println("Role OFF");
  }
  
}

//MQTT connect
bool Client_connect()
{
  bool retn;
  client.setServer(mqttServer, mqttPort);
  client.setCallback(callback);
    

  Serial.println("Connecting to MQTT...");
  if (client.connect(mqttClientID, mqttUser, mqttPassword ))
  {
    Serial.println("connected");
    client.subscribe("test/role1");
    retn = true;  
  } 
  else 
  {
    Serial.print("failed with state ");
    retn = false;
  }
  delay(100);
}

//wifi connect
bool Wifi_connect()
{
  bool retn;
  Serial.print("SSID:");
  Serial.print(ssid); 
  Serial.print("\r\n");
  WiFi.begin(ssid, password);  
  Serial.print("Baglaniyor... ");
 
  //try to connect for 10 seconds
  int i = 10;
  while(WiFi.status() != WL_CONNECTED && i >=0) 
  {
    delay(750);
    Serial.print(i);
    Serial.print(", ");
    i--;
  }
 
  //print connection result
  if(WiFi.status() == WL_CONNECTED)
  {
    Serial.print("Baglandi.\r\n"); 
    Serial.print("NodeMCU ip address: "); 
    Serial.println(WiFi.localIP());
    retn = true;
  }
  else 
  {
    Serial.println("Baglanti hata !!!\r\n");
    retn = false;
  }
 
  return retn;
}

ilk olarak programın en başındaki ayarları düzenlememiz gerekiyor;

  • Hangi Wifi ağına bağlanacaksa SSID ve şifre girilir.
/**********Wifi Setup*********/
const char* ssid =  "XXXXX";
const char* password =  "xxxxx";
  • MQTT ayarları yapılır. Burada dikkat edilmesi gereken MQTT broker a verdiğiniz şifre ve kullanıcı adını doğru girmelisiniz. Bir de mqttClientID kesinlikle diğer bağlanacak cihazlarla aynı olmaması gerekiyor. (Broker tarafında bağlantı kopabilir.)
/**********MQTT Setup*********/
const char* mqttServer = "x.x.x.x";
const int mqttPort = 1883;
const char* mqttUser = "xxxxx";
const char* mqttPassword = "xxxxx";
const char* mqttClientID = "ESP8266ClientID00001";
  • Son olarak rolenin bağlı olduğu pin ayarlanır
/**********Hardware Setup*********/
#define Role 0 // GPIO0 -> D3

Sonra programın çalışması; ilk olarak wifi ağına bağlanacak eğer bağlantı gerçekleşti ise MQTT bağlantısına geçecek. MQTT bağlantısı da tamamlandıktan sonra subscribe ı belirteceğiz. Ben burada subscribe topic olarak test/role1 tanımladım siz istediğiniz gibi değiştirebilirsiniz.

client.subscribe("test/role1");

MQTT ye bağlandıktan sonra, belirlediğimiz topic e mesaj geldiğinde gideceği fonksiyonu belirtiriz.

client.setCallback(callback);

Artık mesaj geldiğinde bu fonksiyonu girecektir. Burada bizim belirlediğimiz mesaj ile role yi açıp kapatacağız. Ben burada on ve off mesajlarını belirledim.

//mesaj geldiginde
void callback(char* topic, byte* payload, unsigned int length) 
{
  String message = "";
  for (int i = 0; i < length; i++)
  {
    message = message + (char)payload[i];
  }
  
  if(message == onString)
  {
    digitalWrite(Role,LOW); //role on
    Serial.println("Role ON");
  }
  else if(message == offString)
  {
    digitalWrite(Role,HIGH); //role off
    Serial.println("Role OFF");
  }
}

Role modülü bu şekilde çalışacak. Kısaca DHT11 modülünden bahsedeyim

DHT11 Modül Programı:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include "DHT.h"

/**********Wifi Setup*********/
const char* ssid =  "XXXXX";
const char* password =  "xxxxx";

/**********MQTT Setup*********/
const char* mqttServer = "x.x.x.x";
const int mqttPort = 1883;
const char* mqttUser = "xxxxx";
const char* mqttPassword = "xxxxx";
const char* mqttClientID = "ESP8266ClientID00002";

/**********Hardware Setup*********/
#define DHTPIN 2 
#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
//#define DHTTYPE DHT21 // DHT 21 (AM2301)

/**********DHT Topic Setup*********/
#define humidity_topic "sensor/hum"
#define temperature_celsius_topic "sensor/tempc"
#define temperature_fahrenheit_topic "sensor/tempf"


DHT dht(DHTPIN, DHTTYPE);
WiFiClient espClient;
PubSubClient client(espClient);

bool Wifi_connect();
bool Client_connect();
 
void setup() 
{
  Serial.begin(115200);
  delay(10);
  pinMode(DHTPIN, INPUT);
  dht.begin();
  
  while(!Wifi_connect()){
  }
  while(!Client_connect()){
  }
}

 
void loop() 
{
  //wifi baglanti kontrol edilir
  if(WiFi.status()==WL_CONNECTION_LOST)
  {
    Serial.println("Balanti koptu");
    while(!Wifi_connect()){
    } 
  }
  
  //MQTT baglanti kontrol edilir
  if (!client.connected())
  {
    Serial.println("MQTT baglantisi koptu");
    while(!Client_connect()){
    }
  }

  client.loop();
  
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  float f = dht.readTemperature(true);

  if (isnan(h) || isnan(t) || isnan(f))
  {
    //okuma hatalı ise gonderme yapma
    Serial.println("Failed to read from DHT sensor!");
  }
  else
  {
    //okuma doğru ise yayınla
    client.publish(temperature_celsius_topic, String(t).c_str(), true);
    client.publish(temperature_fahrenheit_topic, String(f).c_str(), true);
    client.publish(humidity_topic, String(h).c_str(), true);
  } 
  delay(5000);
}


//MQTT connect
bool Client_connect()
{
  bool retn;
  client.setServer(mqttServer, mqttPort);

  Serial.println("Connecting to MQTT...");
  if (client.connect(mqttClientID, mqttUser, mqttPassword ))
  {
    Serial.println("connected");
    retn = true;  
  } 
  else 
  {
    Serial.print("failed with state ");
    retn = false;
  }
  delay(100);
}

//wifi connect
bool Wifi_connect()
{
  bool retn;
  Serial.print("SSID:");
  Serial.print(ssid); 
  Serial.print("\r\n");
  WiFi.begin(ssid, password);  
  Serial.print("Baglaniyor... ");
 
  //try to connect for 10 seconds
  int i = 10;
  while(WiFi.status() != WL_CONNECTED && i >=0) 
  {
    delay(750);
    Serial.print(i);
    Serial.print(", ");
    i--;
  }
 
  //print connection result
  if(WiFi.status() == WL_CONNECTED)
  {
    Serial.print("Baglandi.\r\n"); 
    Serial.print("NodeMCU ip address: "); 
    Serial.println(WiFi.localIP());
    retn = true;
  }
  else 
  {
    Serial.println("Baglanti hata !!!\r\n");
    retn = false;
  }
 
  return retn;
}

Yukarıdaki Role modül programı ile aynı sayılır ama burda mesaj almayacağız tam tersi belirlediğimiz topic e mesaj göndereceğiz. Programı incelediğimizde 3 değer sensörden okunur ve yayın yapılır.

client.publish(temperature_celsius_topic, String(t).c_str(), true);
client.publish(temperature_fahrenheit_topic, String(f).c_str(), true);
client.publish(humidity_topic, String(h).c_str(), true);

Kullanılan topicleri ise en başta tanımladım siz burada istediğiniz topic adını verebilirsiniz.

/**********DHT Topic Setup*********/
#define humidity_topic "sensor/hum"
#define temperature_celsius_topic "sensor/tempc"
#define temperature_fahrenheit_topic "sensor/tempf"

5 sn de bir 3 değeri yayınlıyoruz.

Loop kısmında dikkat ettiyseniz wifi ve mqtt bağlantılarını kontrol ediyorum eğer bağlantı kesilme durumuz var ise tekrar baştan bağlantı kurmayı deniyor.

  //wifi baglanti kontrol edilir
  if(WiFi.status()==WL_CONNECTION_LOST)
  {
    Serial.println("Wifi baglantisi koptu");
    while(!Wifi_connect()){
    } 
  }

  //MQTT baglanti kontrol edilir
  if (!client.connected())
  {
    Serial.println("MQTT baglantisi koptu");
    while(!Client_connect()){
    }
  }

Buraya kadar ESP ile yayın yaptık yada mesaj aldık. Siz burada mantığı çözüp farklı modüller yada sensörler kullanıp sisteme yenisini ekleyebilirsiniz.

Şimdi gelelim bu sistemi uzaktan takip yada kontrol etmeye. Bunun için Google Play de mqtt yazıp arattığınızda karşınıza bir çok uygulama geliyor ama benim beğendiğim ve tavsiyem MQTT Dashboard uygulamasıdır.

https://play.google.com/store/apps/details?id=com.app.vetru.mqttdashboard&hl=tr

Programı kullanmak oldukça basit, MQTT broker ı ekleyip ardından sayfanıza istediğiniz nesneleri ekleyebilirsiniz, eklerken topic adlarına dikkat edin esp yazılımındaki ile aynı olsun. Programın güzel özellikleri var mesela istediğiniz topic e mesaj geldiğinde bildirim geliyor yada eklediğiniz nesnelere icon resmi seçebiliyorsunuz.

Bir başka uygulamada görüşmek üzere kolay gelsin.

MQTT Kaynak: http://devnot.com/2017/mqtt-nedir-nasil-bir-mimaride-calisir

“Raspberry Pi ve ESP8266 ile MQTT Smart Home” için 6 yorum

  1. Kardeşim yaklaşık 2005 yılından bu yana senin devrelerin ve yazılımlarını takip ediyorum hatta lcd ekranlı şifreli ev alarmı devren vardı onu evime yaptım halen kullanıyorum başarılarının devamını diliyorum seni takip etmeye devam ediyorum allah yolunu açık etsin.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.