Automatisation IoT

Surveillance d'onduleur solaire via MQTT avec SunSpec Modbus et Python

Lisez les données de production en direct de votre onduleur photovoltaïque via SunSpec Modbus TCP ou une API locale, publiez la puissance, l'énergie journalière et l'état en MQTT, et rendez les données solaires accessibles à chaque tableau de bord et automatisation de la maison.

Panneaux solaires en toiture et onduleur mural transmettant des données vers un tableau de bord cloud pour la surveillance d'onduleur solaire
Essayez-le sur votre propre broker MQTTObtenez un broker MQTT privé et managé avec l’offre Free et partez d’exemples de code prêts à l’emploi.
Essayer gratuitement Exemples de code Aucune carte bancaire requise

La surveillance d'onduleur solaire via MQTT libère vos données de production de l'application du fabricant et les met en temps réel à la disposition des tableaux de bord, de la domotique de votre maison connectée et de la logique de pilotage des charges. Dans ce tutoriel, vous allez lire la puissance, l'énergie et l'état d'un onduleur à l'aide du standard SunSpec Modbus TCP en Python, publier un JSON propre vers un broker toutes les quelques secondes, et comprendre les pièges qui font échouer la plupart des premières tentatives. Les autres voies, via des API HTTP locales et le RS485, sont également abordées.

Trois façons d'extraire les données d'un onduleur

Les portails des fabricants suffisent pour un coup d'œil mensuel, mais ils se mettent généralement à jour lentement et dépendent d'internet. L'accès local est plus rapide, fonctionne hors ligne et c'est ce qu'il vous faut pour des automatisations comme faire tourner une pompe à chaleur sur le surplus.

Méthode Onduleurs typiques Avantages Inconvénients
SunSpec Modbus TCP De nombreux onduleurs string de grandes marques Table de registres standardisée, réseau local uniquement, rapide Doit souvent être activé dans les paramètres installateur
API HTTP locale du fabricant Certaines marques exposent du JSON sur le réseau local Facile à lire avec n'importe quel client HTTP Différente selon le fabricant, peut nécessiter des jetons
Modbus RTU sur RS485 De nombreux onduleurs hybrides et d'entrée de gamme Fonctionne sans port réseau Nécessite un adaptateur RS485 et la table de registres du fabricant

SunSpec est le meilleur point de départ lorsque votre onduleur le prend en charge, car le même code fonctionne d'une marque à l'autre. La SunSpec Alliance définit des « modèles » : des blocs de registres à la disposition fixe. Les modèles d'onduleur 101 (monophasé), 102 (biphasé) et 103 (triphasé) partagent la même disposition de champs, ce sur quoi repose le code ci-dessous.

Activer Modbus TCP sur l'onduleur

Chaque marque cache ce réglage à un endroit différent, mais la démarche est la même :

  1. Attribuez à l'onduleur une adresse IP fixe via une réservation DHCP.
  2. Dans le menu installateur ou de mise en service, activez Modbus TCP (parfois appelé « SunSpec » ou « Modbus slave »).
  3. Notez le port (presque toujours 502) et l'unit ID (souvent 1, parfois 126 ou une autre valeur).
  4. Choisissez le format de registres SunSpec / float ou int+SF si l'onduleur le demande ; ce guide utilise le format entier plus facteur d'échelle, le plus largement pris en charge.
  5. Si votre onduleur propose une option « lecture seule » pour Modbus, activez-la. Vous n'avez besoin que de lire.

Certains onduleurs n'acceptent qu'un seul client Modbus TCP à la fois. Si un gestionnaire d'énergie ou un contrôleur de borne de recharge est déjà connecté, votre script peut être refusé ou déconnecter l'autre client : décidez donc quel système détient la connexion.

Fonctionnement des registres SunSpec

