2025年12月22日で太陽光発電 通知メールがなくなる件。 代替として自前で収集した情報をLINEに通知してみた

いよいよ「太陽光発電、 通知メールがなくなる」。さてどうしようか、2025/12/07時点で、一番下に添付したメールが朝9:00ころに届いている。これを、代替できるLINE通知する仕組みを作ってみました。 12/14に取得した結果は次の通り、ほぼ同じ結果で十分な結果と言えるでしょう。

自作したLINEでの表示例 と【フロンティアモニター】のレポート
下記の通り、2025年12月13日の発電量をお知らせいたします。

発電量:7.52kWh
下記の通り、2025年12月13日の電力量をお知らせいたします。

発電量:7.52kWh
売電量:0.28kWh
買電量:53.99kWh
今月の目標売電量(223kWh)に対して、28%達成しました。
今月の目標消費電力量(1,106kWh)に対して、641kWh消費しました。
下記の通り、2025年12月07日-2025年12月13日の電力量をお知らせいたします。

発電量:96.83kWh
売電量:31.50kWh
買電量:281.26kWh
今月の目標売電量(223kWh)に対して、28%達成しました。
今月の目標消費電力量(1,106kWh)に対して、641kWh消費しました。


実装方針

・従来の通知メールに含まれる発電量等の計測値データはすべて含める
・通知メールの種類はいくつかあるが、元データは1つなので、引数で送信メッセージの内容を切り替える
・CRONで起動指定する

この方針で、ここまでで作成した実装をベースに集計+メッセージ送信するスクリプトを作成します。まずは、iPython上で動作確認して、hsBox上に移植しました。
以下のスクリプトを /home/hsbox/pyd/power_report.py に配置し、後述の設定を行いました。

スクリプト実装(例)

# power_report.py
import pandas as pd
from datetime import datetime, timedelta
import os
import sys
import argparse
import requests

# ==================== 設定エリア ====================
NAS_PATH = r"/mnt/nas<★NASマウント+パス>" #★
IFTTT_WEBHOOK_URL0 = "https://maker.ifttt.com/trigger/{event}/with/key/{your_key}"
IFTTT_EVENT_NAME = "******" # IFTTTで作ったイベント名★
your_key="********" # ←ここを自分のものに変更★
IFTTT_WEBHOOK_URL = IFTTT_WEBHOOK_URL0.replace("{your_key}", your_key)
# ====================================================


def send_line_message(title: str, body: str, timestamp: str):
payload = {
"value1": title,
"value2": body,
"value3": timestamp
}
url = IFTTT_WEBHOOK_URL.replace("{event}", IFTTT_EVENT_NAME)
try:
response = requests.post(url, headers={"Content-Type": "application/json"}, json=payload, timeout=10)
if response.status_code == 200:
print("LINE通知成功")
else:
print(f"エラー: {response.status_code}")
except Exception as e:
print(f"LINE通知失敗: {e}")

def load_day_data(target_date: datetime) -> pd.DataFrame:
date_str = target_date.strftime("%Y%m%d")
file_path = fr"{NAS_PATH}/power_{date_str}.parquet"
if not os.path.exists(file_path):
raise FileNotFoundError(f"データが見つかりません: {file_path}")
return pd.read_parquet(file_path)

def calc_daily_summary(df: pd.DataFrame, date_label: str):
# 数値化
df["value1"] = pd.to_numeric(df["value1"], errors="coerce") # 発電 kW
df["value2"] = pd.to_numeric(df["value2"], errors="coerce") # 買電 kW
df["value3"] = pd.to_numeric(df["value3"], errors="coerce") # 売電 kW
df["value4"] = pd.to_numeric(df["value4"], errors="coerce") / 6 # 消費 kWh(既に1時間積算値)

# 10分間隔と仮定して正確にkWh計算
interval_min = 10
hours_per_record = interval_min / 60.0

total_gen_kwh = df["value1"].mean() * len(df) * hours_per_record
total_buy_kwh = df["value2"].mean() * len(df) * hours_per_record
total_sell_kwh = df["value3"].mean() * len(df) * hours_per_record
total_use_kwh = total_buy_kwh + total_gen_kwh - total_sell_kwh # 電力収支で算出(最も正確)

return {
"date": date_label,
"gen": round(total_gen_kwh, 2),
"buy": round(total_buy_kwh, 2),
"sell": round(total_sell_kwh, 2),
"use": round(total_use_kwh, 2)
}

def calc_week_summary(days=7, da=-8 ):
"""過去days日分の集計(今日を除く昨日まで)"""
base_day = datetime.now().date()
results = []
for i in range(1+8+da, days + 1+8+da):
target_date = base_day - timedelta(days=i)
try:
df = load_day_data(target_date)
date_label = target_date.strftime("%m/%d")
summary = calc_daily_summary(df, date_label)
results.append(summary)
except Exception as e:
print(f"{target_date} のデータ読み込み失敗: {e}")

if not results:
return None

total_gen = sum(r["gen"] for r in results)
total_buy = sum(r["buy"] for r in results)
total_sell = sum(r["sell"] for r in results)
total_use = sum(r["use"] for r in results)

lines = [f"【過去{days}日間実績】"]
for r in reversed(results): # 古い順→新しい順
lines.append(f"{r['date']}: 発電{r['gen']} kWh")
lines.append("")
lines.append(f"合計発電量: {total_gen:.1f} kWh")
lines.append(f"合計買電量: {total_buy:.1f} kWh")
lines.append(f"合計売電量: {total_sell:.1f} kWh")
lines.append(f"合計消費量: {total_use:.1f} kWh")

return "\n".join(lines)

def main():
parser = argparse.ArgumentParser(description="電力データ集計&LINE通知")
parser.add_argument("--da", type=int, default=0, help="日付加算。-1=昨日, 0=今日, 1=明日…")
parser.add_argument("--ptn", type=str, default="f", choices=["p", "f", "w"],
help="p=発電量のみ, f=全項目, w=週間集計")
args = parser.parse_args()

# --- 対象日の決定 ---
base_date = datetime.now()
if args.da != 0:
base_date += timedelta(days=args.da)

# 今日の場合、現在時刻までのデータのみ読み込む(ファイルは当日分全部ある前提)
target_date = base_date.date()
date_label = base_date.strftime("%Y/%m/%d")

if args.ptn == "w":
message = calc_week_summary(7,args.da)
if message:
send_line_message("太陽光発電1週間データ",message,"-")
message=f"{message}\n"
else:
send_line_message("太陽光発電","週間集計データが取得できませんでした","-")
message="週間集計データが取得できませんでした"
print(message)
return
else:
try:
df = load_day_data(base_date)
except Exception as e:
send_line_message("太陽光発電",f"⚠️ {date_label} のデータがありません\n{e}","-")
message = f"⚠️ {date_label} のデータがありません\n{e}"
print(message)
return

summary = calc_daily_summary(df, date_label)

