Skip to main content

Qcells - HA

Depuis un moment je me dis qu’il est nécessaire de faire un petit post sur ce projet…

Commençons par bien décrire ce qui fonctionne aujourd’hui

J’ai acheté une maison en Juillet 2023 dans le sud de la France, elle était équipée d’une installation PV de marque QCells.

Elle fonctionne correctement et remonte ses informations sur une console web chez le constructeur uniquement.

L’interface est très limitée et fermée…

Une image contenant texte, capture d’écran, logiciel, Logiciel multimédia

Le contenu généré par l’IA peut être incorrect.

Bref, ce n’est pas la solution que j’aurai choisie mais elle est la et je dois faire avec !

Cet onduleur QCells est connecté sur un compteur relié au tableau electrique via une liaison RS-485

L’onduleur adapte l’injection en fonction de la consommation de la maison et la production solaire.

Ainsi si la production PV est de 1000W, que la maison à besoin de 500W, il va aller compenser cette demande « EDF » en injectant autour de 500W pour essayer d’effacer « EDF » !

Ok, c’est bien beau tout ca, mais comment faire pour pouvoir l’intégrer dans une solution domotique ?!

Ma première étape sera donc de voir ce qu’il sera possible de faire pour récupérer un maximum d’informations depuis le dashboard « myess.hansoltechnics.com »

Une rapide recherche sur le net ne m’apporte rien de bon et je décide donc d’aller fouiller un peu s’il est possible d’avoir d’accès a une webui sur la carte LAN de l’onduleur QCells

Les ports 80, 443, 8080 ne répondent pas mais en recherchant un peu, google toujours notre ami, je tombe sur un poste allemand qui parle d’un accès à l’interface BMS sur le port 21710 !

Aller, on va aller voir ça bingo !

L’interface du BMS !

On fouille un peu dans les menus sans aller sur les parties de configuration, on se contente de la page de monitoring

Effectivement on a bien plus de chose et si on va dans [More data] encore plus !

La ca parle, GRID, PV, LOAD, c’est les valeurs qu’il me faut !

Etant équipe d’une solution Home Assistant avec un Lixee sur la prise TIC, je constate que les valeurs sont bien cohérentes.

On va donc voir comment faire pour récupérer ses valeurs et les injecter dans Home Assistant pour les utiliser.

Pour cela, j’ai décidé de venir parser la page en question à intervalle régulier pour en extraire les informations d’on j’ai besoin.

Ca tombe bien, j’ai un Rasbperry qui ne sert à rien dans un coin !

N’etant pas super alaise avec certain language et connaissant un peu PHP, j’ai décidé de créer un script assez simple.

J’extrairai les informations de la page de l’onduleur et les injecterai via MQTT dans Home Assistant.

Etape 1 – Récupérer la page dans mon script :

Je charge ma page onduleur :

// URL de la page web
$url = 'http://10.105.10.1:21710/f0';
$html = file_get_contents($url);
if (!$html) {
    die(" Impossible de charger la page web !");
}

Etape 2 - Extraction des données

// Extraction des valeurs
$data = [];
preg_match('/GRID_P.*?(-?\d+[\.,]?\d*)/', $html, $matches);
$data['grid'] = $matches[1] ?? "N/A";

preg_match('/LOAD_P.*?(-?\d+[\.,]?\d*)/', $html, $matches);
$data['load_p'] = $matches[1] ?? "N/A";

preg_match('/PV_P.*?(-?\d+[\.,]?\d*)/', $html, $matches);
$data['pv_prod'] = $matches[1] ?? "N/A";

preg_match('/BT_SOC.*?(\d+)/', $html, $matches);
$data['batt_lvl'] = $matches[1] ?? "N/A";

preg_match('/BT_P.*?(-?\d+[\.,]?\d*)/', $html, $matches);
$data['battery_charge'] = $matches[1] ?? "N/A";

preg_match('/INV_P.*?(-?\d+[\.,]?\d*)/', $html, $matches);
$data['inverter_p'] = $matches[1] ?? "N/A";

preg_match('/<td width=80>SYS_READY<\/td>\s*<td width=20>(\d+)<\/td>/', $html, $matches);
$data['SYS_READY'] = $matches[1] ?? "N/A";

preg_match('/<td width=80>SYS FAULT<\/td>\s*<td width=20>(\d+)<\/td>/', $html, $matches);
$data['SYS_FAULT'] = $matches[1] ?? "N/A";

