ESP32とDHT11で取得した温湿度をAWS IoT Coreへ送信してみた
こんにちは!コンサルティング部のくろすけです!
今回は、ESP32とDHT11を使い、取得した温度・湿度をAWS IoT CoreへMQTTで送信してみました。
本記事では、環境構築からつまずいたポイント、解決方法までをまとめます。
前提
今回使用したのは、Freenove Basic Starter Kit for ESP32(FNK0061)です。
ESP32-WROVERを中心に、拡張ボード、カメラ、各種センサー、電子部品などを含むスターターキットです。
| 項目 | 内容 |
|---|---|
| スターターキット | Freenove FNK0061 |
| MicroPythonファームウェア | MicroPython v1.28.0 |
| デプロイ・REPL | mpremote v1.28.0 |
| センサー | DHT11 |
| MQTT送信間隔 | 5分 |
今回はMicroPythonを使用します。MicroPythonはESP32上でPythonを実行するための処理系です。
また、使い慣れているCursorを使用したかったので、ESP32へのファイル転送やREPL接続にはmpremoteを利用しました。
やってみた
1. MicroPythonを書き込む
最初にMicroPythonのファームウェアを書き込みます。
ファームウェアはMicroPython ESP32_GENERIC Downloadsからダウンロードします。
esptool --chip esp32 --port "<SERIAL_PORT>" erase-flash
esptool --chip esp32 --port "<SERIAL_PORT>" \
write-flash -z 0x1000 "ESP32_GENERIC-<version>.bin"
書き込み後は、以下のコマンドでREPLへ接続できます。
mpremote connect "<SERIAL_PORT>" repl
>>>プロンプトが表示され、print("Hello, ESP32!")が正常に出力されれば準備完了です。

2. mpremoteで開発中のスクリプトを実行・転送する
開発中のスクリプトは、runでESP32上に一度だけ送って実行できます。
mpremote connect "<SERIAL_PORT>" run <SCRIPT_NAME>.py

一方、ESP32をMacから外しても自律実行させる場合は、ファイルをESP32のルートへ転送します。
mpremote connect "<SERIAL_PORT>" cp <SCRIPT_NAME>.py :<SCRIPT_NAME>.py
3. DHT11をGPIO 27へ接続する
DHT11はI²Cではなく、1本のDATA線で通信するセンサーです。DATA線には入力・出力の両方で使えるGPIOを選ぶ必要があります。
今回は以下のように配線しました。

温湿度の取得には、MicroPython標準のdhtモジュールを使います。
検証中のサンプルコード
import dht
from machine import Pin
sensor = dht.DHT11(Pin(27))
sensor.measure()
print(sensor.temperature())
print(sensor.humidity())
4. Wi-Fiへ接続する
ESP32のWi-Fi接続は、プログラムからSSIDとパスワードを指定します。
ESP32-D0WD-V3は2.4GHz帯のみをサポートするため、5GHzのSSIDを指定すると接続できませんでした。
検証中のサンプルコード
import network
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
5. AWS IoT CoreへMQTT送信する
AWS IoT Coreの設定については、他の記事での紹介が多いため、ここでは割愛します。
公式ドキュメントでは下記が参考になるかと思います。
AWS IoT Coreとの接続には、MQTT over TLS(ポート8883)とX.509証明書を使用します。
ESP32側には次のファイルを配置しました。
/main.py
/config.py
/AmazonRootCA1.der
/device.pem.crt
/private.pem.key
MicroPythonにはAWS IoT Device SDKはないため、軽量なMQTTクライアントであるumqtt.simpleを利用しました。
AWS IoTのエンドポイント、Wi-Fi認証情報、デバイス証明書、秘密鍵、Amazon Root CA 1のパスなどはconfig.pyへ設定しています。
config.py
WIFI_SSID = "<WIFI_SSID>"
WIFI_PASSWORD = "<WIFI_PASSWORD>"
AWS_IOT_ENDPOINT = "<AWS_IOT_ENDPOINT>"
THING_NAME = "dht11-esp32"
MQTT_TOPIC = "devices/dht11-esp32/telemetry"
MQTT_PORT = 8883
DHT_PIN = 27
AMAZON_ROOT_CA = "<AMAZON_ROOT_CA_PATH>"
DEVICE_CERTIFICATE = "<DEVICE_CERTIFICATE_PATH>"
PRIVATE_KEY = "<PRIVATE_KEY_PATH>"
main.py
import dht
import json
import network
import ntptime
import ssl
import time
from machine import Pin
from umqtt.simple import MQTTClient
from config import (
AMAZON_ROOT_CA,
AWS_IOT_ENDPOINT,
DEVICE_CERTIFICATE,
DHT_PIN,
MQTT_PORT,
MQTT_TOPIC,
PRIVATE_KEY,
THING_NAME,
WIFI_PASSWORD,
WIFI_SSID,
)
sensor = dht.DHT11(Pin(DHT_PIN))
def read_binary(path):
with open(path, "rb") as file:
return file.read()
def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print("Connecting to Wi-Fi...")
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
for _ in range(20):
if wlan.isconnected():
break
time.sleep(1)
if not wlan.isconnected():
raise OSError("Wi-Fi connection timed out")
print("Wi-Fi connected:", wlan.ifconfig()[0])
def sync_clock():
try:
ntptime.settime()
print("Clock synchronized with NTP")
except OSError as error:
print("NTP synchronization failed:", error)
def connect_mqtt():
client = MQTTClient(
client_id=THING_NAME,
server=AWS_IOT_ENDPOINT,
port=MQTT_PORT,
ssl=True,
ssl_params={
"key": PRIVATE_KEY,
"cert": DEVICE_CERTIFICATE,
"cadata": read_binary(AMAZON_ROOT_CA),
"cert_reqs": ssl.CERT_REQUIRED,
"server_hostname": AWS_IOT_ENDPOINT,
},
)
client.connect()
print("Connected to AWS IoT Core")
return client
def read_telemetry():
sensor.measure()
return json.dumps(
{
"thing_name": THING_NAME,
"temperature_c": sensor.temperature(),
"humidity_percent": sensor.humidity(),
"timestamp": time.time(),
}
)
def disconnect(client):
if client is None:
return
try:
client.disconnect()
except OSError:
pass
def main():
connect_wifi()
sync_clock()
client = None
while True:
try:
if client is None:
client = connect_mqtt()
message = read_telemetry()
client.publish(MQTT_TOPIC, message)
print("Published:", message)
except OSError as error:
print("DHT11, network, or MQTT error:", error)
disconnect(client)
client = None
time.sleep(300)
if __name__ == "__main__":
main()
つまずき: CA証明書の形式
最初はAmazon Root CA 1のPEMファイルのパスをcadataへ渡しており、以下のエラーになりました。
ValueError: invalid cert
MicroPython v1.28では、cadataへDER形式の証明書バイト列を渡す必要があります。
PEM形式のAmazon Root CA 1をDER形式へ変換し、バイト列として読み込むことで解決しました。
openssl x509 \
-in AmazonRootCA1.pem \
-outform DER \
-out AmazonRootCA1.der
送信するデータ
送信するJSONは以下の形式です。温度・湿度はDHT11から読み取り、5分ごとにdevices/dht11-esp32/telemetryへ送信しています。
{
"thing_name": "dht11-esp32",
"temperature_c": 27,
"humidity_percent": 56,
"timestamp": 840529808
}
IoT Core側で確認できました!

あとがき
実際にデバイスを含めて動かしてみると、アイデアが湧いてきて楽しいですね!
今後は IoT データのAWS上での分析や処理についても試してみたいと思います。
以上、くろすけでした!