# --- メッセージ作成 ---
if args.ptn == "p":
message = f"☀️ {base_date.date()} 発電量\n{summary['gen']} kWh"
else: # f
message = f"⚡️ {base_date.date()} 電力実績\n" \
f"発電量 :{summary['gen']} kWh\n" \
f"買電量 :{summary['buy']} kWh\n" \
f"売電量 :{summary['sell']} kWh\n" \
f"消費電力量:{summary['use']} kWh"

send_line_message("太陽光発電データ",message,"-OK-")
print(message)

import sys
if "ipykernel_launcher.py" in sys.argv[0]:
# ここに実行したい引数を書く(好きな組み合わせでOK)
sys.argv = ["power_report.py"] # ← ptnなし → f 扱い(今日分フル)
#sys.argv = ["power_report.py", "--da", "-1"] # 昨日分フル
#sys.argv = ["power_report.py", "--ptn", "p"] # 今日の発電量だけ
# sys.argv = ["power_report.py", "--ptn", "w"] # 週間集計

if __name__ == "__main__":
main()
使用方法・CRON設定方法(CRON起動設定 例)
30 19 * * * /usr/bin/python3 /home/hsbox/pyd/power_report.py --da 0 --ptn p
19:30に当日の発電量を通知

0 9 * * * /usr/bin/python3 /home/hsbox/pyd/power_report.py --da -1 --ptn f
AM9:00に前日の発電量・売電量・買電量・消費電力を通知

1 9 * * 7 /usr/bin/python3 /home/hsbox/pyd/power_report.py --da -8 --ptn w
日曜日 AM9:00に前日までの7日間の発電量・売電量・買電量・消費電力を通知

IFTTTの設定

IFTTTでの設定は、随時更新されるため参考程度で見てください。詳細はWebhooksやLINEの項目を確認してください。 ※これは、2025/12/10時点の情報です。

Webhooksの「Your key」の確認方法

1. IFTTT にログイン

https://ifttt.com
にアクセスし、ログインします。

2. Webhooks サービスページへ移動

以下の公式ページを開く
👉 https://ifttt.com/maker_webhooks

3. 右上の「Settings」をクリック

画面右上に Settingsという青いボタンがあります。

4. “Webhooks Settings” の欄を確認

開いたページに以下のような記載があります:

URL
https://maker.ifttt.com/use/**********


この key(*******の部分) が個人専用の Webhooks Key です。
このkeyをスクリプト(power_report.py)のyour_keyに設定してください
IFTTTの Applet 作成例

Appletの名称は自分にわかりやすいように任意に設定してください。

イベント(THEN)に「Receive a web request」を選択し、Event Nameを設定します。このEvent Nameをスクリプト(power_report.py)内のIFTTT_EVENT_NAMEに設定します。

THAT(実行内容)に LINEの「Send message to self」を選択し、自分のLINE accountを設定します。 Messageは、上のように設定すれば、設定完了です。

この設定は、自分あてのメッセージ送信なので、このスクリプトに限らず、他のメッセージ送信にも応用できます。

以下、2025/12/07に届いた通2知メール
件名:【フロンティアモニター】 12月06日 電力量レポート


内容:
**** 様

日頃より【フロンティアモニター】ホームエネルギーモニタリングサービスをご利用いただき、誠にありがとうございます。

【システム終了のお知らせ】
2025年12月22日(月)をもって本計測装置のサービスを終了いたします。
なお、システムの都合により、一部サービス終了のタイミングについては前後する可能性がございますので、ご承知おきください。
詳しくはお客様ご利用サイトのお知らせ欄をご覧ください。

本メール発信は、メールシステムメンテナンスにより、1日遅延する場合があります。メンテナンスの日程は、お客様ログイン画面の「お知らせ」欄に随時記載いたします。
メンテナンス時はご不便をおかけしますが、何卒ご承知おきくださいますようお願いいたします。

下記の通り、2025年12月06日の電力量をお知らせいたします。

発電量:19.98kWh
売電量:9.56kWh
買電量:37.58kWh

今月の目標売電量(223kWh)に対して、14%達成しました。
今月の目標消費電力量(1,106kWh)に対して、293kWh消費しました。

省エネ目標が01月01日から変更されておりません。

発電・消費電力量は季節ごとにかわりますので、目標も毎月更新されることをおすすめします。

日没後に送られてくる当日分発電量
**** 様

日頃より【フロンティアモニター】ホームエネルギーモニタリングサービスをご利用いただき、誠にありがとうございます。

【システム終了のお知らせ】
2025年12月22日(月)をもって本計測装置のサービスを終了いたします。
なお、システムの都合により、一部サービス終了のタイミングについては前後する可能性がございますので、ご承知おきください。
詳しくはお客様ご利用サイトのお知らせ欄をご覧ください。

本メール発信は、メールシステムメンテナンスにより、1日遅延する場合があります。メンテナンスの日程は、お客様ログイン画面の「お知らせ」欄に随時記載いたします。
メンテナンス時はご不便をおかけしますが、何卒ご承知おきくださいますようお願いいたします。

下記の通り、2025年12月06日の発電量をお知らせいたします。

発電量:19.98kWh















今後ともフロンティアモニターをよろしくお願いいたします。
★なお、お心当たりのない方は、お手数ではございますが、下記メールアドレスまでご連絡頂きますようお願いいたします。
★このメールは送信専用メールアドレスから配信しています。このまま返信いただいてもお答えできませんのでご了承ください。
-----------------------------------------------
ソーラーフロンティア株式会社
【フロンティアモニター】お客様サービスセンター
電話:0570-053115(受付時間:9:00-17:00)※日曜、祝祭日、メーデー、年末年始を除く
メール:information@solar-frontier.com
-----------------------------------------------

上の内容のうち、太字部分に相当する情報を、LINEで通知するようにしてみました。
参考にしてみてください。

関連記事

ソーラーフロンティア太陽光発電・発電量独自集積データ解析をiPythonで書いてみた

モニタリングを視覚化と、異常検知するアプローチを進めていきましょう。 まずは、自動化に向けて太陽光発電・発電量独自集積データ解析をiPythonで書いてみます。

先の記事までにデータ収集に成功し、ソーラーフロンティア太陽光発電のモニタリングサービスで収集した結果とデータ比較しほとんど一致していることを確認できています。ここからは、モニタリングを視覚化と、異常検知するアプローチを進めていきましょう。 まずは、自動化に向けて太陽光発電・発電量独自集積データ解析をiPythonで書いてみます。 → LINE通知はこちら

システム構成
fmget
ソーラフロンティアモニタ代替

ここからは、前にNASに保存した形式のデータを扱う前提で書いていきます。

元のデータは、10分毎の瞬間値データでした。1時間ごとに平均してkWhに変換すると、ソーラーフロンティアモニタリングサービスに蓄積されたデータとほとんど同じデータになります。※取得した瞬間値の取得タイミングが異なるので、雲がまばらにあるような瞬間値の変動が激しい天候の場合はずれが大きくなるでしょう。
 1日分の発電量を集計・グラフ化するipythonコードは次の通りです。

import pandas as pd
import matplotlib.pyplot as plt
import japanize_matplotlib
from datetime import datetime

