はじめに
こちらの続きです。
ESP-IDFを使ってESP32からAWS-IoTにつないでみた
上記で利用したesp-aws-iotのサンプルをカスタマイズして、温湿度センサのデータをAWS IoTへ送ってみました。
【今回の環境】
- 開発環境:Windows 10 + MSP-IDF
- ボード:ESP32-DevKitC-32D
- センサ:Adafruit Si7021
センサはアスクルで買いました。アスクルは文房具だけじゃないのですね。
センサの接続
ESP32 | Si7021 |
---|---|
3V3 | VIN |
GND | GND |
IO21 | SDA |
IO22 | SCL |
センサのデータを読み取るプログラム
Adafruit Si7021を操作するライブラリは、ArduinoやPython用のものはありましたが、ESP-IDFで使えそうなものはありません。とはいえI2Cの操作を一から書くのも自身が無かったので、ググって以下の記事を参考にさせていただきました。
Hardware Interactions: Part 4 – I2C Temperature and Humidity Sensor
まず、サンプルのsubscribe_publish_sample.c
の中に、以下3つの関数を追加定義。
int initSensor(void)
float readTemp(void)
float readHumid(void)
#include "driver/i2c.h"
// Commands for Si7021
#define SI_7021_ADDRESS 0x40
#define SI_7021_MEASURE_HUMIDITY 0xE5
#define SI_7021_MEASURE_TEMPERATURE 0xE3
#define SI_7021_TIMEOUT (1000 / portTICK_RATE_MS)
static int initSensor(void)
{
esp_err_t error;
i2c_config_t config;
config.sda_io_num = 21;
config.sda_pullup_en = GPIO_PULLUP_ENABLE;
config.scl_io_num = 22;
config.scl_pullup_en = GPIO_PULLUP_ENABLE;
config.mode = I2C_MODE_MASTER;
config.master.clk_speed = 100000;
error = i2c_param_config(I2C_NUM_0, &config);
if (error != ESP_OK) {
ESP_LOGI(TAG, "Failed to configure shared i2c bus: %s", esp_err_to_name(error));
return -1;
}
error = i2c_set_timeout(I2C_NUM_0, 100000);
if (error != ESP_OK) {
ESP_LOGI(TAG, "Failed set timeout for i2c bus: %s", esp_err_to_name(error));
return -1;
}
error = i2c_driver_install(I2C_NUM_0, config.mode, 512, 512, 0);
if (error != ESP_OK) {
ESP_LOGI(TAG, "Failed to install driver for i2c bus: %s", esp_err_to_name(error));
return -1;
}
return 0;
}
static float readTemp(void)
{
i2c_cmd_handle_t handle;
esp_err_t error;
// Write measure humidity command
handle = i2c_cmd_link_create();
i2c_master_start(handle);
i2c_master_write_byte(handle,
SI_7021_ADDRESS << 1 | I2C_MASTER_WRITE,
I2C_MASTER_ACK);
i2c_master_write_byte(handle,
SI_7021_MEASURE_TEMPERATURE,
I2C_MASTER_ACK);
i2c_master_stop(handle);
error = i2c_master_cmd_begin(I2C_NUM_0, handle, SI_7021_TIMEOUT);
i2c_cmd_link_delete(handle);
if (error != ESP_OK) {
ESP_LOGI(TAG, "Failed to write temperature command: %s", esp_err_to_name(error));
return 0;
}
vTaskDelay(50 / portTICK_RATE_MS);
// Read two bytes from the temperature and humidity sensor
uint8_t tmpMSB;
uint8_t tmpLSB;
handle = i2c_cmd_link_create();
i2c_master_start(handle);
i2c_master_write_byte(handle,
SI_7021_ADDRESS << 1 | I2C_MASTER_READ,
I2C_MASTER_ACK);
i2c_master_read_byte(handle, &tmpMSB, I2C_MASTER_ACK);
i2c_master_read_byte(handle, &tmpLSB, I2C_MASTER_NACK);
i2c_master_stop(handle);
error = i2c_master_cmd_begin(I2C_NUM_0, handle, SI_7021_TIMEOUT);
i2c_cmd_link_delete(handle);
if (error != ESP_OK) {
ESP_LOGI(TAG, "Failed to read temperature: %s", esp_err_to_name(error));
return 0;
}
float temp = ((uint16_t) tmpMSB << 8) | (uint16_t) tmpLSB;
temp *= 175.72;
temp /= 65536;
temp -= 46.85;
return temp;
}
static float readHumid(void)
{
i2c_cmd_handle_t handle;
esp_err_t error;
// Write measure humidity command
handle = i2c_cmd_link_create();
i2c_master_start(handle);
i2c_master_write_byte(handle,
SI_7021_ADDRESS << 1 | I2C_MASTER_WRITE,
I2C_MASTER_ACK);
i2c_master_write_byte(handle,
SI_7021_MEASURE_HUMIDITY,
I2C_MASTER_ACK);
i2c_master_stop(handle);
error = i2c_master_cmd_begin(I2C_NUM_0, handle, SI_7021_TIMEOUT);
i2c_cmd_link_delete(handle);
if (error != ESP_OK) {
ESP_LOGI(TAG, "Failed to write humidity command: %s", esp_err_to_name(error));
return 0;
}
vTaskDelay(50 / portTICK_RATE_MS);
// Read two bytes from the temperature and humidity sensor
uint8_t humMSB;
uint8_t humLSB;
handle = i2c_cmd_link_create();
i2c_master_start(handle);
i2c_master_write_byte(handle,
SI_7021_ADDRESS << 1 | I2C_MASTER_READ,
I2C_MASTER_ACK);
i2c_master_read_byte(handle, &humMSB, I2C_MASTER_ACK);
i2c_master_read_byte(handle, &humLSB, I2C_MASTER_NACK);
i2c_master_stop(handle);
error = i2c_master_cmd_begin(I2C_NUM_0, handle, SI_7021_TIMEOUT);
i2c_cmd_link_delete(handle);
if (error != ESP_OK) {
ESP_LOGI(TAG, "Failed to read humidity: %s", esp_err_to_name(error));
return 0;
}
float humid = ((uint16_t) humMSB << 8) | (uint16_t) humLSB;
humid *= 125;
humid /= 65536;
humid -= 6;
return humid;
}
そして、whileループの手前でinitSensor()
を呼んでセンサを初期化し、whileループの中でメッセージを送っている部分を以下で置き換えます。
sprintf(cPayload, "{\"Temperature\": %.02f, \"Humidity\": %.02f}", readTemp(), readHumid());
paramsQOS1.payloadLen = strlen(cPayload);
rc = aws_iot_mqtt_publish(&client, TOPIC, TOPIC_LEN, ¶msQOS1);
あとはいくつか微修正。
MQTTのトピック名を変更。
const char *TOPIC = "esp32/temphumid";
whileループの中の待ち時間を1秒から20秒に変更。
vTaskDelay(20 * 1000 / portTICK_RATE_MS);
ビルドと書込み
ビルドして書込みます。
idf.py build
idf.py -p COM3 flash
AWS IoTのコンソールで確認すると、良い感じでメッセージが送られてきています。
AWS側でグラフ化
グラフ化に際してはこちらを参考にさせていただきました。
AWS IoT に上げたデータをCloudWatchで簡単にグラフ化する
AWS IoTで「ルール」を作成
AWS IoTの「ACT」-「ルール」を開き、
「ルールの作成」へ。以下の設定をして「ルールの作成」をクリック。
項目 | 設定値 |
---|---|
名前 | ESP32_TempHumid |
ルールクエリステートメント | SELECT * FROM 'esp32/temphumid' |
アクション | CloudWatch Logsにメッセージデータを送信する |
ロググループ名 | ESP32_TempHumid(新規作成) |
ロール | CloudWatch(新規作成) |
CloudWatchでグラフ化
続いて、CloudWatchの画面で「インサイト」を開きます。
先ほど作成したロググループを選択し、クエリ欄に以下を入力して「クエリの実行」をクリックすると、ESP32から送られた温度の一分毎の平均値が表示されます。
stats avg(Temperature) by bin(1m)
「ダッシュボードに追加」をクリックし、新しく作ったダッシュボードに折れ線グラフを追加します。
もう一度「インサイト」に戻って、湿度についても同様に追加すると、温度と湿度が良い感じでグラフ表示されるようになりました。
おしまい。