[IoT] Bài 8: Giao thức MQTT với tập lệnh ATcommand – esp8266

Trong bài trước, mình đã giới thiệu về giao thức MQTT và chúng ta đã nhanh tóng test qua về MQTT trên esp8266 với arduino. Tiếp tục phần này, mình sẽ giới thiệu về giao tiếp MQTT qua tập lệnh AT

Các bạn cần đọc bài 3bài 5 trước thì mới hiểu bài này nhé !

MQTT hoạt động trên nền TCP hoặc Socket, trong bài này mình sẽ chỉ demo qua trên nền tảng TCP, còn socket chúng ta sẽ tìm hiểu ở các bài sau nhé

Cấu trúc của các gói tin MQTT

Các gói tin liên quan đến MQTT thì nhiều lắm, mình chỉ giới thiệu qua 3 gói tin cơ bản

  • Gói tin connect
  • Gói tin publish
  • Gói tin subscriber

1, Connect – Client gửi 1 thông điệp kết nối đến broker

Control Header : 1 byte

4 bit cao nhất mô tả MQTT Control Packet type và 4 bit thấp chứa Control flags.

Dưới đây là bảng mô tả của Control Header

CONNECT 0x10
CONNACK  0x20
PUBLISH  0x30
PUBACK  0x40
PUBREC 0x50
PUBREL  0x60
PUBCOMP  0x70
SUBSCRIBE  0x80
SUBACK  0x90
UNSUBSCRIBE 0xA0
UNSUBACK  0xB0
PINGREQ  0xC0
PINGRESP 0xD0
DISCONNECT 0xE0

Packet Length (1 byte đến 4 byte)

Packet Length mô tả phía sau nó còn bao nhiêu byte nữa (không tính bản thân nó)

Trường này không cố định số lượng byte, tối đa 4 và tối thiểu 1. Bit cao nhất của byte sẽ xác định xem byte phía sau nó có thuộc Packet Length không ! Do đó chỉ có 7bit dùng để mã hóa dữ liệu


Ví dụ 1: Gói tin phía sau còn 31 byte thì ta chỉ cần 1 byte cho Packet Length
=> Packet Length = 0x1F

Ví dụ 2: Gói tin phía sau còn 321 byte thì ta sẽ cần 2 byte cho Packet Length với byte1 là byte thấp và byte2 là byte cao. Cứ mỗi giá trị của byte cao sẽ = 128 lần byte thấp. Ta tách 321 = 65 + 2*128

=> Packet Length = 0x41 0x02
Bit cao nhất của byte1 phải được set lên 1 để báo vẫn còn 1 byte nữa cho Packet Length nên phải sửa thành Packet Length = 0xC1 0x02

Với 4 byte Packet Length, ta sẽ mã hóa được tối đa 268,435,455 byte dữ liệu

FromTo
0 (0x00) 127 (0x7F)
28 (0x80, 0x01) 16 383 (0xFF, 0x7F)
16 384 (0x80, 0x80, 0x01) 2 097 151 (0xFF, 0xFF, 0x7F)
2 097 152 (0x80, 0x80, 0x80, 0x01) 268 435 455 (0xFF, 0xFF, 0xFF, 0x7F)

Tiếp tục tới trường thứ 3 là Variable length Header, nó gồm 4 trường nhỏ sau: Protocol Name, Protocol Level, Connect Flags, and Keep Alive

  • Protocol Name: (6byte) 0x00 0x04 0x4D 0x51 0x54 0x54
  • Protocol Level: (1byte) 0x04
  • Connect Flags: (1 byte) 0x??
  • Keep Alive: (2 byte) 0x?? 0x??

Các bạn chỉ cần quan tâm tới Connect Flags
Cấu trúc của nó như sau:

Bit 1 chúng ta sẽ mặc định để bằng 1
Các bit khác các bạn xài cái nào thì set nó lên. Ví dụ mình không cần user, password thì chỉ cần 0x02 là ok, nếu set cái nào lên thì phải mô tả nó trong payload nhé

Payload là trường sẽ chứa các thông tin để phục vụ việc connect như ID_Client, User, Password. Thông tin trong trường này phải tuân thủ thứ tự sau:
Client ID -> Will Topic -> Will Message -> User Name -> Password

Chú ý: Ở trên byte Connect Flags cái nào không set thì bỏ qua nó trong Payload nhé !

Còn Keep Alive là 2 byte chứa thời gian được tính bằng giây. Đó là khoảng thời gian tối đa được phép trôi qua giữa điểm mà Client hoàn thành việc truyền một Control Packet và điểm mà nó bắt đầu gửi tiếp theo. Nói chung cứ để từ 10 đến 60s tùy các bạn