dt1 = "2025/12/02" #★参照したい日付 を指定
nas_path = r"<NASのパス名>" #★NASのパス 環境に合わせて指定


date_obj = datetime.strptime(dt1, "%Y/%m/%d")
date_with_slash = date_obj.strftime("%Y/%m/%d")
date_str = date_obj.strftime("%Y%m%d")

# --- ① parquet 読み込み(あなたのコード) ---
# ファイルパスを組み立て
file_path = fr"{nas_path}\power_{date_str}.parquet"
df = pd.read_parquet(file_path)
ttl=f"発電量推移 {date_with_slash}"

# --- ② Value1 を数値化(エラーを NaN に) ---
df["value1"] = pd.to_numeric(df["value1"], errors="coerce")

# --- ③ timestamp を datetime に変換 ---
df["timestamp"] = pd.to_datetime(df["timestamp"])

# --- ④ 時刻(Hour)を抽出 ---
df["hour"] = df["timestamp"].dt.hour

# --- ⑤ 1時間ごとの平均値を計算 ---
hourly_mean = df.groupby("hour")["value1"].mean()

# --- ⑥ 結果表示 ---
print(hourly_mean)
total_sum = df["value1"].sum()/6
print(total_sum)

# timestamp を x 軸として、そのままプロット
plt.figure(figsize=(14,4))
plt.plot(hourly_mean, linewidth=1)
plt.title(ttl)
plt.grid(True)
plt.tight_layout()
plt.show()

★印の箇所は、任意に変更してください。NASのパスは iPythonが動作しているマシン上から見た、データ保存のパスです。
\\192.168.1.50\share など

表示結果例

SolarPower

つぎは、月単位、年単位の集計値を出すコード書いてみましょう。それから、hsBoxで、スマートディスプレイやGoogleTVに表示させる仕組みに着手です。

関連記事

hsbox1.3で屋内のソーラーフロンティアホームサーバから直接発電量データ取得、データ検証編 まず2日分データで検証

hsbox でのソーラーフロンティアホームサーバーからのデータ収集の続きをしましょう。ホームサーバから直接取得する方法で、ホームエネルギーモニタリングサービス とほぼ一致するデータが取れたことを確認できました。


今回は、情報採取した2日分のデータと、「フロンティアモニター – ホームエネルギーモニタリングサービス -」のデータがどの程度一致しているか検証してみます。

取得データ比較結果

12/1と12/2の発電量の比較デーは以下の通りです。10分間隔で取得して1時間ごとに平均化しています。ほぼ同じ取得方法ですが、取得タイミングが微妙に違うので少しずれます。それでも、1日の発電量の一致度は、12/1は98.4%、 12/2は100.5%でした。十分満足できる結果でした。昨日公開した実装方法で発電量などのデータを取得できることを確認できました。

先のValue1が発電量のデータです。さらに2週間ほど並行してソーラーフロンティアに上がっているデータと一致しているか、詳細確認をしてみます。

検証環境

今回、データ取得に使用した環境は次の通りです。
フロンティアモニターホームサーバー
カーネルVer. 3.22
システムVer. 3.22
AD変換ボードVer. 2.00

hsBox
Version: 1.03.01.01, Build: 324

fmget
ソーラフロンティアモニタ代替

関連記事

https://www.frontier-monitor.com/persite/top

hsbox1.3で、ソーラーフロンティアホームサーバから発電量データ取得 遂に成功!? (fm_dataget.py)

hsbox でのソーラーフロンティアホームサーバーからのデータ収集の続きをしましょう。PROXY方式は諦めて、ホームサーバから直接取得する方法で再検討です。
結論から言うと、どうもうまくいっていそうです。最初に構成図です、前に描いた図と同じですが、ホームサーバから受け取るのではなく、ホームサーバに取りに行くイメージです。

検証環境

今回、データ取得に使用した環境は次の通りです。
フロンティアモニターホームサーバー
カーネルVer. 3.22
システムVer. 3.22
AD変換ボードVer. 2.00

hsBox
Version: 1.03.01.01, Build: 324

データ取得実装例(/home/hsbox/pyd/fm_dataget.py)

フロンティアモニターホームサーバーのバージョンによってデータ取得方法に違いがあります。参考にしてみてください

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import pandas as pd
import os
import json
import logging
from datetime import datetime
from pathlib import Path
import platform

# ===== 設定 =====
URL = "http://<★フロンティアモニターホームサーバーIP>/getEpData.cgi"
if platform.system() == "Windows":
NAS_DIR = Path(r"\\<★NAS IP>\share\PowerData")
else:
NAS_DIR = Path("/mnt/nas/PowerData") ★

NAS_DIR.mkdir(parents=True, exist_ok=True)

# ===== ログ設定 =====
today = datetime.now().strftime("%Y%m%d")
logfile = NAS_DIR / f"powerD_{today}.log"

logging.basicConfig(
filename=str(logfile),
level=logging.INFO,
format='%(asctime)s %(levelname)s %(message)s',
encoding='utf-8'
)

# ===== データ取得 =====
try:
response = requests.post(URL, data={"ep_units": "KW"}, timeout=5)
response.raise_for_status()
raw_data = response.text.strip()
except Exception as e:
logging.error(f"データ取得エラー: {e}")
print(f"データ取得エラー: {e}")
exit(1)

# ===== データ整形 =====
values = raw_data.split('|')

now = datetime.now()
data_dict = {
"timestamp": now,
"value1": values[0],
"value2": values[1],
"value3": values[2],
"value4": values[3],
"value5": values[4],
"value6": values[5],
"value7": values[6],
"value8": values[7] if len(values) > 7 else None,
"value9": values[8] if len(values) > 8 else None,
"value10": values[9] if len(values) > 9 else None,
"value11": values[10] if len(values) > 10 else None,
}

df = pd.DataFrame([data_dict]) # ← 1行 DataFrame

# ===== daily Parquet 追記 =====
daily_file = NAS_DIR / f"power_{today}.parquet"

try:
if daily_file.exists():
df_existing = pd.read_parquet(daily_file)
df = pd.concat([df_existing, df], ignore_index=True)

df.to_parquet(daily_file, index=False)
print(f"{daily_file} にデータを保存しました。")

# JSON ログ用に datetime を文字列化
log_dict = data_dict.copy()
log_dict["timestamp"] = log_dict["timestamp"].isoformat()
logging.info(f"データ保存: {json.dumps(log_dict, ensure_ascii=False)}")

except Exception as e:
logging.error(f"Parquet 保存エラー: {e}")
print(f"Parquet 保存エラー: {e}")

★印の箇所は、環境に合わせて、書き換えてください。
NAS設定はこちらのページを参考してください

cron設定

*/10 * * * *  /usr/bin/python3 /home/hsbox/pyd/fm_dataget.py

CRON設定で、10分おきに実行するように設定します。
CRON設定の方法は、hsbox本家サイトのページを参考にしてください。

このような感じでデータを取得できました


