開発環境構築
今回IoT デバイス側のコード実装には、Arduino IDE をMacBook Proにインストールして使用。
環境構築手順
1. Install Arduino IDE
2. Setup IDE
省略!
3. Add additional libraries
ESP32 ESP-32S
BME280
Adafruit_SSD1306
4. Install USB- UART bridge driver
5. Install phython3 (Option)
2台あるうちのIDEをインストールしたMacBook Pro には何故かphyhon3 がインストールされていなくてエラーとなったので別途インストールを行った。
コード記述
機能設計
機能1 – WEB サーバー
Wifi 接続を前提として、WEB 機能を実装。
環境により要下記情報変更
IP アドレス – 192.168.1.49 に固定
ポート番号 – 8090 (将来的なNAT用)
機能2 – センサ情報読み出し
BME280 センサから、温度・湿度・気圧情報を読み出す
機能3 – OLED表示
ブレッドボード上のOLEDディスプレーに、現在時刻と計測値を交互に表示
コード記述
Arduino IDE で下記コードをコンパイル&書き込みを行う。
– 要変更箇所
Wifi のSSIDとパスワード情報は環境に合わせて変更
固定IP アドレスを設定するようになっているが、環境に応じて変更
DHCP 管理で良ければ、WiFi.config行をコメントとすれば良い
(IP アドレスはシリアル画面に表示される)
/*
// WiFi Network
*/
#include <WiFi.h>
#include <WiFiClient.h>
const char* ssid = "xxxxxxx"; // 要変更
const char* password = "yyyyyyy"; // 要変更
IPAddress ip(192, 168, 1, 49); // 固定IPアドレス設定関係
IPAddress gateway(192,168, 1, 1); //
IPAddress subnet(255, 255, 255, 0); //
IPAddress DNS(192, 168, 1, 1); //
/*
// Web Server
*/
#include <WebServer.h>
WebServer server(8090); // ポート番号
/*
// BME280 Sensor (Temperature, Humidity, Pressure)
*/
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
//#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C
//Adafruit_BME280 bme(BME_CS); // hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI
/*
// OLED SSD1306
*/
#include <Wire.h>
#include "SSD1306.h" // ディスプレイ用ライブラリを読み込み
SSD1306 display(0x3c, 21, 22); // SSD1306インスタンスの作成(I2Cアドレス,SDA,SCL)
/*
//
// Routines
//
*/
void handleData() {
char dt_msg[20]; // 日時文字列格納用
char wb_msg[400]; // WEB 返信文字列格納用
float room_temp,room_humi,room_prss; // 温度データ、湿度データ、気圧データ
struct tm timeInfo; // 時刻を格納する構造体
// BME280センサより温度データ、湿度データ、気圧データの取得
room_temp = bme.readTemperature();
room_humi = bme.readHumidity();
room_prss = bme.readPressure() / 100.0F;
// 日時情報の取得
getLocalTime(&timeInfo);
sprintf(dt_msg, "%04d/%02d/%02d %02d:%02d:%02d",
timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday,
timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec);
// データ返送文字列作成
sprintf(wb_msg, "%s\nRoom Temrerature=%2.2f *C,Room Humidity=%2.2f %%,Atmospheric Pressure=%4.2f hPa\n%2.2f\n%2.2f\n%4.2f\n",
dt_msg, room_temp, room_humi, room_prss, room_temp, room_humi, room_prss);
server.send(200, "text/plain", wb_msg); // WEB TEXT 返送
// 日時調整
configTime(9 * 3600L, 0, "ntp.nict.jp", "time.google.com", "ntp.jst.mfeed.ad.jp");
}
void handleRoot() {
char dt_msg[20]; // 日時文字列格納用
char wb_msg[400]; // WEB 返信文字列格納用
struct tm timeInfo; // 時刻を格納する構造体
float room_temp,room_humi,room_prss; // 温度データ、湿度データ、気圧データ
// 日時情報の取得
getLocalTime(&timeInfo);
sprintf(dt_msg, "%04d/%02d/%02d %02d:%02d:%02d",
timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday,
timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec);
// BME280センサより温度データ、湿度データ、気圧データの取得
room_temp = bme.readTemperature();
room_humi = bme.readHumidity();
room_prss = bme.readPressure() / 100.0F;
// HTML 構文構築
sprintf(wb_msg, "<html>\n<head><title>RoomStat WEB</title></head>\n<body>\n<h1>%s</h1>\n<h2>Temperature=%2.2f *C</h2>\n<h2>Humidity=%2.2f %%</h2>\n<h2>Pressure=%4.2f hPa</h2>\n<body>\n</html>\n",
dt_msg, room_temp, room_humi, room_prss);
Serial.println(wb_msg);
server.send(200, "text/html", wb_msg); // WEB HTML 返送
}
void handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
}
void setup(void) {
Serial.begin(115200); // シリアルコンソールの速度設定
bool status;
Serial.print(F("Checking BME280... ")); // BME280センサ確認開始メッセージ表示
// default settings
// (you can also pass in a Wire library object like &Wire2)
status = bme.begin(0x76);
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
} else {
Serial.println("OK");
}
delay(10);
Serial.print("Checking OLED... "); // OLEDディスプレー初期化開始メッセージ表示
status = display.init(); //ディスプレイを初期化
if (!status) {
Serial.println("Could not find a valid OLED display, check wiring!");
while (1);
} else {
Serial.println("OK");
}
display.setFont(ArialMT_Plain_16); // フォント設定
display.drawString(0, 0, "Initializing...\n.........\n.........");
display.display(); //指定された情報を描画
delay(10);
Serial.println("Setting up WEB server"); // WEBサーバー開始メッセージ表示
WiFi.config(ip, gateway, subnet, DNS); // Set fixed IP address
delay(10);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password); // WiFi接続開始
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
// 接続情報表示
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// WEB リクエストマッピング設定
server.on("/", handleRoot);
server.on("/data", handleData);
server.on("/inline", []() {
server.send(200, "text/plain", "this works as well");
});
server.onNotFound(handleNotFound);
// WEB サービス開始
server.begin();
Serial.println("HTTP server started");
// 時間調整
configTime(9 * 3600L, 0, "ntp.nict.jp", "time.google.com", "ntp.jst.mfeed.ad.jp");
}
void loop(void) {
struct tm timeInfo; // 時刻を格納する構造体
char dt_msg[20]; // 日時文字列格納用
char dp_msg[100]; // ディスプレー表示文字列格納用
float room_temp,room_humi,room_prss; // 温度データ、湿度データ、気圧データ
// 日時情報の取得
getLocalTime(&timeInfo);
sprintf(dt_msg, "%04d/%02d/%02d\n%02d:%02d:%02d",
timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday,
timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec);
server.handleClient();
// Display Date/Time to OLED
display.clear(); // 画面消去
display.drawString(0, 0, dt_msg); // 画面描画
display.display(); // 画面表示
delay(1000);
// OLED表示保持ディレイループ (3秒)
// 単に server.handleI();delay(3000) とするとWEB不感時間が長すぎるので...
for (uint8_t i = 0; i < 30; i++) {
server.handleClient();
delay(100);
}
// BME280センサより温度データ、湿度データ、気圧データの取得
room_temp = bme.readTemperature();
room_humi = bme.readHumidity();
room_prss = bme.readPressure() / 100.0F;
sprintf(dp_msg, "Temp:%2.2f\nHumd:%2.2f\nPres:%4.2f",
room_temp, room_humi, room_prss);
display.clear(); // 画面消去
display.drawString(0, 0, dp_msg); // 画面描画
display.display(); // 画面表示
delay(1000);
// OLED表示保持ディレイループ (4秒)
for (uint8_t i = 0; i < 40; i++) {
server.handleClient();
delay(100);
}
}
WEB(&Network)、BME280、OLED のブロック毎に出来るだけ分けているので、例えばOLED が必要なければ削除は容易だと思う。
シリアルコンソールに初期化状況等表示されるようになっている。
対象IP アドレス接続可能なネットワーク内で、ブラウザから下記URLにアクセスしてセンサーからの情報が得られれば確認完了。
http://192.168.1.49:8090/
http://192.168.1.49:8090/data