ESP32入門|Arduinoとの違い・Wi-Fi・Bluetoothの使い方

プログラミング・電子工作

ESP32 Getting Started Guide — Wi-Fi / BLE

ESP32入門|使い方とArduinoとの違い、Wi-Fi・Bluetooth接続まで

ESP32は、Wi-FiとBluetoothを内蔵したEspressif Systems社のマイコンです。Arduino Uno R3との大きな違いは、無線を最初から使えることと、信号が3.3Vであることです。

Arduino IDEでそのまま開発でき、センサーの値をスマホやPCへ無線で送れます。この記事では、LED点滅 → Wi-Fi接続 → BLEでスマホ通知 → 温湿度データの送信までを、順番に進めます。

この記事でできるようになること

  • 自分の用途に合うESP32ボードを選び、必要な部品をそろえる
  • Arduino IDEにESP32を追加し、LED点滅で書き込みを確認する
  • ESP32をWi-Fiに接続し、IPアドレスを表示する
  • BLEでスマートフォンに値を通知する
  • 温湿度センサーの値をWi-Fi経由でPC(Python)へ送って記録する
対象読者: ESP32初心者・Arduino経験者 基準ボード: ESP32-DevKitC-32E(ESP32-WROOM-32E) 環境: Arduino IDE 2.x/Arduino-ESP32 3.3系
全コードCOPY対応配線・出力例付きエラー対処表付きPython受信サーバー付き

執筆・実機検証:YOFUKASI LAB運営者

理学療法士/Arduino・Pythonを使った医療機器制作・学会発表経験あり

現時点の確認状況は、コードごとの「検証状況」ラベルに記載しています(実機未確認のコードを含みます)。

01

ESP32とは?Arduinoとの違いを初心者向けに解説

ESP32は、Espressif Systems社が開発した無線機能内蔵のマイコン(SoC)のシリーズです。Arduino社の製品ではありませんが、Espressifが公開しているArduino core for ESP32 ↗を追加すると、Arduino IDEからsetup()・loop()・digitalWrite()といったいつもの書き方で動かせます。

ESP32開発ボードとArduino Unoを並べ、基板の大きさと形の違いを比べている写真

ESP32でできること5選

  • Wi-Fiでデータを送る:センサーの値をPCやクラウドへ送信し、記録・グラフ化する
  • スマホから操作する:ESP32をWebサーバーにして、ブラウザのボタンでLEDや機器を動かす
  • BLEでスマホと通信する:Wi-Fiのない場所でも、測定値をスマホへ通知する
  • 電池で長く動かす:Deep Sleepで普段は眠らせ、一定間隔だけ起きて測定する
  • ケーブルなしで計測する:体や道具に付けたセンサーの値を無線で取り出す(動作計測の試作など)

ESP32とArduino Uno R3・Uno R4の違い

「Arduinoは5V・8bit・無線なし」という説明は、Uno R3には当てはまりますが、Uno R4には当てはまりません。比較対象を明確にして要点だけ整理します。

項目 ESP32-DevKitC-32E Arduino Uno R3 Arduino Uno R4 WiFi
CPU 32bit デュアルコア・最大240MHz 8bit AVR・16MHz 32bit Arm Cortex-M4・48MHz
信号の電圧 3.3V(5V入力は不可) 5V 5V
Wi-Fi 内蔵(2.4GHz帯) なし あり(搭載のESP32-S3モジュール経由)
Bluetooth Classic+BLE なし BLE
向いている用途 IoT・無線通信・スマホ連携 電子工作の基礎学習・5V部品 Unoの形と5Vのまま無線を使う

※EspressifのESP32データシートとArduino公式ドキュメントに基づく概要です(2026年10月確認)。メモリ・ADC・DACまで含めた詳しい比較は下記の比較記事にまとめています。

ESP32とArduinoはどちらがおすすめ?

  • Wi-FiやBluetoothを使う予定がある:ESP32
  • 5Vのセンサーやシールドで基礎から学びたい:Arduino Uno R3/R4
  • Unoの形のまま無線も使いたい:Arduino Uno R4 WiFi(ただしWi-FiライブラリはESP32用と異なります)
LINK

この記事は「実際に動かす手順」に絞っています。スペックの詳しい比較やメリット・デメリットを先に確認したい方は、ESP32とは?Arduinoとの違い・特徴・できることを比較した記事をご覧ください。Linuxが動くボードとの違いはRaspberry PiとArduinoの違いを比較した記事で整理しています。

02

ESP32初心者におすすめのボードと必要なもの

「ESP32」という名前は、チップ・モジュール・開発ボードのどれを指すかで意味が変わります。購入するのは開発ボードです。

  • チップ(SoC):ESP32、ESP32-S3、ESP32-C3など。半導体そのもの
  • モジュール:ESP32-WROOM-32Eなど。チップにフラッシュメモリとアンテナを組み合わせた部品
  • 開発ボード:ESP32-DevKitC-32Eなど。モジュールにUSB端子・電源回路・ピンヘッダを付けた基板

ESP32・S3・C3・C6などの違い

シリーズによって、CPUもBluetoothの種類もWi-Fiの周波数帯も異なります。「ESP32はBluetooth Classicが使える」「2.4GHzのみ」といった説明は、シリーズを確認してから当てはめてください。

シリーズ CPU Wi-Fi Bluetooth 向いている用途
ESP32(初代) Xtensa デュアルコア 2.4GHz Classic+BLE はじめての1台。作例と解説が最も多い
ESP32-S3 Xtensa デュアルコア 2.4GHz BLEのみ USB機能、カメラ・表示など重めの処理
ESP32-C3 RISC-V シングルコア 2.4GHz BLEのみ 小型・低コストのセンサー端末
ESP32-C6 RISC-V 2.4GHz(Wi-Fi 6) BLEのみ Thread/Zigbee対応のスマートホーム機器
ESP32-C5 RISC-V 2.4GHz/5GHz(Wi-Fi 6) BLEのみ 5GHz帯が必要な場合。作例はまだ少なめ

※Espressif公式の製品一覧 ↗に基づく概要です(2026年10月確認)。詳細は各シリーズのデータシートで確認してください。

初心者向けボードの選び方

  • 迷ったら初代ESP32の開発ボード(ESP32-DevKitC-32Eなど)。この記事のコードとピン番号はこのボードが基準です。
  • ピン配置図と回路図が公開されているボードを選ぶと、トラブル時に原因を調べやすくなります。
  • ブレッドボードで使う場合、ボードの幅を確認します。幅の広いボードは片側の穴がふさがるため、ブレッドボードを2枚並べる方法もあります。

必要部品と購入時の注意点

必要なもの 使う場面 補足
ESP32開発ボード すべて 技適マークの表示があるもの
データ通信対応のUSBケーブル すべて 端子(USB-C/Micro-USB)はボードに合わせる。充電専用は不可
ブレッドボード・ジャンパー線 LED点滅・センサー はじめての方はブレッドボードの使い方ガイドを参照
LEDと抵抗(220〜330Ω) 動作確認 ボード上にLEDがある場合は省略可
DHT22(またはDHT11) センサー送信 抵抗付きのモジュール品が配線しやすい
スマートフォン BLEの確認 BLEスキャナーアプリを入れる
CHECK

