Sympapaのスマートホーム日記

スマートなんとかはスマートじゃない方法でつくられている

Home Assistant: ESP Home+ESP32でPCの電源ON/OFFをIoT化する(1)

Sympapaです。

今までデスクトップPCの電源のIoT化はSwitchbotボットに担当して貰っていました。物理的にスイッチなどを押してくれるアレです。
Switchbotボットを使ってIoT化するのはステータスも判らないし個人的には全くスマートだと思えませんが、他の手段ではどうにもならない時に最後の砦的な存在ではあります。それに動きがシュールでいいんですよね(笑)


しかし物理的にちょっと邪魔であるのと、Bluetoothを介したHome Assistantからの操作が安定しない(SwitchbotアプリやSwitchbotハブ経由では問題ない)のと、そもそもPCのスイッチ周りは仕組みが単純なのでSwitchbotボットじゃなくても制御できるよねって思ってたりしました。
PCなのでそもそもWake on LANを使えばいいんじゃないかという話もあるかと思いますが、私のデスクトップPCはどう設定してもWi-Fi接続ではWake on LANによる起動が出来ないんです。


そんなワケで、PCの電源ボタン担当をSwitchbotボットからESP32に変えてしまおうというのが今回のお話です。

■構想

PCケースの電源スイッチはマザーボードにある2つのピンに繋がっていて、この2つのピンを短絡させるとマザーボードが電源をオンにしてくれるという仕組みです。なのでマザーボードには電源OFFの時にもスタンバイ用の電源が供給されており、その電圧は5Vで電源ボタンのピンの電圧も5Vだそうです。
デフォルトでは普通に押すとON or スリープ、ONの時に長押しするとシャットダウンという風になっていると思いますが、動作はOS側の設定によります。
ESP Home + ESP32を使ってこのピンの短絡を制御し、Home AssistantからPCをオンオフできるようにします。


また、PCの電源はトグルスイッチなので、PCの電源状態も取得しそれをチェックした上で電源のトグルスイッチを操作させるのかを判断する処理が必要です。なので合わせて電源状態取得も出来るようにします。

■回路を考える

基本的には以前考えたHA端子(JEM-A端子)を制御する回路の抵抗だけ変えればいけるんじゃないかと思います。
なので今回もフォトカプラはTLP785を使います。
sympapa.hatenablog.com


電源スイッチの方はPCケースのスイッチと並列に入力を割り込ませればいいでしょう。
PC側の電源ボタンの2ピン間の電圧は5Vのようです。
とりあえずフォトカプラを壊さないように、フォトカプラの推奨コレクタ電流が1~10mAを超えない抵抗からスタートして様子を見ることにします。
5V/10mA=500Ωにします。


電源ON/OFFの状態はどこから取得しようかな?
ひとつ目の候補は電源ランプのLEDから、ふたつめの候補は内部USBコネクタから。
電源ランプのLEDに割り込ませるとLEDが暗くなるかもしれないし、USB2.0の内部コネクタは空きがありません。
しかしマザーボードの取説をまじまじと眺めていたら電源LEDの端子が2系統あることが判明したので、ここから取ることにします。
しかし、後でPCの電源LEDはスリープ時に点滅することに気づき、ここから取ることにしたことを後悔しました(笑)


TLP785の推奨順電流は標準:16mA 最大:25mAってことですが、10mAで全く問題なく動作するので10mAで計算します。
RIN = (VCC-VF)/IF = (5V-1.3V)/10mA = 370 Ω
※電源LED出力の電圧を5Vで計算しましたが実測は3Vでした。まぁ動いたのでこのままにしてますが。


ESP32側は制御側が300Ω、モニタ側が1000Ωとしています。
まとめたのが下図。

■ESP Homeの設定

Home AssistantからESP32を制御するのにはESP Homeアドオンを使います。
esphome.io


ESP Homeの設定は以下の.yamlのとおりです。
遠隔操作を考えるとPCがONの状態からいきなりシャットダウン落としたくはないので、常にスリープモードに入るようPCの電源スイッチ端子を短絡させるためのスイッチは300msのモメンタリスイッチに設定します。
今のところ300msで確実にスリープ、スリープからの復帰が出来ています。


電源状態の取得側の方ですが、PC電源のLED端子から取ることにしたのでPCの電源がONの場合は常時ONとなりますが、スリープ中は間欠でON/OFFを繰り返す(LEDが点滅するので)ことになってしまい、ダイレクトに電源がONかOFFかのステータスを取得することが出来ません。
ここの処理は後でやりたいと思います。

switch:
  - platform: gpio
    pin: 32
    id: pc_switch_esp32
    name: "PC_switch_ESP32"
    icon: "mdi:gate"
    on_turn_on:
    - delay: 300ms
    - switch.turn_off: pc_switch_esp32

binary_sensor:
  - platform: gpio
    pin:
      number: 33
      mode: INPUT_PULLUP
      inverted: true
    name: 'PC_power_status_esp32'

■Home Assistantの設定

