大家好,我是ST!
上次給大家分享了如何使用ESP32實(shí)現(xiàn)藍(lán)牙通信,今天跟大家聊聊如何使用ESP32連接騰訊云實(shí)現(xiàn)遠(yuǎn)程控制。本次實(shí)驗(yàn)用到MQTT協(xié)議,同樣,我用miropython編寫(xiě)程序?qū)崿F(xiàn),最終可以通過(guò)騰訊連連微信小程序添加設(shè)備來(lái)發(fā)布主題消息給騰訊云,ESP32負(fù)責(zé)訂閱騰訊云主題消息,當(dāng)收到某訂閱消息時(shí),來(lái)控制ESP32設(shè)備上LED燈的亮滅。
第一步、創(chuàng)建騰訊云產(chǎn)品和設(shè)備
瀏覽器搜索【騰訊云】,進(jìn)入騰訊云官網(wǎng),微信注冊(cè)登錄
點(diǎn)擊【產(chǎn)品】搜索【物聯(lián)網(wǎng)開(kāi)發(fā)平臺(tái)】,點(diǎn)擊【管理控制臺(tái)】
在實(shí)例管理中點(diǎn)擊【公共實(shí)例】
點(diǎn)擊【新建項(xiàng)目】
填寫(xiě)自己的項(xiàng)目名稱(chēng),點(diǎn)擊【保存】
點(diǎn)擊剛新建的項(xiàng)目
點(diǎn)擊【新建產(chǎn)品】
輸入自己定義的【產(chǎn)品名稱(chēng)】,【產(chǎn)品類(lèi)別】選智慧城市->公共事業(yè)->路燈照明,【通信設(shè)備】填wi-fi,其他的默認(rèn),點(diǎn)擊【確定】
點(diǎn)擊自己剛新建的產(chǎn)品名稱(chēng)
下拉到最后點(diǎn)擊【下一步】
點(diǎn)擊【基于模組開(kāi)發(fā)】,產(chǎn)品平臺(tái)選擇【樂(lè)鑫】,類(lèi)型選擇【wifi】,點(diǎn)擊【樂(lè)鑫ESP-WROOM-】點(diǎn)擊【確定】
下拉到最后,點(diǎn)擊【下一步】
點(diǎn)擊【產(chǎn)品展示配置】右側(cè)的【配置】
【產(chǎn)品展示名稱(chēng)】填寫(xiě)自己自定義的名稱(chēng),【廠家名稱(chēng)】填安信可,【產(chǎn)品信號(hào)】填esp32,點(diǎn)擊【保存】,上拉點(diǎn)擊【<-】返回
點(diǎn)擊【快捷入口配置】右側(cè)的【配置】,默認(rèn)不修改,點(diǎn)擊【保存】,上拉點(diǎn)擊【<-】返回
點(diǎn)擊【面板配置】右側(cè)的【配置】,默認(rèn)不修改,點(diǎn)擊【保存】,點(diǎn)擊【<-】返回
點(diǎn)擊【配網(wǎng)引導(dǎo)】右側(cè)的【配置】,【芯片方案選擇】選擇樂(lè)鑫,【首選配網(wǎng)方式】選擇Smart Config,【次配網(wǎng)方式】選擇Soft Ap,點(diǎn)擊;【保存】,點(diǎn)擊【<-】返回
點(diǎn)擊【掃一掃產(chǎn)品介紹】右側(cè)的【配置】,默認(rèn)不修改,點(diǎn)擊【保存】,點(diǎn)擊【<-】返回
點(diǎn)擊【智能聯(lián)動(dòng)配置】右側(cè)的【配置】,默認(rèn)不修改,點(diǎn)擊保存,點(diǎn)擊【<-】返回
點(diǎn)擊【下一步】
點(diǎn)擊【新建設(shè)備】,自定義【設(shè)備名稱(chēng)】,點(diǎn)擊【保存】
點(diǎn)擊【二維碼】,用手機(jī)微信小程序【騰訊連連】掃碼添加設(shè)備
此時(shí)設(shè)備已經(jīng)創(chuàng)建完成,但是設(shè)備還未激活,需要后面的的操作連接才可激活
第二步:生成Username和Password
點(diǎn)擊【設(shè)備調(diào)試】,點(diǎn)擊【設(shè)備名稱(chēng)】
復(fù)制保存設(shè)備信息三件套:設(shè)備名稱(chēng)、產(chǎn)品ID、設(shè)備密鑰
后面生成MOTT協(xié)議中的Username和Password需要用到
打開(kāi)password生成工具,在文件夾里有給出,點(diǎn)擊【sign.html】
輸入剛剛復(fù)制的設(shè)備信息三件套,Hmac簽名算法選擇【HMAC-SHA1】,點(diǎn)擊【Generate】,即可生成Usename和Password,復(fù)制保存,后面esp32連接騰訊云和MQTTfx模擬的客戶(hù)端連接騰訊云需要用到
第三步:MQTTfx模擬客戶(hù)端連接騰訊云步驟與調(diào)試(非必須步驟)
打開(kāi)MQTT.fx軟件,我的壓縮包里面有,點(diǎn)擊下圖的齒輪圖形,進(jìn)入設(shè)置
【Profile name】:自定義的名字
【Profile Type】:選擇【MQTT Broker】
【Broker Address】:騰訊云三件套中的產(chǎn)品ID+.iotcloud.tencentdevices.com
如我的騰訊云ID為:D89S2VVAFT,
那么Broker Address為:D89S2VVAFT.iotcloud.tencentdevices.com
Broker Port:1883
【Client ID】:騰訊云產(chǎn)品ID+騰訊云設(shè)備名稱(chēng)+|securemode=3,signmethod=hmacsha1|
例如我的騰訊云產(chǎn)品ID為:D89S2VVAFT,騰訊云產(chǎn)品名稱(chēng)為:esp_led
則Client ID為:D89S2VVAFTesp_led|securemode=3,signmethod=hmacsha1|
填寫(xiě)這些數(shù)據(jù)完畢后,點(diǎn)擊【User Credentlals】
User Name和Password填寫(xiě)第二步生成的,每個(gè)人的都不一樣
【User Name】:D89S2VVAFTesp_led;12010126;CU7SQ;1660090317
【Password】:cd6c31a3d4cfdba2759deab02fb831a0f672e008;hmacsha1
點(diǎn)擊【OK】保存
點(diǎn)擊【Connect】連接騰訊云
MQTT.fx模擬的客戶(hù)端連接騰訊云成功后可以看到右邊的原點(diǎn)變綠,并且有個(gè)打開(kāi)的所,
這時(shí)候我們就可以通過(guò)手機(jī)端小程序騰訊連連來(lái)給騰訊云發(fā)送消息,騰訊云再將此消息發(fā)送給MQTT.fx客戶(hù)端,但是前提是MQTT.fx客戶(hù)端需要訂閱騰訊云,下面是訂閱的步驟
點(diǎn)擊【Subscribe】,Subscribe左邊的空格填寫(xiě)格式為:
$thing/down/property/“騰訊云產(chǎn)品ID”/“騰訊云產(chǎn)品名稱(chēng)”
例如:$thing/down/property/D89S2VVAFT/esp_led
填寫(xiě)完成后,點(diǎn)擊【Subscribe】,現(xiàn)在手機(jī)端騰訊練練發(fā)送消息,MQTT.fx可以收到消息了
可以看到MQTT.fx收到了消息,MQTT.fx只是模擬一個(gè)客戶(hù)端接收消息,我們需要將我們的esp32模塊替代MQTT.fx,這樣我們就可以通過(guò)手機(jī)發(fā)送消息給騰訊云,騰訊云轉(zhuǎn)發(fā)消息給esp32模塊了,通過(guò)單片機(jī)對(duì)收到的數(shù)據(jù)處理,就可以通過(guò)手機(jī)端控制開(kāi)發(fā)板的LED燈亮滅。
第四步、編寫(xiě)程序代碼
首先需要用到MQTT的驅(qū)動(dòng)代碼,我在網(wǎng)上找到了一個(gè)用miropython寫(xiě)的驅(qū)動(dòng)代碼,大家可以直接復(fù)制使用,命名為umqttsimple.py即可,代碼如下:
import usocket as socket import ustruct as struct from ubinascii import hexlify class MQTTException(Exception): pass class MQTTClient: def __init__( self, client_id, server, port=0, user=None, password=None, keepalive=0, ssl=False, ssl_params={}, ): if port == 0: port = 8883 if ssl else 1883 self.client_id = client_id self.sock = None self.server = server self.port = port self.ssl = ssl self.ssl_params = ssl_params self.pid = 0 self.cb = None self.user = user self.pswd = password self.keepalive = keepalive self.lw_topic = None self.lw_msg = None self.lw_qos = 0 self.lw_retain = False def _send_str(self, s): self.sock.write(struct.pack("!H", len(s))) self.sock.write(s) def _recv_len(self): n = 0 sh = 0 while 1: b = self.sock.read(1)[0] n |= (b & 0x7F) << sh if not b & 0x80: return n sh += 7 def set_callback(self, f): self.cb = f def set_last_will(self, topic, msg, retain=False, qos=0): assert 0 <= qos <= 2 assert topic self.lw_topic = topic self.lw_msg = msg self.lw_qos = qos self.lw_retain = retain def connect(self, clean_session=True): self.sock = socket.socket() addr = socket.getaddrinfo(self.server, self.port)[0][-1] self.sock.connect(addr) if self.ssl: import ussl self.sock = ussl.wrap_socket(self.sock, **self.ssl_params) premsg = bytearray(b"x10") msg = bytearray(b"x04MQTTx04x02") sz = 10 + 2 + len(self.client_id) msg[6] = clean_session << 1 if self.user is not None: sz += 2 + len(self.user) + 2 + len(self.pswd) msg[6] |= 0xC0 if self.keepalive: assert self.keepalive < 65536 msg[7] |= self.keepalive >> 8 msg[8] |= self.keepalive & 0x00FF if self.lw_topic: sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 msg[6] |= self.lw_retain << 5 i = 1 while sz > 0x7F: premsg[i] = (sz & 0x7F) | 0x80 sz >>= 7 i += 1 premsg[i] = sz self.sock.write(premsg, i + 2) self.sock.write(msg) # print(hex(len(msg)), hexlify(msg, ":")) self._send_str(self.client_id) if self.lw_topic: self._send_str(self.lw_topic) self._send_str(self.lw_msg) if self.user is not None: self._send_str(self.user) self._send_str(self.pswd) resp = self.sock.read(4) assert resp[0] == 0x20 and resp[1] == 0x02 if resp[3] != 0: raise MQTTException(resp[3]) return resp[2] & 1 def disconnect(self): self.sock.write(b"xe0") self.sock.close() def ping(self): self.sock.write(b"xc0") def publish(self, topic, msg, retain=False, qos=0): pkt = bytearray(b"x30") pkt[0] |= qos << 1 | retain sz = 2 + len(topic) + len(msg) if qos > 0: sz += 2 assert sz < 2097152 i = 1 while sz > 0x7F: pkt[i] = (sz & 0x7F) | 0x80 sz >>= 7 i += 1 pkt[i] = sz # print(hex(len(pkt)), hexlify(pkt, ":")) self.sock.write(pkt, i + 1) self._send_str(topic) if qos > 0: self.pid += 1 pid = self.pid struct.pack_into("!H", pkt, 0, pid) self.sock.write(pkt, 2) self.sock.write(msg) if qos == 1: while 1: op = self.wait_msg() if op == 0x40: sz = self.sock.read(1) assert sz == b"x02" rcv_pid = self.sock.read(2) rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] if pid == rcv_pid: return elif qos == 2: assert 0 def subscribe(self, topic, qos=0): assert self.cb is not None, "Subscribe callback is not set" pkt = bytearray(b"x82") self.pid += 1 struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) # print(hex(len(pkt)), hexlify(pkt, ":")) self.sock.write(pkt) self._send_str(topic) self.sock.write(qos.to_bytes(1, "little")) while 1: op = self.wait_msg() if op == 0x90: resp = self.sock.read(4) # print(resp) assert resp[1] == pkt[2] and resp[2] == pkt[3] if resp[3] == 0x80: raise MQTTException(resp[3]) return # Wait for a single incoming MQTT message and process it. # Subscribed messages are delivered to a callback previously # set by .set_callback() method. Other (internal) MQTT # messages processed internally. def wait_msg(self): res = self.sock.read(1) self.sock.setblocking(True) if res is None: return None if res == b"": raise OSError(-1) if res == b"xd0": # PINGRESP sz = self.sock.read(1)[0] assert sz == 0 return None op = res[0] if op & 0xF0 != 0x30: return op sz = self._recv_len() topic_len = self.sock.read(2) topic_len = (topic_len[0] << 8) | topic_len[1] topic = self.sock.read(topic_len) sz -= topic_len + 2 if op & 6: pid = self.sock.read(2) pid = pid[0] << 8 | pid[1] sz -= 2 msg = self.sock.read(sz) self.cb(topic, msg) if op & 6 == 2: pkt = bytearray(b"x40x02") struct.pack_into("!H", pkt, 2, pid) self.sock.write(pkt) elif op & 6 == 4: assert 0 # Checks whether a pending message from server is available. # If not, returns immediately with None. Otherwise, does # the same processing as wait_msg. def check_msg(self): self.sock.setblocking(False) return self.wait_msg()
主程序代碼如下:
import time import network from umqttsimple import MQTTClient from machine import Pin,Timer def do_connect(): wlan = network.WLAN(network.STA_IF) wlan.active(True) if not wlan.isconnected(): print('connecting to network...') wlan.connect('11', '1234567a') i = 1 while not wlan.isconnected(): print("正在鏈接...{}".format(i)) i += 1 time.sleep(1) print('network config:', wlan.ifconfig()) def sub_cb(topic, msg): # 回調(diào)函數(shù),收到服務(wù)器消息后會(huì)調(diào)用這個(gè)函數(shù) print(topic, msg) top=str(topic,'UTF-8') strdata=str(msg,'UTF-8') count=strdata.find("power_switch") print(strdata[count+len("power_switch")+2]) if strdata[count+len("power_switch")+2]=='0' and top=='$thing/down/property/D89S2VVAFT/esp_led': led.value(1) if strdata[count+len("power_switch")+2]=='1' and top=='$thing/down/property/D89S2VVAFT/esp_led': led.value(0) #客戶(hù)端ID client_id="D89S2VVAFTesp_led|securemode=3,signmethod=hmacsha1|" #服務(wù)器域名 addr="D89S2VVAFT.iotcloud.tencentdevices.com" #端口號(hào) port=1883 #用戶(hù)名 username="D89S2VVAFTesp_led;12010126;KTXHT;1669512546" #密碼 password="0569df86e0c75494960cc922703c9ddd47c3fee048ed03d6b1a22d89a8b8a305;hmacsha256" led=Pin(22,Pin.OUT) led.value(1) # 1. 聯(lián)網(wǎng) do_connect() # 2. 創(chuàng)建mqt c = MQTTClient(client_id=client_id,server=addr,port=port,user=username,password=password,keepalive=60) # 建立一個(gè)MQTT客戶(hù)端 c.set_callback(sub_cb) # 設(shè)置回調(diào)函數(shù) c.connect() # 建立連接 c.subscribe(b"$thing/down/property/D89S2VVAFT/esp_led") # 監(jiān)控ledctl這個(gè)通道,接收控制命令 timer1 = Timer(0) timer1.init(period=1000*60, mode=Timer.PERIODIC, callback=lambda t: c.ping()) while True: c.check_msg()
點(diǎn)擊編譯,編譯成功如下
查看騰訊云建立的設(shè)備,可以看到,此時(shí)設(shè)備已經(jīng)在線(xiàn)
點(diǎn)擊二維碼,打開(kāi)騰訊連連小程序,掃碼添加設(shè)備
現(xiàn)在就可以通過(guò)騰訊連連來(lái)控制ESP32設(shè)備啦!點(diǎn)擊點(diǎn)燈開(kāi)關(guān),ESP32設(shè)備打印出收到的消息,如下:
審核編輯:湯梓紅
-
遠(yuǎn)程控制
+關(guān)注
關(guān)注
4文章
617瀏覽量
34883 -
騰訊云
+關(guān)注
關(guān)注
0文章
207瀏覽量
16744 -
MQTT
+關(guān)注
關(guān)注
5文章
647瀏覽量
22392 -
ESP32
+關(guān)注
關(guān)注
17文章
950瀏覽量
16992
原文標(biāo)題:使用ESP32連接騰訊云實(shí)現(xiàn)遠(yuǎn)程控制
文章出處:【微信號(hào):嵌入式開(kāi)發(fā)愛(ài)好者,微信公眾號(hào):嵌入式開(kāi)發(fā)愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論