micro:bit 的無線電通訊功能使其成為學習物聯網和無線感測網路的理想平台。本文除了介紹 micro:bit 如何實作裝置間的訊息廣播和同步閃爍特效外,也探討其無線電通訊的底層機制,例如訊息快取管理、按鈕事件處理,以及訊息的接收與轉發。此外,文章也涵蓋瞭如何使用 ESP8266/ESP32 等 WiFi 模組擴充套件 micro:bit 的網路連線能力,包含連線 WiFi 網路、設定存取點,以及使用 urequests 模組簡化 HTTP 請求等實務操作。最後,文章也簡要介紹了 MQTT 協定及其在物聯網應用中的重要性,為讀者提供更全面的技術視野。

微位元(micro:bit)無線電廣播技術詳解與實務應用

簡介

微位元(micro:bit)裝置之間的無線電通訊為物聯網(IoT)與無線感測網路技術提供了簡易且具教育意義的實作方式。本文將探討兩個主要的程式範例:簡易訊息廣播系統與螢火蟲同步閃爍特效,並分析其技術細節、實作方法及改進方向。

簡易訊息廣播系統實作分析

系統架構與運作原理

該系統主要實作了多個micro:bit裝置之間的訊息快取管理、按鈕事件處理以及訊息的接收與轉發功能。核心程式碼如下:

message_cache = {}
cache_lifetime = 1000 * 5  # 5秒快取生命週期
position = 0

while True:
    sleep(20)
    now = running_time()
    to_delete = []
    
    # 快取管理機制
    for key, timestamp in message_cache.items():
        if now > timestamp + cache_lifetime:
            to_delete.append(key)
    for stale_message in to_delete:
        del message_cache[stale_message]

    # 按鈕事件處理
    if button_a.was_pressed():
        position = (position + 1) % len(messages)
        display.scroll(messages[position], 50, wait=False)
    
    if button_b.was_pressed():
        radio.send('{}:{}'.format(device_name, messages[position]))

    # 訊息接收與轉發
    msg = radio.receive()
    if msg and msg not in message_cache:
        message_cache[msg] = running_time()
        radio.send(msg)
        sender, message = msg.split(':')
        display.scroll('{} says: {}'.format(sender, message), 50, wait=False)

內容解密:

  1. 快取管理機制:透過定期清除過期訊息,避免記憶體資源耗盡。

    • 使用running_time()取得當前時間戳記。
    • 比對訊息時間戳記與當前時間,判斷是否超出快取生命週期。
  2. 按鈕事件處理邏輯

    • A按鈕用於迴圈切換預設訊息。
    • B按鈕負責傳送當前選定的訊息。
  3. 訊息接收與轉發機制

    • 接收到的訊息會被快取並轉發。
    • 使用split(':')解析訊息來源與內容。

螢火蟲同步閃爍特效實作分析

技術原理與實作方法

該特效模擬了螢火蟲的生物發光同步行為,裝置之間透過無線電訊號同步閃爍。核心程式碼如下:

flash = [Image().invert()*(i/9) for i in range(9, -1, -1)]
radio.on()

while True:
    if button_a.was_pressed():
        radio.send('flash')
    
    incoming = radio.receive()
    if incoming == 'flash':
        sleep(random.randint(50, 350))
        display.show(flash, delay=100, wait=False)
        if random.randint(0, 9) == 0:
            sleep(500)
            radio.send('flash')

內容解密:

  1. 動畫效果實作

    • 建立漸變閃爍動畫陣列flash
    • 使用Image().invert()實作畫面反轉效果。
  2. 同步機制

    • 接收到'flash'訊號後隨機延遲顯示閃爍動畫。
    • 以一定機率轉發訊號,實作訊號傳播。
  3. 隨機性設計

    • 使用random.randint()引入隨機延遲,避免同步閃爍。

系統最佳化與擴充套件方向

  1. 安全性提升

    • 增加訊息驗證機制,防止惡意幹擾。
    • 實作簡單的加密傳輸。
  2. 功能擴充套件

    • 新增語音或音樂提示功能。
    • 增加搖晃偵測啟動閃爍效果。
  3. 效能最佳化

    • 改善快取管理策略。
    • 降低不必要的無線電廣播。

微位元(micro:bit)的無線電與網路連線能力

微位元(micro:bit)是一款強大的微控制器,具備無線電通訊能力,能夠實作多個裝置之間的無線資料傳輸。本文將探討微位元的無線電功能及其網路連線能力,並提供程式碼範例來說明如何使用這些功能。

微位元的無線電功能

微位元的無線電功能允許裝置之間進行無線通訊。預設情況下,微位元使用特定的頻率進行通訊,但開發者可以根據需要更改頻道、群組和功率等設定。

使用無線電傳送和接收訊息

微位元提供了簡單易用的API來傳送和接收訊息。開發者可以使用radio.send()radio.receive()函式來傳送和接收字串訊息,或者使用radio.send_bytes()radio.receive_bytes()來傳送和接收位元組訊息。

import radio

# 初始化無線電
radio.on()

