Depois de bater cabeça com um no-break NHS que nenhum driver aberto reconhece, acabei decifrando o protocolo dele e trazendo toda a telemetria pro Home Assistant sem depender do software oficial da NHS. Fica aqui o tutorial completo — e o método serve pra outros modelos NHS.
O que você tem no final: sensores de tensão de entrada/saída, tensão de bateria, carga %, temperatura e um binário “na bateria”, tudo via MQTT Discovery + um dashboard bonitinho.

Ambiente testado
- No-break: NHS Premium PDV GII 2200VA, USB-CDC (
/dev/ttyACM0, USB ID0925:1241), placa v18 / firmware v80 - Host: Proxmox VE 9 (Debian 13) — mas serve pra qualquer Linux
- HA: add-on Mosquitto (MQTT) + integração MQTT
Cada família de NHS pode ter pequenas diferenças de escala. Veja a seção “Adaptando pro seu modelo” — o método de captura serve pra todos.
Por que não dá pra usar NUT
Se você chegou aqui procurando “NHS + NUT”, já adianto: não funciona com este modelo. Testei tudo:
nhs_upsnão existe na build do NUT do Debian (a premissa “o Debian já traz” está errada);nhs_ser(compilado do fonte oficial) roda mas retorna 0 bytes;nutdrv_qx/blazer_*(Megatec/Q1) →read: timeoutem todos os comandos.
Motivo: o NHS é reply-only e fala um protocolo proprietário — só responde a um comando específico e não transmite sozinho (escuta passiva retorna 0 bytes). Por isso o clyra/nhs2mqtt (que é passivo) também não pega. A saída foi enviar o comando certo.
O protocolo (o que descobri)
- Serial:
2400 8N1, sem paridade,CLOCAL(ignora DTR/RTS — não precisa mexer nas linhas), modo raw. - Enquadramento:
FF <len> <payload...> <checksum> FE(início0xFF, fim0xFE).
Comandos capturados (o software oficial alterna os dois):
| Enviar (hex) | Resposta | Conteúdo |
|---|---|---|
FF 05 01 06 FE |
FF 15 44 …(21B)… FE (tipo 0x44=‘D’) |
Status: tensões, bateria, carga, temp |
FF 09 53 03 00 00 00 5F FE |
FF 12 53 …(18B)… FE (tipo 0x53=‘S’) |
Equipamento: modelo, firmware, placa |
Decode do frame de STATUS — seja b o frame sem o 0xFF inicial. Exemplo:
ff 15 44 74 00 88 00 07 73 00 74 00 75 00 24 00 00 40 00 1c fe
| Campo | Bytes | Fórmula |
|---|---|---|
| Tensão de entrada (V) | b[2],b[3] |
b2 + b3/100 |
| Tensão de bateria (V) | b[4],b[5] |
b4/5 (neste modelo; ver nota) |
| Carga (%) | b[6] |
valor direto |
| Entrada mín / máx (V) | b[7-8] / b[9-10] |
b + b/100 |
| Tensão de saída (V) | b[11],b[12] |
b + b/100 |
| Temperatura (°C) | b[13],b[14] |
b + b/100 |
| Corrente do carregador (mA) | b[15] |
b/25*750 |
| Flags | b[16] |
0x40=rede presente · 0x80=carregador (cai o 0x40 na falta de rede) |
Nota da bateria: aqui a bateria (24V nominal) veio como
b[4]/5(raw 136 → 27.2V). O parser doclyra/nhs2mqttusa outra fórmula. Confira com o software oficial e calibre.
Como capturei o comando (método reutilizável)
O software oficial “NHS Control” (nhsupsserver) conversa com o aparelho. Grampeei a serial dele com strace e li o writev (o comando enviado):
# instale o NHS Control oficial (Linux x86_64), configure a porta
# /dev/ttyACM0 na UI web (localhost:2001) e então:
PID=$(pidof nhsupsserver)
strace -f -p $PID -e trace=%desc -s 500 -o /tmp/nhs.strace # ~30s, Ctrl+C
grep -nE 'writev\([0-9]+,' /tmp/nhs.strace | head
Foi assim que apareceram os bytes FF 05 01 06 FE. %desc é essencial — o software usa readv/writev, que um strace -e read,write não pega. (Detalhe: o auto-detect do NHS Control só varre ttyS*; para USB ttyACM*, selecione a porta manualmente na UI.)
Instalação (poller → MQTT → HA)
Pré-requisitos: no-break no USB, um broker MQTT (add-on Mosquitto) + integração MQTT no HA, e Python 3:
dmesg | grep -i -e tty -e acm # confirme a porta (/dev/ttyACM0)
sudo apt install -y python3-serial python3-paho-mqtt
- Copie
nhs2mqtt.pypara/usr/local/bin/echmod +x. - Copie o
.conf.examplepara/etc/nhs2mqtt.conf, preencha host/usuário/senha do MQTT,chmod 600. - Teste em primeiro plano:
python3 /usr/local/bin/nhs2mqtt.py→ deve imprimir{'vin': 124.0, 'load': 7, 'temp': 36.0, ...}. - Instale como serviço:
sudo cp nhs2mqtt.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now nhs2mqtt
Em segundos o HA cria sozinho (MQTT Discovery) o dispositivo “Nobreak NHS” com os sensores.
Se você tinha o NHS Control ou algum driver do NUT instalado, pare/desabilite — eles disputam a
/dev/ttyACM0com o poller.
Dashboard
Card em vertical-stack com Mushroom + mini-graph-card (via HACS): estado “na rede/na bateria”, carga, bateria, temperatura e gráficos de entrada×saída e carga/temperatura (24h). O YAML completo está no repositório.

