前回の記事では、ポータブル電源自動充電システムに必要な EcoFlow IoT Developer Platform(開発者プラットフォーム)の署名生成について解説しました。
今回からは、作成した署名を利用して実際に開発者プラットフォーム(API)との通信を行っていきます。
本記事では、アカウントに紐づいているデバイスリストを取得するコードをご紹介します。
デバイスリストを取得することで、開発者プラットフォーム(API)を経由して自宅のポータブル電源と通信できていることの確認ができるかと思います。
ちなみにポータブル電源自動充電システムのシステム構成とメリット・デメリットについては、以下の記事で紹介しています。
EcoFlow IoT Developer Platform(開発者プラットフォーム)とは
EcoFlow IoT Developer Platform(開発者プラットフォーム)はざっくり言うと、プログラム上からポータブル電源の情報を取得したり、ポータブル電源の設定を変更する操作を行えるようにするためのサービスです。
開発者プラットフォームを利用するためには、開発者になるための申請を行い、アクセスキーとシークレットキーを発行する必要があります。
まだの方は以下の記事をご覧ください。
デバイスリストの取得
デバイスリストとは、ご自身のアカウントに紐づいているポータブル電源など、EcoFlowの機器の一覧のことです。
以降の手順でデバイスリストの取得に成功すると、取得結果のレスポンスデータにポータブル電源のシリアルナンバーと名称がありますので、シリアルナンバーと名称が間違いなく自宅のポータブル電源と一致していることを確認してください。
公式ドキュメント
まずは公式ドキュメントのページを確認してみましょう。
Query the user’s bound device list
EcoFlow IoT Developer Platform – generalInfo
デバイスリストを取得するためのリクエスト情報は、以下となっています。
必要なパラメータなどはなく、単純にURLに対してリクエストすればOKです。
Key | Value |
Method | GET |
URL | https://${host}/iot-open/sign/device/list |
Content-Type | none |
Request Body | none |
サンプルコードは以下となっていますが、こちらはコマンドで実行する場合のサンプルとなっています。
(Google Apps Script(GAS)で利用する場合のコードは後述します)
// request
curl -X GET https://api-e.ecoflow.com/iot-open/sign/device/list \
-H 'accessKey:OCHzRuj6NLF7o43***' \
-H 'timestamp:1681796503289' \
-H 'nonce:234762' \
-H 'sign:f560c3e31d96ad31e4567939f9b3dca7b2c454ca7003f60***'
// response
{
"code":"0",
"message":"Success",
"data":[
{
"sn":"DCABZ****",
"online":1
}
]
}
Google Apps Script(GAS)でコーディング
では実際にコードを書いてみましょう。
最終的なコードは以下になります。
function ecoflowDeviceList() {
// ① リクエストURL
const host = "https://api-e.ecoflow.com";
const requestUrl = host + "/iot-open/sign/device/list";
// ② アクセスキーとシークレットキー
const accessKey = "※開発者プラットフォームで発行したアクセスキー";
const secretKey = "※開発者プラットフォームで発行したシークレットキー";
// ③ nonceとタイムスタンプを生成
let nonce = String(Math.floor(Math.random() * 900000) + 100000);
let timestamp = String((new Date).getTime());
// ④ 署名用パラメータ
let signParam = "accessKey=" + accessKey + "&nonce=" + nonce + "×tamp=" + timestamp;
// ⑤ 暗号化して16進文字列に変換
let signature = Utilities.computeHmacSha256Signature(signParam, secretKey);
let sign = signature.reduce(function(str,chr){
chr = (chr < 0 ? chr + 256 : chr).toString(16);
return str + (chr.length==1?'0':'') + chr;
},'');
// ⑥ リクエストヘッダー
let requestHeaders = {
'accessKey': accessKey
,'timestamp': timestamp
,'nonce': nonce
,'sign':sign
}
// ⑦ リクエストオプション
let requestOptions = {
"method" : "GET",
"headers" : requestHeaders,
"muteHttpExceptions" : true
}
// ⑧ API実行(開発者プラットフォームへのリクエスト)
let response = UrlFetchApp.fetch(requestUrl, requestOptions);
// ⑨ 結果(レスポンス)を取得
let responseCode = response.getResponseCode();
let responseText = response.getContentText();
// ⑩ ログ出力
Logger.log("responseCode=" + responseCode);
Logger.log(JSON.stringify(JSON.parse(responseText), null, 2));
}
コードの解説
コードの内容をそれぞれ解説していきます。
// ① リクエストURL
const host = "https://api-e.ecoflow.com";
const requestUrl = host + "/iot-open/sign/device/list";
EcoFlow IoT Developer Platform(開発者プラットフォーム)にリクエストするためのURLを定義しています。
開発者プラットフォーム(API)のホスト名はhttps://api-e.ecoflow.comです。
そこに今回取得したいデバイスリストのURL:/iot-open/sign/device/listを組み合わせて、最終的なURLを作っています。
https://api-e.ecoflow.com/iot-open/sign/device/list
// ② アクセスキーとシークレットキー
const accessKey = "※開発者プラットフォームで発行したアクセスキー";
const secretKey = "※開発者プラットフォームで発行したシークレットキー";
EcoFlow IoT Developer Platform(開発者プラットフォーム)から発行した、ご自身のアクセスキーとシークレットキーをここに設定してください。
今回はわかりやすいようにアクセスキーとシークレットキーを直接ソースコードに記載していますが、本来はセキュリティを考慮し、アクセスキーやシークレットキーはソースコードと別で管理することをお勧めします。
Google Apps Script(GAS)のプロパティサービス等の利用を検討してください。
まだアクセスキーとシークレットキーを発行していないようであれば、以下の記事を参考に発行してください。
// ③ nonceとタイムスタンプを生成
let nonce = String(Math.floor(Math.random() * 900000) + 100000);
let timestamp = String((new Date).getTime());
③ではnonceとtimestampの作成を行っています。
順に見ていきましょう。
- Code1Math.random()
Math.random()では 0~1未満 の乱数が生成されます。
- Code2Math.floor(Math.random() * 900000)
上記Code1で採番した乱数(0~1未満)に 900000 を掛けることで、0~900000未満 の値となります。
Math.floor()では小数点以下を切り捨てています。
結果手として、ここでは 0~899999 の乱数が作り出されます。 - Code3Math.floor(Math.random() * 900000) + 100000
上記Code2で出来た 0~899999 の乱数に対して、100000を足しています。
これで値としては 100000~999999 となり nonceとして欲しい6桁の整数となります。 - Code4String(Math.floor(Math.random() * 900000) + 100000)
最後にString()で文字列に変換してnonceは完成です。
nonceの採番(生成)方法については、必ずしも上記の実装である必要はありません。
ようは6桁数整数文字列が作成できれば良いので、他のやり方でも構いません。
- Code1new Date
システム日時(現在日時)で日付オブジェクトを作成しています。
- Code2(new Date).getTime()
上記Code1で作成した日付オブジェクトに対してgetTime()することで、システム日時(現在日時)のミリ秒を取得しています。
- Code3String((new Date).getTime())
最後にString()で文字列に変換してtimestampは完成です。
- Qnonceとは?
- A
nonceとは、ノンス/ナンスと呼ばれます。
API呼び出し時に一度だけ有効な任意の値(乱数)になります。
開発者プラットフォームではnonceとして 6桁の整数文字列 が必要です。
セキュリティ保護のためにAPIにリスエストする都度、新たな乱数を採番します。
- Qtimestampとは?
- A
名前の通りタイムスタンプ(現在日時)になります。
1970年1月1日00:00:00UTCからの経過ミリ秒数を設定します。
// ④ 署名用パラメータ
let signParam = "accessKey=" + accessKey + "&nonce=" + nonce + "×tamp=" + timestamp;
④では署名生成用のパラメータ文字列を作成しています。
デバイスリストを取得するリクエストでは特にパラメータとして渡さないといけない情報はありません。
ですので、署名用のパラメータとしてはお決まり(固定)の以下パラメータのみを単純に文字列として連結しています。
- アクセスキー(accesskey)
- ナンス/ノンス(nonce)
- タイムスタンプ(timestamp)
// ⑤ 暗号化して16進文字列に変換
let signature = Utilities.computeHmacSha256Signature(signParam, secretKey);
let sign = signature.reduce(function(str,chr){
chr = (chr < 0 ? chr + 256 : chr).toString(16);
return str + (chr.length==1?'0':'') + chr;
},'');
ここでは署名用パラメータを暗号化して、署名(署名値)を作成しています。
以前の記事でも記載していますが、この部分の実装は難解ですので、一旦はお決まりとして「こういうものなんだなー」と思っていただければOKだと思います。
// ⑥ リクエストヘッダー
let requestHeaders = {
'accessKey': accessKey
,'timestamp': timestamp
,'nonce': nonce
,'sign':sign
}
EcoFlow IoT Developer Platform(開発者プラットフォーム)にリクエストするためのHTTPヘッダーを作成しています。
開発者プラットフォームではHTTPヘッダーに以下を設定してAPIを呼び出すルール(仕様)になっています。
- アクセスキー(accesskey)
- タイムスタンプ(timestamp)
- ナンス/ノンス(nonce)
- 署名(sign)
// ⑦ リクエストオプション
let requestOptions = {
"method" : "GET",
"headers" : requestHeaders,
"muteHttpExceptions" : true
}
こちらはリクエストのオプション設定になります。
オプションとして必須なのは以下のみです。
- method
デバイスリストの取得リクエストではGETを指定するルール(仕様)です。 - headers
⑥で作成したHTTPヘッダーを指定します。
他、以下の指定はおまけ程度です(とりあえず無くても動くと思います)
- muteHttpExceptions
trueを指定することで、HTTPリクエスト時のエラー(例外)を抑制するオプションです。
※すべての例外を抑制できるわけではないという事と、例外が発生しないだけでエラー処理が不要になる訳では無い(本来は適切にエラー処理が必要)というところは注意が必要です。
// ⑧ API実行(開発者プラットフォームへのリクエスト)
let response = UrlFetchApp.fetch(requestUrl, requestOptions);
ここでは実際にAPI(開発者プラットフォームへのリクエスト)の実行を行っています。
ここまでで作成したリクエストURLとリクエスト用のオプションを指定して、UrlFetchApp.fetch()を呼び出すことで、実際の通信が行われ、結果のレスポンスがresponse(変数)に格納されます。
// ⑨ 結果(レスポンス)を取得
let responseCode = response.getResponseCode();
let responseText = response.getContentText();
デバイスリストの取得結果(レスポンス)にはHTTPステータスとデバイス一覧情報が格納されています。
ここではHTTPステータスとデバイス一覧情報をそれぞれ変数に格納しているだけですね。
// ⑩ ログ出力
Logger.log("responseCode=" + responseCode);
Logger.log(JSON.stringify(JSON.parse(responseText), null, 2));
⑧、⑨で取得したHTTPステータスとデバイス一覧情報をそれぞれログに出力しています。
おまけ程度ですがデバイス一覧情報については、JSON.parse()、JSON.stringify()、を介すことで整形された形でログ出力しています。
コード実行
コーディングを行ったら、変更を保存(フロッピーのアイコンをクリック)してから実行してみてください。
以下のような結果がレスポンスとして返ってくると思います。
{
"code": "0",
"message": "Success",
"data": [
{
"sn": "**************",
"deviceName": "**************",
"online": 1,
"productName": "DELTA 2 Max"
}
],
"eagleEyeTraceId": "****************************",
"tid": ""
}
我が家ではポータブル電源1台だけですが、複数台のポータブル電源や他のエコフロー製品を台保有している方であれば、開発者プラットフォーム(API)の結果として複数のリストが返ってくると思います。
- Q実行時に「認証が必要です」「このアプリはGoogleで確認されていません」といったセキュティの警告が表示される場合は?
- A
Google Apps Script(GAS)では、プログラムの初回実行時などに「認証が必要です」や「このアプリはGoogleで確認されていません」といったセキュリティの警告が出ることがあります。
今回のソースコードでは、外部サービス(EcoFlow開発者プラットフォーム)に接続しようとしているため、その外部サービスに接続して本当に大丈夫ですか?安全ですか?とGoogleから確認されている状態です。
あなた自身がソースコードを理解し、外部サービス(EcoFlow開発者プラットフォーム)に接続して問題ないと判断したのであれば以下の手順に従って、プログラムの実行を承認(許可)してください。
脅すわけではありませんが、これはセキュリティ警告です。
記事に記載してあるソースコードを鵜呑みにせず、必ずご自身で理解し、問題ないことを確認の上で『承認(許可)』の操作をお願いします。
以下、それぞれご自身のポータブル電源の情報と一致していることを確認しましょう。
- sn:シリアルナンバー
- deviceName:デバイス名称
- productName:製品名
ご自身のポータブル電源のシリアルナンバーとデバイス名称は、スマホアプリ上で確認することが出来ます。
まとめ
お疲れ様でした。
これで開発者プラットフォーム(API)とご自身のポータブル電源との間で間違いなく通信できているということが確認できたかと思います。
次回はEcoFlow IoT Developer Platform(開発者プラットフォーム)を利用して、ポータブル電源のリアルタイム情報を取得する方法を記載していければと思っています。
ポータブル電源のバッテリー残量や充電状況などが取得できるので、次回からはやっと本格的な感じになっていくかなと思います。