日本国内でWi-Fi・Bluetoothの電波を出すには、原則として技術基準適合証明(技適)を受けたモジュール・ボードである必要があります。「ESP32」と書かれていても、すべての製品が適合しているとは限りません。販売ページと実物(モジュールの金属カバーなど)で、技適マークと番号の表示を確認してください。

03

ESP32の始め方|Arduino IDEの設定から動作確認まで

作業は「IDEを入れる → ESP32用のパッケージを追加する → ボードとポートを選ぶ → LED点滅で確認する」の4段階です。メニュー名はArduino IDE 2.x(日本語表示)のものです。

1. Arduino IDEのインストール

まだ入れていない場合は、Arduino IDEのダウンロード・インストール方法を先に済ませてください。

2. ボードマネージャーURLの追加

  1. 「ファイル」→「基本設定」を開く(macOSは「Arduino IDE」→「設定」)
  2. 「追加のボードマネージャのURL」に下記の安定版URLを貼り付けて「OK」を押す。すでに別のURLがある場合はカンマで区切って追加する
  3. 「ツール」→「ボード」→「ボードマネージャ」で「esp32」と検索し、esp32 by Espressif Systemsをインストールする(容量が大きく、数分かかります)
ボードマネージャURL(安定版)
https://espressif.github.io/arduino-esp32/package_esp32_index.json

URLはArduino-ESP32公式インストールガイド ↗に掲載されている安定版(Stable release)のものです。

この記事のコードは3.3系(2026年10月時点の安定版は3.3.12)を前提にしています。4.0系はリリース候補版の段階で、BluetoothまわりのAPIが見直されているため、当面は3.3系の利用をおすすめします。

3. ESP32ボードの選択とUSB接続

  1. データ通信対応のUSBケーブルでESP32とPCを接続する
  2. 「ツール」→「ボード」→「esp32」→「ESP32 Dev Module」を選ぶ(S3やC3のボードは、対応するボード名を選びます)
  3. 「ツール」→「ポート」で、接続したときに増えたポートを選ぶ

ポートが表示されない場合は、ケーブルが充電専用でないか、ボードのUSBシリアル変換IC(CP210x系・CH340系など)のドライバが必要でないかを確認します。切り分けの手順はArduinoで「ポートが見つからない」ときの原因と解決策と共通です。

4. LED点滅で最初の動作確認

外付けLEDを1秒ごとに点滅させ、同時にシリアルモニタへ文字を出します。LEDが手元になくても、シリアルモニタの表示だけで書き込みの成功を確認できます。

対象ボード

ESP32-DevKitC-32E(ボード設定:ESP32 Dev Module)

必要部品

LED 1個、抵抗(220〜330Ω)1本、ブレッドボード、ジャンパー線

配線

GPIO23 → 抵抗 → LEDの長い足(アノード)/LEDの短い足(カソード)→ GND

ライブラリ

追加不要(Arduino-ESP32 3.3系に含まれる機能のみ)

CHECK

ボード上のLEDが使えるピンはボードごとに異なります。ESP32-DevKitCには自由に使えるLEDが載っていない版があり、GPIO2にLEDがあるボードや、カラーLEDが載っているボードもあります。「LED_BUILTINで必ず光る」とは限らないため、ここではピン番号を明示して外付けLEDを使います。

検証状況:公式APIに沿って作成/実機未確認

blink_gpio23.ino
// ESP32の動作確認:外付けLEDを1秒ごとに点滅し、シリアルにも表示する
// 対象: ESP32-DevKitC-32E / ボード設定「ESP32 Dev Module」
const int LED_PIN = 23;   // LEDをつないだGPIO番号(ボードと配線に合わせて変更)
void setup() {
  Serial.begin(115200);   // シリアルモニタも115200bpsに合わせる
  pinMode(LED_PIN, OUTPUT);
}
void loop() {
  digitalWrite(LED_PIN, HIGH);
  Serial.println("LED ON");
  delay(1000);
  digitalWrite(LED_PIN, LOW);
  Serial.println("LED OFF");
  delay(1000);
}
  1. コードをArduino IDEに貼り付け、左上の「→」(書き込み)を押す
  2. 下部に「Connecting…」と出たまま進まない場合は、ボードのBOOTボタンを押し続け、書き込みが始まったら離す
  3. 書き込み完了後、「ツール」→「シリアルモニタ」を開き、右下の速度を115200 baudにする
成功したときのシリアルモニタ(想定出力)
LED ON
LED OFF
LED ON
LED OFF
うまくいかないとき 原因と対策
文字は出るがLEDが光らない LEDの向きが逆、または配線したGPIOとLED_PINの番号が違う
文字化けする シリアルモニタの速度が115200 baudになっていない
書き込みに失敗する ポート・ボードの選択違い、BOOTボタンの操作が必要(エラーと解決方法へ)

setup()とloop()の意味から確認したい場合は、Arduinoのコード・プログラムの書き方(コピペ可20選)が参考になります。Arduino用のコードをESP32へ移すときは、ピン番号をGPIO番号に読み替えるのが最初の作業です。

04

ESP32のGPIOと配線で注意すること

ESP32開発ボードのピンヘッダと、基板に印刷されたGPIO番号を指し示している写真

digitalWrite()やanalogRead()の書き方はArduinoとほぼ共通ですが、ピンの制約は大きく異なります。ArduinoからESP32へ移行するときに、最初に確認したい点を整理します。

3.3Vと5Vの違い

CHECK 1

ESP32のGPIOは3.3Vで動作し、5Vの信号を直接入力できません。USBから5Vで給電していても、信号ピンは3.3Vです。5V出力のセンサーやUno用モジュールをつなぐ場合は、レベル変換モジュールや分圧抵抗で3.3V以下に下げてください。3.3V電源・3.3V信号に対応した部品であれば、通常はそのまま接続できます。

アナログ入力の値の範囲も変わります。Uno R3のanalogRead()は0〜1023、ESP32は初期設定で0〜4095です。しきい値を固定の数値で書いたコードは、移植時に見直しが必要です。センサーの扱い方そのものは圧力センサーを使った電子工作の基礎と共通です。

入力専用・起動に影響するピン

次の表は初代ESP32(ESP32-WROOM-32E/ESP32-DevKitC-32E)の場合です。S3やC3などはピン番号も制約も異なるため、使用するチップのデータシートとボードのピン配置図を確認してください。

GPIO 制約 使い方
34・35・36・39 入力専用。内部プルアップ・プルダウンなし センサーの読み取りのみ。LEDやモーターの制御には使えない
0・2・5・12・15 起動時の動作を決めるピン(ストラッピングピン) 外部回路の状態によっては起動や書き込みに失敗する。慣れるまで避ける
6〜11 モジュール内部のフラッシュメモリ接続に使用 使わない
1・3 USBシリアル通信(書き込み・シリアルモニタ)に使用 使わない

Wi-Fi使用時のADCとピン選択

CHECK 2

