1.3 ESP32-MicroPython高级模块操作

本文介绍了如何在ESP32上使用MicroPython进行蓝牙配网并保存账户密码,MQTT库的安装与应用,搭建本地MQTT服务器,以及Modbus读写的实现。内容涵盖从源码安装MQTT库,启动和停止EMQ X MQTT服务器,到改造Modbus读取函数,并探讨了内存管理和消耗。
摘要由CSDN通过智能技术生成

这一部分是较为复杂一点的micropython库,包括蓝牙配置wifi,mqtt,modbus,内存管理等.

1.蓝牙配网,保存账户密码在文件中

from machine import Pin
from machine import Timer
from time import sleep_ms
import bluetooth
import network
import time
import json

BLE_MSG = ""

class ESP32_BLE():
    def __init__(self, name):
        self.led = Pin(12, Pin.OUT)    #配置LED灯引脚为输出模式
        self.timer1 = Timer(0)         #配置定时器
        self.name = name
        self.ble = bluetooth.BLE()     #创建蓝牙对象
        self.ble.active(True)          #开启蓝牙
        self.ble.config(gap_name=name) #配置蓝牙信息
        self.disconnected()            #设置定时器中断
        self.ble.irq(self.ble_irq)     #蓝牙时间处理
        self.register()                #配置蓝牙的uuid
        self.ble.gatts_write(self.rx, bytes(100))#默认蓝牙只接收20字节,这里更改为接收100字节
        self.advertiser()              #蓝牙广播
        self.ok=0

    def disconnected(self):        
        self.timer1.init(period=100, mode=Timer.PERIODIC, callback=lambda t: self.led.value(not self.led.value()))

    def register(self):        
        service_uuid = '6E400001-B5A3-F393-E0A9-E50E24DCCA9E'
        reader_uuid = '6E400002-B5A3-F393-E0A9-E50E24DCCA9E'
        sender_uuid = '6E400003-B5A3-F393-E0A9-E50E24DCCA9E'

        services = (
            (
                bluetooth.UUID(service_uuid), 
                (
                    (bluetooth.UUID(sender_uuid), bluetooth.FLAG_NOTIFY), 
                    (bluetooth.UUID(reader_uuid), bluetooth.FLAG_WRITE),
                 )
             ), 
        )

        ((self.tx, self.rx,), ) = self.ble.gatts_register_services(services)

    def advertiser(self):
        name = bytes(self.name, 'UTF-8')
        adv_data = bytearray('\x02\x01\x02') + bytearray((len(name) + 1, 0x09)) + name
        self.ble.gap_advertise(100, adv_data)

    def ble_irq(self, event, data):
        global BLE_MSG
        if event == 1: #手机连接了此设备
            self.connected()
        elif event == 2: #手机断开此设备
            if self.ok==0:
                self.advertiser()
                self.disconnected()
        elif event == 3: #手机发送了数据 
            buffer = self.ble.gatts_read(self.rx)
            BLE_MSG = buffer.decode('UTF-8').strip()
            self.wifi_get_data(BLE_MSG)

    def connected(self):
        self.timer1.deinit()
        self.led.value(0)

    def wifi_get_data(self,BLE_MSG):
        if len(BLE_MSG)>0:
            ssid,password=BLE_MSG.split(':')   #分离信息
            wifi_connect_ok=wifi_connect(ssid,password) #对WiFi进行连接
            if wifi_connect_ok:
                config = dict(ssid=ssid, password=password)  #将WiFi信息写成字典格式
                with open('wifi_config','w+') as f: #将字典转成json写入wifi_config文件中
                    f.write(json.dumps(config))
                self.ok=1
                self.ble.active(False)  #关闭蓝牙
            else:
                self.ble.active(False) #这里要先关闭蓝牙,不关闭的话虽然也可以用,但python会弹出报错
                self.__init__("ESP32") #重新初始化蓝牙

def wifi_connect(ssid,pwd):
    station = network.WLAN(network.STA_IF)  #配置WiFi的STA模式
    station.active(True)   #开启esp32的WiFi
    print(ssid,pwd)
    station.connect(ssid, pwd) #进行WiFi连接
    count=0
    while station.isconnected() == False: #检测是否连接成功
        count+=1
        time.sleep(1)
        if count>5:    #如果检测到大于5次没有连接成功(5秒后还没有联网)关闭WiFi并返回
            station.active(False)
            return 0
    print("Connection successful")
    print(station.ifconfig())
    led = Pin(12, Pin.OUT)  #连接成功后配置LED引脚为输出模式,让LED灯长亮
    led.value(1)
    return 1

if __name__ == "__main__":
    wifi_connect_ok=False
    
    try:
        with open('wifi_config','r+') as f: #尝试打开wifi_config文件
            config = json.loads(f.read())   #获取wifi_config的信息
        wifi_connect_ok=wifi_connect(config['ssid'],config['password']) #进行WiFi连接
        if wifi_connect_ok:
            wifi_connect_flag=1
        else:
            ble = ESP32_BLE("ESP32")  #如果连接失败则进入蓝牙配网模式
    except OSError:
        ble = ESP32_BLE("ESP32")  #如果查找不到文件则进入蓝牙配网模式

    while True:
        if wifi_connect_ok or ble.ok: #如果WiFi已连接,进行xxxxx
            print("i am ok")
            
            pass

2.MQTT