Dưới đây là 1 ví dụ về 1 gói tin connect vào broker với Client id là IOT47 và không sử dụng tên user lẫn password

0x10 0x11 0x00 0x04 0x4D 0x51 0x54 0x54 0x04 0x02 0x00 0x3C 0x00 0x05 0x49 0x4F 0x54 0x34 0x37

Trong đó:

0x10 là Control Header
0x11 = 17 là trường Packet Length báo phía sau nó có 17 byte
0x00 0x04 0x4D 0x51 0x54 0x54 là Protocol Name thuộc trường Variable length Header
0x04 là Protocol Level
0x02 là Connect Flag
0x00 0x3C là Keep Alive mình để 60 giây
0x00 0x05 0x49 0x4F 0x54 0x34 0x37 là gói Packet, với 0x05 ám chỉ phía sau nó có 5byte data. Do Connect Flag mình để 0x02 ( tức không xài user name, pasword hay gì hết) nên thông tin ở packet chỉ cần id client là được (với id client là IOT47 = 0x49 0x4F 0x54 0x34 0x37 ) ( id client là bắt buộc phải có nha, nó là gì cũng được tùy các bạn)

Publish – gửi 1 tin nhắn đến 1 topic

Cấu trúc như sau

1byte Control Header = 0x30
1 đến 4 byte Packet Length
1 byte 0x00
1byte chứa độ dài của topic
còn lại là nội dung của tin nhắn

Ví dụ: mình sẽ publish tin nhắn tới topic ESP8266_sent_data và nội dung là xinchao

0x30 0x1A 0x00 0x11 0x45 0x53 0x50 0x38 0x32 0x36 0x36 0x5F 0x73 0x65 0x6E 0x74 0x5F 0x64 0x61 0x74 0x61 0x78 0x69 0x6E 0x63 0x68 0x61 0x6F

Trong đó:

0x30 là Control Header
0x1A = 26 là số lượng byte phía sau
0x11 = 17 là độ dài của topic
0x45 0x53 0x50 0x38 0x32 0x36 0x36 0x5F 0x73 0x65 0x6E 0x74 0x5F 0x64 0x61 0x74 0x61 = ESP8266_sent_data là tên của topic
0x78 0x69 0x6E 0x63 0x68 0x61 0x6F = xinchao là nội dung tin nhắn

Subscriber – đăng kí nhận tin nhắn từ 1 topic

Cấu trúc như sau

1byte Control Header = 0x82
1 đến 4 byte Packet Length
1 byte 0x00 và 1 byte 0x01 (Variable header)
1 byte 0x00
1byte chứa độ dài của topic
1 byte 0x00

Ví dụ, mình sẽ đăng kí topic ESP8266_read_data

0x82 0x16 0x00 0x01 0x00 0x11 0x45 0x53 0x50 0x38 0x32 0x36 0x36 0x5F 0x72 0x65 0x61 0x64 0x5F 0x64 0x61 0x74 0x61 0x00

Trong đó:

1byte Control Header = 0x82
0x16 = 22 là số lượng byte phía sau
0x11 = 17 là độ dài của topic
0x45 0x53 0x50 0x38 0x32 0x36 0x36 0x5F 0x72 0x65 0x61 0x64 0x5F 0x64 0x61 0x74 0x61 = ESP8266_read_data là tên của topic

Mình đã giới thiệu qua 1 vài cấu trúc cơ bản để làm việc với MQTT, các bạn tự tìm hiểu thêm ở đây nhé !
https://docs.solace.com/MQTT-311-Prtl-Conformance-Spec/MQTT%20Control%20Packet%20format.htm

DEMO giao tiếp MQTT với tập lệnh AT Command

Trước tiên chúng ta sẽ test bằng cách gửi thủ công bằng tay qua phần mềm Hercules luôn nhé

Các bạn chuẩn bị

Hoặc sử dụng module esp8266 node-MCU cho nó tiện, chỉ việc cắm dây usb vào là xong, bao nhanh bao phê

Nhắc lại 1 vài lệnh cơ bản ở bài 2

AT+CWJAP=”IOT47″,”12345678″<CR><LF> //kết nối vào wifi nhà bạn
AT+CWMODE=1<CR><LF> // yêu cầu module hoạt động ở chế độ Station/Client
AT+CIPMUX=0<CR><LF>
ATE0<CR><LF> //tắt chế độ phản hồi ngứa mắt

Các bạn gọi các lệnh cơ bản phía trên để khởi tạo module trước nhé ! <CR><LF> là 2 byte 0x0D 0x0A hay \r\n dấy nhé ! Trên phần mềm Hercules thì là $0D$0A

