MESTRADO EM COMPUTAÇÃO APLICADA
Computação Móvel - Prof Dr. Willingthon Pavan JOGO DA VELHA IOT ARDUINO VERSUS ANDROID
Introdução A disciplina de Computação Móvel, do curso de Mestrado em Computação Aplicada, da Universidade de Passo Fundo (RS), desafiou seus alunos a encontrarem algo relevante em alguma aplicação para smartphone. Uma nova tecnologia, linguagem, plataforma, design pattern ou, algo similar, que valesse a pena compartilhar com o restante da sala. Ao analisar o tráfego de logs gerados pelo aplicativo Facebook Lite, percebi que o mesmo utiliza um protocolo conhecido como MQTT (Message Queuing Telemetry Transport). Isso
me levou a um reforço de conceito que havia construído ao longo dos últimos meses. O MQTT é considerado um protocolo que segue o padrão publisher subscriber, que já é utilizado em um número considerável de aplicativo que o autor deste texto conhece. Sendo assim, tracei como objetivo criar um aplicativo de demonstração de um dos principais benefícios do Publisher Subscriber. No meu entendimento, esta característica que mais chama atenção é a independência dos atores, ou seja, do canal que recebe as publicações e repassa aos seus assinantes. Para atingir tal objetivo foi construído uma aplicação de jogo da velha entre uma aplicação Android e um Arduino Mega ADK (Accessory Development Kit). Ambas não são autônomas e necessitam de um controle manual. No Android é o próprio evento de toque na tela e, no Arduino, foi usado um Push Button e um Joystick.
Encontrando o protocolo Publisher Subscriber Devido a exigência do trabalho do mestrado, o primeiro passo que realizei foi plugar o smartphone na porta serial do notebook e, através da IDE (Integrated Development Environment) Android Studio, acompanhar os logs que a aplicação do Facebook Lite poderia lançar. Nas aplicações Android, é possível lançar um registro com a classe Log da própria biblioteca da plataforma. Usado principalmente durante o processo de desenvolvimento, para acompanhar certos processos e fluxos, além de testes incipientes, estas informações às vezes são mantidas mesmo depois que a aplicação entra em produção, ou seja, qualquer aplicação da Play Store pode notificar o Logcat (ferramenta da IDE para captura de Logs) do Android Studio. Durante o acompanhamento dos logs, recordei que já havia feito este exercício uma vez e, que uma busca por um protocolo muito específico, o MQTT, resultou em resultados interessantes. O objetivo pelo MQTT foi seu crescente uso na Internet das Coisas e a curiosidade referente a seu uso em smartphones. O logcat mostrou que o Facebook faz uso do MQTT em diversos momentos. Abaixo, segue um trecho muito curto que comprova isso:
2
04–11 17:13:46.914 1801–1892/? I/ActivityManager: Start proc 4366:com.facebook.katana/u0a29 for service com.facebook.katana/com.facebook.mqttlite.MqttService 04–11 17:13:48.446 4366–4366/? D/SplashScreenApplication: Special delaying init message { when=-1s444ms what=114 obj=CreateServiceData{token=android.os.BinderProxy@fd0a729 className=com.facebook.mqttlite.MqttService packageName=com.facebook.katana intent=null} target=android.app.ActivityThread$H } 04–11 17:14:27.552 1801–2495/? W/ActivityManager: Scheduling restart of crashed service com.facebook.katana/com.facebook.mqttlite.MqttService in 1000ms No primeiro momento foi a dúvida sobre o porque de um protocolo de Internet das Coisas estar presente no facebook, uma rede social entre pessoas. Ao pesquisar mais sobre o tema, percebi que diversas fontes apontavam o MQTT como um exemplo de Publisher-Subscriber. Inclusive no site oficial (mqtt.org) encontra-se esta descrição: “MQTT is a machine-to-machine (M2M)/"Internet of Things" connectivity protocol. It was designed as an extremely l ightweight publish/subscribe messaging transport. It is useful for connections with remote locations where a small code footprint is required and/or network bandwidth is at a premium. For example, it has been used in sensors communicating to a broker via satellite link, over occasional dial-up connections with healthcare providers, and in a range of home automation and small device scenarios. It is also ideal for mobile applications because of its small size, low power usage, minimised data packets, and efficient distribution of information to one or many receivers”.
O protocolo Publish/Subscribe já havia sido usado com significativos ganhos em algumas empresas que trabalhei. E me surpreendi com esta informação. Logo, atingi um ponto de colisão e tinha algo concreto para mostrar aos meus colegas.
3
O Protocolo Publish/Subscribe O padrão Publish/Subscribe define um ponto central, que pode ser chamado de Broker em alguns documentos, de canal em outros. Mas, o importante é que este elemento orquestra as mensagens oriundas de Publishers e entrega aos Subscribers interessados. A Figura 1 foi retirado de um documento da Microsoft sobre este padrão.
Figura 1: Padrão Publish/Subscribe segundo representação da Microsoft: https://msdn.microsoft.com/en-us/library/ff649664.aspx
O mesmo documento também trata da divisão das mensagens em tópicos. Veja a Figura 2. Neste caso, os assinantes definem de quais tópicos desejam receber mensagens. Um subscriber pode, inclusive, assinar somente um tópico, ou ainda, todos os tópicos disponíveis.
4
Figura 2: Divisão de tópicos no padrão Publish/Subscribe segundo representação da Microsoft: https://msdn.microsoft.com/en-us/library/ff649664.aspx
O ponto chave aqui é que o Publisher desconhece totalmente os Subscriber que irão receber suas mensagem. Ele apenas envia os dados para este elemento centralizador, o broker ou o canal, sendo que, este componente sabe para quais assinantes deve direcionar. O Subscriber, por sua vez, também não tem nenhum conhecimento de quem publicou a mensagem. Apenas sabe que a mesma lhe interessa.
Materiais Usados No desenvolvimento foi utilizado um Arduino Mega Seeduino ADK (Figura 3). Sobre esta placa microcontrolada, encontra-se um Groove Mega Shield (Figura 4). Como atuadores foram usados: Groove-LCD RGB Backlight (Figura 5), Groove Thumb Joystick (Figura 6) e Groove Button v1.1 (Figura 7). O display de LCD mostra um texto que define o status do jogo, sendo eles: ●
Jogo em andamento: “Peleando”.
●
Android ganhou: “Android vencedor”.
●
Arduino ganhou: “Arduino vencedor”.
5
Figura 3: Arduino Mega Seeduino ADK.
Figura 4: Groove Mega Shield.
6
Figura 5: Groove LCD RGB Backlight
Figura 6: Groove Thumb Joystick
Figura 7: Groove Button v1.1
Software Usados Além do arduino que funcionou como a computação física do projeto, fez-se necessário o uso de diversos componentes de software.
Aplicativo Mobile - Android Na aplicação mobile foi usado toda a pilha de software do Android, desde seu sistema operacional alvo como seu ambiente de desenvolvimento oficial (Android Studio). A aplicação foi direcionada do Android 4.1 e superiores. O que compreende mais de 90% de market share atualmente (Abril de 2018).
Aplicação no Microcontrolador A placa microcontrolada escolhida foi a Arduino. Por esta razão usamos seu ambiente de desenvolvimento, a Arduino IDE. Foi usado o protocolo Firmata, para fazer a interface das portas com um servidor rodando no notebook (poderia muito bem ter sido substituído por um mini-pc, como o Raspberry Pi).
7
Aplicação no Notebook Como mencionado, o uso do notebook deu-se apenas pela facilidade de demonstração em um ambiente heterogêneo e sujeito a falhas e interferências, como uma sala de aula em uma rede instável. Usamos o NodeJS e a biblioteca Johnny Five. Com isso, a comunicação entre o microcontrolador e o script executando no notebook se dá de forma simplificada. Por exemplo, não é necessário fazer uma rotina que pesquisa as portas seriais para encontrar o Arduino, muito menos trabalhar streaming de bytes pela mesma porta para tráfego de informações.
Biblioteca de Publish/Subscribe A primeira opção analisada foi a Event Bus. Esta biblioteca, desenvolvida pela GreenRobot é de grande valia, porém, seu suporte é limitado a plataforma Android. O site oficial pode ser encontrado nesta URL: h ttps://github.com/greenrobot/EventBus. E, caso o leitor tenha alguma dúvida se a mesma segue o Pub/Sub, veja a Figura 8 e a frase que a define. Ambas foram retirados do site oficial.
Figura 8: EventBus is a publish/subscribe event bus for Android and Java.
Também temos a Eclipse Paho. Apesar de bastante conceituada no mercado, a documentação da mesma pareceu inferior às demais. E seu suporte a diversas plataformas não é padronizado. 8
A terceira, última e a escolhida, foi a PubNub. Apesar de ser a única das opções enumeradas que não é open source e nem gratuita, tem pontos positivos que foram preponderantes para a decisão. ●
Apesar de ser paga, a licença gratuita permite um uso moderado e totalmente aceitável para provas de conceito;
●
Documentação boa com diversos exemplos no próprio site oficial https://www.pubnub.com/;
●
O principal ponto: possui SDK para mais de 70 plataformas. Como o objetivo principal era deixar muito claro a disparidade dos elementos Publisher e Subscriber e, consequentemente, o poder deste protocolo, a PubNub se sobressaiu.
A Solução Todo o código do projeto foi disponibilizado no Github, neste endereço: https://github.com/ricardoogliari/JogoDaVelhaIoT/tree/master/app/src/main/java/pubnub/ estudos/com/jogodavelhaiot. Por esta razão, somente os pontos que tem relação com o Pub/Sub serão comentados. Fique a vontade para visitar o repositório e reutilizar o código como bem entender.
Aplicação no Computador/Arduino Observação 1: Todo o código da solução arduino é encontrado aqui: https://github.com/ricardoogliari/JogoDaVelhaIoT/blob/master/app/src/main/java/pubnub/ estudos/com/jogodavelhaiot/CODIGO_NODEJS. O código que roda no Arduino é apenas uma interface para o protocolo Firmata. O NodeJS rodando no computador recebe e ou envia dados via porta serial. No início do código JavaScript temos a importação das bibliotecas e a definição do objeto PubNub. Neste momento passamos a Publish Key e a Subscribe Key. Ambas podem ser criadas com um novo projeto criado diretamente na página do PubNub. Veja a Listagem 1:
9
var five = require("johnny-five"); var board = new five.Board(); var PubNub = require('pubnub') pubnub = new PubNub({ publishKey : 'pub-c-0e59b032-e680-4ea2-a1a6-53b77fd88bec', subscribeKey : 'sub-c-51e68992-3ba4-11e8-8394-86efddfa61f5' }) Listagem 1: Criação do objeto PubNub
Na sequência encontra-se o código que escuta mudanças no atuador Joystick. Quando este evento ocorrer, um JSON object é passado para o m essage. Ainda, o nome do canal alvo também é definido, na propriedade channel. Estas duas definições são enviadas para o método publish d a instância de PubNub. Veja a Listagem 2. Um ponto interessante aqui, o PubNub trata os tópicos do PubSub como canais. var joystick = new five.Joystick(["A2", "A3"]); joystick.on("change", function() { pubnub.publish( { message: { type: "move", x : this.x, y : this.y }, channel: 'awesomeChannel' }, function (status, response) {}); }); Listagem 2: eventos do joystick e publicação no canal.
10
Na sequência encontra-se o código que intercepta o evento de click no Push Button. Veja a Listagem 3. Agora este código deve ser simples para o leitor. Atenção para o envio do type como p ress. Na listagem anterior a mesma propriedade era enviada como m ove. Isso será importante para o Subscriber (no caso a aplicação Android) saber qual ação deverá tomar no outro lado da solução. var button = new five.Button(4); button.on("press", function() { pubnub.publish( { message: { type: "press" }, channel: 'awesomeChannel' }, function (status, response) {}); }); Listagem 3: evento de click no Push Button e envio dos dados para o canal.
Na sequência, um ponto crucial no entendimento. Veja a Listagem 4 primeiramente. Neste momento definimos o Arduino como um subscriber, para os canais finishGame e resetGame. O que o leitor deve se importar e tomar nota aqui: um componente/elemento pode ser Publisher e Subscriber ao mesmo tempo. E isso estamos vendo aqui. Ele publicado os dados do Joystick e do Push Button mas, atua como Subscriber para receber as informações de reset e final do jogo. pubnub.addListener({ status: function(statusEvent) {}, message: function(message) { if (message.subscribedChannel == "finishGame"){ lcd.cursor(0, 0).bgColor("green").print(message.message); } else {
11
lcd.clear(); lcd.cursor(0, 0).bgColor("white").print("Peleando"); } }, presence: function(presenceEvent) {} }); pubnub.subscribe({ channels: ['finishGame', 'resetGame'] }); Listagem 4: assinatura dos canais finishGame e resetGame no arduino.
Aplicação no Android Observação: Todo o código da aplicação Android pode ser encontrado aqui: https://github.com/ricardoogliari/JogoDaVelhaIoT. Veja que na Listagem 5, também precisamos colocar as mesmas chaves de Publisher e Subscriber definidas no Arduino. Para isso utiliza-se uma instância de P NConfiguration. Logo na sequência é possível criar a instância de P ubNub. E , finalmente, podemos adicionar um l istener para os canais de sua escolha. Mova seu olho rapidamente para o final da listagem, verá que a instância de pubnub foi usada para chamar o método s ubscribe e, na sequência, para chamar o channels, a ssinando os canais passados por parâmetro neste último método. No listener que falamos a pouco é necessário sobrescrever alguns métodos. O mais importante deles é o message. Q uando este método for acionado significa que o canal assinado recebeu dados de Publishers, logo, desejamos ler e utilizar estas informações. Um teste lógico foi feito para saber se o publicador informou uma movimentação do joystick ou um push button click. PNConfiguration pnConfiguration = n ew P NConfiguration(); pnConfiguration.setSubscribeKey("sub-c-51e68992-3ba4-11e8your-key-here:)"); pnConfiguration.setPublishKey("pub-c-0e59b032-e680-4ea2your-key-here:)"); pubnub = n ew PubNub(pnConfiguration); pubnub.addListener(new S ubscribeCallback() {
12
@Override public void status(PubNub pubnub, PNStatus status) {}
@Override public void message(PubNub pubnub, PNMessageResult message) { String type = message.getMessage().getAsJsonObject().get("type").getAsString(); if ( type.equals("move")) { d ouble x = message.getMessage().getAsJsonObject().get("x").getAsDouble(); d ouble y = message.getMessage().getAsJsonObject().get("y").getAsDouble(); / /trata dados de posicionamento em resposta ao posicionamento do joystick }e lse { / /pinta a célula escolhida pelo Arduino com o Push Button } } @Override public void presence(PubNub pubnub, PNPresenceEventResult presence) { } }); pubnub.subscribe().channels(Arrays.asList(" awesomeChannel")).execute(); Listagem 5: assinatura de canal no Android e biblioteca do PubNub para esta plataforma.
Por fim, temos dois trechos de código na Listagem 6, mostrando como é a publicação de uma mensagem no lado do Android. Novamente, este elemento/componente também está sendo usado como Pub e Sub. public void c heckFinishGame(){ if ( c ells[0] [0] != 0 & & cells[0][0] == cells[0][1] && cells[0][1] == cells[0 ][2]){ //jogo da velha na primeira linha hoizontal pubnub.publish().channel("finishGame").message((cells[0 ][0] == 1 ? "Android" : "Arduino") + " vencedor").async(callback); } ... }
13
@OnClick(R.id.btnReset) public void r eset(){ ... pubnub.publish().channel("resetGame").message("reset").async(callback); } PNCallback callback = n ew PNCallback() { @Override public void onResponse(Object result, PNStatus status) {} }; Listagem 6: Android atuando como Publisher no protocolo.
Para publicar é tão simples como o restante da biblioteca. Na instância p ubnub u samos o método publish. N a sequência, escolhe-se o canal onde será publicada a mensagem. E por fim, o método a sync define a ação de forma assíncrona e, recebe por parâmetro justamente uma implementação da interface PNCallbak, mostrada logo abaixo.
Conclusão Esta pesquisa para o mestrado só me mostrou de forma ainda mais clara a importância do padrão Publisher Subscriber. Pensando na internet das coisas, o nível de heterogeneidade que os elementos da arquitetura terão, é enorme. Sendo assim, a característica de independência e acoplamento/coesão zero entre publicador e assinante, são cruciais. As bibliotecas/frameworks/plataformas que existem hoje para implementação do padrão tornam a vida do desenvolvedor muito fácil. Independente de ser Android, iOS ou qualquer outra plataforma mobile, teremos uma biblioteca. Até mesmo para sistema operacional de aparelhos televisores, ou ainda, para microcontroladores que podem estar no seu carro, relógio, ou marcapasso, também temos uma biblioteca. Agora, é ser criativo na junção dos elementos heterogêneos que você quer trabalhar e, com o uso do padrão Publisher Subscriber, programar publicadores e assinantes para fornecer soluções computacionais inovadoras!.
14