Automação IoT

Monitoramento de Inversor Solar via MQTT com SunSpec Modbus e Python

Leia dados de produção ao vivo do seu inversor fotovoltaico via SunSpec Modbus TCP ou uma API local, publique potência, energia diária e status no MQTT e disponibilize os dados solares para todos os dashboards e automações da casa.

Painéis solares no telhado e um inversor de parede enviando dados a um dashboard na nuvem para monitoramento de inversor solar
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

O monitoramento de inversor solar via MQTT liberta seus dados de produção do app do fabricante e os torna disponíveis em tempo real para dashboards, automação residencial e lógicas de deslocamento de carga. Neste tutorial você vai ler potência, energia e status de um inversor usando o padrão SunSpec Modbus TCP com Python, publicar um JSON limpo em um broker a cada poucos segundos e entender as armadilhas que derrubam a maioria das primeiras tentativas. Rotas alternativas por APIs HTTP locais e RS485 também são abordadas.

Três Formas de Extrair Dados de um Inversor

Os portais dos fabricantes servem para uma olhada mensal, mas costumam atualizar devagar e dependem da internet. O acesso local é mais rápido, funciona offline e é o que você quer para automações como ligar uma bomba de calor com o excedente.

Método Inversores típicos Vantagens Desvantagens
SunSpec Modbus TCP Muitos inversores string das principais marcas Mapa de registradores padronizado, apenas na LAN, rápido Muitas vezes precisa ser ativado nas configurações do instalador
API HTTP local do fabricante Algumas marcas expõem JSON na LAN Fácil de ler com qualquer cliente HTTP Diferente para cada fabricante, pode exigir tokens
Modbus RTU via RS485 Muitos inversores híbridos e de baixo custo Funciona sem porta de rede Exige um adaptador RS485 e o mapa de registradores do fabricante

O SunSpec é o melhor ponto de partida quando o seu inversor o suporta, porque o mesmo código funciona entre marcas. A SunSpec Alliance define "modelos": blocos de registradores com layout fixo. Os modelos de inversor 101 (monofásico), 102 (fase dividida) e 103 (trifásico) compartilham o mesmo layout de campos, e é nisso que o código abaixo se apoia.

Ativando o Modbus TCP no Inversor

Cada marca esconde essa configuração de um jeito, mas o padrão é o mesmo:

  1. Dê ao inversor um IP fixo com uma reserva de DHCP.
  2. No menu do instalador ou de comissionamento, ative o Modbus TCP (às vezes chamado de "SunSpec" ou "Modbus slave").
  3. Anote a porta (quase sempre 502) e o unit ID (geralmente 1, às vezes 126 ou outro valor).
  4. Escolha o formato de registradores SunSpec / float ou int+SF se o inversor perguntar; este guia usa o formato inteiro com fator de escala, que é o mais amplamente suportado.
  5. Se o inversor tiver uma opção "somente leitura" para o Modbus, ative-a. Você só precisa ler.

Alguns inversores aceitam apenas um cliente Modbus TCP por vez. Se um gerenciador de energia ou um controlador de wallbox já estiver conectado, seu script pode ser recusado ou pode derrubar o outro cliente, então defina qual sistema é dono da conexão.

Como Funcionam os Registradores SunSpec

Um dispositivo SunSpec começa com o marcador SunS em um endereço base, geralmente 40000. Depois do marcador vem uma cadeia de modelos, cada um começando com um ID de modelo e um comprimento. Você percorre a cadeia até encontrar o modelo 101, 102 ou 103 e então lê os campos em offsets fixos:

Offset no modelo Campo Tipo Significado
2 A uint16 Corrente CA, escalada por A_SF (offset 6)
10 PhVphA uint16 Tensão da fase A, escalada por V_SF (offset 13)
14 W int16 Potência CA, escalada por W_SF (offset 15)
16 Hz uint16 Frequência, escalada por Hz_SF (offset 17)
24–25 WH acc32 Energia acumulada em Wh, escalada por WH_SF (offset 26)
31 DCW int16 Potência CC, escalada por DCW_SF (offset 32)
33 TmpCab int16 Temperatura do gabinete, escalada por Tmp_SF (offset 37)
38 St enum16 Estado de operação (4 = MPPT, produzindo)

Os offsets contam a partir do registrador do ID do modelo. Cada valor é multiplicado por 10 elevado ao seu fator de escala com sinal, então um W bruto de 51234 com W_SF igual a -1 significa 5123,4 W. Registradores não implementados retornam 0x8000 (com sinal) ou 0xFFFF (sem sinal) e devem ser ignorados.

O Publicador em Python

Instale as bibliotecas:

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

O script encontra a base SunSpec, percorre os modelos, lê o bloco do inversor e publica JSON. Ele usa primeiro o servidor MQTT público (gratuito), com um prefixo aleatório, porque essa área pode ser lida por todos e serve apenas para testes.

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:      # valor acc32 igual a 0 significa não implementado
        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)