preg_match('/PV_run.*?(\d+)/', $html, $matches);
$data['PV_run'] = $matches[1] ?? "N/A";

preg_match('/BT_CH_run.*?(\d+)/', $html, $matches);
$data['BT_CH_run'] = $matches[1] ?? "N/A";

preg_match('/BT_DIS_run.*?(\d+)/', $html, $matches);
$data['BT_DIS_run'] = $matches[1] ?? "N/A";

En détail :
- GRID_P : La puissance en provenance d’EDF (W)
- LOAD_P : La puissance demandée par la maison (W)
- PV_P : La puissance produite par les PV (W)
- BT_SOC : Le niveau de charge de la batterie QCells (%)
- BT_P : La puissance entrant/sortant de la batterie QCells (W)
- INV_P : La puissance envoyée en sortie du système QCells (W)
- SYS_READY : Etat du système QCells (1 ou 0)
- SYS_FAULT : La présence d’un defaut sur le système QCells (1 ou 0)
- PV_run : Production PV active ou non (1 ou 0)
- BT_CH_run : Charge Batterie activée (1 ou 0)
- BT_DIS_run Décharge de Batterie activée (1 ou 0)

Etape 3 – Traitement et injections des données dans HA

Pour cela, j’utilise l’addon php MQTT.


require 'vendor/autoload.php';  // Charge Bluerhinos\phpMQTT
use Bluerhinos\phpMQTT;

// Configuration MQTT
$server = "10.105.1.16";
$port = 1883;
$username = "mqtt";
$password = "mqtt";
$client_id = "qcells_mqtt_client";

On commence simple, on va injecter le statu du QCells, est-il en charge, décharge, standby ?

// Déterminer l'état de charge/décharge
if ($data['BT_CH_run'] == 1 && $data['BT_DIS_run'] == 0)  $data['etat'] = "En charge";
if ($data['BT_CH_run'] == 0 && $data['BT_DIS_run'] == 1) $data['etat'] = "En décharge";
if ($data['BT_CH_run'] == 0 && $data['BT_DIS_run'] == 0) $data['etat'] = "Standby";

 

Et on envoi ca dans Home Assistant

On va donc se connecter au MQTT

// Création du client MQTT
$mqtt = new phpMQTT($server, $port, $client_id);
if (!$mqtt->connect(true, NULL, $username, $password)) {
    die(" Échec de connexion au broker MQTT !");
}

On créé notre device

// Identifiant du device (Qcells)
$device_id = "qcells";

// Informations sur l'onduleur solaire (Qcells)
$device_info = ["identifiers" => [$device_id], "name" => "Qcells", "model" => "Hybrid Inverter", "manufacturer" => "Qcells", "via_device" => "MQTT"];

On créé notre « sensor »

// Définition des capteurs MQTT Discovery
$sensors = [
    "etat" => ["name" => "État", "device_class" => "enum", "state_class" => "measurement", "icon" => "mdi:battery-sync"],
];

Et enfin on publie tout ca sur Home Assistant

// Publier chaque capteur avec MQTT Discovery
foreach ($sensors as $key => $sensor) {
    $discovery_topic = "homeassistant/sensor/{$device_id}_{$key}/config";
    $discovery_payload = json_encode([
        "name" => $sensor["name"],
        "state_topic" => "homeassistant/sensor/qcells",
        "value_template" => "{{ value_json.$key }}",
        "unit_of_measurement" => $sensor["unit_of_measurement"] ?? NULL,
        "device_class" => $sensor["device_class"],
        "state_class" => $sensor["state_class"],
        "icon" => $sensor["icon"],
        "unique_id" => "{$device_id}_{$key}",
        "device" => $device_info
    ]);
    $mqtt->publish($discovery_topic, $discovery_payload, 0);
}

// Publication des données JSON à MQTT
$mqtt->publish("homeassistant/sensor/qcells", json_encode($data), 0);
$mqtt->close();

Des lors, une nouvelle entité est créée sous Home Assistant

Une image contenant texte, capture d’écran, Police, ligne

Le contenu généré par l’IA peut être incorrect.

Avec dedans notre etat !

Impeccable tout ça on va pouvoir s’attaquer à la suite !

On va donc ajouter dans section « Définition des capteurs MQTT Discovery » tout ce dont nous avons besoin et qui ne nécessite pas de calcul avancé.