読み込み完了! → 143 行 × 12 列
timestamp value1 value2 value3 value4 value5 value6 value7 value8 value9 value10 value11
0 2025-12-01 00:00:03.338238 0.00 1.15 0.00 6.39 99.59 6.64 99.35 --/-- --:-- -.-- -.-- --/-- --:--
1 2025-12-01 00:10:03.199163 0.00 1.84 0.00 11.67 99.55 8.01 99.48 --/-- --:-- -.-- -.-- --/-- --:--
2 2025-12-01 00:20:03.231549 0.00 1.19 0.00 5.79 100.05 7.47 99.64 --/-- --:-- -.-- -.-- --/-- --:--
3 2025-12-01 00:30:02.432434 0.00 1.66 0.00 10.68 99.80 7.15 99.72 --/-- --:-- -.-- -.-- --/-- --:--
4 2025-12-01 00:40:03.512127 0.00 1.12 0.00 5.50 100.37 7.18 99.92 --/-- --:-- -.-- -.-- --/-- --:--
5 2025-12-01 00:50:02.524990 0.00 1.66 0.00 10.88 99.81 7.06 99.78 --/-- --:-- -.-- -.-- --/-- --:--
6 2025-12-01 01:00:03.315994 0.00 1.67 0.00 11.06 100.06 7.03 100.07 --/-- --:-- -.-- -.-- --/-- --:--
7 2025-12-01 01:10:02.494529 0.00 1.13 0.00 5.94 100.36 6.77 100.07 --/-- --:-- -.-- -.-- --/-- --:--
8 2025-12-01 01:20:03.026167 0.00 1.08 0.00 5.49 100.05 6.85 99.70 --/-- --:-- -.-- -.-- --/-- --:--
9 2025-12-01 01:30:03.163444 0.00 1.03 0.00 5.21 100.12 6.67 99.77 --/-- --:-- -.-- -.-- --/-- --:--
10 2025-12-01 01:40:02.385593 0.00 0.99 0.00 5.46 100.18 6.18 99.92 --/-- --:-- -.-- -.-- --/-- --:--
11 2025-12-01 01:50:03.190017 0.00 0.91 0.00 5.44 100.25 5.43 100.11 --/-- --:-- -.-- -.-- --/-- --:--

それぞれの項目のデータの意味は次のようになっているようです。

保存されたデータを確認

とりあえず一部のみです。

発電量のデータです。 多分取れているようです。2週間ほど並行してそらーフロンティアに上がっているデータと一致しているか、詳細確認をしてみます。

関連記事

本番、仕切り直し。(proxy設定 httpからhttpsに変換、 ポストデータ取得を検証)この方法は断念…   

「フロンティアモニターホームサーバー」のプロキシ設定を変更して、プロキシ経由でのデータ送信を検証してみます。hsBoxのIPとプロキシのポート番号8080を設定しました。すると、フロンティアモニター – ホームエネルギーモニタリングサービス – https://www.frontier-monitor.com/persite/top へのデータ反映が止まりました。当然過去分は見えますが、プロキシ設定変更後のデータが反映されません。 先のポストデータの取得のスクリプトでは、データが取れないどころか、「フロンティアモニターホームサーバー」から何か届いているのかさえも確認できません。スプリプトを改造してスタブ実装で200応答するように改造しましたが、コネクションまでは確認でき接続先サーバーを記録できることまではできましたが、TLS接続してくるのを疑似CAで応答できなさそうであることを確認しました。

solar
solar

PROXY方式についての結論

ユーザー名、パスワードを設定してもhttpsで接続し、httpで接続してくることはない。疑似的接続させることもほぼ不可能である。
 ということで、PROXY方式での情報採取はあきらめました。


再び、内部APIの調査、CGIでデータを採取

次回は、内部CGIでデータをとれるかを検証してみます。 どうもこっちが本命になりそう。


関連記事

さて本番だ、切り替えてみよう。(proxy設定 httpからhttpsに変換、 ポストデータ取得を検証)あと1歩に見えたが…

「フロンティアモニターホームサーバー」のプロキシ設定を変更して、プロキシ経由でのデータ送信を検証してみます。hsBoxのIPとプロキシのポート番号8080を設定しました。すると、フロンティアモニター – ホームエネルギーモニタリングサービス – https://www.frontier-monitor.com/persite/top へのデータ反映が止まりました。当然過去分は見えますが、プロキシ設定変更後のデータが反映されません。 先のポストデータの取得のスクリプトでは、データが取れないどころか、「フロンティアモニターホームサーバー」から何か届いているのかさえも確認できません。横から、テスト用のポストをするとデータは記録されるので、構築した環境は動いているようです。

今回の結果を先に書くと、www.frontier-monitor.comの仕様の古さのために、当初の第一階目のゴールにはたどり着けないということが判明した。そして、いきなり最終ゴールにむけた実装が必要ということがわかった。調査結果を以下に書く。ゴールだけを見たいという人はこの記事は読み飛ばしてもらって構わない。

再びデバック開始

よく見たら、ジャーナルにたくさん「フロンティアモニターホームサーバー」接続記録が出ていました。

journalctl -u fm-mitmproxy.service -f


11月 29 17:11:53 hsbox mitmdump[47809]: [17:10:04.599][192.168.x.xx:57372] server connect www.frontier-monitor.com:443 (150.31.252.104:443)
11月 29 17:11:53 hsbox mitmdump[47809]: [17:10:05.235][192.168.x.xx:57372] Client TLS handshake failed. Client and mitmproxy cannot agree on a TLS version to use. You may need to adjust mitmproxy's tls_version_client_min option.
11月 29 17:11:53 hsbox mitmdump[47809]: [17:10:05.240][192.168.x.xx:57372] client disconnect
11月 29 17:11:53 hsbox mitmdump[47809]: [17:10:05.245][192.168.x.xx:57372] server disconnect www.frontier-monitor.com:443 (150.31.252.104:443)
11月 29 17:11:53 hsbox mitmdump[47809]: [17:10:11.362][192.168.x.xx:43760] client connect
11月 29 17:11:53 hsbox mitmdump[47809]: [17:10:11.469][192.168.x.xx:43760] server connect www.frontier-monitor.com:443 (150.31.252.104:443)
11月 29 17:11:53 hsbox mitmdump[47809]: [17:10:12.019][192.168.x.xx:43760] Client TLS handshake failed. Client and mitmproxy cannot agree on a TLS version to use. You may need to adjust mitmproxy's tls_version_client_min option.
11月 29 17:11:53 hsbox mitmdump[47809]: [17:10:12.023][192.168.x.xx:43760] client disconnect
11月 29 17:11:53 hsbox mitmdump[47809]: [17:10:12.028][192.168.x.xx:43760] server disconnect www.frontier-monitor.com:443 (150.31.252.104:443)
11月 29 17:11:53 hsbox mitmdump[47809]: [17:10:18.092][192.168.x.xx:40724] client connect
11月 29 17:11:53 hsbox mitmdump[47809]: [17:10:18.143][192.168.x.xx:40724] server connect www.frontier-monitor.com:443 (150.31.252.104:443)
11月 29 17:11:53 hsbox mitmdump[47809]: [17:10:18.670][192.168.x.xx:40724] Client TLS handshake failed. Client and mitmproxy cannot agree on a TLS version to use. You may need to adjust mitmproxy's tls_version_client_min option.
11月 29