Un appareil SunSpec commence par le marqueur SunS à une adresse de base, généralement 40000. Après le marqueur vient une chaîne de modèles, chacun débutant par un identifiant de modèle et une longueur. Vous parcourez la chaîne jusqu'à trouver le modèle 101, 102 ou 103, puis lisez les champs à des décalages fixes :

Décalage dans le modèle Champ Type Signification
2 A uint16 Courant AC, mis à l'échelle par A_SF (décalage 6)
10 PhVphA uint16 Tension de la phase A, mise à l'échelle par V_SF (décalage 13)
14 W int16 Puissance AC, mise à l'échelle par W_SF (décalage 15)
16 Hz uint16 Fréquence, mise à l'échelle par Hz_SF (décalage 17)
24–25 WH acc32 Énergie cumulée en Wh, mise à l'échelle par WH_SF (décalage 26)
31 DCW int16 Puissance DC, mise à l'échelle par DCW_SF (décalage 32)
33 TmpCab int16 Température du boîtier, mise à l'échelle par Tmp_SF (décalage 37)
38 St enum16 État de fonctionnement (4 = MPPT, en production)

Les décalages se comptent à partir du registre d'identifiant du modèle. Chaque valeur est multipliée par 10 élevé à la puissance de son facteur d'échelle signé : un W brut de 51234 avec un W_SF de -1 signifie donc 5123,4 W. Les registres non implémentés renvoient 0x8000 (signé) ou 0xFFFF (non signé) et doivent être ignorés.

Le publieur Python

Installez les bibliothèques :

pip install "paho-mqtt>=2.0" "pymodbus>=3.7"

Le script trouve la base SunSpec, parcourt les modèles, lit le bloc onduleur et publie du JSON. Il utilise d'abord le serveur MQTT public gratuit, avec un préfixe aléatoire, car cet espace réservé aux tests est lisible par tous.

import json
import time
import uuid
import paho.mqtt.client as mqtt
from pymodbus.client import ModbusTcpClient

INVERTER_IP = "192.168.1.60"
INVERTER_PORT = 502
POLL_SECONDS = 10

PREFIX = f"connectmq/demo/{uuid.uuid4().hex[:8]}/solar/inverter1"
STATE_NAMES = {1: "off", 2: "sleeping", 3: "starting", 4: "mppt",
               5: "throttled", 6: "shutting_down", 7: "fault", 8: "standby"}


def s16(v):
    return None if v == 0x8000 else (v - 0x10000 if v & 0x8000 else v)


def u16(v):
    return None if v == 0xFFFF else v


def scaled(value, sf):
    if value is None or sf is None:
        return None
    return round(value * (10 ** sf), 3)


def kwh(wh_raw, sf):
    if not wh_raw or sf is None:      # une valeur acc32 de 0 signifie non implémenté
        return None
    return round(wh_raw * (10 ** sf) / 1000, 3)


def find_inverter_model(client):
    for base in (40000, 39999, 50000, 0):
        rr = client.read_holding_registers(base, count=2)
        if rr.isError() or rr.registers != [0x5375, 0x6E53]:   # "SunS"
            continue
        addr = base + 2
        for _ in range(30):
            rr = client.read_holding_registers(addr, count=2)
            if rr.isError():
                break
            model_id, length = rr.registers
            if model_id == 0xFFFF:
                break
            if model_id in (101, 102, 103):
                return addr, length, model_id
            addr += 2 + length
    raise RuntimeError("No SunSpec inverter model found - check Modbus settings and unit ID")


def read_inverter(client, addr, length):
    rr = client.read_holding_registers(addr, count=length + 2)
    if rr.isError():
        raise IOError(rr)
    r = rr.registers
    wh_raw = (r[24] << 16) | r[25]
    return {
        "ac_power_w": scaled(s16(r[14]), s16(r[15])),
        "ac_current_a": scaled(u16(r[2]), s16(r[6])),
        "ac_voltage_v": scaled(u16(r[10]), s16(r[13])),
        "frequency_hz": scaled(u16(r[16]), s16(r[17])),
        "energy_total_kwh": kwh(wh_raw, s16(r[26])),
        "dc_power_w": scaled(s16(r[31]), s16(r[32])),
        "temp_c": scaled(s16(r[33]), s16(r[37])),
        "state": STATE_NAMES.get(r[38], str(r[38])),
    }