On ajoute donc, le niveau de la batterie, la puissance demandée à EDF, la puissance demandée par la maison, la puissance en sortie des PV, la puissance en sortie du QCells, etc…

    "batt_lvl" => ["name" => "Niveau Batterie", "unit_of_measurement" => "%", "device_class" => "battery", "state_class" => "measurement", "icon" => "mdi:battery"],

    "pv_prod" => ["name" => "Production Solaire", "unit_of_measurement" => "W", "device_class" => "power", "state_class" => "measurement", "icon" => "mdi:solar-power"],

    "inverter_p" => ["name" => "Inverter Production", "unit_of_measurement" => "W", "device_class" => "power", "state_class" => "measurement", "icon" => "mdi:solar-power"],

    "battery_charge" => ["name" => "Charge Batterie", "unit_of_measurement" => "W", "device_class" => "power", "state_class" => "measurement", "icon" => "mdi:battery-charging"],

    "grid" => ["name" => "Consommation Réseau", "unit_of_measurement" => "W", "device_class" => "power", "state_class" => "measurement", "icon" => "mdi:transmission-tower"],

    "load_p" => ["name" => "Consommation Maison", "unit_of_measurement" => "W", "device_class" => "power", "state_class" => "measurement", "icon" => "mdi:transmission-tower"],

    "etat" => ["name" => "État", "device_class" => "enum", "state_class" => "measurement", "icon" => "mdi:battery-sync"],

    "dernier_releve" => ["name" => "Dernier relevé", "unit_of_measurement" => "", "device_class" => "enum", "state_class" => "measurement", "icon" => "mdi:calendar-clock"],

    "SYS_READY" => ["name" => "Système Prêt", "unit_of_measurement" => "", "device_class" => "enum", "state_class" => "measurement", "icon" => "mdi:check-circle"],

    "SYS_FAULT" => ["name" => "Fautes Système", "unit_of_measurement" => "", "device_class" => "enum", "state_class" => "measurement", "icon" => "mdi:alert-circle"],

    "etat_pv" => ["name" => "Status PV", "unit_of_measurement" => "", "device_class" => "enum", "state_class" => "measurement", "icon" => "mdi:solar-power"]

Et donc dans Home Assistant, ca remonte également !

Une image contenant texte, capture d’écran, nombre, logiciel

Le contenu généré par l’IA peut être incorrect.

Il ne reste plus qu’a exécuter ce script toutes les 10 secondes à l’aide de cron sous linux !

Et voila, on a notre QCells qui est maintenant interfacé avec Home Assistant :D

Alors vous me direz, oui mais dans ta capture y a des valeurs en kwh !

Et bien oui on y vient, pour calculer la production solaire en kWh, l’interface du QCells ne me le dit pas, il faut que je le calcule.

On a une valeur à un instant T et je vais extrapoler cela pour 10 secondes :

On part du principe que je produis 1000W par seconde sur une durée de 10 secondes donc 1000W x 10sec : 10000W

Maintenant pour les avoir en Wh, je divise le tout par 3600 (60 secondes * 60 minutes = 3600)

Mais moi, il me faut des kWh pas des Wh !

Donc je redivise le tout par 1000, soit 3600000 !

Pour être précis, je vais arrondir le résultat à 4 chiffres derrière la virgule à l’aide de fonction php round()

// Calcul de la production en kWh (converti depuis W sur 10s)
$production_kwh = ($data['pv_prod'] * 10) / 3600000;
$data['pv_prod_kwh'] = round($production_kwh, 4);

Et voilà, j’ai ma production en kwh !

On vérifie quand même si c’est cohérant

Depuis le portail QCells, j’ai pour Janvier :

Et depuis Home Assistant (en jaune, les autres on y viendra plus tard) :

Une image contenant capture d’écran, texte, diagramme, ligne

Le contenu généré par l’IA peut être incorrect.

Et depuis le portail QCells

Une image contenant texte, capture d’écran, Police, nombre

Le contenu généré par l’IA peut être incorrect.

Les valeurs sont IDENTIQUES !

Sur janvier 2026, HA me remonte une production de 91,46kWh et le dashboard Qcells 91,06kWh

Pourquoi un écart de 400Wh ?
Simple, il est arrivé que l’onduleur n’est pas réussi à envoyer des informations sur MyESS à certain moment (perte d’accès internet ou autre) alors que mon HA est en local et hautement disponible.

Pour les autres valeurs en kWh, il ne vous reste plus qu’a faire pareil selon vos envies !

J’espère que cela aura été utiles à ceux disposant d’un système solaire QCells et qui souhaite l’intégrer dans une solution domotique tel qu’Home Assistant