Bu yazıda IOT projelerinde sıklıkla kullanılan MQTT protokolüne ve ESP8266 modülü ile nasıl kullanılabileceğine değineceğim. Öncelikle MQTT nedir ve nasıl çalışır bir bakalım.
MQTT (Message Queuing Telemetry Transport)
IOT uygulamaları için mükemmel bir çözüm olarak görülen MQTT basit bir haberleşme protokolüdür. MQTT internete bağlı olan bir cihazın çıkışlarını kontrol etmek için veri göndermeye veya sensor vb. girişlerden ölçülen verileri diğer cihazlara göndermesine olanak sağlar. Bu nedenle birden fazla cihaz arasında iletişim kurmayı kolaylaştırır. Bu yüzden M2M(machine to machine) ve IOT(internet of things) uygulamaları için tercih sebebidir.
MQTT Kavramları
- Publish/Subscribe
- Message
- Topic
- Broker
İlk değineceğim kavramlar publish ve subscribe kavramlarıdır.
Publish; Bir cihazın yayın yapması yani veri göndermesidir.
Subscribe; Bir cihazın abone olması anlamına gelir. Cihazların veri alabilmesi için kullanılır. Kısaca bir cihaz mesaj gönderecek ise publish yani yayın yapar. Eğer komut alacak ise subscribe yani abone olur.
Mesaj; Cihazlar arasında gönderilen verilerdir.
Topic; Mesajların kimden geldiği veya hangi cihazlara iletileceği topiclere göre belirlenir.
Broker; Tüm bu haberleşmeyi yöneten birimdir. Öncelikle tüm mesajları almak ve bu mesajların hangi cihazları ilgilendirdiğini belirlemek ve ilgili cihazlara yayın(publish) yapmaktan sorumludur. Broker için mosquitto vb. belirli yazılımlar bulunmaktadır. Daha iyi anlayabilmek için aşağıdaki görselden yaralanabiliriz.
Yukarıdaki görselde görüldüğü gibi üç farklı cihaz brokera bağlanmıştır. Burada Broker bir bilgisayarda veya bulut sisteminde çalışan bir yazılım olabilir(örneğin;Mosquitto ve CloudMQTT). Görselde telefon ve bilgisayar “temperature” isimli topic’e abone olmuştur. Sensör ise “temperature” topic’ine yayın yapmaktadır. Burada sensörden kasıt içerisinde mikrodenetleyici barındıran ve internete bağlanabilen bir donanımdır. Sensör mesajı “temperature” topic adı ile broker’a gönderir. Broker bu mesajı aldıktan sonra “temperature” topic’ine abone olan bir cihaz olup olmadığına bakar. Eğer “temperature” topic’ine abone olmuş cihazlar var ise bu cihazlara sensörden aldığı mesajı aynen iletir.
Broker Yazılımı ve Broker’a Bağlanma
Broker’ın bir bilgisayarda veya bulut sisteminde çalışan yazılımlar olduğunu söylemiştim. Ben ücretsiz olan Mosquitto yazılımı kullanacağım. Mosquitto komut satırından çalıştırılan bir yazılım. Yani mosquitto ile broker açabilmek için cmd ekranından bir takım komutlar yazmamız gereklidir.
Bu komutlardan sonra Broker’ı açmış oluyoruz. Her seferinde tek tek bu komutları yazmamak için şöyle bir yöntem uyguluyorum. Yeni bir metin belgesi oluşturup içine yukarıdaki resimdeki komutların aynısını yazıyorum ve metin belgesinin uzantısını .bat olarak değiştiriyorum. Böylece oluşturduğum .bat uzantılı dosyaya tıklayınca broker otomatik olarak açılıyor.
Broker için yazdığım .bat uzantılı dosya(son satır enter karakteri ile bitiyor );
1 2 3 | cd\ cd C:\Program Files\mosquitto .\mosquitto.exe -v |
Publisher.bat dosyasının içeriği;
1 2 3 | cd\ cd C:\Program Files\mosquitto .\mosquitto_pub.exe -h "192.168.1.103" -t IOT -m "LED_ON" |
Burada dikkat edilmesi gereken bir kaç nokta var. publisher.bat dosyasının içerisindeki “192.168.1.103” benim brokerı çalıştırdığım bilgisayarın IP’si. “IOT” ise benim rastgele isim verdiğim bir topic adı. Bu Ahmet de olabilir Mehmet de size bağlı. En sondaki “LED_ON” ise IOT topic’ine gönderilecek mesajdır.
Subscriber.bat dosyasının içeriği;
1 2 3 | cd\ cd C:\Program Files\mosquitto .\mosquitto_sub.exe -h "192.168.1.103" -t IOT |
Burada da aynı bilgisayardan IOT topic’ine subscribe yani abone olduk. Bu komutlarda mosquitto programını nereye kurduysanız (C veya D) ona göre düzenlemeniz gerekmektedir. Benim bilgisayarımda mosquitto C:\Program Files altında kurulu olduğu için .bat uzantılı dosyalar ona göre düzenlenmiştir.
MQTT Paket Formatı
ESP ile MQTT üzerinden bir broker’a TCP/IP ile belirli hexadecimal paketler gönderilerek bağlanılır ve veri alışverişi yapılır. Başlangıç olarak Broker’a bağlanma paketi , Subscribe paketi ve Publish paketinden bahsedeceğim. MQTT yalnızca bu üç paket ile sınırlı değildir. Unsubscribe,Pinqrequest gibi farklı paketler de vardır. Bu paketler hakkında daha fazla bilgi için mqtt.org adresini ziyaret edebilirsiniz.
Broker’a Bağlanma Paketi
Broker’a bağlanabilmek için yukarıdaki paketi TCP/IP üzerinden servera göndermemiz gerekir. Burada her bir kutucuk 8 bitlik hexadecimal sayıya karşılık gelmektedir.
Gönderilecek ilk iki byte “Fixed Header” olarak isimlendirilmektedir. İlk byte kontrol paket tipidir. Connect için 0x10 ,Subscribe için 0x82, Publish için 0x30 olarak ayarlanmalıdır. İkinci byte ise bundan sonra kaç byte veri göndereceğimizi yazdığımız byte’dır ve “remaining length” olarak isimlendirilir. Yukarıdaki resimde dikkat edilirse remain length’ten sonra 17 byte’lık bir veri daha paket içerisinde bulunmaktadır. Decimal 17 sayısı hexadecimal 0x11 değerine eşit olduğu için Remain Length’e 0x11 yazdık. Bu byte sizin belirleyeceğiniz “Client ID” ye göre değişecektir.
Protocol Length(16bit) ve ardından gelen Protokol adı MQTT. Burada protokol ismi 4 karakter olduğu için “Protocol Length” 0x00 ve 0x04 oldu. MQTT kutucuğunun altında yazan değerler bu harflerin ASCII tablosuna karşılık gelen değerlerdir.
Level byte mqtt.org sitesinde 0x04 olmalı dediği için öyle yazdım. Bunun neden 4 olduğu ile ilgili bir açıklama bulamadım.
Flag byte ile bağlantının şifreli mi şifresiz mi yapılacağı vb. ayarlamalar yapılabilir.
Şifreli bir bağlantı yapmak güvenlik açısından önemlidir. Ben şifresiz bağlanmayı deneyeceğim. O yüzden burada sadece “Clean Session” bitini aktif ediyorum. Bu yüzden Flag byte = 0x02 oldu.
Keep Alive ; Broker’a bağlandıktan sonra eğer publish veya farklı bir işlem yapılmaz ise broker bağlantınızı belli bir süre sonra otomatik olarak kesiyor. Bu süreyi ise 2 byte’lık “keep alive” ile ayarlıyoruz. Buraya yazdığımız değer saniye cinsindendir. Ben bunu 60 saniye olarak ayarladım araştırmalarıma göre de genellikle 60 saniye olarak ayarlanmış. Eğer brokera bağlandıktan sonra 30 saniye de bir publish yapıyorsanız broker sizin bağlantınızı kesmeyecektir. Publish yapmadan broker bağlantınızın sürekli aktif kalmasını istiyorsanız 40 sn veya 50 saniye aralıklarla “Ping Request” paketini yollayabilirsiniz.Böylece her ping gönderdiğinizde broker sizin hala aktif olduğunuzu bilecektir.
Son olarak ise “Client ID” uzunluğunu ve adını göndermemiz gereklidir. Benim Client ID’im “Topuz” olduğu için ve 5 byte olduğu için Client ID lenght = 0x05 oldu. Böylece broker’a bağlanmak için gönderilmesi gereken paketi bitirdik.
Şimdi gelelim STM32 kod tarafına. Ben bu uygulamada STM32F103 kullandım fakat yazdığım kodlar diğer STM serilerinde de sorunsuz çalışacaktır. Başlangıç olarak STM32 ile ESP yi haberleştirebilmek için USART çevrebirimini aktif ettim. Her bir işlem için ayrı ayrı kısa fonksiyonlar yazdım.
Öncelikle ESP8266’yı internete bağlayalım. Bunun için aşağıdaki gibi bir fonksiyon yazdım.
1 2 3 4 5 6 7 8 9 10 11 | void Wifi_Connect(char *SSID ,char *Password) { HAL_UART_Transmit(&huart1,(uint8_t *)"AT+CWMODE=1\r\n",strlen("AT+CWMODE=1\r\n"),1000); HAL_Delay(1000); HAL_UART_Transmit(&huart1,(uint8_t *)"AT+CWQAP\r\n",strlen("AT+CWQAP\r\n"),1000); HAL_Delay(1000); // HAL_UART_Transmit(&huart1,(uint8_t *)"AT+RST\r\n",strlen("AT+RST\r\n"),100); // HAL_Delay(5000); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"AT+CWJAP=\"%s\",\"%s\"\r\n",SSID,Password),1000); } |
Bu fonskiyonun aldığı parametreler Wi-fi adınız ve şifreniz olacaktır. ESP sorunsuz bir şekilde internete bağlandıktan sonra Broker’a bağlanma işlemine geçebiliriz.
Broker’a bağlanmak için yazdığım kod aşağıdaki gibidir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | void Connect_Broker(char *Ip ,char *Port) { HAL_UART_Transmit(&huart1,(uint8_t *)"AT+CIPCLOSE\r\n",strlen("AT+CIPCLOSE\r\n"),1000); HAL_Delay(100); HAL_UART_Transmit(&huart1,(uint8_t *)"AT+CIPMUX=0\r\n",strlen("AT+CIPMUX=0\r\n"),1000); HAL_Delay(100); HAL_UART_Transmit(&huart1,(uint8_t *)"AT+CIFSR\r\n",strlen("AT+CIFSR\r\n"),1000); HAL_Delay(100); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"AT+CIPSTART=\"TCP\",\"%s\",%s\r\n",Ip,Port),5000); HAL_Delay(2000); //connect packet ProtocolNameLength = strlen(protocolName); ClientIDLength = strlen(clientID); uint8_t Remainlength; Remainlength = 2+ProtocolNameLength+6+ClientIDLength; uint16_t length = sprintf(tx_buffer,"%c%c%c%c%s%c%c%c%c%c%c%s",(char)connect,(char)Remainlength,(char)(ProtocolNameLength << 8),(char)ProtocolNameLength,protocolName,(char)level,(char)flag,(char)(keepAlive << 8),(char)keepAlive,(char)(ClientIDLength << 8),(char)ClientIDLength,clientID); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"AT+CIPSEND=%d\r\n",length),1000); HAL_Delay(100); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"%c%c%c%c%s%c%c%c%c%c%c%s",(char)connect,(char)Remainlength,(char)(ProtocolNameLength << 8),(char)ProtocolNameLength,protocolName,(char)level,(char)flag,(char)(keepAlive << 8),(char)keepAlive,(char)(ClientIDLength << 8),(char)ClientIDLength,clientID),5000); } |
Bu fonksiyonu biraz inceleyelim. ESP modülünün AT komutları ile haberleştiğini biliyoruz. Kullanacağımız AT komutlarına bir bakalım.
AT+CIPCLOSE : Bu komutu fonksiyonun başında kullandım çünkü cihaz daha önceden bir server’a bağlı ise bağlantıyı kessin.
AT+CIPMUX=0 : Birden fazla bağlantı (TCP) yapılacaksa 1 , tek bağlantı yapılacaksa 0 olarak ayarlanmalı.
AT+CIFSR : ESP’ye atanan IP numarasını gösterir. Bağlanmak için gerekli bir fonksiyon değildir sadece ESP’nin IP numarasını öğrenmek için yazdım.
AT+CIPSTART = “TCP”,”192.168.1.103″,1883 : Server’a bağlanmak için gerekli olan komuttur. Burada bağlantı şekli TCP seçildi. IP olarak ise Broker’ın çalıştığı bilgisayarın IP’si yazıldı. Son parametre ise port parametresidir. Yukarıda cmd ekranından broker’ı çalıştırdığımızda hangi portu dinlediğini yazmaktadır. O yüzden port olarak 1883 portu girilmiştir ve genellikle bu kullanılır.
Buraya kadar her şey tamam AT+CIPSTART komutu gönderildikten sonra server’a bağlanmış olduk. Daha sonra AT+CIPSEND komutu ile MQTT paketimizi göndereceğiz.
AT+CIPSEND=%d yazmamdaki sebep kaç byte’lık veri göndereceğimi ESP’ye bildirmektir.
Bağlantı paketini bir diziye kaydetmek için “string.h” kütüphanesinin içerisindeki sprintf() fonksiyonunu kullanıyorum. Char tipinde oluşturduğum bir diziye(tx_buffer) sprintf fonksiyonunu kullanarak bütün paketi kaydediyorum.
1 2 3 | uint16_t length = sprintf(tx_buffer,"%c%c%c%c%s%c%c%c%c%c%c%s",(char)connect,(char)Remainlength,(char)(ProtocolNameLength << 8),(char)ProtocolNameLength,protocolName,(char)level,(char)flag,(char)(keepAlive << 8),(char)keepAlive,(char)(ClientIDLength << 8),(char)ClientIDLength,clientID); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"AT+CIPSEND=%d\r\n",length),1000); |
sprintf fonksiyonu aynı zamanda size integer olarak diziye kaydedilen stringin uzunluğunu verir. Bu uzunluğu CIPSEND komutu ile gönderip ESP’ye diyorum ki sana bu kadar byte’lık bir veri göndereceğim.
Son olarak ise Broker bağlanmak için gerekli olan paketi UART üzerinden ESP8266‘ya gönderiyoruz.
1 | HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"%c%c%c%c%s%c%c%c%c%c%c%s",(char)connect,(char)Remainlength,(char)(ProtocolNameLength << 8),(char)ProtocolNameLength,protocolName,(char)level,(char)flag,(char)(keepAlive << 8),(char)keepAlive,(char)(ClientIDLength << 8),(char)ClientIDLength,clientID),5000); |
Buradaki değişkenlerin bazılarını main fonksiyonun üzerinde tanımladım. Bunları en altta paylaştığım STM32 kodlarının tamamında bulabilirsiniz.
Komut satırından broker’ı çalıştırıp STM’ e kodu yükledikten sonra ESP ile broker’a bağlantı sağlayabilirseniz komut satırı ekranınız aşağıdaki gibi olacaktır.
Bu aşamadan sonra eğer 60 saniye içerisinde publish veya herhangi bir işlem yapmazsak broker bizim server ile olan bağlantımızı kesecek.
Broker bağlantıyı kestikten sonra tekrar bağlanmadan subcribe veya publish yapamazsınız. Siz farkında olmadan bağlantınız kopmuştur sonra neden mesajı publish edemiyorum diye kıvranırsınız. Buna dikkat etmekte fayda var.
Subscribe(Abone Olma) Paketi
Subscribe olurken package Id belirlemek gerekiyor ve bu değer sıfır olamaz. O yüzden bu değeri 0x01 olarak yazdım.
Abone olunacak topic ismini “IOT” olarak seçiyorum.
Quality of Service(Qos) : Servis kalitesi olarak isimlendirilen bu bit 3 farklı değer alır. Bunlar 0, 1 ve 2’dir. Bu değerler verilerin karşı tarafa iletilip iletilmediğini garanti eden hizmet seviyeleridir.
- QoS 0: Hizmet kalitesinin minimum seviyesidir.Bu seviyede verinin karşı tarafa iletildiğine dair bir garanti yoktur.
- QoS 1: Bu seviyede mesajın alıcıya en az bir kez iletildiği garanti edilir. Gönderen alıcıdan PUBACK paketini alana kadar mesajı saklar.
- QoS 2: En yüksek hizmet seviyesidir. Bu seviyede karşı tarafın mesajı sadece bir kez alacağı garanti edilir. En güvenli ve en yavaş olan seviyedir.
Ben burada QoS=0 olarak seçtim.
1 2 3 4 5 6 7 8 9 10 | void Subscribe(char *topic) { uint16_t TopicLength = strlen(topic); uint8_t RemainLength = 2+2+TopicLength+1; // packetIDlength(2) + topiclengthdata(2)+topiclength+Qos uint16_t length = sprintf(tx_buffer,"%c%c%c%c%c%c%s%c",(char)subscribeCon,(char)RemainLength,(char)(packetID << 8),(char)packetID,(char)(TopicLength << 8),(char)TopicLength,topic,(char)Qos); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"AT+CIPSEND=%d\r\n",length),1000); HAL_Delay(100); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"%c%c%c%c%c%c%s%c",(char)subscribeCon,(char)RemainLength,(char)(packetID << 8),(char)packetID,(char)(TopicLength << 8),(char)TopicLength,topic,(char)Qos),5000); } |
Subscribe için yazdığım fonksiyon yukarıdaki gibidir. Connect_broker() fonksiyonuna göre daha küçük bir fonksiyon. Parametre olarak sadece topic ismini alıyor. STM32 bu fonksiyonu çağırdıktan sonra cmd ekranında aşağıdaki gibi değişiklikler olması gerekmektedir.
Subscribe olduktan sonra farklı bir cihaz IOT topic’ine bir mesaj gönderdiğinde ESP UART üzerinden STM32’ye bir paket göndermektedir. Bu paket çözümlenerek gönderilen mesaj çekilebilir ve STM’de bir karar mekanizması ile gelen mesaja göre istenilen işlemler yapılabilir.
Publish(yayın) Paketi
Publish için gerekli olan paket formatı yukarıdaki gibidir. Diğer paketlerdeki benzer değişkenler olduğu için tekrar etmek istemiyorum. Burada ekstradan “message” değişkenimiz var. Yani göndereceğimiz string mesajı paketin sonuna eklememiz gerekir. Publish yapacağım topic adını subscribe topic’inden farklı seçtim çünkü bir cihazın aynı topic’e hem abone olup hemde yayın yapması mantıklı bir hareket değil. Eğer aynı olursa yayın yapar yapmaz aynı topic’e abone olduğu için gönderdiği mesajı kendisi de alacaktır. Böyle bir durumu istemediğim için yayın yaptığım topic’i ESP8266 olarak seçtim.
*** Önemli Ekleme: Yukarıda publish paketi için de Qos seviyesi belirlenebilmektedir. Bu gözümden kaçmış. Bu yüzden sanki yayın yaparken Qos seçilmiyormuş gibi anlaşılabilir. Aşağıda görüldüğü gibi publish paket formatının “fixed header” olarak isimlendirilen baytının 1. ve 2. biti ile servis kalitesi seçilebilir. Qos sıfırdan farklı seçildiğinde server ile client arasında bir doğrulama mekanizması kurmak gerekir. Örneğin; Qos 1 iken server’a bir mesaj gönderdiğinizde eğer mesaj alınmış ise server PUBACK(Publish Acknowledgement) paketini client’a geri göndermelidir. Böylece bu paket client tarafından alınarak mesajın servera ulaşıp ulaşmadığı kontrol edilebilir ve veri kaybı önlenebilir. Eğer servis kalitesini sıfırdan farklı seçecek iseniz bu bitlere dikkat etmeniz gerekir. Bu paketler hakkında daha fazla bilgi için buraya tıklayabilirsiniz.
***
1 2 3 4 5 6 7 8 9 10 11 12 | void publish(char *topic, char *message) { uint16_t topiclength = strlen(topic); uint8_t remainlength = 2+topiclength+strlen(message); int length = sprintf(tx_buffer,"%c%c%c%c%s%s",(char)publishCon,(char)remainlength,(char)(topiclength << 8),(char)topiclength,topic,message); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"AT+CIPSEND=%d\r\n",length),100); HAL_Delay(100); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"%c%c%c%c%s%s",(char)publishCon,(char)remainlength,(char)(topiclength << 8),(char)topiclength,topic,message),5000); HAL_Delay(100); } |
Publish için yazdığım fonksiyon ise yukarıdaki gibidir. Parametre olarak ise yayın yapılacak topic adı ve mesaj değişkenlerini alır. Stm32 de bu fonksiyonu iki saniyede bir publish edecek şekilde sonsuz döngünün içerisinde kullandım. STM32 , ESP üzerinden publish yaptığı zaman konsol ekranı aşağıdaki gibi olur.
Resimde görüldüğü gibi broker konsol ekranında yayınlanan mesajı göremiyoruz. Peki publish ettiğimiz bu mesajı nereden izleyebiliriz. Bunun için yukarıda verdiğim subscribe.bat uzantılı dosyayı kendinize göre yazarak yine konsol ekranından izleyebilirsiniz. Ayrıca MQTT için ücretsiz mobil uygulamalar bulunmaktadır. Bunlardan birini de kullanabilirsiniz. Ben MyMQTT isimli ücretsiz uygulamayı kullandım. Arayüzü gayet basit ve başlangıç için kullanışlı bir uygulama.
Projenin dosyalarına Github üzerinden ulaşmak için buraya tıklayın.
STM32 Kodlarının Tamamı
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** ** This notice applies to any and all portions of this file * that are not between comment pairs USER CODE BEGIN and * USER CODE END. Other portions of this file, whether * inserted by the user or by software development tools * are owned by their respective copyright owners. * * COPYRIGHT(c) 2020 STMicroelectronics * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of STMicroelectronics nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "stm32f1xx_hal.h" /* USER CODE BEGIN Includes */ #include "string.h" /* USER CODE END Includes */ /* Private variables ---------------------------------------------------------*/ UART_HandleTypeDef huart1; /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ char rx_buffer[500],tx_buffer[150]; uint16_t ProtocolNameLength; uint16_t ClientIDLength; uint8_t connect = 0x10,publishCon = 0x30,subscribeCon = 0x82; char *protocolName = "MQTT"; uint8_t level = 0x04; uint8_t flag = 0x02; // 02--> sifresiz uint16_t keepAlive =60; uint16_t packetID = 0x01; uint8_t Qos = 0x00; char *clientID = "Topuz"; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART1_UART_Init(void); /* USER CODE BEGIN PFP */ /* Private function prototypes -----------------------------------------------*/ void Wifi_Connect(char *SSID ,char *Password) { HAL_UART_Transmit(&huart1,(uint8_t *)"AT+CWMODE=1\r\n",strlen("AT+CWMODE=1\r\n"),1000); HAL_Delay(1000); HAL_UART_Transmit(&huart1,(uint8_t *)"AT+CWQAP\r\n",strlen("AT+CWQAP\r\n"),1000); HAL_Delay(1000); // HAL_UART_Transmit(&huart1,(uint8_t *)"AT+RST\r\n",strlen("AT+RST\r\n"),100); // HAL_Delay(5000); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"AT+CWJAP=\"%s\",\"%s\"\r\n",SSID,Password),1000); } void Connect_Broker(char *Ip ,char *Port) { HAL_UART_Transmit(&huart1,(uint8_t *)"AT+CIPCLOSE\r\n",strlen("AT+CIPCLOSE\r\n"),1000); HAL_Delay(100); HAL_UART_Transmit(&huart1,(uint8_t *)"AT+CIPMUX=0\r\n",strlen("AT+CIPMUX=0\r\n"),1000); HAL_Delay(100); HAL_UART_Transmit(&huart1,(uint8_t *)"AT+CIFSR\r\n",strlen("AT+CIFSR\r\n"),1000); HAL_Delay(100); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"AT+CIPSTART=\"TCP\",\"%s\",%s\r\n",Ip,Port),5000); HAL_Delay(2000); //connect packet ProtocolNameLength = strlen(protocolName); ClientIDLength = strlen(clientID); uint8_t Remainlength; Remainlength = 2+ProtocolNameLength+6+ClientIDLength; uint16_t length = sprintf(tx_buffer,"%c%c%c%c%s%c%c%c%c%c%c%s",(char)connect,(char)Remainlength,(char)(ProtocolNameLength << 8),(char)ProtocolNameLength,protocolName,(char)level,(char)flag,(char)(keepAlive << 8),(char)keepAlive,(char)(ClientIDLength << 8),(char)ClientIDLength,clientID); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"AT+CIPSEND=%d\r\n",length),1000); HAL_Delay(100); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"%c%c%c%c%s%c%c%c%c%c%c%s",(char)connect,(char)Remainlength,(char)(ProtocolNameLength << 8),(char)ProtocolNameLength,protocolName,(char)level,(char)flag,(char)(keepAlive << 8),(char)keepAlive,(char)(ClientIDLength << 8),(char)ClientIDLength,clientID),5000); } void Subscribe(char *topic) { uint16_t TopicLength = strlen(topic); uint8_t RemainLength = 2+2+TopicLength+1; // packetIDlength(2) + topiclengthdata(2)+topiclength+Qos uint16_t length = sprintf(tx_buffer,"%c%c%c%c%c%c%s%c",(char)subscribeCon,(char)RemainLength,(char)(packetID << 8),(char)packetID,(char)(TopicLength << 8),(char)TopicLength,topic,(char)Qos); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"AT+CIPSEND=%d\r\n",length),1000); HAL_Delay(100); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"%c%c%c%c%c%c%s%c",(char)subscribeCon,(char)RemainLength,(char)(packetID << 8),(char)packetID,(char)(TopicLength << 8),(char)TopicLength,topic,(char)Qos),5000); } void publish(char *topic, char *message) { uint16_t topiclength = strlen(topic); uint8_t remainlength = 2+topiclength+strlen(message); int length = sprintf(tx_buffer,"%c%c%c%c%s%s",(char)publishCon,(char)remainlength,(char)(topiclength << 8),(char)topiclength,topic,message); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"AT+CIPSEND=%d\r\n",length),100); HAL_Delay(100); HAL_UART_Transmit(&huart1,(uint8_t *)tx_buffer,sprintf(tx_buffer,"%c%c%c%c%s%s",(char)publishCon,(char)remainlength,(char)(topiclength << 8),(char)topiclength,topic,message),5000); HAL_Delay(100); } /* USER CODE END PFP */ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * * @retval None */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ HAL_Delay(1000); HAL_UART_Receive_IT(&huart1,(uint8_t *)rx_buffer,500); Wifi_Connect("TP-LINK_9B7ECA","a1b2c3"); // kendi wifi adınız ve sifreniz HAL_Delay(5000); Connect_Broker("192.168.1.103","1883"); HAL_Delay(1000); Subscribe("IOT"); while (1) { HAL_Delay(2000); publish("ESP8266","deneme"); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; /**Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL7; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure the Systick interrupt time */ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); /**Configure the Systick */ HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* SysTick_IRQn interrupt configuration */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } /* USART1 init function */ static void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart1) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } } /** Configure pins as * Analog * Input * Output * EVENT_OUT * EXTI */ static void MX_GPIO_Init(void) { /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @param file: The file name as string. * @param line: The line in file as a number. * @retval None */ void _Error_Handler(char *file, int line) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ while(1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ |
Bu yazıda ESP8266 ile ilgili bir kütüphane kullanmadan MQTT protokolü ile haberleşmeyi dilim döndüğünce anlatmaya çalıştım. Yazıda eksik veya hatalı bir kısım görürseniz yorumlarda belirtebilirsiniz.
Aynı uygulamayı GSM modülü ile de yapıp paylaşmayı düşünüyorum. GSM modüllerinin çoğu AT komutları ile haberleştiği için kodlar aşağı yukarı aynı olacaktır. Fakat Broker tarafında port yönlendirme gibi birkaç işlem yapmak gerekecektir.
NOT: Yeri gelmişken belirteyim. Broker’a mobil uygulama üzerinden bağlanabilmek için broker’ın çalıştığı bilgisayar ile aynı wifi ağına bağlı olmanız gerekmektedir. Aynı şekilde ESP modülü de aynı ağa bağlı olmak zorundadır. Farklı ağa bağlı cihazlar arasında da MQTT ile veri alışverişi yapılabilir fakat bunun için port yönlendirme ayarları yapılmalıdır.
Bir sonraki yazıda görüşmek üzere …
Github
Proje dosyalarına github üzerinden erişmek için buraya tıklayabilirsiniz.
Merhaba,
Elinize sağlık. ESP8266’ya ait bir modül mü kullandınız yoksa direkt chip’in kendisini mi kullandınız. Tüm ESP8266’lar AT komutları ile haberleşebilecek diye bir durum söz konusu değil diye biliyorum. Bunun için gerekli firmware’in ESP8266 yüklenmiş olması gerekir diye düşünüyorum.
Teşekürler. ESP’yi modül olarak kullandım.
https://www.direnc.net/esp8266-serial-wifi-modul?language=tr&h=f4ade492&gclid=Cj0KCQjwmpb0BRCBARIsAG7y4zbB3qMn7lveLOYhn3m7zF3D-BSPONMPkLjKm6quz_sNJcYUopAfHh0aAgXvEALw_wcB
Merhaba,
Konyu çok güzel anlatmışsınız. Siz broker’ı kendi bilgisayarınıza kurmuşsunuz bulut sistemde olanlara nasıl bağlanabilinir?
Merhaba,
Bulut sistemi için deneme fırsatım olmadı ama nasıl bağlanılacağı ile ilgili bir fikrim var. Öncelikle CloudMQTT için konuşacağım. Siteye üye olduktan sonra size “m11.cloudmqtt.com” şeklinde bir server adresi veriyor. Bunu benim yazdığım koddaki ip değişkeni yerine yazabilirsin. Ayrıca CloudMQTT servera bağlanabilmeniz için sizden kullanıcı adı ve şifre oluşturmanızı istiyor. Bu aşamadan sonra benim yazdığım kodda biraz değişiklik yapmak gerekiyor çünkü yukarıdaki kodlar servera şifresiz bağlanıyor. Şifreli bağlanabilmek için flag isimli değişkenin 0xC2 olması gerekir. Daha sonra “Connect packet” içerisine kullanıcı adı ve şifreyi eklemelisin. Bunu da şöyle yapmalısın; “Connect packet”in sonuna
(16bitlik kullanıcı adı uzunluğu)+(string olarak kullanıcı adı) + (16 bitlik şifre uzunluğu)+(string olarak şifre)
şeklinde gönderilmesi gerekir.Şifreli bağlanmayı kendi bilgisayarıma bağlanırken bu şekilde yapmıştım. CloudMQTT için de çalışır diye umuyorum.
Hello, I was very happy to find your tutorial when I was learning AT commands to MQTT. But like the other commented, I have difficulty connecting MQTT hivemq with ID and password. Have you tried it with the AT + MQTT commands of Espressif?
Look forward to hearing from you!
Hello,
I have never tried AT+MQTT commands. I didn’t even know the existence of this commands. But i connected to Mqtt broker with ID and Password using AT+CIPSTART and AT+CIPSEND commands. If you want to connect like this you must change the flag variable to 0xC2 and you must add the ID and password at the end of the connect packet. For example
…+IDlength(2 bytes)+ID(string)+passworLength(2 bytes)+password(string)
Thank you very much for answering my question. Your tutorials are great, but I’m a bit bad at using bit and flag…. Here is a tutorial from Espressif about AT + MQTT commands. It seems simpler to me. However, I have tried and failed to connect with broker with username and password. I have a deadline to submit my homework and I’m still struggling. I look forward to your help. Thank you very much
Or you can post the code you did with username and password, I’m a bit stupid
Sorry. I am busy these days. I can’t help you with AT + MQTT commands, but as you said, I can share my code. Here is my mqtt_connect function that I use with the GSM module (SIM800C). Hope this fixes your problem.
https://paste.ubuntu.com/p/M65nhfBwGk/
I don’t think you answered that quickly
Saygılarımla teşekkür ederim, sağlık!
Thank you very much dear!
Merhaba rehberiniz için çok teşekkürler. Anlamadığım bir kısım var. Stm32 ile bir topice subscribe olunca gelen mesajlar hangi değişkende kaydedilecek ve mesaj gelip gelmediğini nasıl kontrol edebilirim?
Rica ederim. Topice gelen mesajlar UART üzerinden gelecek. Gelen mesaj da publish paketinin içinde gelecek. Yani publish paketinin içinden mesajı çekmeniz gerekmetedir. Bununla ilgili bir örnek bir sonraki yazıda var incelemenizi tavsiye ederim.
In case the message is a variable value, for example type int, how to fix the publish code?
Looking forward to hearing from you
Thank you!
The package structure type is already a byte array. Therefore, you can put your int variables inside the package without using the sprintf function. if you want to use sprintf function. you can use like this.
uint8_t msg_value=10;
sprintf(tx_buffer,"%c%c%c%c%s%c",
(char)publishCon,(char)remainlength,
(char)(topiclength << 8),(char)topiclength,
topic,(char)msg_value);
merhaba benim bir projem var. Bunda esp modülü kullanacağım. Stm32f401re kartına sahibim Burada esp modülü üzerinden 4 kontrol yapmak istiyorum ve bunları da bir web server oluşturup oradan kontrol etmek istiyorum burada bunu sadece at komutları ve html kodları kullanarak yapabilir miyim. Arduinoda örnekleri var ama stm32 için örneklerini bulamadım. Bana yardımcı olup yol gösterirseniz sevinirim
Merhaba,
Ben daha önce esp ile webserver üzerine bir çalışma yapmadım ama dediğiniz şey yapılabilir. At komutları ve basit html komutları ile dediğiniz gibi bir kontrol uygulaması yapılabilir. Linkteki videoda buna benzer bir örnek var incelemenizi tavsiye ederim.
https://youtu.be/MG-5Ct_rCZQ
Paylaştığınız videoyu izledim sanırım bana yardımcı olacak bunun için teşekkür ederim bir sorunla karşılaşırsam sizi tekrar rahatsız edeceğim 🙂
Rica ederim. Herhangi bir sorunla karşılaşırsanız benimle iletişime geçebilirsiniz. Elimden geldiğince yardım ederim. Mail adresim iletişim sayfasına bulunmaktadır.
iyi çalışmalar.
To stay connected, as you said, Ping Request, what is the Ping packet structure? Have you tried it?
I hope your answer! Thank you so much.
You’re welcome,
Ping request packet format is very simple. it only has 2 bytes. The first byte is the type of control that should be 0xC0. The second byte is the remaining length. Since the packet size is 2 bytes, the remaining length should be 0x00. I’ve tried it before. I sent the ping request packet to the server every 50 seconds (because keep alive = 60).
For more information about ping request packet you can visit this link-> https://docs.solace.com/MQTT-311-Prtl-Conformance-Spec/MQTT%20Control%20Packets.htm#_Toc430864945
uint8_t Ping_control = 0xC0;
uint8_t Ping_load = 0x00;
void Ping_connect (){
HAL_UART_Transmit(&huart1, (uint8_t*)tx_buf,
sprintf (tx_buf, “%c%c”, (char) Ping_control, (char) Ping_load ), 1000);
}
I did like this, but it doesn’t work. It looks stupid 🙁 Can u help me fix it
Thanks for your help. And I tried it like that:
uint8_t Ping_control = 0xC0;
uint8_t Ping_load = 0x00;
void Ping_connect (){
HAL_UART_Transmit(&huart1, (uint8_t*)tx_buf,
sprintf (tx_buf, “%c%c”, (char) Ping_control, (char) Ping_load ), 1000);
}
but it doesn’t work. It looks stupid 🙁 Can u help me fix it
I fixed a bit. If I do it right then this is no different from publishing, it will take 2 turns 🙁 Are u there?
void Ping_connect (){
int length = sprintf (tx_buf, “%c%c”, (char) Ping_control, (char) Ping_load );
HAL_UART_Transmit(&huart1,(uint8_t *)tx_buf,sprintf(tx_buf,”AT+CIPSEND=%d\r\n”,length),100);
while (!Wait(“OK\r\n”));
HAL_UART_Transmit(&huart1, (uint8_t *)tx_buf,
sprintf (tx_buf, “%c%c”, (char) Ping_control, (char) Ping_load ), 1000);
while (!Wait (“\320”));
}
After sending the pingrequest packet, the server will send the ping response packet. Not “\ 320”. The ping response packet is 2 bytes (0xD0 and 0x00) just like the ping request. You can use the wait () function like this.
…
char response[2] = {0xD0,0x00};
while(!wait(response));
…
Merhaba, bu kodlar üzerinde ufak değişiklikler yaptık ve dakikada bir veri gönderiyoruz. Fakat bazen veri kaybı yaşıyoruz, mesela 10. dk’daki veriler web sunucuya gelmiyor, sizce neden kaynaklanmış olabilir?Qos=0 olarak kullanıyoruz, bundan kaynaklı olabilir mi?
Merhaba,
Bu sorun dediğiniz gibi Qos 0 olmasından kaynaklanıyor olabilir. Servis kalitesi(Qos) sıfır olduğunda publish yapan cihaz serverdan mesajın alındığına dair bir onaylama(acknowledge) beklemez. Qos 1 seçildiğinde her yayın yaptığınızda server size PUBACK paketini gönderir. Eğer Qos 1 seçerseniz bu PUBACK paketinin gelip gelmediğini kontrol etmeniz gerekir. Eğer gelmediyse mesajı tekrar gönderebilirsiniz. Bu durumda mesaj servera iki kere veya daha fazla gitmiş olabilir. Qos 1 mesajın servera en az 1 kere gittiğini doğrular. Qos 2 seçildiğinde server ile client arasında 4 aşamalı bir doğrulama yapılır. Bu en gecikmeli yöntemdir ama mesajın kesin olarak gittiğini garanti eder. Qos parametresini kullandığınız sistemin isterlerine göre seçmeniz gerekir. Olmazsa olmaz dediğiniz, mutlaka veri kaçırmamam gerekiyor dediğiniz bir veriyi gönderiyorsanız servis kalitesini en yüksek seçebilirsiniz. Atıyorum pil ile çalışan bir sisteminiz var ve pil voltaj seviyesini her saniyede bir gönderiyorsunuz. Bu gibi durumlarda Qos 0 seçebilirsiniz çünkü o bir saniyelik veri kaybı sizin için çok önemli değildir. Kaldı ki pil voltajı o bir saniyede değişmemiş bile olabilir. Uzun lafın kısası Qos ile oynayarak ve stm32 tarafındaki implementasyonu iyi yaparak veri kaybını önleyebilirsiniz.
Ayrıca bu yorum için teşekkür ederim yazıdaki bir eksiği farketmeme sebep oldu. Normalde publish paketinin “fixed header” bitlerinden ikisi Qos belirlemeye yarıyor. Yazıda sanki publish yaparken Qos belirlenmiyormuş gibi anlaşılıyor. Bu kısım gözümden kaçmış. Bunu da en kısa zamanda ekleyeceğim. Eğer Qos ile oynayacak iseniz bu dediklerime dikkat edin. Publish paketinin “fixed header” bitlerini incelemek için linke tıklayabilirsin. https://docs.solace.com/MQTT-311-Prtl-Conformance-Spec/MQTT%20Control%20Packets.htm#_Toc430864901
iyi akşamlar esp8266 üzerinde çalışmalar yapıyorum arduino üzerinde yaptığım zaman hiç bir hata almadan hem at komutlarına cevap alabiliyorum hem de sunucu kurabiliyorum fakat bunu stm32f401re kartımla yapmaya çalıştığım zaman hep hiç bir hareket olmamakla beraber esp8266 modülümde aşırı bir ısınma oluyor bağlantıları çok kontrol ettim fakat bir sıkıntı göremedim bunun nedeni ne olabilir acaba ?
Bu sorunun neyden kaynaklandığını bilmiyorum malesef. Ben doğrudan stm32f103C8T6 ya bağlamıştım sorun çıkarmamıştı.
Merhaba hocam, projeyi çalıştırdım,publish oluyor fakat board üzerine gelen publishleri bir türlü alamadım(sizin kodunuzu direk copy paste yapmama rağmen olmuyor).Mqtt lens veya my mqtt programları ile birbiri arasında veri gönderip alabildim ama karta mesajı alamadım(usart irq handlere kesme koymama rağmen kesmeye gitmiyor).Sorun ne olabilir? Teşekkürler
Merhaba, huart->ErrorCode değişkenini debug ekranından kontrol edin. Kesmeye gitmiyorsa Uarttan kaynaklı bir hata olabilir. Eğer uarttan kaynaklı bir hata ise ErrorCode değişkenine bir değer atanır. Daha sonra bu değerin karşılığı olan hata koduna bakmak lazım.
Sorunu buldum,read_messaje fonksiyonunu gsm-mqtt programında var ama bu sayfada yok. Bende kendi read fonksiyonumu oluşturdum.teşekkürler.
Rica ederim. Evet bu yazıda sadece veri gönderme var. Veri alma yok.
Hocam merhaba. Teşekkürler öncelikle bu güzel tutorial için. Yukarıdaki örneği kullanarak ESP ile bağlanmaya çalıştığımda Mosquitto tarafında şöyle bir hata alıyorum >> Client disconnected due to protocol error.
Bir türlü çözemedim. ESP önce bağlanıyor mesajı fakat Connect_Broker fonk çalıştığında bağlantı kesiliyor. Mqtt explorer uygulaması ile bağlanabiliyorum fakat gömülüden bir türlü bağlanamıyorum. Siz acaba bu hata ile karşılaştınız mı veya ne gibi ayarlar yaptınız Mosquitto server tarafında?
Merhaba, Bu hata bağlantı paketinin yanlış gönderilmesinden kaynaklanıyor. Bu hatayı daha önce bende almıştım. Pakete eklediğiniz baytları kontrol etmenizi tavsiye ederim. Elinizde USB-TTl dönüştürücü falan varsa UART üzerinden gönderdiğiniz paketleri seri port yazılımları ile izlemenizi tavsiye ederim. Paket içerisindeki verilerin sırası yukarıdaki “connect packet” içindeki baytların sırası ile aynı olmalı.
Aynen dediğiniz gibi çıktı. Oluşturulan datanın içindeki bazı karakterler bir noktada kullandığım strcpy fonk. unu bozmus. Düzgün kopyalayamadığım içinde verileri yanlış gönderiyormuşum. Yazmış olayım benzer problem problem yaşayan arkadaşlarda görmüş olsunlar. Teşekkürler
Rica ederim.
Merhaba, iyi çalışmalar Mehmet bey. ESP kodunun brokera bağlanma kısmında gerekli olan paketi gönderiyorum fakat geri dönüş olarak ‘link is not valid’ hatası alıyorum, sebebi ne olabilir acaba?
Merhaba, Bunun sebebini bilmiyorum açıkcası fakat birkaç tahminim var. Birincisi AT komut versiyonundan olabilir bunun için ESP firmware’i güncellemeniz gerekebilir. İkincisi ise besleme ile ilgili sorun olabilir. Bu tarz modüller bazı komutları yerine getirirken gereğinden fazla akım çekebilir ve beslediğiniz kaynak bunu sağlayamıyorsa bu tarz sorunlar olabilir. Ayrıca beslemeden kaynaklı olsa sürekli açılıp kapanması gerekir modülün. Sonu “ready” ile biten bir mesaj geldiğini hatırlıyorum böyle durumlarda. Bunların haricinde bir fikrim yok malesef. Bu arada MQTT için güzel bir kütüphane hazırlıyorum bu aralar. Umarım bir an önce bitirip paylaşabilirim.
Teşekkürler, sıkıntı beslemedeymiş, espnin bozuk olduğunu fark ettim şu an çalışan bir tane kullanıyorum fakat şimdi de brokera bağlandıktan sonra “Client disconnected due to protocol error.” hatası alıyorum. Bunun sebebinin bağlantı için gönderilen paketten olduğunu düşündüm fakat sizin kodunuzdaki formatı kullanıyorum. Mqtt’nin sayfasından da ayrıca kontrol ettim acaba pakette değişmesi gereken bir şey var mı diye ama bulamadım. Publish’i ve Subscribe’ı mosquitto_pub ve sub ile yapınca bir sıkıntı olmuyor.
Bu hata dediğiniz gibi paketin yanlış gönderilmesi ile ilgili olması lazım. MQTT nin versiyonları var bu yüzden kullandığınız broker programı farklı bir versiyona göre paket bekliyor olabilir. Ayrıca gönderdiğiniz paketi debug ekranından byte byte inceleyip karşılaştırmanızı tavsiye ederim. Paketi yanlış oluşturuyor da olabilirsiniz. Geçen gün başıma gelen birşey; Mosquitto broker’ı kullanmak için son versiyonunu indirdim fakat ne ESP’den ne de bilgisayardan bağlanamadım. Daha sonra 1.6 versiyona geri döndüm sorunsuz çalıştı. Sebebini hala tam olarak anlayamadım. Forumlarda ise Windowsta çalışmıyor demişler anlamadım yani. Neyse böyle yani Mert. Paketi tekrar bir kontrol et eğer hata yok ise farklı bir broker dene. Hatta online bir broker dene HiveMQ gibi.
Merhaba, yazınız çok bilgilendirici bunun için teşekkür ederim, fakat bir sorun yaşıyorum. Esp8266’yı stm32 ile modeme bağlantım gerçekleşmiyor. TTL uart haberleşme ile at komutlarını yazdığımda modeme bağlanabiliyorum. Fakat sizin kodlarınızla bağlantıyı bir türlü gerçekleştiremedim. Bunun sebebini çok düşünsem de bulamadım. Bu konu hakkında bir fikriniz var mı?
Merhaba, Bu sorunu bulmak için tavsiyem STM32 ile ESP arasındaki UART hattına USB-TTL bağlayıp izleyin. Eğer bir hata var ise orada görünecektir. Bazen gözden kaçan ufak hatalar olabilir. STM32 komutları doğru gönderiyor mu? ESP bu komuta nasıl bir cevap dönüyor? Bazen bir komutu işlemeden bir daha komut gönderince “busy” mesajını dönebiliyor. O yüzden dediğim gibi UART hattını bir dinleyin derim.