WiFi、リアルタイム温度モニターを製作する

,

お風呂を沸かしている間、「そろそろ沸いたかな」と何度も見に行ったことはありませんか?

工場や事務所でも、似たことが起きています。装置や部屋の温度を見に行って、数字を紙に書き写す。見に行く時間も書き写す手間も、積み重なると小さくありません。

そこで今回は、お風呂の湯温を題材にしました。温度センサーで測ったデータをWiFiでPCに送り、グラフに表示して、42℃になったら音で知らせてくれる仕組みを作ります。小さな実験ですが、工場の温度監視にもそのまま通じる考え方です。

IoTは「測る・送る・知らせる」の3つだけ

IoT(アイ・オー・ティー)とは、モノをネットワークにつないで、データを集めたり活用したりする仕組みのことです。難しそうに聞こえますよね。でも、やっていることは3つだけです。

やること今回の担当
測る温度センサー(DS18B20)
送るESP32(WiFi付きの小型コンピューター)が、家庭内のWiFiでPCへ
知らせるPC上のPythonプログラムが、グラフと音で

今回は、家の中のWiFiだけで完結します。インターネット上のサービスの契約は要りません。

今回使うもの

  • ESP32の開発ボード(今回はFREENOVE ESP32 WROOM)  一個 1500円くらい
  • DS18B20(防水型の温度センサー。先端が金属の筒になっていて、水に入れられるタイプです。精度は仕様上±0.5℃程度です) 220円くらい
  • 4.7kΩの抵抗を1本(センサーの信号を安定させるために使います)
  • リチウムイオン電池(3.7V)x2と、電池用の充電・降圧モジュール 電池750円くらい 降圧モジュール 700円くらい
  • Windows PC(Python 3を使います。無料です)

部品代は約3千円程度が目安です(価格は購入先で変わります)。ソフトはすべて無料です。

配線:センサーをつなぐ

DS18B20には3本の線があります。多くの製品では、赤が電源、黒がGND(マイナス)、黄または白が信号線です。線の色は製品によって違うことがあるので、お手元の説明書で確認してください。

  • 赤(電源)→ ボードの3V3ピン
  • 黒(GND)→ ボードのGNDピン
  • 黄または白(信号)→ ボードのGPIO4ピン
  • 4.7kΩの抵抗を、信号線(GPIO4)と3V3ピンの間に1本つなぐ

ESP32の電池駆動

今回は電池で動かします。ちょっと苦労しました。最初はピンに5Vを供給すればいいと思っていましたが、それではだめでした。

100均で買った充電用のUSB-Cケーブルを真ん中でカットし、赤、黒の線のみを使って5Vを供給します。これでうまくいきました。

降圧モジュールは、8Vを5Vに降下させています。ボリュームで調整します。4.9Vなのは、テスターで調整したからです。

お風呂で使うときは、100均のアクリルケースに入れました。

お風呂で使うときは、水と湯気にも注意が必要です。湯に入れるのはセンサーの防水部分だけにして、ボードと電池は防水の容器に入れ、浴槽から十分離して置いてください。ケースはテープなどでシーリングし湿気が入らないようにします。くれぐれも浴槽に落とすことのないようにしてください。リチウムイオン電池は水につけると危険です。

ESP32のプログラム(Arduino IDE)

Arduino IDEの「ライブラリを管理」から、OneWireとDallasTemperatureの2つをインストールしておきます(どちらも無料です)。ボードの選び方は、Freenoveの説明書に従ってください。

まず、設定をまとめた部分です。WiFiの名前とパスワード、PCのIPアドレスを、ご自宅に合わせて書き換えてください。PCのIPアドレスは、コマンドプロンプトで ipconfig と入力すると分かります。

#include <WiFi.h>
#include <HTTPClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>

const char* WIFI_SSID = "自宅WiFiの名前";
const char* WIFI_PASS = "WiFiのパスワード";
const char* SERVER_URL = "http://192.168.XX.XX:8000/";  // PCのIPアドレスに書き換える
const int SENSOR_PIN = 4;         // 信号線をつないだGPIO番号
const uint64_t SLEEP_SEC = 5;    // 何秒ごとに測るか

OneWire oneWire(SENSOR_PIN);
DallasTemperature sensors(&oneWire);

次が本体です。「測る→WiFiにつなぐ→PCに送る→眠る」を1回やって、5秒眠ります。眠っている間はほとんど電気を使わないので、電池が長持ちします。眠りから覚めると、また最初(setup)からやり直す仕組みです。データを送信する間隔は実際には5秒プラスWiFiが接続確立する時間がありますので10秒以上かかる場合もあります。10秒以下で計測したい場合はスリープは外したほうがいいでしょう。ただしWiFiは電力消費が激しいので電池で駆動する場合は適切にロギング間隔を選択する必要があります。