while True:
    # 接收無線電訊息
    radio_msg = radio.receive_bytes()
    if radio_msg:
        # 處理接收到的訊息
        print(radio_msg)

    # 傳送無線電訊息
    msg = b'Hello, micro:bit!'
    radio.send_bytes(msg)

處理接收到的訊息

在接收訊息時,可能會遇到額外的位元組。這些額外的位元組是為了與其他平台相容而新增的,通常可以忽略。

import radio

radio.on()

while True:
    radio_msg = radio.receive_bytes()
    if radio_msg:
        # 移除額外的位元組
        if radio_msg[:3] == b'\x01\x00\x01':
            radio_msg = radio_msg[3:]
        # 處理接收到的訊息
        print(radio_msg)

連線USB串列埠讀取訊息

開發者可以透過USB串列埠連線微位元,並讀取從微位元傳送的訊息。可以使用pySerial函式庫來實作這一點。

import serial
from serial.tools.list_ports import comports

def find_microbit():
    ports = comports()
    for port in ports:
        if "VID:PID=0D28:0204" in port[2].upper():
            return port[0]
    return None

def get_serial():
    port = find_microbit()
    if port is None:
        raise IOError('無法找到微位元。')
    return serial.Serial(port, 115200, timeout=1, parity='N')

serial_conn = get_serial()

while True:
    msg = serial_conn.read_all()
    if msg:
        print(msg)

ESP8266/32 WiFi模組

要使微位元具備網際網路連線能力,可以使用ESP8266或ESP32 WiFi模組。這些模組提供了WiFi連線功能,使得微位元可以連線到網際網路。

連線到WiFi網路

可以使用network模組來連線到WiFi網路。

import network

# 初始化WiFi站點
station = network.WLAN(network.STA_IF)

# 啟用WiFi站點
station.active(True)

# 掃描可用的WiFi網路
available_networks = station.scan()
for network in available_networks:
    print(network)

設定存取點

也可以將ESP8266/32設定為WiFi存取點,讓其他裝置連線。

import network

# 初始化存取點
access_point = network.WLAN(network.AP_IF)

# 取得存取點的IP設定
print(access_point.ifconfig())

# 設定DNS伺服器
access_point.ifconfig(dns='208.67.222.222')

設定 WiFi 連線

在開始使用 MicroPython 進行網路相關操作之前,首先需要設定 WiFi 連線。這包括將裝置設定為存取點(Access Point)或連線到第三方 WiFi 網路。

設定裝置為存取點

若要將裝置設定為存取點,可以使用 config 方法,如下所示:

>>> access_point.config('essid')
'MicroPython-121ce1'
>>> access_point.config('authmode')
4
>>> access_point.config(essid='new_net_name', password='new_password')
>>> access_point.config('password')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: unknown config param

內容解密:

  • access_point.config('essid') 用於查詢目前的網路名稱。
  • access_point.config('authmode') 傳回目前的驗證模式。
  • access_point.config(essid='new_net_name', password='new_password') 更新網路名稱和密碼。
  • access_point.config('password') 嘗試查詢密碼,但 MicroPython 不會顯示密碼,因此會出現錯誤。

MicroPython 支援以下引數來定義存取點網路的設定:

  • mac:MAC 位址,以位元組表示。
  • essid:WiFi 存取點的網路名稱,以字串表示。
  • channel:WiFi 頻道,以整數表示。
  • hidden:布林值,表示網路是否隱藏。
  • authmode:支援的驗證模式,如前所述。
  • password:密碼,以字串表示。

建議在將裝置用作存取點時盡快更新網路名稱(essid)和密碼。

連線到 WiFi 網路

若要將裝置連線到可用的 WiFi 網路,請啟用站點(station)並呼叫 connect 方法:

>>> station.active(True)
>>> station.connect('Network Name', 'password123')
>>> station.ifconfig()
('192.168.178.190', '255.255.255.0', '192.168.178.1', '192.168.178.1')

內容解密:

  • station.active(True) 啟用站點。
  • station.connect('Network Name', 'password123') 連線到指定的 WiFi 網路。
  • station.ifconfig() 傳回裝置的 IP 位址組態。

一旦連線,ifconfig 方法會告訴你裝置的 IP 位址。MicroPython 會記住站點和存取點模式的組態,因此在重啟後裝置會嘗試還原或重新連線。

管理連線

你可以輕鬆停用站點或存取點連線:

>>> access_point.active(False)

或者,你可以斷開連線:

>>> access_point.disconnect()

要檢查連線狀態,可以使用 isconnected 方法或 status 方法:

>>> station.isconnected()
True
>>> access_point.status()
STAT_GOT_IP

內容解密:

  • isconnected 方法傳回布林值,表示連線狀態。
  • status 方法傳回連線狀態的列表。

簡單的網路連線範例

以下範例展示如何使用 socket 模組連線到伺服器並接收資料:

