Veja neste artigo um passo a passo completo sobre como desenvolver aplicativos de controle remoto wi-fi para celulares em HTML5 e usá-los em aplicações IoT com dispositivos NodeMCU e compatíveis (ESP8266 / ESP32)
Introdução
Atualmente tornou-se prática comum usar o celular como controle remoto em aplicações IoT e, para isso, existem várias alternativas de desenvolvimento tais como:
O que vamos mostrar aqui é uma solução alternativa para desenvolvimento de aplicativos mobile nativos usando HTML5 e tecnologias conhecidas, tais como:
JQuery: Biblioteca Javascript que facilita a manipulação de elementos e eventos em páginas WEB.
Onsen UI: Framework de componentes CSS responsivos para desenvolvimento de aplicativos mobile com tecnologias tais como HTML5, CSS, Javascript.
PhoneGap: Framework para geração de aplicativos móveis híbridos a partir de aplicações web.
Aplicações móveis híbridas são aplicações que combinam componentes nativos e componentes web.
Do ponto de vista do usuário, uma aplicação híbrida é idêntica a uma aplicação nativa. No entanto, internamente, uma aplicação híbrida utiliza um componente web view que contém a maioria do conteúdo e lógica da aplicação.
O projeto
Para testar as ferramentas acima descritas, vamos desenvolver um pequeno projeto da seguinte forma:
- Uma placa NodeMCU ligada a três leds;
- Essa placa vai se conectar à rede wi-fi e rodar um servidor WEB que aguardará as requisições de um cliente;
- O cliente vai ser nosso app de controle remoto no celular que apresentará uma tela para controlar os três leds. O LED 1 e 2 poderão ser ligados e desligados através de um botão. Já, o LED 3, vamos controlar sua luminosidade através de um slider.
Obs: Para termos uma ideia melhor, veja abaixo imagens e vídeos de nosso projeto já funcionando:
Vídeo demonstrativo
Passo 1: O protótipo
Os seguintes componentes serão necessários para montagem do nosso experimento:
- Protoboard;
- Placa NodeMCU ou compatível (Wemos, MKR1000, ESP8266 Standalone);
- Três LEDs coloridos;
- Três resistores de 220 Ohms;
- Fios jumpers.
A montagem ficará da seguinte forma:
Passo 2: Sketch do NodeMCU
A função do nosso sketch será basicamente conectar-se à rede Wi-Fi e criar um web server que ficará aguardando e respondendo as requisições com os comandos de controle dos LEDs.
Vamos usar a própria IDE do Arduino para o desenvolvimento. Caso ainda não tenha feito, será necessário configurar o ambiente com o software das placas ESP8266. Para isso, siga os passos desse outro artigo: NodeMCU com a IDE do Arduino
Vejamos agora o código-fonte com os comentários:
/* NodeMCU Web server for wi-fi remote control 2019, José Augusto Cintra www.josecintra.com/blog */ #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WiFiMulti.h> #include <ESP8266mDNS.h> #include <ESP8266WebServer.h> ESP8266WiFiMulti wifiMulti; // For multiple wi-fi configuratiosn ESP8266WebServer server(80); // Create a webserver object that listens for HTTP request on port 80 // function prototypes for HTTP handlers void handleRoot(); void handleRequest(); void handleNotFound(); void setup(void){ delay(1000); pinMode(5, OUTPUT); //Led 1 pinMode(4, OUTPUT); //Led 2 digitalWrite(5, 0); digitalWrite(4, 0); analogWriteRange(100); //Led 3 (PWM) analogWrite(0, 0); Serial.begin(9600); // Start the Serial communication to send messages to the computer delay(10); Serial.println('\n'); wifiMulti.addAP("ssid1", "password1"); // add Wi-Fi networks you want to connect to wifiMulti.addAP("ssid2", "password2"); Serial.println("Connecting ..."); int i = 0; while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above delay(250); Serial.print('.'); } Serial.println('\n'); Serial.print("Connected to "); Serial.println(WiFi.SSID()); // Tell us what network we're connected to Serial.print("IP address:\t"); Serial.println(WiFi.localIP()); // Send the IP address of the ESP8266 to the computer if (MDNS.begin("esp8266")) { // Start the mDNS responder for esp8266.local Serial.println("mDNS responder started"); } else { Serial.println("Error setting up MDNS responder!"); } server.on("/", HTTP_GET, handleRoot); // Call the 'handleRoot' function when a client requests URI "/" server.on("/command", HTTP_POST, handleRequest); // Call the 'handRequest' function when a POST request is made to URI "/command" server.onNotFound(handleNotFound); // When a client requests an unknown URI server.begin(); // Actually start the server Serial.println("HTTP server started"); return; } void loop(void){ server.handleClient(); // Listen for HTTP requests from clients return; } void handleRoot() { // When URI / is requested, send a standard web page server.send(200, "text/html", "Wi-fi Remote Control Example"); return; } void handleNotFound(){ server.send(404, "text/plain", "404: Not found"); // Send HTTP status 404 (Not Found) when there's no handler for the URI in the request return; } void handleRequest() { // If a POST request is made to URI /command // Validate parameters if(!server.hasArg("pin") || !server.hasArg("value") || server.arg("pin") == NULL || server.arg("value") == NULL) { server.send(400, "text/plain", "400: Invalid Request"); // The request is invalid, so send HTTP status 400 return; } // Get the parameters: pin and value String temp = ""; temp = server.arg("pin"); int pin = temp.toInt(); temp = server.arg("value"); int value = temp.toInt(); Serial.println(pin); Serial.println(value); if (pin >= 0 && pin < 17 && value >= 0 && value <= 100) { if (pin == 0) { analogWrite(pin, value); } else { digitalWrite(pin, value); } } server.send(200, "text/html", "Wi-fi Remote Control Example"); return; }
Pontos de interesse:
- A lib WiFiMulti permite configurar a autenticação de várias redes wi-fi, facilitando a conexão. Substitua o ssid e password de acordo com a sua rede;
- A lib mDNS permite nomear um DNS para a rede local do ESP. Nesse caso, não estamos usando esse recurso, pois o Android não oferece suporte;
- O método handleClient inicia um loop que atua como um listener para as requisições web;
- Existem três funções que são responsáveis por tratar as requisições vindas do celular:
- A função handleNotFound é disparada quando a URI não foi encontrada;
- A função handleRoot é disparada quando recebe uma requisição GET padrão. No nosso caso, essas requisição é desprezada;
- A função handleRequest disparado pela condição server.on é responsável por tratar as requisições POST disparadas pelo controle remoto no celular. Nesse ponto iremos validar os parâmetros enviados pelo controle remoto e tomar a ação apropriada.
Passo 3: Aplicativo WEB
Para o desenvolvimento do aplicativo de controle remoto, teremos que fazer o download das bibliotecas JQuery e OnsenUI e descompactá-las nas pastas respectivas, conforme a estrutura descrita abaixo:
- app
config.xml ←Arquivo de configuração do Phonegap
- www
index.html ←Arquivo HTML de entrada
- assets
- img ←Aqui ficam os ícones do app
icon-128.png
icon-256.png - js
wifi_rc.js ←Arquivo JS com a lógica do app - lib
- jquery ←Descompacte o JQuery aqui
- onsenui ←Descompacte o OnsenUI aqui
- jquery ←Descompacte o JQuery aqui
- img ←Aqui ficam os ícones do app
- assets
- www
Neste momento vamos nos preocupar com os arquivos index.html e wifi_rc.js responsáveis pela apresentação e programação do nosso controle remoto, conforme abaixo.
<!-- Wi-fi Remote Control with JQuery and Onsen UI Demo by José Cintra www.josecintra.com/blog --> <!DOCTYPE html> <html lang="pt-br"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="Author" content="José Cintra" <link rel="stylesheet" href="assets/lib/OnsenUI/css/onsenui.min.css"> <link rel="stylesheet" href="assets/lib/OnsenUI/css/onsen-css-components.min.css"> </head> <body> <ons-page modifier="material"> <ons-toolbar modifier="material"> <div class="center"><strong>Wi-Fi Remote Control</strong></div> </ons-toolbar> <br/> <ons-card modifier="material"> <div class="content"> <ons-list modifier="material"> <ons-list-item modifier="material"> <div class="center" > <strong>LED 1 </strong> <label id="led1v">OFF</label> </div> <div class="right"> <ons-switch id="led1" class="sw" modifier="material"></ons-switch> </div> </ons-list-item > <ons-list-item modifier="material"> <div class="center" > <strong>LED 2 </strong> <label id="led2v">OFF</label> </div> <div class="right"> <ons-switch id="led2" class="sw" modifier="material"></ons-switch> </div> </ons-list-item> <ons-list-item modifier="material"> <div class="center"> <strong>LED 3 </strong> <label id="led3v">0</label>% </div> <div class="right"> <ons-range id="led3" class="rg" modifier="material" style="width: 100%;" value="0" max = "100" ></ons-range> </div> </ons-list-item> </ons-list> </div> </ons-card> </ons-page> <!-- Javascript --> <script src="assets/lib/OnsenUI/js/onsenui.min.js"></script> <script src="assets/lib/jquery/jquery-3.3.1.min.js"></script> <script src="assets/js/wifi_rc.js"></script> </body> </html>
/* Wi-fi Remote Control with JQuery and Onsen UI Demo by José Cintra www.josecintra.com/blog */ $(function () { // Server address and pin numbers of the board (ESP8266/32 and compatibles) let addr = "http://192.168.0.33/command"; let pins = new Map([ [ '#led1', '05' ], [ '#led2', '04' ], [ '#led3', '00' ], ]); // Click Event on switch Class $('.sw').on('click', function (e) { let onoff = ['OFF','ON']; let id = "#" + $(this).attr("id"); // Get the id of the control let pin = pins.get(id); // Pin number let value = String(+$(id).prop('checked')); // On or Off $(id + 'v').html(onoff[value]); sendAjax(addr, pin, value); }); // Input event on range class $('.rg').on('input', function (e) { let id = "#" + $(this).attr("id"); // Get the id of the control let value = String($(id).val()); // Input range $(id + 'v').html(value); // Notification }); $('.rg').on('change', function (e) { let id = "#" + $(this).attr("id"); // Get the id of the control let pin = pins.get(id); // Pin number let value = String($(id).val()); // Input range sendAjax(addr, pin, value); }); }); function sendAjax(addr, p, v) { $.ajax({ method: "POST", url: addr, data: {pin: p, value: v} }); }
Pontos de interesse:
- No arquivo index.html fica toda a parte de apresentação do aplicativo com os elementos CSS disponibilizados pelo framework OnsenUI.
- Os LEDs 1 e 2 serão controlados por um botão tipo switch e o LED 3 por um controle range. É importante observar os atributos id e class que vão ser usados no script JS.
- O código Javascript do arquivo wifi_rc.js adota o padrão ES6.
- No arquivo wifi_rc.js destaca-se o evento function() que ocorre uma única vez após a carga da página. É ali que programamos as ações que respondem aos eventos dos controles.
- Para representar os números dos pinos no NodeMCU usamos uma estrutura MAP. Essas informações serão passadas, juntamente com os valores dos controles, para o método sendAjax e enviadas ao web server da placa.
Passo 4: Aplicativo Mobile
Finalmente, nesse ponto vamos gerar nossa aplicação mobile para ser instalada no celular. Para que o nosso aplicativo HTML5 possa ser instalado como um app nativo, será necessário usar as ferramentas de compilação do Phonegap.
A maneira mais simples de fazer isso é usar os serviços de compilação em nuvem do Phonegap Build.
Os passos são os seguintes:
- Criar uma conta no serviço Phonegap Build, escolhendo um plano pago ou gratuito;
- Criar os ícones do aplicativo que serão exibidos no celular
- Criar um arquivo config.xml com as configurações necessárias;
- Compactar todos os arquivos e enviar para compilação;
- Solicitar a compilação do aplicativo;
- Escolher a plataforma desejada (Android, iPhone ou Microsoft) e baixar o app compilado para essa plataforma.
Obs: Os arquivos dos ícones devem ser no formato png, nos tamanhos 128×128 e 256×256.
Segue abaixo um exemplo de arquivo config:
<?xml version="1.0" encoding="UTF-8" ?> <widget id="com.josecintra.wifi_rc" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0"> <name>Wi-fi Remote Control</name> <description>Example of building a wi-fi remote control with HTML5/JQuery/Onsen UI and Phonegap. It will be used to control IoT devices, such as NodeMCU and compatibles</description> <author href="https://www.josecintra.com/blog" email="josecintra@josecintra.com">Jose Cintra</author> <icon src="www/assets/img/icon-256.png" width="256" height="256" density="xxxhdpi" /> <icon src="www/assets/img/icon-128.png" width="128" height="128" density="xhdpi" /> <preference name="android-targetSdkVersion" value="26" /> <preference name="orientation" value="portrait" /> <preference name="fullscreen" value="true" /> <preference name="DisallowOverscroll" value="true" /> <config-file parent="UIStatusBarHidden" platform="ios" target="*-Info.plist"><true/></config-file> <config-file parent="UIViewControllerBasedStatusBarAppearance" platform="ios" target="*-Info.plist"><false/></config-file> <preference name="deployment-target" value="10.0" /> <preference name="android-minSdkVersion" value="21" /> <access origin="*" /> <plugin name="cordova-custom-config" /> <plugin name="cordova-plugin-file" /> <plugin name="cordova-plugin-media" /> <plugin name="cordova-plugin-statusbar" /> <plugin name="cordova-plugin-whitelist" /> <engine name="ios" /> <engine name="android" /> </widget>
Pontos de interesse
O arquivo config.xml contém todas as informações necessária para a geração do app. Entre elas, destacamos:
- name: Nome do app
- description: Descrição do app
- author: Informações sobre o autor do app
- icon: Nome dos ícones que irão identificar o app no celular
- orientation: O app pode ser exibido no modo portrait, landscape. Caso não seja informado. O app irá se adaptar à inclinação do celular.
- access origin: Define quais urls a aplicação pode acessar
Além dessas, existem dezenas de outras configurações. Um ponto importante é a escolha dos plugins que permitem adicionar funcionalidades adicionais ao aplicativo como o acesso à câmera, gps, e outros recursos nativos do celular. Para mais detalhes sobre o processo de compilação, consulte esse link.
Passo 5: Instalação do App
No passo anterior, geramos um app que pode ser instalado no celular ou disponibilizado para download nas app stores. No nosso caso, geramos um app Android com a extensão apk.
Para testar esse aplicativo no celular sem passar pela app store, precisamos configurar o Android para permitir a instalação de apps de “Fontes desconhecidas”. Normalmente essa opção está na seção de segurança.
Depois disso, é só copiar o app para o celular. Isso pode ser feito de várias maneiras como, por exemplo, vias USB, Kies, Wi-Fi ou através de um link na Internet. O próprio Android cuidará da instalação.
E agora?
Apresentamos aqui um exemplo didático simples de um controle remoto wi-fi para dispositivos IoT. Esse exemplo pode ser aprimorado de diversas formas:
- Melhorar o tratamento de erros nas requisições ajax;
- Adotar medidas de segurança na transmissão wi-fi;
- Disponibilizar opções de armazenamento e gerenciamento das conexões wi-fi;
- Aprimorar a interface do controle remoto;
- Colocar o app para ser distribuído nas apps stores;
- Consultar outras referências úteis na Internet:
Últimas Palavras
Obrigado por visitar meu blog. Os arquivos desse tutorial estão todos disponíveis também no GitHub. Ah! Não esqueça de configurar o ssid e password do seu wi-fi no sketch do NodeMCU…