Integração do Protocolo MQTT em Aplicações Angular

Introdução ao Angular e MQTT

Angular é uma robusta plataforma de desenvolvimento baseada em TypeScript, ideal para a construção de aplicações web escaláveis. Ela oferece um framework de compnoentes, um conjunto de bibliotecas bem integradas para funcionalidades como roteamento, gerenciamento de formulários e comunicação cliente-servidor, além de ferramentas completas para o ciclo de vida do desenvolvimento.

O MQTT (Message Queuing Telemetry Transport) destaca-se como um protocolo de mensagens leve e eficiente, utilizando o padrão de publicação/assinatura, o que o torna uma escolha excelente para cenários de Internet das Coisas (IoT). Ele facilita a distribuição de mensagens um-para-muitos, desacopla aplicações e minimiza o tráfego de rede, oferecendo ainda diferentes níveis de Qualidade de Serviço (QoS) para atender a diversas necessidades de entrega.

Este artigo demonstrará como incorporar o protocolo MQTT em projetos Angular, cobrindo desde a conexão com um servidor MQTT até a publicação, subscrição de mensagens e o gerenciamento de inscrições.

Preparação do Ambiente de Desenvolvimento

Criação de um Novo Projeto Angular

Para iniciar, crie uma nova aplicação Angular utilizando o Angular CLI. Se o CLI não estiver instalado, você pode instalá-lo globalmente via npm.

ng new nome-do-projeto
cd nome-do-projeto

Instalação da Biblioteca Cliente MQTT

Para interagir com o MQTT em Angular, utilizaremos a biblioteca ngx-mqtt. Esta é uma camada sobre o MQTT.js, adaptada para Angular (versões 2 e superiores), que faz um excelente uso de Observables e gerencia o ciclo de vida das subscrições e o roteamento de mensagens, sendo particularmente útil em aplicações complexas com múltiplos componentes e subscritores.

Instale ngx-mqtt via npm ou yarn:

npm install ngx-mqtt --save
# ou
yarn add ngx-mqtt

Utilização do Protocolo MQTT

Configuração e Conexão ao Servidor MQTT

Para os exemplos a seguir, utilizaremos um servidor MQTT público e gratuito, oferecido pela EMQX, que é uma plataforma de mensagens MQTT distribuída de alta performance, ideal para conectar uma vasta gama de dispositivos IoT.

Detalhes do Broker Público:

  • Broker: broker.emqx.io
  • Porta TCP: 1883
  • Porta WebSocket: 8083

Para estabelecer a conexão no seu projeto Angular, configure um serviço ou componente conforme o exemplo abaixo. Neste trecho, definimos os parâmetros de conexão e tratamos os eventos de conexão, erro e recebimento de mensagens.

import { Component } from '@angular/core';
import { IMqttMessage, IMqttServiceOptions, MqttService, IPublishOptions } from 'ngx-mqtt';
import { IClientSubscribeOptions } from 'mqtt-browser';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-mqtt-dashboard',
  templateUrl: './mqtt-dashboard.component.html',
  styleUrls: ['./mqtt-dashboard.component.scss'],
})
export class MqttDashboardComponent {
  private activeSubscription: Subscription | undefined;
  private mqttClientService: MqttService;

  public isClientConnected: boolean = false;
  public subscriptionEstablished: boolean = false;

  public connectionParameters = {
    brokerHost: 'broker.emqx.io',
    webSocketPort: 8083,
    basePath: '/mqtt',
    cleanSession: true, // Manter sessão limpa
    connectionTimeoutMs: 4000, // Tempo limite para conexão
    reconnectIntervalMs: 4000, // Intervalo para tentativas de reconexão
    clientId: 'angular_client_' + Math.random().toString(16).substr(2, 8), // ID de cliente único
    authUsername: 'emqx_user',
    authPassword: 'emqx_password',
    protocolType: 'ws' as 'ws', // Protocolo WebSocket
  };

  public subscriptionSettings = {
    topicToSubscribe: 'angular/data',
    qosLevel: 0,
  };

  public messagePublisher = {
    targetTopic: 'angular/command',
    qosLevel: 0,
    payloadData: '{ "action": "ping", "timestamp": ' + Date.now() + ' }',
  };

  public receivedMessagesLog: string[] = [];

  public qualityOfServiceOptions = [
    { label: 'QoS 0 (No Ack)', value: 0 },
    { label: 'QoS 1 (At Least Once)', value: 1 },
    { label: 'QoS 2 (Exactly Once)', value: 2 },
  ];

  constructor(private mqttService: MqttService) {
    this.mqttClientService = mqttService;
  }