初代ESP32では、Wi-Fiを使っている間はADC2系のピン(GPIO0・2・4・12〜15・25〜27)でanalogRead()が使えません。Wi-Fiと併用するアナログ入力は、ADC1系のGPIO32〜36・39につないでください。デジタル入出力として使う分には、この制限は関係ありません。

初心者向けの安全な配線例

  • デジタル入出力(LED・ボタン・DHT22など):GPIO18・19・21・22・23・25・26・27・32・33
  • アナログ入力(Wi-Fiと併用):GPIO32・33・34・35
  • I2C(初期設定):SDA=GPIO21、SCL=GPIO22
  • 電源:3.3V対応のセンサーは3V3ピンから。モーターやサーボは別電源にし、GNDだけ共通にする
Arduino Uno: digitalWrite(13, HIGH);
Unoは基板に印字されたピン番号をそのまま関数に渡します。
ESP32: digitalWrite(23, HIGH);
ESP32は「GPIO番号」で指定します。基板の印字が「D23」「IO23」でも、コードに書くのは23です。印字とGPIO番号の対応はボードごとに異なるため、ピン配置図で確認してください。
05

ESP32をWi-Fiに接続する方法【コピペコード付き】

ESP32が自宅のWi-Fiルーターを経由してネットワークにつながる様子を表したイメージ

Wi-Fiは、Arduino-ESP32に含まれるWiFiライブラリ ↗で扱います。追加のライブラリは不要です。自宅のルーターに接続し、IPアドレスが表示されるところまで進めます。

対象ボード

ESP32-DevKitC-32E(ボード設定:ESP32 Dev Module)

必要部品・配線

ESP32本体とUSBケーブルのみ。配線は不要

ライブラリ

WiFi.h(Arduino-ESP32 3.3系に同梱)

Wi-Fiの条件

2.4GHz帯のSSID(初代ESP32・S3・C3・C6は5GHz帯に接続できません)

SSIDとパスワードの設定

コードのyour-ssidとyour-passwordを、自宅のWi-Fiの情報に書き換えます。ルーターが2.4GHz用と5GHz用でSSIDを分けている場合は、2.4GHz側(末尾が「-G」「-2G」などのSSID)を指定します。大文字・小文字、全角・半角の違いにも注意してください。

Wi-Fi接続コード

検証状況:公式APIに沿って作成/実機未確認

wifi_connect.ino
// ESP32をWi-Fiに接続する(タイムアウト・自動再接続つき)
// 対象: ESP32-DevKitC-32E / Arduino-ESP32 3.3系 / シリアルモニタ 115200bps
#include <WiFi.h>
const char* WIFI_SSID = "your-ssid";             // 2.4GHz帯のSSIDに書き換える
const char* WIFI_PASSWORD = "your-password";
const unsigned long CONNECT_TIMEOUT_MS = 15000;  // 1回の接続待ちの上限(15秒)
const unsigned long RETRY_INTERVAL_MS = 10000;   // 再接続を試す間隔(10秒)
unsigned long lastRetryMs = 0;
// 接続できたらtrue、時間切れならfalseを返す
bool connectWiFi() {
  Serial.print("Connecting to ");
  Serial.println(WIFI_SSID);
  WiFi.mode(WIFI_STA);                           // 子機(ステーション)として動かす
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  unsigned long startMs = millis();
  while (WiFi.status() != WL_CONNECTED) {
    if (millis() - startMs >= CONNECT_TIMEOUT_MS) {
      Serial.println();
      Serial.print("[ERROR] Wi-Fi timeout. status=");
      Serial.println(WiFi.status());
      WiFi.disconnect();                         // 次の再試行に備えて切断
      return false;
    }
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Connected! IP address: ");
  Serial.println(WiFi.localIP());
  Serial.print("RSSI: ");
  Serial.print(WiFi.RSSI());                     // 電波強度(0に近いほど強い)
  Serial.println(" dBm");
  return true;
}
void setup() {
  Serial.begin(115200);
  delay(1000);                                   // シリアルモニタの準備待ち
  connectWiFi();
}
void loop() {
  // 切断されていたら、10秒おきに再接続を試す
  if (WiFi.status() != WL_CONNECTED && millis() - lastRetryMs >= RETRY_INTERVAL_MS) {
    lastRetryMs = millis();
    Serial.println("Wi-Fi disconnected. Reconnecting...");
    connectWiFi();
  }
  // ここにセンサーの読み取りなどの処理を書く
}

シリアルモニタでIPアドレスを確認

書き込み後、シリアルモニタ(115200 baud)を開きます。何も表示されないときは、ボードのEN(リセット)ボタンを押すと最初から実行されます。

成功したときのシリアルモニタ(想定出力・数値は環境で変わります)
Connecting to your-ssid
......
Connected! IP address: 192.168.1.23
RSSI: -52 dBm
if (millis() – startMs >= CONNECT_TIMEOUT_MS)
15秒たっても接続できなければ、状態コードを表示して処理を戻します。パスワードを間違えても永久に待ち続けることがありません。
if (WiFi.status() != WL_CONNECTED && …)
loop()で接続状態を確認し、切れていれば10秒おきに再接続します。長時間動かす機器では必須の処理です。条件分岐の基本はArduinoのif文の書き方ガイドで解説しています。

Wi-Fiに接続できないときの対処法

症状 確認すること
「.」が続いたあと[ERROR] Wi-Fi timeout ①SSID・パスワードの入力ミス ②5GHz側のSSIDを指定していないか ③ルーターとの距離 ④ルーターの接続制限(MACアドレス制限など)
SSIDが合っているか分からない サンプルコード01(Wi-Fiスキャン)で、ESP32から見えているSSIDを一覧表示する
接続と切断を繰り返す・再起動する 電源不足の可能性。USBハブを避けてPCに直接つなぐ、短いケーブルに替える
スマホのテザリングにつながらない テザリングの周波数帯を2.4GHzに設定する(機種により「互換性を優先」などの項目名)
POINT

SSIDとパスワードを書いたスケッチを、GitHubなどの公開リポジトリやSNSのスクリーンショットにそのまま載せないよう注意してください。

06

ESP32のBluetooth・BLEの使い方【スマホ接続】

Bluetooth ClassicとBLEの違い

項目 Bluetooth Classic BLE(Bluetooth Low Energy)
対応シリーズ 初代ESP32のみ 初代ESP32・S3・C3・C6・C5など
得意な用途 シリアル通信(SPP)で文字を連続して送る 小さなデータを省電力でやり取りする
スマホとの相性 iPhoneでは原則として使えない(専用の認証を受けた機器が必要) iPhone・Androidの両方で使える
主なライブラリ BluetoothSerial BLEDevice(この記事で使用)

スマホと連携する作品は、機種を選ばないBLEで作るのが基本です。ここでは「ESP32をスマホから見える状態にして、温度の値を5秒ごとに通知する」BLEサーバーを作ります。

BLE接続のサンプルコード

対象ボード

ESP32-DevKitC-32E(BLE対応の他シリーズでも同じAPIで動く想定)

必要部品・配線

ESP32本体とスマートフォン。配線は不要

ライブラリ

BLEDevice(Arduino-ESP32 3.3系に同梱。追加インストール不要)

スマホアプリ

nRF Connect for Mobile、LightBlueなどのBLEスキャナーアプリ

検証状況:公式サンプルのAPIに沿って作成/実機未確認

ble_temperature_notify.ino
// BLEサーバーとして、ダミーの温度値を5秒ごとにスマホへ通知する
// 対象: ESP32-DevKitC-32E / Arduino-ESP32 3.3系 / シリアルモニタ 115200bps
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
// 公式サンプルと同じUUID。自分の作品ではUUID生成ツールで作り直す
#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
BLEServer *bleServer = nullptr;
BLECharacteristic *tempCharacteristic = nullptr;
volatile bool deviceConnected = false;
bool wasConnected = false;
unsigned long lastNotifyMs = 0;
const unsigned long NOTIFY_INTERVAL_MS = 5000;
// スマホの接続・切断を検知する
class ServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer *server) { deviceConnected = true; }
  void onDisconnect(BLEServer *server) { deviceConnected = false; }
};
void setup() {
  Serial.begin(115200);
  BLEDevice::init("ESP32-Sensor");               // スマホ側に表示される名前
  bleServer = BLEDevice::createServer();
  bleServer->setCallbacks(new ServerCallbacks());
  BLEService *service = bleServer->createService(SERVICE_UUID);
  tempCharacteristic = service->createCharacteristic(
    CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
  );
  tempCharacteristic->addDescriptor(new BLE2902()); // 通知のON/OFFを受け付ける設定
  tempCharacteristic->setValue("no data");
  service->start();
  BLEAdvertising *advertising = BLEDevice::getAdvertising();
  advertising->addServiceUUID(SERVICE_UUID);
  BLEDevice::startAdvertising();                 // スマホから見える状態にする
  Serial.println("BLE server started. Waiting for a connection...");
}
void loop() {
  // 接続中だけ、5秒ごとに値を更新して通知する
  if (deviceConnected && millis() - lastNotifyMs >= NOTIFY_INTERVAL_MS) {
    lastNotifyMs = millis();
    float dummyTemp = random(200, 300) / 10.0;   // 20.0〜29.9度のダミー値
    String payload = String(dummyTemp, 1) + "C";
    tempCharacteristic->setValue((uint8_t *)payload.c_str(), payload.length());
    tempCharacteristic->notify();
    Serial.println("Notify: " + payload);
  }
  // 切断されたら、もう一度スマホから見える状態に戻す
  if (!deviceConnected && wasConnected) {
    wasConnected = false;
    delay(500);
    bleServer->startAdvertising();
    Serial.println("Disconnected. Advertising again...");
  }
  if (deviceConnected && !wasConnected) {
    wasConnected = true;
    Serial.println("Device connected.");
  }
}
成功したときのシリアルモニタ(想定出力)
BLE server started. Waiting for a connection...
Device connected.
Notify: 24.3C
Notify: 27.1C

