Zum Inhalt

powerwall.tc

Powerwall — Tesla Powerwall API access

Source on GitHub

// Powerwall — Tesla Powerwall API access
// Replicates the Scripter powerwall_script.tas
// Queries battery %, power flow, capacity
//
// Requires: TESLA_POWERWALL enabled in firmware build

// ─── Powerwall data (shared via UDP) ───
global float pwl  = 8.0;    // battery percentage
global float sip  = 0.0;    // site/grid import power (W)
global float sop  = 0.0;    // solar output power (W)
global float bip  = 0.0;    // battery import power (W)
global float hip  = 0.0;    // home/load power (W)
global float tcap = 0.0;    // total capacity (Wh)
global float rcap = 0.0;    // remaining capacity (Wh)
global float rper = 0.0;    // reserve percent

global float phs1 = 0.0;    // grid phase 1
global float phs2 = 0.0;    // grid phase 2
global float phs3 = 0.0;    // grid phase 3

global float p1w = 0.0;    // solar power phase 1
global float p2w = 0.0;    // solar power phase 2
global float p3w = 0.0;    // solar power phase 3

// State
int cnt = 0;
char buf[128];

// Background task — one request per cycle, long delay between
void TaskLoop() {
    // Initial delay to let system stabilize
    delay(10000);

    while (1) {
        if (cnt == 0) {
            int res = pwlRequest("/api/meters/aggregates");
            if (res == 0) {
                sip = pwlGet("site#instant_power");
                bip = pwlGet("battery#instant_power");
                hip = pwlGet("load#instant_power");
                sop = pwlGet("solar#instant_power");
                printStr("agg ok\n");
            }
        }
        if (cnt == 1) {
            int res = pwlRequest("/api/system_status/soe");
            if (res == 0) {
                pwl = pwlGet("percentage");
            }
        }
        if (cnt == 2) {
            int res = pwlRequest("/api/system_status");
            if (res == 0) {
                tcap = pwlGet("nominal_full_pack_energy");
                rcap = pwlGet("nominal_energy_remaining");
            }
        }
        if (cnt == 3) {
            int res = pwlRequest("/api/operation");
            if (res == 0) {
                rper = pwlGet("backup_reserve_percent");
            }
        }
        if (cnt == 4) {
            // Per-panel readings — CTS2 grid phases are occurrences 6,7,8 of "p_W"
            int res = pwlRequest("/api/meters/readings");
            if (res == 0) {
                phs1 = pwlGet("p_W[6]");
                phs2 = pwlGet("p_W[7]");
                phs3 = pwlGet("p_W[8]");
                sprintf(buf, "phases: %.0f", phs1);
                printString(buf);
                sprintf(buf, " %.0f", phs2);
                printString(buf);
                sprintf(buf, " %.0f\n", phs3);
                printString(buf);
                p1w = pwlGet("p_W[2]");
                p3w = pwlGet("p_W[4]");             

            } else {
                sprintf(buf, "readings FAILED res=%d\n", res);
                printString(buf);
            }
        }

        cnt = cnt + 1;
        if (cnt > 4) {
            cnt = 0;
        }

        // 60 second delay between requests — gives web server lots of time
        delay(60000);
    }
}

void EverySecond() {
    // Only print status — no blocking calls here
    if (tasm_uptime % 30 == 0) {
        sprintf(buf, "PWL: Bat=%.1f%%", pwl);
        printString(buf);
        sprintf(buf, " Grid=%.0fW", sip);
        printString(buf);
        sprintf(buf, " Sol=%.0fW", sop);
        printString(buf);
        sprintf(buf, " Home=%.0fW\n", hip);
        printString(buf);
    }
}

void WebCall() {
    sprintf(buf, "{s}Battery{m}%.1f %%{e}", pwl);
    webSend(buf);
    sprintf(buf, "{s}Grid{m}%.0f W{e}", sip);
    webSend(buf);
    sprintf(buf, "{s}Solar{m}%.0f W{e}", sop);
    webSend(buf);
    sprintf(buf, "{s}Battery Power{m}%.0f W{e}", bip);
    webSend(buf);
    sprintf(buf, "{s}Home{m}%.0f W{e}", hip);
    webSend(buf);
    sprintf(buf, "{s}Total Capacity{m}%.1f kWh{e}", tcap / 1000.0);
    webSend(buf);
    sprintf(buf, "{s}Remaining{m}%.1f kWh{e}", rcap / 1000.0);
    webSend(buf);
    sprintf(buf, "{s}Reserve{m}%.0f %%{e}", rper);
    webSend(buf);

    sprintf(buf, "{s}Solar Phase 1{m}%.0f W{e}", p1w);
    webSend(buf);
    sprintf(buf, "{s}Solar Phase 2{m}%.0f W{e}", p2w);
    webSend(buf);

    sprintf(buf, "{s}Phase 1{m}%.0f W{e}", phs1);
    webSend(buf);
    sprintf(buf, "{s}Phase 2{m}%.0f W{e}", phs2);
    webSend(buf);
    sprintf(buf, "{s}Phase 3{m}%.0f W{e}", phs3);
    webSend(buf);
    sprintf(buf, "{s}Heap{m}%d kb{e}", tasm_heap / 1024);
    webSend(buf);
}

void JsonCall() {
    sprintf(buf, ",\"PWL\":{\"Battery\":%.1f", pwl);
    responseAppend(buf);
    sprintf(buf, ",\"Grid\":%.0f", sip);
    responseAppend(buf);
    sprintf(buf, ",\"Solar\":%.0f", sop);
    responseAppend(buf);
    sprintf(buf, ",\"BattPwr\":%.0f", bip);
    responseAppend(buf);
    sprintf(buf, ",\"Home\":%.0f}", hip);
    responseAppend(buf);
}

int main() {
    // Configure Powerwall connection
    pwlRequest("@D<POWERWALL_IP>,<TESLA_EMAIL>,<TESLA_PASSWORD>");
    pwlRequest("@C<CTS1_SERIAL>,<CTS2_SERIAL>");

    printStr("Powerwall monitor started\n");
    return 0;
}