「毎月の電気代が高い気がするけど、どの家電が電力を食ってるのかわからない…」

そんな悩みを持っている方、意外と多いんじゃないでしょうか。スマートメーターを契約会社に頼んで見せてもらうのも一手ですが、自分でリアルタイムに消費電力を見える化できたらもっと面白いですよね。

今回は ESP32 + CTセンサー(電流センサー)+ Pythonダッシュボード を組み合わせて、自宅のコンセントを流れる電流をリアルタイム計測し、ブラウザ上のグラフに表示する家庭用電力モニターを作ります。IoT × 電子工作 × Pythonの3つが合体した実践的なプロジェクトです!

対象読者:ESP32やArduinoの基本操作ができる初〜中級者(Pythonも多少書ける方)
難易度:★★★☆☆(電気工事の資格は不要!コンセントを直接改造しません)

仕組みの全体像をざっくりつかもう

electricity monitor dashboard
electricity monitor dashboard / Photo by Paul Lichtblau via Pexels

まず全体のデータの流れをイメージしてください。

  1. CTセンサー(クランプ型)をコンセントのコードに挟む → 電流値をアナログ信号で出力
  2. ESP32がそのアナログ信号をADC(アナログ→デジタル変換)で読み取り、実効値(RMS)を計算
  3. ESP32が計算した電流値を Wi-Fi経由でHTTPリクエスト としてPythonサーバーに送信
  4. Python(Flask + Dash)がデータを受け取り、ブラウザ上のリアルタイムグラフに描画

コンセントの配線を直接いじらないので、電気工事士の資格は不要です。CTセンサーはケーブルの外側からクランプ(挟む)だけでOKなので、安全に電流計測できますよ。

必要な部品と環境

部品はすべて2,000〜3,000円程度で揃います。

  • ESP32開発ボード(WROOM-32系で可)
  • SCT-013-030(30A対応クランプ型CTセンサー)※ 出力タイプは「電圧出力(0〜1V)」を推奨
  • バイアス抵抗(10kΩ × 2)とバイパスコンデンサ(10µF)
  • PCまたはRaspberry Pi(Pythonサーバー用)
  • Python 3.x(Flask・Dash・plotlyをインストール)

ソフトウェア側のインストールはこのコマンドでOKです。

pip install flask dash plotly pandas

STEP 1:ESP32のファームウェアを書く

CTセンサーの出力電圧をESP32のADCピン(GPIO34など)で読み取り、実効値(RMS値)を計算してWi-Fi送信します。RMS値とは交流電流の「実際の仕事量」に相当する値で、単純な最大値とは違います。

ポイントをまとめると:

  • ADCを短時間に大量サンプリング(500回程度)して二乗平均の平方根を計算する
  • ESP32のADCは0〜3.3Vの入力を想定。センサー出力がその範囲に収まるようバイアス回路で中点電圧(1.65V)を作る
  • 計測した電流値をHTTP POSTでPythonサーバーに送る
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

const char* ssid     = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";
const char* serverUrl = "http://192.168.1.100:5000/data"; // PythonサーバーのIP

const int CT_PIN     = 34;    // ADC入力ピン
const int SAMPLES    = 500;   // サンプル数
const float VREF     = 3.3;   // ADC基準電圧
const float ADC_MAX  = 4095.0;
const float CALIB    = 30.0;  // SCT-013-030 の定格(30A / 1V)

float calcRMS() {
  long sumSq = 0;
  for (int i = 0; i < SAMPLES; i++) {
    int raw = analogRead(CT_PIN);
    // 中点(2048)を引いてゼロクロス波形に変換
    long offset = raw - 2048;
    sumSq += offset * offset;
    delayMicroseconds(200);
  }
  float rmsRaw = sqrt((float)sumSq / SAMPLES);
  // ADC値 → 電圧 → 電流に変換
  float voltage = rmsRaw * (VREF / ADC_MAX);
  float current = voltage * CALIB;
  return current;
}

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWi-Fi接続完了!");
}