スマホアプリによる確認方法

CHECK

このBLE機器は、スマホの「設定」→「Bluetooth」の画面からペアリングする必要はありません(設定画面の一覧には表示されないことがあります)。イヤホンなどと違い、BLEの自作機器はBLEスキャナーアプリの中で探して接続します。

  1. スマホのBluetoothをオンにし、BLEスキャナーアプリ(例:nRF Connect)を開く。Androidは位置情報・付近のデバイスの権限を許可する
  2. スキャン結果からESP32-Sensorを探し、「CONNECT」を押す
  3. サービス(UUIDが4fafc201で始まるもの)を開き、キャラクタリスティック(beb5483eで始まるもの)を表示する
  4. 通知を有効にする(購読する)ボタンを押す。Android版のnRF Connectでは下向き矢印が3本並んだアイコンです(表示はアプリやバージョンで異なります)
  5. 5秒ごとに値が更新される。16進数で表示される場合は、表示形式をUTF-8(文字列)に切り替える

手順4の購読を行わないと、ESP32側でnotify()を呼んでもスマホには値が届きません。NOTIFYは「スマホ側が受け取りを申し込んだときだけ送られる」仕組みで、コード中のBLE2902がその申し込みを受け付ける設定です。

if (deviceConnected && millis() – lastNotifyMs >= NOTIFY_INTERVAL_MS)
delay()で止めずに、millis()で経過時間を見て「5秒に1回だけ」実行する書き方です。考え方はArduinoのmillis()でdelayを使わない書き方と同じです。

接続できない場合の原因

症状 原因と対策
アプリに「ESP32-Sensor」が出ない アプリのBluetooth・位置情報の権限、スマホとの距離、シリアルモニタに起動メッセージが出ているかを確認。別のスマホが接続中だと表示されない
接続はできるが値が変わらない 通知の購読をしていない(手順4)
名前や内容が古いまま表示される スマホ側のキャッシュ。アプリの再スキャン、またはスマホのBluetoothを入れ直す
BLEDevice.h: No such fileでコンパイルできない ボードの選択がESP32になっていない。「ツール」→「ボード」を確認
「スケッチが大きすぎます」と出る BLEはプログラムサイズが大きい。「ツール」→「Partition Scheme」で「Huge APP」などアプリ領域の広い設定を選ぶ
POINT

UUIDはサービスとキャラクタリスティックを見分ける番号です。自分の作品ではUUID Generator ↗などで生成し、スマホアプリ側の設定と一致させます。実装の詳細はArduino-ESP32のBLEドキュメント ↗と公式サンプルで確認できます。

07

ESP32でセンサーデータをWi-Fi送信する方法

Wi-Fi接続とセンサーの読み取りを組み合わせ、DHT22の温度・湿度を30秒ごとにPCへ送って記録する構成を作ります。送信先には、自分のPCで動かす小さなPythonプログラムを使います。外部サービスの登録が不要で、送ったデータがその場で画面に表示されるため、成功したかどうかを確実に確認できます。

データの流れ
DHT22 --(信号線)--> ESP32 --(Wi-Fi / HTTP POST / JSON)--> PCのPythonサーバー --> 画面表示・CSV保存

必要な部品と配線

対象ボード

ESP32-DevKitC-32E(ボード設定:ESP32 Dev Module)

必要部品

DHT22(またはDHT11)、10kΩ抵抗(基板付きモジュール品は不要な場合が多い)、ESP32と同じWi-Fiにつながったパソコン

配線

DHT22のVCC → 3V3/DATA → GPIO4/GND → GND。センサー単体の場合はDATAと3V3の間に10kΩを入れる

ライブラリ

ArduinoJson 7系(執筆時点の最新は7.4.3)、DHT sensor library(Adafruit)、Adafruit Unified Sensor

ライブラリは「ツール」→「ライブラリを管理」で名前を検索してインストールします。「DHT sensor library」を入れるときに依存ライブラリの追加を聞かれたら「全てをインストール」を選びます。操作に迷ったらArduinoライブラリの入れ方・管理方法を参照してください。

温湿度センサーの読み取り

