> For the complete documentation index, see [llms.txt](https://portal-integracao.intelbras.com.br/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://portal-integracao.intelbras.com.br/defense-ia-and-lite/readme/uso-do-metodo-mq.md).

# Uso do método MQ

Guia de uso do MQ (MQTT) no Defense IA: autenticação BRMS, GetMqConfig, credenciais/TLS, tópicos de eventos e alarmes, exemplo de cliente Go e troubleshooting.

A MQ é responsável por gerenciar a comunicação assíncrona entre serviços internos da plataforma. Seu papel é garantir que **eventos, alarmes e notificações** sejam entregues de forma confiável, mesmo em condições de falhas temporárias, instabilidade de rede ou indisponibilidade momentânea de serviços consumidores.

***

### O que é o sistema MQ?

O MQ funciona como um **intermediário**: um serviço envia uma mensagem para uma fila (ou tópico) e outro serviço consome essa mensagem no momento adequado.

| Item            | Descrição                                                    |
| --------------- | ------------------------------------------------------------ |
| **Função**      | Troca de mensagens entre sistemas                            |
| **Operação**    | Produtor → Broker → Consumidor                               |
| **Comunicação** | Assíncrona (não depende de resposta imediata)                |
| **Vantagens**   | Confiabilidade, resiliência, escalabilidade e desacoplamento |

***

### Termos importantes

| Termo            | Descrição                                         |
| ---------------- | ------------------------------------------------- |
| **Broker**       | Servidor que recebe, armazena e entrega mensagens |
| **Producer**     | Serviço que envia mensagens para o MQ             |
| **Consumer**     | Serviço que lê/processa mensagens                 |
| **Queue** (Fila) | Canal onde mensagens ficam aguardando consumo     |
| **Topic**        | Canal de publicação/assinatura (modelo Pub/Sub)   |
| **Mensagem**     | Conteúdo enviado (JSON, texto, números, etc.)     |

***

### Tratamento de Erros

| Erro                  | Causa provável       | Ação recomendada                   |
| --------------------- | -------------------- | ---------------------------------- |
| Timeout ao enviar msg | Broker indisponível  | Validar conexão e tentar novamente |
| Mensagem duplicada    | Falha no ACK         | Implementar mecanismo idempotente  |
| Perda de mensagens    | Fila não persistente | Habilitar persistência no broker   |

***

### Autenticação BRMS e obtenção das credenciais MQTT

Antes de poder se conectar ao Broker MQTT, é necessário realizar a autenticação no BRMS. Os passos são:

1. **Primeiro login** (desafio) → retorna `realm`, `publicKey`, `randomKey`
2. **Segundo login** (autenticação) → retorna:
   * `token`
   * `secretKey`
   * `credential`
3. **GetMqConfig** → retorna:
   * Host / Porta do Broker
   * Usuário / Senha MQTT
   * Habilitação de TLS
   * Configurações adicionais

***

### Como utilizar um Broker MQ (MQTT)

Após obter as configurações com `/brms/api/v1.0/BRM/config/GetMqConfig`, você poderá se conectar ao Broker usando qualquer cliente MQTT.

A plataforma utiliza MQTT com TLS e autenticação simples (usuário/senha).

***

### Implementação em Go (MQTT Client)

Esta seção explica o funcionamento e o propósito do cliente Go utilizado para consumir os tópicos de eventos.\
O código base enviado está em **`main.go`**.

<figure><img src="https://3558738335-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fu2gr1s2Izdazx5BlQHLu%2Fuploads%2FV0aLrkG0yfAlTfLxEOLG%2FDefense%20Events%20MQTT-2025-12-11-162251.png?alt=media&amp;token=82a1fb0f-262d-4335-bc27-16c984b2ce12" alt="" width="563"><figcaption></figcaption></figure>

***

### Explicação do Fluxo

#### **1. BRMS**

* Autentica o cliente
* Fornece `token`, `secretKey`, `user`, `password`
* API `/brms/api/v1.0/BRM/config/GetMqConfig` entrega o IP/porta do broker MQTT

#### **2. Broker MQTT**

* Armazena e distribui mensagens
* Tópicos:
  * `mq/event/msg/topic/1`
  * `mq/event/msg/topic/#`
  * `mq/event/alarm/#`

#### **3. Cliente Go (ou Python)**

{% embed url="<https://github.com/Integracao-Intelbras-Cftv/Mqtt-Client.git>" %}
Client pronto para uso
{% endembed %}

* Recebe o HEX do endpoint GetMqConfig
* Decriptografa a senha
* Conecta ao broker via TLS
* Assina tópicos
* Recebe JSON
* Converte para struct (`payloadDefense`)
* Aplica filtros, regras, transformações
* Envia para uma API interna

#### **4. API Interna**

* Armazena eventos
* Gera notificações
* Integra com dashboards, bancos de dados, etc.

### Client MQTT em GO

Cliente em Go que autentica no BRMS (Defense), obtém credenciais e configurações de MQTT e mantém uma assinatura ativa para receber e processar eventos em tempo real.

***

### Arquitetura geral do cliente Go

O cliente executa o fluxo completo:

1. **Lê parâmetros** (flags) com fallback para **variáveis de ambiente**
2. **Gera um par de chaves RSA** (local) para o handshake com o BRMS
3. **Autentica no BRMS** (`/brms/api/v1.0/accounts/authorize`) e obtém:
   * `token` (X-Subject-Token)
   * `secretKey` e `secretVector` (criptografados)
4. **Descriptografa `secretKey` e `secretVector`** com a RSA private key local
5. **Consulta o GetMqConfig** (`/brms/api/v1.0/BRM/Config/GetMqConfig`) usando o `token`, recebendo:
   * `data.mqtt` (`host:port`)
   * `data.userName`
   * `data.password` (HEX criptografado)
   * `data.enableTls` (“1”/“0”)
6. **Descriptografa a senha do MQTT** com AES-CBC (key/iv = secretKey/secretVector)
7. **Conecta ao broker MQTT** (`ssl://` ou `tcp://`) e **assina o tópico**
8. Mantém a aplicação rodando até **CTRL+C**, então desconecta

### Configuração (flags e variáveis de ambiente)

#### Flags disponíveis

* `--host` (default: `192.168.1.108`) → host do Defense/BRMS
* `--port` (default: `443`) → porta HTTPS do Defense/BRMS
* `--user` (default: `system`) → usuário BRMS
* `--pass` (**obrigatório** se não usar ENV) → senha BRMS
* `--topic` (default: `mq/event/msg/topic/#`) → tópico MQTT para assinatura
* `--clientid` (default: `mqtt-client-idDADAsa`) → ClientID MQTT

#### Variáveis de ambiente (fallback)

* `DEFENSE_HOST`
* `DEFENSE_PORT`
* `DEFENSE_USER`
* `DEFENSE_PASSWORD`

{% hint style="info" %}
Se algum parâmetro obrigatório faltar, o programa encerra com erro indicando o parâmetro faltante.
{% endhint %}

***

### Módulo HTTP/API (BRMS)

O cliente usa um wrapper simples `api` para requisições HTTPS:

* Sempre adiciona `Content-Type: application/json`
* Se houver token, adiciona `X-Subject-Token: <token>`
* Usa timeout de 8s por chamada
* TLS está com `InsecureSkipVerify: true` (modo teste)

{% hint style="info" %}
**Produção:** validar certificado (CA confiável/pinning) e remover `InsecureSkipVerify`.
{% endhint %}

***

### Autenticação no BRMS e obtenção de chaves

#### Objetivo

* `token` (para chamadas autenticadas)
* `secretKey` e `secretVector` (para descriptografar a senha do MQTT)

#### Função principal do fluxo

`GetDefenseKeysAndToken(cfg Config) (secretKey, secretVector, token string, err error)`

#### Passo a passo

1. **Gera RSA local (2048 bits)** via `RSAx.GenerateKeyPair(2048)`
2. **Monta a public key limpa** (`buildPublicKeyClean`)
   * Converte para PEM
   * Remove header/footer e quebras de linha
3. **Chama `Defense.Auth(...)`** que executa 2 POSTs no endpoint `/brms/api/v1.0/accounts/authorize`

***

### Etapas do endpoint `/accounts/authorize`

#### 1) EncData (pré-desafio)

Envia `EncDataPayload` e recebe `EncDataRes`:

```go
type EncDataRes struct {
  Realm       string `json:"realm"`
  RandomKey   string `json:"randomKey"`
  EncryptType string `json:"encryptType"`
  Publickey   string `json:"publickey"`
}
```

* `realm` e `randomKey` são usados para calcular a assinatura.
* A `publickey` retornada pode ser substituída pela public key gerada localmente (limpa).

{% hint style="info" %}
Observação do código: `EncData.CreatePayload(username string)` define `UserName: "system"` e `ClientType: "WINPC_V2"`.\
Se você quiser respeitar o `username` informado, ajuste esse método.
{% endhint %}

#### 2) Auth (autenticação final)

Calcula `signature` e envia `AuthPayload`, recebendo `AuthRes`:

```go
type AuthRes struct {
  Token        string `json:"token"`
  SecretKey    string `json:"secretKey"`
  SecretVector string `json:"secretVector"`
  Code         int    `json:"code"`
}
```

Se o `Token` vier vazio, o cliente falha com `token not created`.

***

### Como a assinatura (signature) é calculada

A assinatura usa MD5 encadeado (`Auth.CreateSignature()`):

1. `md5(password)`
2. `md5(username + hash)`
3. `md5(hash)`
4. `md5(username + ":" + realm + ":" + hash)`
5. `md5(hash + ":" + randomKey)`

Resultado final → `Signature`.

Esse esquema combina credenciais com valores dinâmicos da sessão (`realm`, `randomKey`).

{% hint style="info" %}
Mesmo processo do desafio para recebimento do Token.
{% endhint %}

***

### Descriptografia do `secretKey` e `secretVector`

O servidor retorna `secretKey` e `secretVector` em formato criptografado (às vezes base64).

O cliente:

* tenta `base64 decode` primeiro
* depois descriptografa com RSA private key local (`rsa.DecryptPKCS1v15`)

Função central: `RSAx.Decrypt(ciphertext []byte)`.

***

### GetMqConfig (obter credenciais do broker MQTT)

Endpoint:

* `POST /brms/api/v1.0/BRM/Config/GetMqConfig`
* Header: `X-Subject-Token: <token>`
* Body: `{}`

Resposta mapeada em:

```go
type MqConfigRes struct {
  Code int    `json:"code"`
  Desc string `json:"desc"`
  Data struct {
    EnableTls string `json:"enableTls"`
    Password  string `json:"password"` // HEX
    Mqtt      string `json:"mqtt"`     // host:port
    Addr      string `json:"addr"`
    UserName  string `json:"userName"`
  } `json:"data"`
}
```

Validações:

* `Code == 1000`
* `Data.Password`, `Data.UserName`, `Data.Mqtt` preenchidos

***

### Descriptografia da senha MQTT (HEX → AES-CBC)

A senha vem como `Data.Password` em **HEX**. O fluxo:

1. HEX → bytes (`hex.DecodeString`)
2. bytes → base64 (`base64.StdEncoding.EncodeToString`)
3. AES-CBC decrypt (`GetAESDecrypted`):
   * `key = secretKey`
   * `iv = secretVector`
4. Remove padding PKCS5 (`PKCS5UnPadding`)

Funções envolvidas:

* `DecryptPassword(passwordHex, sk, sv)`
* `GetAESDecrypted(encryptedBase64, key, iv)`
* `PKCS5UnPadding(src []byte)`

***

### MQTT: assinatura e processamento de eventos

### Conexão ao broker

O broker é construído a partir de `mqCfg.Data.Mqtt` (`host:port`):

* Se `EnableTls == "1"` → `ssl://host:port`
* Caso contrário → `tcp://host:port`

Opções do client:

* `ClientID` via `--clientid`
* `Username` via `mqCfg.Data.UserName`
* `Password` via `mqttPass` descriptografado
* TLS opcional com `InsecureSkipVerify: true` (teste)

***

### Estrutura do Payload (eventos)

O JSON recebido no tópico é convertido na struct `payloadDefense`:

```go
type payloadDefense struct {
  Method string `json:"method"`
  Info []struct {
    DeviceCode      string   `json:"deviceCode"`
    AlarmType       string   `json:"alarmType"`
    AlarmDate       string   `json:"alarmDate"`
    DeviceName      string   `json:"deviceName"`
    AlarmGrade      string   `json:"alarmGrade"`
    MapIds          []string `json:"mapIds"`
    // ... demais campos do seu código
  } `json:"info"`
}
```

Notas:

* `Info` é um **array**: podem vir múltiplos itens no mesmo evento.
* Alguns campos estão como `[]any` para flexibilidade (quando schema varia).

***

### Explicação do `messageHandler`

Toda mensagem recebida aciona `messageHandler`:

* lê payload bruto
* imprime diagnóstico (tamanho, tópico, conteúdo)
* faz `json.Unmarshal` para `payloadDefense`
* a partir daí, permite processar campos tipados

Trecho:

```go
func messageHandler(_ MQTT.Client, msg MQTT.Message) {
  currentDefPayload = string(msg.Payload())
  fmt.Printf("Tamanho: %d\n", len(currentDefPayload))
  fmt.Printf("Topic: %s\n", msg.Topic())

  var evento payloadDefense
  if err := json.Unmarshal(msg.Payload(), &evento); err != nil {
    fmt.Printf("Error decoding JSON: %v\n", err)
    return
  }
}
```

{% hint style="info" %}
Para uso “real”, o ideal é percorrer `evento.Info` com `for _, item := range evento.Info { ... }`.
{% endhint %}

***

### Assinatura do tópico

Assinatura no `main()`:

```go
client.Subscribe(*topic, 0, messageHandler)
```

* QoS = **0** (rápido, sem confirmação)
* Para mais confiabilidade, considerar QoS 1/2

Default do projeto:

* `mq/event/msg/topic/#`

***

### Mantendo o serviço rodando e encerramento

O programa aguarda CTRL+C:

```go
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
client.Disconnect(250)
```

***

### Como rodar

### Exemplo via flags

```bash
go run main.go \
  --host 192.168.1.108 \
  --port 443 \
  --user system \
  --pass SUA_SENHA \
  --topic "mq/event/msg/topic/#" \
  --clientid "mqtt-client-01"
```

### Exemplo via ENV + flags mínimas

```powershell
DEFENSE_HOST="Host"
DEFENSE_PORT="PortadeServiço"
DEFENSE_USER="UserdoDefense"
DEFENSE_PASSWORD="SUA_SENHA"

go run main.go --topic "mq/event/msg/topic/#"
```

go run main.go --host IPdoservidor --port porta --user UserdoDefense --pass 'SuaSenha'

***

### Exemplo de mensagem recebida

Exemplo compatível com o schema:

```json
{
  "method": "alarm",
  "info": [{
    "deviceCode": "ABC123",
    "deviceName": "Cam 01",
    "alarmType": "HumanDetection",
    "alarmDate": "2025-01-11 14:33:10",
    "alarmGrade": "1",
    "mapIds": ["map-01"]
  }]
}
```

***

### Troubleshooting (Possíveis erros)

#### 1) token not created

* Senha/usuário BRMS incorretos
* Problema de conectividade HTTPS com o host/porta
* Fluxo de assinatura (MD5) divergente do esperado

#### 2) Falha ao descriptografar `secretKey/secretVector`

* O servidor pode estar retornando em formato diferente (base64 vs raw)
* Chave pública enviada inválida (formatação PEM/limpeza)

#### 3) GetMqConfig returned `code != 1000`

* Token inválido/expirado
* Permissão do usuário não habilitada para o endpoint
* Verificar `desc` retornado

#### 4) ciphertext is not a multiple of block size

* `Data.Password` não está no formato esperado
* `secretKey/secretVector` incorretos (falha na etapa RSA)

#### 5) Conecta no broker, mas não recebe eventos

* Tópico incorreto (wildcard/prefixo)
* Broker/usuário sem permissão de subscribe no tópico
* Eventos não estão sendo publicados naquele namespace

***

### Recomendações de produção (hardening)

* **TLS**: remover `InsecureSkipVerify` e validar certificado
* **Auto-reconnect**: habilitar `SetAutoReconnect(true)` e callbacks (`OnConnectionLost`)
* **Logging**: evitar logar payload completo em produção (pode conter dados sensíveis)
* **Processamento**: iterar todos os itens em `info[]` e tratar casos de payload parcial

***


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://portal-integracao.intelbras.com.br/defense-ia-and-lite/readme/uso-do-metodo-mq.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
