PowerStream en mode développeur dans Home Assistant

powerstream mode developpeur

🎯 Contrôler le PowerStream : deux méthodes simples et efficaces

Dans cette vidéo, je te montre deux façons de contrôler ton PowerStream Ecoflow depuis Home Assistant. La première passe par IOBroker, la seconde par un compte développeur Ecoflow.
Le but ? Gérer en temps réel la charge, la décharge et l’injection solaire… le tout avec un maximum de réactivité.


🔹 Méthode 1 : via IOBroker (mise à jour améliorée)

J’avais déjà présenté cette méthode dans une précédente vidéo, mais cette fois le script est plus simple et beaucoup plus rapide.

  • 📈 Réactivité : à partir d’une valeur de 10, le changement de puissance prend moins de 4 à 5 secondes.
  • Démarrage lent : le PowerStream met un peu de temps à sortir du mode veille si on part de zéro.
  • 📜 Script dispo : je te mets le code pour que tu puisses le tester.
// Version ultra-simplifiée : Envoi de la valeur d'injection pour PowerStream uniquement sur changement de Setpower
const SERIAL_NUMBER = "XXXXXXXXXXXXX"; // Votre numéro de série PowerStream

var ConfigData = {
  email: "XXXXXXXXXXX",       // Identifiants d'accès à l'app EcoFlow
  passwort: "XXXXXXXXXXX",
  Debug: false
};

// Création du state "Setpower" (number de 0 à 800)
createState("Setpower", 0, {
  name: "Set Power",
  type: "number",
  role: "value",
  read: true,
  write: true,
  min: 0,
  max: 800
});

let lastSentValue = null; // mémorise la dernière valeur envoyée

// Définition Protobuf (réduite à l'essentiel pour l'envoi)
const protoSource2 = `
syntax = "proto3";
message setMessage { setHeader header = 1; }
message setHeader {
  setValue pdata = 1 [proto3_optional = true];
  int32 src = 2 [proto3_optional = true];
  int32 dest = 3 [proto3_optional = true];
  int32 d_src = 4 [proto3_optional = true];
  int32 d_dest = 5 [proto3_optional = true];
  int32 enc_type = 6 [proto3_optional = true];
  int32 check_type = 7 [proto3_optional = true];
  int32 cmd_func = 8 [proto3_optional = true];
  int32 cmd_id = 9 [proto3_optional = true];
  int32 data_len = 10 [proto3_optional = true];
  int32 need_ack = 11 [proto3_optional = true];
  int32 is_ack = 12 [proto3_optional = true];
  int32 seq = 14 [proto3_optional = true];
  int32 product_id = 15 [proto3_optional = true];
  int32 version = 16 [proto3_optional = true];
  int32 payload_ver = 17 [proto3_optional = true];
  int32 time_snap = 18 [proto3_optional = true];
  int32 is_rw_cmd = 19 [proto3_optional = true];
  int32 is_queue = 20 [proto3_optional = true];
  int32 ack_type = 21 [proto3_optional = true];
  string code = 22 [proto3_optional = true];
  string from = 23 [proto3_optional = true];
  string module_sn = 24 [proto3_optional = true];
  string device_sn = 25 [proto3_optional = true];
}
message setValue { optional int32 value = 1; }
`;

// Messages modèles (réduits pour l'envoi)
const musterGetPS = {
  header: { src: 32, dest: 32, seq: 1651831507, OS: "ios" }
};

const musterSetAC = {
  header: {
    pdata: { value: 1300 },
    src: 32, dest: 53, dSrc: 1, dDest: 1,
    checkType: 3, cmdFunc: 20, cmdId: 129, dataLen: 3,
    needAck: 1, seq: 1651831507, version: 19, payloadVer: 1,
    from: "ios", deviceSn: SERIAL_NUMBER
  }
};

const musterSetAC2 = {
  header: {
    pdata: { value: 17477 },
    src: 32, dest: 53, dSrc: 1, dDest: 1,
    checkType: 3, cmdFunc: 32, cmdId: 11, dataLen: 4,
    needAck: 1, seq: 1651831507, version: 19, payloadVer: 1,
    from: "ios", deviceSn: SERIAL_NUMBER
  }
};

// Données MQTT
const mqttDaten = { UserID: "", User: "", Passwort: "", URL: "", Port: "", protocol: "", clientID: "" };