mq = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                 client_id=f"solar-{uuid.uuid4().hex[:6]}")
mq.will_set(f"{PREFIX}/status", "offline", qos=1, retain=True)
mq.connect("broker.connectmq.com", 1883, keepalive=60)
mq.loop_start()
mq.publish(f"{PREFIX}/status", "online", qos=1, retain=True)
print("Publishing to", PREFIX)

mb = ModbusTcpClient(INVERTER_IP, port=INVERTER_PORT, timeout=3)
model_addr = model_len = None

while True:
    try:
        if not mb.connected:
            mb.connect()
        if model_addr is None:
            model_addr, model_len, model_id = find_inverter_model(mb)
            print(f"Found SunSpec model {model_id} at {model_addr}")
        data = read_inverter(mb, model_addr, model_len)
        data["ts"] = int(time.time())
        mq.publish(f"{PREFIX}/telemetry", json.dumps(data), qos=1, retain=True)
        print(data)
    except Exception as exc:
        print("Read failed:", exc)
        mb.close()
        model_addr = None
    time.sleep(POLL_SECONDS)

Si votre onduleur utilise un unit ID autre que 1, passez-le à chaque lecture avec le mot-clé device_id (appelé slave dans les anciennes versions de pymodbus). Observez la sortie depuis une autre machine :

mosquitto_sub -h broker.connectmq.com -p 1883 -i solar-viewer-2290 -t "connectmq/demo/+/solar/#" -v

Un message typique ressemble à ceci :

{"ac_power_w": 4183.0, "ac_current_a": 6.05, "ac_voltage_v": 231.4, "frequency_hz": 50.01,
 "energy_total_kwh": 18342.611, "dc_power_w": 4301.0, "temp_c": 41.2, "state": "mppt", "ts": 1760603520}

Pièges de la surveillance d'onduleur solaire

La plupart des problèmes proviennent d'une poignée de causes :

  • Adresses décalées d'une unité. La documentation mélange numérotation des registres à partir de 0 et à partir de 1. C'est pourquoi le script essaie à la fois 40000 et 39999.
  • Les facteurs d'échelle changent. Certains onduleurs modifient W_SF dynamiquement. Lisez toujours le facteur d'échelle dans la même requête que la valeur, comme le fait le code en lisant le bloc entier.
  • La nuit. De nombreux onduleurs éteignent leur carte de communication la nuit ou signalent l'état « sleeping » avec des valeurs vides. Considérez les dépassements de délai après le coucher du soleil comme normaux et conservez la dernière valeur retained.
  • Fréquence d'interrogation. Toutes les 5 à 10 secondes suffit largement pour les tableaux de bord et le pilotage du surplus. Interroger plusieurs fois par seconde n'apporte rien et peut perturber certains onduleurs.
  • Compteur ou onduleur. L'onduleur connaît la production, pas la consommation ni l'injection. Pour une logique d'autoconsommation, il vous faut aussi un compteur réseau ; le guide moniteur d'énergie domestique couvre cette moitié.
  • Les onduleurs hybrides avec batterie exposent souvent les données de la batterie dans des modèles propres au fabricant plutôt que dans les modèles SunSpec standard. Consultez surveillance de batterie domestique pour publier les valeurs du BMS.

Exploiter les données