  // Função para estabelecer a conexão MQTT
  public initiateMqttConnection(): void {
    const opts: IMqttServiceOptions = {
      hostname: this.connectionParameters.brokerHost,
      port: this.connectionParameters.webSocketPort,
      path: this.connectionParameters.basePath,
      clean: this.connectionParameters.cleanSession,
      connectTimeout: this.connectionParameters.connectionTimeoutMs,
      reconnectPeriod: this.connectionParameters.reconnectIntervalMs,
      clientId: this.connectionParameters.clientId,
      username: this.connectionParameters.authUsername,
      password: this.connectionParameters.authPassword,
      protocol: this.connectionParameters.protocolType,
    };

    try {
      this.mqttClientService.connect(opts);
    } catch (error) {
      console.error('Falha ao tentar conectar ao MQTT:', error);
      this.isClientConnected = false;
    }

    this.mqttClientService.onConnect.subscribe(() => {
      this.isClientConnected = true;
      console.log('Conexão MQTT realizada com êxito!');
    });

    this.mqttClientService.onError.subscribe((error: any) => {
      this.isClientConnected = false;
      console.error('Erro na conexão MQTT:', error);
    });

    this.mqttClientService.onMessage.subscribe((packet: IMqttMessage) => {
      const msgContent = packet.payload.toString();
      this.receivedMessagesLog.push(`[${new Date().toLocaleTimeString()}] Tópico: ${packet.topic}, Mensagem: ${msgContent}`);
      console.log(`Mensagem recebida do tópico ${packet.topic}: ${msgContent}`);
    });
  }
}

Inscrição em um Tópico

Após uma conexão bem-sucedida, você pode se inscrever em um tópico específico para receber mensagens. O método observe da biblioteca ngx-mqtt retorna um Observable, permitindo gerenciar o fluxo de mensagens de forma reativa.

  // Dentro da classe MqttDashboardComponent
  public subscribeToMqttTopic(): void {
    const { topicToSubscribe, qosLevel } = this.subscriptionSettings;
    const subscribeOptions: IClientSubscribeOptions = { qos: qosLevel };

    this.activeSubscription = this.mqttClientService.observe(topicToSubscribe, subscribeOptions).subscribe({
      next: (message: IMqttMessage) => {
        this.subscriptionEstablished = true;
        console.log(`Inscrição no tópico '${message.topic}' ativa. Última mensagem: ${message.payload.toString()}`);
      },
      error: (error) => {
        console.error('Erro ao subscrever o tópico:', error);
        this.subscriptionEstablished = false;
      },
      complete: () => {
        console.log('Ciclo de subscrição completado.');
        this.subscriptionEstablished = false;
      }
    });
  }

Cancelamento da Inscrição

Para parar de receber mensagesn de um tópico, você deve cancelar a inscrição. O método unsubscribe() no objeto Subscription liberará os recursos associados.

  // Dentro da classe MqttDashboardComponent
  public unsubscribeFromMqttTopic(): void {
    if (this.activeSubscription) {
      this.activeSubscription.unsubscribe();
      this.subscriptionEstablished = false;
      console.log('Inscrição no tópico foi cancelada.');
    } else {
      console.warn('Não há nenhuma subscrição ativa para cancelar.');
    }
  }

Publicação de Mensagens

Para enviar dados para um tópico MQTT, utilize o método unsafePublish. Este método permite especificar opções adicionais como QoS e Retain.

  // Dentro da classe MqttDashboardComponent
  public publishMqttMessage(): void {
    const { targetTopic, qosLevel, payloadData } = this.messagePublisher;
    const publishOptions: IPublishOptions = { qos: qosLevel };

    if (this.mqttClientService) {
      this.mqttClientService.unsafePublish(targetTopic, payloadData, publishOptions).subscribe({
        next: () => console.log(`Mensagem publicada no tópico '${targetTopic}' com sucesso.`),
        error: (error) => console.error('Falha ao publicar a mensagem:', error)
      });
    } else {
      console.warn('Cliente MQTT não inicializado; incapaz de publicar mensagens.');
    }
  }

Desconexão do Cliente

Para finalizar a sessão MQTT, chame o método disconnect. Passar true como parâmetro garante uma desconexão forçada.

  // Dentro da classe MqttDashboardComponent
  public terminateMqttConnection(): void {
    try {
      if (this.mqttClientService) {
        this.mqttClientService.disconnect(true); // Forçar desconexão
        this.isClientConnected = false;
        this.subscriptionEstablished = false;
        console.log('Cliente MQTT desconectado com sucesso!');
      }
    } catch (error) {
      console.error('Falha ao desconectar o cliente MQTT:', error);
    }
  }

Teste de Funcionalidade

Com o código implementado no Angular, é possível desenvolver uma interface de usuário simples que exponha as funcionalidades de conectar, subscrever, publicar, cancelar subscrição e desconectar. Para testar a comunicação de ponta a ponta, pode-se usar uma ferramenta cliente MQTT como o MQTT X.

Ao conectar o aplicativo Angular e o MQTT X ao mesmo broker, é possível:

  • Publicar mensagens do Angular para um tópico e visualizá-las no MQTT X.
  • Publicar mensagens do MQTT X para um tópico e recebê-las no Angular (se o Angular estiver subscrito a esse tópico).
  • Validar o cancelamento da subscrição: submeta o Angular a um tópico, envie algumas mensagens do MQTT X, cancele a subscrição no Angular e, em seguida, tente enviar mais mensagens do MQTT X. O Angular não deverá mais receber essas últimas mensagens, confirmando que a subscrição foi corretamente encerrada.

Tags: Angular MQTT TypeScript ngx-mqtt WebSockets

Publicado em 6-29 22:15