void loop() {
  float current = calcRMS();
  // 100V家庭用コンセントとして電力を計算(W)
  float power   = current * 100.0;

  Serial.printf("電流: %.2f A  消費電力: %.1f W\n", current, power);

  // JSON形式でPythonサーバーにPOST
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.begin(serverUrl);
    http.addHeader("Content-Type", "application/json");

    StaticJsonDocument<128> doc;
    doc["current"] = current;
    doc["power"]   = power;
    String body;
    serializeJson(doc, body);

    int code = http.POST(body);
    Serial.printf("HTTPレスポンス: %d\n", code);
    http.end();
  }

  delay(2000); // 2秒ごとに計測・送信
}

このコードのポイントはここです:

  • calcRMS() でサンプリング → 二乗平均 → 平方根の順に計算しているのが実効値の本質
  • 電力(W)は「電流 × 電圧(100V)」で概算。より精度を上げたい場合は電圧センサーも追加します
  • ArduinoJson ライブラリを使うとJSONの組み立てが楽になります

STEP 2:PythonサーバーとDashダッシュボードを作る


次に、ESP32からのデータを受け取るFlaskエンドポイントと、リアルタイムグラフを表示するDashアプリを 1つのPythonファイル にまとめます。

import threading
import time
from collections import deque
from datetime import datetime

from flask import Flask, request, jsonify
import dash
from dash import dcc, html
from dash.dependencies import Input, Output
import plotly.graph_objs as go

# ---- データストア(最大200件を循環保持) ----
MAX_POINTS = 200
times   = deque(maxlen=MAX_POINTS)
currents = deque(maxlen=MAX_POINTS)
powers   = deque(maxlen=MAX_POINTS)

# ---- Flask(データ受信エンドポイント) ----
server = Flask(__name__)

@server.route("/data", methods=["POST"])
def receive_data():
    body = request.get_json()
    if not body:
        return jsonify({"error": "no data"}), 400
    times.append(datetime.now().strftime("%H:%M:%S"))
    currents.append(body.get("current", 0))
    powers.append(body.get("power", 0))
    return jsonify({"status": "ok"})

# ---- Dashアプリ(リアルタイムグラフ) ----
app = dash.Dash(__name__, server=server)

app.layout = html.Div([
    html.H1("🏠 家庭用電力モニター",
            style={"textAlign": "center", "fontFamily": "sans-serif"}),
    dcc.Graph(id="power-graph"),
    dcc.Graph(id="current-graph"),
    # 2秒ごとにグラフを更新
    dcc.Interval(id="interval", interval=2000, n_intervals=0)
])

@app.callback(
    [Output("power-graph", "figure"),
     Output("current-graph", "figure")],
    Input("interval", "n_intervals")
)
def update_graphs(_):
    t = list(times)
    p = list(powers)
    c = list(currents)

    power_fig = go.Figure(
        go.Scatter(x=t, y=p, mode="lines+markers",
                   line=dict(color="#e74c3c", width=2),
                   name="消費電力 (W)")
    )
    power_fig.update_layout(
        title="消費電力 (W)",
        xaxis_title="時刻",
        yaxis_title="W",
        template="plotly_white"
    )

    current_fig = go.Figure(
        go.Scatter(x=t, y=c, mode="lines+markers",
                   line=dict(color="#3498db", width=2),
                   name="電流 (A)")
    )
    current_fig.update_layout(
        title="電流 (A)",
        xaxis_title="時刻",
        yaxis_title="A",
        template="plotly_white"
    )
    return power_fig, current_fig

if __name__ == "__main__":
    # Flaskサーバーを別スレッドで起動
    flask_thread = threading.Thread(
        target=lambda: server.run(host="0.0.0.0", port=5000, use_reloader=False)
    )
    flask_thread.daemon = True
    flask_thread.start()

    # Dashアプリをメインスレッドで起動
    app.run(debug=False, host="0.0.0.0", port=8050)

