Home Assistantで太陽光の余りだけEV充電|自宅充電自動化⑤

太陽光・EV充電

 

当ブログではアフィリエイト・Google AdSenseによる広告を掲載しています

昼は電気を買わずに、太陽光の余りだけでATTO 3を充電しています。

Home Assistantで家の買電・売電が見えるようになり、Wallboxも画面から操作できるようになったので、あとは電流を自動で上げ下げするだけです。

Home AssistantでWallboxの充電電流を操作|自宅充電自動化④
Wallbox Pulsar PlusをHome Assistantにつなぎ、充電電流や充電の開始・停止をスマホから操作できるようにしました。AIに作ってもらった操作パネルのYAMLも公開します。

設定のコードは全部AI(Claude Code)に作ってもらったもので、自分は中身を全然わかっていません。

実際に動いている昼の制御の設定ファイル(YAML)を載せて紹介します。

スポンサーリンク

Claude Codeに伝えたのは「余りだけで充電したい」

MacのClaude Codeに伝えたのは、この一言です。

「昼は太陽光の余りだけで充電したい。買電が出たら電流を下げて、余ったら上げてというオートメーションを作りたい。」

Home Assistantの画面も設定ファイルも、Claude Codeが直接触って作りました。

自分がやったのは、できあがったものを見てスクショをClaude Codeへ貼って要望を伝えて直してもらうことです。決め打ちだった数字を画面から変えられるようにしたり、スライダーを付けたりしてもらいました。

強制充電のモードも作ってもらっています。何度か直してもらった今は、なかなか完璧に制御できています。

昼の制御は3つのオートメーション

Home Assistantのオートメーション一覧。昼間充電制御にEV21・EV22・EV30、夜充電制御にEV20

昼の制御は、「昼間充電制御」にまとめた3つのオートメーションです。

  • EV21:太陽光の余りに合わせて電流を上げ下げする
  • EV22:買電が5分続いたら止める
  • EV30:16時で止めて翌朝を待つ

下のEV20は夜の制御です。

AIが全部作った、太陽光の余りだけでEV充電するYAML

ここからは設定ファイルの中身です。

先に書いておくと、ここから載せるコードは全部AIに作ってもらったものです。

自分は1行も書いていませんし、いま読んでも中身はよくわかりません。

説明もClaude Codeにしてもらった内容をそのまま書いています。Wallboxのシリアルナンバーだけは、「x」の並びに置き換えて伏せています。

YAMLは、「項目名: 値」を字下げして並べる設定の書き方だそうです。

制御の元になる買電・売電の数字(Power Import・Power Export)は、Nature Remo Eから50秒おきに取っている値です。取り方のYAMLとYAMLの読み方は、買電・売電を見える化した記事で紹介しています。

ラズパイのHome Assistantで買電・売電を見える化|自宅充電自動化③
ラズパイのHome Assistantで、Nature Remo Eから買電・売電を取り込んで見える化。AIに作ってもらったAPI設定のYAMLと、電気の流れのカードの設定を公開します。

余りに合わせて電流を上げ下げする(EV21)

昼の制御の本体がEV21です。やっていることはこの4つです。

  • 3分おきに電流を決め直す(売電が90秒続いたとき、買電が300Wを超えて60秒続いたとき、スライダーを動かしたときはその場で)
  • 使っていい電力は「今の充電電力+売電−買電+300W」
  • それを200Wで割った数を、合わせる電流にする(200Vなので1Aでおよそ200W)
  • 下は6A、上はAutoModeMaxの値までで、1A刻み

300W足してあるのは、少しの買電なら目をつぶるためです。充電は6Aより下げられないので、余りが少ないときは少しだけ買いながら充電を続けます。

名前は「6-26A」ですが、いまの上限はAutoModeMaxのスライダーで決まります。

- id: '1776476562430'
  alias: EV21 [昼間] PV連動 6-26A 1A刻み
  description: 発電余剰追従。300Wまでの買電は許容、6A未満で停止/余剰回復で自動再開
  triggers:
  - trigger: numeric_state
    entity_id: sensor.power_export
    above: 0
    for:
      seconds: 90
  - trigger: numeric_state
    entity_id: sensor.power_import
    above: 300
    for:
      seconds: 60
  - trigger: time_pattern
    minutes: /3
  - trigger: state
    entity_id: input_number.evzi_dong_zhi_yu_shang_xian_dian_liu
  conditions:
  - condition: template
    value_template: '{{ now().strftime(''%H:%M'') >= states(''input_select.day_charge_start'')
      and now().strftime(''%H:%M'') < states(''input_select.day_charge_end'') }}'
  - condition: state
    entity_id: input_boolean.ev_auto_control
    state: 'on'
  actions:
  - variables:
      cur: '{{ states(''sensor.wallbox_pulsar_plus_na_sn_xxxxxx_max_charging_current'')
        | int(6) }}'
      on_state: '{{ is_state(''switch.wallbox_pulsar_plus_na_sn_xxxxxx_pause_resume'',
        ''on'') }}'
      car_w: '{{ (states(''sensor.wallbox_pulsar_plus_na_sn_xxxxxx_charging_power'')
        | float(0)) * 1000 }}'
      exp: '{{ states(''sensor.power_export'') | float(0) }}'
      imp: '{{ states(''sensor.power_import'') | float(0) }}'
      headroom_w: '{{ (car_w + exp - imp + 300) if on_state else (exp - imp + 300)
        }}'
      cap: '{{ states(''input_number.evzi_dong_zhi_yu_shang_xian_dian_liu'') | int(26)
        }}'
      ideal_a: '{{ (headroom_w / 200) | int(0) }}'
      target: '{{ [6, [cap, ideal_a] | min] | max }}'
  - choose:
    - conditions:
      - condition: template
        value_template: '{{ on_state and ideal_a < 6 and cur > 6 }}'
      sequence:
      - action: number.set_value
        target:
          entity_id: number.wallbox_pulsar_plus_na_sn_xxxxxx_maximum_charging_current
        data:
          value: 6
    - conditions:
      - condition: template
        value_template: '{{ not on_state and ideal_a >= 6 }}'
      sequence:
      - action: number.set_value
        target:
          entity_id: number.wallbox_pulsar_plus_na_sn_xxxxxx_maximum_charging_current
        data:
          value: 6
      - delay:
          seconds: 2
      - action: switch.turn_on
        target:
          entity_id: switch.wallbox_pulsar_plus_na_sn_xxxxxx_pause_resume
    - conditions:
      - condition: template
        value_template: '{{ on_state and target != cur }}'
      sequence:
      - action: number.set_value
        target:
          entity_id: number.wallbox_pulsar_plus_na_sn_xxxxxx_maximum_charging_current
        data:
          value: '{{ target }}'
  mode: single

