M5Stack学习笔记(8)—— MQTT通信

万物互联的时代,网络通讯功能必须强! M5Stack因为可以通过wifi接入互联网,所以自然是可以方便的通过网络来传输数据的。

其实M5Stack可以用UIFlow的Web IDE进行编程,程序编写完毕后通过Cloud云端下载到M5Stack,云端通过一个8位16进制的APIKEY识别每个M5Stack。这个APIKEY可以在M5Stack的云端编程模式下看到。

M5Stack之间也可以向特定的APIKEY的另一个M5Stack发消息,这个可以在UIFlow Web IDE的Network模块里面找到相关功能。不过这个功能看起来过于简单,而且应该是比较依赖M5Stack的官方服务器(不确定可靠性怎样),也只能在M5Stack之间交换消息,所以我并没有深入研究。

MQTT是IoT领域广泛使用的,比较适合做轻量的数据交换。用起来也比较简单方便,就直接上示例代码了:

import wifisetup
wifisetup.auto_connect()

from m5mqtt import M5mqtt
m5mqtt = M5mqtt('m5stack','m88.cloudmqtt.com',21399,'user','password',60)

def fun(topic_data):
  print(topic_data)

m5mqtt.subscribe('iPad',fun)
m5mqtt.start()

m5mqtt.publish('PC','hello')
  • 首先要连上wifi网络
  • m5stack是随便写的client-id;m88.cloudmqtt.com是MQTT服务器,我用的cloudmqtt,5个以下连接免费;21399是端口;user是用户名;password是密码;60是keepalive时间,单位是秒
  • fun是收到了订阅的topic的消息的callback函数
  • m5mqtt.start()我想是开始了一个检查订阅消息的线程
  • m5mqtt.publish是发布了一个topic为“PC”的消息

简单的使用MQTT很容易,网络上也有很多介绍MQTT的文章,很容易上手。

下面我就给上次写的记录温湿度的程序加入发布温湿度数据到MQTT服务器的功能。因为只加入了publish功能,所以并没有subscribe以及相应的回调函数。

from m5stack import *
from m5ui import *
import units
import wifisetup
wifisetup.auto_connect()

from m5mqtt import M5mqtt
print('Init.m5mqtt...')
m5mqtt = M5mqtt('m5stack','m88.cloudmqtt.com',21399,'user','password',60)

rtc = machine.RTC()
rtc.ntp_sync(server = "ntp.aliyun.com",tz='CST-8')
while not rtc.synced():
    print("Waiting time synced with NTC server.")
    wait(0.2)


clear_bg(0x0)
env0 = units.ENV(units.PORTA)


flag_rec  = False
flag_disp = True
inteval   = 30  # seconds
filename  = '/sd/' + time.strftime('%Y%m%d_%H%M%S',time.localtime())+'.csv'

if 'sd' in os.listdir('/'):
    flag_sd  = True
    sd_info  = 'SD Mounted'
    sd_color = 0x00FF00
else:
    flag_sd  = False
    sd_info  = 'SD Not Mounted'
    sd_color = 0xFFFF00  


btnA    = M5Button(name="ButtonA", text="Rec", visibility=True)
btnB    = M5Button(name="ButtonB", text="SD", visibility=True)
btnC    = M5Button(name="ButtonC", text="Display", visibility=True)

label_t  = M5TextBox(0, 0, "Text", lcd.FONT_DejaVu24,0xFFFFFF, rotate=0)
label_h  = M5TextBox(0, 25, "Text", lcd.FONT_DejaVu24,0xFFFFFF, rotate=0)
label_p  = M5TextBox(0, 50, "Text", lcd.FONT_DejaVu24,0xFFFFFF, rotate=0)
label_s  = M5TextBox(0, 100, "REC stopped.", lcd.FONT_DejaVu24,0xFFFF00, rotate=0)
label_mt = M5TextBox(0, 150, sd_info, lcd.FONT_DejaVu24, 0xFFFF00, rotate=0)


def buttonA_pressed():
    # Rec Start/Stop
    global flag_disp
    global flag_rec
    global flag_sd
    if flag_disp and flag_sd:
        if flag_rec:
            flag_rec = False
            label_s.setText("REC stopped.")
            label_s.setColor(0xFFFF00)
        else:
            flag_rec = True
            label_s.setText("REC started.")
            label_s.setColor(0xFF0000)