void setup() {
  sensors.begin();
  sensors.requestTemperatures();
  float temp = sensors.getTempCByIndex(0);

  if (temp != DEVICE_DISCONNECTED_C) {   // センサーが読めたときだけ送る
    WiFi.begin(WIFI_SSID, WIFI_PASS);
    for (int i = 0; i < 20 && WiFi.status() != WL_CONNECTED; i++) {
      delay(500);                        // 最大10秒、WiFiにつながるのを待つ
    }
    if (WiFi.status() == WL_CONNECTED) {
      HTTPClient http;
      http.begin(String(SERVER_URL) + "?temp=" + String(temp, 1));
      http.GET();                        // PCに温度を送る
      http.end();
    }
  }
  esp_sleep_enable_timer_wakeup(SLEEP_SEC * 1000000ULL);
  esp_deep_sleep_start();                // 眠る
}

void loop() {}

PC側のプログラム(Python)

PCは「受付係」です。ESP32から届いた温度を受け取り、グラフに点を足し、42℃になったら音を鳴らします。

最初に、必要なライブラリを入れます。pyqtgraphはリアルタイムのグラフ表示が得意な無料のライブラリ、PyQt6は画面を出すための部品です。Pythonの仮想環境(venv)の中に入れておくと、ほかのプログラムに影響しません。

pip install pyqtgraph PyQt6

プログラムは、次の3つのブロックを上から順に、1つのファイル(たとえば bath_monitor.py)に書きます。1つ目は、ESP32からの温度を受け取る部分です。

import queue
import threading
import time
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import parse_qs, urlparse

import pyqtgraph as pg
import winsound

THRESHOLD = 42.0  # 「沸いた」と判断する温度(℃)
PORT = 8000
temp_queue = queue.Queue()

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        query = parse_qs(urlparse(self.path).query)
        try:
            temp_queue.put(float(query["temp"][0]))
            self.send_response(200)
        except (KeyError, ValueError):
            self.send_response(400)
        self.end_headers()

    def log_message(self, *args):
        pass  # 受信のたびに文字を出さない

def run_server():
    HTTPServer(("0.0.0.0", PORT), Handler).serve_forever()

2つ目は、グラフの画面です。42℃のところには赤い線を引いています。

app = pg.mkQApp("お風呂の湯温モニター")
plot = pg.PlotWidget(title="湯温を待っています...")
plot.setLabel("left", "温度(℃)")
plot.setLabel("bottom", "経過時間(秒)")
plot.showGrid(x=True, y=True)
plot.addLine(y=THRESHOLD, pen="r")  # 42℃の赤い線
curve = plot.plot(pen=pg.mkPen("b", width=2))
plot.resize(800, 500)
plot.show()

times, temps = [], []
start = time.time()
notified = False

3つ目は、0.5秒ごとに届いたデータをグラフに足して、42℃になったら音を鳴らす部分です。音は1回だけ鳴らし、鳴りっぱなしにはしません。音を出すwinsoundは、Windowsに最初から入っています。

def update():
    global notified
    while not temp_queue.empty():
        temp = temp_queue.get()
        times.append(time.time() - start)
        temps.append(temp)
        title = f"現在の湯温: {temp:.1f}℃"
        if temp >= THRESHOLD:
            title = "お風呂が沸きました! " + title
            if not notified:  # 知らせるのは1回だけ
                notified = True
                for _ in range(3):
                    winsound.Beep(1000, 300)
        plot.setTitle(title)
    curve.setData(times, temps)

timer = pg.QtCore.QTimer()
timer.timeout.connect(update)
timer.start(500)  # 0.5秒ごとに画面を更新

threading.Thread(target=run_server, daemon=True).start()
pg.exec()

実行すると、グラフの窓が開きます。初めて実行したときは、Windowsから「ネットワークへのアクセスを許可しますか?」と聞かれます。家庭内のネットワーク(プライベートネットワーク)だけ許可してください。ここを許可しないと、ESP32からの温度が届きません。

やってみた結果

お風呂のお湯を沸かし始めてから、グラフがどう変わったかを見てみましょう。

だいたい、18分30秒で「お風呂が沸きました」の音声が流れました。湯温は38度ですから、設定した42度にはとどいていません。これは、センサーがお風呂の底にほうにあったせいでしょう。実際にセンサーを取り出すときに表面に近い温度を計測すると40度であったことがわかります。

工場や事務所では何に使えるでしょう

お風呂を、別のものに置き換えてみてください。

  • 装置や部屋の温度を見に行って、紙に書き写している作業
  • 冷蔵庫や保管庫の温度管理
  • 倉庫や事務所の室温の見える化

どれも「測る・送る・知らせる」の流れは同じです。私が長く関わってきた半導体装置の分野でも、温度の管理は欠かせないものでした。ただし、実際の設備に使うときは、必要な精度や安全面の確認が別に要ります。今回の実験は、まず「仕組みを体験する」ための例と考えてください。

まとめ

今回は、DS18B20で湯温を測り、ESP32が家庭内のWiFiでPCに送り、PythonとpyqtgraphがグラフとBeep音で知らせる仕組みを作りました。部品代は数千円程度、ソフトはすべて無料です。

「うちの設備の温度も、自動で記録できないかな」と思われた方は、お気軽にご相談ください。


トップへ戻る