rabbit51

Apr.28 2025, transferred from goo

H2Vサービス廃止対策

2025年中に変更あるいは終了するPC・ネットワーク関連サービスの対応について

電力消費とPHEV車への充電量をモニターしまとめてくれるサービス。月毎の充電量を集計し、事業比率を掛け、青色申告の事業経費に計上していたが、使えなくなる。

H2Vサービスは、H2V Controllerで使用電力と充電電力が計測され、H2V Gatewayで表示とトヨタスマートセンターへデータを提供している。スマートセンターは、データを蓄積し、グラフ化した情報をiPhoneなどのスマートフォンアプリやPCデータ(pdfなど)で利用できる情報を提供する。導入システムの詳細は下記参照。
Prius PHV充電モニタH2Vmanagerの導入」
「H2Vmanagerシステムの無線LAN接続を既存のAP経由で接続させる」
「プリウスPHV H2V controller 無線LAN 復帰
2025年3月31日でスマートセンターのデータ提供を終了する連絡が来た(必要なデータ収集を行なったので経費のかかるシステム維持は終わりと言う事か)。

(1)H2VGateway


「設定」「ルータ設定」画面(BuffaloのWiFiルータとほぼ同じ)

H2VControllerから定時的にWiFi接続で送られてくる使用電力と充電電力を表示したり、トヨタスマートセンターへインターネット経由でデータを送出する。WiFi接続に不具合があるとH2VControllerに一時的に情報が蓄えられ、WiFi接続が回復すると蓄えられた情報を送出する。プロトコルは公開されていない。

H2VManagerのトップ画面には「消費電力(本日)(昨日)[Kwh]」の積算値、「現在の消費電力[Kw]」「充電使用電力[Kw]」が表示されている。画面情報をHTMLテキストから取り出そうと調べていると、HTML headの前に下記情報がコメントで含まれているのが判った。
Device Num : 1
<table>
<tr><th>Device-ID[1] = [34 c7 31 XX XX XX]</th></tr>
<tr><th>本日</th><td>[6932]</td></tr>
<tr><th>昨日</th><td>[22436]</td></tr>
<tr><th>平均</th><td>[817]</td></tr>
<tr><th>最大</th><td>[849]</td></tr>
<tr><th>車充電</th><td>[2]</td></tr>
<tr><th>ピークカット状態</th><td>[0]</td></tr>
<tr><th>リレー状態</th><td>[1]</td></tr>
<tr><th>最新電力情報の時刻</th><td>[2025/02/20 20:09]</td></tr>
<tr><th>PCC接続状態</th><td>[-64]</td></tr>
<tr><th>TSC接続状態</th><td>[4]</td></tr>
<tr><th>充電開始時刻(nooffset)</th><td>[1970/01/01 09:00]</td></tr>
</table>
「Device-ID」は、H2VControllerのMAC address。「最新電力情報の時刻」は、JST+9の時刻と思われる。GMT+9なら判るが。。。

スケシューラで1分毎に下記Pythonスクリプトを起動し月毎のcsvファイルを作る
h2vmgr.py
#!/usr/bin/python
import os
import urllib.request
import re
from datetime import datetime, timedelta

pat1='<th>(本日)</th><td>\[(\d+)\]</td>'
pat2='<th>(昨日)</th><td>\[(\d+)\]</td>'
pat3='<th>(平均)</th><td>\[(\d+)\]</td>'
pat4='<th>(最大)</th><td>\[(\d+)\]</td>'
pat5='<th>(車充電)</th><td>\[(\d+)\]</td>'
pat6='<th>(ピークカット状態)</th><td>\[(\d+)\]</td>'
pat7='<th>(リレー状態)</th><td>\[(\d+)\]</td>'
pat8='<th>(最新電力情報の時刻)</th><td>\[([\d\s/:]+)\]</td>'
pat9='<th>(PCC接続状態)</th><td>\[([\d-]+)\]</td>'
pat10='<th>(TSC接続状態)</th><td>\[(\d+)\]</td>'
pat11='<th>(充電開始時刻\(nooffset\))</th><td>\[([\d\s/:]+)\]</td>'

h2vurl="http://h2vmgr.matsuura/h2v/top_phv_ev.html"
req=urllib.request.Request(h2vurl)