DHT22はdht.readTemperature()とdht.readHumidity()で値を取得します。読み取りは2秒以上の間隔を空ける必要があり、失敗するとNaN(数値でない値)が返ります。センサーの選び方と配線の基礎はArduinoで温湿度センサーを使う方法|DHT11・DHT22の使い分けで解説しています。

サーバー側で受信を確認する方法(先に準備)

ESP32のコードを書き込む前に、受信側を用意します。Python 3が入っているPCで、次のファイルをsensor_server.pyとして保存し、ターミナル(コマンドプロンプト)でpython sensor_server.pyを実行します。追加のパッケージは不要です。

検証状況:PC上で受信・CSV保存の動作を確認済み(ESP32実機からの送信は未確認)

sensor_server.py(PC側・Python 3)
# ESP32から届いたJSONを表示し、CSVに保存する(家庭内LANでの学習用)
import csv
import json
from datetime import datetime
from http.server import BaseHTTPRequestHandler, HTTPServer
CSV_FILE = "sensor_log.csv"
PORT = 8000
latest = {}
class Handler(BaseHTTPRequestHandler):
    def _send_json(self, status, body):
        data = json.dumps(body).encode("utf-8")
        self.send_response(status)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(data)))
        self.end_headers()
        self.wfile.write(data)
    def do_POST(self):
        global latest
        if self.path != "/api/sensor":
            self._send_json(404, {"error": "not found"})
            return
        length = int(self.headers.get("Content-Length", 0))
        try:
            payload = json.loads(self.rfile.read(length))
        except json.JSONDecodeError:
            payload = None
        if not isinstance(payload, dict):
            self._send_json(400, {"error": "invalid json"})
            return
        now = datetime.now().isoformat(timespec="seconds")
        latest = {"time": now, **payload}
        print(now, payload)
        with open(CSV_FILE, "a", newline="") as f:
            csv.writer(f).writerow([now, payload.get("device"), payload.get("temperature"), payload.get("humidity"), payload.get("value")])
        self._send_json(200, {"result": "ok"})
    def do_GET(self):
        if self.path == "/latest":
            self._send_json(200, latest)
        else:
            self._send_json(404, {"error": "not found"})
if __name__ == "__main__":
    print("Listening on port", PORT, "... (Ctrl+C to stop)")
    HTTPServer(("0.0.0.0", PORT), Handler).serve_forever()
  1. PCのIPアドレスを調べる。Windowsはipconfig、macOS・Linuxはifconfigまたはip addrで、192.168.x.xのような値を確認する
  2. 初回実行時にファイアウォールの確認が出たら、プライベートネットワークでの通信を許可する
  3. PCとESP32を同じルーター(同じWi-Fi)につなぐ。来客用(ゲスト)Wi-Fiは機器どうしの通信が遮断されることがあります
CHECK

このサーバーは認証も暗号化もない学習用です。自宅のLAN内だけで使い、インターネットへ公開しないでください。確認が終わったらCtrl+Cで停止します。

HTTP送信の仕組みとコード

ESP32は、温度と湿度を{"device":"esp32-dht22","temperature":24.3,"humidity":51.2}というJSON形式の文字列にまとめ、HTTPのPOSTでPCへ送ります。コード中のAPI_URLのIPアドレスを、先ほど調べたPCのIPアドレスに書き換えてください。

検証状況:公式APIに沿って作成/実機未確認

dht22_http_post.ino
// DHT22の温湿度をJSONにまとめ、30秒ごとにHTTP POSTで送信する
// 対象: ESP32-DevKitC-32E / Arduino-ESP32 3.3系 / ArduinoJson 7系 / DHT sensor library
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <DHT.h>
const char* WIFI_SSID = "your-ssid";
const char* WIFI_PASSWORD = "your-password";
const char* API_URL = "http://192.168.1.10:8000/api/sensor"; // 受信するPCのIPアドレスに書き換える
#define DHT_PIN 4
#define DHT_TYPE DHT22            // DHT11を使う場合は DHT11 に変更
DHT dht(DHT_PIN, DHT_TYPE);
const unsigned long SEND_INTERVAL_MS = 30000;   // 送信間隔(30秒)
const unsigned long WIFI_TIMEOUT_MS = 15000;    // Wi-Fi接続待ちの上限
unsigned long lastSendMs = 0;
bool connectWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  unsigned long startMs = millis();
  while (WiFi.status() != WL_CONNECTED) {
    if (millis() - startMs >= WIFI_TIMEOUT_MS) {
      Serial.println("[ERROR] Wi-Fi timeout.");
      WiFi.disconnect();
      return false;
    }
    delay(500);
  }
  Serial.print("Wi-Fi connected. IP: ");
  Serial.println(WiFi.localIP());
  return true;
}
// 送信に成功(HTTPステータスが200番台)したらtrueを返す
bool sendSensorData(float temperature, float humidity) {
  HTTPClient http;
  http.setConnectTimeout(5000);
  http.setTimeout(5000);
  if (!http.begin(API_URL)) {
    Serial.println("[ERROR] Invalid URL.");
    return false;
  }
  http.addHeader("Content-Type", "application/json");
  JsonDocument doc;                 // ArduinoJson 7系の書き方
  doc["device"] = "esp32-dht22";
  doc["temperature"] = temperature;
  doc["humidity"] = humidity;
  String payload;
  serializeJson(doc, payload);
  int statusCode = http.POST(payload);
  bool ok = (statusCode >= 200 && statusCode < 300);
  if (ok) {
    Serial.print("POST OK. status=");
    Serial.println(statusCode);
  } else if (statusCode < 0) {
    Serial.print("[ERROR] Could not reach server: ");
    Serial.println(http.errorToString(statusCode));
  } else {
    Serial.print("[ERROR] Server returned status=");
    Serial.println(statusCode);
  }
  http.end();
  return ok;
}
void measureAndSend() {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("Wi-Fi not connected. Reconnecting...");
    if (!connectWiFi()) {
      return;                       // つながらなければ今回は送信しない
    }
  }
  float humidity = dht.readHumidity();
  float temperature = dht.readTemperature();
  if (isnan(humidity) || isnan(temperature)) {
    Serial.println("[ERROR] Failed to read from DHT sensor.");
    return;                         // 読み取り失敗時は送信しない
  }
  Serial.print("Temp: ");
  Serial.print(temperature, 1);
  Serial.print(" C  Humidity: ");
  Serial.print(humidity, 1);
  Serial.println(" %");
  sendSensorData(temperature, humidity);
}
void setup() {
  Serial.begin(115200);
  dht.begin();
  connectWiFi();
  delay(2000);                      // DHTセンサーの安定待ち
  measureAndSend();                 // 起動直後に1回送信する
  lastSendMs = millis();
}
void loop() {
  if (millis() - lastSendMs >= SEND_INTERVAL_MS) {
    lastSendMs = millis();
    measureAndSend();
  }
}
成功したときの表示(想定出力・数値は環境で変わります)
[ESP32のシリアルモニタ]
Wi-Fi connected. IP: 192.168.1.23
Temp: 24.3 C  Humidity: 51.2 %
POST OK. status=200
[PCのターミナル]
2026-10-09T21:15:03 {'device': 'esp32-dht22', 'temperature': 24.3, 'humidity': 51.2}

HTTPの結果の読み方

表示 意味 対策
200番台(200・201・204など) サーバーが受け付けた 成功。200だけでなく200番台全体を成功として扱う
負の数(connection refusedなど) サーバーまで届いていない IPアドレスとポート番号、Pythonサーバーが起動しているか、ファイアウォール、同じWi-Fiかを確認
400番台 届いたが、URLや送った内容に問題がある 404はURLのパス違い、400はJSONの形式違い
500番台 サーバー側のプログラムでエラーが起きた PCのターミナルに出たエラーを確認
CHECK

インターネット上のサービスへ送る場合は、httpsを使います。その際、証明書の検証を無効にするsetInsecure()は通信相手を確認しない設定で、動作確認の一時的な手段にとどめてください。本番ではNetworkClientSecureに接続先のルート証明書を設定して検証を行います。この記事のコードのURL(192.168.1.10)は例であり、そのままでは送信できません。

Pythonとの連携と応用

受信したデータはsensor_log.csvに追記されるので、pandasやExcelでそのまま開けます。グラフ化の方法はArduinoのセンサーデータをリアルタイムでグラフ表示する方法(Python連携)が参考になります。USBシリアルで受け取っていた値がWi-Fi経由に変わるだけで、PC側の処理の考え方は共通です。

APPLICATION

無線化すると、体や道具に付けたセンサーの値をケーブルなしで取り出せるため、動作計測の試作に向いています。考え方はArduinoとPythonとセンサーを用いたリハビリテーションへの応用やArduino×筋電センサーのガイドで紹介しています。なお、本記事の内容は研究・試作・教育を目的としたもので、医療機器としての安全性や有効性を示すものではありません。人を対象に使う場合は、所属機関の倫理審査や関連法規に従ってください。

補足:AIにコードの改造を頼むときの指示例
PROMPT次のESP32用スケッチ(Arduino-ESP32 3.3系、ArduinoJson 7系)を改造してください。対象ボードはESP32-DevKitC-32Eです。変更点:送信間隔を60秒にし、送信後にDeep Sleepへ入るようにする。Wi-Fi接続のタイムアウトとHTTPステータスの判定(200番台を成功とする)は残してください。変更した行に日本語コメントを付けてください。
(この下に現在のコードを貼り付ける)
08

ESP32のサンプルコード6選【コピーして使える】

ここまでの内容を発展させる、独立したスケッチを6本まとめました。すべてESP32-DevKitC-32E(ボード設定:ESP32 Dev Module)とArduino-ESP32 3.3系が前提で、シリアルモニタは115200 baudです。検索欄に「Wi-Fi」「BLE」「HTTP」などと入力すると絞り込めます。

検証状況:6本とも公式APIに沿って作成/実機未確認

6 / 6件を表示
該当するコードがありません。別のキーワードで検索してください。
CODE 01

周囲のWi-Fi(SSID)をスキャンして一覧表示する

ESP32から見えているSSIDと電波強度を表示します。Wi-Fiにつながらないときの最初の切り分けに使えます。

入門ライブラリ:WiFi.h

必要部品

ESP32本体のみ(USBケーブルで給電)

配線

不要

コードを表示・コピー
e01_wifi_scan.ino
#include <WiFi.h>
void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);
}
void loop() {
  Serial.println("Scanning...");
  int n = WiFi.scanNetworks();
  if (n <= 0) {
    Serial.println("No networks found.");
  }
  for (int i = 0; i < n; i++) {
    Serial.print(i + 1);
    Serial.print(": ");
    Serial.print(WiFi.SSID(i));
    Serial.print("  RSSI=");
    Serial.print(WiFi.RSSI(i));
    Serial.print(" dBm  ch=");
    Serial.println(WiFi.channel(i));
  }
  WiFi.scanDelete();   // スキャン結果のメモリを解放
  delay(10000);        // 10秒ごとに再スキャン
}

成功時の出力例:1: my-home-wifi RSSI=-48 dBm ch=6のような行が並びます。
調整ポイント:一覧に自宅のSSIDが出ない場合、そのSSIDは5GHz帯専用の可能性があります(初代ESP32は2.4GHz帯のみ対応)。目安として、RSSIが-80 dBmより小さい場合は電波が弱い状態です。

6選の一覧へ戻る ↑

CODE 02

固定IPアドレスでWi-Fiに接続する

毎回同じIPアドレスで起動させます。ESP32をWebサーバーにして、決まったアドレスでアクセスしたい場合に使います。

入門+ライブラリ:WiFi.h

必要部品

ESP32本体のみ

配線

不要

コードを表示・コピー
e02_wifi_static_ip.ino
#include <WiFi.h>
const char* ssid = "your-ssid";
const char* password = "your-password";
// 自宅のネットワークに合わせて書き換える(ルーターのDHCP範囲外のアドレスを指定)
IPAddress localIP(192, 168, 1, 50);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(192, 168, 1, 1);     // 多くの家庭用ルーターではgatewayと同じ
void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  if (!WiFi.config(localIP, gateway, subnet, dns)) {
    Serial.println("Static IP configuration failed.");
  }
  WiFi.begin(ssid, password);
  unsigned long startMs = millis();
  while (WiFi.status() != WL_CONNECTED) {
    if (millis() - startMs >= 15000) {
      Serial.println();
      Serial.println("[ERROR] Wi-Fi timeout.");
      return;
    }
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Fixed IP address: ");
  Serial.println(WiFi.localIP());
}
void loop() {}

成功時の出力例:Fixed IP address: 192.168.1.50
調整ポイント:gateway・subnetはルーターの管理画面、またはPCのipconfigの結果に合わせます。DNSを指定しないと、IPアドレスでは通信できても、URL(ホスト名)での通信に失敗することがあります。

6選の一覧へ戻る ↑

CODE 03

HTTP GETでサーバーからJSONを取得する

サーバーにあるJSONを取得し、必要な値を取り出す基本形です。第7節のPythonサーバーの/latestから、最後に受信したデータを読み出します。

基礎+ライブラリ:HTTPClient / ArduinoJson 7系

必要部品

ESP32本体、第7節のsensor_server.pyを起動したPC

配線

不要

コードを表示・コピー
e03_http_get_json.ino
// ライブラリマネージャーでArduinoJson(7系)を追加しておく
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
const char* ssid = "your-ssid";
const char* password = "your-password";
const char* API_URL = "http://192.168.1.10:8000/latest"; // 受信するPCのIPアドレスに書き換える
void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  unsigned long startMs = millis();
  while (WiFi.status() != WL_CONNECTED) {
    if (millis() - startMs >= 15000) {
      Serial.println("[ERROR] Wi-Fi timeout.");
      return;
    }
    delay(500);
  }
  HTTPClient http;
  http.setConnectTimeout(5000);
  http.begin(API_URL);
  int statusCode = http.GET();
  if (statusCode >= 200 && statusCode < 300) {
    JsonDocument doc;
    DeserializationError error = deserializeJson(doc, http.getString());
    if (error) {
      Serial.print("[ERROR] JSON parse failed: ");
      Serial.println(error.c_str());
    } else {
      float temperature = doc["temperature"] | -999.0;  // キーが無いときは-999
      Serial.print("temperature: ");
      Serial.println(temperature);
      serializeJsonPretty(doc, Serial);                 // 受け取ったJSON全体を表示
      Serial.println();
    }
  } else {
    Serial.print("[ERROR] GET failed. status=");
    Serial.println(statusCode);
  }
  http.end();
}
void loop() {}

