大家好,上次给大家分享了如何使用ESP32实现蓝牙通信,今天跟大家聊聊如何使用ESP32连接腾讯云实现远程控制。本次实验用到MQTT协议,同样,我用miropython编写程序实现,最终可以通过腾讯连连微信小程序添加设备来发布主题消息给腾讯云,ESP32负责订阅腾讯云主题消息,当收到某订阅消息时,来控制ESP32设备上LED灯的亮灭。
目录
第一步、创建腾讯云产品和设备
第二步:生成Username和Password
第三步:MQTTfx模拟客户端连接腾讯云步骤与调试(非必须步骤)
第四步、编写程序代码
本次实验资料
第一步、创建腾讯云产品和设备
浏览器搜索【腾讯云】,进入腾讯云官网,微信注册登录
点击【产品】搜索【物联网开发平台】,点击【管理控制台】
在实例管理中点击【公共实例】
点击【新建项目】
填写自己的项目名称,点击【保存】
点击刚新建的项目
点击【新建产品】
输入自己定义的【产品名称】,【产品类别】选智慧城市->公共事业->路灯照明,【通信设备】填wi-fi,其他的默认,点击【确定】
点击自己刚新建的产品名称
下拉到最后点击【下一步】
点击【基于模组开发】,产品平台选择【乐鑫】,类型选择【wifi】,点击【乐鑫ESP-WROOM-】点击【确定】
下拉到最后,点击【下一步】
点击【产品展示配置】右侧的【配置】
【产品展示名称】填写自己自定义的名称,【厂家名称】填安信可,【产品信号】填esp32,点击【保存】,上拉点击【<-】返回
点击【快捷入口配置】右侧的【配置】,默认不修改,点击【保存】,上拉点击【<-】返回
点击【面板配置】右侧的【配置】,默认不修改,点击【保存】,点击【<-】返回
点击【配网引导】右侧的【配置】,【芯片方案选择】选择乐鑫,【首选配网方式】选择Smart Config,【次配网方式】选择Soft Ap,点击;【保存】,点击【<-】返回
点击【扫一扫产品介绍】右侧的【配置】,默认不修改,点击【保存】,点击【<-】返回
点击【智能联动配置】右侧的【配置】,默认不修改,点击保存,点击【<-】返回
点击【下一步】
点击【新建设备】,自定义【设备名称】,点击【保存】
点击【二维码】,用手机微信小程序【腾讯连连】扫码添加设备
此时设备已经创建完成,但是设备还未激活,需要后面的的操作连接才可激活
第二步:生成Username和Password
点击【设备调试】,点击【设备名称】
复制保存设备信息三件套:设备名称、产品ID、设备密钥
后面生成MOTT协议中的Username和Password需要用到
打开password生成工具,在文件夹里有给出,点击【sign.html】
输入刚刚复制的设备信息三件套,Hmac签名算法选择【HMAC-SHA1】,点击【Generate】,即可生成Usename和Password,复制保存,后面esp32连接腾讯云和MQTTfx模拟的客户端连接腾讯云需要用到
第三步:MQTTfx模拟客户端连接腾讯云步骤与调试(非必须步骤)
打开MQTT.fx软件,我的压缩包里面有,点击下图的齿轮图形,进入设置
【Profile name】:自定义的名字
【Profile Type】:选择【MQTT Broker】
【Broker Address】:腾讯云三件套中的产品ID+.
如我的腾讯云ID为:D89S2VVAFT,
那么Broker Address为:D89S2VVAFT.
Broker Port:1883
【Client ID】:腾讯云产品ID+腾讯云设备名称+|securemode=3,signmethod=hmacsha1|
例如我的腾讯云产品ID为:D89S2VVAFT,腾讯云产品名称为:esp_led
则Client ID为:D89S2VVAFTesp_led|securemode=3,signmethod=hmacsha1|
填写这些数据完毕后,点击【User Credentlals】
User Name和Password填写第二步生成的,每个人的都不一样
【User Name】:D89S2VVAFTesp_led;1126;CU7SQ;1660090317
【Password】:cd6c31a3d4cfdba2759deab02fb831a0f672e008;hmacsha1
点击【OK】保存
点击【Connect】连接腾讯云
MQTT.fx模拟的客户端连接腾讯云成功后可以看到右边的原点变绿,并且有个打开的所,
这时候我们就可以通过手机端小程序腾讯连连来给腾讯云发送消息,腾讯云再将此消息发送给MQTT.fx客户端,但是前提是MQTT.fx客户端需要订阅腾讯云,下面是订阅的步骤
点击【Subscribe】,Subscribe左边的空格填写格式为:
$thing/down/property/“腾讯云产品ID”/“腾讯云产品名称”
例如:$thing/down/property/D89S2VVAFT/esp_led
填写完成后,点击【Subscribe】,现在手机端腾讯练练发送消息,MQTT.fx可以收到消息了
可以看到MQTT.fx收到了消息,MQTT.fx只是模拟一个客户端接收消息,我们需要将我们的esp32模块替代MQTT.fx,这样我们就可以通过手机发送消息给腾讯云,腾讯云转发消息给esp32模块了,通过单片机对收到的数据处理,就可以通过手机端控制开发板的LED灯亮灭。
第四步、编写程序代码
首先需要用到MQTT的驱动代码,我在网上找到了一个用miropython写的驱动代码,大家可以直接复制使用,命名为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\0\0\0\0\0")
msg = bytearray(b"\x04MQTT\x04\x02\0\0")
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\0")
self.sock.close()
def ping(self):
self.sock.write(b"\xc0\0")
def publish(self, topic, msg, retain=False, qos=0):
pkt = bytearray(b"\x30\0\0\0")
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\0\0\0")
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"\x40\x02\0\0")
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): # 回调函数,收到服务器消息后会调用这个函数
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)
#客户端ID
client_id="D89S2VVAFTesp_led|securemode=3,signmethod=hmacsha1|"
#服务器域名
addr="D89S2VVAFT."
#端口号
port=1883
#用户名
username="D89S2VVAFTesp_led;1126;KTXHT;1669512546"
#密码
password="0569df86e0c75494960cc922703c9ddd47c3fee048ed03d6b1a22d89a8b8a305;hmacsha256"
led=Pin(22,Pin.OUT)
led.value(1)
# 1. 联网
do_connect()
# 2. 创建mqt
c = MQTTClient(client_id=client_id,server=addr,port=port,user=username,password=password,keepalive=60) # 建立一个MQTT客户端
c.set_callback(sub_cb) # 设置回调函数
c.connect() # 建立连接
c.subscribe(b"$thing/down/property/D89S2VVAFT/esp_led") # 监控ledctl这个通道,接收控制命令
timer1 = Timer(0)
timer1.init(period=1000*60, mode=Timer.PERIODIC, callback=lambda t: c.ping())
while True:
c.check_msg()
点击编译,编译成功如下
查看腾讯云建立的设备,可以看到,此时设备已经在线
点击二维码,打开腾讯连连小程序,扫码添加设备
现在就可以通过腾讯连连来控制ESP32设备啦!点击点灯开关,ESP32设备打印出收到的消息,如下:
本次实验资料
链接:/s/1IoiBnT5zfXnL6BgP24XZcg
提取码:rwk1