// Connexion MQTT
let isMqttConnected = false;
const mqtt = require("mqtt");
const https = require("https");
const protobuf = require("protobufjs");

// Récupérer les données MQTT EcoFlow
await getEcoFlowMqttData(ConfigData.email, ConfigData.passwort);

async function getEcoFlowMqttData(email, password) {
  const options = {
    hostname: "api.ecoflow.com",
    path: "/auth/login",
    method: "POST",
    headers: { "content-type": "application/json", "user-agent": "okhttp/3.14.9" }
  };
  const data = {
    email: email,
    password: Buffer.from(password).toString("base64"),
    scene: "IOT_APP",
    userType: "ECOFLOW"
  };

  function httpsRequest(opts, body) {
    return new Promise((resolve, reject) => {
      const req = https.request(opts, res => {
        let d = "";
        res.on("data", chunk => { d += chunk; });
        res.on("end", () => resolve(d));
      });
      req.on("error", reject);
      if (body) req.write(JSON.stringify(body));
      req.end();
    });
  }

  let response = await httpsRequest(options, data);
  let parsed = JSON.parse(response);
  let token = parsed.data.token;
  let userid = parsed.data.user.userId;

  options.path = `/iot-auth/app/certification?userId=${userid}`;
  options.method = "GET";
  options.headers.authorization = `Bearer ${token}`;

  response = await httpsRequest(options);
  parsed = JSON.parse(response);

  mqttDaten.Passwort = parsed.data.certificatePassword;
  mqttDaten.Port = parsed.data.port;
  mqttDaten.UserID = userid;
  mqttDaten.User = parsed.data.certificateAccount;
  mqttDaten.URL = parsed.data.url;
  mqttDaten.protocol = parsed.data.protocol;
  mqttDaten.clientID = "ANDROID_" + require("crypto").randomUUID() + "_" + userid;
}

// Établir la connexion MQTT (simplifiée pour l'envoi uniquement)
function setupMQTTConnection() {
  const options = {
    port: mqttDaten.Port,
    clientId: mqttDaten.clientID,
    username: mqttDaten.User,
    password: mqttDaten.Passwort,
    protocol: mqttDaten.protocol
  };
  const client = mqtt.connect("mqtt://" + mqttDaten.URL, options);

  client.on("connect", function () {
    log("Connecté au MQTT EcoFlow");
    SubscribeEco();
    setmusterGetPS(SERIAL_NUMBER);
    isMqttConnected = true;
  });

  client.on("close", () => { isMqttConnected = false; });
  client.on("error", e => { log("Erreur MQTT : " + e, "warn"); });

  return client;
}

let client = setupMQTTConnection();

// Abonnement minimal
function SubscribeEco() {
  client.subscribe("/app/" + mqttDaten.UserID + "/" + SERIAL_NUMBER + "/thing/property/set"); // optionnel
}

// Simuler le heartbeat de l'app
function setmusterGetPS(asn) {
  let updatedMusterGetPS = JSON.parse(JSON.stringify(musterGetPS));
  updatedMusterGetPS.header.seq = Date.now();

  SendProto(JSON.stringify(updatedMusterGetPS), "/app/" + mqttDaten.UserID + "/" + asn + "/thing/property/get");
  SendProto(JSON.stringify(updatedMusterGetPS), "/app/" + mqttDaten.UserID + "/" + asn + "/thing/property/get");
  SendProto(JSON.stringify(updatedMusterGetPS), "/app/" + mqttDaten.UserID + "/" + asn + "/thing/property/get");

  let updatedMusterSetAC2 = JSON.parse(JSON.stringify(musterSetAC2));
  updatedMusterSetAC2.header.seq = Date.now();
  updatedMusterSetAC2.header.deviceSn = asn;

  SendProto(JSON.stringify(updatedMusterSetAC2), "/app/" + mqttDaten.UserID + "/" + asn + "/thing/property/set");
}

// Heartbeat périodique
var intervalID3 = setInterval(function () {
  if (isMqttConnected) setmusterGetPS(SERIAL_NUMBER);
}, 32 * 1000);

// Listener : changement de javascript.0.Setpower
on({ id: "javascript.0.Setpower", change: "any" }, function () {
  SetBasePower();
});