成功時の出力例:temperature: 24.30に続いてJSON全体が表示されます(先に第7節またはコード04でデータを送っておきます)。
調整ポイント:取り出すキー名はサーバーが返すJSONに合わせます。インターネット上の公開APIの多くはhttpsのため、NetworkClientSecureと証明書の設定が別途必要です。

6選の一覧へ戻る ↑

CODE 04

ダミー値をJSONでHTTP POST送信する(センサーなしでテスト)

センサーが手元になくても、乱数の値を送って通信部分だけ先に確認できます。

基礎+ライブラリ:HTTPClient / ArduinoJson 7系

必要部品

ESP32本体、第7節のsensor_server.pyを起動したPC

配線

不要

コードを表示・コピー
e04_http_post_dummy.ino
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
const char* ssid = "your-ssid";
const char* password = "your-password";
const char* API_URL = "http://192.168.1.10:8000/api/sensor"; // 受信するPCのIPアドレスに書き換える
void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  unsigned long startMs = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - startMs < 15000) {
    delay(500);
  }
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("[ERROR] Wi-Fi timeout. Press EN to retry.");
  }
}
void loop() {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.setConnectTimeout(5000);
    http.begin(API_URL);
    http.addHeader("Content-Type", "application/json");
    JsonDocument doc;
    doc["device"] = "esp32-test";
    doc["value"] = random(0, 100);   // 実センサーの値に置き換える
    String payload;
    serializeJson(doc, payload);
    int statusCode = http.POST(payload);
    if (statusCode >= 200 && statusCode < 300) {
      Serial.print("POST OK. status=");
    } else {
      Serial.print("[ERROR] POST failed. status=");
    }
    Serial.println(statusCode);
    http.end();
  } else {
    Serial.println("Wi-Fi not connected. Skip sending.");
  }
  delay(10000);                      // 10秒間隔
}

成功時の出力例:ESP32側にPOST OK. status=200、PC側に{'device': 'esp32-test', 'value': 42}のような行が表示されます。
調整ポイント:doc["value"]を実測値に置き換えれば、第7節のコードへ発展できます。

6選の一覧へ戻る ↑

CODE 05

BLEでボタンの状態をスマホへ通知する

物理ボタンを押した・離したという変化を、BLE経由でスマホへその場で通知します。

基礎+ライブラリ:BLEDevice

必要部品

ESP32本体、押しボタン(タクトスイッチ)、BLEスキャナーアプリを入れたスマホ

配線

ボタンの片側 → GPIO27/反対側 → GND(内蔵プルアップを使うため抵抗は不要)

コードを表示・コピー
e05_ble_button_notify.ino
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#define SERVICE_UUID        "6e400001-b5a3-f393-e0a9-e50e24dcca9e"
#define CHARACTERISTIC_UUID "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
#define BUTTON_PIN 27
BLEServer *bleServer = nullptr;
BLECharacteristic *buttonCharacteristic = nullptr;
volatile bool deviceConnected = false;
bool wasConnected = false;
bool lastPressed = false;
class ServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer *server) { deviceConnected = true; }
  void onDisconnect(BLEServer *server) { deviceConnected = false; }
};
void setup() {
  Serial.begin(115200);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  BLEDevice::init("ESP32-Button");
  bleServer = BLEDevice::createServer();
  bleServer->setCallbacks(new ServerCallbacks());
  BLEService *service = bleServer->createService(SERVICE_UUID);
  buttonCharacteristic = service->createCharacteristic(
    CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
  );
  buttonCharacteristic->addDescriptor(new BLE2902());
  buttonCharacteristic->setValue("released");
  service->start();
  BLEDevice::getAdvertising()->addServiceUUID(SERVICE_UUID);
  BLEDevice::startAdvertising();
  Serial.println("BLE button ready.");
}
void loop() {
  bool pressed = digitalRead(BUTTON_PIN) == LOW;   // 内蔵プルアップなのでLOWで押下
  if (pressed != lastPressed) {
    lastPressed = pressed;
    buttonCharacteristic->setValue(pressed ? "pressed" : "released");
    if (deviceConnected) {
      buttonCharacteristic->notify();
    }
    Serial.println(pressed ? "pressed" : "released");
  }
  if (!deviceConnected && wasConnected) {          // 切断されたら再び見える状態に戻す
    wasConnected = false;
    delay(500);
    bleServer->startAdvertising();
  }
  if (deviceConnected && !wasConnected) {
    wasConnected = true;
  }
  delay(30);                                       // 簡易的なチャタリング対策
}

成功時の出力例:ボタンを押すたびにシリアルモニタへpressed/releasedが表示され、アプリ側の値も切り替わります。
調整ポイント:アプリで通知の購読を有効にしてから押してください。UUIDはNordic UART Service互換の値を例として使っています。

6選の一覧へ戻る ↑

CODE 06

Deep Sleepで一定間隔だけ起きる省電力運用

電池で動かすセンサー端末の定番です。60秒ごとに起きて処理をし、すぐに眠ります。

基礎+ライブラリ:esp_sleep.h

必要部品

ESP32本体(電池での運用を想定)

配線

不要

コードを表示・コピー
e06_deep_sleep.ino
#include <esp_sleep.h>
#define uS_TO_S_FACTOR 1000000ULL  // マイクロ秒→秒の変換係数
#define SLEEP_SECONDS 60           // 60秒ごとに起床
RTC_DATA_ATTR int bootCount = 0;   // スリープをまたいで保持される変数
void setup() {
  Serial.begin(115200);
  delay(200);
  bootCount++;
  Serial.print("Woke up. bootCount=");
  Serial.println(bootCount);
  // ここでセンサーの読み取りやWi-Fi送信を行う
  Serial.println("Going to deep sleep now.");
  Serial.flush();                  // 送信しきってから眠る
  esp_sleep_enable_timer_wakeup(SLEEP_SECONDS * uS_TO_S_FACTOR);
  esp_deep_sleep_start();          // ここでCPUがほぼ停止する
}
void loop() {
  // Deep Sleepからの復帰は再起動に近く、loop()には到達しない
}

成功時の出力例:60秒ごとにWoke up. bootCount=2のように数字が増えていきます。
調整ポイント:復帰のたびにsetup()が最初から実行されるため、Wi-Fiへの接続も毎回やり直しになります。開発ボードはUSB変換ICや電源LEDが電流を消費するため、ボード全体の消費電流はチップ単体の仕様値より大きくなります。

6選の一覧へ戻る ↑

09

ESP32のよくあるエラーと解決方法

