SwitchBotAPI icon indicating copy to clipboard operation
SwitchBotAPI copied to clipboard

I want to output past plug mini data.

Open Ritsu-Kobayashi opened this issue 1 year ago • 2 comments

Current Situation

I want to output historical data from plug mini to a google spreadsheet, but it doesn't work because I get an error that I can't get the device ID.

If the code is incorrect, I would appreciate it if you could rewrite it. I will also share tokens and secrets if needed.

Logs

19:13:09	お知らせ	実行開始
19:13:05	情報	❌ SwitchBot APIエラー: {"statusCode":190,"body":{},"message":"wrong deviceId"}
19:13:10	お知らせ	実行完了

Configuration

// STEP1: 認証情報設定
const token = PropertiesService.getScriptProperties().getProperty("SWITCHBOT_API_TOKEN");
const secret = PropertiesService.getScriptProperties().getProperty("SWITCHBOT_API_SECRET");
const baseURL = "https://api.switch-bot.com/v1.1";

// STEP2: 認証パラメータを取得
function getAuthParams() {
    const t = Date.now().toString();
    const nonce = Utilities.getUuid();
    const data = token + t + nonce;
    const sign = Utilities.base64Encode(Utilities.computeHmacSha256Signature(data, secret)).toUpperCase();

    return { t, nonce, sign };
}

// STEP3: プラグのステータスを取得
function getDeviceStatus(deviceId) {
    const { t, nonce, sign } = getAuthParams();

    const headers = {
        "Authorization": token,
        "sign": sign,
        "nonce": nonce,
        "t": t,
    };

    const options = {
        "method": "GET",
        "headers": headers,
        "muteHttpExceptions": true,
    };

    const response = UrlFetchApp.fetch(baseURL + "/devices/" + deviceId + "/status", options);
    const data = JSON.parse(response.getContentText());

    // APIエラー処理
    if (data["message"] !== "success") {
        Logger.log("❌ SwitchBot APIエラー: " + JSON.stringify(data));
        return null;
    }

    return data;
}

// STEP4: スプレッドシートにデータを記録
function appendPowerConsumptionDataToSheet() {
    const deviceId = PropertiesService.getScriptProperties().getProperty("SWITCHBOT_API_DEVICEID");
    const data = getDeviceStatus(deviceId);

    if (!data) {
        return; // エラー時は処理終了
    }

    const d = new Date();
    const power = data["body"]["power"];
    const current = data["body"]["electricCurrent"];
    const voltage = data["body"]["voltage"];

    const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
    const sheet = spreadsheet.getActiveSheet();

    // 初回:列タイトルを1行目に挿入
    if (sheet.getRange("A1").getValue() === "") {
        sheet.getRange("A1:D1").setValues([["日時", "電源状態", "電流 (mA)", "電圧 (V)"]]);
    }

    // 2行目にデータ追加
    sheet.insertRowBefore(2);
    sheet.getRange("A2").setValue(d);
    sheet.getRange("B2").setValue(power);
    sheet.getRange("C2").setValue(current);
    sheet.getRange("D2").setValue(voltage);

    // 101行目以降を削除(データ上限100行に制限)
    const lastRow = sheet.getLastRow();
    if (lastRow > 100) {
        sheet.deleteRows(101, lastRow - 100);
    }
}

Environment

  • OS:Windows11
  • Software: GoogleCrohme
  • Node: python
  • npm:

Additional Context

No response

Ritsu-Kobayashi avatar Apr 09 '25 10:04 Ritsu-Kobayashi