はじめに
秋月電子の謎SOC基板を使って、家の電力計の値を取得してHome Assistantで可視化しようの続きです。Home Assistantに電力量を蓄積できましたので、いつでも電力量を見られるように、常時表示する電力量専用の液晶画面を作りました。
ESPHomeを使おう
ESPHomeは、この記事を閲覧されている方にお馴染みの超お手軽SoCESP-WROOM-32 (以下ESP32)を使って、Home Assistantに接続する機器を自作できるアドオンです。
ESPHomeは、Home Assistantのアドオンとして組み込まれるため、設定からESP32への書き込みまですべてHome Assistant上で行えます。そして液晶に表示するためのコードは、Arduino的な専用スクリプトで処理部分のみ追記すればいいので、超簡単です。
表示デバイスを用意する
デバイスとして、ESP32-WROOM-32E 開発ボードと、ILI9341搭載TFT液晶ボード (以下ILI9341)を利用しました。(実際には、同型のタッチパネルなしモデルを使用しています。実際にどのような液晶が使えるかは、ESPHomeのサイトで確認できます)。以下図のように接続しています。(ESP32とILI9341の接続は、最後に載せたyamlスクリプトもご確認ください)
| 液晶ピン番号 | 液晶信号名 | ESP32開発ボードピン番号 | ESP32信号名 | 
|---|---|---|---|
| 1 | VCC(3.3V) | 2 | 3V3 | 
| 2 | GND | 38 | GND | 
| 3 | CS | 29 | GPIO5 | 
| 4 | RESET | 28 | GPIO17 | 
| 5 | DC/RS | 27 | GPIO16 | 
| 6 | SDI(MOSI) | 37 | GPIO23 | 
| 7 | SCK | 30 | GPIO18 | 
| 8 | LED | 8 | GPIO32 | 
| 9 | SDO(MISO) | 31 | GPIO19 | 
あと細かいことですが、ESP32はWIFI4(2.4GHz帯)を使用しますので、接続可能なWIFI環境を用意しておきます。
ESPHomeアドオンをHome Assistantにインストールする
Home Assistantのweb画面から、「設定」⇒「アドオン」⇒「アドオンストア」で、「ESPHome」を選ぶだけです。インストール完了すると、画面左のメニューに「ESPHome」が追加されます。
ESP32をデバイスとして追加する
- まずはESP32-WROOM-32E 開発ボードを、Home Assistantが稼働しているサーバーに、USBケーブルで接続します。
- Home Assistantの画面左のメニュー「ESPHome」を開き、「NEW DEVICE」をクリックします。説明内容を確認し、「CONTINUE」をクリックします。
- デバイスの名前を入力します(例えばESP-echonetviewのように、既存の機器と重ならないような名前を付けます)。「Configuration created!」の画面が表示されるので、「INSTALL」をクリックします。
- 「How do you want to install ... on your device?」が表示されます。「Plug into this computer running ESPHome Dashboard」を選び、Pick Server Portで、USBケーブルでつないだESP32-WROOM-32E 開発ボードのデバイス名を選択します。(例えば「CP2102 USB to UART Briged Controller」(/dev/ttyUSB0)など、USB経由のシリアル(UART)接続デバイスを選びます)
- 後は、ESPHomeが自動で環境をビルドして、USBケーブル経由でESP32にファームウェアを書き込みます。環境によりますが、最初は5~10分程度かかります。
- 無事完了すれば、ESPHomeの画面に、デバイスが追加されます。
- 上記の作業を完了すれば、サーバとESP32間は無線LANで通信を行いますので、サーバーにUSBケーブルを接続しなくても単体で動作します。
デバイスの設定yamlファイルを作成する
- 文字表示のために、TTFフォントが必要です。Home Assistantサーバの homeassistant/esphome/ にTTFファイルをコピーしておきます。(今回はVeraMono.ttfを使用しています。ESP32はそれほど多くのメモリを積んでいないので、小さな(100KB未満くらい)のTTFファイルを探して入れましょう)
- 上記で作成したデバイスの「EDIT」をクリックして、以下を追記します(既存の記載をそのまま残して追記しましょう)。(細かい部分は環境に合わせてテキトウに修正してください)追記したら、「INSTALL」でESP32を更新します。
- グラフは「graph:」エントリ、画面の位置情報、グラフの凡例などの文字列は「display:」エントリで設定しています。自分の好みに合わせて変更してみてください。
- グラフやパーセンテージ表示は、上限30Aで決め打ちしています。変更したい場合は、「display:」「graph:」エントリあたりを変更してみてください。
esp32:
  board: esp32dev
  framework:
    type: arduino
# SPI configuration
spi:
    clk_pin: GPIO18
    mosi_pin: GPIO23
    miso_pin: GPIO19
    interface: hardware
# Home Assistant Sensor
sensor:
  - platform: homeassistant
    id: ha_measured_power
    name: "Echonet Measured Power"
    entity_id: sensor.echonet_measured_power
  - platform: homeassistant
    id: ha_integrated_power
    name: "Echonet Integrated Power"
    entity_id: sensor.echonet_integrated_power
time:
  - platform: homeassistant
    id: esptime
# Define a PWM output on the ESP32
output:
  - platform: ledc
    pin: GPIO32
    id: gpio_32_backlight_pwm
# Define a monochromatic, dimmable light for the backlight
light:
  - platform: monochromatic
    output: gpio_32_backlight_pwm
    name: "Display Backlight"
    id: back_light
    restore_mode: ALWAYS_ON
font:
  - file: 'VeraMono.ttf'
    id: mono10
    size: 10
  - file: 'VeraMono.ttf'
    id: mono16
    size: 16
  - file: 'VeraMono.ttf'
    id: font_pwr
    size: 56
  - file: 'VeraMono.ttf'
    id: font_per
    size: 52
color:
  - id: graph_line
    red: 25%
    green: 100%
    blue: 50%
  - id: title_blue
    red: 25%
    green: 50%
    blue: 100%
graph:
  # Show bare-minimum auto-ranged graph
  - id: measured_power_graph
    duration: 2h
    width: 280
    height: 120
    max_value: 3000
    min_value: 0
    x_grid: 30min
    y_grid: 500
    traces:
    - sensor: ha_measured_power
      line_type: SOLID
      line_thickness: 2
      continuous: true
      color: graph_line
display:
  - platform: ili9xxx
    model: ILI9341
    cs_pin: GPIO5
    dc_pin: GPIO16
    reset_pin: GPIO17
    auto_clear_enabled: True 
    rotation: 270
    update_interval: 10s
    lambda: |-
      it.fill(COLOR_OFF);
      auto back_blue = Color(16, 16, 96);
      it.filled_rectangle (0,  0,320,20 ,back_blue);
      it.filled_rectangle (0,224,320,240,back_blue);
      it.strftime(319, 0, id(mono16), TextAlign::TOP_RIGHT, "%y-%m-%d %H:%M", id(esptime).now());
      it.print (  4,   0, id(mono16), id(title_blue), TextAlign::TOP_LEFT, "Measured POWER");
      it.printf( 87,  76, id(font_pwr), TextAlign::BASELINE_CENTER, "%.0fW", id(ha_measured_power).state);
      it.printf(259,  76, id(font_per), TextAlign::BASELINE_CENTER, "%.0f%%", id(ha_measured_power).state/30 );
      it.printf(159, 240, id(mono16), TextAlign::BASELINE_CENTER, "TOTAL:%.1f KW", id(ha_integrated_power).state);
      
      it.graph (30  , 94, id(measured_power_graph));
      it.print (26  , 98, id(mono10), TextAlign::BASELINE_RIGHT , "3000");
      it.print (26  ,138, id(mono10), TextAlign::BASELINE_RIGHT , "2000");
      it.print (26  ,178, id(mono10), TextAlign::BASELINE_RIGHT , "1000");
      it.print (26  ,218, id(mono10), TextAlign::BASELINE_RIGHT , "0");
      it.print (92  ,224, id(mono10), TextAlign::BASELINE_CENTER, "-1:30");
      it.print (162 ,224, id(mono10), TextAlign::BASELINE_CENTER, "-1:00");
      it.print (232 ,224, id(mono10), TextAlign::BASELINE_CENTER, "-0:30");
      it.print (302 ,224, id(mono10), TextAlign::BASELINE_CENTER, "-0:00");