def buttonC_pressed():
    # Display On/Off
    global flag_disp
    if flag_disp:
        flag_disp = False
        clear_bg(0x0)
        lcd.setBrightness(0)      
    else:
        flag_disp = True
        lcd.setBrightness(50)
        clear_bg(0x222222)
        
        label_t.show()
        label_h.show()
        label_p.show()
        label_s.show()
        label_mt.show()


def buttonB_pressed():
    # Display On/Off
    global flag_disp
    global flag_sd
    global flag_rec
    if flag_disp:
        if flag_sd and (not flag_rec):
            flag_sd = False
            label_mt.setText("SD Not Mounted")
            label_mt.setColor(0xFFFF00)
            os.umountsd()

        else:
            flag_sd = True
            label_mt.setText("SD Mounted")
            label_mt.setColor(0x00FF00)
            os.mountsd()


def save_tofile(rec_string):
    f = open(filename,'a+')
    f.write(rec_string)
    f.close()


buttonA.wasPressed(callback = buttonA_pressed)
buttonC.wasPressed(callback = buttonC_pressed)
buttonB.wasPressed(callback = buttonB_pressed)

timesec_start = round(time.time())
time_tick     = timesec_start - inteval

#save_tofile("SEC,TEMP,HUMI,PRES\n")

while True:
    m5mqtt.publish('0', '0')

    label_t.setText("TEMP: " + str(env0.temperature()))
    label_h.setText("HUMI: " + str(env0.humidity()))
    label_p.setText("PRES: " + str(env0.pressure()))

    if flag_rec:
        if time.time() - time_tick >= inteval:
            rec_data = "%s,%s,%s,%s" % (time.strftime('%Y/%m/%d %H:%M:%S',time.localtime()), str(env0.temperature()), str(env0.humidity()), str(env0.pressure()))
            save_tofile(rec_data + '\n')
            try:
                m5mqtt.publish('M5STACK_ENV_REC_DATA', rec_data)
            except OSError as exc:
                if str(exc)=='[Errno 104] ECONNRESET':
                    print('OSError: [Errno 104] ECONNRESET')
                    print('Reconnect.')
                    m5mqtt = M5mqtt('m5stack','m88.cloudmqtt.com',21399,'user','password',60)

            time_tick = time.time()

    wait(1)
  • 代码中try的部分,处理了MQTT掉线重连的情况。
  • m5mqtt.publish(‘0’, ‘0’)一句是“心跳包”,也为了保持alive防止超时掉线
  • [20190611更新] 在保存数据之后可能需要gc.collect()一下,否则可能会出现Guru Meditation Error: Core 1 panic’ed (LoadProhibited)错误 参考: https://docs.espressif.com/projects/esp-idf/zh_CN/latest/api-guides/fatal-errors.html

可以在cloudmqtt的管理界面WEBSOCKET UI里看到M5Stack发送的数据。 我也另外在Pythonista(好像是60块钱)里编写了几句代码,可以在手机上查看到MQTT数据。
要Pythonist支持MQTT需要先在StaSh里pip install paho-mqtt
参考了: https://qiita.com/inasawa/items/18640c328fdca297bc96

#!/usr/bin/env python2
import paho.mqtt.client as mqtt
import time

# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))

    # Subscribing in on_connect() means that if we lose the connection and
    # reconnect then subscriptions will be renewed.
    #client.subscribe("$SYS/#")
    #client.subscribe("PC")
    client.subscribe("M5STACK_ENV_REC_DATA")

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    print("[%s]  %s" % (msg.topic, str(msg.payload)))

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.username_pw_set("user", "password")
client.connect("m88.cloudmqtt.com", 21399, 60)

#client.publish('emqtt',payload='Pythonista started.',qos=0)

client.loop_start()

while True:
    #temperature = sensor.blocking_read()
    #temperature = temperature + 1
    client.publish("iPad", str(raw_input()))
    
    time.sleep(0.5)
    


# Blocking call that processes network traffic, dispatches callbacks and
# handles reconnecting.
# Other loop*() functions are available that give a threaded interface and a
# manual interface.
client.loop_forever()

参考了: https://blog.csdn.net/yannanxiu/article/details/52716997

你可能感兴趣的:(M5Stack学习笔记(8)—— MQTT通信)