ここが重要です:

  • deque(maxlen=200) を使うと古いデータが自動的に捨てられ、メモリが膨らみません
  • FlaskとDashを同じプロセスで動かすために スレッドで分離 しています
  • ブラウザで http://localhost:8050 を開くとグラフが表示されます

STEP 3:動作確認をしておきましょう

起動の流れはこうなります。

  1. PCでPythonスクリプトを実行 → Flaskサーバー(ポート5000)とDashアプリ(ポート8050)が起動
  2. ESP32のスケッチを書き込み、シリアルモニタで「Wi-Fi接続完了!」を確認
  3. CTセンサーを計測したい家電のコードにクランプ(外側から挟むだけ)
  4. ブラウザで http://<PythonサーバーのIP>:8050 を開く
  5. 2秒ごとにグラフが自動更新されれば成功です🎉

ESP32のシリアルモニタにこんな出力が出れば正常動作しています。

Wi-Fi接続完了!
電流: 1.23 A  消費電力: 123.0 W
HTTPレスポンス: 200
電流: 1.25 A  消費電力: 125.0 W
HTTPレスポンス: 200

精度を上げるヒント・応用アイデア


基本動作が確認できたら、こんな改善も試してみてください。

  • 電圧センサー(ZMPT101B)を追加:電圧も計測することで有効電力(W)と力率を正確に算出できます
  • 💾 CSV/SQLiteに記録:Pythonサーバー側でデータを保存すれば、日別・時間帯別の消費電力グラフも作れます
  • 📱 閾値アラート:消費電力が500Wを超えたらLINE Messaging APIで通知を飛ばす処理をFlask側に追加すると省エネ意識が高まります(※かつて使われていたLINE Notifyは2025年3月末にサービス終了しています)
  • 🔌 複数回路の監視:CTセンサーを複数つなぐことでエアコン用・電子レンジ用など回路別に見える化できます

まとめ

今回は ESP32 + CTセンサー + Python(Flask・Dash) を組み合わせて、家庭の消費電力をリアルタイムにブラウザグラフで見える化する電力モニターを作りました。

コンセントを直接改造せずに電流計測できるCTセンサーのおかげで、安全に試せるのが嬉しいポイントです。データを蓄積していくと「夜9時以降の待機電力が意外と多い」といった発見があって、省エネへのモチベーションも上がりますよ。

ぜひ手元で試してみてください!わからない部分があればコメントで気軽に質問してくださいね 😊

ESP32シリアルモニタ出力(正常動作時)
ESP32シリアルモニタ出力(正常動作時)

📡 Arduinoをもっと深く学ぼう!

Arduino・ラズパイ・ロボットプログラミングを体系的に学びたい方へ。おすすめのUdemyコースや電子部品もまとめています。

Arduinoロボット入門のおすすめコース・部品を見る →

📚 関連商品・おすすめ書籍

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

もしも

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

初心者に定番のPython入門書

Amazonで見る

Arduinoをはじめよう 第4版 (Make: PROJECTS)

もしも

Arduinoをはじめよう 第4版 (Make: PROJECTS)

Arduino公式推薦の定番入門書

Amazonで見る

徹底攻略! 電子工作&プログラミング Arduinoで学ぶ電子工作完全ガイド

もしも

徹底攻略! 電子工作&プログラミング Arduinoで学ぶ電子工作完全ガイド

電子工作とプログラミングを同時に学べる

Amazonで見る

※本記事にはアフィリエイトリンクが含まれます。

ABOUT ME
やまちゃん
これまで学生と社会人を合わせて5000人以上にプログラミング学習を指導。 ゼロからイチをわかりやすく解説する専門家として活動しており、本業ではArduinoを用いたIoT開発とロボットプログラミングが専門。 Pythonを用いたアプリ開発、ウェブアプリケーションの開発で業務の効率化をサポートしています。