途中の input_number.evzi_dong_zhi_yu_shang_xian_dian_liu が、パネルのAutoModeMaxのスライダーです。

晴れた日の充電中は、売電がほとんど出なくなりました。アプリを開いて電流をいじることもなくなっています。

Nature Homeアプリで見た2026年5月16日の1日のグラフ。発電40kWh、ホーム50.7kWh、買電13.5kWh、売電2.7kWh、自家消費スコア73Pt

5月16日は、ATTO 3を昼に充電した日です。発電40kWhのうち37kWhほどを家で使って、売ったのは2.7kWhだけでした。

昼のあいだは、水色の家の消費がオレンジの発電にほぼ重なっています。充電の電流が発電に合わせて上下するので、発電の形をなぞるように動いています。

Nature Remo EをBルート接続|発電の9割を自家消費できた日
Nature Remo EのBルート接続で家じゅうの電力を1W単位で見える化。太陽光・エコキュート・全館空調を連携し、発電40kWhの9割を自家消費できた日の実測と、E2とE2 liteの違いをまとめました。

売るのと家で使うのとどちらが得かは、売電と買電の単価しだいで入れ替わります。以前書きました。

太陽光の自家消費より夜間電力が得?はぴeタイムRの実質単価を比較
関西電力はぴeタイムRで太陽光の自家消費と夜間電力を比較。燃料費調整・再エネ賦課金・政府補助金・電化割引をこみにした実質単価を2025年から月別にグラフ化。2026年夏は夜間が売電19円を下回り、夜に買うほうが得でした。

買電が5分続いたら止める(EV22)

EV21は6Aより下げません。そのままだと、曇った日は6Aのまま電気を買い続けることになります。

そこで、止める役をEV22に分けてあります。6Aまで下がっても買電300W超えが5分続いたら、充電を一時停止します。

雲が抜けて売電が900Wくらいまで戻ると、EV21が6Aで充電を再開させます。

Force Chargeがオンの日は、ここでは止めません。

- id: '1778282685514'
  alias: EV22 [07-17] 6Aで5分買電継続→停止
  description: 6Aまで落とした上で買電>300Wが5分続いたら一時停止
  triggers:
  - trigger: numeric_state
    entity_id: sensor.power_import
    above: 300
    for:
      minutes: 5
  conditions:
  - condition: time
    after: 07:00:00
    before: '17:00:00'
  - condition: state
    entity_id: switch.wallbox_pulsar_plus_na_sn_xxxxxx_pause_resume
    state: 'on'
  - condition: numeric_state
    entity_id: sensor.wallbox_pulsar_plus_na_sn_xxxxxx_max_charging_current
    below: 7
  - condition: state
    entity_id: input_boolean.ev_auto_control
    state: 'on'
  - condition: state
    entity_id: input_boolean.ev_no_pause
    state: 'off'
  actions:
  - action: switch.turn_off
    target:
      entity_id: switch.wallbox_pulsar_plus_na_sn_xxxxxx_pause_resume
  mode: single

16時で止めて翌朝を待つ(EV30)

昼の制御は7時から16時までです。16時になったら充電を止めて、電流を10Aにしておきます。

こちらもForce Chargeがオンなら止めません。確実に入れたい日は、16時を過ぎても充電が続きます。

- id: '1775481089170'
  alias: EV30 [昼間終了] OFF+10A待機
  description: 昼間モード終了時刻に充電停止、翌朝の太陽光待ち
  triggers:
  - trigger: template
    value_template: '{{ now().strftime(''%H:%M'') >= states(''input_select.day_charge_end'')
      }}'
  conditions:
  - condition: state
    entity_id: input_boolean.ev_auto_control
    state: 'on'
  - condition: state
    entity_id: input_boolean.ev_no_pause
    state: 'off'
  actions:
  - action: switch.turn_off
    target:
      entity_id: switch.wallbox_pulsar_plus_na_sn_xxxxxx_pause_resume
  - action: number.set_value
    target:
      entity_id: number.wallbox_pulsar_plus_na_sn_xxxxxx_maximum_charging_current
    data:
      value: 10
  mode: single

終わりの16時はヘルパー(input_select.day_charge_end)に入れてあるので、YAMLを書き換えなくても変えられます。

まとめ

載せたコードは全部AIが作ったもので、自分はいまもClaude Codeの説明を読みながら追いかけている状態です。

伝えたのは「昼は太陽光の余りだけで充電したい」という一言と、できあがったものを見て「ここを変えられるようにして」と頼んだことだけです。

夜に契約容量を超えないように絞る制御も動いているので、まとまったらまた記事にしようと思います。

タイトルとURLをコピーしました