MQTT库的安装,精简版的源码版本

https://github.com/fizista/micropython-umqtt.simple2/tree/master/src_minimized/umqtt

ESP32自己下载安装的方法

import upip
#upip.install('micropython-umqtt.simple')#旧版本
upip.install("micropython-umqtt.simple2")#新版本

安装实际是下载py文件到机器,下载完,有以下的函数可以调用

connect(...)
 - Connect to a server. Returns True if this connection uses persisten session stored on a server (this will be always False if clean_session=True argument is used (default)).
disconnect()
 - Disconnect from a server, release resources.
ping()
 - Ping server (response is processed automatically by wait_msg()).
publish()
 - Publish a message.
subscribe()
 - Subscribe to a topic.
set_callback()
 - Set callback for received subscription messages.
set_last_will()
 - Set MQTT “last will” message. Should be called before connect().
wait_msg()
 - Wait for a server message. A subscription message will be delivered to a callback set with set_callback(), any other messages will be processed internally.
check_msg()
 - Check if there’s pending message from server. If yes, process the same way as wait_msg(), if not, return immediately.

普通mqtt

from umqtt.simple import MQTTClient
from machine import Pin
import network
import time

client_id = "wifimodule2"
#mserver = "emqx-public.xxxxxxx"#MQTT服务器的域名
#mserver = "120.xx.xx.xx"#MQTT服务器的IP
user="xxxx"
pswd="xxxx"
port=1883
topic_ctl = "testtopic1"#设备订阅的主题,客户端推送消息的主题
topic_fromwifi ="testtopic1"#客户端订阅的主题,设备推送消息的主题
client = None

led1=Pin(2, Pin.OUT, value=1)
led2=Pin(5, Pin.OUT, value=1)
    
def sub_callback(topic, msg):
    global client
    print((topic_ctl, msg))
    if msg == b'led1 ON' or msg == b'led1 on':
        pub_msg = 'LED1: ON-state'
        led1.value(0)
    else:
        pub_msg = 'other msg'
    client.publish(topic_sta, pub_msg, retain=True)

#main当中  mqtt 连接    
client = MQTTClient(client_id, mserver,port,user,pswd,0)
client.set_callback(sub_callback)
client.connect()
#client.subscribe(topic_ctl)
client.publish(topic_fromwifi, 'ESP32 Device online', retain=True,qos=1)
print("Connected to %s, subscribed to %s topic" % (mserver, topic_ctl))

-------主程序样本---------

# try:
#     client = MQTTClient(client_id, mserver, 0)
#     client.set_callback(sub_callback)
#     client.connect()
#     client.subscribe(topic_ctl)
#     client.publish(topic_sta, 'ESP32 Device online', retain=True)
#     print("Connected to %s, subscribed to %s topic" % (mserver, topic_ctl))
#     while True:
#         client.wait_msg()
# finally:
#     if client is not None:
#         print('off line')
#         client.disconnect()
#     wlan.disconnect()
#     wlan.active(False)

3.搭建本地MQTT服务器

curl -s https://assets.emqx.com/scripts/install-emqx-deb.sh | sudo bash
sudo apt-get install emqx
sudo snap install emqx  #ubuntu 20.04以后的

从github端下载最新的5版本

https://github.com/emqx/emqx/releases/tag/v5.0.11

下载emqx-5.0.11-ubuntu20.04-amd64.deb
启动和停止emqx

sudo emqx start
sudo emqx stop

访问dashboard

http://192.168.148.132:18083

测试客户端

sudo snap install mqttx

4.modbus读写

串口初始化,使用ASCII或RTU模式读写设备;
导入micropython的modbus库。https://github.com/techbase123/micropython-modbus
因为使用的是串口,所以把TCP相关的文件删掉,只保留三个文件,放在main.py同目录
uModBusConst.py
uModBusFunctions.py
uModBusSerial.py

主程序导入:

from uModBusSerial import uModBusSerial
import uModBusConst as Const

我改造了一下读取的函数

    def read_holding_registers(self, starting_addr, register_qty, signed=True, retrycount=2):

        while (retrycount > 0):  # 重试机制
            #modbus_pdu = functions.read_holding_registers(starting_addr, register_qty)
            modbus_pdu, slave_addr0 = functions.read_holding_registers(starting_addr, register_qty)
           resp_data = self._send_receive(modbus_pdu, slave_addr0, True)
           if(resp_data!=""):
           		return   resp_data #读取到返回
           else:   
                retrycount = retrycount-1  #读取不到重试
        return 0  #重试次数到了,还没有读到,则返回0

读取modbus数据:

modubsrtu=uModBusSerial(1,115200,8,1,None,[17,16]) 	#初始化modbus串口,16,17是我接的引脚号
temp = modubsrtu.read_holding_registers(3000, 32)  # 读3000地址的32字节

5.内存查看和整理

加载了wifi,蓝牙,机器库machine,内存管理库gc,mqtt库,modbus库之后,固定剩余内存消耗为92K。

>>> import machine
>>> import gc
>>> from umqtt.simple import MQTTClient
>>> import uModBusSerial
>>> gc.mem_free()
69744
>>> gc.collect()
>>> gc.mem_free()
92144

发送了mqtt消息后,还剩余内存:

Connected to emqx-server, subscribed to testtopic1 topic
collect mem,RAM free is  93.504 KB
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员熊子峰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值