这一部分是较为复杂一点的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