1. 程式人生 > >基於ESP8266的MicroPython連線MQTT伺服器

基於ESP8266的MicroPython連線MQTT伺服器

從標題看對於小白來說似乎資訊量很大,ESP8266是什麼?MicroPython是什麼?MQTT又是什麼?

ESP8266

ESP8266 是一款由上海樂鑫資訊科技開發的可以作為微控制器使用的成本極低且具有完整TCP/IP協議棧的Wi-Fi IoT控制晶片。Ai-Thinker生產的ESP-01晶片於2014年8月首次引起了西方的創客們的注意,這個小模組允許微控制器通過海斯命令集使用TCP / IP協議棧連線到Wi-Fi網路。然而,在最初的晶片上幾乎沒有使用英文的文件及可接受的命令。由於模組上外部元件非常少的原因,導致了其價格十分便宜,並吸引了許多創客來研究和使用該模組、開發配套該晶片使用的軟體以及對其使用中文的使用指南進行多語言翻譯。

原廠有ESP8266-01,-07,-12E,和-13四款主打,價格在$2.3-$3.8之間。3.3V的電壓可以直接用LiPo電池供電,比5V功耗要省。我最喜歡的是ESP8266-12E款,GPIO口多,可作為獨立的計算原價。ESP8285即是內建了1MiB快閃記憶體的ESP8266,其允許單晶片裝置能夠直接連線到Wi-Fi進行使用。其後續產品是2016年所釋出的ESP32。本人是在淘寶購買的NodeMCU Lua 的ESP8266開發板。

MicroPython

MicroPython,是Python 3程式語言的一個完整軟體實現,用C語言編寫,被優化於執行在微控制器 M

