Skip to content

Instantly share code, notes, and snippets.

@Reelix
Last active September 25, 2026 21:30
Show Gist options
  • Select an option

  • Save Reelix/72686cab818c08b2f0a2ce5cee26b82e to your computer and use it in GitHub Desktop.

Select an option

Save Reelix/72686cab818c08b2f0a2ce5cee26b82e to your computer and use it in GitHub Desktop.
Ecoflow - Get device status WITHOUT a developer account

1.) Login using Mobile App creds and get auth token (Only change Email and Password - Rest can stay the same)

curl -s -X POST "https://api.ecoflow.com/auth/login" \
-H "Content-Type: application/json" \
-d '{
"email": "email@address.com",
"password": "base64-encoded-password",
"userType": "ECOFLOW",
"os": "ios",
"scene": "IOT_APP",
"appVersion": "3.0.1",
"osVersion": "15.4.1",
"oauth": {
"bundleId": "com.ef.EcoFlow"
}
}' | jq -r '.data.token'

2.) Use Token to retrieve device info (Replace token.value.here with the long string (JWT) from the above command)

curl -s -X GET "https://api-e.ecoflow.com/iot-service/user/device" -H "Authorization: Bearer token.value.here" | jq

soc is the current battery value

Bonus (Warning - Hard Mode)

3.) Generate the mqtt.conf file with this bash script. Should look something like this

connection bridge-ecoflow
address mqtt-e.ecoflow.com:8883
remote_username app-4c384blahblahblah
remote_password f17ea2ablahblahblah

# Friendly named topics for device woofles
topic "" in   0 bridge-ecoflow/woofles/data /app/device/property/R351blahblahblah
topic "" both 0 bridge-ecoflow/woofles/set  /app/1673640896999415809/R351blahblahblah/thing/property/set
topic "" both 0 bridge-ecoflow/woofles/get  /app/1673640896999415809/R351blahblahblah/thing/property/get
topic "" in   0 bridge-ecoflow/woofles/set_reply /app/1673640896999415809/R351blahblahblah/thing/property/set_reply
topic "" in   0 bridge-ecoflow/woofles/get_reply /app/1673640896999415809/R351blahblahblah/thing/property/get_reply

remote_clientid ANDROID_CECAFblahblahblahblahblahblahblahblahblah15809
cleansession true
try_private true
bridge_insecure false
bridge_protocol_version mqttv311
bridge_tls_version tlsv1.2
bridge_capath /etc/ssl/certs/

3.) mosquito -c ./mqtt.conf

4.) Run the following python3 script, and see some battery data (Note: % doesn't come through often)

import sys
import json
import time
import threading
import paho.mqtt.client as mqtt

# Heartbeat interval (in seconds)
HEARTBEAT_INTERVAL = 10

state = {"watts_in": 0, "watts_out": 0, "soc": "..."}
current_sec = [HEARTBEAT_INTERVAL]
print_lock = threading.Lock()

PING_PAYLOAD = json.dumps({
    "id": 12345678,
    "version": "1.0",
    "moduleType": 0,
    "operateType": "latestQuotas",
    "params": {}
})

def countdown_worker(client):
    """Counts down, clears the line, sends heartbeat, and repeats."""
    while True:
        for sec in range(HEARTBEAT_INTERVAL, 0, -1):
            current_sec[0] = sec
            with print_lock:
                sys.stdout.write(f"\r\033[KHeartbeat in: {sec}")
                sys.stdout.flush()
            time.sleep(1)

        # Reached 0: Clear line and send heartbeat ping
        with print_lock:
            sys.stdout.write("\r\033[K")
            sys.stdout.flush()

        try:
            client.publish("bridge-ecoflow/woofles/get", PING_PAYLOAD)
        except Exception:
            pass

def on_message(client, userdata, msg):
    try:
        params = json.loads(msg.payload.decode()).get("params", {})
        has_watts = "pd.wattsInSum" in params or "pd.wattsOutSum" in params
        has_soc = "pd.soc" in params

        if "pd.wattsInSum" in params:
            state["watts_in"] = params["pd.wattsInSum"]
        if "pd.wattsOutSum" in params:
            state["watts_out"] = params["pd.wattsOutSum"]
        if "pd.soc" in params:
            state["soc"] = params["pd.soc"]

        # If telemetry updated, print the new line and preserve the countdown below it
        if has_watts or has_soc:
            with print_lock:
                # Erase current countdown line, print status line, then re-render countdown
                sys.stdout.write(f"\r\033[KInput: {state['watts_in']} W | Output: {state['watts_out']} W | Battery SOC: {state['soc']}%\n")
                sys.stdout.write(f"\r\033[KRefreshing in: {current_sec[0]}")
                sys.stdout.flush()
    except Exception:
        pass

def on_connect(client, userdata, flags, rc, properties=None):
    client.subscribe("bridge-ecoflow/woofles/data")
    t = threading.Thread(target=countdown_worker, args=(client,), daemon=True)
    t.start()

try:
    client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
except AttributeError:
    client = mqtt.Client()

client.on_connect = on_connect
client.on_message = on_message

try:
    client.connect("127.0.0.1", 1883, 60)
    client.loop_forever()
except KeyboardInterrupt:
    print("\nExiting...")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment