見出し画像

【ESP32プログラム】計測データのグラフを描かせてみよう!


前回の「無料のAmbientプラットフォームを利用してIoTシステムを構築してみよう」の記事ではESP32で作成した簡単なIoTシステムのデータをWiFi経由で無料のAmbientサービスへ送信してデータを取得しました。
今回はAmbientを使わず、ESP32自体にデータを蓄積して、外部からWiFi経由でESP32に直接アクセスすることで蓄積したデータを見る方法について紹介します。

結線図

図1に結線図を示します。これは「無料のAmbientプラットフォームを利用してIoTシステムを構築してみよう」の記事と同じなので、詳しくはそちらを参照してください。

図1 結線図

プログラム


300ポイント分を記録して表示する
新しいデータを記録したら一番古いデータを削除して常に300個のデータを記録して表示するようにします。


#include <WiFi.h>
#include <WebServer.h>
#include <DHT.h>

// WiFi接続情報(各自の環境に合わせて変更)
const char* ssid = "WiFiのSSID"; // 各自のルータのSSIDを記入
const char* password = "WiFiのパスワード"; // 各自のルータのパスワードを記入

#define DHTPIN 32  // DHTセンサのピン
#define DHTTYPE DHT11  // 使用するDHTセンサのタイプ
DHT dht(DHTPIN, DHTTYPE);  // DHTセンサのインスタンス作成
const int cdsPin = 33;  // 照度センサのピン

WebServer server(80);  // Webサーバーのインスタンス

const int dataSize = 300;  // 300点分のデータを保持
float lightData[dataSize] = {0};  // 照度データ
float humidityData[dataSize] = {0};  // 湿度データ
float temperatureData[dataSize] = {0};  // 温度データ

unsigned long lastSendTime = 0;
const unsigned long sendInterval = 600000;  // 10分ごとにデータ更新(600000ms)

void setup() {
    Serial.begin(115200);  // シリアルモニタの初期化
    WiFi.begin(ssid, password);  // WiFiに接続
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);  // WiFiが接続されるまで待機
        Serial.print(".");  // 接続状態を表示
    }
    Serial.println("\nWiFi connected");
    Serial.println(WiFi.localIP());  // 接続されたIPアドレスを表示
    dht.begin();  // DHTセンサの初期化
    server.on("/", handleRoot);  // Webサーバーのルートにリクエストが来た時の処理
    server.begin();  // Webサーバーを開始
}

void loop() {
    if (WiFi.status() != WL_CONNECTED) {  // WiFi接続が切れた場合
        WiFi.disconnect();
        WiFi.reconnect();
        delay(5000);  // 再接続まで待機
    }
    unsigned long currentTime = millis();  // 現在の時刻を取得
    if (currentTime - lastSendTime >= sendInterval) {  // 10分経過したらデータを更新
        updateSensorData();  // センサデータの更新
        lastSendTime = currentTime;  // 最後の更新時刻を記録
    }
    server.handleClient();  // クライアントからのリクエストを処理
}

// センサデータを更新する関数
void updateSensorData() {
    // 古いデータを1つずつ前にシフト
    for (int i = 1; i < dataSize; i++) {
        lightData[i - 1] = lightData[i];
        humidityData[i - 1] = humidityData[i];
        temperatureData[i - 1] = temperatureData[i];
    }
    // 新しいデータを取得
    lightData[dataSize - 1] = analogRead(cdsPin);  // 照度データを取得
    humidityData[dataSize - 1] = dht.readHumidity();  // 湿度データを取得
    temperatureData[dataSize - 1] = dht.readTemperature();  // 温度データを取得
}

// Webページの処理を行う関数
void handleRoot() {
    String html = "<html><head><script src='https://cdn.jsdelivr.net/npm/chart.js'></script></head><body>";
    html += "<h2>ESP32 IoT Data Graphs</h2>";
    html += "<canvas id='lightChart' width='400' height='66'></canvas>";  // 照度グラフ
    html += "<canvas id='humidityChart' width='400' height='66'></canvas>";  // 湿度グラフ
    html += "<canvas id='temperatureChart' width='400' height='66'></canvas>";  // 温度グラフ

    html += "<script>";
    
    // 照度データの配列をJavaScriptで使用する形式に変換
    html += "var lightData = [";
    for (int i = 0; i < dataSize; i++) html += String(lightData[i]) + ((i < dataSize - 1) ? "," : "");
    html += "];";

    // 湿度データの配列をJavaScriptで使用する形式に変換
    html += "var humidityData = [";
    for (int i = 0; i < dataSize; i++) html += String(humidityData[i]) + ((i < dataSize - 1) ? "," : "");
    html += "];";

    // 温度データの配列をJavaScriptで使用する形式に変換
    html += "var temperatureData = [";
    for (int i = 0; i < dataSize; i++) html += String(temperatureData[i]) + ((i < dataSize - 1) ? "," : "");
    html += "];";

    // 時間ラベル(6時間ごとのラベル)
    html += "var labels = [];";
    for (int i = 0; i < dataSize; i++) {
        int hours = (i * 10) / 60;  // 10分ごとのデータを時間に変換
        if (hours % 6 == 0) {
            html += "labels.push('" + String(hours) + "h');";
        } else {
            html += "labels.push('');";  // 6時間ごとでない時はラベルを表示しない
        }
    }

    // チャート作成関数(y軸の設定、グラフの色などを指定)
    html += "function createChart(ctx, label, data, color, minY, maxY, stepSize) {";
    html += "return new Chart(ctx, { type: 'line', data: { labels: labels, datasets: [{ label: label, data: data, borderColor: color, fill: false }] },";
    html += "options: { scales: { x: { title: { display: true, text: 'Time [hr]' },";
    html += "grid: { borderColor: '#000000', borderWidth: 1, color: '#cccccc' }, },";
    html += "y: { min: minY, max: maxY, ticks: { stepSize: stepSize }, title: { display: true, text: label }, grid: { borderColor: '#000000', borderWidth: 1 } } } } }); }";

    // 各グラフの作成
    html += "createChart(document.getElementById('lightChart').getContext('2d'), 'Light Intensity [mV]', lightData, 'red', 0, 6000, 2000);";
    html += "createChart(document.getElementById('humidityChart').getContext('2d'), 'Humidity [%]', humidityData, 'blue', 0, 60, 20);";
    html += "createChart(document.getElementById('temperatureChart').getContext('2d'), 'Temperature [C]', temperatureData, 'green', 0, 30, 10);";

    html += "</script></body></html>";

    // HTMLをWebブラウザに送信
    server.send(200, "text/html", html);
}

実行してみよう

それではプログラムをコンパイルしてESP32 へ書き込みます。
そして、シリアルモニタを起動するとESP32のIPアドレスが表示されます。
例えば、シリアルモニタには「192.168.0.xxx」というIPアドレスが表示されます。
このIPアドレスをパソコン等に入っているブラウザでアドレスを
「http://192.168.0.xxx/」とすると以下のWEBページが表示されます。

参考:
私のMACだとSafariでは表示されたのですが、Chromeではなぜか表示されませんでした。iPhoneではSafariでもChromeでも表示されています。表示されない場合には他のデバイスやブラウザでトライしてみてください。

購入部品

最新情報「電子工作お買い物一覧」の記事を参照ください。
リンク切対応や代替部品の紹介もしています。



いいなと思ったら応援しよう!