「Client TLS handshake failed. Client and mitmproxy cannot agree on a TLS version to use. You may need to adjust」このログが大量に出ているが、これが問題だったようだ。 TLS1.0に下げるように要求されている。 hsBoxでも設定で下げれないことはないが、外部公開している入り口が怪しくなるので無理にTLS1.0にさげないことにした。

太陽光機器(192.168.*.**)  
      ↓ CONNECT www.frontier-monitor.com:443 HTTP/1.1    プロキシ宛
mitmproxy(192.168.*.*:8080) ←ここで TLS 開始(クライアント側 TLS)  
      ↓ TLS ハンドシェイク開始  
      × 失敗 → Client TLS handshake failed  
      (mitmproxy → 150.31.252.104:443 にはまだ接続すらしていない)


ということで、データのキャプチャにも失敗し、プロキシ経由でのサーバへのアップロードもできていない。 プロキシ設定してから、 www.frontier-monitor.comへのデータアップロードも止まったままである。
  この記事での成果は、「フロンティアモニターホームサーバー」の送信先がwww.frontier-monitor.comであると確認できたことだ。

一旦、切り戻しして、仕切り直しましょう。そして、最終型にむけて再検討します。


関連記事

proxy設定のその2 httpからhttpsに変換、 ポストデータ取得を検証

hsbox の proxy実装の続きをしましょう。 httpは通りました https対応に挑戦です。
最初に検証方法を確認しておきましょう。 httpサービスをしていないhttpsのみのサイトを探しましょう そのサイトを使って、送信データを取得できるか検証しましょう。

確認方法の検討

$ curl -I http://github.com
HTTP/1.1 301 Moved Permanently
Content-Length: 0
Location: https://github.com/


$ curl -I https://github.com
HTTP/2 200
date: Fri, 28 Nov 2025 02:58:12 GMT
content-type: text/html; charset=utf-8
vary: X-PJAX, X-PJAX-Container, Turbo-Visit, Turbo-Frame, X-Requested-With, Accept-Language,Accept-Encoding, Accept, X-Requested-With
content-language: en-US
etag: W/"06826aee56dafc29be870ab3e992ec77"
cache-control: max-age=0, private, must-revalidate
strict-transport-security: max-age=31536000; includeSubdomains; preload
---以下省略

guithub.comのトップでhttpsへのプロキシが効くが確認することにします。

最初の状態でのProxy動作を確認してみます

$ curl -x http://192.168.2.45:8080 http://github.com

何も応答がありません。
まだ、Proxyが自動的にhttpsに変換していないようです。

プロキシをとおしてプロキシでポストデータを取得するのが目的です。 この場合、POSTはhttpsではなくhttpで送られる必要があるでしょう。そして、プロキシでhttpsに変換する。 そのような使い方をしたいので、 mitmproxy の 設定方法を変更します。

 mitmproxy 用解析・保存スクリプトを更新配置(仮2)

■/home/hsbox/pyd/fm_capture.py  を更新配置  (内容は以下)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File: ~/fm_capture.py

import json
import os
from datetime import datetime
from mitmproxy import http
from mitmproxy import ctx

DATA_DIR = "/home/hsbox/fm_data" # ← 自分のホームに合わせて変更
os.makedirs(DATA_DIR, exist_ok=True)

# fm_capture.py の先頭に追加
force_https_domains = {
"www.frontier-monitor.com",
"github.com",
# ここに対象ドメインを全部書く(または全部強制したいなら条件を緩く)
}

def request(flow):
host = flow.request.pretty_host
if host in force_https_domains or host.endswith(".example.com"):
if flow.request.scheme == "http":
flow.request.scheme = "https"
flow.request.port = 443

def response(flow: http.HTTPFlow):
# フロンティアモニターの送信先だけを対象にする
if "frontier-monitor.com" not in flow.request.pretty_host:
return

if flow.request.path.startswith("/upload/data.php"): # 実際のURLに合わせて調整可
try:
# POSTされたJSONを取得
raw = flow.request.get_text()
data = json.loads(raw)

# タイムスタンプを付与(モニターの時刻を優先)
timestamp = data.get("timestamp", datetime.now().isoformat())

# 1. 生JSONを保存(デバッグ用)
raw_file = f"{DATA_DIR}/raw_{timestamp.replace(':', '-')}.json"
with open(raw_file, "w") as f:
f.write(raw)

# 2. 最新データを上書き保存
latest_file = f"{DATA_DIR}/latest.json"
with open(latest_file, "w") as f:
json.dump(data, f, indent=2)

