基于IoT的多功能智能跑操系统
项目目标
- 通过ESP32作为主控芯片实现打卡系统的基本逻辑功能
- 利用RFID Unit 实现IC卡的信息识别、读取功能
- 基于MQTT信息传输技术实现跑操信息的”线下-云平台“交互功能
- 使用M5 StickV实现二维码识别技术
项目原理
- MQTT
设置MQTT服务器有三个步骤:
-
设置MQTT服务器设置
MQTT服务器的三大要素是:服务器ID,用户名和密码。其他要素,比如端口号是1883,一般都是用这个的,还有服务器是该平台的网址。
-
发布数据
发布数据的两个要点是主题和数据格式。主题的格式不同的平台会有不同的要求,建议参考平台的API参数。第二是数据格式,一般都是用JSON格式。
-
订阅数据
订阅数据和发布数据基本相同,也是设置主题和数据。但发布和订阅的主题不同。因为MQTT是比较简单的通讯协议,所以安全性要由中间人来提供。订阅数据会返回Mid, Result两个值,可以透过这两个值检查数据有没有错误和有没 有上传成功,具体语句可以看PahoMQTT库。
我们用的是Ubidots这个IoT平台,详情可以参考这个网站。
Ubidots Docs
-
M5StickV
设置M5StickV识别二维码的步骤:
- 使用micropython自带的sensor和image库,分别设置摄影镜头和图像的参数。而LCD库为控制屏幕显示的参数。我们我镜头参数设定如下图像色彩格式:选择是RGB565色彩图。设置图像像素大小,sensor.QQVGA: 160x120。把img设为获取摄影机的图像。
- 使用img库的find_qrcode是检测图上是否有qrcode,如果有则会返回一系列的qrcode的参数,如解析的数据,规格等。
- 因为我们主要用的是解碼的代码,所以单独取译码结果来作下一步使用。
-
RFID
RFID卡的结构有UID和BLOCKS。UID是每张卡的唯一标识符,只可读不可写。BLOCKS是可读可写的,因此我们把学生的数据放在BLOCKS里。值得注意的时要加入延时,否则如果进行可累加的操作,会因为射频处理识别的频率高而多次识别。
-
UART
通用异步收发传输器(Universal Asynchronous Receiver/Transmitter,通常称作UART) 是一种串行异步收发协议,应用十分广泛。UART工作原理是将数据的二进制位一位一位的进行传输。在UART通讯协议中信号线上的状态位高电平代表’1’低电平代表’0’。当然两个设备使用UART串口通讯时,必须先约定好传输速率和一些数据位。在进行传输前必须要对硬件进行连接,连接方式如图所示:
TX:发送数据端,要接对面设备的RX
RX:接收数据端,要接对面设备的TX
GND:保证两设备共地,有统一的参考平面
我们先分析我们使用到的器件的接口,可以从硬件设计图中找到我们使用到的器件,M5Go Lite的TX和RX接口为GPIO17和GPIO16,而我们对M5StickV的GPIO35和GPIO34做端口映射成RX和TX,使M5GO和M5StickV的TX和RX相连,RX和TX相连。使用方法为调用Micropython带有的uart库,设置好相应平台。
概念图
功能实现
以下功能在代码里都有注译,欢迎取用。
主要功能实现
-
M5GO LITE UI交互界面
-
M5GO LITE 实现 Wifi 连接功能
-
RFID读写IC卡信息
-
MQTT网络协议通讯实现云平台与开发板信息交互
-
M5StickV 识别读取二维码信息
-
打卡系统以及其包含的信息查询、显示功能
次要功能實現
- 单日不可重复打卡,不论任何方式
- 扫瞄了非学生信息的二维码,不上传
- 临时数据储存列表,以防上传失败
代码
M5GO LITE的代码
from m5stack import *
from m5ui import *
from uiflow import *
import wifiCfg
from m5mqtt import M5mqtt
import json
import time
import unit
import machine
from numbers import Number
def Wifi_reconnect():
while (wifiCfg.wlan_sta.isconnected()) != 1:
wifiCfg.reconnect()
label0.setText('Wifi connected')
data = Noneial
#rfid init
rfid0 = unit.get(unit.RFID, unit.PORTA)
uart = None
t1 = None
t2 = None
student_checkag=[] #存人数的列表
#mqtt initial
m5mqtt = M5mqtt('random', 'industrial.api.ubidots.com', 1883, 'BBFF-HXOoqxfhftjZSub2lDqbK019M3KHFg', '', 300)
#Label and tile set
setScreenColor(0x000000)
label0 = M5TextBox(69, 33, "Running System", lcd.FONT_Comic,0x89eee1, rotate=0)
label1 = M5TextBox(40, 86, "Name :", lcd.FONT_DejaVu18,0xff66d2, rotate=0)
label2 = M5TextBox(76, 124, "ID :", lcd.FONT_DejaVu18,0xff66d2, rotate=0)
label3 = M5TextBox(40, 165, "Count :", lcd.FONT_DejaVu18,0xff66d2, rotate=0)
label4 = M5TextBox(135, 86, "", lcd.FONT_DejaVu18,0xff66d2, rotate=0)
label5 = M5TextBox(135, 124, "", lcd.FONT_DejaVu18,0xff66d2, rotate=0)
label6 = M5TextBox(135, 165, "", lcd.FONT_DejaVu18,0xff66d2, rotate=0)
label7 = M5TextBox(30, 188, "", lcd.FONT_DejaVu18,0xffd400, rotate=0)
label10 = M5TextBox(20, 35, "123", lcd.FONT_Default,0xFFFFFF, rotate=0)
label10.hide()
title10 = M5Title(title="Today runner list:", x=3 , fgcolor=0xFFFFFF, bgcolor=0x0000FF)
title10.hide()
#uart initial
uart = machine.UART(2, tx=17, rx=16)
uart.init(115200, bits=8, parity=None, stop=1)
#var set
wifistatus = None
Name = None
count = None
uid = None
A = None
uartmsg=None
A_J = None
qruid=None
qrName=None
qrcount=None
m5mqtt.start()
#label hide and show
def showlist():
title10.show()
label10.show()
def hidelist():
title10.hide()
label10.hide()
def showmainui():
label0.show()
label1.show()
label2.show()
label3.show()
label4.show()
label5.show()
label6.show()
label7.show()
label8.show()
label9.show()
def hidemainui():
label0.hide()
label1.hide()
label2.hide()
label3.hide()
label4.hide()
label5.hide()
label6.hide()
label7.hide()
label8.hide()
label9.hide()
def buttonA_wasPressed():
showlist()
global list_run
list_run = ''
student_checkag.sort()
for i in range(len(student_checkag)):
if(i==0):
list_run=str(i+1)+'. '+student_checkag[i]+' '
elif(i%4==0):
list_run=str(i+1)+'. '+student_checkag[i]+' '+'\n'
else:
list_run=str(i+1)+'. '+student_checkag[i]+' '
label10.setText(str(list_run))
hidemainui()
pass
btnA.wasPressed(buttonA_wasPressed)
def mainproamg():
while True:
while wifistatus == 0: #wifi set
wifiCfg.auto_connect()
Wifi_reconnect()
try :
if rfid0.isCardOn(): #如有卡片接触
rgb.setColorAll(0xff0000)
#rfid0.writeBlock(1,'213173444')
#rfid0.writeBlock(2,'yangmi')
uid = rfid0.readBlockStr(1) #读UID
if(str(uid) not in student_checkag):#该人本日是否有跑操记录
Name = rfid0.readBlockStr(2) #读Name
count = int((rfid0.readBlockStr(4))) #读跑操次數
count = count + 1
rfid0.writeBlock(4,str(count)) #刷新跑操次數 写入卡
A = {"Student":{"value":count, "context":{"CardID":uid, "name" :Name }}}
A_J = json.dumps(A) #生成JSON包
label5.setText(str(uid))
label4.setText(str(Name))
label6.setText(str(count))
m5mqtt.publish(str('/v1.6/devices/esp32'),str(A_J)) #publish mqtt
student_checkag.append(str(uid)) #跑操者 寫入 列表
speaker.sing(392, 1) #铃声
speaker.sing(349, 1)
speaker.sing(330, 1)
speaker.sing(294, 1)
wait_ms(1000)
label7.setText(str(""))
else:
#提示本日已經有拍卡
label7.setText(str("Please do not scan again!"))
wait_ms(2000)
label7.setText(str(""))
elif(uart.any()): #如uart有资料
#label5.setText(str("enter qr"))
uartmsg = str((uart.read()).decode())#qrcode msg
#label5.setText(str(uartmsg))
save_d =eval(uartmsg)
#label5.setText(str(uartmsg))
qruid=save_d.get('Student').get('context').get('CardID')
label5.setText(str(qruid))
if(str(qruid) not in student_checkag): #该人本日是否有跑操记录
qrcount=save_d.get('Student').get('value')#解释dict 取其中的关键值
qrName=save_d.get('Student').get('context').get('name')
qrcount=int(qrcount+1)
label5.setText(str(qruid))
label4.setText(str(qrName))
label6.setText(str(qrcount))
B = {"Student":{"value":qrcount, "context":{"CardID":qruid, "name" :qrName }}}
B_J = json.dumps(B)
m5mqtt.publish(str('/v1.6/devices/esp32'),str(B_J))
student_checkag.append(str(qruid))
wait_ms(2)
else:
label7.setText(str("Please do not scan again!"))
wait_ms(2000)
label7.setText(str(""))
pass
except:
wait(1)
wait_ms(2)
def buttonB_wasPressed():
hidelist()
showmainui()
mainproamg()
pass
btnB.wasPressed(buttonB_wasPressed)
mainproamg()
M5STICKV的代码
import sensor, image ,time #forcam
import lcd #for lcd屏
from machine import I2C,UART
from fpioa_manager import fm #导入maipy的fm(fpioa manager)这个内置的对象,用于后续注册工作。
#uart initial
fm.register(35, fm.fpioa.UART2_RX, force=True)
fm.register(34, fm.fpioa.UART2_TX, force=True)
uart_Port = UART(UART.UART2, 115200,8,0,0, timeout=1000, read_buf_len= 4096)
clock = time.clock()
lcd.init() #lcd initial
#set camera
sensor.reset()
sensor.set_pixformat(sensor.RGB565) #RGB565
sensor.set_framesize(sensor.QQVGA) # can be QVGA on M7...
sensor.set_vflip(1)
sensor.set_hmirror(1)
sensor.skip_frames(20)
sensor.run(1)
sensor.set_auto_gain(False) #自动增益off
while(True):
img = sensor.snapshot()
fps =clock.fps() #
check =img.find_qrcodes()#scan img find qrcode
if(len(check)>0):
try:
tuplexboxa =check[0].rect()
data0=check[0].payload()
img.draw_string(15,20,"Scan Successfully!",(236,36,36),scale=1.0)
img.draw_rectangle(tuplexboxa,(236,36,36))
lcd.display(img)#在Lcd 屏中顯示鏡頭取得的圖片
data=eval(data0)
data2=data.get('Student')
data3=data2.get("context")
check1=('Student' in data)
check2=('value' in data2)
check3=('context' in data2)
check4=('CardID' in data3)
check5=('name' in data3)
if(check1==True & check2==True & check3==True & check4==True & check5==True):
uart_Port.write(str(data))#uart发送解码资料
time.sleep(2)
except:
print("Invalid QR code") #如二维码格式不符
strerror="Invalid QR code"#
lcd.display(strerror)#
实际操作视频
查询跑操是否记录在列
wifi连接+单日打卡限制功能
RFID实现不同人连续打卡功能
StickV实现二维码读取功能