icrocontrollers之上。MicroPython是執行在微控制器硬體之上的完全的Python編譯器和執行時系統。提供給使用者一個互動式提示符(REPL)來立即執行所支援的命令。除了包括選定的核心Python庫,MicroPython還包括了給予程式設計者訪問低層硬體的模組MicroPython是澳大利亞程式設計師和物理學家Damien George,在2013年一次成功的Kickstarter眾籌活動之後最初建立的[5]。儘管最初的Kickstart眾籌活動將MicroPython與pyboard微控制器一起發行,MicroPython支援大量的基於ARM的體系結構[6]。MicroPython已經運行於
ArduinoESP8266ESP32、和物聯網(WiPy、pyboard、pyboard D-series、 STM32F4 Discovery、 NUCLEO-F401RE、 NUCLEO-F767ZI硬體。在2016年,Python軟體基金會建立了MicroPython的BBC Micro Bit版本,作為其BBC Micro Bit合作伙伴貢獻的一部分這個專案的原始碼託管於GitHub

Micropython的由來:
這得益於Damien George這位偉大的計算機工程師,Damien George每天都會使用Python工作,他有一天冒出一個大膽的想法:能否用Python來控制微控制器,從而實現對機器人的操作呢?Python語言本身就是一款簡單上手的指令碼語言,一些非計算機專業的愛好者都選Python語言作為入門語言,但是美中不足(中國跟美國為什麼不參加世界盃),它不能實現對一些底層的操作,在硬體領域毫不起眼。所以,Damien George利用6個月時間打造了MicroPython,這就是MicroPyhton的由來。

MQTT

MQTT訊息佇列遙測傳輸(Message Queuing Telemetry Transport) 一種基於釋出/訂閱(publish/subscribe)模式的"輕量級"通訊協議 該協議構建於TCP/IP協議上,由IBM在1999年釋出,目前已成為 IoT 通訊的標準。MQTT最大優點在於,可以以極少的程式碼和有限的頻寬,為連線遠端裝置提供實時可靠的訊息服務。作為一種低開銷、低頻寬佔用的即時通訊協議,使其在物聯網、小型裝置、移動應用等方面有較廣泛的應用。IBM公司的安迪·斯坦福-克拉克及Arcom公司的阿蘭·尼普於1999年撰寫了該協議的第一個版本。該協議的可用性取決於該協議的使用環境。IBM公司在2013年就向結構化資訊標準促進組織提交了 MQTT 3.1 版規範,並附有相關章程,以確保只能對規範進行少量更改 MQTT是一個基於客戶端-伺服器的訊息釋出/訂閱傳輸協議。MQTT協議是輕量、簡單、開放和易於實現的,這些特點使它適用範圍非常廣泛。在很多情況下,包括受限的環境中,如:機器與機器(M2M)通訊和物聯網(IoT)。其在,通過衛星鏈路通訊感測器、偶爾撥號的醫療裝置、智慧家居、及一些小型化裝置中已廣泛使用。

開發環境

  • Windows 10 x64
  • NodeMCU開發板
  • Python 3.7.4
  • uPyLoader
  • teraterm-4.96
  • MicroPython 1.8.7
  • esp8266 firmware

下載和配置環境

本人使用的是搭載Windows 10 X64 laptop.所有工具都是基於Windows 10作業系統。首先我們需要準備下面幾個工具(python-3.7.4 esptool 和 uPyLoader)方便我們下載和除錯NOdeMCU開發板。

首先到python官網下載 python-3.7.4-amd64.exe,並按照如下選項安裝。

然後到Github上下載uPyLoader由於沒有打包成可執行檔案,所以需要使用Python啟動。uPyLoader基於Python 3,並且需要這兩個包:PyQt5和pyserial,pyserial版本要大於等於3.1.1。通過cmd shell 命令對NodeMCU firmware進行下載,我們需要esptool。

進入windows cmd

python -m pip install --upgrade pip
pip install PyQt5
pip install esptool
pip install pyserial>=3.1.1

使用esptool.py你能下面的命令擦除flash。

esptool.py --port COM3 erase_flash
 
#########################################
esptool.py v2.7
Serial port COM3
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: 2c:3a:e8:43:c1:c6
Uploading stub...
Running stub...
Stub running...
Erasing flash (this may take a while)...
Chip erase completed successfully in 6.5s
Hard resetting via RTS pin...
##########################################

使用下面的命令燒寫firmware。你可以 到www.micropython.org官網下載NodeMCU最新的firmware。我在寫這個文件是最新是esp8266-20190529-v1.11.bin

esptool.py --port COM3 --baud 460800 write_flash --flash_size=detect 0 esp8266-20190529-v1.11.bin
 
#################################################################################################
esptool.py v2.7
Serial port COM64
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: 2c:3a:e8:43:c1:c6
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Flash params set to 0x0040
Compressed 617880 bytes to 402086...
Wrote 617880 bytes (402086 compressed) at 0x00000000 in 9.6 seconds (effective 512.9 kbit/s)...
Hash of data verified.
 
Leaving...
Hard resetting via RTS pin...
 
#################################################################################################

進入到uPyLoader-master目錄,在命令列輸入python .\main.py啟動uPyLoader。

注意如果之前用串列埠連線了8266,要關閉之前的連線。這樣uPyLoader才能找到對應的串列埠。

點選最右邊的「Connect」即可連線。接下來,選單欄->「File」->「Init transfer files」。初始化傳輸檔案,初始化成功後在MCU端會新增__upload.py和__download.py兩個檔案。另外,在選單欄->「View」下面可以開啟終端(Terminal)和編輯器(Code Editor),方便除錯和程式碼編寫。

因為uPyLoader似乎無法跳轉到工作目錄以外的目錄,所以可以在該目錄下建立一個project資料夾,然後把自己的工程程式碼(main.py等)放進去,方便管理。

需要傳輸檔案過去的話,只需要雙擊對應的py檔案,然後點選「MCU name」後面的「Transfer」,等待彈窗結束後,檔案就下載過去了。

uPyLoader 容易crash。建議還是使用MicroPython File Uploader.exe 會比較穩定點。大家可以百度或者google搜尋這個工具。大家給去下載 TPYBoard v202資料 資料包裡有相應的測試程式碼和MicroPython File Uploader 工具。

開啟MicroPython File Uploader 工具,Open連上開發板。選擇要傳送的程式檔案。點選Send即可。注意把“Autorun“勾選去掉。如果不去掉,每次傳送完檔案後會自動復位。

接下來可以通過在工具命令列框裡敲命令查詢檔案列表

import os
os.listdir()

之外你還能使用除錯串列埠工具teraterm-4.96 。直接發命令除錯

MQTT伺服器搭建

這裡我使用了雲伺服器。阿里雲百度雲騰訊雲都可以。我這裡使用的是花了99元/年的騰訊雲伺服器。點選連結 騰訊雲伺服器 選擇好配置購買就可以了。

我的主機配置是

系統是centos 7.6 64位的。

yum -y install unzip
mkdir -p /root/mqtt-server && cd /root/mqtt-server
wget https://www.emqx.io/downloads/broker/v2.3.11/emqttd-centos7-v2.3.11.zip
unzip emqttd-centos7-v2.3.11.zip

配置系統環境變數

> vim /etc/profile
 
# emqtt
export EMQPATH=/root/mqtt-server/emqttd
export PATH=$EMQPATH/bin:$PATH
 
> source /etc/profile

檢查emq是否正常

> emqttd console
## 如下輸出代表正常
starting emqttd on node '[email protected]'
emqttd ctl is starting...[ok]
emqttd hook is starting...[ok]
emqttd router is starting...[ok]
emqttd pubsub is starting...[ok]
emqttd stats is starting...[ok]
emqttd metrics is starting...[ok]
emqttd pooler is starting...[ok]
emqttd trace is starting...[ok]
emqttd client manager is starting...[ok]
emqttd session manager is starting...[ok]
emqttd session supervisor is starting...[ok]
emqttd wsclient supervisor is starting...[ok]
emqttd broker is starting...[ok]
emqttd alarm is starting...[ok]
emqttd mod supervisor is starting...[ok]
emqttd bridge supervisor is starting...[ok]
emqttd access control is starting...[ok]
emqttd system monitor is starting...[ok]
emqttd 2.3.11 is running now
Eshell V9.0  (abort with ^G)
([email protected])1> Load emq_mod_presence module successfully.
dashboard:http listen on 0.0.0.0:18083 with 4 acceptors.
mqtt:tcp listen on 127.0.0.1:11883 with 4 acceptors.
mqtt:tcp listen on 0.0.0.0:1883 with 64 acceptors.
mqtt:ws listen on 0.0.0.0:8083 with 4 acceptors.
mqtt:ssl listen on 0.0.0.0:8883 with 16 acceptors.
mqtt:wss listen on 0.0.0.0:8084 with 4 acceptors.
mqtt:api listen on 0.0.0.0:8080 with 4 acceptors.

啟動EMQ服務

> emqttd start
emqttd 2.3.11 is started successfully!
 
> emqttd_ctl status
Node '[email protected]' is started
emqttd 2.3.11 is running

當我們啟動了EMQ之後就可以使用客戶端進連結了,埠如下

  • 1883 MQTT 協議埠
  • 8883 MQTT/SSL 埠
  • 8083 MQTT/WebSocket 埠
  • 8080 HTTP API 埠
  • 18083 Dashboard 管理控制檯埠

通過IP訪問18083埠可以通過Dashboard線上觀察EMQ的執行狀態等引數

預設使用者: admin,密碼:public (可在平臺中配置使用者)

MicroPython的MQTT

MicroPython是支援MQTT客戶端的,在Github的micropython-lib中,找到umqtt.simple資料夾,裡面就有使用MQTT介面的例程。在ESP8266的MicroPython官方API文件中,並沒有給出這個介面的介紹,所以需要到搜尋下相關資料。

進入umqtt.simple目錄,把umqtt資料夾中的simple.py檔案下載到ESP8266。

增加程式碼如下:

mqtt.py

from simple import MQTTClient
from machine import Pin
import machine,time, math
import micropython
#選擇G4引腳
led_blue = machine.PWM(machine.Pin(2), freq=1000)  # 設定 GPIO2 為輸出
led_blue.duty(1024)
# MQTT伺服器地址域名為:49.235.173.142,不變
SERVER = "49.235.173.142"
#裝置ID
CLIENT_ID = "umqtt_client"
#隨便起個名字
TOPIC = b"ledctl"
TOPIC2 = b"pwmled"
TOPIC3 = b"ledstatus"
username="123123"
password="321321"
pwm_old = 0
pwmval = 0
c=None
 
def delay(t):
    for i in range(t):
    k=0;
 
def sub_cb(topic, msg):
    global pwm_old,pwmval
    if topic == b"ledctl":
        print((topic, msg))
        if msg == b"on":
                pwmval = 0
 
        elif msg == b"off":
                led_blue.duty(1024)
                pwmval = 1024;
 
    if topic == b"pwmled":
        pwmval = int(((100-int(msg))/100)*1024)
        print((topic, pwmval))
 
 
def main(server=SERVER):
    #埠號為:6002
    c = MQTTClient(CLIENT_ID, server)
    c.set_callback(sub_cb)
    c.connect()
    c.subscribe(TOPIC)
    c.subscribe(TOPIC2)   
    print("Connected to %s, subscribed to %s topic" % (server, TOPIC))
    try:
        while 1:
            c.wait_msg()
            global pwm_old,pwmval
 
            if pwmval == 1024 :
                c.publish(TOPIC3,'ledoff')
            elif pwmval < 1024 :
                c.publish(TOPIC3,'ledon');
 
            if pwmval > pwm_old :
                for i in range(pwm_old,pwmval,1):
                    led_blue.duty(i)
                    delay(30)
            elif pwmval < pwm_old :
                for i in range(pwm_old,pwmval,-1):
                    led_blue.duty(i)
                    delay(30)
            pwm_old = pwmval
 
    finally:
            c.disconnect()
main.py

from machine import Timer,Pin,I2C,SPI
import machine,mqtt
import dht,ssd1306,math,time
 
def f(t):
    d=dht.DHT11(machine.Pin(0))
    d.measure()
    a=d.temperature()
    b=d.humidity()
    display.fill(0)
    display.text('TPYBoard V202',1,1)
    display.text('Hi, TurnipSmart',1,16)   
    temp = 'Temp '+str(a)+'C'
    display.text(temp,1,31)
    humi = 'humidity '+ str(b)+'%'
    display.text(humi,1,46)
    display.show()   
 
spi = SPI(baudrate=10000000, polarity=1, phase=0, sck=Pin(14,Pin.OUT), mosi=Pin(13,Pin.OUT), miso=Pin(12))
display = ssd1306.SSD1306_SPI(128, 64, spi, Pin(5),Pin(4), Pin(16))
 
tim = Timer(-1)  #新建一個虛擬定時器
tim.init(period=2000, mode=Timer.PERIODIC, callback=f)
 
try:
  display.poweron()
  display.init_display()
 
  display.text('TPYBoard V202',1,1)
  display.text('Hi, TurnipSmart',1,16)
  temp = 'Temp '+str(18)+'C'
  display.text(temp,1,31)
  humi = 'humidity '+str(70)+'%'
  display.text(humi,1,46)
  mqtt.main()
 
except Exception as ex:
  print('Unexpected error: {0}'.format(ex))
  display.poweroff()
boot.py

def do_connect():
        import network
        sta_if = network.WLAN(network.STA_IF)
        ap_if = network.WLAN(network.AP_IF)
        if ap_if.active():
                ap_if.active(False)
        if not sta_if.isconnected():
                print('connecting to network...')
        sta_if.active(True)
        sta_if.connect('mqtt-server', '123456') #wifi的SSID和密碼
        while not sta_if.isconnected():
                pass
        print('network config:', sta_if.ifconfig())
do_connect()

Android的MQTT應用

網上已經有APP(IoT MQTT Panel)基於MQTT協議,實現對NodeMCU的控制。

提示沒有連線,點那個紅色按鈕建立一個連線:

前兩項都是隨便填的,值得注意的的是那個Broker Web/IP Address,這個最好自己架個伺服器,可以是上面搭建騰訊雲伺服器,也可以是本地搭建的伺服器,當然這裡做個例子,填完後點那個CREATE:

分別添加了Switch,Slider和LED Indicator面板。

這理解釋下:Topic可以理解為一個通道,比如開關,按下後會往ledctl這個通道里發ledon這個資訊,再按一下會往ledctl通道里發ledoff這個資訊,最終介面如下:

基於上面所有內,小白們都能很輕鬆的搭建IOT網路。