はじめに
WiFiモジュールを搭載したマイコンモジュールの一つにESP32があります。
マイコン初心者の私が備忘録を兼ねて、Micropython環境の構築からSwitchbotAPIを操作するところまで書きます。
以下の流れです。
- ESP32 PC接続設定
- MicroPython環境構築
- ESP32 WiFi接続
- SwitchbotAPI操作
参考
MicroPython環境構築の参考にしました。
Zenn: Thonnyで、ESP32 - MicroPython環境を構築するよ
ネットワーク接続の参考にしました。ESP8266とありますが、ESP32でも使えるようです。
MicroPython: ESP8266 用クイックリファレンス
SwitchbotAPIのドキュメント
GitHub: OpenWonderLabs/SwitchBotAPI
ヘッダーの作成の参考にしました。
Qiita: [Switchbot API v1.1が登場] APIでSwitchBotロックを遠隔操作する
SwitchbotAPIの認証キーを生成する際に用いるmicropython-hmacではエラーがでて困りましたが、こちらを使えば解決しました。
GitHub: gloveboxes/ESP32-Micropython-Azure-IoT-and-Event-Hub-Client
環境
- ホストPC
- OS: windows 10 Pro 64bit
- Python: Python 3.7.4
- IDE: Thonny 4.01
- マイコンボード
- ESP32: Aideepen ESP32 ESP-32S 開発ボード
1. ESP32 PC接続設定
まずはESP32をUSB(microB-TypeA)ケーブルでPCに接続し、
「デバイスマネージャー」の「ポート(COMとLPT)」欄を開きます。
その中の「Silicon Labs CP210x USB to UART Bridge」末尾についているCOM~の番号を覚えておきます。
黄色の!が表示されている場合はドライバが入っていないので、Silicon Labs: CP210x USB to UART Bridge VCP Driversからドライバをダウンロードしインストールしてください。
ESP32とPCの接続はこれで完了です。
2. MicroPython環境構築
参考ページに従って設定します。
MicroPythonのリンクからファームウェアをダウンロードします。
ホストPCにESP32にファームウェアを書き込むためのモジュールをインストールします。
pip install esptool
ESP32のROMを消去します。com~にはデバイスマネージャーで確認したポート番号を指定します。
esptool --port com5 erase_flash
ファームウェアのダウンロード先に作業ディレクトリを移動し、以下のコマンドを入力してESP32にファームウェアを書き込みます。
esptool --chip esp32 --port com5 write_flash -z 0x1000 esp32-20220618-v1.19.1.bin
Thonnyをインストールし起動します。
右下のインタプリタ設定から「MicroPython(ESP32)・COM~」を選択すれば準備は完了です。
3. ESP32 WiFi接続
ESP32を自宅のWiFiに接続します。以下のクイックリファレンスにESP8266とありますが、ESP32でもそのまま動きます。
MicroPython: ESP8266 用クイックリファレンス
def do_connect():
import network
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('connecting to network...')
wlan.connect('ssid', 'key') #ここに接続したいWiFiのSSIDとパスワードを書く
while not wlan.isconnected():
pass
print('network config:', wlan.ifconfig()) #IPアドレス、ネットマスク、ゲートウェイ、DNS
接続が完了するとIPアドレス、ネットマスク、ゲートウェイ、DNSが表示されます。
簡単にマイコンのWiFi接続ができました。便利です。
4. SwitchbotAPI操作
公式ドキュメントに従います。
SwitchbotAPIの操作の流れは以下の通りです。
- 認証のためのヘッダーを作成する
- Switchbotのデバイス一覧を取得し、操作したいデバイスのIDを確認する
- デバイスに対して操作を行う
4-1. 認証のためのヘッダーを作成する
Switchbotのスマホアプリの「設定」→「アプリバージョン」を項目を連続で10回タップすると「トークンを取得」ボタンが現れます。これを記録しておきます。
公式ドキュメントの「Authentication」項のサンプルプログラムと参考をもとにしました。
ホストPCではこのまま動きますが、ESP32で実行するためにはMicroPythonのデフォルトのライブラリにhmac, base64がないためモジュールの追加インストールが必要です。
import time
import hashlib
import hmac
import base64
# open token
token = '' # copy and paste from the SwitchBot app V6.14 or later
# secret key
secret = '' # copy and paste from the SwitchBot app V6.14 or later
def get_auth_header(token, secret):
nonce = '' #空欄のままで良いらしい
t = int(round((time.time() + 946684800) * 1000)) #後述 基準の時刻がホストPCとESP32で異なるため30年分の秒数を足す
string_to_sign = '{}{}{}'.format(token, t, nonce)
string_to_sign = bytes(string_to_sign, 'utf-8')
secret = bytes(secret, 'utf-8')
sign = base64.b64encode(hmac.new(secret, msg=string_to_sign,
digestmod=hashlib.sha256).digest())
print ('Authorization: {}'.format(token))
print ('t: {}'.format(t))
print ('sign: {}'.format(str(sign, 'utf-8')))
print ('nonce: {}'.format(nonce))
header={}
header["Authorization"] = token
header["sign"] = str(sign, 'utf-8')
header["t"] = str(t)
header["nonce"] = nonce
return header
ここで色々つまづきました。
MicroPython版のパッケージ管理モジュールupipでhmacをインストールし、上のプログラムのハッシュ化部分を実行すると以下のエラーがでます。
Traceback (most recent call last):
File "<stdin>", line 5, in <module>
File "/lib/hmac.py", line 149, in new
File "/lib/hmac.py", line 63, in __init__
AttributeError: 'sha256' object has no attribute 'digest_size'
困り果てましたが、GitHub: gloveboxes/ESP32-Micropython-Azure-IoT-and-Event-Hub-Clientからhashlib, base64.py, hmac.py, warnings.pyをESP32にインストールしたところ無事ハッシュ化できました。
これで認証ヘッダーの生成は完了です。
4-2. Switchbotのデバイス一覧を取得し、操作したいデバイスのIDを確認する
公式ドキュメントに従って、Switchbotデバイスの一覧を取得します。
host_domain = "https://api.switch-bot.com"
ver = "/v1.1"
def get_device_list(header):
response = urequests.get(host_domain + ver + "/devices", headers=header)
return_json = response.json()
if return_json["message"] == "success":
print("取得成功")
return return_json["body"]
elif return_json["message"] == "Unauthorized":
print("認証エラー")
return None
else:
print("エラー")
return None
header = get_auth_header(token, secret)
device_list = get_device_list(header)
print(device_list)
ここで、ホストPCでAPIを操作したあとにESP32で同じことをしたら認証エラーがでました。
詳しく調べていませんが、ホストPCとESP32でtime.time()で得るエポック秒数が大きくずれていることが問題のようでした。
それぞれの基準時刻を取得します。
imoort time
time.gmtime(0)
ホストPCの基準時刻は1970/01/01 00:00:00です。
time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)
一方でESP32の基準時刻は2000/01/01 00:00:00です。
(2000, 1, 1, 0, 0, 0, 5, 1)
両者の差の秒数を求めます。
import datetime
(datetime.datetime(2000,1,1,0,0,0) - datetime.datetime(1970,1,1,0,0,0)).total_seconds()
946684800.0
以上からget_auth_header関数ではこの秒数を足しています。
これで今のところ問題は起こっていませんが、もっと良い対処法がありそうです。
t = int(round((time.time() + 946684800) * 1000))
これでSwitchbotのデバイス一覧が取得できました。
操作したいデバイスのdeviceIdを控えておきます。
4-3. デバイスに対して操作を行う
ここではお試しで温湿度計の温度を取得してみます。
def get_th(header):
th_deviceid = "" #デバイスIDを入力する
response = urequests.get(host_domain + ver +"/devices/" + th_deviceid + "/status", headers=header)
temperature = response.json()["body"]["temperature"]
humidity = response.json()["body"]["humidity"]
return temperature, humidity
header = get_auth_header(token, secret)
temperature, humidity = get_th(header)
print(f"室温:{temperature}℃ 湿度{humidity}%")
室温:25.1℃ 湿度42%
無事に温度と湿度が取得できました。
他のデバイスの操作も公式ドキュメントを参考に行えます。
本文で使用したプログラムを以下にアップロードしました。
まとめ
タイトルの通り、マイコンボードESP32についてMicroPython環境構築からSwitchbotAPI操作まで行いました。いくつかの躓きがありましたが、最終的に温湿度計のデータを取得するところまで来ました。
なにかの役に立てば幸いです。