MQTT - O protocolo da IoT (Internet das Coisas) II

Primeiros exemplos de software

Nesse post vamos ver como é fácil trocar mensagens usando-se o MQTT, em diferentes linguagens e sistemas operacionais.

1) O Broker

Para os nossos testes usaremos o broker do Eclipse, que é publicado pelo site iot.eclise.org. É muito fácvil usá-lo, vc não tem que fazer inscrição nem nada, basta acessar o endereço iot.eclipse.org na porta 1883 com um cliente MQTT e pronto. Na realidade é um broker Mosquitto que os caras deixaram "aberto ao público".

Outros clientes MQTT públicos podem ser encontrados aqui.

2) Python no PC

Vamos começar com o Python para aprender como conectar coisas através do MQTT.
Importante: todos os exemplos em Python desse blog são em Python 2.7. Devem funcionar para versões mais recentes.

O que precisamos:

1) Instalar o Python no Windows. Para isso, aqui tem um bom roteiro em português.

2) Instalar o cliente MQTT Python para que esteja disponível para nosso uso. Para isso, siga o roteiro abaixo.  Se vc já tem o pip instalado e funcionando, pode pular pro item "c" abaixo.

   a) Primeiro instale o easy_install. Eu usei essa versão aqui. Depois adicione o easy_install ao seu path, ou então execute-o a partir do diretório onde foi instalado: C:\Python27\Scripts.

   b) Depois você pode instalar o pip, que é uma "casca" em python para o easy_install. Comando:

   c:\python27\Scripts\easy_install pip

   c) Por fim, instale o pacote Paho, que é o client mais popular para MQTT em Python:

   c:\python27\Scripts\pip install paho-mqtt

Agora, ao código:
# -*- coding: utf-8 -*-
import paho.mqtt.client as mqtt

ipBroker = "iot.eclipse.org"
portBroker = 1883

def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))
    client.subscribe("$SYS/#")
    
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    print(msg.topic+" "+str(msg.payload))

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.connect(ipBroker,portBroker,60)

client.loop_forever()

Esse código subscreve as mensagens publicadas pelo SYS/#, que é a tag das mensagens do próprio broker.

Essas linhas são as que criam o objecto client, definindo duas callbacks (funções que são chamadas quando ocorrem eventos do MQTT): on_connect, que é chamada após a conexão e a on_message, que é chamada a cada mensagem que é recebida.

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.connect(ipBroker,portBroker,60)

Observe que colocamos a instrução de subscrição da mensagem dentro do calback on_connect. Isso é feito assim para que, uma vez que a conexão seja perdida, ao ser restabelecida a subscrição será novamente feita.


def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))
    client.subscribe("$SYS/#")

Ao executar esse código "de dentro" do Python, vc vai ver algo como:

Python 2.7.6 (default, Nov 10 2013, 19:24:18) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>> 
Connected with result code 0
$SYS/broker/version mosquitto version 1.3.2
$SYS/broker/timestamp 2014-07-22 07:11:39-0400
$SYS/broker/changeset 437df4dc8accc0cbf652a2c169c9d8cc85c0f2bf
$SYS/broker/clients/total 13132
$SYS/broker/clients/active 275
$SYS/broker/clients/inactive 12857
$SYS/broker/clients/maximum 13132
$SYS/broker/clients/expired 0
$SYS/broker/messages/received 14083665
$SYS/broker/messages/sent 31839636
$SYS/broker/messages/stored 155234
$SYS/broker/bytes/received 2058300766
$SYS/broker/bytes/sent 2375988666
$SYS/broker/publish/messages/received 4834330
$SYS/broker/publish/messages/sent 21818090
$SYS/broker/publish/messages/dropped 17708425
$SYS/broker/publish/bytes/received 1188558495
$SYS/broker/publish/bytes/sent 8174454185
$SYS/broker/subscriptions/count 20154
$SYS/broker/connection/m2m.cosm-data/state 1
$SYS/broker/connection/zenzium3.zenzium1/state 1
$SYS/broker/connection/zenzium3.m2m/state 1
$SYS/broker/connection/lt022.m2m.eclipse.org/state 0
$SYS/broker/connection/lt022.brigde-to-me/state 0
$SYS/broker/uptime 2247659 seconds
$SYS/broker/retained messages/count 149976
$SYS/broker/heap/current 298899392
$SYS/broker/heap/maximum 455509304
$SYS/broker/load/messages/received/1min 480.04
$SYS/broker/load/messages/received/5min 453.04
$SYS/broker/load/messages/received/15min 446.98
$SYS/broker/load/messages/sent/1min 411.49
$SYS/broker/load/messages/sent/5min 392.83

2) Python no Linux (Raspbian, do Raspberry Pi)

Nesse caso também vc deve instalar o cliente MQTT paho, só que o Python já estará instalado e o pip também, então será só dar o comando abaixo, numa janela do terminal:

   pip install paho-mqtt

Em seguida, se vc executar o mesmíssimo programa acima, obterá os mesmos resultados.

3) C# .Net

Agora vamos ver como subscrever a mesma lista de mensagens no C# .Net. A primeira coisa é instalar o client MQTT no Visual Studio. O exemplo abaixo foi feito no Visual Studio 2013 Express, versão gratuita, então certamente funcionará nas versões mais parrudas do VS.

