ESPHome 気象センサーデバイス構築手順書

対象: ESP32-C3 SuperMini + SHT41(温湿度) + BMP280(気圧) + SSD1306 OLED(0.96inch, I2C)


1. 構成概要

項目内容
CPUESP32-C3 SuperMini
温湿度センサーSHT41 (I2Cアドレス 0x44)
気圧センサーBMP280 (I2Cアドレス 0x76 または 0x77)
表示器0.96inch OLED SSD1306 (I2C, 128×64)
Home Assistantで取得する値温度・湿度・気圧・飽和水蒸気圧・実際の水蒸気圧・絶対湿度
OLED表示温度・湿度・気圧の3項目

I2C配線

ボードによってピン配置が異なるため、必ず実機で確認すること。

•ESP32C3 Super mini: SDA=GPIO8, SCL=GPIO9

•ESP32C3 Super mini OLED一体型: SDA=GPIO5, SCL=GPIO6

GPIO8/9はストラッピングピンだが、I2Cプルアップがあれば通常問題なく動作する(警告は出るが無視して良い)。


2. ESPHome YAML設定

esphome:
  name: study-weather-station
  friendly_name: Study Weather Station

esp32:
  board: esp32-c3-devkitm-1
  variant: esp32c3
  framework:
    type: arduino

logger:

api:
  encryption:
    key: !secret study_weather_station_api_key

ota:
  platform: esphome
  password: !secret study_weather_station_ota_password

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: "Study Weather Station Fallback"
    password: !secret study_weather_station_ap_password

captive_portal:

i2c:
  sda: GPIO8
  scl: GPIO9
  scan: true
  id: bus_a

sensor:
  # SHT41: 温度・湿度
  - platform: sht4x
    address: 0x44
    update_interval: 60s
    temperature:
      name: "Study Temperature"
      id: study_temp
      accuracy_decimals: 1
    humidity:
      name: "Study Humidity"
      id: study_humi
      accuracy_decimals: 1

  # BMP280: 気圧 (温度はSHT41優先のためinternal化)
  # 注意: プラットフォーム名は bmp280 ではなく bmp280_i2c (ESPHome仕様変更)
  - platform: bmp280_i2c
    i2c_id: bus_a
    address: 0x76   # SDO→GND接続時。VDD接続なら0x77
    update_interval: 60s
    temperature:
      name: "Study Pressure Sensor Temperature"
      id: study_bmp_temp
      internal: true
    pressure:
      name: "Study Pressure"
      id: study_press
      accuracy_decimals: 1

  # 飽和水蒸気圧 (Tetensの式, hPa)
  - platform: template
    name: "Study Saturation Vapor Pressure"
    id: study_sat_vapor_pressure
    unit_of_measurement: "hPa"
    icon: "mdi:water-percent"
    accuracy_decimals: 2
    update_interval: 60s
    lambda: |-
      if (id(study_temp).has_state()) {
        float t = id(study_temp).state;
        return 6.112 * exp((17.67 * t) / (t + 243.5));
      } else {
        return {};
      }

  # 実際の水蒸気圧 (hPa)
  - platform: template
    name: "Study Actual Vapor Pressure"
    id: study_actual_vapor_pressure
    unit_of_measurement: "hPa"
    icon: "mdi:water"
    accuracy_decimals: 2
    update_interval: 60s
    lambda: |-
      if (id(study_temp).has_state() && id(study_humi).has_state()) {
        float t = id(study_temp).state;
        float rh = id(study_humi).state;
        float es = 6.112 * exp((17.67 * t) / (t + 243.5));
        return es * rh / 100.0;
      } else {
        return {};
      }

  # 絶対湿度 (g/m3)
  - platform: template
    name: "Study Absolute Humidity"
    id: study_absolute_humidity
    unit_of_measurement: "g/m³"
    icon: "mdi:water-outline"
    accuracy_decimals: 2
    update_interval: 60s
    lambda: |-
      if (id(study_temp).has_state() && id(study_humi).has_state()) {
        float t = id(study_temp).state;
        float rh = id(study_humi).state;
        float es = 6.112 * exp((17.67 * t) / (t + 243.5));
        float e = es * rh / 100.0;
        return 216.7 * e / (273.15 + t);
      } else {
        return {};
      }