try:
    with urllib.request.urlopen(req) as res:
        body=res.read().decode("euc-jp")
        res1=re.search(pat8,body,re.S) #最新電力情報の時刻
        if res1:
            dt=datetime.strptime(res1.group(2),"%Y/%m/%d %H:%M")
            dt=dt-timedelta(hours=9)
            os.chdir(os.path.dirname(os.path.abspath(__file__)))
            ofn=dt.strftime("%Y%m")+"h2vmgr-rawd.csv"
            csvh="""+res1.group(1)+"""
            csvd="""+dt.strftime("%Y/%m/%d %H:%M")+"""

        res1=re.search(pat1,body,re.S) #本日
        if res1:
            csvh=csvh+",""+res1.group(1)+"""
            csvd=csvd+","+res1.group(2)
        res1=re.search(pat2,body,re.S) #昨日
        if res1:
            csvh=csvh+",""+res1.group(1)+"""
            csvd=csvd+","+res1.group(2)
        res1=re.search(pat3,body,re.S) #平均
        if res1:
            csvh=csvh+",""+res1.group(1)+"""
            csvd=csvd+","+res1.group(2)
        res1=re.search(pat4,body,re.S) #最大
        if res1:
            csvh=csvh+",""+res1.group(1)+"""
            csvd=csvd+","+res1.group(2)
        res1=re.search(pat5,body,re.S) #車充電
        if res1:
            csvh=csvh+",""+res1.group(1)+"""
            csvd=csvd+","+res1.group(2)
        res1=re.search(pat6,body,re.S) #ピークカット
        if res1:
            csvh=csvh+",""+res1.group(1)+"""
            csvd=csvd+","+res1.group(2)

        res1=re.search(pat9,body,re.S) #PCC接続状態
        if res1:
            csvh=csvh+",""+res1.group(1)+"""
            csvd=csvd+","+res1.group(2)

        res1=re.search(pat10,body,re.S) #TSC接続状態
        if res1:
            csvh=csvh+",""+res1.group(1)+"""
            csvd=csvd+","+res1.group(2)

        res1=re.search(pat11,body,re.S) #充電開始時刻(nooffset)
        if res1:
            csvh=csvh+",""+res1.group(1)+"""
            csvd=csvd+",""+res1.group(2)+"""

        dtn=datetime.now()
        if ( dt.strftime("%Y/%m/%d %H:%M") == "1970/01/01 00:00" ):
            with open(ofn, mode='a') as f:
                f.write(csvd+",""+dtn.strftime("%Y%m%d%H%M")+""\n")
        else:
            if not os.path.isfile(ofn):
                with open(ofn, mode='w') as f:
                    f.write(csvh+"\n")
            with open(ofn, mode='a') as f:
                f.write(csvd+"\n")

except urllib.error.HTTPError as e:
    if e.code >= 400:
        print(e.reason)
    else:
        raise e
毎月1日に下記Pythonスクリプトを実行し使用電力と充電電力の集計を行う
h2vmgrmsum.py
#!/usr/bin/python
# "最新電力情報の時刻","本日","昨日","平均","最大","車充電","ピークカット状態","PCC接続状態","TSC接続状態","充電開始時刻(nooffset)"
import csv
import os
from datetime import date, datetime, timedelta

# 毎月1日に前月分の消費電力と充電電力を計算する
dt=date.today()   #dt=date(2025,2,1)
dtp=dt-timedelta(days=27)  # 集計月(前月)
dtd=date(dt.year,dt.month,1)-date(dtp.year, dtp.month,1)  # 集計月の日数
# 前月の集計するファイル名
fni=dtp.strftime("%Y%m")+"h2vmgr-rawd.csv"
fno=dtp.strftime("%Y%m")+"h2vmgr-sum.txt"
os.chdir(os.path.dirname(os.path.abspath(__file__)))
ofn=dt.strftime("%Y%m")+"h2vmgr-rawd.csv"

tpwr=0
chrg=0
cnt=0
data=""
with open(fni, newline='') as f:
    h2vd=csv.reader( f )
    header=next(h2vd)
    for row in h2vd:
            tpwr=tpwr+int(row[3])
            chrg=chrg+int(row[5])
            cnt=cnt+1
data="Sumary of the "+dtp.strftime("%Y/%m")+"\n"
data=data+"Total used power(Kwh) : "+str( '{:8g}'.format(tpwr/60000) ) + "\n"
data=data+"Total charged power(Kwh) : " + str( chrg/60000 ) + "\n"
data=data+"Lost " + str(dtd.days*1440-cnt) + "/ Recorded " + str(cnt) + " minutes("+str(dtd.days) +"days)\n"
#print(data)

if not os.path.isfile(fno):
    with open(fno, mode='w') as f:
        f.write(data+"\n")
with open(fno, mode='a') as f:
    f.write(data+"\n")
毎月の集計値ファイルが作られる
202501h2vmgr-sum.txt
Sumary of the 2025/01
Total used power(Kwh) :  653.023
Total charged power(Kwh) : 21.29235
Lost 10/ Recorded 44630 minutes(31days)