// Envoi de la valeur d'injection (seulement si changée)
function SetBasePower() {
  let currentValue = Math.floor(getState("javascript.0.Setpower").val) * 10;
  if (currentValue === lastSentValue) {
    if (ConfigData.Debug) log("Valeur inchangée (" + currentValue / 10 + "), pas d'envoi.");
    return;
  }
  setAC(SERIAL_NUMBER, currentValue);
  lastSentValue = currentValue;
  log("Injection modifiée : " + currentValue / 10);
}

// Définir la puissance AC (injection)
function setAC(asn, Value) {
  let updatedMusterSetAC = JSON.parse(JSON.stringify(musterSetAC));
  updatedMusterSetAC.header.pdata.value = Value;
  updatedMusterSetAC.header.dataLen = getVarintByteSize(Value);
  updatedMusterSetAC.header.seq = Date.now();
  updatedMusterSetAC.header.deviceSn = asn;
  SendProto(JSON.stringify(updatedMusterSetAC), "/app/" + mqttDaten.UserID + "/" + asn + "/thing/property/set");
}

// Encodage Protobuf + publication
function SendProto(protomsg, topic) {
  const root = protobuf.parse(protoSource2).root;
  const PowerMessage = root.lookupType("setMessage");
  const message = PowerMessage.create(JSON.parse(protomsg));
  const messageBuffer = PowerMessage.encode(message).finish();
  client.publish(topic, messageBuffer, { qos: 1 });
}

// Taille varint
function getVarintByteSize(number) {
  let byteSize = 0;
  while (number >= 128) { byteSize++; number >>= 7; }
  byteSize += 2;
  return byteSize;
}

// Arrêt du script
onStop(function (callback) {
  if (client) client.end();
  clearInterval(intervalID3);
  callback();
}, 2000);

// Listener MQTT depuis HA (topic /ha/setpower)
client.subscribe("/ha/setpower");
client.on("message", function (topic, message) {
  if (topic === "/ha/setpower") {
    let newValue = parseFloat(message.toString());
    setState("javascript.0.Setpower", newValue); // déclenche SetBasePower
  }
});

Cette méthode reste très fiable, mais demande d’installer IOBroker dans un conteneur Docker, puis de configurer MQTT et un script JavaScript pour que Home Assistant envoie les ordres au PowerStream.


🔹 Méthode 2 : via un compte développeur Ecoflow

Un spectateur m’a parlé de cette méthode et honnêtement… elle est beaucoup plus simple.
Pas besoin de scripts compliqués : on utilise directement les API officielles d’Ecoflow.

1️⃣ Création et activation du compte développeur

  1. Crée un compte Ecoflow (si ce n’est pas déjà fait).
  2. Cherche “Ecoflow compte développeur” sur Google et clique sur le premier lien.
  3. Connecte-toi puis clique sur “Devenir développeur”.
  4. Valide ton compte par SMS (ça peut parfois demander plusieurs essais).
  5. Attends la validation (jusqu’à 5 jours).
  6. Récupère tes deux clés API dans ton espace développeur.

2️⃣ Intégration dans Home Assistant

  1. Ajoute le dépôt personnalisé fourni dans la description.
  2. Télécharge la dernière version stable de l’intégration.
  3. Redémarre Home Assistant.
  4. Dans Paramètres > Appareils et services, ajoute l’intégration Ecoflow.
  5. Entre tes deux clés API et le numéro de série du PowerStream.

Tu peux maintenant gérer :

  • L’éclairage intégré du PowerStream
  • La charge et la décharge de ta batterie
  • L’injection solaire vers ton réseau

⚡ Résultat : deux méthodes, même efficacité

Que tu passes par IOBroker ou par l’API officielle, la réactivité est au rendez-vous.
Mais si tu veux la solution la plus rapide à mettre en place, le compte développeur Ecoflow est clairement la voie à suivre.


💡 Dans la prochaine vidéo, on parlera des chargeurs, de leurs réglages et de comment optimiser leur utilisation avec ton installation solaire.

▶️ Voir le tuto complet en vidéo sur YouTube :

Maxresdefault

3 réflexions sur “PowerStream en mode développeur dans Home Assistant”

  1. Effectivement
    La méthode avec le compte développeur est quand même plus simple et pour l’instant assez stable.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Retour en haut