Home Assistant上でPC用のスイッチを作ります。
Google Homeからも操作したいので、このスイッチをGoogle Homeと同期させます。

configuration.yaml

input_boolean:
  pc_power:
    name: pc_power
switch:
  - platform: template
    switches:
      pc_power:
        value_template: "{{ states('input_boolean.pc_power') }}"
        turn_on:
          - service: input_boolean.turn_on
            entity_id: input_boolean.pc_power
          - service: script.pc_power_on
        turn_off:
          - service: input_boolean.turn_off
            entity_id: input_boolean.pc_power
          - service: script.pc_power_off


次に上で作ったHome Assistant上のスイッチがON/OFFされたら、実際のPCの電源ステータスをチェックしPCの電源スイッチ端子を短絡させるスイッチをONにするスクリプトを作ります。
電源状態をPC電源のLED端子から取得することにしたので、PCがスリープ中はbinary_sensor.pc_power_status_esp32がON/OFFを繰り返すため、これが連続で4秒以上ONになっていない場合はPCの電源がOFF又はスリープであると判定するようにしました。
そして、Home Assistant上のスイッチがONになった時に既にPCの電源がONであった場合はPCの電源スイッチ端子を短絡させず、Home Assistant上のスイッチがOFFになった時に既にPCの電源がスリープ又はOFFであった場合もPCの電源スイッチ端子を短絡させないようにしています。

alias: PC_power_on
sequence:
  - condition: not
    conditions:
      - condition: state
        entity_id: binary_sensor.pc_power_status_esp32
        state: 'on'
        for:
          hours: 0
          minutes: 0
          seconds: 4
  - service: switch.turn_on
    data: {}
    target:
      entity_id: switch.pc_switch_esp32
  - service: automation.turn_on
    data: {}
    target:
      entity_id: automation.pc_power_off
mode: single
alias: PC_power_off
sequence:
  - condition: state
    entity_id: binary_sensor.pc_power_status_esp32
    state: 'on'
    for:
      hours: 0
      minutes: 0
      seconds: 4
  - service: switch.turn_on
    data: {}
    target:
      entity_id: switch.pc_switch_esp32
  - service: automation.turn_off
    data:
      stop_actions: false
    target:
      entity_id: automation.pc_power_off
  - wait_for_trigger:
      - platform: state
        entity_id:
          - binary_sensor.pc_power_status_esp32
        from: 'on'
        to: 'off'
    timeout: '20'
mode: single


次にPCの物理スイッチやPC上の操作で電源を操作した場合にHome Assistant上のスイッチをON/OFFするオートメーションを作ります。
ONにするオートメーションのトリガーは「binary_sensor.pc_power_status_esp32が4秒以上連続でONになった時」としています。
問題はOFFにするオートメーションで、PCの電源がスリープの場合はbinary_sensor.pc_power_status_esp32がON/OFFを繰り返すので、これがOFFになったことをトリガーにすると処理が頻繁に発動してしまいます。
ちょっと悩みましたが、電源OFFの処理をひととり終えたらこのオートメーションを無効化し、PCの電源がオンになったら無効化したオートメーションを有効化する処理を上のスクリプトに加えることで対処しました。
(しかしこの処理をしてもスリープ中はESP32からHome Assistantへ絶えずステータスの変化が送信されWi-Fiへの負荷がかかりそうなので、次回見直しします。)

alias: PC_power_on
description: ''
trigger:
  - platform: state
    entity_id:
      - binary_sensor.pc_power_status_esp32
    from: 'off'
    to: 'on'
    for:
      hours: 0
      minutes: 0
      seconds: 4
condition:
  - condition: state
    entity_id: input_boolean.pc_power
    state: 'off'
action:
  - service: switch.turn_on
    data: {}
    target:
      entity_id: switch.pc_power
mode: single
alias: PC_power_off
description: ''
trigger:
  - platform: state
    entity_id:
      - binary_sensor.pc_power_status_esp32
    from: 'on'
    to: 'off'
    for:
      hours: 0
      minutes: 0
      seconds: 0
condition:
  - condition: state
    entity_id: input_boolean.pc_power
    state: 'on'
  - condition: not
    conditions:
      - condition: state
        entity_id: binary_sensor.pc_power_status_esp32
        state: 'on'
        for:
          hours: 0
          minutes: 0
          seconds: 4
action:
  - service: switch.turn_off
    data: {}
    target:
      entity_id: switch.pc_power
mode: single

■テストする

とりあえずテストなのでブレッドボード上で回路を作製しました。
OK Google!PCをつけて」で起動、「OK Google!PCを消して」でスリープに出来るし、Home Assistant上のスイッチでもPCのスイッチでも操作出来ます。

■まとめ

これでPCの電源をHome AssistantやGoogle Homeからオンオフできるようになりました。
次は回路部品をユニバーサル基板にハンダ付けして完成させたいと思います。
PCのケースにESP32を入れてしまうとWi-Fi接続に支障はないやろか?
ESP32の電源はどこから取ろうかな?


それでは。つづく