HSPで東京電力の電力使用状況を可視化
1.概要
毎日、365日利用している電気について、その使用量がどうなっているのか気にしたことはありませんか?
東京電力のサイトでは、でんき予報として電気の使用量についての、予測や実績をリアルタイムで数値で公開されています。
過去の使用実績についても、数値をダウンロードできます。
でんき予報には東京電力グループだけでなく、サービスエリア内全ての電力需要ならびに電力供給力の合計値が掲載されています。
今回、普段あまり気にすることは多くないと思いますが、サービス提供されているデータをHSPスクリプト言語でリアルタイムに
取得し、グラフ化して可視化します。
2.ソースコード 作成したプログラムは、東京電力 - 電力使用状況 (poweruse.exe)です。起動すると、 最新の使用率(%)をゲージグラフで表示します。使用率は、実績値 / 供給力で表されます。 グラフボタンをクリックすると、使用量の時間帯別推移をグラフ化して表示します。1時間単位ですので、〇〇時台の実績となり、 1時間前の状況となります。下記の画面は、この記事を作成する前に取得したもので、画面下のグラフは24時間の推移がどんな風にグラフ化 されるのを見せるために、過去のデータから参考としてグラフ化したものです。
尚、poweruse.exeを実行させるには、設定情報の保存にSQLite3を利用していますので、同一フォルダに SQLite3.dllが必要です。ダウンロードアーカイブに同梱しています。 ソースコードは、下記の通りです。コードの前半部分は、画面の描画や移動などに必要なAPIやグラフ描画のためのモジュールを定義 しています。起動すると、電力使用状況のサイトページにアクセスして、一旦ページ全体を取得しバッファに格納します。 取得先ページは、予め取得し易いようにテキスト形式のカンマ区切りとしてデータが掲載されています。 取得できたら、現在の時間から、最新のデータに更新されている行を取得後、改行コードを変換します。 取得データを分解して配列に格納したら、ゲージグラフを描画します。ゲージグラフは「アナログ時計」の 針の位置を描画するルーチンの応用で270°を 0(基点)として計算しています。以下、その状態でタイマー割り込みで10分単位に サイトにアクセスして更新データを取得していきます。
グラフボタンをクリックすると、使用時間帯別の棒グラフを描画します。 グラフのデータは、取得データを事前に配列に格納してあるので、配列から読み込みます。 グラフ描画に関しては、特別なモジュールなどがないので、縦軸、横軸のサイズ(線の長さ)から グラフが収まるように計算しています。ポイントは、縦軸のスケールの決め方です。 データの最大値を6000(万kw) として、目盛の刻み単位を500に定めて13段階に区分しています。 横軸は、0~23時までの24時間として横軸目盛を刻んでいます。 グラフの描画開始位置を決めて、boxf命令で描画させています。 縦軸スケールをデータの値によって自動で調整できるようなモジュールがあれば楽なのですが、 うまく作成できませんでした。
3.ダウンロード 提供するソースコードのライセンスは、CC0 (クレジット表示不要、改変可、商用可) とします。自由に利用して頂いてかまいません。 尚、データの取得やプログラム実行において損害等が生じた場合は、筆者は一切の責任も負いません。全て自己責任でお願いします。
実行形式(exe)ファイルとソースコード一式のアーカイブは下記よりダウンロードして下さい。
ダウンロード
2.ソースコード 作成したプログラムは、東京電力 - 電力使用状況 (poweruse.exe)です。起動すると、 最新の使用率(%)をゲージグラフで表示します。使用率は、実績値 / 供給力で表されます。 グラフボタンをクリックすると、使用量の時間帯別推移をグラフ化して表示します。1時間単位ですので、〇〇時台の実績となり、 1時間前の状況となります。下記の画面は、この記事を作成する前に取得したもので、画面下のグラフは24時間の推移がどんな風にグラフ化 されるのを見せるために、過去のデータから参考としてグラフ化したものです。
尚、poweruse.exeを実行させるには、設定情報の保存にSQLite3を利用していますので、同一フォルダに SQLite3.dllが必要です。ダウンロードアーカイブに同梱しています。 ソースコードは、下記の通りです。コードの前半部分は、画面の描画や移動などに必要なAPIやグラフ描画のためのモジュールを定義 しています。起動すると、電力使用状況のサイトページにアクセスして、一旦ページ全体を取得しバッファに格納します。 取得先ページは、予め取得し易いようにテキスト形式のカンマ区切りとしてデータが掲載されています。 取得できたら、現在の時間から、最新のデータに更新されている行を取得後、改行コードを変換します。 取得データを分解して配列に格納したら、ゲージグラフを描画します。ゲージグラフは「アナログ時計」の 針の位置を描画するルーチンの応用で270°を 0(基点)として計算しています。以下、その状態でタイマー割り込みで10分単位に サイトにアクセスして更新データを取得していきます。
グラフボタンをクリックすると、使用時間帯別の棒グラフを描画します。 グラフのデータは、取得データを事前に配列に格納してあるので、配列から読み込みます。 グラフ描画に関しては、特別なモジュールなどがないので、縦軸、横軸のサイズ(線の長さ)から グラフが収まるように計算しています。ポイントは、縦軸のスケールの決め方です。 データの最大値を6000(万kw) として、目盛の刻み単位を500に定めて13段階に区分しています。 横軸は、0~23時までの24時間として横軸目盛を刻んでいます。 グラフの描画開始位置を決めて、boxf命令で描画させています。 縦軸スケールをデータの値によって自動で調整できるようなモジュールがあれば楽なのですが、 うまく作成できませんでした。
;**************************************************************************** ;* ;* 東京電力 - 電力使用状況 (poweruse.hsp) Ver1.0 ;* ;* <処理の概要> ;* 本プログラムは、東京電力パワーグリッドにて提供している電力使用状況 ;* のデータを取得して、当日実績の使用率等を表示するものである。 ;* また、使用量の時間帯別推移をグラフ化して表示する。 ;* ;* ;* ●東京電力 - でんき予報 ;* URL : https://www.tepco.co.jp/forecast/index-j.html ;* https://www.tepco.co.jp/forecast/html/images/juyo-j.csv ;* ;* ●過去の実績データ ;* https://www.tepco.co.jp/forecast/html/images/juyo-2016.csv ;* https://www.tepco.co.jp/forecast/html/images/juyo-2017.csv ;* https://www.tepco.co.jp/forecast/html/images/juyo-2018.csv ;* https://www.tepco.co.jp/forecast/html/images/juyo-2019.csv ;* https://www.tepco.co.jp/forecast/html/images/juyo-2020.csv ;* ;* ;* ●モジュール(mod_jcode.hsp) ;* むしゃぺらりさんのモジュールを利用させて頂きました。 ;* http://www.setsuki.com/ ;* ;* ;**************************************************************************** #include "sqlele.hsp" ;***** 実行ファイル自動作成 (追加) **** #packopt type 0 #packopt name "poweruse" #packopt runtime "hsprt" #packopt manifest "app.manifest" #packopt icon "script.ico" #packopt hide 1 #pack "batsu4.png" #pack "powerbtn.png" #pack "gage.png" ;***** 線(line)の太さを変更 ***** #define pLine(%1=0, %2=0, %3=ginfo_cx, %4=ginfo_cy, %5=1) _pLine %1, %2, %3, %4, %5 #module #uselib "gdi32.dll" #func CreatePen "CreatePen" int, int, int #func SelectObject "SelectObject" int,int #func Polyline "Polyline" int, var, int #func DeleteObject "DeleteObject" int #define ctype RGB(%1,%2,%3) ((%3*65536)+(%2*256)+%1) #deffunc _pLine int _ex, int _ey, int _sx, int _sy, int _size CreatePen 0, _size, RGB(ginfo_r, ginfo_g, ginfo_b) hPen = stat if( stat == 0 ){ dialog "ペン設定に失敗しました。" return 1 } dim p, 4 p = _ex, _ey, _sx, _sy SelectObject hdc, hPen hOldPen = stat Polyline hdc, p, 2 if( stat == 0 ){ dialog "描画に失敗しました。" return 1 } DeleteObject hPen SelectObject hdc, hOldPen pos _ex, _ey return 0 #global ;***** 複数ウィンドウ判定用 ***** #module #deffunc _ginfo int prm1 prmx@=ginfo(prm1*2) prmy@=ginfo(prm1*2+1) return #global ;***** カーソルの形状を変更 ***** #module #uselib "user32.dll" #func LoadCursorFromFile "LoadCursorFromFileA" var #func LoadCursor "LoadCursorA" int,int #func SetClassLong "SetClassLongA" int,int,int #func SetCursor "SetCursor" int #define IDC_ARROW $00007F00 #deffunc chengecur int prm1,str prm2,int prm3 UserMode = prm1 : if UserMode<0 : return -1 sdim Curfname,260 Curfname = prm2 ;カーソルファイル名 resourceID = prm3 ;リソースID (0~ ;UserMode=$200 でカーソルファイル名が設定されていた場合は、 ;ユーザーカーソルを設定 if (UserMode==$200)&(strlen(Curfname)!0) { LoadCursorFromFile varptr(Curfname) hcurwnd=stat SetClassLong hwnd,-12,hcurwnd SetCursor hcurwnd sdim Curfname,0 return 0 } ;リソースIDに対応するカーソルを設定 (object Mode) (ID=0~28) hinst=0 : lpszCursor=IDC_ARROW if resourceID>=5 : resourceID+=123 LoadCursor hinst,resourceID+lpszCursor hcurwnd=stat ;if UserMode==$100 { ; hCld=hwnd ; }else{ hCld=objinfo(UserMode,2) ;} SetClassLong hCld,-12,hcurwnd SetCursor hcurwnd sdim Curfname,0 return 0 #global #module #uselib "kernel32.dll" #cfunc CreateMutex "CreateMutexA" int,int,sptr #cfunc GetLastError "GetLastError" ;***** 二重起動防止 ***** #deffunc wexapend str prm1 strname=prm1 ;***** 名前の文字列が省略された場合 ***** if strlen(strname)==0 : strname="HSP340ONIWND" ;Default String ret=CreateMutex(0,1,strname) ;二重起動か? if GetLastError()==0 : return 0 ;同じジョブが起動していない if GetLastError()==183 : return 1 ;既に起動している return -1 #global #module #deffunc strdigit str prm1,int prm2 ;************************************* ; prm1 : 数値文字列(文字列型) ; prm2 : 最大桁数(整数値) ;************************************* sPrm =prm1 iLenInteger=strlen(sPrm) MaxLen=prm2 : if MaxLen<0 : MaxLen=iLenInteger+3 sInteger=sPrm sTarget="" if iLenInteger<=3 : sTarget=sInteger : ref=sTarget : return -1 iFirst=iLenInteger¥3 : if iFirst==0: iFirst=3 sTarget=strmid(sInteger,0,iFirst) ;***** 三桁毎にカンマを付加 ***** repeat (iLenInteger-1)/3 sTarget+="," : sTarget+=strmid(sInteger, cnt*3+iFirst, 3) loop ;***** 右揃えルーチン (最大桁数の変数MaxLenを渡す) ***** dspsize=strlen(sTarget) if dspsize<MaxLen { repeat MaxLen-dspsize : sTarget=" "+sTarget : loop } return sTarget #global #uselib "user32.dll" #func GetWindowRect "GetWindowRect" int,int #func GetSystemMetrics "GetSystemMetrics" int #func MoveWindow "MoveWindow" int,int,int,int,int,int #func SetWindowLong "SetWindowLongA" int , int , int #cfunc GetWindowLong "GetWindowLongA" int , int #define global GWL_STYLE 0xFFFFFFF0 #define global WS_SYSMENU 0x00080000 #define global WS_MAXIMIZEBOX 0x00010000 #define global WS_MINIMIZEBOX 0x00020000 #define SM_CXSCREEN $00000000 #define SM_CYSCREEN $00000001 #define obj_wmnclbtndown sendmsg hwnd,$00A1,2,0 #define WM_CLOSE $00000010 #define g_box(%1,%2,%3,%4) line %3,%2,%1,%2 : ¥ line %3,%4,%3,%2 : ¥ line %1,%4,%3,%4 : ¥ line %1,%2,%1,%4 #func SetTimer "SetTimer" int, int, int, int #func KillTimer "KillTimer" int, int #define WM_TIMER 0x0113 #define ID_TIMER 1 #include "mod_jcode.hsp" ;***** 起動ディレクトリ取得 ***** sdim Startdir,512 if hspstat&1=0 { Startdir=dir_exe+"¥¥" : chdir dir_exe } else { Startdir=dir_cur+"¥¥" } chdir Startdir ;***** データベース存在確認 ***** exist Startdir+"setting¥¥poweruse.ini" if strsize ==-1 { dialog "データベースファイルが見つかりません。",0 : end } await wexapend "poweruse" : if stat : end ;***** データベースオープン ***** sql_open Startdir+"setting¥¥poweruse.ini" ;***** 画面表示位置設定 ***** sql_q "SELECT * FROM TValu WHERE ID = "+1 xpos=sql_i("wxpos") : ypos=sql_i("wypos") if (xpos<0 or xpos>ginfo_dispx) : xpos=0 if (ypos<0 or ypos>ginfo_dispy) : ypos=0 sql_close buffer 2,11,11,0 : picload "batsu4.png",0 buffer 3,80,20,0 : picload "powerbtn.png",0 buffer 4,79,41,0 : picload "gage.png",0 *main bgscr 0,150,170,,xpos,ypos SetWindowLong hwnd,GWL_STYLE,$B0000|GetWindowLong(hwnd,GWL_STYLE) title "電力使用状況(東京電力)" redraw 0 font "Meiryo UI",10,3 color 120,0,120 : boxf 0,0,ginfo(10),20 color 255,255,255 : pos 8,3 : mes "Power usage" color 240,240,240 : boxf 0,20,150,170 ;***** 閉じる( × )画像をボタンにセット ***** pos 130,5 : objsize 11,11 : objimage 2,0,0,0,11 : button "",*owari pos 15,146: objsize 40,20 : objimage 3,0,0,40,20 : button "",*mode01 ;更新 pos 56,146: objsize 40,20 : objimage 3,40,0,40,20 : button "",*mode02 ;確認 pos 97,146: objsize 40,20 : objimage 3,80,0,40,20 : button "",*mode03 ;グラフ chengecur 0,"",14 pos 37,90 : gmode 2 : gcopy 4,0,0,79,41 redraw 1 onexit *owari onclick gosub *move ReturnHTML="" ;***** 東京電力電力使用状況のURLを指定 ***** sURL = "https://www.tepco.co.jp/forecast/html/images/juyo-j.csv" charcode = "UTF-8" newcom objXMLHTTP, "Microsoft.XMLHTTP" objXMLHTTP->"Open" "GET", sURL, 0 objXMLHTTP->"Send" if objXMLHTTP("status") = 200 { newcom objRS,"ADODB.Stream" if stat!0 : dialog "ADODB.Streamがサポートされていません。",0 : end objRS("Type") = 1 objRS->"Open" sHtml=objXMLHTTP("ResponseBody") objRS->"Write" sHtml objRS("Position") = 0 objRS("Type") = 2 objRS("Charset") = charcode ReturnHTML=objRS("ReadText") objRS->"Close" buf = "" : tempstr = "" ;***** 改行コードを変換 ***** toCRLF buf,ReturnHTML notesel buf gosub *gyopos ;***** 現在時間の1時間前が取得対象行 ***** if M_time<10 : gyou-=1 sdim data,128 : sdim update,48 noteget update,0 ;更新日付・時間 noteget data,gyou-1 ;本日の電力使用状況 ;******************************************************** ;* 本日の電力使用状況 ;* DATE,TIME,当日実績(万kW),予測値(万kW),使用率(%) ;* 2018/6/13,19:00,3507,0,76 ;******************************************************** notepos = 0 : sdim tempbuf,32 : sdim resvName,24,5 ;***** 取得データを分解して配列に格納 ***** repeat 5 getstr tempbuf,data,notepos,',' : notepos+=strsize resvName(cnt)=tempbuf loop ;▼▼▼▼▼ 実績グラフ作成用の24時間分のデータを取得 ▼▼▼▼▼ ;***** 24時間分のデータを取得して配列に格納 ***** gyou = 8 sdim data,500 notepos = 0 : sdim tempbuf,32 : dim value,24 ;***** 取得データを分解して配列に格納 ***** i = 0 : p = 0 repeat 24 noteget data,gyou repeat 3 getstr tempbuf,data,notepos,',' : notepos+=strsize if p==2 : value(i)=int(tempbuf) p++ loop i++ : p = 0 : notepos = 0 : gyou++ : tempbuf = "" loop ;***** 取得データの表示 ***** font "Meiryo UI",12,1 ls= strlen(resvName(1)) if ls==4 { dsp = strmid(resvName(1),0,1)+"時台実績" }else{ dsp = strmid(resvName(1),0,2)+"時台実績" } color 24,24,24 : boxf 6,24,74,42 color 255,255,0 : pos 8,26 : mes dsp strdigit resvName(2),4 font "Arial",12,1 color 0,0,200 : boxf 78,24,116,42 color 255,255,255 : pos 82,26 : mes refstr font "Meiryo UI",10,1 color 0,0,255 : pos 118,27 : mes "万kW" font "Meiryo UI",9,1 color 64,64,64 : pos 10,48 : mes update ;***** 使用率の色分け設定 ***** if int(resvName(4))<93 : color 0,180,0 if (int(resvName(4))>93) & (int(resvName(4))<95) : color 242,210,0 if (int(resvName(4))>95) & (int(resvName(4))<97) : color 255,128,0 if int(resvName(4))>97 : color 255,0,0 ;***** 使用率表示 ***** font "Arial",16,1 pos 64,68 : mes resvName(4) font "Meiryo UI",12,1 : pos 84,70 : mes "%" r = 30.0 kd=double(int(resvName(4)))*double(1.8)+double(180) rad=deg2rad(kd) Y = r*sin(rad) X = r*cos(rad) color 0,180,0 redraw 0 : pLine 150/2+1,128,X+150/2+1,Y+129,3 : redraw 1 }else{ font "Meiryo UI",16,1 color 240,240,240 : boxf 0,20,150,170 color 230,0,0 : pos 40,50 : mes "取得失敗!" } delcom objXMLHTTP gsel 0,1 ;***** 10min毎に更新 ***** oncmd gosub *OnTimer, WM_TIMER SetTimer hwnd, ID_TIMER, 600*1000, 0 stop *maru circle 30,66,120,136,1 color 240,240,240 : circle 35,71,115,131,1 return *OnTimer ;***** タイマー ***** goto *main return *mode01 ;***** 手動更新 ***** goto *main stop *mode02 ;***** 東京電力電力使用量サイト確認 ***** exec "https://www.tepco.co.jp/forecast/index-j.html",16 stop *mode03 ;***** 東京電力電力使用量実績グラフ ***** ;***** 画面表示位置設定 ***** sql_open Startdir+"setting¥¥poweruse.ini" sql_q "SELECT * FROM SValu WHERE ID = "+1 px=sql_i("pxpos") : py=sql_i("pypos") sql_close screen 5,500,300,,px,py title "東京電力 - 電力使用量実績グラフ" basex = 50 ;グラフ描画基準位置 basey = 10 ;縦軸開始位置 kankau = 0 ;グラフ横軸間隔 haba = 14 ;グラフ帯幅 kaishi = 0 ;グラフ横軸描画開始位置 scale = 200 ;縦軸の基本長さ vpos = 200 ;縦軸の値の基点 endy = 250 ;横軸終端座標 vrange = 100 ;縦軸目盛の最大値 redraw 0 color 240,240,240 : boxf ;***** グラフタイトルの設定 ***** color 64,64,6 font "Meiryo UI",11,1 pos 190,272 : mes "時間帯別電力使用量実績の推移" ;***** グラフ単位の設定 ***** color 0,0,0 font "Meiryo UI",10,0 pos 55,2 : mes "(万kw)" ;縦軸単位 pos 465,270 : mes "(時)" ;横軸単位 pos 360,5 : mes update ;更新日時 ;***** 縦軸線 ***** basex = 50 : basey = 10 line basex-1,basey,basex-1,endy ;***** 縦軸目盛線とスケール名 ***** ; 縦軸の最大値 : 6000 目盛の刻み単位 : 500 とした場合 vrange = 6000 : basex = 50 : basey = 10 repeat 13 line basex-5,basey,basex-1,basey ls=strlen(str(vrange)) if ls==4 : pos 18,basey-7 if ls==3 : pos 24,basey-7 if ls==2 : pos 30,basey-7 if ls==1 : pos 34,basey-7 mes vrange basey+=20 vrange-=500 loop ;***** 横軸線 ***** basex = 50 : basey = 10 line basex,endy,vpos*2+82,endy ;***** 横軸目盛線と項目名 ***** x_pos=18 : d_pos=0 repeat 24 line basex+x_pos,endy,basex+x_pos,endy+4 ls=strlen(str(cnt+1)) if ls==1 : pos basex+6+d_pos,endy+7 if ls==2 : pos basex+4+d_pos,endy+7 mes cnt x_pos+=18 d_pos+=18 loop color 0,0,190 basex = 50 : kaishi = 2 : kankaku = 0 repeat 24 data = basex+scale-((value(cnt)/50)*2) ;***** グラフの描画位置を決める ***** stpos = basex+kaishi+kankaku endpos = basex+kaishi+haba+kankaku ;***** 棒グラフ描画 ***** color 0,0,190 boxf stpos,data,endpos,endy kankaku+=2 kaishi+=16 loop redraw 1 gsel 4,1 stop *gyopos ;***** 現在の時間から当日実績の取得行を判定 ***** H_time = gettime(4) M_time = gettime(5) switch H_time case 0 : gyou=32 : swbreak case 1 : gyou=9 : swbreak case 2 : gyou=10 : swbreak case 3 : gyou=11 : swbreak case 4 : gyou=12 : swbreak case 5 : gyou=13 : swbreak case 6 : gyou=14 : swbreak case 7 : gyou=15 : swbreak case 8 : gyou=16 : swbreak case 9 : gyou=17 : swbreak case 10: gyou=18 : swbreak case 11: gyou=19 : swbreak case 12: gyou=20 : swbreak case 13: gyou=21 : swbreak case 14: gyou=22 : swbreak case 15: gyou=23 : swbreak case 16: gyou=24 : swbreak case 17: gyou=25 : swbreak case 18: gyou=26 : swbreak case 19: gyou=27 : swbreak case 20: gyou=28 : swbreak case 21: gyou=29 : swbreak case 22: gyou=30 : swbreak case 23: gyou=31 : swbreak swend return *owari ;***** 終了処理 ***** _ginfo 1 if prmx==5 { ;***** 終了位置を保存 ***** gsel 5,0 sql_open Startdir+"setting¥¥poweruse.ini" px=str(ginfo_wx1) ; 現在の画面左上 X 座標取得 py=str(ginfo_wy1) ; 現在の画面左上 y 座標取得 sql_q "UPDATE SValu SET pxpos=" + prm_text(px) + ", pypos=" + prm_text(py)+ " WHERE ID="+1 sql_close gsel 5,-1 : gsel 0 : stop } if prmx==0 { gsel 0,0 await KillTimer hwnd, ID_TIMER sql_open Startdir+"setting¥¥poweruse.ini" wx=str(ginfo_wx1) ; 現在の画面左上 X 座標取得 wy=str(ginfo_wy1) ; 現在の画面左上 y 座標取得 ;***** 終了位置を保存 ***** sql_q "UPDATE TValu SET wxpos=" + prm_text(wx) + ", wypos=" + prm_text(wy)+ " WHERE ID="+1 sql_close end } end *move ;***** マウスの左クリックボタンで移動 ***** if wparam == 1 { obj_wmnclbtndown ;***** 画面終端位置の取得と制御 ***** dim rc,4 GetWindowRect hwnd,varptr(rc) w = rc(2)-rc(0) h = rc(3)-rc(1) GetSystemMetrics SM_CXSCREEN : CSX=stat GetSystemMetrics SM_CYSCREEN : CSY=stat if rc(0)<0 : rc(0)=0 if rc(1)<0 : rc(1)=0 if rc(2)>CSX : rc(0)=CSX-w if rc(3)>CSY : rc(1)=CSY-h-30 MoveWindow hwnd,rc(0),rc(1),w,h,1 } return
3.ダウンロード 提供するソースコードのライセンスは、CC0 (クレジット表示不要、改変可、商用可) とします。自由に利用して頂いてかまいません。 尚、データの取得やプログラム実行において損害等が生じた場合は、筆者は一切の責任も負いません。全て自己責任でお願いします。
実行形式(exe)ファイルとソースコード一式のアーカイブは下記よりダウンロードして下さい。
ダウンロード
コメント
コメントを投稿