Còn đây là lệnh cho giao thức TCP mà chúng ta sẽ dùng để phục cho các kết nối MQTT
AT+CIPSTART=”TCP”,”yourserver.com”,80<CR><LF> // khởi động 1 kết nối TCP đến server nào đó ở 1 port nào đó (ví dụ ở đây là cổng 80)
AT+CIPSEND=X<CR><LF> // bắt đầu gửi 1 gói tin TCP với độ dài X

Ở demo này, mình kết nối tới broker MQTT là broker.hivemq.com và cổng sử dụng là 1883 – đây là cổng chuyên dụng cho các kết nối TCP. Do broker.hivemq.com là broker free không bảo mật nên chúng ta không cần user và password gì sất 🙂

Các bạn có thể thử với mã html mình đã viết và hướng dẫn ở bài 7 hoặc mình sẽ show giao diện web đó trực tiếp ở đây cho các bạn test luôn

Demo MQTT

Điều khiển thiết bị qua WIFI - MQTT

Tin nhắn từ esp8266: ...

Note pad của mình đây nhé:
//kết nối tới broker mqtt
AT+CIPSTART="TCP","broker.hivemq.com",1883$0D$0A
// kết nối tới broker
AT+CIPSEND=19$0D$0A
$10$11$00$04$4D$51$54$54$04$02$00$3C$00$05$49$4F$54$34$37

//gửi tin nhắn xinchao tới topic ESP8266_sent_data
AT+CIPSEND=28$0D$0A
$30$1A$00$11$45$53$50$38$32$36$36$5F$73$65$6E$74$5F$64$61$74$61$78$69$6E$63$68$61$6F

//đăng kí nhận tin nhắn từ topic ESP8266_read_data
AT+CIPSEND=24$0D$0A
$82$16$00$01$00$11$45$53$50$38$32$36$36$5F$72$65$61$64$5F$64$61$74$61$00

Lập trình giao tiếp Arduino với esp8266 qua tập lệnh AT - giao thức MQTT điều khiển 4 thiết bị

Kết nối

ArduinoESP8266
3.3V3.3V
GNDGND
RX TX
TX RX

Giống như bài 3, mình sẽ sử dụng phần mềm mô phỏng proteus để giao tiếp arduino ảo với esp8266 thật thông qua cổng COMPIM ( nghèo quá không có tiền mua arduino 🙂 )

Sơ đồ kết nối

Mình thêm 2 cái virtul terminal để debug dữ liệu vào ra trên cổng UART

Lập trình

Hàm ESP8266_SendCommand có nhiệm vụ gửi 1 AT command tới cho esp8266 và chờ cho tới khi trả về value, mình cũng cho thêm 1 cái timeout để thoái ra khi hết thời gian chờ

Hàm ESP82666_init sẽ khởi tạo module esp8266 và trả về err_code nếu gặp phải lỗi

Tiếp tục là hàm khởi tạo giao thức MQTT

FULL code arduino, các bạn tự ngâm cứu nhé

Demo mô mô phỏng trên proteus

Chú ý: Các bạn tự viết thêm hàm pulish tương tự nhé, và phải thường xuyên gửi gói tin keep alive để giữ kết nối với broker

Download

Các bạn có thể tài về project tại đây
https://drive.google.com/open?id=1Pi-MqD1HbaRWmgQhB6Kbmwe4dpg6SDjf

 

Từ tác giả:

Nếu có bất kì thắc mắc nào trong bài viết, vui lòng để lại comment dưới mỗi bài ! Mình sẽ không trả lời thắc mắc của các bạn ở facebook hay email !

Nếu trong phần code bạn nhìn thấy nhưng thứ kiểu như &amp; thì đó là lỗi hiển thị, cụ thể 3 kí tự < > & bị biến đổi thành như thế
&amp; là &
&lt;  là <
&gt; là >

Giới thiệu Đào Nguyện 80 bài viết
DIY,chế cháo, viết blog chia sẽ kiến thức về lập trình,điện tử - IoT. Rất mong được giao lưu, kết bạn với các bạn cùng đam mê. Địa chỉ Facebook: https://www.facebook.com/nguyendao207

1 bình luận

  1. Em chào anh! Tập lệnh AT commands có hỗ trợ AT+MQTT, anh đã từng làm qua chưa ạ? Em đã test nhưng hiện vẫn đang lỗi. Với cả trong phần anh làm, tại sao phải đổi ASCII sang HEX ở một số chỗ ạ?

Đã đóng bình luận.