お知らせ
2020年4月23日
ESP-WROOM-02でIoT その③ WiFiを使って温度と湿度をグラフ化する
前回は、ESP-WROOM-02にプログラムを書き込み、ディスプレイに情報を表示しました。
今回は、温度と湿度をWiFiで送信しnode.jsとsocket.ioを使ってグラフ化します。
※事前にnode.jsの環境を構築しておく必要があります。Visual Studio Code等を利用すると簡単です。
■クライアント側(ESP-WROOM-02)
前回のプログラムにWiFiへの接続、HTTPクライアントでのPOST処理、JSONオブジェクトの作成処理を追加します。
ssidとpasswordは、ご自身のWiFi環境に合わせ修正してください。
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
#include <Adafruit_BME280.h>
#include <Adafruit_SSD1306.h>
#define SEALEVELPRESSURE_HPA (1013.25)
#define OLED_RESET 2
Adafruit_BME280 bme; // I2C
Adafruit_SSD1306 display(OLED_RESET);
const char *ssid = "xxxxxx";
const char *password = "xxxxxxxx";
void setup()
{
// シリアルポート開始(Serial.print用)
Serial.begin(9600);
//OLED(SSD1306)開始
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
// BME280センサー開始
if (!bme.begin(0x76, &Wire))
{
OLEDPrint("BME280 Sensor error. SensorID 0x" + String(bme.sensorID(), HEX), 0, true);
while (1)
delay(10);
}
Serial.println();
// WiFi開始
WiFi.begin(ssid, password);
OLEDPrint(String("Connecting to \r\n" + String(ssid)), 0, true);
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
OLEDPrint("WiFi connected", 0, true);
}
delay(2000);
}
const size_t CAPACITY = 300;
void loop()
{
// 各種センサー情報をJSONオブジェクトに設定
StaticJsonDocument<CAPACITY> json_doc;
JsonObject json_object = json_doc.to<JsonObject>();
json_object["temp"] = bme.readTemperature();
json_object["prsr"] = bme.readPressure() / 100.0F;
json_object["attr"] = bme.readAltitude(SEALEVELPRESSURE_HPA);
json_object["humi"] = bme.readHumidity();
display.clearDisplay();
OLEDPrint("Temp:" + json_object["temp"].as<String>() + "*C", 0, false); // 温度
OLEDPrint("Prsr:" + json_object["prsr"].as<String>() + " hPa", 8, false); // 気圧
OLEDPrint("Attr:" + json_object["attr"].as<String>() + " m", 16, false); // 高度
OLEDPrint("Humi:" + json_object["humi"].as<String>() + " %", 24, false); // 湿度
display.display();
// JSONをシリアライズ
char json_buf[CAPACITY];
serializeJsonPretty(json_doc, json_buf, CAPACITY);
// 受信側のサーバへJSON形式で送信(POST)
HTTPClient http;
http.begin("http://192.168.0.2:3000/");
http.addHeader("Content-Type", "application/json");
int http_code = http.POST(json_buf);
if (http_code < 0) //Send the request
{
Serial.println("HTTP POST ERROR. CODE:" + String(http_code));
}
Serial.println(http.getString());
http.end(); //Close connection
delay(2000);
}
void OLEDPrint(String str, int cur_y, bool refresh)
{
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, cur_y);
if (refresh) display.clearDisplay();
display.println(str);
if (refresh) display.display();
}
■サーバ側(app.js)
"use strict";
var port = 3000;
const bodyParser = require("body-parser")
var app = require("express")();
var http = require("http").Server(app);
var io = require("socket.io")(http);
app.get("/", function (req, res) {
res.sendFile(__dirname + "/index.html");
});
app.use(bodyParser.json({
extended: true
}));
// コネクションの確立
io.on("connection", function (socket) {
socket.on("disconnect", function () {
console.log("Client disconnected");
});
});
app.post("/", function (req, res, next) {
// クライアント側に送るためのfunction
io.emit("graph_update", req.body);
//console.log(req.body);
res.send({});
});
http.listen(port, function () {
console.log("listening on *:3000");
});
■サーバ側(index.html)
<!DOCTYPE html>
<html>
<head>
<title>グラフテスト</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.0/Chart.min.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.2/moment.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
</head>
<body>
<script>
$(document).ready(function () {
var socket = io();
// 温度グラフ設定
var tempChartObj = {
type: "line",
data: {
labels: [],
datasets: [{
label: "温度",
data: [],
backgroundColor: [
"rgba(255, 99, 132, 0.2)"
],
borderWidth: 1
}]
},
options: {
responsive : true,
maintainAspectRatio : true,
legend: {
display: true // 凡例表示
},
scales: {
yAxes: [{
scaleLabel: { // 軸ラベル
display: true, // 表示設定
labelString: "温度(℃)", // ラベル
//fontColor: "red", // 文字の色
fontSize: 12 // フォントサイズ
},
ticks: {
beginAtZero: true,
min: 0,
max: 50
}
}]
}
}
}
// 湿度グラフ設定
var humiChartObj = jQuery.extend(true, {}, tempChartObj);
humiChartObj.options.scales.yAxes[0].scaleLabel.labelString = "湿度(%)";
humiChartObj.data.datasets[0].label = "湿度";
humiChartObj.data.datasets[0].backgroundColor[0] = "rgba(255, 159, 64, 0.2)";
humiChartObj.options.scales.yAxes[0].ticks.min = 0;
humiChartObj.options.scales.yAxes[0].ticks.max = 100;
// 温度グラフの作成
var tempChart = new Chart($("#temp_graph")[0].getContext("2d"), tempChartObj);
// 湿度グラフの作成
var humiChart = new Chart($("#temp_graph2")[0].getContext("2d"), humiChartObj);
$(function () {
// サーバから値を受け取った時の処理
socket.on("graph_update", (data) => {
// 現在時刻の取得
const outputTime = moment().format("HH : mm : ss");
// 追加するデータのラベルに時間を付与
tempChart.data.labels.push(outputTime);
humiChart.data.labels.push(outputTime);
// グラフにデータを追加
tempChart.data.datasets[0].data.push(data.temp);
humiChart.data.datasets[0].data.push(data.humi);
// グラフの表示更新
tempChart.update();
humiChart.update();
});
});
});
</script>
<div class="left" style="width:500px; height:500px; float:left;">
<canvas id="temp_graph" height="150"></canvas>
</div>
<div class="right" style="width:500px; height:500px; float:left;">
<canvas id="temp_graph2" height="150"></canvas>
</div>
</body>
</html>
■実行
サーバーを起動し、以下URLを実行するとグラフが表示されます。
モバイルバッテリーなどを使い、外に放置すれば外の気温が家のPCで確認できたりします。
温度、湿度がわかれば梅雨~夏場の不快指数なども計算できます。