micropython连接onenet实现从应用端调用api到设备端执行-汇总-CSDN博客
↑汇总
目录
我们要明确功能
(1)我们要上传数据即post
(2)我们也要set属性和处理set属性
1明确需求
2创建任务
3创建任务函数
4运行异步程序
5测试一下
micropython通过umqtt连接至onenet-设备直接读取设备信息-CSDN博客
上一篇↑
文末有完整代码直接用配合着理解,虽然简单但是怕出错
未注明作者,请勿转载
下一篇↓
我们上一步实现了micropython设备端的三大基本功能,即post数据到平台,set设备属性,get设备属性。本来应该直接配合我们第一步写的应用端的,但我们发现micropython的性能不够。
当我们在设备调试时:
多点几次属性设置就会出现属性设置失败,原因是我们post数据到平台是一个阻塞的过程,我们一直post就会导致程序一直阻塞在那,无法处理平台下发的set属性topic。导致回复超时,平台判断我们没有收到属性设置的命令。
有人选择调整post的频率,这样也不是不行,但主程序依然会卡在那。
这俩完全是一个异步的程序,即(1)阻塞时候我们就可以去处理(2)中的事情,没必要一直等着(1)来浪费时间,当(1)做完了平台会返回消息我们再去处理(1)即可。
这时候异步协程就非常好用
即async
搞过爬虫的朋友应该很熟悉了,线程池容易把网站搞死,协程相对于他已经是算温和的了。我用的这块esp32-s3是多核,各位大佬有兴趣可以取尝试使用多线程thread。我们这里使用携程就足够了。
python async这个大家建议去b站看一看视频在来看本篇文章,这个东西还是比较难理解的。看完再回来看本篇文章。
我们直接开始。
我们要把原来的俩个需求拆开来执行,即post数据一个,处理返回数据一个,总共俩个功能。
# 发送post数据
# client.Post_Data(brightness=get_sensor_data(),led=get_led_state())
#处理返回的程序
# try:
# while True:
#
# client.client.check_msg() # 检查是否有新的消息
# # 你可以在这里执行其他操作,例如读取传感器数据等
# print("Performing other tasks...")
# if replay_state_code == "reply":
# print("Post success")
# replay_state_code = None
# # break
# if replay_state_code =="set":
# wait_handle_msg = replay_msg
# replay_id = wait_handle_msg["id"]
# client.Set_replay(replay_id)
# params = wait_handle_msg.get("params", {})
# for key,value in params.items():
# if key =="led":
# print("+++++++++++++++++++++++++++++++++++++")
# replay_msg = None
# replay_state_code = None
# # break
# if replay_state_code == "get":
# wait_replay_msg = replay_msg
# get_replay_id = wait_replay_msg["id"]
# data={}
# for params in wait_replay_msg["params"]:
# if params=="brightness":
# data[params] = get_sensor_data()
# if params=="led":
# data[params] = get_led_state()
# # print(data)
# client.Get_replay(get_replay_id,data)
# print("Data has post to client")
# # print(data)
# replay_msg = None
# replay_state_code = None
#
#
# time.sleep(1)
# except KeyboardInterrupt:
# print("MQTT subscription stopped.")
# finally:
# client.client.disconnect()
我们要把这一部分拆开来执行。
导入模块 imort uasyncio
我们要创建这个任务
async def creat_tasks(client):
tasks = []
t1 = uasyncio.create_task(Regularly_upload_data(client,3))
t2 = uasyncio.create_task(Regularly_hanle_msg(client,1))
tasks.extend([t1, t2])
await uasyncio.gather(*tasks)
pass
创建一个任务列表用于存储任务,用uasyncio(micropython自带)的create_task方法创建任务,再将任务添加到任务列表里面传给uasyncio.gather()并用await挂起。
await的意义是:程序挂起任务,在程序执行此任务时一旦遇到阻塞就会去执行其他任务,这里是固定用法。
注意这一部里面用到了await挂起任务,所以我们就需要再def函数时加上async,这样才能识别我们的该程序是异步程序。
在2中我们已经看到俩个函数即
定义了俩个参数第一个是用来传递我们类对象的clinet即我们要post数据需要用到的类onenet中的post_data方法,第二个是间隔时间。
#处理平台返回数据函数
Regularly_hanle_msg(client,1)
#处理上传数据的函数
Regularly_upload_data(client,3)
然后我们来写这一部分函数
每个任务都是需要循环进行的,那么我们直接while起来。
然后这俩个任务需要挂起的所以都需要async一下。
然后我们把1中的俩个需求函数加进去。
之后我们需要找到阻塞(罪魁祸首)将他挂起(await)
很显然我们通过网络上传数据会阻塞,我们要挂起。
即
client.Post_Data()
client.Set_replay()
client.Get_replay()
还有time.sleep我们希望这个程序睡眠时候其他程序可以执行比如上传数据post。
time.sleep我们需要用到asyncio里面自带的睡眠sleep。
async def Regularly_upload_data(client,time):
while 1:
await client.Post_Data(brightness=get_sensor_data(),led=get_led_state())
await uasyncio.sleep(time);
pass
async def Regularly_hanle_msg(client,time):
global replay_state_code
global replay_msg
try:
while True:
client.client.check_msg() # 检查是否有新的消息
# 你可以在这里执行其他操作,例如读取传感器数据等
if replay_state_code == "reply":
print("Post success")
replay_state_code = None
# break
if replay_state_code =="set":
wait_handle_msg = replay_msg
replay_id = wait_handle_msg["id"]
await client.Set_replay(replay_id)
params = wait_handle_msg.get("params", {})
for key,value in params.items():
if key =="led":
print("+++++++++++++++++++++++++++++++++++++")
replay_msg = None
replay_state_code = None
# break
if replay_state_code == "get":
wait_replay_msg = replay_msg
get_replay_id = wait_replay_msg["id"]
data={}
for params in wait_replay_msg["params"]:
if params=="brightness":
data[params] = get_sensor_data()
if params=="led":
data[params] = get_led_state()
# print(data)
await client.Get_replay(get_replay_id,data)
print("Data has post to client")
# print(data)
replay_msg = None
replay_state_code = None
await uasyncio.sleep(time)
except KeyboardInterrupt:
print("MQTT subscription stopped.")
finally:
client.client.disconnect()
pass
然后我们发现
会报各种错误,即我们挂起时用到的函数已经被我们await挂起了,现在是异步程序,所以我们要在原函数的def前面加入async,表面这个函数我们是异步程序。
即在原方法onenet类里面在def前面加入async即可
async def Post_Data(self,**kwargs):
data = self.posts_data
data["id"] = str(random.randint(1,1000))
self.id = data["id"]
for key,value in kwargs.items():
data["params"][key] = {"value":value}
self.client.publish(self.post_topic,json.dumps(data))
print(data)
def Subscribe_topic(self,**kwargs):
for sub_topic,sub_topic_value in kwargs.items():
try:
self.client.subscribe(sub_topic_value)
print(f"Subscribed to {sub_topic}")
except:
print(f"Faile Subscribed to {sub_topic}!!!!")
pass
async def Set_replay(self,msg_id):
data = self.set_replay
data["id"] = msg_id
data = json.dumps(data)
self.client.publish(self.set_replay_topic,data)
print(data)
async def Get_replay(self,msg_id,replay_data):
data = self.get_replay
data["id"]=msg_id
data["data"]=replay_data
data = json.dumps(data)
self.client.publish(self.get_replay_topic,data)
print(data)
pass
uasyncio.run(creat_tasks(client))
在主要程序main中运行我们的异步任务,用uasyncio.run方法执行我们的创建函数任务即可
至此我们算是完成了所有的操作
依然用平台的调试工具
post执行没有问题
下发的指令也是可以的平台有收到set_replay且没有超时
我们现在的单片机已经可以在阻塞的时候处理其他程序了 下一步我们就要配合应用端的api来完整的进行物联网了。
import onenet_device_token
from umqtt.robust import MQTTClient
from wifi_connect import wifi
import time
import random
import json
import uasyncio
replay_msg = None
replay_state_code = None
token = None
ssid = "405"
password = "15980997653"
url = "mqtts.heclouds.com"
port = 1883
DeviceName = "stm32" # 设备ID
Productid = "xsH8t9odKK" # 产品ID
access_key = "ODg3MG9qOTdncEtoTmtVZHlNOVR3MGFwMjBUM2tsZ24=" # 秘钥
def main():
global replay_msg
global replay_state_code
token = onenet_device_token.get_token(Productid,DeviceName,access_key,time=1735971695)
print(token)
wlan = wifi(ssid = ssid,password = password)
client = ONENET(client_id=DeviceName,server=url,port=port,user=Productid,keepalive=100,password=token)
#设置回调函数(必须要)
client.client.set_callback(on_message)
client.Subscribe_topic(post_replay_topic="$sys/xsH8t9odKK/stm32/thing/property/post/reply")
client.Subscribe_topic(set_topic = "$sys/xsH8t9odKK/stm32/thing/property/set")
client.Subscribe_topic(get_topic = "$sys/xsH8t9odKK/stm32/thing/property/get")
uasyncio.run(creat_tasks(client))
# client.Post_Data(brightness=get_sensor_data(),led=get_led_state())
# try:
# while True:
#
# client.client.check_msg() # 检查是否有新的消息
# # 你可以在这里执行其他操作,例如读取传感器数据等
# print("Performing other tasks...")
# if replay_state_code == "reply":
# print("Post success")
# replay_state_code = None
# # break
# if replay_state_code =="set":
# wait_handle_msg = replay_msg
# replay_id = wait_handle_msg["id"]
# client.Set_replay(replay_id)
# params = wait_handle_msg.get("params", {})
# for key,value in params.items():
# if key =="led":
# print("+++++++++++++++++++++++++++++++++++++")
# replay_msg = None
# replay_state_code = None
# # break
# if replay_state_code == "get":
# wait_replay_msg = replay_msg
# get_replay_id = wait_replay_msg["id"]
# data={}
# for params in wait_replay_msg["params"]:
# if params=="brightness":
# data[params] = get_sensor_data()
# if params=="led":
# data[params] = get_led_state()
# # print(data)
# client.Get_replay(get_replay_id,data)
# print("Data has post to client")
# # print(data)
# replay_msg = None
# replay_state_code = None
#
#
# time.sleep(1)
# except KeyboardInterrupt:
# print("MQTT subscription stopped.")
# finally:
# client.client.disconnect()
class ONENET():
posts_data ={
"id": "123",
"version": "1.0",
"params": {}
}
set_replay ={
"id": "30",
"code": 200,
"msg": "succ"
}
get_replay = {
"id":"102",
"code":200,
"msg":"succ",
"data":{
}
}
# post_topic = f"$sys/{Productid}/{DeviceName}/thing/property/post" pub
# post_replay_topic =f"$sys/{Productid}/{DeviceName}/thing/property/post/reply" sub
# set_topic = "$sys/{Productid}/{DeviceName}/thing/property/set" sub
# set_replay_topic = "$sys/{Productid}/{DeviceName}/thing/property/set_reply" pub
# get_topic = "$sys/{Productid}/{DeviceName}/thing/property/get" sub
# get_replay_topic = f"$sys/{Productid}/{DeviceName}/thing/property/get_reply" pub
#======================================================================================
#作者:trashedmaker
#开源文件,未注明请勿转载
#原文链接:https://blog.csdn.net/m0_73949172/article/details/144929662?spm=1001.2014.3001.5501
#======================================================================================
def __init__(self,client_id,server,port,user,keepalive,password):
self.client_id = client_id
self.server = server
self.port = port
self.user = user
self.keepalive = keepalive
self.password = password
self.client =self.connect_mqtt(self.password)
self.id = None
self.post_topic = f"$sys/{user}/{client_id}/thing/property/post"
self.set_replay_topic = f"$sys/{user}/{client_id}/thing/property/set_reply"
self.get_replay_topic = f"$sys/{user}/{client_id}/thing/property/get_reply"
def connect_mqtt(self,token):
client = MQTTClient(client_id=self.client_id,server=self.server,port=self.port,user=self.user,keepalive=self.keepalive,password=self.password)
while 1:
try:
client.connect()
print('Has Connected to OneNET')
break
# 0 CONNECTION_ACCEPTED - 连接成功
# 1 CONNECTION_REFUSED_PROTOCOL_VERSION - 版本号错误
# 2 CONNECTION_REFUSED_IDENTIFIER_REJECTED - 连接标识符被拒绝
# 3 CONNECTION_REFUSED_SERVER_UNAVAILABLE - 服务器不可用
# 4 CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD - 错误的用户名或密码
# 5 CONNECTION_REFUSED_NOT_AUTHORIZED - 没有权限
except Exception as e: # 捕获所有异常
print(f"Something went wrong: Wrong code is {e}") # 打印错误信息
print("We are trying again...")
time.sleep(1) # 等待 1 秒后重新尝试连接
return client
async def Post_Data(self,**kwargs):
data = self.posts_data
data["id"] = str(random.randint(1,1000))
self.id = data["id"]
for key,value in kwargs.items():
data["params"][key] = {"value":value}
self.client.publish(self.post_topic,json.dumps(data))
print(data)
def Subscribe_topic(self,**kwargs):
for sub_topic,sub_topic_value in kwargs.items():
try:
self.client.subscribe(sub_topic_value)
print(f"Subscribed to {sub_topic}")
except:
print(f"Faile Subscribed to {sub_topic}!!!!")
pass
async def Set_replay(self,msg_id):
data = self.set_replay
data["id"] = msg_id
data = json.dumps(data)
self.client.publish(self.set_replay_topic,data)
print(data)
async def Get_replay(self,msg_id,replay_data):
data = self.get_replay
data["id"]=msg_id
data["data"]=replay_data
data = json.dumps(data)
self.client.publish(self.get_replay_topic,data)
print(data)
pass
#回复的消息topic和msg都是b""需要decode一下
def on_message(topic, msg):
topic = topic.decode('utf-8')
msg = json.loads(msg.decode('utf-8'))
global replay_msg
global replay_state_code
topic = topic.split("/")[-1]
if topic == "reply":
if msg["msg"] == "success":
replay_state_code = topic
if topic == "set":
replay_state_code = topic
replay_msg = msg
if topic == "get":
replay_state_code = topic
replay_msg = msg
print(msg)
def get_sensor_data():
data = random.randint(0,100)
return data
def get_led_state():
data = random.randint(0,1)
if data == 1:
return True
else:
return False
async def Regularly_upload_data(client,time):
while 1:
await client.Post_Data(brightness=get_sensor_data(),led=get_led_state())
await uasyncio.sleep(time);
pass
async def Regularly_hanle_msg(client,time):
global replay_state_code
global replay_msg
try:
while True:
client.client.check_msg() # 检查是否有新的消息
# 你可以在这里执行其他操作,例如读取传感器数据等
if replay_state_code == "reply":
print("Post success")
replay_state_code = None
# break
if replay_state_code =="set":
wait_handle_msg = replay_msg
replay_id = wait_handle_msg["id"]
await client.Set_replay(replay_id)
params = wait_handle_msg.get("params", {})
for key,value in params.items():
if key =="led":
print("+++++++++++++++++++++++++++++++++++++")
replay_msg = None
replay_state_code = None
# break
if replay_state_code == "get":
wait_replay_msg = replay_msg
get_replay_id = wait_replay_msg["id"]
data={}
for params in wait_replay_msg["params"]:
if params=="brightness":
data[params] = get_sensor_data()
if params=="led":
data[params] = get_led_state()
# print(data)
await client.Get_replay(get_replay_id,data)
print("Data has post to client")
# print(data)
replay_msg = None
replay_state_code = None
await uasyncio.sleep(time)
except KeyboardInterrupt:
print("MQTT subscription stopped.")
finally:
client.client.disconnect()
pass
async def creat_tasks(client):
tasks = []
t1 = uasyncio.create_task(Regularly_upload_data(client,3))
t2 = uasyncio.create_task(Regularly_hanle_msg(client,1))
tasks.extend([t1, t2])
await uasyncio.gather(*tasks)
pass
if __name__ == '__main__':
main()
pass
#======================================================================================
#作者:trashedmaker
#开源文件,未注明请勿转载
#原文链接:https://blog.csdn.net/m0_73949172/article/details/144929662?spm=1001.2014.3001.5501
#======================================================================================