# 3. SQLiteに挿入(初回はテーブル自動作成)
import sqlite3
db_path = f"{DATA_DIR}/fm_data.db"
conn = sqlite3.connect(db_path)
cur = conn.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS power (
ts TEXT PRIMARY KEY,
generation INTEGER,
consumption INTEGER,
grid_buy INTEGER,
grid_sell INTEGER,
temperature REAL,
status INTEGER
)
""")
cur.execute("""
INSERT OR REPLACE INTO power VALUES (?, ?, ?, ?, ?, ?, ?)
""", (
timestamp,
data.get("generation"),
data.get("consumption"),
data.get("grid_buy"),
data.get("grid_sell"),
data.get("temperature"),
data.get("status")
))
conn.commit()
conn.close()

ctx.log.info(f"[FM] データ保存成功 → {timestamp}")
except Exception as e:
ctx.log.error(f"[FM] エラー: {e}")

systemd サービスファイルの更新

[Unit]
Description=Frontier Monitor Transparent Proxy
After=network.target
Wants=network.target

[Service]
Type=simple
User=hsbox
Environment="PATH=/home/hsbox/.local/bin:/usr/local/bin:/usr/bin:/bin"
ExecStart=/home/hsbox/.local/bin/mitmdump --mode regular --listen-host 0.0.0.0 --listen-port 8080 --set upstream_cert=false --showhost --proxyauth ユーザー名:パスワード@ --script /home/hsbox/pyd/fm_capture.py --quiet
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

ユーザー名とパスワードを設定してください。 使用しない場合、”–proxyauth”の設定は不要です。
上の設定をしたら、設定反映と起動、起動確認を行います。

動作確認

■curlで、 動作検証します。
curl -x http://<プロキシが動作するhsboxのIP>:8080 http://github.com/

実行結果例:
curl -x http://192.168.1.10:8080 http://github.com








<!DOCTYPE html>
<html
lang="en"
data-color-mode="dark" data-dark-theme="dark"
data-color-mode="light" data-light-theme="light" data-dark-theme="dark"
data-a11y-animated-images="system" data-a11y-link-underlines="true"

>




<head>
<meta charset="utf-8">
<link rel="dns-prefetch" href="https://github.githubassets.com">
<link rel="dns-prefetch" href="https://avatars.githubusercontent.com">
<link rel="dns-prefetch" href="https://github-cloud.s3.amazonaws.com">
<link rel="dns-prefetch" href="https://user-images.githubusercontent.com/">
<link rel="preconnect" href="https://github.githubassets.com" crossorigin>
<link rel="preconnect" href="https://avatars.githubusercontent.com">


<link crossorigin="anonymous" rel="preload" as="script" href="https://github.githubassets.com/assets/global-banner-disable-54e442fb573b.js" />

<link rel="preload" href="https://github.githubassets.com/assets/mona-sans-14595085164a.woff2" as="font" type="font/woff2" crossorigin>



※これで、proxyで、httpをhttpsに変換してアクセスできていそうです。

NAS設定の修正

11月 28 23:03:07 hsbox systemd[1]: Started Frontier Monitor Transparent Proxy.
11月 28 23:03:45 hsbox mitmproxy[1050039]: POST CAPTURE FAILED: [Errno 13] Permission denied: ‘/mnt/nas/solar_data/capture_20251128.log’

NASの書き込み権限がないため書き込めません、mitmproxyは、hsbox権限で起動しているので、権限を777に設定します。

しかし、smbマウントしていると、chmodでは、権限を設定できません。NAS側のGUI等で、ログインユーザの権限等でフルアクセスできるように設定しておきます。
また、暫定対処ですが、起動時に自動マウントするように以下のマウントコマンドを仕込んでおきました。※事前に手動実行で操作確認しておいてください

# mitmproxy 用 NAS マウント
mount -t cifs //<NASのIP>/share /mnt/<マウントポイント> -o username=user,password=pass,vers=3.0,iocharset=utf8,uid=1000,gid=1000,nounix,cache=none,nolease && logger "NAS mounted for mitmproxy by startup script"

 mitmproxy 用解析・保存スクリプトを更新配置(仮3)

キャプチャデータをローカルおよびNASに保存するスプリプとに更新します。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import json
import os
from datetime import datetime
from mitmproxy import http
from urllib.parse import urlencode

LOG_DIR = "/home/hsbox/fm_data" # まずローカルで確認
#LOG_DIR = "/mnt/nas/solar_data"

os.makedirs(LOG_DIR, exist_ok=True, mode=0o777)

def request(flow):
host = flow.request.pretty_host
if host in {"www.frontier-monitor.com", "github.com"}:
if flow.request.scheme == "http":
flow.request.scheme = "https"
flow.request.port = 443

def response(flow: http.HTTPFlow):
# POSTじゃなければ完全スルー(無駄な書き込みゼロ)
#if flow.request.method != "POST":
# return

now = datetime.now().strftime("%Y%m%d")
logfile = f"{LOG_DIR}/capture_{now}.log"

post_data = ""
if flow.request.urlencoded_form:
post_data = urlencode(flow.request.urlencoded_form)
elif flow.request.multipart_form:
post_data = urlencode(flow.request.multipart_form)
elif flow.request.text:
post_data = flow.request.text

# 空のPOSTは記録しない(必要なら残す)
if not post_data.strip():
return

entry = {
"ts": datetime.now().isoformat(),
"host": flow.request.pretty_host,
"url": flow.request.pretty_url,
"post": post_data
}

try:
with open(logfile, "a", encoding="utf-8", buffering=1) as f:
f.write(json.dumps(entry, ensure_ascii=False) + "\n")
f.flush()
os.fsync(f.fileno())
except Exception as e:
os.system(f'logger -t mitmproxy "POST CAPTURE FAILED: {e}"')

手動でポストをシミュレーションして動作確認

httpsのサイトに手動でポストしてみたデータを保存できるか検証します

~$ curl -x http://<hsBoxのIP>:8080 --insecure -X POST -d "test=2111
1&name=フロンティア
" http://github.com

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; base-uri 'self'; connect-src 'self'; form-action 'self'; img-src 'self' data:; script-src 'self'; style-src 'unsafe-inline'">
<meta content="origin" name="referrer">
<title>Page not found &middot; GitHub</title>
<style type="text/css" media="screen">

保存されたデータを確認

{“ts”: “2025-11-29T10:13:24.269169”, “host”: “github.com”, “url”: “https://github.com/”, “post”: “test=11111&name=%C3%A3%C2%83%C2%95%C3%A3%C2%83%C2%AD%C3%A3%C2%83%C2%B3%C3%A3%C2%83%C2%86%C3%A3%C2%82%C2%A3%C3%A3%C2%82%C2%A2”}
{“ts”: “2025-11-29T10:52:06.845328”, “host”: “github.com”, “url”: “https://github.com/”, “post”: “test=21111&name=%C3%A3%C2%83%C2%95%C3%A3%C2%83%C2%AD%C3%A3%C2%83%C2%B3%C3%A3%C2%83%C2%86%C3%A3%C2%82%C2%A3%C3%A3%C2%82%C2%A2“}

1回のポストで1行追加されました。

ポストしたデータが丸ごと入っていることを確認できました。
これでキャプチャ成功です。 
NASへの保存も成功です。

ハードルが複数あるので、着実に1つづつクリアしていくのが、近道でしょう。

・–quiet にしないとサービス起動できない
・サービス起動は通常root相当だが、mitmproxyの起動ユーザはrootではうまく動かない
・書き込みタイミングの課題
・NASの書き込み権限
・hsBox独特?の自動マウントの手法

簡単にまとめると権限問題とタイミング問題ですね。開発者あるあるですね。。

関連記事

hsbox1.3上にproxyを構築する手順

太陽光発電のモニタリングサービスが終了するため、データ取得を検討中です。このデータ取得のために、proxyを構築します。 誰でも簡単に導入できるようにするためにここでは、hsbox(無料版:freebox)上に構築してみます。

どのような構成にするのかは、過去の記事を参考にしてください。ここでは、hsboxに構築する手順に特化して記載します。

0.前準備

hsboxを構築する手順はここでは省きます。本家サイトの記事(リンク先)か、Vectorサイトのドキュメント入りアーカイブを参照してください。
有償版は、GUIから操作できるなど操作性が上がりますが、ここでは無償版でも使える機能をベースに記載します。

1.プロキシのインストール

hsbox1.3は、python3環境を構築済みなので、プロキシのインストールからはじめます。

■1. hsboxに、sshでログインします。  *参考:本家サイト
  ホームディレクトリ /home/hsbox に移動。

■2. mitmproxy をインストール
pip3 install --user mitmproxy

■3. 実行パスを通す
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

■4. スクリプト等配置用のディレクトリ作成
mkdir /home/hsbox/pyd

2. mitmproxy 用解析・保存スクリプトを配置(仮版)

■/home/hsbox/pyd/fm_capture.py  を配置  (内容は以下)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File: ~/fm_capture.py

import json
import os
from datetime import datetime
from mitmproxy import http
from mitmproxy import ctx

DATA_DIR = "/home/hsbox/fm_data"   # ← 自分のホームに合わせて変更
os.makedirs(DATA_DIR, exist_ok=True)

def response(flow: http.HTTPFlow):
    # フロンティアモニターの送信先だけを対象にする
    if "frontier-monitor.com" not in flow.request.pretty_host:
        return

    if flow.request.path.startswith("/upload/data.php"):  # 実際のURLに合わせて調整可
        try:
            # POSTされたJSONを取得
            raw = flow.request.get_text()
            data = json.loads(raw)

            # タイムスタンプを付与(モニターの時刻を優先)
            timestamp = data.get("timestamp", datetime.now().isoformat())

            # 1. 生JSONを保存(デバッグ用)
            raw_file = f"{DATA_DIR}/raw_{timestamp.replace(':', '-')}.json"
            with open(raw_file, "w") as f:
                f.write(raw)

            # 2. 最新データを上書き保存
            latest_file = f"{DATA_DIR}/latest.json"
            with open(latest_file, "w") as f:
                json.dump(data, f, indent=2)

            # 3. SQLiteに挿入(初回はテーブル自動作成)
            import sqlite3
            db_path = f"{DATA_DIR}/fm_data.db"
            conn = sqlite3.connect(db_path)
            cur = conn.cursor()
            cur.execute("""
                CREATE TABLE IF NOT EXISTS power (
                    ts TEXT PRIMARY KEY,
                    generation INTEGER,
                    consumption INTEGER,
                    grid_buy INTEGER,
                    grid_sell INTEGER,
                    temperature REAL,
                    status INTEGER
                )
            """)
            cur.execute("""
                INSERT OR REPLACE INTO power VALUES (?, ?, ?, ?, ?, ?, ?)
            """, (
                timestamp,
                data.get("generation"),
                data.get("consumption"),
                data.get("grid_buy"),
                data.get("grid_sell"),
                data.get("temperature"),
                data.get("status")
            ))
            conn.commit()
            conn.close()

            ctx.log.info(f"[FM] データ保存成功 → {timestamp}")
        except Exception as e:
            ctx.log.error(f"[FM] エラー: {e}")

3. systemd サービスファイル

[Unit]
Description=Frontier Monitor Transparent Proxy
After=network.target
Wants=network.target

[Service]
Type=simple
User=hsbox
Environment="PATH=/home/hsbox/.local/bin:/usr/local/bin:/usr/bin:/bin"
ExecStart=/home/hsbox/.local/bin/mitmdump --mode regular --listen-host 0.0.0.0 --listen-port 8080 --script /home/hsbox/pyd/fm_capture.py --quiet
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

※ファイルの書き込みはいろいろありますが、ルート権限で上書きcat するのか簡単でしょう。

4. 設定反映と起動

# ファイルを反映
sudo systemctl daemon-reload

# 自動起動設定+今すぐ起動
sudo systemctl enable fm-mitmproxy.service
sudo systemctl start fm-mitmproxy.service

# 状態確認
sudo systemctl status fm-mitmproxy.service
journalctl -u fm-mitmproxy.service -f # リアルタイムログ

参考

statusでの確認で、起動していれば次のように”active (running)”が表示されます

root@hsbox:~# sudo systemctl status fm-mitmproxy.service
● fm-mitmproxy.service - Frontier Monitor Transparent Proxy
Loaded: loaded (/etc/systemd/system/fm-mitmproxy.service; enabled; vendor >
Active: active (running) since Sun 2025-11-23 15:29:08 JST; 1 day 7h ago
Main PID: 135951 (mitmdump)
Tasks: 2 (limit: 4378)
Memory: 46.0M
CPU: 1min 2.732s
CGroup: /system.slice/fm-mitmproxy.service
mq135951 /usr/bin/python3 /home/hsbox/.local/bin/mitmdump --mode r>

11月 23 15:29:08 hsbox systemd[1]: Started Frontier Monitor Transparent Proxy.

動作確認

■curlで、 動作検証します。
curl -x http://<プロキシが動作するhsboxのIP>:8080 http://mic.or.jp/

例:
curl -x http://192.168.1.10:8080 http://mic.or.jp/

※とりあえず、確認できるのはhttpのみ、 この設定だけではhttpsサイトへのproxy利用ができません。 httpsは次のステップです。

関連記事

ソーラーフロンティア ホームエネルギーモニタリングサービス終了! 2025年12月solar発電データ監視がストップ?の代替で継続を検討

ソーラーフロンティア ホームエネルギーモニタリングサービスが2025年12月に終了!hsboxでsolar発電データ監視を代替を検討

過去の関連記事

はじめに

次のようにフロンティアモニターのシステム終了のアナウンスがきています。
hsBoxを使って代替機能を実装していきましょう。

**** 様

日頃より【フロンティアモニター】ホームエネルギーモニタリングサービスをご利用いただき、誠にありがとうございます。

【システム終了のお知らせ】
2025年12月22日(月)をもって本計測装置のサービスを終了いたします。
なお、システムの都合により、一部サービス終了のタイミングについては前後する可能性がございますので、ご承知おきください。
詳しくはお客様ご利用サイトのお知らせ欄をご覧ください。

本メール発信は、メールシステムメンテナンスにより、1日遅延する場合があります。メンテナンスの日程は、お客様ログイン画面の「お知らせ」欄に随時記載いたします。
メンテナンス時はご不便をおかけしますが、何卒ご承知おきくださいますようお願いいたします。

下記の通り、2025年11月07日の発電量をお知らせいたします。

発電量:37.44kWh


今後ともフロンティアモニターをよろしくお願いいたします。
★なお、お心当たりのない方は、お手数ではございますが、下記メールアドレスまでご連絡頂きますようお願いいたします。
★このメールは送信専用メールアドレスから配信しています。このまま返信いただいてもお答えできませんのでご了承ください。
-----------------------------------------------
ソーラーフロンティア株式会社
【フロンティアモニター】お客様サービスセンター
電話:0570-053115(受付時間:9:00-17:00)※日曜、祝祭日、メーデー、年末年始を除く
メール:information@solar-frontier.com
-----------------------------------------------

順次、実装を進めていきます。 参考してみてください。 コメントなどあればお願いします。

まずは、次の情報を集めます

●パワーコンディショナー(メーカーと型番)
●フロンティアモニターの接続方式

次の図ような方式で、データ収集できそうな目途が立ちました。
※最初PROXY方式で検討しましたが、途中で直接採取する方式に変更してデータ取得できるようになりました。

順番に構築・検証していきます。以下に一部公開済みです。

hsBoxにproxyを構築 [公開済み]
hsBoxのproxyでデータ収集を検証[公開済み]
proxyで実データ収集に調整 pruxy方式は放棄、諦めて別方式へ[公開済み]
・hsBoxで、直接発電電力データの取得に成功!![公開済み]
・hsBoxで収集してデータを蓄積[公開済み、取得と同時にNASへ蓄積]
・hsBoxで取得したデータの妥当性を比較検証[公開済み]
・集積したデータでグラフを書かせてみた[公開済み]
・発電量通知メールを置き換え LINEで通知[公開済み]

この後の作業予定です。[近日追加公開予定]
・異常検知を検知して、メール、LINEで通知
・蓄積したデータのhsBoxでTVやスマートディスプレイに表示

関連記事

太陽光発電の軌跡:個人導入のリアル ~運用実績から見る2025年Solarの投資回収と総所有コスト~


太陽光発電を検討中のあなたは、きっとこんな疑問をお持ちではないでしょうか。

「投じたお金、いつ元が取れるの?」
「メンテナンスや廃棄まで考えたら、本当に得になるの?」

当サイトでは、2013年に太陽光発電を導入して以来、実際の運用データを10年以上にわたり公開してきました。
その結果、導入当初のROI(Return on Investment:投資回収期間)は、計算通り約6年で達成しました。
しかし2023年にFIT(固定価格買取制度)が終了し、売電価格が約7分の1(=15%)に低下したことで、改めてROIの意味を見つめ直す必要が生まれました。

ROIは「どの提案を選べば最短で投資を回収できるか」を測るための指標です。
一方で、TOC(Total Cost of Ownership:総所有コスト)は、初期投資だけでなく、メンテナンス費用や廃棄コストまでを含めた“本当のコスト”を示します。

当サイトの実績では、ROI上は6年で回収を達成していましたが、TOCを考慮すると実質7年。
つまり、これから導入するなら、卒FIT後の運用シナリオまで見越した試算が欠かせません。


1. 当サイトの実績が示すROI(投資回収期間)の信頼性

太陽光発電の普及は、1954年のシリコン太陽電池の発明から始まり、2012年のFIT制度導入で一気に一般家庭に広がりました。
発電コストは2010年の1Wあたり約4ドルから、2025年には0.3ドル未満にまで低下。これがROI(投資回収期間)を劇的に短縮させた要因です。
現在、世界の累積導入量は2TWを突破し、家庭用のROIは平均8年前後とされています。

当サイトの実例(2013年導入)

  • 導入内容:4.4kW+5.5kWシステム(計約10kW)
  • 初期投資:約200万円
  • 年間発電量:約8,000kWh
  • ROI:6年(FIT単価42円/kWh+自家消費分)

導入から3か月後にパワコン故障が発生しましたが、アラートメールによる早期検知で迅速に対応でき、運用体制の重要性を実感しました。

運用解析・異常検知

夜間消費電力の変動を解析し、AIによる異常検知(例:浄化槽ブロワーの故障)を実現。
30%以下の発電低下を自動通知する仕組みを構築し、メンテナンスコストを削減。
これがTOC(総所有コスト)最適化の第一歩となりました。

経年劣化と長期視点

10年後の発電量は設置当初の84〜86%。
メーカー保証(10年・81%未満で交換)内で維持できており、定期点検と早期対応の重要性を再確認。
劣化率を年0.5〜0.8%で見積もることで、ROIの延長を防ぐことができます。

故障対策とFIT終了後の変化

FIT終了後(2023年)は売電価格が42円→8円/kWhへ低下。
それでも自家消費を中心にした運用でROI約6年を維持。
ただし、TOC(運用・廃棄費用含む)を加味すれば実質7年となります。

記事URLテーマROI / TOC のポイント
2019/04/24導入実績ROI6年達成、最短提案の選択
2019/08/21経年劣化劣化0.5%/年を想定しROI延長を防ぐ
2019/11/20故障AIメンテ自動化でTOC削減

2. 現在の導入判断:ROIとTOCを自宅で試算する

2025年の家庭用太陽光は、ROI8〜10年が標準。
補助金(最大36万円/kW)により、設置費用は4kWで約120万円まで低下。
FIT単価は16円/kWh、自家消費率70%を想定すれば、投資回収の現実味が見えてきます。

シミュレーション例(4kW家庭)

項目内容
初期投資120万円(補助後)
年間発電量約4,500kWh
自家消費(70%)3,150kWh × 31円 = 約9.8万円節約
売電(30%)1,350kWh × 16円 = 約2.2万円収入
年間合計利益約12万円
ROI約10年(=120万 ÷ 12万)

TOCを考慮すると、メンテ25万円+廃棄15万円で総追加40万円。
25年間での累積利益300万円に対して、ネット利益は約260万円。
実質ROIは約11年となります。

卒FIT後(2035年以降)は売電価格が8円に下がるため、年利益は約9.8万円へ。
ただしV2H(EV充電併用)を導入すれば、エネルギーロスが減りROIを10年程度に短縮可能です。

シナリオ初期費用年利益ROI(年)TOC追加実質ROI(年)
当サイト(2013年)200万円33万円640万円7
2025年(FIT中)120万円12万円1040万円11
卒FIT後(V2Hなし)120万円9.8万円1240万円13
卒FIT後(V2Hあり)120万円11.8万円1040万円11

ポイント:ROIは「早い回収」、TOCは「持続可能な回収」。
どちらも考慮してこそ、真にお得な投資判断が可能です。


3. これからの展望:ペロブスカイトと再利用でTOCを最小化

新技術「ペロブスカイト」でROI短縮へ

2025年時点で実用化が進むペロブスカイト太陽電池は、軽量・高効率(18〜30%)で注目されています。
2030年以降には住宅向けタンデム型が普及し、ROIはさらに短縮される見通しです。
導入を急がず、補助金制度を活用して技術成熟を待つのも賢明な選択です。

廃棄から再利用へ ― TOCの最大課題を克服

廃棄費用(約15万円)はTOCを押し上げる要因でしたが、2025年からはリサイクル義務化により、
メーカー負担による95%回収目標が設定されました。

TOCを抑える具体策:

  • リユース買取の活用:状態の良いパネルを無料回収する業者が登場。廃棄コストゼロでROIを1年短縮。
  • 積立制度の活用:10kW以上で廃棄積立義務化(年5,000円程度)。住宅にも推奨。
  • AI診断の導入:劣化0.5%/年を自動監視し、交換タイミングを最適化。

これらを組み合わせれば、TOCの「廃棄部分」を半減し、持続的ROIが実現します。


結論:ROIとTOCを味方につけ、賢く始める太陽光発電

当サイトの実績(ROI6年・TOC7年)は、実際に数字で回収が可能であることを示しました。
2025年の現在、補助金や技術革新によりROI10年前後が現実的なライン。
卒FIT後もV2Hや再利用によって持続的にコストを抑えられます。

ROIは「どれだけ早く投資を回収できるか」、
TOCは「どれだけ長く安心して使い続けられるか」。

この2つを理解して選ぶことが、これからの太陽光発電の“本当の価値”です。
ぜひ、経産省などのシミュレーションツールを使って、ご自宅のROIを試算してみてください。

あなたの家にも、確かな投資回収の太陽が昇りますように。
コメント欄で、あなたのROI体験もぜひ教えてください。


参考資料

  • 当サイト「太陽光発電シリーズ(2019)」
  • 経済産業省 FIT制度データ
  • IEA “Renewables 2025” / IRENA Global PV Report 2025

関連記事