Para "pegar" a lib, podemos usar  o NuGet de dentro do VS mesmo. Para isso:

       a) Crie uma nova aplicação C# WinForms.

       b) Clique com o botão direito em cima do nome do projeto no Solution Explorer. Selecione a opção Manage NuGets Packages.

       c) Na caixa Search, digite: M2Mqtt. O Manager vai fazer os downloads necessários e também adicionar ao seu projeto as referências às assemblies necessárias, no caso M2Mqtt.

Ao código, então. Fiz um form com quatro "TextBoxes": Um para informar a URL do broker, outro para a porta, um terceiro para informar a tag das mensagens a serem subscritas e um quarto para exibir as mensagens. Um botão inicia o funcionamento:


Aqui, os fontes, como é de lei nesse blog:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;

namespace MQTT.Net
{
    
    public partial class Form1 : Form
    {
        MqttClient mqttclient = null;

        public Form1()
        {
            InitializeComponent();
        }

        delegate void SetTextCallback(string text);

        private void SetText(string text)
        {
            if (this.Messages.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
                Messages.AppendText(text+"\r\n");
        }

        private void Go_Click(object sender, EventArgs e)
        {
            // Create client
            mqttclient = new MqttClient(Broker.Text);
            
            // Set the message receive event
            mqttclient.MqttMsgPublishReceived += 
                client_MqttMsgPublishReceived;

            // Connect to the broker
            string clientId = Guid.NewGuid().ToString();
            mqttclient.Connect(clientId);

            // Subscribe messages
            mqttclient.Subscribe(new string[] { Subscribe.Text }, 
                new byte[] { MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE });
        }

        void client_MqttMsgPublishReceived(object sender, 
            MqttMsgPublishEventArgs e)
        {
            // The MQTT lib engine runs in another tread, so it´s necessary 
            // to do some trick to update Messages.Text property.
            // See SetText above.
            SetText(e.Topic);
        }

    }
}

À exceção do "truquinho" por causa das threads diferentes, nada de complicado, nénão?

Abaixo, uma imagem dos três subscribers rodando simultaneamente, recebendo as mensagens do $SYS/# no broker do eclipse.org. A tela em azul mais à direita é a aplicação Python rodando no Windows, a azul mais ao fundo à esquerda tá rodando no Raspberry via Terminal Services. E a tela à frente é a .Net C#.

CQD, molezinha.




















No próximo post vamos fazer um aplicação completa envolvendo Arduino e também estressar um pouco o servidor com mensagens rápidas.

Abracadabraço, até o próximo post.

Comentários

  1. Parabéns pelo post Mauro!

    ResponderExcluir
  2. Boa tarde Mauro. estou estudando sobre automacao e as melhoras formas de fazer o raspberry funcionar como servidor. Vi que voce utilizou o C#, gostaria de utilizar outra linguagem, talvez php. É possível? Tambem gostaria de tirar umas duvidas com voce a medida que forem surgindo caso nao haja problema. Grato

    ResponderExcluir
    Respostas
    1. Marcus, a parte do Pi eu fiz em Python, a do Windows em C#. Acredito que certamente deve ser possível fazer em php, basta vc achar o client Mosquitto.

      Excluir
    2. fazer essa conexao eh tranquilo. gostaria de saber como funciona a parte de envio e recebimento de pacoes. ta meio nebuloso.

      Excluir
    3. A parte de envio e recebimento de pacotes é encapsulada pela biblioteca. Vc só envia mensagens, e assina as mensagens do outro lado. Quando vc envia a mensagem e ela chega no servidor, um evento é gerado no aplicativo cliente.

      Excluir
  3. poderiamos fazer a parte 3 com a camera pi. eu posso disponibilzar minha picamera para vc tirar fotos ou videos ou te notificar quando a ultima foto ou videos foi tirado. seria um teste bem legal...

    ResponderExcluir
  4. Este comentário foi removido pelo autor.

    ResponderExcluir
  5. Ola
    No caso do c#, estou tentando mostrar o topico + a mensagem, usando:

    SetText(e.Topic + '/' + e.Message );

    enviando o tópico VP e a mensagem Ola.

    Na tela do mqttlens retorna ok, mas no form do c# recebo

    VP/System.byte[]

    Agradeço a ajuda

    ResponderExcluir
    Respostas
    1. Vidal, é porque a mensagem está vindo em formato binário para o C#, provavelmente. Tente usar o depurador para entender melhor como a mensagem está chegando e faça a conversão adequada.

      Excluir
    2. Ola.
      Agradeço sua atenção.
      Encontrei a resposta.
      O tópico vem em formato string, mas a mensagem em array de caracteres.
      Basta usar:
      SetText(System.Text.Encoding.UTF8.GetString(e.Message));

      Vidal

      Excluir
  6. Show de artigo, apenas sugiro trocar o link de "iot.eclise.org" por "iot.eclipse.org". O primeiro link está redirecionando para o azure...

    ResponderExcluir
  7. fimeAcaiku-1978 Frankie Fernandez Here
    glebdefpurpven

    ResponderExcluir

Postar um comentário

Postagens mais visitadas deste blog

Controle PID de Potência em Corrente Alternada - Arduino e TRIAC - Parte III

Dividindo um programa (sketch) do Arduino em mais de um arquivo

Controle PID de Potência em Corrente Alternada - Arduino e TRIAC - Parte I