動かないときは、「ケーブル → ポート → ボード設定 → 書き込み → 電源 → 配線」の順に確認すると、原因を早く絞り込めます。エラーメッセージの文言はツールのバージョンによって多少異なります。

書き込みできないとき

症状 主な原因 対策(上から順に)
ボード一覧に「esp32」がない パッケージが未導入、URLの入力ミス ①ボードマネージャURLを確認 ②「esp32 by Espressif Systems」をインストール ③IDEを再起動
ポートが表示されない 充電専用ケーブル、ドライバ未導入 ①データ通信対応ケーブルに交換 ②別のUSB端子で試す ③USBシリアルIC(CP210x・CH340など)のドライバを入れる
「Connecting…」のまま進まず、接続失敗のエラーになる 書き込みモードに入れていない ①BOOTボタンを押し続け、書き込みが始まったら離す ②GPIO0・2・12などにつないだ配線を外して再試行
ポートが使用中というエラー シリアルモニタや他のソフトがポートを使用 シリアルモニタ、シリアルプロッタ、Pythonなど同じポートを開いているソフトを閉じる
書き込み途中で失敗する ケーブルやUSBハブの品質、通信速度 ①PCに直接つなぐ ②「ツール」→「Upload Speed」を115200に下げる

ポートまわりの切り分けはArduinoで「ポートが見つからない」ときの原因と解決策と共通点が多くあります。なお、avrdudeの書き込みエラーはAVR系Arduino用のツールのエラーで、ESP32の書き込み(esptool)では表示されません。ケーブルやポートの確認手順は参考になります。

コンパイルエラーが出るとき

メッセージの例 原因と対策
WiFi.hやBLEDevice.hがNo such file or directory ボードの選択がESP32になっていない。「ツール」→「ボード」→「esp32」から選び直す
ArduinoJson.hやDHT.hがNo such file or directory ライブラリが未インストール。「ライブラリを管理」から追加する
JsonDocumentの行でエラーになる ArduinoJsonが6系以前。ライブラリマネージャーで7系に更新する
ネットで見つけた古いコードがコンパイルできない Arduino-ESP32の2系と3系ではAPIが一部変わっている(PWMのledcSetupなど)。公式の移行ガイド ↗を確認する

書き込めたのに動かないとき

症状 原因と対策
シリアルモニタが文字化けする 速度の不一致。Serial.begin(115200)とモニタ側の115200 baudをそろえる
再起動を繰り返す(Brownout detector was triggered) 電源不足。①外部回路を外して単体で確認 ②USBハブを避ける ③モーターやサーボは別電源にする
Guru Meditation Errorで再起動する プログラムの異常(初期化していないポインタの使用など)。直前に追加した処理を戻して切り分ける
Wi-Fiを使うとアナログ値が読めない ADC2系のピンを使っている。GPIO32〜36・39へ移す(GPIOの注意点)
Wi-Fiにつながらない Wi-Fiに接続できないときの対処法へ
BLEがスマホに表示されない BLEで接続できない場合の原因へ
HTTP送信が失敗する HTTPの結果の読み方へ。まずステータスの数値をシリアルモニタで確認する

原因の切り分けは、シリアルモニタに途中経過を出すのが近道です。出力の使いこなしはArduinoのシリアルモニタ活用術にまとめています。

10

ESP32入門のよくある質問

ESP32はArduino IDEで使えますか?

使えます。Arduino IDEの基本設定にEspressif公式のボードマネージャURLを追加し、ボードマネージャで「esp32 by Espressif Systems」をインストールすると、Arduinoと同じ書き方でスケッチを書き込めます。

ESP32とArduinoはどちらを買えばいいですか?

Wi-FiやBluetoothでスマホやPCと連携したいならESP32、5Vのセンサーやシールドで基礎から学びたいならArduino Unoが取り組みやすい選択です。Unoの形のまま無線を使いたい場合はUno R4 WiFiも候補になります。両方を用途で使い分ける人も多くいます。

初心者が最初に買うESP32ボードはどれがいいですか?

作例と解説が最も多い初代ESP32の開発ボード(ESP32-DevKitC-32Eなど)が進めやすい選択です。技適マークの表示があること、ピン配置図が公開されていること、USB端子の形状が手持ちのケーブルと合うことを確認してください。

ESP32は5GHzのWi-Fiに接続できますか?

初代ESP32、ESP32-S3、C3、C6は2.4GHz帯のみに対応します。5GHz帯を使いたい場合は、ESP32-C5など対応するシリーズを選ぶ必要があります。

ESP32に5Vのセンサーをつないでも大丈夫ですか?

センサーの出力信号が5Vの場合、GPIOへ直接つなぐことはできません。レベル変換モジュールか分圧抵抗で3.3V以下に下げてください。3.3Vの電源と信号に対応したセンサーであれば、通常はそのまま接続できます。

Wi-FiとBluetoothは同時に使えますか?

同時に使えます。ただし1つの無線回路とアンテナを時間で分け合って動作するため、両方で大量の通信を行うと速度の低下や不安定さが出ることがあります。BLEも使うとプログラムサイズとメモリの使用量が増える点にも注意してください。

スマホのBluetooth設定画面にESP32が表示されません。故障ですか?

故障ではありません。BLEの自作機器は、スマホの設定画面ではなくBLEスキャナーアプリ(nRF Connectなど)の中で探して接続します。アプリにも表示されない場合は、アプリの権限と、ESP32のシリアルモニタに起動メッセージが出ているかを確認してください。

センサーデータを送る先はどう用意すればいいですか?

最初は、この記事で紹介した自分のPC上のPythonプログラムが手軽で確実です。登録が不要で、届いたデータをその場で確認できます。慣れてきたら、MQTTブローカーやクラウドのIoTサービス、自作のWebサーバーなど、目的に合わせた送信先に切り替えます。

11

まとめ|ESP32で最初に作りたい電子工作

  • ESP32は無線内蔵・3.3V動作のマイコンで、Arduino IDEからそのまま開発できます。
  • はじめての1台は初代ESP32の開発ボード。シリーズによってBluetoothの種類やWi-Fiの周波数帯が異なります。
  • 配線は5Vを信号ピンに入れないこと、入力専用・起動に関わるピンを避けること、Wi-Fi併用時のアナログ入力はGPIO32〜36・39を使うことが要点です。
  • 通信のコードにはタイムアウトと再接続を入れ、成功・失敗をシリアルモニタで確認できるようにします。

進める順番は、LED点滅 → Wi-Fi接続 → BLEでスマホ通知 → センサーデータの送信がおすすめです。そこまで動けば、次のような作品に発展させられます。

  • 部屋の温湿度ロガー:第7節の構成をそのまま動かし続け、CSVをグラフにする
  • 電池で動く見守りセンサー:第7節の送信とコード06のDeep Sleepを組み合わせる
  • スマホに通知するボタン:コード05を応用し、呼び出しボタンやカウンターにする

あわせて読みたい関連記事

参考にした公式資料

ESP32 GETTING STARTED GUIDE — Arduinoで学んだ基礎を、無線でつながる作品へ。

関連記事

特集記事

コメント

この記事へのコメントはありません。

TOP
CLOSE