micropython通过umqtt连接至onenet-uasyncio提升性能(异步协程)

 

 micropython连接onenet实现从应用端调用api到设备端执行-汇总-CSDN博客

↑汇总

目录

我们要明确功能

(1)我们要上传数据即post

(2)我们也要set属性和处理set属性

1明确需求

2创建任务

3创建任务函数

4运行异步程序

5测试一下


micropython通过umqtt连接至onenet-设备直接读取设备信息-CSDN博客

上一篇↑

文末有完整代码直接用配合着理解,虽然简单但是怕出错

未注明作者,请勿转载

下一篇↓

我们上一步实现了micropython设备端的三大基本功能,即post数据到平台,set设备属性,get设备属性。本来应该直接配合我们第一步写的应用端的,但我们发现micropython的性能不够。

当我们在设备调试时:

micropython通过umqtt连接至onenet-uasyncio提升性能(异步协程)_第1张图片

多点几次属性设置就会出现属性设置失败,原因是我们post数据到平台是一个阻塞的过程,我们一直post就会导致程序一直阻塞在那,无法处理平台下发的set属性topic。导致回复超时,平台判断我们没有收到属性设置的命令。

有人选择调整post的频率,这样也不是不行,但主程序依然会卡在那。

我们要明确功能

(1)我们要上传数据即post

(2)我们也要set属性和处理set属性

这俩完全是一个异步的程序,即(1)阻塞时候我们就可以去处理(2)中的事情,没必要一直等着(1)来浪费时间,当(1)做完了平台会返回消息我们再去处理(1)即可。

这时候异步协程就非常好用

即async

搞过爬虫的朋友应该很熟悉了,线程池容易把网站搞死,协程相对于他已经是算温和的了。我用的这块esp32-s3是多核,各位大佬有兴趣可以取尝试使用多线程thread。我们这里使用携程就足够了。

python async这个大家建议去b站看一看视频在来看本篇文章,这个东西还是比较难理解的。看完再回来看本篇文章。

我们直接开始。

1明确需求

我们要把原来的俩个需求拆开来执行,即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()

我们要把这一部分拆开来执行。

2创建任务

导入模块 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,这样才能识别我们的该程序是异步程序。

3创建任务函数

在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

4运行异步程序

uasyncio.run(creat_tasks(client))

在主要程序main中运行我们的异步任务,用uasyncio.run方法执行我们的创建函数任务即可

至此我们算是完成了所有的操作

5测试一下

依然用平台的调试工具

micropython通过umqtt连接至onenet-uasyncio提升性能(异步协程)_第2张图片

post执行没有问题

micropython通过umqtt连接至onenet-uasyncio提升性能(异步协程)_第3张图片

下发的指令也是可以的平台有收到set_replay且没有超时

micropython通过umqtt连接至onenet-uasyncio提升性能(异步协程)_第4张图片

我们现在的单片机已经可以在阻塞的时候处理其他程序了 下一步我们就要配合应用端的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
#======================================================================================    
    
    


你可能感兴趣的:(linux,数据库,网络)