Une fois la production sur MQTT, chaque consommateur peut l'utiliser sans plus jamais toucher à l'onduleur. Home Assistant peut associer le JSON à des capteurs via son intégration MQTT, Node-RED peut piloter une prise connectée lorsque la production dépasse un seuil, et Telegraf peut tout stocker dans une base de séries temporelles pour des rapports de rendement mensuels. Comme le message de télémétrie est retained, un tableau de bord ouvert à midi voit immédiatement la production en cours. Jeedom et Domoticz savent aussi communiquer en MQTT.

Les intégrations fonctionnent ainsi à dessein : le broker est le hub, et chaque outil s'y connecte comme client MQTT. Si cette idée est nouvelle pour vous, la présentation du rôle d'un broker MQTT explique le modèle publish/subscribe sous-jacent.

Passer en production avec un broker privé

Les données solaires ne sont pas secrètes au même titre que des mots de passe, mais elles révèlent des habitudes de présence et des détails sur l'installation, et le serveur MQTT public gratuit est partagé. Pour une installation permanente, exécutez le publieur sur un Raspberry Pi ou un serveur domestique et envoyez les données vers un broker MQTT cloud en TLS. Avec ConnectMQ, créez un broker dans le portail, copiez les identifiants générés et remplacez les lignes de connexion :

mq = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="YOUR_CLIENT_ID")
mq.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
mq.tls_set()
mq.will_set("home/solar/inverter1/status", "offline", qos=1, retain=True)
mq.connect("broker.connectmq.com", 8883, keepalive=60)

Un broker cloud vous permet aussi de consulter la production depuis votre téléphone sans rien exposer sur votre réseau domestique, car le Raspberry Pi n'établit qu'une connexion sortante. Le guide de l'automatisation IoT montre plus largement comment les données solaires s'intègrent aux flux énergétiques de toute la maison.

Surveillez votre production solaire avec ConnectMQ

ConnectMQ est un broker MQTT managé avec TLS sur le port 8883, un accès WebSocket pour les tableaux de bord dans le navigateur, un explorateur de topics en direct et des règles d'alerte à seuil, par exemple pour vous avertir lorsqu'un onduleur signale un état de défaut en pleine journée. Créez un broker Serverless gratuit sur app.connectmq.com, sans carte bancaire.

Questions fréquentes

Tous les onduleurs prennent-ils en charge SunSpec Modbus ?

Non. De nombreuses marques reconnues d'onduleurs string le font, souvent après activation dans les paramètres installateur, tandis que certains onduleurs hybrides et d'entrée de gamme ne proposent que des tables Modbus RTU propres au fabricant ou des API cloud. Cherchez « SunSpec » dans la documentation de votre modèle.

À quelle fréquence interroger l'onduleur ?

Toutes les 5 à 10 secondes suffisent pour les tableaux de bord en direct et les automatisations basées sur le surplus. Une interrogation plus rapide apporte rarement quelque chose et certains onduleurs y répondent mal.

Pourquoi mon script échoue-t-il la nuit ?

De nombreux onduleurs mettent hors tension leur interface de communication en l'absence de production photovoltaïque. Considérez les dépassements de délai nocturnes comme attendus et appuyez-vous sur le dernier message MQTT retained.

Puis-je piloter l'onduleur via MQTT ?

Certains onduleurs acceptent des registres de commande SunSpec pour limiter la puissance, mais écrire dans un onduleur peut enfreindre les règles de raccordement au réseau. Gardez ce tutoriel en lecture seule, sauf si votre installateur confirme ce qui est autorisé.

Articles liés

Guide d'installation de Zigbee2MQTT : du coordinateur au tableau de bord

Installez Zigbee2MQTT avec Docker, configurez le coordinateur et la connexion MQTT, appairez et renommez les appareils, pilotez-les via MQTT et affichez leurs états sur un tableau de bord, en testant d'abord sur le serveur MQTT public gratuit.

8 min de lecture

Tous les articles →

Votre broker MQTT privé, à quelques clics

Créez un compte, récupérez les identifiants de votre broker et connectez votre premier appareil — aucun serveur à installer, mettre à jour ou dimensionner.