Se o seu inversor usa um unit ID diferente de 1, passe-o em cada leitura com o parâmetro device_id (chamado slave em versões mais antigas do pymodbus). Acompanhe a saída de outra máquina:

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

Uma mensagem típica fica assim:

{"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}

Armadilhas do Monitoramento de Inversor Solar

A maioria dos problemas vem de poucas causas:

  • Endereços deslocados em um. A documentação mistura numeração de registradores começando em 0 e em 1. Por isso o script tenta tanto 40000 quanto 39999.
  • Fatores de escala mudam. Alguns inversores alteram o W_SF dinamicamente. Sempre leia o fator de escala na mesma requisição do valor, como o código faz ao ler o bloco inteiro.
  • Período noturno. Muitos inversores desligam a placa de comunicação à noite ou informam o estado "sleeping" com valores vazios. Trate timeouts depois do pôr do sol como normais e mantenha o último valor retido.
  • Taxa de leitura. A cada 5 a 10 segundos é mais que suficiente para dashboards e controle de excedente. Ler várias vezes por segundo não traz ganho e pode perturbar alguns inversores.
  • Medidor versus inversor. O inversor conhece a produção, não o consumo nem a injeção na rede. Para lógica de autoconsumo você também precisa de um medidor da rede; o guia de monitor de energia residencial cobre essa metade.
  • Inversores híbridos com baterias frequentemente expõem os dados da bateria em modelos específicos do fabricante, e não nos modelos SunSpec padrão. Veja monitoramento de bateria residencial para publicar valores do BMS.

Usando os Dados

Com a produção no MQTT, qualquer consumidor pode usá-la sem tocar no inversor de novo. O Home Assistant pode mapear o JSON para sensores pela integração MQTT, o Node-RED pode acionar uma tomada inteligente quando a produção passar de um limite e o Telegraf pode armazenar tudo em um banco de dados de séries temporais para relatórios mensais de geração. Como a mensagem de telemetria é retida, um dashboard aberto ao meio-dia vê a produção atual imediatamente.

As integrações funcionam assim de propósito: o broker é o hub, e cada ferramenta se conecta a ele como cliente MQTT. Se a ideia for nova para você, a visão geral sobre o que faz um broker MQTT explica o modelo publish/subscribe por trás disso.

Indo para Produção com um Broker Privado

Dados solares não são secretos como senhas, mas revelam padrões de ocupação e detalhes do sistema, e o servidor MQTT público é compartilhado. Em uma instalação permanente, rode o publicador em um Raspberry Pi ou servidor doméstico e envie os dados a um broker MQTT na nuvem via TLS. Com o ConnectMQ, crie um broker no portal, copie as credenciais geradas e substitua as linhas de conexão:

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)

Um broker MQTT gerenciado na nuvem também permite ver a produção pelo celular sem expor nada na sua rede doméstica, porque o Raspberry Pi só faz uma conexão de saída. Em um telhado industrial com vários inversores, como o de um galpão em Joinville ou de uma usina de geração distribuída, o mesmo fluxo de telemetria alimenta um gêmeo digital da planta solar. O guia de automação com IoT, mais amplo, mostra como os dados solares se encaixam nos fluxos de energia da casa inteira.

Monitore sua Produção Solar com o ConnectMQ

O ConnectMQ é um broker MQTT gerenciado com TLS na porta 8883, acesso via WebSocket para dashboards no navegador, explorador de topics ao vivo e regras de alerta por limite, por exemplo para avisar quando um inversor informar estado de falha durante o dia. Crie um broker Serverless gratuito em app.connectmq.com, sem cartão de crédito.

Perguntas frequentes

Todo inversor suporta SunSpec Modbus?

Não. Muitas marcas consolidadas de inversores string suportam, muitas vezes depois de ativar a opção nas configurações do instalador, enquanto alguns inversores híbridos e de baixo custo oferecem apenas mapas Modbus RTU específicos do fabricante ou APIs na nuvem. Procure "SunSpec" na documentação do seu modelo.

Com que frequência devo ler o inversor?

A cada 5 a 10 segundos basta para dashboards ao vivo e automações baseadas em excedente. Leituras mais rápidas raramente agregam valor, e alguns inversores reagem mal a elas.

Por que meu script falha à noite?

Muitos inversores desligam a interface de comunicação quando não há entrada fotovoltaica. Trate os timeouts noturnos como esperados e conte com a última mensagem MQTT retida.

Posso controlar o inversor via MQTT?

Alguns inversores aceitam registradores de controle SunSpec para limitação de potência, mas escrever em um inversor pode violar as regras de conexão à rede. Mantenha este tutorial somente leitura, a menos que seu instalador confirme o que é permitido.

Artigos relacionados

Guia de Configuração do Zigbee2MQTT: do Coordenador ao Painel

Instale o Zigbee2MQTT com Docker, configure o coordenador e a conexão MQTT, pareie e renomeie dispositivos, controle-os via MQTT e veja seus estados em um painel, testando primeiro no servidor MQTT público (gratuito).

8 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.