>>> import socket
>>> addr_info = socket.getaddrinfo("towel.blinkenlights.nl", 23)
>>> addr_info
[(2, 1, 0, '', ('94.142.241.111', 23))]
>>> server_addr = addr_info[0][-1]
>>> s = socket.socket()
>>> s.connect(server_addr)
>>> while True:
...     data = s.recv(500)
...     print(str(data, 'utf8'), end='')
...

內容解密:

  • socket.getaddrinfo 方法將網域名稱轉換為 IP 位址。
  • 建立 socket 連線到遠端伺服器。
  • 無限迴圈接收並列印從伺服器接收的資料。

使用 urequests 模組簡化 HTTP 請求

MicroPython 的 urequests 模組模擬了 requests 模組的核心功能,使得發出 HTTP 請求變得更加容易:

>>> import urequests as requests
>>> response = requests.get('http://micropython.org/')

內容解密:

  • 使用 urequests 模組發出 GET 請求。
  • requests.get 方法傳回伺服器的回應。

網路應用與MQTT協定

MicroPython在ESP8266上的網路功能非常強大,允許開發者輕鬆地與各種網路服務進行互動。由於大多數根據HTTP的程式化互動都使用JSON格式,因此使用諸如Star Wars API等服務變得非常簡單。

使用urequests進行HTTP請求

首先,我們來看看如何使用urequests模組來進行HTTP請求。以下是一個簡單的例子,展示瞭如何從Star Wars API取得資料:

>>> import urequests as requests
>>> response = requests.get('http://swapi.co/api/people/1/')
>>> dir(response)
['text', '__init__', '__qualname__', 'close', 'content', 'json', '__module__', 'encoding', 'raw', 'reason', '_cached', 'status_code']
>>> person = response.json()
>>> person['name']
'Luke Skywalker'
>>> person['homeworld']
'http://swapi.co/api/planets/1/'
>>> person['films']
['http://swapi.co/api/films/6/', 'http://swapi.co/api/films/3/', 'http://swapi.co/api/films/2/', 'http://swapi.co/api/films/1/', 'http://swapi.co/api/films/7/']

內容解密:

  • urequests.get()用於傳送HTTP GET請求到指定的URL。
  • response.json()將伺服器的回應解析為Python字典。
  • 我們可以像存取普通字典一樣存取傳回的資料,例如person['name']

傳送資料到伺服器

除了取得資料外,我們還可以向伺服器傳送資料。以下是一個使用JSON placeholder服務傳送資料的例子:

>>> import urequests as requests
>>> import json
>>> data = json.dumps({'hello': 'world'})
>>> url = 'http://jsonplaceholder.typicode.com/posts'
>>> response = requests.post(url, data=data)
>>> response.json()
{'id': 101}

內容解密:

  • json.dumps()將Python字典轉換為JSON格式的字串。
  • requests.post()用於傳送HTTP POST請求,將資料傳送到指定的URL。
  • 伺服器回應一個包含新建立資源ID的JSON物件。

建立簡單的Web伺服器

MicroPython還允許我們在ESP8266上建立一個簡單的Web伺服器。以下是一個例子,展示瞭如何建立一個傳回GPIO引腳狀態的JSON表示的Web伺服器:

import machine
import socket
import json

template = """HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: {length}
Server: MicroPython

{json}"""

pins = [machine.Pin(i, machine.Pin.IN) for i in (0, 2, 4, 5, 12, 13, 14, 15)]
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]

s = socket.socket()
s.bind(addr)
s.listen(1)
print('listening on', addr)

while True:
    cl, addr = s.accept()
    print('client connected from', addr)
    cl_file = cl.makefile('rwb', 0)
    while True:
        line = cl_file.readline()
        if not line or line == b'\r\n':
            break
    status = {str(p): p.value() for p in pins}
    data = json.dumps(status)
    response = template.format(length=len(data), json=data)
    cl.send(response)
    cl.close()

內容解密:

  • 使用socket模組建立一個TCP通訊端,並監聽80埠上的連線請求。
  • 當客戶端連線時,讀取請求頭,直到遇到空行。
  • 取得GPIO引腳的狀態,將其轉換為JSON格式的字串。
  • 將JSON資料插入到HTTP回應範本中,並傳送給客戶端。

MQTT協定簡介

MQTT(Message Queue Telemetry Transport)是一種輕量級的發布/訂閱(pub/sub)訊息傳輸協定。在MQTT網路中,裝置(稱為客戶端)連線到一個中央伺服器(稱為代理),並訂閱他們感興趣的主題。客戶端也可以向主題發布訊息。許多客戶端可以訂閱同一個主題,並且任何發布到該主題的訊息都將被匯總到訂閱者。

MQTT的工作原理

  • 主題命名: 主題使用類別似於URL路徑的命名約定,使用“/”作為分隔符。這使得主題可以按照共同的主題進行組織,並且命名約定可以隨著時間的推移而演變。
  • 發布和訂閱: 客戶端可以向特定主題發布訊息,也可以訂閱特定主題以接收發布到該主題的訊息。
  • 萬用字元: 客戶端可以使用萬用字元(+和#)來訂閱符合特定模式的所有主題。