Dá até pra acompanhar a rede elétrica oscilando ao longo do dia:

Shutdown automático — a pegadinha do religamento
Cuidado com uma armadilha clássica: a BIOS “Restore on AC Power Loss = Power On” só religa a máquina quando a fonte perde e recupera energia de verdade. Se você faz um shutdown gracioso com a bateria ainda cheia e a rede volta antes da bateria acabar, a fonte nunca perdeu energia → a BIOS não dispara → a máquina fica desligada (ruim pra site remoto).
Por isso aqui eu fiquei na opção “só telemetria + aviso”: deixo a bateria descarregar até o no-break cortar a saída sozinho; a máquina perde energia de fato e a BIOS religa quando a rede volta (o ZFS tolera bem a queda). Monte uma automação de aviso a partir do binary_sensor.*_nobreak_na_bateria.
Adaptando pro seu modelo NHS
- Rode o poller e compare com a UI do NHS Control (
:2001), lado a lado (a porta é exclusiva, não simultâneo). - Carga e temperatura costumam bater direto. Tensões/bateria podem precisar de outro fator — ajuste as fórmulas em
decode(). - Se o seu NHS não responder a
FF 05 01 06 FE, capture o comando dele pelo método dostraceacima. - Mapeie o
flags(b[16]) tirando o aparelho da tomada e vendo quais bits mudam.
Código
Tudo no GitHub (poller, config de exemplo, serviço systemd e o card do dashboard):
Se este tutorial te ajudou, deixa uma
no repositório — ajuda outros donos de NHS a encontrarem o projeto. ![]()
Créditos ao clyra/nhs2mqtt (GitHub - clyra/nhs2mqtt: Um script simples para ler o status de um nobreak NHS com interface USB e enviar para um broker MQTT · GitHub) pela base do decode do frame — aqui adaptei pra enviar o comando de polling e calibrar este modelo.
Sem garantia — mexer na serial de um no-break é por sua conta e risco.
Alguém mais aí tem NHS e quer testar? Se rodarem em outro modelo, me contem os valores que aparecem no decode() que a gente vai mapeando a família toda. ![]()