font:
  - file: "gfonts://Roboto"
    id: font_main
    size: 20

display:
  - platform: ssd1306_i2c
    i2c_id: bus_a
    model: "SSD1306 128x64"
    address: 0x3C
    id: study_oled_display
    update_interval: 60s
    lambda: |-
      it.printf(0, 2,  id(font_main), "TEMP %.1f C", id(study_temp).state);
      it.printf(0, 23, id(font_main), "HUMI %.0f %%", id(study_humi).state);
      it.printf(0, 44, id(font_main), "PRES %.0f hPa", id(study_press).state);

secrets.yaml (ESPHome側)

wifi_ssid: "your-wifi-ssid"
wifi_password: "your-wifi-password"

study_weather_station_api_key: "(32byte base64キー。ESPHome Dashboardで生成)"
study_weather_station_ota_password: "(個別に設定、他デバイスと共用しない)"
study_weather_station_ap_password: "(共用可)"

重要: 3つのキーの共用可否

項目共用リスク推奨
ap_password低い(物理近接必須・一時的)共用でOK
api_key中(LAN内限定なら許容範囲)個別推奨
ota_password高い(乗っ取り被害範囲が広がる)個別必須

3. 他の部屋(温湿度のみ)へのテンプレート展開

気圧・水蒸気圧系が不要な部屋(寝室等)は、SHT41+OLEDのみの簡易版を使う。substitutionsブロックの4行を書き換えるだけで複製可能。

substitutions:
device_name: bedroom-weather-station
friendly_name: "Bedroom Weather Station"
room_id: bedroom
room_label: "Bedroom"

既知の制約!secretタグの引数の中ではsubstitutionsが展開されない(ESPHomeの既知の制限、feature request #3171)。api_key/ota_password/ap_passwordの3箇所とap: ssidは、部屋を追加するたびにroom_id部分を手動でリテラル文字列に書き換える必要がある。


4. Home Assistant側 entity_id 整理手順

日本語のデバイス名/エリア名を使うと、entity_id自動生成時に中国語ピンインへ誤変換される既知の不具合があるため(GitHub Issue #155528)、以下の手順で対処する。

1.設定 > システム > Entity ID format で、フォーマットからできれば「エリア」を除外する(「デバイス」は削除できない仕様の場合が多い)

2.デバイス名を一時的に英語にリネーム(例: Studyroom Weather Station)

3.設定 > デバイスとサービス > デバイス → 該当デバイスを開く → 右上「⋮」→ 「エンティティIDを再作成する」

4.entity_idが英語のきれいな形(sensor.studyroom_weather_station_study_temperature等)になっていることを確認

5.表示を日本語に戻したい場合は、各エンティティの「名前」欄(entity_idではなく表示名)だけを日本語に変更する。デバイス名も日本語に戻して良い(entity_idは既に固定済みのため影響しない)

Advanced Mode(上級者モード)のトグルは2026.6で廃止されており、機能はデフォルトで誰でも使える状態になっている。


5. 遭遇したトラブルと対処まとめ

症状原因対処
board unknown警告ボード種別未指定esp32: に variant: esp32c3 を追加
日本語名エンティティが重複エラーentity_idスラグ化で非ASCII文字が消えるnameをASCII(英語)にする
bmp280 platform エラーESPHomeの仕様変更bmp280_i2c に変更
entity_idが中国語ピンイン風の長い文字列HAの既知バグ(kanji→pinyin誤変換)上記4章の手順で再作成
ダッシュボードで同じラベルが何度も表示デバイス名+エンティティ名が連結される仕様エンティティ名を短く(「Temperature」等)にする

※Claude により作成した。