0% acharam este documento útil (0 voto)
741 visualizações335 páginas

IoT Com MicroPython e NodeMCU - Claudio Luis Vieira Oliveira, H

O documento aborda a utilização de IoT com MicroPython e NodeMCU, apresentando conceitos, ferramentas e projetos práticos. Ele detalha a programação em MicroPython, a configuração de hardware como NodeMCU ESP8266-12 e ESP32, e a interação com serviços de nuvem. O conteúdo é voltado para iniciantes e profissionais, visando facilitar a criação de soluções inovadoras em automação e conectividade.
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
741 visualizações335 páginas

IoT Com MicroPython e NodeMCU - Claudio Luis Vieira Oliveira, H

O documento aborda a utilização de IoT com MicroPython e NodeMCU, apresentando conceitos, ferramentas e projetos práticos. Ele detalha a programação em MicroPython, a configuração de hardware como NodeMCU ESP8266-12 e ESP32, e a interação com serviços de nuvem. O conteúdo é voltado para iniciantes e profissionais, visando facilitar a criação de soluções inovadoras em automação e conectividade.
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
Você está na página 1/ 335

IoT com

MicroPython
e NodeMCU

Cláudio Luís Vieira Oliveira


Humberto A. Piovesana Zanetti

Novatec
Copyright © 2022 da Novatec Editora Ltda.
Todos os direitos reservados e protegidos pela Lei 9.610 de 19/02/1998. É proibida a
reprodução desta obra, mesmo parcial, por qualquer processo, sem prévia autorização,
por escrito, do autor e da Editora.
Editor: Rubens Prates GRA20220125
Revisão gramatical: Tássia Carvalho
Capa: Wellinton Lenzi
Ilustração de capa: freepik.com
ISBN do impresso: 978-65-86057-86-7
ISBN do ebook: 978-65-86057-87-4
Histórico de impressões:
Fevereiro/2022 Primeira edição
Novatec Editora Ltda.
Rua Luís Antônio dos Santos 110
02460-000 – São Paulo, SP – Brasil
Tel.: +55 11 2959-6529
Email: [email protected]
Site: https://novatec.com.br
Twitter: twitter.com/novateceditora
Facebook: facebook.com/novatec
LinkedIn: linkedin.com/in/novatec
GRA20220125
À minha esposa Claudia, por tantos e tantos anos
de companheirismo, comunhão e amor.
À minha filha Franciele, com muito amor.
Aos meus pais Maria Creyde e Manoel,
pela dedicação e pelo amor à família.
Ao grande amigo Humberto,
pelos inúmeros projetos compartilhados.
– Cláudio Vieira Oliveira
À minha esposa Flavia, por seu incentivo e dedicação.
Aos meus pais Alberto e Célia, e meus irmãos Luis Gustavo e Pedro,
por sempre acreditarem em mim.
Ao meu grande amigo Cláudio, pela parceria nos projetos nesses anos.
E à minha princesa Betina, por tornar meus dias cada vez mais felizes.
– Humberto Zanetti
Arquivos para download
Imagens coloridas e códigos-fontes podem ser baixados em
https://novatec.com.br/livros/iot-micropython-nodemcu/.
Sumário

Sobre os autores
Apresentação
capítulo 1 NodeMCU e MicroPython
NodeMCU ESP8266-12 e ESP32
MicroPython
Programas utilizados
Atualização do firmware
Material necessário

capítulo 2 Introdução ao Python


Variáveis e operadores
Seleção e repetição
Listas
Funções
capítulo 3 Portas de entrada e saída
Saída digital
Tratamento de exceções
Simulação de um semáforo
Entrada digital
Modulação por largura de pulso
LED RGB
Conversor analógico digital
Medidor de intensidade luminosa
Medidor de temperatura com termístor

capítulo 4 Orientação a objetos


Classes, objetos, atributos e métodos
Classe LED
Abstração da chave táctil
Uma classe para o LED RGB
Herança
Display de LEDs com 7 segmentos
capítulo 5 Comunicação em rede
Wi-Fi integrado
Soquetes
Controle de dispositivos pela internet
Recepção de dados da internet
Envio de dados para uma página web
Serviços de rede

capítulo 6 Displays
Display de cristal líquido (LCD) I2C
Termômetro digital – versão 1
Display de LEDs de 7 segmentos e 4 dígitos
Relógio digital
Relógio e termômetro digital
Display OLED
Exibição de imagens no display OLED
Termômetro digital – versão 2

capítulo 7 Redes de sensores


Inter-Integrated Circuit (I²C)
1-Wire
MQTT (Message Queue Telemetry Transport)

capítulo 8 Node-RED
Olá Node-RED
JavaScript
Requisições HTTP
Interação com broker MQTT
Dashboard
Sistema de monitoramento
Armazenamento de dados no MongoDB
Comunicação entre serviços

capítulo 9 IBM Watson IoT Platform


Medidor de temperatura e umidade
Configuração do dispositivo e dos serviços
Armazenamento no IBM Cloudant
Front-end da aplicação
Comandos
Interação pela internet
capítulo 10 ThingSpeak
Medidor de temperatura e umidade
Canais
TalkBack App
capítulo 11 IFTTT
Inserção de dados em uma planilha
Envio de notificações por e-mail

capítulo 12 Interrupções, temporizadores e threads


Sensor de presença
Matriz de LEDs
Web-Clock
Deep sleep
Sobre os autores

Cláudio Luís Vieira Oliveira


Mestre em Sistemas de Computação pela Pontifícia Universidade Católica
de Campinas e bacharel em Análise de Sistemas pela Universidade
Metodista de Piracicaba. Ampla experiência na área de Ciência da
Computação. Coordenador de Curso e Professor da Faculdade de
Tecnologia (FATEC) de Jundiaí, atua também como Professor nas
Faculdades de Tecnologia (FATEC) de Bragança Paulista e Campinas.

Humberto A. Piovesana Zanetti


Doutorando em Tecnologia pela Faculdade de Tecnologia da Universidade
Estadual de Campinas (FT – UNICAMP) e Mestre em Ciência da
Computação pela Faculdade de Centro Universitário Campo Limpo
Paulista (UNIFACCAMP). Atua há 15 anos nos ensinos técnico e superior.
Atualmente é professor na Escola Técnica Rosa Perrone Scavone (Itatiba,
SP) e na Faculdade de Tecnologia de Jundiaí (FATEC).
Apresentação

A IoT (Internet of Things – Internet das Coisas) faz parte de uma


revolução tecnológica, em que dispositivos de custo muito baixo podem
se conectar à Internet e interagir com sistemas, serviços e outros
dispositivos. Dessa forma, a automação, que por muitos anos esteve
restrita a ambientes industriais, passou a fazer parte do cotidiano de
muitas pessoas, seja em suas casas, veículos e até mesmo em dispositivos
de uso pessoal. Hoje podemos ter em nossas residências dispositivos de
segurança, monitoramento e controle à distância de equipamentos.
Microcontroladores, serviços em nuvem, interconectividade entre sistemas
e diversos tipos de equipamentos definem um cenário em que temos um
mundo totalmente conectado. Inúmeras possibilidades de projetos
surgem a cada dia, acessíveis e fáceis de construir – o limite é a
imaginação.
Nesse contexto, diversos modelos de dispositivos microcontrolados
passam a contar com conexão às redes de computadores, sem a
necessidade de módulos adicionais. Nesta obra, abordaremos alguns
desses dispositivos, denominados NodeMCU, que são fundamentados
sobre a família de baixo custo de microcontroladores da Espressif
Systems.
A facilidade de uso desses dispositivos se torna latente com a adoção da
linguagem de programação Python, agora portada para o ambiente dos
dispositivos microcontrolados e denominada MicroPython. Uma
poderosa linguagem de programação de fácil aprendizado e que possui
uma comunidade atuante de desenvolvedores que disponibilizam
inúmeras bibliotecas, deixando a tarefa de programação cada vez mais
simples e produtiva.
Além disso, os projetos propostos neste livro irão interagir com serviços e
plataformas de IoT muito populares e empregados mundialmente, como
Watson IoT da IBM, ThingSpeak e IFTT.
Desejamos uma leitura motivadora e produtiva e que o auxilie no
desenvolvimento de projetos inovadores!
capítulo 1

NodeMCU e MicroPython

O NodeMCU (Node MicroController Unit) consiste em uma plataforma,


de hardware e software abertos (open source), focada em aplicações de
Sistemas Embarcados e IoT. Utiliza como base microcontroladores de
baixo custo e baixo consumo de energia produzidos pela empresa chinesa
Espressif Systems. Essa plataforma contém elementos essenciais de um
computador, como CPU, interface de rede (WiFi), memória RAM e, em
alguns modelos, até mesmo um sistema operacional.
Existem diversos modelos de NodeMCU, sendo que os mais populares
utilizam os módulos ESP8266-12 ou ESP32. A seguir apresentamos
brevemente cada um deles, sendo que ambos serão abordados no decorrer
desta obra.

NodeMCU ESP8266-12 e ESP32


O NodeMCU (Figura 1.1), que adota o módulo ESP8266-12, apresenta um
microcontrolador Tensilica L106 de 32 bits, memória flash de 4 MB,
memória RAM de 160 kB, Wireless padrão 802.11 b/g/n e 13 portas GPIO
(General Purpose Input/Output) mais 1 analógica. Além disso, a GPIO
implementa funcionalidades para PWM (Pulse Width Modulation), I2C
(Inter-Integrated Circuit) e SPI (Serial Peripheral Interface).
Quando o NodeMCU (Figura 1.2) é implementado com o módulo ESP32,
possui um microcontrolador Xtensa LX6 Dual-Core de 32 bits LX6,
memória flash de 4 MB, memória RAM de 512 KB, Wireless padrão
802.11 b/g/n e Bluetooth BLE 4.2. Apresenta 25 portas GPIO disponíveis
para uso, sendo que 15 portas podem ser configuradas como entradas
analógicas se a comunicação sem fio estiver desligada, ou 6 portas, caso a
comunicação sem fio estiver ligada. A GPIO implementa funcionalidades
para PWM, I2C e SPI.

Figura 1.1: NodeMCU com módulo ESP8266-12.

Figura 1.2: NodeMCU com módulo ESP32.


O NodeMCU pode ser programado em diversas linguagens de
programação. Neste livro vamos focar no desenvolvimento de soluções
escritas na linguagem de programação MicroPython.

MicroPython
O MicroPython é uma portabilidade, otimizada para microcontroladores,
da linguagem de programação Python 3, que é amplamente utilizada no
desenvolvimento dos mais diversos tipos de aplicação. A linguagem de
programação Python é bastante poderosa, e seu principal atrativo é
possuir uma estrutura sintática bastante simples. Além disso, possui uma
infinidade de módulos desenvolvidos, uma comunidade muito atuante,
farta documentação e suporte a orientação a objetos. A implementação do
MicroPython utiliza-se das principais funcionalidades da linguagem
Python convencional, sendo uma ótima opção tanto para o iniciante
quanto para projetos profissionais.
O IDE (ambiente integrado de desenvolvimento) que será abordado nesta
obra é o Thonny (Figura 1.3), que está disponível gratuitamente em
https://thonny.org/. É uma ferramenta bastante completa e fácil de
utilizar, possibilitando uma ótima produtividade no desenvolvimento das
soluções. Porém, caso o leitor tenha familiaridade com outros ambientes
de desenvolvimento para o MicroPython, estes podem ser utilizados. No
livro, os códigos em MicroPython a serem executados no
microcontrolador estão indicados pelo símbolo z.
Figura 1.3: Janela principal do Thonny.

Programas utilizados
Além do ambiente de desenvolvimento Thonny, também devemos instalar
o Python, que está disponível gratuitamente em https://www.python.org/.
Também será necessária a instalação da ferramenta esptool, que consiste
em um conjunto de ferramentas que possibilitam a comunicação com o
bootloader dos módulos ESP8266 e ESP32 da Espressif Systems. O esptool
é fundamental para que seja possível instalar ou atualizar o firmware do
NodeMCU e está disponível gratuitamente em
https://github.com/espressif/esptool. Porém, a forma mais fácil de realizar
a instalação é usar o utilitário PIP do Python, que pode ser executado
pelo prompt de comandos do sistema operacional do seu computador,
conforme podemos notar a seguir.
 pip install esptool
Entre muitas funcionalidades, podemos utilizar o esptool no terminal
para obter informações do módulo ESP presente na NodeMCU utilizando
o parâmetro flash_id da maneira indicada a seguir.
 esptool.py flash_id
O comando deverá fornecer um resultado similar ao mostrado pela
Figura 1.4, em que podemos identificar o tipo do chip e o tamanho da
memória flash, entre outras informações.
Figura 1.4: Informações do módulo ESP.
Outro utilitário que será utilizado em alguns dos projetos desenvolvidos
neste livro é o Ampy, que possibilita manipular o sistema de arquivos do
NodeMCU e sua instalação também pode ser realizada utilizando o
utilitário PIP, conforme mostrado a seguir.
 pip install adafruit-ampy

Atualização do firmware
Após a instalação do Python, Thonny e esptool, o primeiro passo para
utilizarmos o MicroPython no NodeMCU é realizar a instalação do
firmware; para isso, acesse https://micropython.org, entre na opção DOWNLOAD
e baixe o arquivo adequado para a sua placa NodeMCU.
Realize a conexão do seu NodeMCU a uma das portas USB do
computador. Execute o programa Thonny.
No Thonny, entre na opção Executar e escolha Select Interpreter. Na janela que
será aberta (Figura 1.5), clique na aba Interpretador e selecione MicroPython (ESP32)
ou MicroPython (ESP8266), conforme o modelo de NodeMCU que você irá usar.
Figura 1.5: Seleção do interpretador.
Em seguida, o quadro Details (Figura 1.6) será mostrado na mesma janela, a
porta será detectada automaticamente, mas é importante que o driver
apropriado à sua NodeMCU já tenha sido instalado. Clique no botão Install
or update firmware.
Na nova janela que foi apresentada (Figura 1.7), selecione a porta e o
arquivo que contém o firmware que foi baixado do site do MicroPython.
Por fim, clique no botão Install e aguarde o término do processo de
instalação ou atualização. É importante salientar que o Thonny utilizará o
esptool para realizar a instalação, dessa forma, é fundamental que a
ferramenta tenha sido previamente instalada.
Figura 1.6: Detalhes da conexão.

Figura 1.7: Instalação do firmware.


Uma mensagem similar à apresentada na Figura 1.8 será mostrada quando
o processo estiver concluído.
Figura 1.8: Término da instalação do firmware.
Clique no botão Stop para verificar se o dispositivo está executando o
MicroPython. Então, será mostrada no shell do Thonny a versão que foi
instalada e o prompt interativo. Digite no shell o comando print('Olá') e
pressione a tecla Enter, conforme podemos notar na Figura 1.9.

Figura 1.9: Shell do MicroPython.

Material necessário
A seguir, apresentamos a relação do material que será empregado nos projetos contidos
nesta obra.

Material Quantidade

1 NodeMCU (ESP8266-12 ou ESP32)

1 Display LCD 1602 I2C


1 Módulo TM1637

1 Display OLED I2C ou SPI

1 Módulo BMP180

1 Módulo BH1750

2 Sensores DS18B20

2 LEDs vermelhos de 5mm


1 LED amarelo de 5mm
1 LED verde de 5mm

1 LED RGB (Cátodo ou Ânodo comum)

4 Resistores de 220 Ohms (ou 330 Ohms)


3 Resistores de 10k Ohms
3 Resistores de 4,7k Ohms

2 Chave táctil
1 Potenciômetro 10k Ohms

1 Sensor DHT11

1 Termístor NTC de 10k Ohms

1 LDR

1 Display de LEDs com 7 Segmentos (Cátodo ou Ânodo comuns)

1 Módulo Relê de 5 Volts

Sensor de Presença Infravermelho (PIR)

1 Módulo Matriz de LEDs de 8x8 com 4 dígitos

1 Placa para prototipagem (Protoboard)


25 Cabos para conexão
capítulo 2

Introdução ao Python

Como já mencionamos, a linguagem de programação Python é bastante


poderosa e apresenta uma estrutura sintática bastante simples. Consiste
em uma linguagem interpretada; sendo assim, pode ser utilizada de duas
maneiras. A primeira é diretamente do console (shell), sendo possível
enviar os comandos da linguagem de modo interativo, sem
necessariamente ter de desenvolver um programa. A segunda maneira
consiste em escrever o programa completo e submetê-lo ao interpretador.
 Os exemplos deste capítulo podem ser executados usando a versão padrão do
Python disponível no Thonny. Após iniciar o programa, entre na opção Executar do
menu e escolha o item Select Interpreter. Na janela que será aberta, clique na aba
Interpretador e escolha a opção The same interpreter which runs Thonny (default). Dessa
maneira, o NodeMCU não precisará ficar conectado ao computador, pois os
programas serão interpretados diretamente pelo computador.
Agora vamos ilustrar a primeira maneira de uso da linguagem Python,
realizando o envio de comandos diretamente ao console (shell), conforme
mostrado na Figura 2.1.
Da mesma forma, é possível enviar diretamente expressões aritméticas
para o console. Por exemplo, digite no shell (45 * 3) + 5. Após pressionar
a tecla Enter, o resultado será exibido, conforme ilustra a Figura 2.2.
O console é bastante útil quando precisamos verificar o funcionamento
de uma instrução ou mesmo para avaliar rapidamente o resultado de uma
expressão (ou equação). Por outro lado, não é prático para escrever um
programa que, em uma visão bastante simplista, pode ser entendido
como uma sequência de instruções que devem ser executadas.
No próximo exemplo será criado um programa bastante simples.
 ola.py
nome = input('Qual é o seu nome? ')
print ('Olá', nome)

Figura 2.1: Modo interativo.


Figura 2.2: Modo interativo.
Basicamente, o programa solicitará ao usuário a digitação do seu nome e,
em seguida, irá exibir o nome que foi digitado. O programa será
executado quando o botão Executar for pressionado ou quando a tecla de
atalho F5 for pressionada, conforme mostra a Figura 2.3.
Observe no programa que a entrada dos dados pode ser realizada usando
a instrução input. Essa instrução sempre irá obter uma cadeia de
caracteres (string) digitada pelo usuário. A exibição dos dados no console
é realizada pela instrução print, já usada anteriormente, sendo que os
diversos valores a serem exibidos deverão estar separados por vírgula.

Figura 2.3: Primeiro programa.


A instrução input sempre irá obter uma string digitada pelo usuário.
Sendo assim, quando necessário, devemos utilizar as funções int ou float
para realizar a conversão para o tipo de dados desejado.
No código-fonte a seguir temos um exemplo da entrada de dados para
obtermos o nome e o ano de nascimento de uma pessoa. Observe que,
após a digitação, o ano de nascimento é convertido pela função int.
 idade.py
import time

nome = input("Digite o seu nome: ")


anoNasc = int(input("Digite o ano de nascimento: "))
anoAtual = int(time.strftime("%Y"))
idade = anoAtual - anoNasc
print (nome, "a sua idade é", idade, "anos")
Note que a exibição dos dados no console é realizada pela instrução
print, já usada anteriormente, sendo que os diversos valores a serem
exibidos deverão estar separados por vírgula. Para obter automaticamente
o ano a partir do relógio do computador, o módulo time deverá ser
importado. Em seguida, a função strftime será utilizada para obtermos
uma string contendo o ano (%Y), a qual será convertida para inteiro e
armazenada na variável anoAtual.

Variáveis e operadores
Em Python, uma variável, atributo ou até mesmo o valor de retorno de
um método não precisa ser previamente declarado. Conforme o valor
atribuído, a variável assume o tipo de dado necessário para armazenar
devidamente o conteúdo. Dessa forma, para armazenar um determinado
valor inteiro em uma variável, devemos simplesmente escrever:
 x = 5
A linguagem Python também permite múltiplas atribuições, por exemplo:
 x, y = 5, 10
Nesse caso, a variável x receberá o valor 5 enquanto y receberá o valor 10.
Quando desejamos atribuir um mesmo valor para diversas variáveis,
podemos especificar:
 x = y = 5
Ou seja, nessa situação ambas as variáveis, isto é, x e y, receberão o valor 5.
Na Tabela 2.1, temos os principais operadores de atribuição, aritméticos,
relacionais e lógicos adotados em Python.
Tabela 2.1: Principais operadores da linguagem Python
Operador Símbolo Operador Símbolo
= ==
Atribuição Igual a
+ !=
Adição Diferente de
- >
Subtração Maior
* >=
Multiplicação Maior ou igual
/ <
Divisão Menor
% <=
Resto Menor ou igual
** and
Exponenciação E (And)
++ or
Incremento Ou (Or)
-- not
Decremento Não (Not)

Dessa maneira, para elevar o valor dois ao cubo (23) e armazenar o


resultado na variável res, teríamos o comando mostrado a seguir.
 res = 2 ** 3
Observe o uso do operador = para a atribuição e do operador ** para
realizar a exponenciação.

Seleção e repetição
As estruturas de controle que permitem determinar a execução ou não de
determinado bloco de código também são responsáveis pela possibilidade
de repetição de um bloco de código.
A estrutura if else é utilizada para realizar a execução condicional de um
determinado bloco de código. No próximo exemplo, essa estrutura será
utilizada para determinar se um número é positivo. Observe que a
instrução else é opcional e, para este caso, não foi utilizada.
 positivo.py
numero = int(input("Digite um número: "))
if numero > 0:
print ("O número é positivo.")
No próximo programa, a partir do exemplo do cálculo de idade
desenvolvido anteriormente, vamos acrescentar uma estrutura de seleção
para determinar se a pessoa é maior ou menor de idade.
 maioridade.py
import time

nome = input("Digite o seu nome: ")


anoNasc = int(input("Digite o ano de nascimento: "))
anoAtual = int(time.strftime("%Y"))
idade = anoAtual - anoNasc
maioridade = ""
if idade < 18:
maioridade = "menor"
else:
maioridade = "maior"
print (nome, "a sua idade é", idade, "anos e você é", maioridade, "de
idade")
Também é possível verificar várias condições utilizando a instrução elif,
que pode ser intercalada dentro de um bloco if else. Para ilustrar esse
conceito, imagine uma situação hipotética em que você precisa escrever
uma aplicação que escreva o valor por extenso dos números inteiros entre
1 e 5.
 extenso.py
num = int(input("Digite um número entre 1 e 5: "))
if num == 1:
print ("Um")
elif num == 2:
print ("Dois")
elif num == 3:
print ("Três")
elif num == 4:
print ("Quatro")
elif num == 5:
print ("Cinco")
else:
print ("Não sei")
Observe que, nesse caso, adotando-se como referência um valor 2,
digitado pelo usuário e atribuído a variável num, a primeira verificação
(num == 1) será falsa, provocando a execução da cláusula elif seguinte, que
irá verificar se num == 2. Após essas verificações o resultado da avaliação
da expressão será verdadeiro e o comando print "Dois" será executado.
A estrutura while possibilita realizar a repetição de um bloco de
comandos até que a expressão lógica fornecida como condição seja
avaliada como falsa. Nesse momento, o while é encerrado e a execução do
programa prossegue na primeira linha de código que possua a mesma
identação que comando while.
Com o intuito de ilustrar o uso da estrutura while, vamos elaborar um
programa que permite a exibição dos números pares entre 2 e 10:
 pares-1.py
num = 2
while num <= 10:
print (num)
num = num + 2
Observe que o bloco de comandos irá se repetir enquanto a variável num
for menor ou igual a 10. A variável num será incrementada até atingir o
valor 12. Nesse momento, a condição torna-se falsa e a repetição será
encerrada.
Outra estrutura de repetição disponível na linguagem de programação
Python é o for. Nesse caso, quando utilizado em conjunto com a função
range, permite especificar uma sequência de valores. Dessa forma, o
programa anterior que usou o comando while poderia ser escrito da
seguinte maneira:
 pares-2.py
for num in range(2, 12, 2):
print(num)
Observe que na função range o primeiro parâmetro representa o início, em
seguida o valor final e o último parâmetro representa o passo. Na função
range, podemos omitir o segundo e o terceiro parâmetros; nesse caso, a
sequência começa em zero e o passo é um. Assim sendo, no programa a
seguir teríamos a exibição dos números de zero até quatro.
 sequencia.py
for num in range(5):
print(num)

Listas
As listas podem ser entendidas como conjuntos de itens. No trecho de
código-fonte a seguir, podemos notar que o simples uso de colchetes
permite especificar uma lista vazia.
 numeros = []
No exemplo a seguir, notamos que é possível criar uma lista contendo um
conjunto de valores predefinidos.
 numeros = [12, 18, 33, 2, 88]
Nesse caso, estamos declarando uma lista contendo cinco números
inteiros. Em uma lista, o primeiro elemento é referenciado pelo índice 0
(zero). Dessa forma, para acessar um elemento dentro de uma lista
devemos referenciar entre colchetes o índice da posição desejada,
conforme mostra o seguinte trecho de programa.
 numeros = [12, 18, 33, 2, 88]
print(numeros[2])
Será exibido o elemento que se encontra no índice 2 da lista numeros que,
nesse exemplo, seria o valor 33.
Aplicando o conceito de lista, vamos a seguir criar um programa que, a
partir de cinco números reais digitados pelo usuário, deve calcular e exibir
o valor da média.
 media.py
numeros = []
soma = 0.0
for i in range(5):
numeros.append(float(input("Número? ")))
soma = soma + numeros[i]
i = i + 1
media = soma / len(numeros)
print ("A media é %3.1f" % media)
Nesse exemplo, é importante salientar que podemos acrescentar
elementos à lista com o método append. Dessa forma, criamos uma lista
vazia e vamos inserindo os elementos durante a execução do programa.
Note também que a função len pode ser usada determinar o tamanho da
lista.

Funções
Na medida em que os programas vão se tornando mais complexos, torna-
se necessário estruturar o código em partes menores com funcionalidades
específicas. Além da organização, as funções também apresentam a
vantagem de permitir a reutilização de parte do programa, evitando assim
que um mesmo trecho do código tenha de ser escrito várias vezes.
Como exemplo, vamos considerar uma aplicação que implemente uma
calculadora básica, em que o usuário irá digitar dois números e escolher
qual das quatro operações aritméticas básicas será realizada. Em seguida,
o programa irá calcular e exibir o resultado com base na operação que foi
escolhida. Vamos resolver esse problema aplicando o conceito de funções.
Inicialmente vamos desenvolver apenas a função que fará a adição.
No trecho de programa a seguir, observe que criamos uma função que
recebe dois números como parâmetros, realiza o cálculo e retorna o valor
da soma.
 def somar (valor1, valor2):
return (valor1 + valor2)
A seguir vamos desenvolver o conteúdo da rotina principal. Observe que,
quando o usuário digitar o sinal de adição, a função somar será executada,
conforme mostrado no código-fonte a seguir.
 calculadora-somar.py
def somar (num1, num2):
return (num1 + num2)

fim = 'n'
while fim == 'n':
valor1 = float(input('Primeiro valor: '))
valor2 = float(input('Segundo valor: '))
opcao = input('Operação (+ - * /)? ')
if opcao == '+':
res = somar (valor1, valor2)
print ('A soma é ', res)
fim = input('Deseja encerrar o programa (s/n)? ')
A seguir temos o programa completo, em que foram implementadas as
funções que realizam a subtração, multiplicação e divisão.
 calculadora-funcao.py
def somar (num1, num2):
return (num1 + num2)

def subtrair (num1, num2):


return (num1 - num2)

def multiplicar (num1, num2):


return (num1 * num2)

def dividir (num1, num2):


return (num1 / num2)

fim = 'n'
while fim == 'n':
valor1 = float(input('Primeiro valor: '))
valor2 = float(input('Segundo valor: '))
opcao = input('Operação (+ - * /)? ')
if opcao == '+':
res = somar (valor1, valor2)
print ('A soma é ', res)
elif opcao == '-':
res = subtrair (valor1, valor2)
print ('A subtração é ', res)
elif opcao == '*':
res = multiplicar (valor1, valor2)
print ('A multiplicação é ', res)
elif opcao == '/':
res = dividir (valor1, valor2)
print ('A divisão é ', res)
else:
print ('Opção inválida!')
fim = input('Deseja encerrar o programa (s/n)? ')
capítulo 3

Portas de entrada e saída

O NodeMCU apresenta um conjunto de portas programáveis para


entrada e saída de dados. Essas portas permitem a sua ligação com
componentes ou circuitos eletrônicos, além de prover interconexão com
outros módulos eletrônicos, utilizando-se, para isso, protocolos de
comunicação. São conhecidas pelo termo GPIO (General Purpose
Input/Output).
Essas portas implementam as funções de saída digital, em que é possível
ligar ou desligar um circuito ou módulo eletrônico. Quando programada
como entrada digital, permite receber informações de um dispositivo
sensor, indicando se ele está ou não ativo. Também existe a possibilidade
de essas portas serem programadas para atuarem como PWM; nesse caso,
em vez de atuarem com níveis digitais (ligado ou desligado), podem enviar
para um circuito ou módulo eletrônico um conjunto de valores existentes
entre o valor mínimo e máximo. Esse recurso, por exemplo, é usado para
controlar a rotação de um motor ou a intensidade com que um LED irá
ser aceso.
Na Figura 3.1, mostramos as funções dos terminais (pinos) do NodeMCU
(ESP8266). Inicialmente observe os terminais identificados como GPIO e
os que são usados para alimentação dos circuitos (3,3V, VIN e GND).
Na Figura 3.2, mostramos as funções dos terminais do NodeMCU
(ESP12). Observe os terminais identificados como GPIO e os que são
usados para alimentação dos circuitos (3,3V, VIN e GND).
 Existem diversos modelos de NodeMCU disponíveis no mercado. Dessa forma,
antes de usar a placa é importante sempre realizar a identificação, pois a
disposição dos terminais pode mudar entre modelos diferentes de placas.
Figura 3.1: Funções dos terminais do NodeMCU (ESP8266).

Saída digital
Este primeiro projeto não irá precisar da montagem de um circuito
eletrônico, pois usaremos o próprio LED que está na placa do NodeMCU
para ilustrar os conceitos iniciais sobre o uso da GPIO.
O NodeMCU (ESP8266) possui dois LEDs integrados na placa e que
estão conectados à GPIO2 e GPIO16. Esses LEDs são ativos (ligados) com
nível 0 (zero) e desligados com nível 1 (um). Por outro lado, o NodeMCU
(ESP12) apresenta apenas um LED que está conectado à GPIO2. Esse
LED é ligado com nível 1 e desligado com nível 0.
 Selecione o interpretador Python adequado à sua placa. Após iniciar o Thonny,
entre na opção Executar do menu e escolha o item Select Interpreter.... Na janela que
será aberta, clique na aba Interpretador e escolha MicroPython (ESP8266) ou MicroPython
(ESP32) e pressione o botão Ok. Não se esqueça também de conectar a NodeMCU na
porta USB do computador.
Figura 3.2: Funções dos terminais do NodeMCU (ESP32).
No Thonny, implemente o código-fonte apresentado a seguir (pisca-pisca-
1.py).

z pisca-pisca-1.py
from time import sleep❶
from machine import Pin❷
led = Pin(2, Pin.OUT) ❸

while True:
led.value(1)
sleep(0.5) ❹
led.value(0)
sleep(0.5) ❺
Após implementar o programa, clique no botão Executar (ou pressione a
tecla F5) para executar o programa, e quando desejar finalizar clique em
Stop (ou pressione a combinação de teclas Ctrl F2).
Analisando o programa, em ❶ e ❷ importamos as funções que serão
usadas no programa. Em ❸ definimos que o terminal (pino) GPIO2 será
utilizado como saída (Pin.OUT), ou seja, será usado para acionar um
determinado elemento que pode ser, por exemplo, LED, motor ou relê,
entre outros tipos de atuadores. Em seguida, na estrutura de repetição
while alternamos o LED entre aceso e apagado com intervalos de
0,5 segundo. Note o uso da função sleep ( ❹ e ❺ ), que irá pausar o
processamento durante o intervalo especificado de tempo.
 Podemos definir que atuador é qualquer tipo de circuito eletrônico ou módulo que
será controlado por um dispositivo microcontrolado, como é o caso do NodeMCU.
Agora podemos realizar a montagem do nosso primeiro circuito
eletrônico e utilizar o mesmo programa que acabamos de implementar
para acionar um LED externo à placa NodeMCU. Comece identificando e
separando os materiais relacionados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
1 LED (qualquer cor)
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 3.3, caso
esteja utilizando o NodeMCU (ESP8266).

Figura 3.3: Ligação do LED à GPIO2 (NodeMCU-ESP8266).


Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 3.4
como referência.
Após realizar a montagem do circuito eletrônico, e lembrando que o
programa é o mesmo que foi desenvolvido anteriormente, clique no botão
Executar (ou pressione a tecla F5) para executar o programa. Quando desejar
finalizar, clique em Stop (ou pressione a combinação de teclas Ctrl F2).

Tratamento de exceções
Você provavelmente notou no programa anterior que, quando
interrompemos a execução do programa, o LED poderá permanecer tanto
aceso quanto apagado, pois não temos controle sobre o momento exato
em que o programa foi interrompido.
O tratamento de exceção é uma boa prática em programação, que permite
evitar que um programa termine de forma abrupta e, mesmo se ocorrer
algo inesperado, ele continuará em execução. Em Python existem as
instruções try e except, que permitem implementar o tratamento de
exceções. No try, colocamos as instruções a serem executadas e, no
except, o que deverá ser feito quando o bloco de instruções especificado
no try gerar algum tipo de erro ou for encerrado de forma intempestiva
por algum evento externo.
Figura 3.4: Ligação do LED à GPIO2 (NodeMCU-ESP32).
Com o objetivo de ilustrar esse conceito, vamos manter a montagem
usada no projeto anterior. O programa, basicamente, é o mesmo usado
anteriormente, porém tem o acréscimo do tratamento de exceções.
z pisca-pisca-2.py
from time import sleep
from machine import Pin

led=Pin(2, Pin.OUT)

try:
while True:
led.value(1)
sleep(0.5)
led.value(0)
sleep(0.5)
except KeyboardInterrupt: ❶
led.value(0) ❷
Observe que nesse caso o programa pode ser interrompido por um evento
externo que é o KeyboardInterrupt ( ❶ ). Esse evento é gerado no momento
que o usuário pressiona a combinação de teclas Ctrl C no shell ou pressiona
o botão Stop e, quando isso ocorrer, em ❷ o LED será desligado antes que
o programa termine.

Simulação de um semáforo
O intuito desse projeto é continuar abordando o conceito das portas do
NodeMCU sendo programadas como saída. Dessa maneira, iremos
realizar a montagem usando três LEDs que simularão o funcionamento
de um sinal de trânsito. Cada LED estará conectado a um pino da GPIO,
sendo controlado individualmente. Vamos começar o projeto
identificando os materiais relacionados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
3 Resistores de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
1 LED vermelho
1 LED verde
1 LED amarelo
1 Protoboard
Cabos de ligação
Na Figura 3.5, temos a montagem do circuito eletrônico para o NodeMCU
(ESP8266), na qual os LEDs vermelho, amarelo e verde são conectados aos
pinos GPIO2, GPIO4 e GPIO5, respectivamente.
Na Figura 3.6, apresentamos o diagrama para a montagem do circuito
eletrônico para o NodeMCU (ESP32). Note que os LEDs serão conectados
da mesma maneira, ou seja, LED vermelho à GPIO2, LED amarelo à
GPIO4 e LED verde à GPIO5.

Figura 3.5: Circuito do semáforo (NodeMCU-ESP8266).


No Thonny, implemente o programa descrito a seguir (semaforo.py). Note
que em ❶ e ❷ iremos importar as funções Pin e sleep, enquanto em ❸, ❹
e ❺ definiremos os respectivos pinos da GPIO para atuarem como saída
(Pin.OUT).
z semaforo.py
from machine import Pin ❶
from time import sleep ❷
led_vm = Pin(2, Pin.OUT) ❸
led_am = Pin(4, Pin.OUT) ❹
led_vd = Pin(5, Pin.OUT) ❺

try:
while True: ⓬
led_vm.value(1)❻
sleep(0.5)
led_vd.value(1)❼
led_vm.value(0)❽
sleep(0.5)
led_am.value(1)❾
led_vd.value(0)❿
sleep(0.5)
led_am.value(0)⓫
except KeyboardInterrupt:
led_vm.value(0) ⓭
led_am.value(0) ⓮
led_vd.value(0) ⓯
Em ❻ o LED vermelho é aceso, ficando nessa condição por 0,5 segundo.
Em seguida, em ❼ o LED verde é aceso e o vermelho é apagado em ❽ ,
após meio segundo o LED amarelo é aceso em ❾ enquanto o LED verde é
apagado em ❿ . Novamente, após meio segundo em ⓫ o LED amarelo é
apagado e o ciclo recomeça em ⓬ devido ao uso da estrutura de repetição
while.
Quando a execução do programa for interrompida, todos os LEDs são
apagados, como podemos observar em ⓭, ⓮ e ⓯.
Figura 3.6: Circuito do semáforo (NodeMCU-ESP32).

Entrada digital
Os terminais da GPIO podem ser programados para atuarem como saída
digital, na qual acionam um determinado circuito ou módulo eletrônico,
ou como entrada digital, em que recebem dados de um determinado
módulo ou circuito eletrônico.
 Circuitos ou módulos eletrônicos que enviam dados para um microcontrolador são
chamados de sensores.
Neste projeto vamos utilizar um pino da GPIO que estará conectado a
uma chave táctil para determinar se essa chave táctil está ou não
pressionada. Os materiais necessários para a montagem do projeto estão
relacionados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
1 Resistor de 10k Ohms (marrom, preto, laranja)
1 LED (qualquer cor)
1 Chave táctil
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 3.7, caso
esteja utilizando o NodeMCU (ESP8266).
Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 3.8
como referência.
No Thonny, implemente o código-fonte apresentado a seguir.
z botao-led-1.py
from machine import Pin
from time import sleep

led = Pin(5, Pin.OUT)


botao = Pin(4, Pin.IN) ❶
try:
while True:
led.value(botao.value()) ❷
sleep(0.2)
except KeyboardInterrupt:
led.value(0)
Execute o programa. O LED deverá ficar aceso apenas enquanto a chave
táctil estiver pressionada. Analisando o código-fonte, vemos que em ❶
definimos o pino GPIO5, que é o local em que a chave táctil foi conectada
como entrada (Pin.IN). Observe em ❷ que, quando a chave táctil não está
pressionada, o método botao.value() irá retornar 0 (zero), e como esse
valor é passado para o LED, este permanecerá apagado. Por outro lado, se
a chave táctil estiver pressionada, o método botao.value() irá retornar 1 e o
LED será aceso.
No próximo programa (botao-led-2.py), vamos usar a chave táctil para
encerrar o programa. O circuito eletrônico é o mesmo que já utilizamos e
é mostrado na Figura 3.7 ou na Figura 3.8, conforme o modelo de
NodeMCU utilizado.

Figura 3.7: Montagem do circuito (NodeMCU-ESP8266).


Figura 3.8 Montagem do circuito (NodeMCU-ESP32).
z botao-led-2.py
from machine import Pin
from time import sleep

led = Pin(5, Pin.OUT)


botao = Pin(4, Pin.IN)
estado = 1
while not botao.value(): ❶
led.value(estado)
sleep(0.2)
estado = not estado
led.value(0)
Conforme podemos notar em ❶ , o valor obtido da chave táctil irá definir
se o while deverá ou não prosseguir. Dessa maneira, o LED ficará
piscando até que a chave táctil seja pressionada.
Uma terceira possibilidade de programa para uso da chave táctil,
mantendo o circuito eletrônico adotado nos programas anteriores, é
aplicar um conceito chamado manutenção de estado. Essa técnica é muito
empregada em aparelhos eletrônicos, por exemplo. Quando pressionamos
o botão para ligar um televisor, este permanecerá ligado até que o mesmo
botão seja pressionado novamente e assim sucessivamente.
z botao-led-3.py
from machine import Pin
from time import sleep

led = Pin(5, Pin.OUT)


botao = Pin(4, Pin.IN)
estado = 0
anterior = 0
try:
while True:
valor = botao.value()
if valor == 1 and anterior == 0: ❶
estado = not estado ❷
led.value(estado)
anterior = valor
sleep(0.2)
except KeyboardInterrupt:
led.value(0)
Analisando o código-fonte, podemos notar que a variável estado será
utilizada para determinar a situação do LED, ou seja, aceso (1) ou
desligado (0). Em ❶ é realizada a verificação se o estado do botão mudou
e, se isso for verdadeiro, em ❷ o valor da variável é invertido com o uso do
operador lógico not.

Modulação por largura de pulso


A PWM (Pulse Width Modulation – Modulação por Largura de Pulso)
consiste em uma técnica que permite, a partir de uma saída digital,
reproduzir uma série de valores entre o valor mínimo (0 Volts) e o valor
máximo (3,3 Volts). No NodeMCU, essa série é representada pelos valores
inteiros entre 0 e 1023.
Agora podemos realizar a montagem do nosso primeiro circuito
eletrônico e utilizar o mesmo programa que acabamos de implementar
para acionar um LED externo à placa NodeMCU. Comece identificando e
separando os materiais relacionados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
1 LED (qualquer cor)
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 3.9, caso
esteja utilizando o NodeMCU (ESP8266).
Figura 3.9: Ligação do LED à GPIO2 (NodeMCU-ESP8266).
Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 3.10
como referência.
Figura 3.10: Ligação do LED à GPIO2 (NodeMCU-ESP32).
Após a montagem, use o Thonny para implementar o programa
apresentado a seguir.
z led-pwm.py
from machine import Pin, PWM
from time import sleep

led = PWM(Pin(2), freq=20000, duty=0) ❶


for valor in range (1024): ❷
led.duty(valor) ❸
sleep(0.01)
led.duty(0)
Observe em ❶ que a função PWM será usada para definir que o terminal
GPIO2 atuará como PWM, sendo que a propriedade duty define o valor
que será aplicado à porta. Em ❷ usamos a instrução for em conjunto com
a função range para gerar uma sequência de valores entre 0 e 1023. Em ❸
esses valores serão usados como parâmetro do método duty e definirão a
intensidade com que LED será aceso.

LED RGB
O LED RGB é um componente eletrônico que apresenta em um mesmo
invólucro três LEDs, sendo um na cor vermelha, outro na cor verde e
outro na cor azul. Além disso, cada um dos LEDs pode ser controlado
individualmente. Existem dois tipos de LEDs RGB. Um é chamado de
cátodo comum, pois os três LEDs estão interligados pelo terminal
negativo (cátodo). Nesse tipo de LED RGB, cada um dos LEDs é ligado
pelo nível 1 e desligado com nível 0.
O outro tipo de LED RGB é o ânodo comum. Nesse caso, os três LEDs
estão interligados pelo terminal positivo (ânodo) e cada um dos LEDs é
ativado com nível 0 e desligado com nível 1.
Comece o projeto identificando e separando os seguintes materiais.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
1 LED RGB (cátodo ou ânodo comuns)
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 3.11,
escolhendo a opção adequada ao tipo de LED RGB, caso esteja utilizando
o NodeMCU (ESP8266).
Adote como referência a Figura 3.12, escolhendo a opção adequada ao tipo
de LED RGB, caso utilize o NodeMCU (ESP32).
Figura 3.11: Conexões (NodeMCU-ESP8266).
Figura 3.12: Conexões (NodeMCU-ESP32).
Após a montagem do circuito eletrônico no Thonny, digite o seguinte
programa.
z led-rgb-random.py
from machine import Pin, PWM
from time import sleep
from random import getrandbits

# Indicar o tipo do LED RGB:


# CATODO_COMUM ou ANODO_COMUM
tipo = 'ANODO_COMUM' ❶
if tipo == 'CATODO_COMUM':
MIN = 0
MAX = 1023
else:
MIN = 1023
MAX = 0
r = PWM(Pin(5), freq=20000, duty=MIN) ❷
g = PWM(Pin(4), freq=20000, duty=MIN) ❸
b = PWM(Pin(15), freq=20000, duty=MIN) ❹
try:
while True:
r.duty(getrandbits(10)) ❺
g.duty(getrandbits(10)) ❻
b.duty(getrandbits(10)) ❼
sleep(1.0)
except KeyboardInterrupt:
r.duty(MIN)
g.duty(MIN)
b.duty(MIN)
No programa em ❶ definimos o tipo do LED RGB que está sendo usado,
pois ele será usado para definir se o LED será apagado com o valor 0, caso
seja cátodo comum, ou 1023, caso seja do tipo com ânodo comum. Assim
sendo, atribua à variável tipo conforme o modelo de LED RGB que você
usou na montagem.
Depois em ❷, ❸ e ❹ os três pinos da GPIO que estão conectados ao LED
RGB são configurados como PWM. Em seguida, com a função
getrandbits obtemos um valor aleatório que será aplicado aos pinos
PWM, como é possível observar em ❺ , ❻ e ❼ . A função getrandbits
recebe, como parâmetro, a quantidade de bits que serão usados para gerar
um valor aleatório. Dessa maneira, nesse projeto colocamos 10, pois 210 é
igual a 1024, ou seja, serão gerados valores inteiros entre 0 e 1023.

Conversor analógico digital


Existe uma vasta gama de sensores que operam com valores analógicos,
por exemplo, sensores de temperatura, umidade e intensidade luminosa.
Dessa forma, para que seja possível utilizá-los no NodeMCU, temos o
Conversor Analógico Digital ou simplesmente ADC, que é a sigla do
termo inglês Analogic Digital Converter.
O NodeMCU (ESP8266) apresenta apenas um terminal com capacidade
de obter valores analógicos, e ele é identificado na placa como A0. Por
outro lado, o NodeMCU (ESP32) apresenta 15 pinos que podem ser
configurados como entradas analógicas se a comunicação sem fio estiver
desligada (observar os pinos com identificação ADC na Figura 3.2). Caso
a comunicação sem fio esteja ligada, esse número é reduzido para
6 terminais (GPIO32, GPIO33, GPIO34, GPIO35, GPIO36 e GPIO39).
O projeto a seguir ilustrará o uso do ADC do NodeMCU. Será utilizado
um potenciômetro para definir a frequência com que o LED deverá piscar.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
1 LED (qualquer cor)
1 Potenciômetro de 10k Ohms
1 Protoboard
Cabos de ligação
Após identificar e separar os materiais necessários, realize a montagem da
maneira indicada pela Figura 3.13, caso esteja utilizando o NodeMCU
(ESP8266).
No Thonny, implemente o seguinte programa (adc-pot-esp8266.py), que
deverá ser usado apenas no NodeMCU (ESP8266), pois o uso do ADC no
NodeMCU (ESP32) é ligeiramente diferente e será mostrado no próximo
programa que será desenvolvido.
Figura 3.13: Conexões com o NodeMCU (ESP8266).
z adc-pot-esp8266.py
from machine import ADC, Pin
from time import sleep_ms

led = Pin(5, Pin.OUT)


pot = ADC(0) ❶
estado = 0
try:
while True:
led.value(estado)
estado = not estado
sleep_ms(pot.read()) ❷
except KeyboardInterrupt:
led.value(0)
Observe em ❶ que definimos que será usado o pino A0 (ADC), que é
onde conectamos o terminal central do potenciômetro. Em ❷ realizamos
a leitura que variará em função da posição do eixo do potenciômetro,
assumindo uma faixa de valores inteiros entre 0 e 1023, que equivalem,
respectivamente, a 0 e 3,3 Volts. O valor obtido é passado como parâmetro
para a função sleep_ms, que definirá o tempo que deverá ser aguardado
antes que o programa continue sua execução.
 Não devemos conectar à NodeMCU (ESP8266) sensores que operem com tensões
maiores que 3,3 Volts, pois corremos o risco de danificar a porta A0.
No NodeMCU (ESP32), a montagem do circuito eletrônico deverá ocorrer
conforme ilustra a Figura 3.14.
Figura 3.14: Conexões com o NodeMCU (ESP32).
No Thonny, implemente o seguinte programa, que deverá ser usado
apenas no NodeMCU (ESP32).
z adc-pot-esp32.py
from machine import ADC, Pin
from time import sleep_ms

led = Pin(5, Pin.OUT)


pot = ADC(Pin(34)) ❶
pot.atten(ADC.ATTN_11DB) ❷
estado = 0
try:
while True:
led.value(estado)
estado = not estado
sleep_ms(int(pot.read() / 4)) ❸
except KeyboardInterrupt:
led.value(0)
Comparando o programa com aquele que foi desenvolvido para o
NodeMCU (ESP8266), notamos que em ❶ definimos que o pino GPIO34
será usado pelo ADC e em ❷ configuramos a atenuação que será aplicada
ao sinal usando a função atten(), e que o parâmetro ADC.ATTN_11DB indica
que a porta lerá valores até 3,6 Volts. Dessa forma, não devemos conectar
sensores que operem uma faixa de tensão maior que 3,6 Volts, pois
corremos o risco de danificar a porta GPIO. Caso queira utilizar outras
faixas de tensão, pode ser configurado usando os parâmetros ADC.ATTN_0DB
(para tensão até 1,0 Volts, sendo a configuração padrão), ADC.ATTN_2_5DB
(para tensão em torno de 1,34 Volts) ou ADC.ATTN_6DB (para tensão de
aproximadamente 2.0 Volts).
Diferente do ADC do NodeMCU (ESP8266), que trabalha com leituras
entre 0 e 1023, no NodeMCU (ESP32) o ADC retornará valores inteiros
entre 0 e 4095. Então, nesse exemplo, para manter o parâmetro de tempo
adotado no programa anterior, note em ❸ que dividimos o valor lido pelo
ADC por 4.
Mantendo a montagem do circuito eletrônico usado no programa
anterior, vamos usar agora o potenciômetro para definir a intensidade
com a qual o LED deverá acender. Dessa forma, se estiver usando o
NodeMCU (ESP8266), implemente no Thonny o programa apresentado a
seguir.
z adc-pot-pwm-esp8266.py
from machine import ADC, Pin, PWM
from time import sleep

led = PWM(Pin(5), freq=20000, duty=0)


pot = ADC(0)
try:
while True:
led.duty(pot.read())
sleep(0.1)
except KeyboardInterrupt:
led.duty(0)
Por outro lado, caso esteja utilizando o NodeMCU (ESP32), implemente o
seguinte código-fonte.
z adc-pot-pwm-esp32.py
from machine import ADC, Pin, PWM
from time import sleep

led = PWM(Pin(5), freq=20000, duty=0)


pot = ADC(Pin(34))
pot.atten(ADC.ATTN_11DB)
try:
while True:
led.duty(int(pot.read() / 4))
sleep(0.1)
except KeyboardInterrupt:
led.duty(0)
Observe nos dois programas que o valor obtido do ADC é usado como
parâmetro do método duty do pino GPIO5 que foi configurado para atuar
com PWM.
Medidor de intensidade luminosa
Neste projeto vamos usar um LDR (Light Dependent Resistor – Resistor
Dependente de Luz) conectado ao ADC do NodeMCU e, com base na
quantidade de luz recebida pelo sensor, o programa irá determinar se
deverá acender nenhum, um, dois ou três dos LEDs que estarão
conectados à GPIO.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
3 Resistores de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
1 Resistor de 10k Ohms (marrom, preto, laranja)
1 LED verde
1 LED amarelo
1 LED vermelho
1 LDR
1 Protoboard
Cabos de ligação
Realize a montagem da maneira indicada pela Figura 3.15 caso esteja
utilizando o NodeMCU (ESP8266).
Figura 3.15: Circuito eletrônico com o NodeMCU (ESP8266).
A seguir temos o programa específico para o NodeMCU (ESP8266).
z adc-ldr-nivel-esp8266.py
from machine import Pin, ADC
from time import sleep

def mapear(x, in_min, in_max, out_min, out_max): ❶


return (x - in_min) * (out_max - out_min) / (in_max - in_min) +
out_min ❷
led_vd = Pin(5, Pin.OUT)
led_am = Pin(4, Pin.OUT)
led_vm = Pin(15, Pin.OUT)

ldr = ADC(0)
try:
while True:
valor_ldr = ldr.read()
valor = int(mapear(valor_ldr, 0, 1024, 0, 4))
print ("ADC: ", valor_ldr, "Mapear:", valor)
if valor == 0:
led_vd.value(0)
led_am.value(0)
led_vm.value(0)
elif valor == 1:
led_vd.value(1)
led_am.value(0)
led_vm.value(0)
elif valor == 2:
led_vd.value(1)
led_am.value(1)
led_vm.value(0)
elif valor == 3:
led_vd.value(1)
led_am.value(1)
led_vm.value(1)
sleep(0.1)
except:
led_vm.value(0)
led_am.value(0)
led_vd.value(0)
A montagem para o NodeMCU (ESP32) é mostrada na Figura 3.16.
Figura 3.16: Circuito eletrônico com o NodeMCU (ESP32).
Na sequência, apresentamos o programa específico para o NodeMCU
(ESP32).
z adc-ldr-nivel-esp32.py
from machine import Pin, ADC
from time import sleep

def mapear(x, in_min, in_max, out_min, out_max): ❶


return (x - in_min) * (out_max - out_min) / (in_max - in_min) +
out_min ❷
led_vd = Pin(5, Pin.OUT)
led_am = Pin(4, Pin.OUT)
led_vm = Pin(15, Pin.OUT)

ldr = ADC(Pin(34))
ldr.atten(ADC.ATTN_11DB)
try:
while True:
valor_ldr = ldr.read()
valor = int(mapear(valor_ldr, 0, 4095, 0, 4))
print ("ADC: ", valor_ldr, "Mapear:", valor)
if valor == 0:
led_vd.value(0)
led_am.value(0)
led_vm.value(0)
elif valor == 1:
led_vd.value(1)
led_am.value(0)
led_vm.value(0)
elif valor == 2:
led_vd.value(1)
led_am.value(1)
led_vm.value(0)
elif valor == 3:
led_vd.value(1)
led_am.value(1)
led_vm.value(1)
sleep(0.1)
except:
led_vm.value(0)
led_am.value(0)
led_vd.value(0)
Analisando ambos os programas, criamos em ❶ e ❷ a função mapear. Essa
função basicamente realiza uma regra de três convertendo o valor obtido
do ADC, que no NodeMCU (ESP8266) é de 0 a 1023 e no NodeMCU
(ESP32) é de 0 a 4095, para a quantidade de LEDs que devem ser acesos.

Medidor de temperatura com termístor


O Termístor é um tipo de resistor que muda o valor de sua resistência em
função da temperatura. Nesse projeto, apenas vamos obter o valor do
ADC, converter para graus Celsius e exibir no shell. Os materiais
necessários estão especificados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 10k Ohms (marrom, preto, laranja)
1 Termístor NTC 10k Ohms
1 Protoboard
Cabos de ligação
Na Figura 3.17, temos o circuito eletrônico para o NodeMCU (ESP8266).

Figura 3.17: Circuito eletrônico com o NodeMCU (ESP8266).


O programa é apresentado a seguir, específico para o NodeMCU
(ESP8266), devendo ser implementado no ambiente de desenvolvimento
Thonny.
z adc-termistor-esp8266.py
from machine import Pin, ADC
from time import sleep
from math import log

def obterTemperatura(termistor): ❶
tempK = log(10000.0 * (1024.0 / termistor - 1)) ❷
tempK = 1 / (0.001129148 + (0.000234125
+ (0.0000000876741 * tempK * tempK )) * tempK)
tempC = tempK - 273.15
return tempC

adc = ADC(0)

while True:
temp = obterTemperatura(adc.read())
print ("Temperatura: ", round(temp, 1), "°C")
sleep(1.0)
Em seguida, na Figura 3.18 mostramos o circuito eletrônico para o
NodeMCU (ESP32).
Figura 3.18: Circuito eletrônico com o NodeMCU (ESP32).
Implemente o programa para o NodeMCU (ESP32).
z adc-termistor-esp32.py
from machine import Pin, ADC
from time import sleep
from math import log

def obterTemperatura(termistor): ❶
tempK = log(10000.0 * (4096.0 / termistor - 1)) ❷
tempK = 1 / (0.001129148 + (0.000234125
+ (0.0000000876741 * tempK * tempK )) * tempK)
tempC = tempK - 273.15
return tempC

adc = ADC(Pin(34))
adc.atten(ADC.ATTN_11DB)
while True:
temp = obterTemperatura(adc.read())
print ("Temperatura: ", round(temp, 1), "°C")
sleep(1.0)
Em ❶ de ambos os programas, definimos a função obterTemperatura. Essa
função recebe como parâmetro o valor obtido pelo ADC e converte para
Kelvin e, em seguida, para graus Celsius. Observe em ❷ que devemos
colocar na fórmula a resolução do ADC. Então, no caso do NodeMCU
(ESP8266) colocamos o valor 1024,0 e no NodeMCU (ESP32) o valor
4096,0.
capítulo 4

Orientação a objetos

Neste capítulo, você irá conhecer o paradigma de Orientação a Objetos


que apresenta uma nova forma de projetar e desenvolver programas de
computadores. O projeto e a programação estruturada focam na redução
dos problemas computacionais considerando apenas três estruturas
básicas: sequência, decisão e interação, sendo que, na programação
estruturada, procedimentos, funções e estruturas de dados apresentam
ligações e relacionamentos tênues. Por outro lado, a Orientação a Objeto
estabelece um forte relacionamento entre os diversos componentes de um
determinado problema computacional.
Na programação orientada a objetos, implementa-se um conjunto de
classes que permitem a definição dos objetos presentes no projeto do
sistema. Cada classe tem por objetivo determinar o comportamento e
estados, sendo que os comportamentos são definidos pelos métodos, e
estados são descritos pelos atributos que compõem e caracterizam os
objetos. Os atributos também permitem a definição do relacionamento
com outros objetos.

Classes, objetos, atributos e métodos


Conforme mencionado anteriormente, a orientação a objetos pode
começar a ser entendida com a definição de dois elementos chave:
• O primeiro é o conceito de classe, que pode ser entendido como a
descrição de um ou mais objetos por um conjunto de características
(atributos) e ações (métodos).
• O segundo é o próprio objeto, que pode ser definido como uma
abstração de algo que existe dentro do domínio (área de aplicação) de
um problema ou na sua implementação, sendo que todo objeto é a
instância de uma classe.
Em síntese, uma classe determina o comportamento dos objetos, e os
objetos são definidos pelos métodos e pelos atributos que compõem e
caracterizam esses objetos. Dessa maneira, o objeto pode ser entendido
como uma abstração de algo que existe dentro do domínio de um
problema ou na sua implementação, sendo que todo objeto é a instância
de uma classe. Para um perfeito entendimento dos conceitos básicos da
orientação a objeto, torna-se necessário definir os seguintes conceitos:
• Atributo: define um conjunto padrão de características específicas para
uma determinada classe. Os valores (estados) que esses atributos
recebem, quando a classe é instanciada, permitem caracterizar um
objeto. Considerando uma determinada classe pessoa, os atributos
poderiam ser nome, endereço e telefone, entre outros.
• Método: solicitação a um objeto invocando um de seus métodos,
método este que ativa um determinado comportamento descrito pela
classe que deu origem ao objeto em questão. Usando como exemplo a
classe pessoa, poderíamos definir métodos para alterar o nome, o
endereço ou o telefone de determinado indivíduo.
As classes implementam também os métodos construtores, que devem ser
identificados com o nome __init__. O método construtor é executado
somente quando o objeto é criado, ou seja, quando uma classe é
instanciada.
Como abordado anteriormente, uma classe define o comportamento de
um objeto pela definição dos métodos e atributos. Porém, a classe em si
não realiza o armazenamento dos valores dos atributos ou a execução dos
métodos. Dessa forma, torna-se necessário instanciar (criar) os objetos a
partir da classe definida. Sendo assim, objetos podem ser entendidos
como instâncias de uma classe.

Classe LED
Aplicando os conceitos iniciais de Orientação a Objetos (objetos, classes,
atributos e métodos), é possível criar uma abstração do componente
eletrônico LED, que foi abordado no capítulo anterior, representando uma
classe que define suas características e comportamentos. Mas, em
primeiro lugar, comece identificando e separando os materiais
relacionados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
1 LED (qualquer cor)
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 4.1, caso
esteja utilizando o NodeMCU (ESP8266).
Figura 4.1: Ligação do LED à GPIO2 (NodeMCU-ESP8266).
Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 4.2
como referência.
Agora podemos passar para a criação da classe Led. O primeiro passo
observamos em ❶ e consiste em realizar a definição da classe. Em ❷ é
realizada a definição do método construtor. A partir da palavra reservada
self, em ❸ e ❹ definimos os atributos da classe LED que, neste
programa, serão __pwm, que representa o pino onde o LED foi conectado, e
__estado, isto é, se o LED está ligado ou desligado.
A palavra-reservada self é utilizada para referenciar um atributo ou
método da própria classe evitando ambiguidade em relação aos
parâmetros ou variáveis declaradas dentro de um método da classe.
Figura 4.2: Ligação do LED à GPIO2 (NodeMCU-ESP32).
Observe também que na definição dos atributos realizada em ❸ e ❹ foi
colocado __ (underscore) na frente do nome do atributo. Ele define que o
atributo é privado e, dessa forma, pode ser acessado apenas dentro da
classe. Esse conceito é chamado de encapsulamento e consiste na
separação de características internas e externas de um determinado
objeto. Esse recurso é comumente utilizado para evitar o acesso direto aos
atributos desse objeto, permitindo, dessa forma, que apenas os métodos
consigam alterar esses atributos.
z led.py
from time import sleep
from machine import Pin, PWM
class Led(object): ❶
def __init__(self, pino): ❷
self.__pwm = PWM(Pin(pino), freq=20000, duty=0) ❸
self.__estado = False ❹
def ligar(self):
self.__pwm.duty(1023)

def desligar(self):
self.__pwm.duty(0)

def alternar(self, tempo=0.5): ❺


if self.__estado:
self.ligar()
else:
self.desligar()
self.__estado = not self.__estado
sleep(tempo)

def piscar(self, tempo=0.5, vezes=1):


for i in range (vezes * 2 + 1):
self.alternar(tempo)

def intensidade(self, valor):


self.__pwm.duty(valor)
Prosseguindo com a análise do código-fonte da classe Led, realizamos a
definição dos métodos ligar, desligar, alternar, piscar e intensidade, que
definem os comportamentos que o objeto pode apresentar. Observe que,
quando definimos um método, obrigatoriamente devemos passar o
parâmetro self e depois os demais parâmetros se estes existirem.
Em ❺ , quando definimos o método alternar, note que podemos ter
parâmetros como valores padrão, por exemplo, tempo = 0.5. Nesse caso, se
o parâmetro tempo não for passado na chamada do método, este assumirá
o valor 0.5.
Após salvar a classe Led em um arquivo com o nome led.py, use o
utilitário Ampy para copiá-lo para o sistema de arquivos do NodeMCU,
conforme mostrado a seguir. Apenas tenha a precaução de trocar a porta
usada no exemplo (com6) pela porta na qual o NodeMCU está conectado
ao seu computador.
 ampy --port com6 put led.py
O programa a seguir irá instanciar (criar) um objeto da classe Led, como
podemos notar em ❶ , e em ❷ executar o método piscar. Observe que a
implementação ficou muito mais simples, pois todo o funcionamento do
LED foi especificado dentro da classe Led, facilitando o seu reúso, além de
não ser necessário conhecermos detalhes do funcionamento do LED. Esse
conceito é chamado de abstração e consiste na capacidade de permitir a
concentração apenas nos aspectos essenciais de um contexto, mascarando
detalhes específicos e características menos importantes para a resolução
de um determinado problema.
z pisca-pisca-1-oo.py
from led import Led

led = Led(2) ❶
led.piscar(0.2, 5) ❷
Note no próximo código-fonte, em ❶ e ❷ , que podemos definir usar o
nome dos parâmetros na chamada de um método. Essa técnica deixa o
programa mais legível, facilitando o entendimento.
z pisca-pisca-2-oo.py
from led import Led

led = Led(pino=2) ❶
led.piscar(tempo=0.2, vezes=5) ❷
Abstração da chave táctil
Neste projeto vamos implementar os detalhes de funcionamento da chave
táctil em uma classe chamada Botao. Os materiais necessários para a
montagem do projeto estão relacionados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
1 Resistor de 10k Ohms (marrom, preto, laranja)
1 LED (qualquer cor)
1 Chave táctil
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 4.3, caso
esteja utilizando o NodeMCU (ESP8266).
Figura 4.3: Montagem do circuito (NodeMCU-ESP8266).
Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 4.4
como referência.
A classe terá os atributos relacionados ao pino utilizado para ligar o botão
(__botao), o estado atual (__estado), isto é, se o botão está ou não
pressionado, e também o estado anterior (__anterior), conforme podemos
observar em ❶ , ❷ e ❸ . O método pressionado irá retornar o estado do
botão no momento. Por outro lado, o método estado irá manter o estado
do botão até que um novo pressionamento ocorra.

Figura 4.4: Montagem do circuito (NodeMCU-ESP32).


z botao.py
from time import sleep
from machine import Pin

class Botao(object):
def __init__(self, pino):
self.__botao = Pin(pino, Pin.IN) ❶
self.__estado = 0 ❷
self.__anterior = 0❸
def pressionado(self):
return self.__botao.value()

def estado(self, quantidade=2):


if self.pressionado() and self.__anterior == 0:
self.__estado = self.__estado + 1
if self.__estado >= quantidade:
self.__estado = 0
self.__anterior = self.pressionado()
sleep(0.1)
return self.__estado
Após salvar a classe Botao em um arquivo com o nome botao.py, use o
utilitário Ampy para copiá-lo para o sistema de arquivos do NodeMCU,
conforme mostrado a seguir. Não se esqueça de trocar a porta usada no
exemplo (com6) pela porta na qual o NodeMCU está conectado ao seu
computador.
 ampy --port com6 put botao.py
Em seguida, vamos desenvolver um programa que fará uso dessa classe.
Observe em ❶ e ❷ que instanciamos os dois objetos, passando os pinos
nos quais o LED e a chave táctil foram conectados. Em ❸ e ❹ , definimos
que o LED ficará aceso enquanto o botão estiver pressionado, caso
contrário, em ❺ e ❻ o LED é apagado.
z botao-led-1-oo.py
from led import Led
from botao import Botao
led = Led(5) ❶
botao = Botao(4) ❷
try:
while True:
if botao.pressionado(): ❸
led.ligar() ❹
else: ❺
led.desligar() ❻
except KeyboardInterrupt:
led.desligar()
O próximo programa apresenta outra maneira de usarmos as classes Led e
Botao. O circuito eletrônico é o mesmo utilizado no programa anterior.
Neste programa, o LED ficará piscando. Observe o uso do método
alternar em ❶ . Até que o botão seja pressionado ❷ , neste momento o
LED será apagado e o programa termina.
z botao-led-2-oo.py
from led import Led
from botao import Botao

led = Led(5)
botao = Botao(4)

while not botao.pressionado(): ❷


led.alternar(0.2) ❶
led.desligar()
Mantendo a montagem do circuito eletrônico usado nos projetos
anteriores, vamos apresentar um terceiro programa que explorará o uso
das classes que desenvolvemos até o momento. Este programa irá usar o
conceito de manutenção de estado, ou seja, quando pressionamos a chave
táctil o LED será ligado, e permanecerá ligado, até que a chave táctil seja
pressionada novamente.
z botao-led-3-oo.py
from led import Led
from botao import Botao

led = Led(5)
botao = Botao(4)

try:
while True:
if botao.estado() == 1: ❶
led.ligar()
else:
led.desligar()
except KeyboardInterrupt:
led.desligar()
Analisando o código-fonte, em ❶ temos o uso do método estado. Como
não passamos um parâmetro para o método, ele assumirá o valor padrão
que é dois, ou seja, atuará com dois estados possíveis (0 e 1).

Uma classe para o LED RGB


Este projeto irá implementar uma classe para usarmos o LED RGB.
Observe que o componente apresenta dois tipos (Cátodo ou Ânodo
comuns), e esse fato faz com que seja necessário, durante a programação,
considerar as peculiaridades de funcionamento de cada tipo. Inicie o
projeto identificando e separando os seguintes materiais.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
1 LED RGB (cátodo ou ânodo comuns)
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 4.5,
escolhendo a opção adequada ao tipo de LED RGB, caso esteja utilizando
o NodeMCU (ESP8266).
Figura 4.5: Conexões (NodeMCU-ESP8266).
Adote como referência a Figura 4.6, escolhendo a opção adequada ao tipo
de LED RGB, caso utilize o NodeMCU (ESP32).
Figura 4.6: Conexões (NodeMCU-ESP32).
Após a montagem do circuito eletrônico, podemos passar para a criação
da classe que irá representar o LED RGB. Em ❶ e ❷ podemos notar que a
classe terá dois atributos que irão determinar o tipo (__tipo) do LED RGB
e os pinos (__pwm) que serão conectados ao NodeMCU. Observe que
vamos aplicar o conceito de lista para definir os pinos do LED RGB. Caso
o tipo de LED RGB seja do tipo Cátodo Comum, em ❸ , ❹ , ❺ e ❻
definimos os pinos usados como PWM e inserimos na lista usando o
método append. Também definimos a propriedade duty de cada pino para
que o LED RGB seja iniciado mantendo todas as cores desligadas.
Por outro lado, em ❼, ❽, ❾ e ❿ realizamos a configuração dos pinos para
quando o tipo do LED RGB for Ânodo Comum. Note que a propriedade
duty é definida para o valor máximo, ou seja, 1023 para que o LED RGB
seja iniciado desligado. Em seguida, são definidos os demais métodos da
classe.
z led-rgb.py
from machine import Pin, PWM
from time import sleep
from random import getrandbits

class LedRGB(object):
VERMELHO = 0
VERDE = 1
AZUL = 2
CATODO_COMUM = 3
ANODO_COMUM = 4

def __init__(self, pinoVermelho, pinoVerde, pinoAzul,


tipo=CATODO_COMUM):
self.__tipo = tipo ❶
self.__pwm = [] ❷
if self.__tipo == self.CATODO_COMUM: ❸
self.__pwm.append(PWM(Pin(pinoVermelho), freq=20000, duty=0)) ❹
self.__pwm.append(PWM(Pin(pinoVerde), freq=20000, duty=0)) ❺
self.__pwm.append(PWM(Pin(pinoAzul), freq=20000, duty=0)) ❻
else: ❼
self.__pwm.append(PWM(Pin(pinoVermelho), freq=20000, duty=1023))

self.__pwm.append(PWM(Pin(pinoVerde), freq=20000, duty=1023)) ❾
self.__pwm.append(PWM(Pin(pinoAzul), freq=20000, duty=1023)) ❿
def ligar(self, cor):
if self.__tipo == self.CATODO_COMUM:
self.__pwm[cor].duty(1023)
else:
self.__pwm[cor].duty(0)

def desligar(self, cor):


if self.__tipo == self.CATODO_COMUM:
self.__pwm[cor].duty(0)
else:
self.__pwm[cor].duty(1023)
def desligarTodas(self):
for cor in range(3):
self.desligar(cor)

def intensidade(self, cor, valor):


if self.__tipo == self.CATODO_COMUM:
self.__pwm[cor].duty(valor)
else:
self.__pwm[cor].duty(1023 - valor)

def caleidoscopio(self, transicao=0.1, duracao=1.0):


for vezes in range (int(duracao/transicao) + 1):
for cor in range(3):
self.__pwm[cor].duty(getrandbits(10))
sleep(transicao)
Use o utilitário Ampy para copiar o arquivo ledrgb.py para o sistema de
arquivos do NodeMCU, conforme mostrado a seguir. Não se esqueça de
trocar a porta usada no exemplo (com6) pela porta na qual o NodeMCU
está conectado ao seu computador.
 ampy --port com6 put ledrgb.py
O código-fonte a seguir irá demonstrar os recursos disponíveis na classe
LedRGB. Observe que o objeto led é criado em ❶ , onde indicamos os pinos
conectados ao NodeMCU e o tipo do LED RGB. Depois acendemos e
apagamos individualmente cada uma das cores. Por fim, em ❷
demonstramos o uso do método caleidoscopio e em ❸ desligamos todas
as cores do LED RGB.
z led-rgb-oo.py
from ledrgb import LedRGB
from time import sleep

led = LedRGB(5, 4, 15, LedRGB.ANODO_COMUM) ❶


led.ligar(LedRGB.VERMELHO)
sleep(1.0)
led.desligar(LedRGB.VERMELHO)
led.ligar(LedRGB.VERDE)
sleep(1.0)
led.desligar(LedRGB.VERDE)
led.ligar(LedRGB.AZUL)
sleep(1.0)
led.desligar(LedRGB.AZUL)
led.caleidoscopio(0.2, 10) ❷
led.desligarTodas()❸
Herança
O conceito de herança pode ser entendido como o recurso pelo qual uma
determinada classe, que será considerada uma subclasse, pode receber
atributos e métodos presentes em outra classe que, neste caso, será
caracterizada como uma superclasse. Uma das características
fundamentais da orientação a objetos é a capacidade de reaproveitamento
de código, a qual pode ser implementada com a adoção do conceito de
herança. O exemplo discutido a seguir mostra uma possibilidade de
aplicação do conceito de herança.
Vamos considerar que o ADC do NodeMCU, vários componentes como
Potenciômetro, Resistor Dependente de Luz (LDR) e Termístor, são
conectados no ADC. Dessa forma, aplicando o conceito de herança
podemos definir uma única classe (superclasse) que irá permitir
configurar e usar o ADC, e as subclasses herdam as características e
métodos da superclasse. Vamos, então, implementar a superclasse que será
chamada de ConversorAD. Observe que, pelo fato de as características do
ADC variarem do modelo do NodeMCU com o ESP8266 em relação ao
que utiliza o ESP32, colocamos dentro desta classe essas peculiaridades,
evitando, posteriormente, que outras classes precisem se preocupar com
isso.
z conversor-ad.py
from machine import Pin, ADC
import os

class ConversorAD(object):
def __init__(self, pino=0):
if os.uname()[0] == 'esp8266':
self.__adc = ADC(0)
self._ADC_MAX = 1024
else:
self.__adc = ADC(Pin(pino))
self.__adc.atten(ADC.ATTN_11DB)
self._ADC_MAX = 4096

def valor(self):
return self.__adc.read()
Analisando o programa, podemos ver que no MicroPython o conceito de
encapsulamento é implementado pelo uso do caractere _ antes do nome
de atributos e métodos. Quando definimos o nome sem usar o caractere _
esse atributo ou método será público. Por exemplo, o método chamado
valor é público e pode ser acessível por métodos implementados em
qualquer outra classe do programa.
Quanto usamos o caractere _ uma única vez na frente do nome do
atributo ou método, por exemplo o atributo _ADC_MAX, este será protegido e
pode ser acessível por métodos da própria classe ou das subclasses.
Por outro lado, se o caractere _ é usado duas vezes antes do nome do
atributo ou método, por exemplo o atributo __adc, este passa a ser privado,
podendo ser acessado exclusivamente por métodos implementados dentro
da própria classe.
Prosseguindo com a aplicação do conceito de herança, vamos
implementar uma subclasse para representar o potenciômetro. Em ❶
ocorre a herança. Observe que a classe Potenciometro, que está sendo
desenvolvida, terá a classe ConversorAD como superclasse. No método
construtor declarado em ❷ , observe em ❸ que usamos o método super
para executar o construtor da superclasse, que é onde ocorre a
configuração do ADC. Em ❹ é possível notar o uso do método valor e do
atributo ADC_MAX, herdados da superclasse.
z potenciometro.py
from conversorad import ConversorAD

class Potenciometro(ConversorAD): ❶
def __init__(self, pino=0): ❷
super().__init__(pino) ❸
def __mapear(self, x, in_min, in_max, out_min, out_max):
return (x - in_min) * (out_max - out_min) / (in_max - in_min) +
out_min

def escalonar(self, min=0, max=1):


return int(self.__mapear(self.valor(), 0, self._ADC_MAX, min, max))

O projeto a seguir ilustrará o uso da classe Potenciometro.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Potenciômetro de 10k Ohms
1 Protoboard
Cabos de ligação
Após identificar e separar os materiais necessários, realize a montagem da
maneira indicada pela Figura 4.7, caso esteja utilizando o NodeMCU
(ESP8266).
Figura 4.7: Conexões com o NodeMCU (ESP8266).
No NodeMCU (ESP32), a montagem do circuito eletrônico deverá ocorrer
conforme ilustra a Figura 4.8.
Use o utilitário Ampy para copiar os arquivos conversorad.py e
potenciometro.py para o sistema de arquivos do NodeMCU, conforme
mostrado a seguir. Não se esqueça de trocar a porta usada no exemplo
(com6) pela porta na qual o NodeMCU está conectado ao seu computador.
 ampy --port com6 put conversorad.py
ampy --port com6 put potenciometro.py
No Thonny, implemente o seguinte programa (potenciometro-oo.py) que
irá demonstrar o uso das classes criadas anteriormente. Em ❶ ou ❷ é
realizada a criação do objeto de acordo com o modelo usado de
NodeMCU. Caso esteja usando o ESP8266 não use comentário (#) em ❶ e
coloque o comentário em ❷ . Por outro lado, se estiver usando o ESP32,
coloque o comentário em ❶ deixando ❷ sem comentário.

Figura 4.8: Conexões com o NodeMCU (ESP32).


z potenciometro-oo.py
from potenciometro import Potenciometro
from time import sleep

# NodeMCU (ESP8266)
pot = Potenciometro() ❶
# NodeMCU (ESP32)
# pot = Potenciometro(34) ❷
while True:
print (pot.valor(), pot.escalonar(0, 10)) ❸
sleep(0.2)
Ao executar o programa, observe que são mostrados no shell do Thonny
os valores obtidos pelo ADC a partir do método valor e em uma escala de
0 a 10 devido ao uso do método escalonar mostrado em ❸. Note que esses
valores são modificados à medida que o eixo do potenciômetro é girado.
Prosseguindo com a aplicação do conceito de herança, vamos criar uma
subclasse para uso do termístor. Os materiais necessários para a
montagem do circuito eletrônico são especificados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 10k Ohms (marrom, preto, laranja)
1 Termístor NTC 10k Ohms
1 Protoboard
Cabos de ligação
Na Figura 4.9, temos o circuito eletrônico para o NodeMCU (ESP8266).
Figura 4.9: Circuito eletrônico com o NodeMCU (ESP8266).
Em seguida, na Figura 4.10, mostramos o circuito eletrônico para o
NodeMCU (ESP32).
Figura 4.10: Circuito eletrônico com o NodeMCU (ESP32).
Implemente a classe Termistor como sendo uma subclasse de ConversorAD
conforme mostrado em ❶ . No método construtor observe em ❷ que
usamos o método super para executar o construtor da superclasse, que é
onde irá ocorrer a configuração do ADC.
z termistor.py
from conversorad import ConversorAD
from math import log

class Termistor(ConversorAD): ❶
def __init__(self, pino=0):
super().__init__(pino) ❷
def temperatura(self):
tempK = log(10000.0 * (self._ADC_MAX / self.__adc.read() - 1))
tempK = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * tempK
* tempK)) * tempK)
tempC = tempK - 273.15
return tempC
Use o utilitário Ampy para copiar o arquivo criado (termistor.py) e o
arquivo que contém a classe ConversorAD (conversorad.py) para o sistema de
arquivos do NodeMCU, conforme mostrado a seguir. Não se esqueça de
trocar a porta usada no exemplo (com6) pela porta na qual o NodeMCU
está conectado ao seu computador.
 ampy --port com6 put conversorad.py
ampy --port com6 put termistor.py
Em seguida, implemente o programa que irá usar a classe Termistor para
obter os dados de temperatura.
z termistor-oo.py
from termistor import Termistor
from time import sleep

# NodeMCU (ESP8266):
termistor = Termistor() ❶
# NodeMCU (ESP32):
# termistor = Termistor(34) ❷
while True:
print('Temperatura: ', round(termistor.temperatura(), 1), '°C')
sleep(5.0)
Note que em ❶ ou ❷ é realizada a criação do objeto de acordo com o
modelo usado de NodeMCU. Caso esteja usando o ESP8266, não use
comentário (#) em ❶ e coloque o comentário em ❷ . Por outro lado, se
estiver usando o ESP32, coloque o comentário em ❶ deixando ❷ sem
comentário.

Display de LEDs com 7 segmentos


Displays de LEDs com sete segmentos são componentes eletrônicos
bastante comuns e acessíveis. Consistindo basicamente em LEDs
interligados por um pino em comum, são utilizados para exibir,
principalmente, informações numéricas e podem ser do tipo cátodo ou
ânodo comuns. Os materiais necessários para a montagem do projeto
estão relacionados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
1 Display de LEDs com 7 Segmentos (Cátodo ou Ânodo comuns)
1 Protoboard
Cabos de ligação
Existem diversos modelos de display de LEDs com 7 segmentos,
apresentando diferentes disposições dos pinos. Porém, todos possuem
terminais para cada um dos segmentos, que são identificados de “A” até
“G”, e um terminal para o ponto decimal (DP), conforme mostra a
Figura 4.11.

Figura 4.11: Display de LEDs com 7 Segmentos


 Antes de realizar a montagem, consulte o manual relativo ao modelo que você
está usando para identificar a função de cada pino, pois a disposição dos terminais
do seu display pode diferir do que é apresentado nas figuras 4.12, 4.13, 4.14 e 4.15.
Considerando que seu modelo de display pode diferir dos modelos
usados nestes projetos, observe nas quatro figuras apresentadas a seguir as
diferenças de montagem, considerando o modelo do NodeMCU
(ESP8266 ou ESP32) e o tipo do display de LEDs utilizado, ou seja, cátodo
ou ânodo comuns. Na Figura 4.12, mostramos o circuito eletrônico para o
NodeMCU (ESP8266) conectado a um display com cátodo comum.
A Figura 4.13 apresenta a montagem para o NodeMCU (ESP8266)
conectado a um display com ânodo comum.
Na Figura 4.14, temos o circuito eletrônico para o NodeMCU (ESP32)
conectado a um display com cátodo comum.
Por fim, a Figura 4.15 apresenta a montagem para o NodeMCU (ESP32)
conectado a um display com ânodo comum.

Figura 4.12: NodeMCU (ESP8266) e display com cátodo comum.


Figura 4.13: NodeMCU (ESP8266) e display com ânodo comum.
Figura 4.14: NodeMCU (ESP32) e display com cátodo comum.
Vamos passar para a criação da classe Display7Segmentos, que
implementará os atributos e métodos que irão caracterizar um display de
LEDs com 7 segmentos. Observe no método construtor, declarado em ❶ ,
que definimos os atributos privados que irão representar os dígitos
hexadecimais que o display pode exibir (__hexa), a definição do tipo do
display (__tipo), a lista com os pinos do NodeMCU que estão conectados
ao display (__segmentos) e se o ponto decimal está ou não ligado (__ponto).
Na sequência do programa são definidos os métodos da classe que serão
responsáveis por exibir um dígito, apagar o display e controlar o ponto
decimal.
Figura 4.15: NodeMCU (ESP32) e display com ânodo comum.
z display7segmentos.py
from machine import Pin

class Display7Segmentos(object):
CATODO_COMUM = 0
ANODO_COMUM = 1

def __init__(self, pinos, ponto, tipo=CATODO_COMUM): ❶


self.__hexa = [
[ 1, 1, 1, 1, 1, 1, 0 ],
[ 0, 1, 1, 0, 0, 0, 0 ],
[ 1, 1, 0, 1, 1, 0, 1 ],
[ 1, 1, 1, 1, 0, 0, 1 ],
[ 0, 1, 1, 0, 0, 1, 1 ],
[ 1, 0, 1, 1, 0, 1, 1 ],
[ 1, 0, 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 0, 0, 0, 0 ],
[ 1, 1, 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 0, 0, 1, 1 ],
[ 1, 1, 1, 0, 1, 1, 1 ],
[ 0, 0, 1, 1, 1, 1, 1 ],
[ 1, 0, 0, 1, 1, 1, 0 ],
[ 0, 1, 1, 1, 1, 0, 1 ],
[ 1, 0, 0, 1, 1, 1, 1 ],
[ 1, 0, 0, 0, 1, 1, 1 ]
]
self.__tipo = tipo
self.__segmentos = []
for p in pinos:
self.__segmentos.append(Pin(p, Pin.OUT))
self.__ponto = Pin(ponto, Pin.OUT)
self.ponto(False)

def exibir(self, digito):


for i in range(len(self.__segmentos)):
self.__segmentos[i].value(abs(
self.__hexa[digito][i] - self.__tipo))

def apagar(self):
for seg in self.__segmentos:
seg.value(self.__tipo)

def ponto(self, ligado):


self.__ponto.value(abs(ligado - self.__tipo))
Use o utilitário Ampy para copiar o arquivo display7segmentos.py para o
sistema de arquivos do NodeMCU, conforme mostrado a seguir. Não se
esqueça de trocar a porta usada no exemplo (com6) pela porta na qual o
NodeMCU está conectado ao seu computador.
 ampy --port com6 put display7segmentos.py
Em seguida, implemente o programa que irá usar a classe
Display7Segmentos para exibir os dígitos hexadecimais entre 0 e F e, no
final, apagar o conteúdo exibido no display. Não se esqueça de que em ❶
ou ❷ você deve utilizar a criação do objeto de acordo com seu modelo de
NodeMCU (ESP8266 ou ESP32), comentando o trecho de programa que
não é aplicável. Também identifique corretamente o tipo de display usado,
ou seja, cátodo ou ânodo comuns.
z display-1-oo.py
from display7segmentos import Display7Segmentos
from time import sleep

# NodeMCU (ESP8266):
ds = Display7Segmentos([15, 13, 12, 14, 2, 0, 4], 5,
Display7Segmentos.CATODO_COMUM) ❶
# NodeMCU (ESP32):
# ds = Display7Segmentos([15, 2, 4, 5, 18, 19, 21], 22,
Display7Segmentos.CATODO_COMUM) ❷
for i in range(16):
ds.exibir(i)
sleep(1.0)
ds.apagar()
Neste projeto, vamos unir os conceitos abordados sobre o display de
LEDs com sete segmentos e a chave táctil para criar um contador
hexadecimal no qual o dígito a ser exibido é alterado sempre que a chave
táctil é pressionada. Na Figura 4.16, mostraremos o circuito eletrônico
considerando o uso do NodeMCU (ESP8266) e um display com cátodo
comum. Porém, como já apresentamos anteriormente, o projeto pode ser
facilmente alterado para funcionar com o NodeMCU (ESP32) e outro tipo
de display.
Use o Ampy para copiar os arquivos necessários para o NodeMCU,
conforme mostrado a seguir. Não se esqueça de trocar a porta usada no
exemplo (com6) pela porta na qual o NodeMCU está conectado ao seu
computador.
 ampy --port com6 put display7segmentos.py
ampy --port com6 put botao.py
O programa em MicroPython irá inicialmente criar os objetos para o
display e para o botão. Perceba que em ❶ e ❷ ou ❸ e ❹ você deve utilizar
a criação do objeto de acordo com seu modelo de NodeMCU (ESP8266
ou ESP32), o tipo de display de LED e o terminal no qual o botão foi
conectado. Em relação ao objeto que representa a chave táctil, iremos usar
em ❺ o método estado para obter o valor que será incrementado cada vez
que a chave táctil for pressionada.

Figura 4.16: NodeMCU (ESP8266) e display com cátodo comum.


z display-2-oo.py
from display7segmentos import Display7Segmentos
from botao import Botao
from time import sleep

# NodeMCU (ESP8266):
ds = Display7Segmentos([15, 13, 12, 14, 2, 0, 4], 5,
Display7Segmentos.CATODO_COMUM) ❶
botao = Botao(16) ❷
# NodeMCU (ESP32):
# ds = Display7Segmentos([15, 2, 4, 5, 18, 19, 21], 22,
Display7Segmentos.CATODO_COMUM) ❸
# botao = Botao(23) ❹
try:
while True:
ds.exibir(botao.estado(16)) ❺
except KeyboardInterrupt:
ds.apagar()
Outra possibilidade é apresentada no próximo projeto, em que vamos
unir os conceitos abordados sobre o display de LEDs com 7 segmentos e
o potenciômetro para criar um contador decimal (0 até 9) no qual o dígito
a ser exibido é definido em função da posição do eixo do potenciômetro.
Na Figura 4.17, iremos mostrar a montagem do circuito eletrônico
considerando o uso do NodeMCU (ESP8266) e um display com cátodo
comum. Porém, o projeto pode ser facilmente alterado para funcionar
com o NodeMCU (ESP32) e outro tipo de display.
Figura 4.17: NodeMCU (ESP8266) e display com cátodo comum.
Use o Ampy para copiar os arquivos necessários para o NodeMCU,
conforme mostramos a seguir. Não se esqueça de trocar a porta usada no
exemplo (com6) pela porta na qual o NodeMCU está conectado ao seu
computador.
 ampy --port com6 put display7segmentos.py
ampy --port com6 put conversorad.py
ampy --port com6 put potenciometro.py
O programa, que será implementado no Thonny, irá inicialmente criar os
objetos para o display e para o potenciômetro. Perceba que em ❶ , ❷ , ❸ e
❹ você deve utilizar a criação do objeto de acordo com seu modelo de
NodeMCU (ESP8266 ou ESP32) e tipo de display de LED. Em relação ao
objeto que representa o potenciômetro, note em ❺ que vamos usar o
método escalonar para obter o valor que será incrementado ou
decrementado conforme o giro do eixo.
z display-3-oo.py
from display7segmentos import Display7Segmentos
from potenciometro import Potenciometro
from time import sleep

# NodeMCU (ESP8266):
ds = Display7Segmentos([15, 13, 12, 14, 2, 0, 4], 5,
Display7Segmentos.CATODO_COMUM) ❶
pot = Potenciometro() ❷
# NodeMCU (ESP32):
# ds = Display7Segmentos([15, 2, 4, 5, 18, 19, 21], 22,
Display7Segmentos.CATODO_COMUM) ❸
# pot = Potenciometro(32) ❹
try:
while True:
ds.exibir(pot.escalonar(0, 9)) ❺
sleep(0.1)
except KeyboardInterrupt:
ds.apagar()
capítulo 5

Comunicação em rede

No cenário de aplicações para IoT é imprescindível a comunicação em


rede. O NodeMCU apresenta vantagem sobre vários outros sistemas
microcontrolados ao oferecer conexão Wi-Fi integrada na própria placa,
reduzindo, dessa forma, os custos, pois não é necessário adquirir um
módulo de comunicação em rede. Além disso, reduz a complexidade dos
circuitos eletrônicos que precisam ser montados em um projeto de
aplicação para IoT, pois não é necessário ter preocupação com a ligação
física do módulo de rede ao restante do projeto.

Wi-Fi integrado
Uma das melhores características do NodeMCU é possuir Wi-Fi
integrado. A partir dele é possível atuar como um access point, em que
outros dispositivos podem se conectar ou atuar como cliente se conectado
a um access point já existente. Não é preciso realizar qualquer montagem
de circuito eletrônico para os comandos mostrados a seguir, visto que
vamos explorar o Wi-Fi integrado utilizando o próprio shell do
NodeMCU e, posteriormente, nos projetos seguintes vamos integrando os
conceitos abordados aplicando-os a projetos completos.
A biblioteca network implementa o conjunto de funções relativas à rede.
Então o primeiro passo consiste em carregá-la a partir do uso da
instrução import.
z import network
Em seguida, é importante definir como o NodeMCU irá atuar, ou seja,
como estação (network.STA_IF).
z wifi = network.WLAN(network.STA_IF)
Ou como um access point (network.AP_IF).
z wifi = network.WLAN(network.AP_IF)
Para o exemplo que vamos desenvolver na sequência, configure como
estação. Em primeiro lugar, ative a interface de comunicação Wi-Fi, use o
método active e depois o método scan irá identificar os access points que
estão disponíveis.
z wifi.active(True)
wifi.scan()
Na Figura 5.1, mostramos um exemplo do resultado exibido após a
execução do método scan.

Figura 5.1: Access point disponíveis.


A conexão com um access point é realizada pelo método connect, e a
string ap deve conter o nome do access point e a string senha deve conter a
senha para aceso. O método ifconfig irá exibir os detalhes da conexão.
z wifi.connect('ap', 'senha')
wifi.ifconfig()

Soquetes
Podemos definir, de maneira simplista, que um soquete é uma forma de
estabelecer uma comunicação regrada entre dois aplicativos interligados
por uma rede. Um exemplo bastante comum para entendermos o conceito
de soquete é pensarmos no modelo de comunicação entre um servidor e
um navegador web, como quando requisitamos uma página dentro de um
website. Em programação, um soquete é uma abstração dos serviços e
protocolos utilizados para a comunicação entre dois ou mais sistemas.
Com o intuito de visualizarmos o conceito na prática, vamos implementar
em MicroPython um servidor web (HTTP) e depois usamos um
navegador para enviar uma requisição e, em seguida, receber os dados
enviados pelo servidor.
z http-ola.py
import network
import usocket as socket
import gc
gc.collect()

html = """<!DOCTYPE html>


<html>
<head>
<title>Olá</title>
<meta charset="utf-8">
</head>
<body>
<h1>Olá!</h1>
</body>
</html>
""" ❶
estacao = network.WLAN(network.STA_IF) ❷
estacao.active(True) ❸
estacao.connect('ap', 'senha') ❹
while estacao.isconnected() == False:
pass
print('Conexao realizada.')
print(estacao.ifconfig())

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ❺
s.bind(('', 80)) ❻
s.listen(5) ❼
try:
while True: ❽
conexao, endereco = s.accept()
print('Conexao de %s' % str(endereco))
requisicao = conexao.recv(1024)
requisicao = str(requisicao)
print('Conteudo = %s' % requisicao)
conexao.send('HTTP/1.1 200 OK\n') ❾
conexao.send('Content-Type: text/html\n') ❿
conexao.send('Connection: close\n\n') ⓫
conexao.sendall(html) ⓬
conexao.close() ⓭
except KeyboardInterrupt:
s.close()
estacao.active(False)
Analisando o código-fonte, em ❶ definimos a variável que irá conter a
página HTML que será enviada pelo servidor.
 Uma ótima referência para conhecer mais sobre HTML é a Mozilla Developer
Network, acesse: https://developer.mozilla.org/pt-BR/docs/Web/HTML
Em seguida, entre em ❷ , ❸ e ❹ para realizarmos a conexão a um access
point, conforme já detalhamos anteriormente.
Em ❺ , criamos um soquete e, em ❻ , realizamos a ligação do soquete à
porta TCP 80, que é a porta padrão usada pelo protocolo HTTP. Em ❼ ,
colocamos a porta associada do soquete em modo de escuta, em que o
parâmetro passado para o método listen, que neste exemplo é 5, indica o
máximo de solicitações de conexões simultâneas.
Em ❽ , o programa entra em um laço, em que aceita pedidos de conexão,
processa a requisição realizada pelo cliente e envia o conteúdo. O
conteúdo está dividido em duas partes, então em ❾ , ❿ e ⓫ é enviado o
cabeçalho e, posteriormente, em ⓬ , as instruções HTML. Em ⓭ , a
conexão com o cliente é encerrada, mas note que o soquete permanece
ativo, aguardando novas conexões.
Após executar o programa no Thonny, aguarde o processo de conexão ao
access point. Em seguida, o endereço atribuído ao NodeMCU será
exibido no shell, conforme é possível notar na Figura 5.2.
Figura 5.2: Endereço IP atribuído ao NodeMCU.
Na sequência, digite o endereço IP do NodeMCU no navegador web de
sua preferência e a página deverá ser carregada (Figura 5.3).

Figura 5.3: Página enviada pelo servidor.

Controle de dispositivos pela internet


Comece identificando e separando os materiais relacionados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
1 LED (qualquer cor)
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 5.4, caso
esteja utilizando o NodeMCU (ESP8266).
Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 5.5
como referência.
No Thonny, implemente o programa a seguir (http-led-1.py). Observe
que, basicamente, é uma implementação do servidor HTTP desenvolvido
anteriormente, porém, em ❶ adicionamos dois botões na página HTML.
Posteriormente, em ❷ , ❸ , ❹ e ❺ identificamos a requisição enviada ao
servidor, isto é, qual botão foi pressionado e acendemos ou apagamos o
LED.

Figura 5.4: Circuito eletrônico (NodeMCU-ESP8266).


z http-led-1.py
import network
import usocket as socket
import machine
import gc
gc.collect()

html = """<!DOCTYPE html>


<html>
<head>
<title>NodeMCU LED</title>
<meta charset="utf-8">
</head>
<body>
<form>
<h1>LED:</h1>
<p align="center">
<button name="LED" value="ON"
type="submit">Ligar</button>&nbsp;&nbsp; ❶
<button name="LED" value="OFF" type="submit">Desligar</button>
<br />❶
</p>
</form>
</body>
</html>
"""

LED = machine.Pin(5, machine.Pin.OUT)

estacao = network.WLAN(network.STA_IF)
estacao.active(True)
estacao.connect('ap', 'senha')
while estacao.isconnected() == False:
pass
print('Conexao realizada.')
print(estacao.ifconfig())

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)

try:
while True:
conexao, endereco = s.accept()
print("Conexao de %s" % str(endereco))
requisicao = conexao.recv(1024)
requisicao = str(requisicao)
print("Conteudo = %s" % requisicao)
if requisicao.find('GET /?LED=ON') != -1: ❷
LED.value(1) ❸
if requisicao.find('GET /?LED=OFF') != -1: ❹
LED.value(0) ❺
conexao.send('HTTP/1.1 200 OK\n')
conexao.send('Content-Type: text/html\n')
conexao.send('Connection: close\n\n')
conexao.sendall(html)
conexao.close()
except KeyboardInterrupt:
s.close()
estacao.active(False)
Figura 5.5: Circuito eletrônico (NodeMCU-ESP32).
Execute o programa no Thonny e acesse pelo navegador o endereço IP do
NodeMCU. Deverá ser mostrada uma página similar à da Figura 5.6.
Clicando nos botões Ligar e Desligar, o LED deve acender ou apagar.
Figura 5.6: Página para controle do LED.
Quando desenvolvemos aplicações para a Internet, devemos considerar a
vasta gama de dispositivos que hoje acessam a rede. Vamos usar uma
biblioteca de funções JavaScript muito utilizada chamada jQuery. Foi
criada com o objetivo de simplificar a seleção de elementos, a criação de
efeitos visuais e a manipulação de eventos. É uma ferramenta bastante
versátil, possibilitando inclusive a criação de plugins.
Além da jQuery, usaremos o Bootstrap, que é um framework HTML, CSS
e JavaScript para desenvolvimento de interfaces responsivas para
aplicações Internet e que, dessa forma, irão funcionar adequadamente
tanto em computadores como em dispositivos móveis.
Esse programa implementará um servidor HTTP que irá obter uma
página HTML, gravada no sistema de arquivos do NodeMCU, e enviará
para o navegador. Essa página usa o Bootstrap para criar uma interface
visualmente mais sofisticada e responsiva.
 O foco deste livro é o MicroPython, mas conhecer HTML, CSS, JavaScript, AJAX e
frameworks, como jQuery e Bootstrap, ajuda a criar aplicações IoT amigáveis e
robustas. Há muitos tutoriais na Internet que abordam essas tecnologias.
O circuito eletrônico é o mesmo usado no projeto anterior, ou seja, um
LED conectado ao pino GPIO5 do NodeMCU. A página HTML que será
usada no projeto é mostrada a seguir.
 http-led-bootstrap.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>NodeMCU IoT</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-
scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/
bootstrap/4.0.0-beta.2/css/bootstrap.min.css">
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.mi
n.js">
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.6/umd/
popper.min.js">
</script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-
beta.2/js/bootstrap.min.js">
</script>
<script>
$(document).ready(function(){
$("#on").click(function(){
$.ajax({url: "/led/1", success: function(result){
$('#on').removeClass('btn-success').addClass('btn-
default');
$('#off').removeClass('btn-default').addClass('btn-
danger');
}});❶
});

$("#off").click(function(){
$.ajax({url: "/led/0", success: function(result){
$('#on').removeClass('btn-default').addClass('btn-
success');
$('#off').removeClass('btn-danger').addClass('btn-
default');
}}); ❷
});
});
</script>
</head>
<body>
<div class="container">
<h1>NodeMCU IoT</h1>
Controle do LED<br /><br />
<div class="btn-group">
<button id="on" type="button" class="btn btn-success btn-
lg">Acender
</button><br><br>
<button id="off" type="button" class="btn btn-default btn-
lg">Apagar
</button>
</div>
</div>
</body>
</html>
Observe em ❶ e ❷ que, no evento clique dos botões Acender e Apagar, usamos
requisições AJAX (Asynchronous Javascript and XML).
Podemos entender que AJAX é uma forma de realizar uma requisição ao
servidor em que este apenas retornará dados, e não uma página HTML
completa com marcadores e conteúdo, muito usado em aplicações como
redes sociais na alimentação de “feeds”, por exemplo. Dessa maneira, é
possível carregar apenas uma parte de uma página, aumentando o
desempenho e possibilitando uma maior interação. O jQuery facilita a
implementação de AJAX, oferecendo um método específico para isso.
Após criar o arquivo HTML, use o utilitário Ampy para copiá-lo para o
sistema de arquivos do NodeMCU, conforme mostrado a seguir. Apenas
tenha a precaução de trocar a porta usada no exemplo (com6) pela porta na
qual o NodeMCU está conectado ao seu computador.
 ampy --port com6 put http-led-bootstrap.html
No Thonny, implemente o código-fonte do servidor HTML. Note que ele
é muito similar ao utilizado no projeto anterior. A principal diferença está
na função obter_arquivo, declarada em ❶ . Essa função obtém e retorna o
conteúdo de um arquivo existente no sistema de arquivos do NodeMCU.
Observe em ❷
que usamos a função para obter o conteúdo da página
http-led-bootstrap.html, desenvolvida anteriormente e copiada para o
NodeMCU pelo do Ampy.
z http-led-2.py
import network
import usocket as socket
import machine
import gc
gc.collect()

LED = machine.Pin(5, machine.Pin.OUT)

def obter_arquivo(arquivo): ❶
conteudo = ''
a = open(arquivo, 'rb')
conteudo = a.read()
a.close()
return conteudo

estacao = network.WLAN(network.STA_IF)
estacao.active(True)
estacao.connect('ap', 'senha')
while estacao.isconnected() == False:
pass
print('Conexao realizada.')
print(estacao.ifconfig())

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)

try:
while True:
conexao, endereco = s.accept()
print('Conexao de %s' % str(endereco))
requisicao = conexao.recv(1024)
requisicao = str(requisicao)
print('Conteudo = %s' % requisicao)
if requisicao.find('/led/1') != -1:
print('Acender')
LED.value(1)
elif requisicao.find('/led/0') != -1:
print('Apagar')
LED.value(0)
else:
LED.value(0)
html = obter_arquivo('http-led-bootstrap.html') ❷
conexao.send('HTTP/1.1 200 OK\n')
conexao.send('Content-Type: text/html\n')
conexao.send('Connection: close\n\n')
conexao.sendall(html)
conexao.close()
except KeyboardInterrupt:
s.close()
estacao.active(False)
Após executar o arquivo no Thonny, use o navegador para acessar o
servidor pelo endereço IP que foi atribuído ao NodeMCU (Figura 5.7).

Figura 5.7: Página com recursos do Bootstrap.

Recepção de dados da internet


Este projeto irá demonstrar como podemos usar serviços de redes para
obter dados que estão na Internet. Vamos usar o WorldTimeAPI, que
consiste em um web service que retorna as informações de data e hora,
em formato JSON, de uma determinada região. Um web service é uma
solução para integrar e criar meios de comunicação entre aplicações
diferentes.
 JSON (JavaScript Object Notation – Notação de Objetos JavaScript) é uma
notação leve para troca de dados. É de fácil compreensão, leitura e escrita. Adota
formato texto e é independente de linguagem.
Não é preciso realizar qualquer montagem de circuito eletrônico para o
NodeMCU, pois apenas usaremos o comando print para exibir as
informações no shell do ambiente de desenvolvimento Thonny. Dessa
maneira, apenas implemente o programa apresentado a seguir.
z world-time-api.py
import network
import urequests
import utime
from machine import RTC, Pin

rtc = RTC()

estacao = network.WLAN(network.STA_IF)
estacao.active(True)
estacao.connect('ap', 'senha')
while estacao.isconnected() == False:
pass
print('Conexao realizada.')
print(estacao.ifconfig())

data_hora_atual = utime.ticks_ms()
url = "http://worldtimeapi.org/api/timezone/
America/Sao_Paulo"
resposta = urequests.get(url) ❶
if resposta.status_code == 200:
print("JSON:", resposta.text)
json = resposta.json() ❷
agora = str(json["datetime"]) ❸
ano = int(agora[0:4]) ❹
mês = int(agora[5:7]) ❺
dia = int(agora[8:10])❻
hora = int(agora[11:13]) ❼
minuto = int(agora[14:16]) ❽
segundo = int(agora[17:19]) ❾
subsegundo = int(round(int(agora[20:26]) / 10000)) ❿
# Atualizar o RTC do NodeMCU
rtc.datetime((ano, mes, dia, 0, hora, minuto, segundo, subsegundo))

data_hora_atual = utime.ticks_ms()
print('RTC atualizado.')
else:
data_hora_atual = utime.ticks_ms()

# Formatar e exibir da data


data = "{2:02d}/{1:02d}/{0:4d}".format(
*rtc.datetime()) ⓬
horario = "{4:02d}:{5:02d}:{6:02d}".format(*rtc.datetime())
print ('Data:', data, 'Hora:', horario) ⓭
estacao.active(False)
Em ❶, realizamos a requisição ao servidor que foi especificado na variável
url. Em ❷ , a resposta enviada pelo servidor é passada por um parser
JSON. A seguir mostramos um exemplo de como o serviço irá enviar as
informações de data e hora.
 {
"week_number":16,
"utc_offset":"-3:00",
"utc_datetime":"2020-04-19T13:38:37.614614+00:00",
"unixtime":1587303517,
"timezone":"America/Sao_Paulo",
"raw_offset":-10800,
"dst_until":null,
"dst_offset":0,
"dst_from":null,
"dst":false,
"day_of_year":110,
"day_of_week":0,
"datetime":"2020-04-19T10:38:37.614614-03:00",
"client_ip":"189.103.201.131",
"abbreviation":"-03"
}
Conforme podemos notar, um objeto JSON consiste em uma coleção de
pares (nome e valor), o que pode caracterizar um objeto em si, registro,
dicionário ou array associativo. Um item da coleção é delimitado por
chaves. Cada nome é seguido pelo caractere ‘:’ (dois pontos) e, em
seguida, temos o valor. Como é possível observar, vários pares
(nome/valor) devem ser separados por vírgula.
No caso do nosso programa, nos interessa o valor do item que tem a
chave datetime, pois ali encontramos a informação da data e hora atuais.
Voltando ao programa em MicroPython, em ❸ a variável agora irá receber
essas informações e em ❹ , ❺ , ❻ , ❼ , ❽ , ❾ e ❿ aplicamos o conceito de
substring para obter separadamente cada um dos componentes da data e
hora.
Em ⓫ , atualizamos o relógio interno (RTC) do NodeMCU e, em ⓬ e ⓭ ,
formatamos e exibimos a data e hora no padrão adotado no Brasil. Um
exemplo das informações exibidas no shell, após a execução do programa,
é mostrado na Figura 5.8.

Figura 5.8: Data e hora.

Envio de dados para uma página web


O objetivo deste projeto é obter a temperatura, que será lida de um
Termístor, e enviar para uma página web. Os materiais necessários estão
especificados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 10k Ohms (marrom, preto, laranja)
1 Termístor NTC 10k Ohms
1 Protoboard
Cabos de ligação
Na Figura 5.9, temos o circuito eletrônico para o NodeMCU (ESP8266).

Figura 5.9: Circuito eletrônico com o NodeMCU (ESP8266).


Na Figura 5.10, mostramos o circuito eletrônico para o NodeMCU
(ESP32).
A página HTML que será usada no projeto é mostrada a seguir (http-
termistor.html), sendo utilizado jQuery e Bootstrap em sua construção.
Note que em ❶ utilizamos o intervalo de tempo de 60.000 milissegundos,
isto é, 1 minuto para atualização de página. Veja em ❷ que vamos precisar
de um arquivo em formato PNG, que represente a imagem de um
termômetro; o arquivo deve ser nomeado como termometro.png.

Figura 5.10: Circuito eletrônico com o NodeMCU (ESP32).


 http-termistor.html
<!DOCTYPE html>
<html>
<head>
<title>Temperatura</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-
scale=1.0">
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.
min.css">
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.mi
n.js">
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/
popper.min.js">
</script>
<script
src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootst
rap.min.js">
</script>
<script type="application/javascript">
function atualizar() {
$("#temperatura").html('...');
$.ajax({
type: "POST",
contentType: "text/plain",
url: window.location + "obter/temperatura",
success: function(dados) {
$("#temperatura").html(dados);
window.setTimeout(atualizar, 60000);❶
},
erro: function(erro) {
console.log("Erro: " + erro);
}
});
}

$(document).ready(function() {
atualizar();
});
</script>
</head>
<body>
<div class="container">
<div class="jumbotron">
<h1>Temperatura</h1>
</div>
<h1>
<img src="images/termometro.png" align="middle"> ❷
<span id="temperatura"></span>°C
</h1>
</div>
</body>
</html>
Em seguida, use o utilitário Ampy para copiar os arquivos http-
termistor.html e termometro.png para o sistema de arquivos do NodeMCU,
conforme mostrado a seguir. Apenas tenha a precaução de trocar a porta
usada no exemplo (com6) pela porta na qual o NodeMCU está conectado
ao seu computador.
 ampy --port com6 put http-termistor.html
ampy --port com6 put termometro.png
No ambiente de desenvolvimento Thonny, implemente o código-fonte
apresentado a seguir.
z http-termistor.py
import network
import usocket as socket
from machine import ADC, Pin
from math import log
import os
import gc
gc.collect()

if os.uname()[0] == 'esp8266': ❶
adc = ADC(0) ❷
else: ❸
adc = ADC(Pin(34)) ❹
adc.atten(ADC.ATTN_11DB) ❺
def obter_temperatura(termistor):
if os.uname()[0] == 'esp8266':
fator = 1024.0
else:
fator = 4096.0
tempK = log(10000.0 * (fator / termistor - 1))
tempK = 1 / (0.001129148 + (0.000234125
+ (0.0000000876741 * tempK * tempK )) * tempK)
tempC = tempK - 273.15
return tempC

def obter_arquivo(arquivo):
conteudo = ''
a = open(arquivo, 'rb')
conteudo = a.read()
a.close()
return conteudo

estacao = network.WLAN(network.STA_IF)
estacao.active(True)
estacao.connect('CasaClaudio1', 'c1l2v6o8')
while estacao.isconnected() == False:
pass
print('Conexao realizada.')
print(estacao.ifconfig())

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)

try:
while True:
conexao, endereco = s.accept()
print('Conexao de %s' % str(endereco))
requisicao = conexao.recv(1024) ❻
requisicao = str(requisicao)
print('Conteudo = %s' % requisicao)
if requisicao.find('obter/temperatura') != -1:
temperatura = obter_temperatura(adc.read()) ❼
html = str(round(temperatura, 1))
elif requisicao.find('/termometro.png') != -1:
html = obter_arquivo('termometro.png')
elif requisicao.find('/') != -1:
html = obter_arquivo('http-termistor.html')
conexao.send('HTTP/1.1 200 OK\n')
conexao.send('Content-Type: text/html\n')
conexao.send('Connection: close\n\n')
conexao.sendall(html) ❽
conexao.close()
except KeyboardInterrupt:
s.close()
estacao.active(False)
Após executar o programa no Thonny, aguarde o processo de conexão ao
access point. Em seguida, o endereço atribuído ao NodeMCU será
exibido no shell, conforme é possível notar na Figura 5.11.

Figura 5.11: Endereço IP atribuído ao NodeMCU.


Na sequência, digite o endereço IP do NodeMCU no navegador web de
sua preferência e a página será carregada, conforme ilustra a Figura 5.12.
Figura 5.12: Página web exibindo a temperatura.
O programa consiste basicamente no servidor web já usado em projetos
anteriores, porém em ❶ , ❷ , ❸ , ❹ e ❺ acrescentamos a definição do pino
do ADC onde o termístor está conectado. Observe que usamos em ❶ o
método uname para determinar o modelo do NodeMCU que está
executando o programa e, com isso, realizar a seleção do código-fonte
específico de cada modelo (ESP8266 ou ESP32).
Em ❻ , recebemos a requisição do cliente (navegador), em ❼ obtemos o
valor do termístor e, em ❽ , enviamos para o cliente, para que a
temperatura seja atualizada na janela do navegador.

Serviços de rede
No programa a seguir, vamos nos conectar a um access point, para ter
acesso à Internet, obter a data e hora de um servidor NTP (Network Time
Protocol) e sincronizar o relógio interno do NodeMCU (RTC).
 O NTP é um protocolo para sincronização dos relógios dos computadores
baseado no protocolo TCP/IP, pela porta 123. É utilizado para sincronizar os
relógios de computadores, smartphones ou qualquer outro dispositivo que se
conecte à rede.
Não é preciso realizar qualquer montagem de circuito eletrônico para o
NodeMCU, pois apenas usaremos o comando print para exibir as
informações no shell do ambiente de desenvolvimento Thonny. Assim
sendo, implemente o programa apresentado a seguir.
z ntp-data-hora-1.py
import network
import ntptime
import machine
import time

wifi = network.WLAN(network.STA_IF) ❶
wifi.active(True) ❷
wifi.connect('ap', 'senha') ❸
while wifi.isconnected() == False:
machine.idle()
print('Conexao realizada:', wifi.ifconfig())
ntptime.settime() ❹
agora = time.localtime() ❺
print ('Data e hora do servidor NTP:', agora)
wifi.active(False)
Observe que em ❶ , ❷ e ❸ realizamos a conexão com um access point.
Em ❹ , ajustamos o Relógio de Tempo Real (Real Time Clock – RTC) do
NodeMCU com as informações obtidas do servidor NTP. Em seguida, em
❺, obtemos as informações de data e hora usando a função localtime.
 A biblioteca ntptime retorna o horário no padrão UTC; dessa forma, é necessário
realizar o ajuste de fuso horário. Por exemplo, para o horário de São Paulo,
devemos subtrair 3 horas (America/Sao_Paulo: UTC/GMT -03:00).
Note que a função localtime retorna uma lista contendo os dados, por
exemplo (2020, 4, 18, 19, 26, 59, 5, 109). Dessa forma, podemos
manipular individualmente os elementos da lista para exibi-los
formatados para o padrão usado no Brasil, como mostra o programa a
seguir.
z ntp-data-hora-2.py
import network
import ntptime
import machine
import time

wifi = network.WLAN(network.STA_IF)
wifi.active(True)
wifi.connect('ap', 'senha')
while wifi.isconnected() == False:
machine.idle()
print('Conexao realizada:', wifi.ifconfig())
ntptime.settime()
agora = time.localtime()
print ('Data: %d/%02d/%d' % (agora[2], agora[1], agora[0])) ❶
print ('Hora: %d:%02d' % (agora[3] - 3, agora[4])) ❷
wifi.active(False)
Em ❶ , exibimos o dia, mês e ano, utilizando os elementos da lista com
índice 2, 1 e 0, respectivamente. Enquanto em ❷ mostramos hora e
minuto, usando os elementos da lista com índice 3 e 4. Note também que
realizamos o ajuste do fuso horário para São Paulo, isto é, subtraímos 3
do elemento da lista com índice 3.
capítulo 6

Displays

Nos projetos anteriores, usamos a função print para exibir no shell


informações obtidas durante a execução dos programas. Porém, em
aplicações reais, na grande maioria das vezes, o NodeMCU irá executar os
programas sem estar conectado a um computador. Nesse contexto, os
displays são uma forma bastante prática, compacta e econômica para
realizar a exibição de dados.

Display de cristal líquido (LCD) I2C


Os LCD (Displays de Cristal Líquido) são bastante populares e
amplamente utilizados. São ideais quando precisamos exibir poucas
informações alfanuméricas. O modelo mais comum é o de 16 colunas por
2 linhas. Ele pode ser conectado diretamente à GPIO mas, nesse caso, irá
usar a maioria dos pinos disponíveis no NodeMCU. Por isso,
normalmente conectamos os LCDs ao NodeMCU usando o barramento
serial I²C.
 I²C é um barramento serial usado para conectar módulos de baixa velocidade a
sistemas microcontrolados. Apresenta um barramento com um sinal de clock
(SCL) e uma linha para dados (SDA).
Identifique os materiais necessários lembrando que, para os projetos que
desenvolveremos na sequência deste capítulo, usaremos sempre o LCD
com barramento serial I2C.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Display LCD 1602 I2C
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 6.1, caso
esteja utilizando o NodeMCU (ESP8266).

Figura 6.1: Ligação do LCD (NodeMCU-ESP8266).


Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 6.2
como referência.
O programa apresentado a seguir (i2c-scan.py) irá identificar o endereço
dos dispositivos I2C conectados ao NodeMCU e deve ser implementado
no Thonny.
z i2c-scan.py
# Conexões
# LCD -> ESP8266/ESP32
# VCC -> VIN
# GND -> GND
# SDA -> GPIO5
# SCL -> GPIO4

from machine import I2C, Pin


from os import uname

i2c = I2C(sda=Pin(5), scl=Pin(4))

print('Pesquisando o barramento I2C do', uname()[0], '...') ❶


dispositivos = i2c.scan()

if len(dispositivos) == 0:
print("Nenhum dispositivo encontrado!")
else:
print('Dispositivos encontrados:', len(dispositivos))
for dispositivo in dispositivos:
print("Endereço:", hex(dispositivo))
Figura 6.2: Ligação do LCD (NodeMCU-ESP32).
Após montar o circuito eletrônico, conectar o NodeMCU à porta USB do
computador e executar o programa, anote o endereço que foi encontrado.
Por exemplo, na Figura 6.3 podemos ver que o LCD I2C possui o endereço
0x27, sendo que o prefixo 0x indica que esse valor foi apresentado em
notação hexadecimal.

Figura 6.3: Dispositivos I2C conectados.


Note também, no mesmo programa, que em ❶ usamos o retorno da
função uname para identificar o modelo de NodeMCU no qual o programa
foi executado.
Dispositivos que apresentam princípios de funcionamento mais
complexos, como é o caso do LCD, normalmente possuem bibliotecas que
facilitam a sua programação.
 Nos projetos deste livro, vamos adotar a biblioteca mp_i2c_lcd1602 que está
disponível em https://github.com/micropython-Chinese-Community/mpy-
lib/tree/master/lcd/I2C_LCD1602. Faça o download para o seu computador do
arquivo mp_i2c_lcd1602.py.
O arquivo mp_i2c_lcd1602.py, que implementa a biblioteca para o LCD
I2C, deverá ser copiado para o sistema de arquivos do NodeMCU. Para
isso, vamos usar o utilitário Ampy, conforme o exemplo mostrado a seguir,
lembrando que o comando deve ser executado no shell do sistema
operacional do seu computador. Apenas tenha a precaução de trocar a
porta usada no exemplo (com6) pela porta na qual o NodeMCU está
conectado ao seu computador.
 ampy --port com6 put mp_i2c_lcd1602.py
Mantendo a montagem do circuito eletrônico, copiada a biblioteca para o
NodeMCU e uma vez identificado o endereço do LCD, vamos desenvolver
o próximo programa, que, basicamente, ilustra as operações básicas que
podemos realizar, como posicionar e exibir um texto e apagar o texto.
z lcd-i2c-ola.py
# Conexões
# LCD -> ESP8266/ESP32
# VCC -> VIN
# GND -> GND
# SDA -> GPIO5
# SCL -> GPIO4

from machine import I2C, Pin


from mp_i2c_lcd1602 import LCD1602
from time import sleep
i2c = I2C(sda=Pin(5), scl=Pin(4)) ❶
LCD = LCD1602(i2c, 0x27) ❷
LCD.puts("Ola!", 0, 0) ❸
sleep(5.0)
LCD.clear() ❹
LCD.backlight(False) ❺
Analisando o código-fonte, em ❶ inicializamos a comunicação I2C,
enquanto em ❷ criamos o objeto para o LCD indicando o barramento a
ser usado e o endereço do dispositivo.
Em ❸ , o método puts irá exibir um texto na tela na coluna e linhas
indicadas. As colunas são numeradas de 0 a 15 e as linhas são 0 e 1. Em ❹,
o método clear irá apagar o conteúdo do LCD e, em ❺ , o método
backlight desliga a iluminação de fundo do LCD para reduzir o consumo
de energia.
Ainda sobre o método puts, por exemplo, para exibir o texto na coluna 6 e
na segunda linha do display, teríamos a seguinte instrução.
z LCD.puts("Ola!", 6, 1)

Termômetro digital – versão 1


Neste projeto, vamos utilizar o termístor para obter a temperatura
ambiente e exibi-la no LCD I2C. Identifique os materiais necessários.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Display LCD 1602 I2C
1 Resistor de 10k Ohms (marrom, preto, laranja)
1 Termístor NTC 10k Ohms
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 6.4, caso
esteja utilizando o NodeMCU (ESP8266).

Figura 6.4: Circuito eletrônico (NodeMCU-ESP8266).


Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 6.5
como referência.
O programa é apresentado a seguir (termistor-lcd-i2c.py) e deve ser
implementado no Thonny, sendo importante salientar que o programa
funcionará adequadamente nos dois modelos de NodeMCU. Observe em
❶ e depois em ❷ que utilizamos a função uname para identificar e
selecionar a parte específica do código-fonte, relacionada ao ADC, que é
requerida para cada modelo de NodeMCU.
z termistor-lcd-i2c.py
# Conexões
# LCD -> ESP8266/ESP32
# VCC -> VIN
# GND -> GND
# SDA -> GPIO5
# SCL -> GPIO4

from machine import Pin, ADC, I2C


from time import sleep
from math import log
from mp_i2c_lcd1602 import LCD1602
from os import uname

def obterTemperatura(termistor):
if uname()[0] == 'esp8266': ❶
fator = 1024.0
else:
fator = 4096.0
tempK = log(10000.0 * (fator / termistor - 1))
tempK = 1 / (0.001129148 + (0.000234125
+ (0.0000000876741 * tempK * tempK )) * tempK)
tempC = tempK - 273.15
return tempC

if uname()[0] == 'esp8266': ❷
adc = ADC(0)
else:
adc = ADC(Pin(34))
adc.atten(ADC.ATTN_11DB)

i2c = I2C(sda=Pin(5), scl=Pin(4))


LCD = LCD1602(i2c, 0x27)

try:
while True:
temp = obterTemperatura(adc.read())
print ("Temperatura: ", round(temp, 1), "°C")
LCD.puts("Temperatura:", 0, 0)
LCD.puts(str(round(temp, 1)) + str(chr(223)) + 'C', 0, 1)
sleep(1.0)
except:
LCD.clear()
LCD.backlight(False)

Figura 6.5: Circuito eletrônico (NodeMCU-ESP32).

Display de LEDs de 7 segmentos e 4 dígitos


O display de LEDs de 7 segmentos e 4 dígitos é outro tipo de display
bastante comum e utilizado, principalmente para a exibição de valores
numéricos. Com o intuito de reduzir o uso dos pinos da GPIO existem
diversos módulos que implementam um circuito integrado para realizar a
comunicação entre o display e o microcontrolador. Vamos utilizar nesta
obra o módulo TM1637, mostrado na Figura 6.6.
Figura 6.6: Módulo TM1637.
Identifique e separe os materiais relacionados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Módulo TM1637
Cabos de conexão
Realize a montagem da maneira indicada pela Figura 6.7, caso esteja
utilizando o NodeMCU (ESP8266).
Figura 6.7: Conexão do TM1637 ao NodeMCU-ESP8266.
No caso de usar o NodeMCU (ESP32), adote a Figura 6.8 como referência.
 A biblioteca MicroPython TM1637 deverá ser usada e está disponível em
https://github.com/mcauser/micropython-tm1637. Faça o download do arquivo
tm1637.py para o seu computador.

Figura 6.8: Conexão do TM1637 ao NodeMCU-ESP32.


Antes de implementar o programa, utilize o utilitário Ampy pelo shell do
sistema operacional do computador para copiar a biblioteca para o
sistema de arquivos do NodeMCU. Troque a porta com6, mostrada no
comando a seguir, para a porta na qual o NodeMCU está conectado ao
seu computador.
 ampy --port com6 put tm1637.py
Após a montagem, use o ambiente de desenvolvimento Thonny para
implementar o programa apresentado a seguir.
z tm-teste.py
from tm1637 import TM1637
from machine import Pin
from time import sleep

tm = TM1637(clk=Pin(5), dio=Pin(4)) ❶
# Ativa todos os LEDs do módulo "88:88"
tm.write([127, 255, 127, 127]) ❷
sleep(2.0)
# Desliga todos os LEDs
tm.write([0, 0, 0, 0])
Note no programa que, em ❶ , criamos o objeto relativo ao display,
indicando os pinos de clock (clk) e dados (dio). Em ❷ , ligamos todos os
LEDs do display utilizando o método write, sendo que cada item da lista
corresponde a um dígito do display, observando que o segundo item
também controla o acendimento do símbolo “:” (dois pontos) do display.
Após 2,0 segundos desligamos todos os LEDs usando novamente o
método write, porém passando 0 para todos os elementos da lista.
Com o intuito de entender os valores passados para o método write,
usando uma lista, observe na Figura 6.9 que cada dígito é composto de
7 segmentos. Para compor o valor do dígito, devemos especificar se
determinado segmento está ligado (1) ou desligado (0), organizando os
valores do segmento “g” até o segmento “a”.

Figura 6.9: Segmentos de um dígito do display.


Dessa forma, para representar o dígito 3, temos de considerar:
g f e d c b a
100 1 1 1 1
Esse valor está representado na base numérica binária, então devemos
converter para decimal, o que resultará no valor 79. Sendo assim, usando o
método write da maneira mostrada a seguir, o primeiro segmento
mostraria o dígito 3, enquanto os demais permanecem apagados.
z tm.write([79, 0, 0, 0])
O símbolo “:” (dois pontos) é ligado somando 128 ao valor desejado para
o segundo dígito da lista.

Relógio digital
Este projeto irá usar o Wi-Fi integrado do NodeMCU para buscar na
Internet a hora atual em um servidor NTP, ajustar o fuso horário e exibi-
la no display.
Mantendo a montagem do projeto anterior que empregou o módulo
TM1637, use o ambiente de desenvolvimento Thonny para implementar o
programa apresentado a seguir.
z tm-relogio.py
from machine import Pin, idle
from time import sleep, localtime
import network
import ntptime
import tm1637

tm = tm1637.TM1637(clk=Pin(5), dio=Pin(4))
tm.show('Sinc')

wifi = network.WLAN(network.STA_IF) ❶
wifi.active(True) ❷
wifi.connect('ap', 'senha') ❸
while wifi.isconnected() == False:
idle()
print('Conexao realizada.')
print(wifi.ifconfig())
ntptime.settime() ❹
wifi.active(False) ❺
try:
fuso = -3
sep = True
while True:
agora = localtime() ❻
tm.numbers (agora[3] + fuso, agora[4], sep) ❼
sep = not sep
sleep(2.0)
except KeyboardInterrupt:
tm.write([0, 0, 0, 0])
Analisando o código-fonte, podemos observar que em ❶ , ❷ e ❸ é
realizada a conexão com um access point. Em ❹ , o relógio interno (RTC)
do NodeMCU é ajustado de acordo com o horário no servidor NTP e, em
❺ , desligamos o módulo Wi-Fi, pois a partir desse momento a hora será
obtida do próprio RTC do NodeMCU.
Em ❻ , a data e a hora são obtidas do RTC, em ❼ usamos o método
numbers para exibir a hora, com o devido ajuste do fuso horário, e os
minutos no display de LEDs.

Relógio e termômetro digital


Com o intuito de apresentar outras funcionalidades do display de LEDs
de 7 segmentos e 4 dígitos, vamos acrescentar ao projeto do “Relógio
Digital” a possibilidade de mostrar, além do horário, a temperatura.
Também será possível realizar o ajuste da intensidade luminosa do
display. Comece identificando e separando os materiais relacionados a
seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Módulo TM1637
3 Resistores de 10k Ohms (marrom, preto, laranja)
2 Chaves táctil
1 Termístor NTC 10k Ohms
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 6.10,
caso esteja utilizando o NodeMCU (ESP8266).
Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 6.11
como referência.
Figura 6.10: Circuito eletrônico (NodeMCU-ESP8266).
No Thonny, implemente o código-fonte mostrado a seguir (tm-relogio-
termistor.py). Note que em ❶ e ❷ definimos os botões que serão usados
para alternar a exibição no display entre data e temperatura e para o
ajuste de intensidade luminosa. Em ❸ , ❹ , ❺ , ❻ e ❼ , é realizado o
controle da intensidade luminosa, em que cada pressionamento do botão
incrementa a variável brilho até o valor 4, nesse caso, a variável recebe o
valor 0. Dessa forma, definimos os 4 níveis de intensidade do display, ou
seja, de zero, que é o mínimo, até 3, que é a intensidade máxima.

Figura 6.11: Circuito eletrônico (NodeMCU-ESP32).


z tm-relogio-termistor.py
from machine import Pin, idle, ADC
from time import sleep, localtime
from math import log
import os
import network
import ntptime
import tm1637
if os.uname()[0] == 'esp8266':
adc = ADC(0)
else:
adc = ADC(Pin(34))
adc.atten(ADC.ATTN_11DB)

def obter_temperatura(termistor):
if os.uname()[0] == 'esp8266':
fator = 1024.0
else:
fator = 4096.0
tempK = log(10000.0 * (fator / termistor - 1))
tempK = 1 / (0.001129148 + (0.000234125
+ (0.0000000876741 * tempK * tempK )) * tempK)
tempC = tempK - 273.15
return tempC

selecao = Pin(13, Pin.IN) ❶


intensidade = Pin(15, Pin.IN) ❷
brilho = 2

tm = tm1637.TM1637(clk=Pin(5), dio=Pin(4))
tm.brightness(brilho)

tm.show('Sinc')
wifi = network.WLAN(network.STA_IF)
wifi.active(True)
wifi.connect('ap', 'senha')
while wifi.isconnected() == False:
idle()
print('Conexao realizada.')
print(wifi.ifconfig())
ntptime.settime()
wifi.active(False)

try:
fuso = -3
sep = True
mostrar = 0
while True:
if intensidade.value() == True: ❸
brilho = brilho + 1 ❹
if brilho == 4: ❺
brilho = 0 ❻
tm.brightness(brilho) ❼

if selecao.value() == True:
mostrar = mostrar + 1 ❾
if mostrar == 2:❿
mostrar = 0 ⓫
if mostrar == 0:⓬
agora = localtime() ⓭
tm.numbers (agora[3] + fuso, agora[4], sep) ⓮
elif mostrar == 1: ⓯
temp = 0 ⓰
for i in range(10): ⓱
temp = temp + obter_temperatura(adc.read()) ⓲
tm.temperature(int(temp/10)) ⓳
sep = not sep
sleep(0.5)
except:
tm.write([0, 0, 0, 0])
Concluindo a análise do programa, em ❽, ❾, ❿, ⓫, ⓬, ⓭, ⓮, ⓯, ⓰, ⓱, ⓲
e ⓳ usamos o botão selecao e a variável mostrar para alternar entre a
exibição da hora atual ou da temperatura.

Display OLED
O display OLED (Organic Light-Emitting Diode) possibilita a exibição
não apenas de caracteres alfanuméricos, mas também de imagens e outros
elementos gráficos. O modelo de 128x64 pixels é o mais facilmente
encontrado, estando disponível com interface I2C, que pode ser visto à
esquerda na Figura 6.12, ou SPI, que está à direita na mesma figura.
Ambos são protocolos de comunicação serial muito utilizados na
comunicação de módulos com dispositivos microcontrolados.
Figura 6.12: Displays OLED.
 Como já abordado anteriormente, o I²C é um barramento serial usado para
conectar módulos de baixa velocidade a sistemas microcontrolados. Apresenta um
barramento com um sinal de clock (SCL) e linhas de dados (SDA). O SPI também
utiliza linhas separadas para clock e dados, além de uma linha de seleção para que
seja possível escolher o módulo com o qual o microcontrolador irá estabelecer a
comunicação.
Neste primeiro projeto com o display OLED, usaremos o modelo com o
barramento I²C. Dessa forma, identifique os seguintes materiais que são
necessários para a montagem.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Display OLED 128x64 I2C
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 6.13,
caso esteja utilizando o NodeMCU (ESP8266).
Figura 6.13: Ligação do OLED I2C ao NodeMCU-ESP8266.
Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 6.14
como referência.
Figura 6.14: Ligação do OLED I2C ao NodeMCU-ESP32.
Resumindo o que é mostrado nas figuras 5.13 e 5.14, a conexão dos
terminais do OLED aos terminais dos dois modelos de NodeMCU devem
ser realizadas conforme a Tabela 6.1.
Tabela 6.1: Conexão dos terminais
OLED I2C NodeMCU (ESP8266 ou ESP32)

SDA (DATA) GPIO5

SCK (CLK) GPIO4

VDD 3V3

GND GND

 A biblioteca ssd1306 suporta displays OLED, os barramentos I2C e SPI e está


disponível em:
https://github.com/micropython/micropython/tree/master/drivers/display.
Realize o download do arquivo ssd1306.py para o seu computador.
Antes de implementar o programa, utilize o utilitário Ampy para copiar a
biblioteca para o sistema de arquivos do NodeMCU. Troque a porta com6,
mostrada no comando a seguir, para a porta na qual o NodeMCU está
conectado ao seu computador.
 ampy --port com6 put ssd1306.py
Em seguida, use o ambiente de desenvolvimento Thonny para
implementar o programa apresentado a seguir.
z oled-i2c-ola-1.py
from machine import Pin, I2C
from time import sleep
import ssd1306 ❶
i2c = I2C(sda=Pin(5), scl=Pin(4)) ❷
oled = ssd1306.SSD1306_I2C(128, 64, i2c) ❸
oled.fill(0) ❹
oled.rect(0, 0, 128, 64, 1) ❺
oled.text('Ola!', 2, 3) ❻
oled.show() ❼
sleep(3.0)
oled.poweroff() ❽
Em ❶, importamos a biblioteca ssd1306, que será responsável pelas classes
que irão possibilitar a manipulação do display OLED. A comunicação I2C
é configurada em ❷ e o objeto que atuará sobre o display OLED é
definido na sequência, em ❸ . Em ❹ , o método fill é usado para apagar
todo o conteúdo do display mantendo todos os pixels desligados, pois o
método foi chamado com o parâmetro 0 (zero). Por outro lado, se fosse
passado o parâmetro 1 (um), o conteúdo seria apagado, porém todos os
pixels ficariam ligados. Como se trata de um display monocromático,
temos duas cores disponíveis: 0 (zero) que representa o preto (pixel
desligado) e 1 (um) para especificar o branco (pixel desligado).
Em ❺ , foi usado o método rect para desenhar um retângulo começando
nas coordenadas x = 0 e y = 0 e com 128 pixels de largura e 64 pixels de
altura. O último parâmetro é a cor que, neste exemplo, será branco. Dessa
forma, acabamos desenhando uma borda que envolve toda a área do
display. Em ❻, o método text possibilita exibir um texto nas coordenadas
especificadas.
O método show, mostrado em ❼ , irá executar os comandos usados
anteriormente, fill, rect e text, no display. Ou seja, qualquer conteúdo só
é exibido no display quando o método show é executado. Concluindo a
análise do código-fonte, em ❽ o display é desligado pelo método poweroff.
Na Figura 6.15, mostramos o resultado da execução do programa.

Figura 6.15: Exibição no Display OLED I2C.


Agora vamos demonstrar o funcionamento do display OLED com
barramento SPI. O programa será o mesmo do projeto anterior, porém,
devidamente alterado para trabalhar com o barramento SPI em vez do
I2C. Comece identificando e separando os seguintes materiais.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Display OLED 128x64 SPI
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 6.16,
caso esteja utilizando o NodeMCU (ESP8266).
Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 6.17
como referência.
Resumindo o que é mostrado nas figuras 5.16 e 5.17, a conexão dos
terminais do OLED SPI aos terminais dos dois modelos de NodeMCU
deve ser realizada conforme a Tabela 6.2.
Tabela 6.2: Conexão dos terminais
OLED SPI NodeMCU (ESP8266 ou ESP32)

CS GPIO15

DC GPIO4

RES (RESET) GPIO5

SDA (DATA) GPIO13

SCK (CLK) GPIO14

VDD 3V3

GND GND
Figura 6.16: Ligação do OLED SPI ao NodeMCU-ESP8266.
 A biblioteca ssd1306, que funciona com displays de OLED com barramento SPI e
I2C, está disponível em:
https://github.com/micropython/micropython/tree/master/drivers/display.
Realize o download do arquivo ssd1306.py para o seu computador.
Antes de implementar o programa, utilize o utilitário Ampy para copiar a
biblioteca para o sistema de arquivos do NodeMCU. Troque a porta com6,
mostrada no comando a seguir, para a porta na qual o NodeMCU está
conectado ao seu computador.
 ampy --port com6 put ssd1306.py
Figura 6.17: Ligação do OLED SPI ao NodeMCU-ESP32.
Em seguida, no Thonny implemente o seguinte código-fonte.
z oled-spi-ola-1.py
from machine import Pin, SPI
from time import sleep
import ssd1306

spi = SPI(sck=Pin(14), mosi=Pin(13), miso=Pin(12)) ❶


oled = ssd1306.SSD1306_SPI(128, 64, spi, dc=Pin(4), res=Pin(5),
cs=Pin(15)) ❷
oled.fill(0)
oled.rect(0, 0, 128, 64, 1)
oled.text('Ola!', 2, 3)
oled.show()
sleep(3.0)
oled.poweroff()
spi.deinit() ❸
O programa tem as mesmas funcionalidades do projeto anterior, que usou
o barramento I2C. As diferenças estão em ❶ , onde o barramento SPI é
configurado, e em ❷ , onde o objeto oled, que irá representar o display, é
criado usando o método SSD1306_SPI. Além disso, concluindo o programa,
em ❸ a interface SPI é desligada.
Na Figura 6.18, mostramos o resultado da execução do programa.

Figura 6.18: Exibição no display OLED SPI.


 Nos projetos a seguir, usaremos o display OLED com barramento de comunicação
SPI, porém eles podem ser facilmente alterados para utilizarem displays OLED I2C.
Neste próximo programa e considerando o programa anterior, note que
vamos simplesmente alterar ❶ , ❷ e ❸ para inverter as cores de exibição
no display OLED.
z oled-spi-ola-2.py
from machine import Pin, SPI
from time import sleep
import ssd1306

spi = SPI(sck=Pin(14), mosi=Pin(13), miso=Pin(12))


oled = ssd1306.SSD1306_SPI(128, 64, spi, dc=Pin(4), res=Pin(5),
cs=Pin(15))
oled.fill(1) ❶
oled.rect(0, 0, 128, 64, 0) ❷
oled.text('Ola!', 2, 3, 0) ❸
oled.show()
sleep(3.0)
oled.poweroff()
spi.deinit()
Podemos observar na Figura 6.19 como ficou a exibição no display OLED.
O código-fonte apresentado a seguir (oled-spi-charset.py) irá mostrar o
conjunto de caracteres que podem ser exibidos no display OLED. Esse
conjunto corresponde aos caracteres entre 32 (espaço em branco) até 127
(~).

Figura 6.19: Exibição invertida.


z oled-spi-charset.py
from machine import Pin, SPI
from time import sleep
import ssd1306

spi = SPI(sck=Pin(14), mosi=Pin(13), miso=Pin(12))


oled = ssd1306.SSD1306_SPI(128, 64, spi, dc=Pin(4), res=Pin(5),
cs=Pin(15))
oled.fill(0)
i = 32
col = 0
lin = 0
while i <= 127:
oled.text(chr(i), col, lin)
i = i + 1
col = col + 10
if (col > 128):
col = 0
lin = lin + 10
if i == 110 or i == 127:
oled.show()
sleep(5.0)
oled.fill(0)
col = 0
lin = 0
oled.poweroff()
spi.deinit()
Observe no programa que controlamos, usando as variáveis col e lin, a
exibição dos caracteres. Sendo que, quando a tela estiver toda preenchida,
iremos aguardar 5 segundos antes de limpar a tela e mostrar os caracteres
restantes.
Outro método disponível é o scroll, que possibilita a rolagem de um
texto na tela do display. O próximo programa irá demonstrar o uso desse
recurso. Observe que em ❶, ❷, ❸ e ❹ usamos uma estrutura de repetição
for para percorrer as linhas do display e o método scroll para realizar a
rolagem do texto uma linha por vez sem mudarmos a coluna. Nesse caso,
realizamos apenas a rolagem na vertical.
z oled-spi-rolagem.py
from machine import Pin, SPI
from time import sleep
import ssd1306

spi = SPI(sck=Pin(14), mosi=Pin(13), miso=Pin(12))


oled = ssd1306.SSD1306_SPI(128, 64, spi, dc=Pin(4), res=Pin(5),
cs=Pin(15))
oled.fill(0)
oled.text('Ola!', 0, 1)
oled.show()
sleep(3.0)
for i in range(0, 56): ❶
oled.scroll(0, 1) ❷
oled.show() ❸
sleep(0.01) ❹
sleep(1.0)
oled.poweroff()
spi.deinit()

Exibição de imagens no display OLED


A biblioteca ssd1306 oferece inúmeros recursos para exibição de elementos
de texto, gráficos e imagens no display OLED. No próximo programa,
vamos desenvolver as rotinas que permitirão a exibição de imagens.
 A biblioteca ss1306 exibe apenas imagens no formato PBM (Portable Bitmap).
Esse formato trabalha apenas com imagens em preto e branco, sem a
representação de tons de cinza e sem compactação. Utilize o programa GIMP
(GNU Image Manipulation Program), disponível gratuitamente em
https://www.gimp.org/, para converter imagens para o formato PBM.
Vamos manter a montagem do circuito eletrônico usado nos programas
anteriores que fazem uso do display OLED, ou seja, é apenas necessário
conectar o display ao NodeMCU. Em seguida, copie a imagem desejada,
no formato PBM e com dimensões máximas de 128x63 pixels para o
sistema de arquivos no NodeMCU.
Utilize o utilitário Ampy para realizar a cópia. No projeto, vamos assumir
que o arquivo da imagem foi nomeado como relogio.pbm. Também troque
a porta com6 para a porta na qual o NodeMCU está conectado ao seu
computador.
 ampy --port com6 put relogio.pbm
No Thonny, digite o código-fonte apresentado a seguir. Importamos em ❶
a biblioteca framebuf, que é necessária para armazenarmos a imagem após
esta ser lida do sistema de arquivos. Em ❷ , é realizada a abertura do
arquivo, enquanto em ❸ , ❹ e ❺ o cabeçalho do arquivo é lido, porém,
observe que não precisamos dessas informações nesse programa.
z oled-spi-imagem.py
from machine import Pin, SPI
from time import sleep
import ssd1306
import framebuf ❶
spi = SPI(sck=Pin(14), mosi=Pin(13), miso=Pin(12))
oled = ssd1306.SSD1306_SPI(128, 64, spi, dc=Pin(4), res=Pin(5),
cs=Pin(15))

with open('relogio.pbm', 'rb') as arquivo: ❷


arquivo.readline() # Ler o ❸
arquivo.readline() # cabeçalho ❹
arquivo.readline() # do arquivo ❺
dados = bytearray(arquivo.read()) ❻
buffer = framebuf.FrameBuffer(dados, 128, 64, framebuf.MONO_HLSB) ❼
oled.invert(0)
oled.blit(buffer, 0, 0)
oled.show()
sleep(5.0)
arquivo.close()
oled.poweroff()
spi.deinit()
Prosseguindo com a explicação do código-fonte, em ❻ a imagem em si é
lida do arquivo, sendo armazenada em um buffer, conforme podemos
notar em ❼. O método invert define o modo de exibição e o método blit
irá copiar a imagem para o display, nas coordenadas especificadas. Por
fim, o método show irá realizar a exibição. Na Figura 6.20, à esquerda,
temos a exibição da imagem quando o parâmetro do método invert é 0
(zero) e a direita, da mesma figura, quando o parâmetro é 1 (um).

Figura 6.20: Possibilidades de exibição da imagem.

Termômetro digital – versão 2


Neste projeto, vamos utilizar o termístor para obter a temperatura
ambiente e exibi-la no OLED SPI. Identifique os materiais necessários.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Display OLED 128x64 SPI
1 Resistor de 10k Ohms (marrom, preto, laranja)
1 Termístor NTC 10k Ohms
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 6.21,
caso esteja utilizando o NodeMCU (ESP8266).

Figura 6.21: Circuito eletrônico (NodeMCU-ESP8266).


Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 6.22
como referência.
Obtenha uma figura que represente um termômetro, reduza para
64x64 pixels e converta para o formato PBM. Utilize o utilitário Ampy
para realizar a cópia, conforme o exemplo a seguir. No projeto, vamos
assumir que o arquivo da imagem foi nomeado como termometro.pbm.
Troque também a porta com6 para a porta na qual o NodeMCU está
conectado ao seu computador.
 ampy --port com6 put termometro.pbm
O programa é apresentado a seguir (oled-spi-imagem-termistor.py) e deve
ser implementado no Thonny, em que é possível notar as rotinas para
configuração do ADC para a conversão do valor analógico lido para graus
Celsius, já utilizadas em projetos anteriores.

Figura 6.22: Circuito eletrônico (NodeMCU-ESP32).


z oled-spi-imagem-termistor.py
from machine import Pin, SPI, ADC
from time import sleep
from math import log
import os
import ssd1306
import framebuf

spi = SPI(sck=Pin(14), mosi=Pin(13), miso=Pin(12))


oled = ssd1306.SSD1306_SPI(128, 64, spi, dc=Pin(4), res=Pin(5),
cs=Pin(15))

if os.uname()[0] == 'esp8266':
adc = ADC(0)
else:
adc = ADC(Pin(34))
adc.atten(ADC.ATTN_11DB)

def obter_temperatura(termistor):
if os.uname()[0] == 'esp8266':
fator = 1024.0
else:
fator = 4096.0
tempK = log(10000.0 * (fator / termistor - 1))
tempK = 1 / (0.001129148 + (0.000234125
+ (0.0000000876741 * tempK * tempK )) * tempK)
tempC = tempK - 273.15
return tempC

with open('termometro.pbm', 'rb') as arquivo:


arquivo.readline() # Ler o
arquivo.readline() # cabeçalho
arquivo.readline() # do arquivo
dados = bytearray(arquivo.read())
buffer = framebuf.FrameBuffer(dados, 64, 64, framebuf.MONO_HLSB)
oled.invert(0)
oled.blit(buffer, 0, 0)
oled.show()
arquivo.close()

try:
while True:
temp = obter_temperatura(adc.read()) ❶
oled.fill_rect(66, 25, 62, 20, 0)
oled.show()
oled.text('Temp.:', 66, 25) ❷
oled.text(str(round(temp, 1)) + "'C", 66, 35) ❸
oled.show()❹
sleep(5.0) ❺
except KeyboardInterrupt:
oled.poweroff()
spi.deinit()
Assim como no programa anterior, observe que ocorre leitura do arquivo
e a exibição da imagem no display OLED. Na sequência do programa é
realizada em ❶ a leitura do termístor e em ❷ , ❸ , ❹ e ❺ a exibição da
temperatura no display a cada 5 segundos. Note que apenas a informação
de temperatura é atualizada com a imagem permanecendo fixa na tela,
pois a imagem é carregada e exibida antes da instrução while. Na
Figura 6.23, apresentamos um exemplo de execução do programa.

Figura 6.23: Exibição da temperatura.


capítulo 7

Redes de sensores

Este capítulo irá abordar a conexão de sensores e outros dispositivos a um


único barramento. Serão exploradas redes de dispositivos com interface
I²C e 1-Wire. Além disso, será mostrada a comunicação com um broker
MQTT (Message Queue Telemetry Transport).
Dispositivos microcontrolados, como o NodeMCU, implementam
interfaces de comunicação, que tornam as montagens dos circuitos
eletrônicos mais simples, mas que também possibilitam a conexão de
uma vasta gama de módulos, sem a necessidade de utilização de muitos
pinos da GPIO. No capítulo anterior, quando abordamos os displays,
mencionamos dois protocolos muito adotados, o I²C e o SPI. Agora vamos
desenvolver projetos que vão mostrar a capacidade de conexão simultânea
de diversos módulos ao NodeMCU usando um único barramento para
realizar a comunicação.

Inter-Integrated Circuit (I²C)


Este projeto irá usar o protocolo I²C para permitir a interconexão ao
NodeMCU de um display LCD, um sensor barométrico (BMP180) e um
sensor de luminosidade (BH1750). Todos os três são módulos que
implementam a interface I2C e irão compartilhar um mesmo barramento,
sendo identificados por endereços únicos.
O I²C consiste em um barramento serial usado para conectar módulos de
baixa velocidade a sistemas microcontrolados. O protocolo I2C atua no
modelo Mestre e Escravo.
Conforme podemos notar na Figura 7.1, temos um dispositivo, que no
nosso caso é o NodeMCU, assumindo o papel de Mestre, sendo o
responsável pelo controle dos demais dispositivos, que são chamados de
Escravos. O barramento I2C possui uma linha com o sinal de clock (SCL)
e outra linha para dados (SDA). O SCL determina de quem é a vez do
envio (mestre ou escravo) e o barramento SDA é responsável por
transmitir os dados.

Figura 7.1: Conexão dos Dispositivos I2C


Comece o projeto identificando e separando os seguintes materiais.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
2 Resistores de 10k Ohms (marrom, preto, laranja)
1 Display LCD 1602 I2C
1 Sensor BMP180
1 Sensor BH1750
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 7.2, caso
esteja utilizando o NodeMCU (ESP8266).
Adote como referência a Figura 7.3 se estiver utilizando o NodeMCU
(ESP32).
Após a montagem do circuito eletrônico, note a vantagem da adoção do
barramento I2C, pois utilizamos apenas dois terminais da GPIO do
NodeMCU para conectar todos os dispositivos. Agora no Thonny vamos
usar o programa i2c-scan.py, já desenvolvido anteriormente e mostrado
novamente a seguir, para verificar a conexão dos módulos ao barramento
I2C.
z i2c-scan.py
from machine import I2C, Pin
from os import uname

i2c = I2C(sda=Pin(5), scl=Pin(4))

print('Pesquisando o barramento I2C do', uname()[0], '...')


dispositivos = i2c.scan()

if len(dispositivos) == 0:
print("Nenhum dispositivo encontrado!")
else:
print('Dispositivos encontrados:', len(dispositivos))
for dispositivo in dispositivos:
print("Endereço:", hex(dispositivo))
Figura 7.2: Conexões (NodeMCU-ESP8266).
Figura 7.3: Conexões (NodeMCU-ESP32).
Após a execução do programa, no shell deveremos observar o endereço
dos três dispositivos I2C conectados ao NodeMCU, conforme Figura 7.4.
Figura 7.4: Dispositivos I2C detectados.
Em seguida, digite o seguinte programa no ambiente de desenvolvimento
Thonny. Em ❶ , note que configuramos o I2C, na sequência o BMP180, o
BH1750 e o LCD1602 são conectados logicamente ao barramento, em que
cada um possui um endereço exclusivo, conforme pode ser observado em
❷, ❸ e ❹.
z lcd-i2c-bmp180-bh1750.py
from machine import Pin, I2C
from time import sleep
from mp_i2c_lcd1602 import LCD1602
from bmp180 import BMP180
from bh1750 import BH1750
import gc
gc.collect()

i2c = I2C(sda=Pin(5), scl=Pin(4)) ❶


bmp = BMP180(i2c) # Endereço: 0x77 ❷
bmp.oversample_sett = 2
bmp.baseline = 101325
bh = BH1750(i2c) # Endereço: 0x23 ❸
LCD = LCD1602(i2c, 0x27) ❹
try:
while True:
temperatura = bmp.temperature
pressao = (bmp.pressure / 100)
altitude = bmp.altitude
luminosidade = bh.luminance(BH1750.ONCE_HIRES_1)
LCD.clear()
LCD.puts('Temperatura:', 0, 0)
LCD.puts('{0:.1f} {1}C'.format(temperatura, chr(223)), 0, 1)
sleep(2.5)
LCD.clear()
LCD.puts('Pressao:', 0, 0)
LCD.puts('{0:.1f} hPa'.format(pressao), 0, 1)
sleep(2.5)
LCD.clear()
LCD.puts('Altitude:', 0, 0)
LCD.puts('{0:.1f} m'.format(altitude), 0, 1)
sleep(2.5)
LCD.clear()
LCD.puts('Luminosidade:', 0, 0)
LCD.puts('{0:.1f} lux'.format(luminosidade), 0, 1)
sleep(2.5)
except:
LCD.clear()
LCD.backlight(False)
Em seguida, no programa, é realizada a leitura dos sensores barométrico e
de luminosidade, sendo que cada um dos dados obtidos é exibido no
display LCD em intervalos de 2,5 segundos.

1-Wire
Neste projeto iremos abordar o uso do DS18B20, que consiste em um
termômetro digital que utiliza o sistema de barramento 1-Wire para se
comunicar com o NodeMCU ou qualquer outro sistema microcontrolado.
O 1-Wire tem a vantagem de usar apenas um terminal da GPIO para
todos os dispositivos, sendo que esses dispositivos são identificados por
meio de um endereço único.
O 1-Wire consiste em um sistema de barramento projetado pela Dallas
Semiconductor que possibilita comunicação de dados em baixa
velocidade. O princípio de funcionamento é similar ao I²C, mas apresenta
uma velocidade menor de transmissão de dados, e por outro lado, oferece
um maior alcance. Atua com o paradigma mestre-escravo, em que o
dispositivo microcontrolado assume o papel de mestre e os demais são
escravos.
Identifique e separe os seguintes materiais.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 4,7k Ohms (amarelo, violeta, vermelho)
1 Display LCD 1602 I2C
2 Sensores DS18B20
1 Protoboard
Cabos de ligação
Realize a montagem da maneira indicada pela Figura 7.5, caso esteja
utilizando o NodeMCU (ESP8266).
Figura 7.5: Conexões (NodeMCU-ESP8266).
Adote como referência a Figura 7.6, se estiver usando o NodeMCU
(ESP32).
Agora no Thonny vamos usar o programa mostrado a seguir para
verificar a conexão dos sensores ao barramento 1-Wire. Em ❶ , indicamos
o pino da GPIO que irá receber os dados dos sensores 1-Wire e em ❷
usamos o método scan para identificar os sensores que estão no
barramento.
Em ❸ e ❹ , percorremos a lista retornada pelo método scan e exibimos a
identificação única de cada um deles.
z 1-wire-scan.py
from machine import Pin
from onewire import OneWire
from ds18x20 import DS18X20
from os import uname

print('Pesquisando o barramento 1-Wire do', uname()[0], '...')


rede = DS18X20(OneWire(Pin(2))) ❶
sensores = rede.scan() ❷
print(len(sensores), 'sensores encontrados.')
for sensor in sensores: ❸
print('Sensor:', sensor) ❹
Figura 7.6: Conexões (NodeMCU-ESP32).
Na Figura 7.7, podemos ver um possível resultado da execução do
programa.

Figura 7.7: Sensores DS18B20 detectados.


No código-fonte a seguir, vamos obter a leitura de temperatura de cada
sensor que está conectado ao barramento 1-Wire e exibir no display LCD.
z lcd-i2c-18b20.py
from machine import Pin, I2C
from onewire import OneWire
from ds18x20 import DS18X20
from time import sleep, sleep_ms
from mp_i2c_lcd1602 import LCD1602

i2c = I2C(sda=Pin(5), scl=Pin(4))


LCD = LCD1602(i2c, 0x27)

rede = DS18X20(OneWire(Pin(2))) ❶
sensores = rede.scan() ❷
try:
while True:
rede.convert_temp() ❸
sleep_ms(750) ❹
i = 1
for sensor in sensores: ❺
temp = rede.read_temp(sensor) ❻
LCD.puts('Temp. Sensor #' + str(i) + ':', 0, 0)
LCD.puts(str(round(temp, 1)) + str(chr(223)) + 'C', 0, 1)
i = i + 1
sleep(2.0)
except:
LCD.clear()
LCD.backlight(False)
Após configurar a comunicação 1-Wire e em ❶ e ❷ identificar os sensores
que estão conectados, em ❸ executamos o método convert_temp para
iniciar o processo de leitura nos sensores, sendo que devemos aguardar
750ms para que essas leituras sejam realizadas, conforme mostrado em ❹.
Posteriormente, em ❺ e ❻, obtemos a temperatura de cada sensor usando
o método read_temp e as exibimos no display LCD.
MQTT (Message Queue Telemetry Transport)
O MQTT consiste em um protocolo de mensagens leve e assíncrono
voltado para sensores, sistemas microcontrolados e pequenos dispositivos
móveis. Fundamentado na pilha de protocolos TCP/IP, a troca de
mensagens é realizada a partir de um modelo Publicador-Subscritor,
bastante simples e leve.
O uso do MQTT possibilita reduzir o uso de banda de rede e dos
recursos dos equipamentos, tem como características básicas desacoplar o
emissor e o receptor da mensagem e é escalável em ambientes de rede de
baixo desempenho e qualidade de transmissão. É o protocolo ideal para
aplicações para IoT em que existe uma enorme gama de dispositivos
trocando pequenas mensagens entre si.
As mensagens no MQTT adotam uma estrutura de tópicos, em que os
níveis são separados por uma barra (“/”), por exemplo,
casa/sensor/cozinha/temperatura.
O termo broker será usado para o servidor que recebe mensagens dos
clientes, sendo que um cliente pode ser qualquer tipo de dispositivo que
pode interagir com o broker, enviando e/ou recebendo mensagens.
Existem alguns brokers públicos disponíveis na Internet e é possível
instalar um broker no seu computador.
 Nesta obra, vamos utilizar o Eclipse Mosquitto, que é um broker de código-fonte
aberto. Ele está disponível para download gratuito em https://mosquitto.org/. O
desenvolvimento dos projetos seguintes exige que o Mosquitto esteja
devidamente instalado no seu computador.
Após instalar Eclipse Mosquitto e ativar o respectivo serviço, vamos
construir um projeto em que enviaremos uma mensagem, por intermédio
de um tópico no broker, que irá possibilitar ligar ou desligar um LED
conectado ao NodeMCU.
 Existe também a possibilidade de usar o ambiente de teste do Eclipse Mosquitto,
disponibilizado no próprio site do Eclipse Mosquitto (https://mosquitto.org/).
Nesse caso, substitua o endereço IP do seu computador por test.mosquitto.org
nos projetos.
Comece identificando e separando os materiais relacionados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
1 LED (qualquer cor)
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 7.8, caso
esteja utilizando o NodeMCU (ESP8266).

Figura 7.8: Circuito eletrônico (NodeMCU-ESP8266).


Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 7.9
como referência.

Figura 7.9: Circuito eletrônico (NodeMCU-ESP32).


A conexão com o broker pode ser realizada pelo endereço IP do
computador no qual ele foi instalado, como no exemplo a seguir.
z servidor = '192.168.100.72'
 Identifique usando os utilitários disponíveis no sistema operacional qual
endereço IP foi atribuído ao computador onde o Eclipse Mosquitto foi instalado.
Ou utilize o servidor de testes disponível na Internet, como mostrado a
seguir.
z servidor = 'test.mosquitto.org'
No ambiente de desenvolvimento Thonny, implemente o programa a
seguir. Observe que realizamos a conexão ao access point em ❶ , ❷ e ❸ .
Posteriormente, em ❹ ocorre a definição da função de call-back, ou seja, a
função que será executada quando uma mensagem chegar ao broker, no
tópico em que o cliente está subscrito.
A conexão com o broker é realizada em ❺ e a subscrição no tópico em ❻.
O monitoramento do broker ocorre em ❼ e ❽ e, quando uma mensagem
é recebida, a função de call-back é executada.
z mqtt-led.py
import network, machine
from umqtt.simple import MQTTClient
from machine import Pin

estacao = network.WLAN(network.STA_IF) ❶
estacao.active(True) ❷
estacao.connect('ap', 'senha') ❸
while estacao.isconnected() == False:
pass
print('Conexao realizada.')
print(estacao.ifconfig())

def obter_mensagem(topico, mensagem): ❹


print(topico, mensagem)
if mensagem == b'ligar':
led.value(1)
elif mensagem == b'desligar':
led.value(0)

led = Pin(5, Pin.OUT)

print ('Conectando ao servidor MQTT')


servidor = 'test.mosquitto.org'
topico = 'atuador/led'
cliente = MQTTClient('NodeMCU', servidor, 1883) ❺
cliente.set_callback(obter_mensagem)
cliente.connect()
cliente.subscribe(topico) ❻
try:
while True: ❼
cliente.wait_msg() ❽
finally:
cliente.disconnect()
estacao.disconnect()
estacao.active(False)
print("Fim.")
Após executar o programa no Thonny, podemos testar o funcionamento
do projeto acessando o shell do sistema operacional. Observe que vamos
utilizar o utilitário mosquito_pub, que faz parte do programa Eclipse
Mosquitto instalado no seu computador. Use a opção -h para especificar o
endereço IP do broker ou o servidor da testes, em seguida a mensagem é
passada usando a opção -m e o tópico pela opção -t, conforme ilustrado a
seguir.
 mosquitto_pub -h 192.168.100.72 -m "ligar" -t atuador/led
Ou
 mosquitto_pub -h test.mosquitto.org -m "ligar" -t atuador/led
Após executar o comando, o LED deverá ser aceso; para apagar o LED
devemos usar:
 mosquitto_pub -h 192.168.100.72 -m "desligar" -t atuador/led
Ou
 mosquitto_pub -h test.mosquitto.org -m "desligar" -t atuador/led
capítulo 8

Node-RED

Muitas vezes a integração de dispositivos com diversos tipos de serviços


acaba se tornando uma tarefa extensa, dificultando o desenvolvimento
dos projetos. Neste capítulo apresentaremos a ferramenta de programação
visual Node-RED, que possui distribuição gratuita disponível para
diversos sistemas operacionais e é bastante intuitiva e permite criar
rapidamente aplicações para IoT.
O Node-RED é uma ferramenta de desenvolvimento baseada em fluxo e
programação visual; foi desenvolvida originalmente pela IBM e depois
disponibilizada em código aberto. Foi desenvolvida utilizando o ambiente
de execução Node.js, que possibilita a execução de JavaScript no lado
servidor, e não apenas no navegador (cliente). O Node-RED permite
conectar diversos tipos de hardware, incluindo dispositivos
microcontrolados, além de Application Programming Interfaces (APIs) e
serviços online, sendo muito útil em projetos de automação e aplicações
para IoT.
 A instalação do Node-RED (https://nodered.org/) é realizada pelo utilitário npm,
disponível no Node.js que está disponível em https://nodejs.org/pt-br/. Dessa
forma, primeiro providencie a instalação do Node.js e, em seguida, instale o Node-
RED.
Após a instalação do Node.js, execute o comando a seguir para realizar a
instalação do Node-RED.
 npm install -g --unsafe-perm node-red
O Node-RED ficará instalado em sua máquina, criando um pequeno
servidor, e será utilizado no navegador. Então, após executar o programa,
vá no navegador e digite a URL http://localhost:1880. A interface
principal será mostrada, conforme podemos ver na Figura 8.1.

Figura 8.1: Node-RED.

Olá Node-RED
Vamos criar um primeiro fluxo, que é como chamamos as aplicações
desenvolvidas no Node-RED. Adote como referência a Figura 8.2 e
identifique na paleta, que está no lado esquerdo da tela, os nós inject e debug
e os arraste para a área central do programa. Em seguida, realize a
conexão entre ambos.
Figura 8.2: Criação de um fluxo.
Realize um duplo clique do mouse sobre o nó inject para abrir o painel de
edição do nó. Altere o tipo do atributo Payload para string e digite o texto
Olá Pessoal!, conforme podemos notar na Figura 8.3. Pressione o botão
Done para concluir a alteração do nó.
Figura 8.3: Edição do nó inject.
Na Figura 8.4, mostramos como o fluxo deverá se assemelhar após a
edição do nó.

Figura 8.4: Criação de um fluxo.


Clique no botão Debug, identificado pelo ícone de um inseto e localizado
no canto superior direito da tela, e depois no botão Deploy para executar o
fluxo. Concluindo o exemplo, clique no quadrado que fica do lado
esquerdo do nó inject, conforme mostra a Figura 8.5.

Figura 8.5: Injeção de dados.


Ao clicar no nó inject, no lado direito da tela, será exibida na área de debug
a mensagem a seguir (Figura 8.6):

Figura 8.6: Exibição da mensagem.

JavaScript
Do mesmo modo que desenvolvemos o fluxo anterior, identifique na
paleta os nós inject e debug e os arraste para a área central do programa. Em
seguida, realize a conexão entre ambos (Figura 8.7).

Figura 8.7: Fluxo.


Clique no botão Debug e depois no botão Deploy para executar o fluxo.
Concluindo o exemplo, clique no quadrado que fica do lado esquerdo do
nó inject, conforme mostra a Figura 8.8.

Figura 8.8: Injeção de dados.


Após clicar no nó inject, na área de debug, deverá ser exibido um número
inteiro que corresponde ao número de milissegundos decorridos desde 1°
de janeiro de 1970 (Figura 8.9).

Figura 8.9: Injeção de dados.


Dessa forma, as informações relativas à data e hora precisam ser
devidamente formatadas para que se torne possível exibi-las para o
usuário de uma aplicação.
Devido ao fato de o Node-RED ser desenvolvido em Node.js ele
possibilita executar funções escritas em JavaScript. Vamos alterar o fluxo
criado anteriormente para demonstrar essa possibilidade. Adicione o nó
function entre o inject e o debug, conforme mostra a Figura 8.10.
Figura 8.10: Adição de um nó.
Vamos entrar em modo de edição. Dê um clique duplo sobre o nó function.
Na tela que será mostrada (Figura 8.11), na propriedade Name, digite
formatar.

Figura 8.11: Propriedades do nó.


Em seguida, digite o código-fonte a seguir, que está escrito em JavaScript,
na propriedade Function, e pressione o botão Done.
 var data = new Date(msg.payload);
var dia = data.getDate();
var mes = data.getMonth() + 1;
var ano = data.getFullYear();
var hor = data.getHours();
var min = data.getMinutes().toString().padStart(2, '0');
msg.payload = dia + '/' + mes + '/' + ano + ' ' + hor + ':' + min;
return msg;
Clique no botão Debug e depois no botão Deploy para executar o fluxo.
Concluindo o exemplo, clique no quadrado que fica do lado esquerdo do
nó inject, conforme mostra a Figura 8.12.

Figura 8.12: Injeção de dados.


Após clicar, no lado direito da tela deverão ser exibidas na área do debug a
data e a hora, devidamente formatadas pela função, conforme ilustra a
Figura 8.13.

Figura 8.13: Resultado da execução do fluxo.

Requisições HTTP
O Node-RED, como já mencionado anteriormente, possibilita a
comunicação de dispositivos de hardware com serviços online. Esse
projeto irá demonstrar essa possibilidade, usando o nó http request. Comece
identificando e separando os materiais relacionados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
1 LED (qualquer cor)
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 8.14,
caso esteja utilizando o NodeMCU (ESP8266).

Figura 8.14: Circuito eletrônico (NodeMCU-ESP8266).


Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Fig. 8.15
como referência.
No Thonny, implemente o programa http-led-2.py, mostrado a seguir,
mas que já foi utilizado no Capítulo 4, no tópico Controle de dispositivos
pela internet.
Lembre-se também de copiar o arquivo http-led-bootstrap.html para o
sistema de arquivos do NodeMCU utilizando o utilitário Ampy.
Figura 8.15: Circuito eletrônico (NodeMCU-ESP32).
z http-led-2.py
import network
import usocket as socket
import machine
import gc
gc.collect()

LED = machine.Pin(5, machine.Pin.OUT)

def obter_arquivo(arquivo):
conteudo = ''
a = open(arquivo, 'rb')
conteudo = a.read()
a.close()
return conteudo

estacao = network.WLAN(network.STA_IF)
estacao.active(True)
estacao.connect('ap', 'senha')
while estacao.isconnected() == False:
pass
print('Conexao realizada.')
print(estacao.ifconfig())

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)

try:
while True:
conexao, endereco = s.accept()
print('Conexao de %s' % str(endereco))
requisicao = conexao.recv(1024)
requisicao = str(requisicao)
print('Conteudo = %s' % requisicao)
if requisicao.find('/led/1') != -1:
print('Acender')
LED.value(1)
elif requisicao.find('/led/0') != -1:
print('Apagar')
LED.value(0)
else:
LED.value(0)
html = obter_arquivo('http-led-bootstrap.html')
conexao.send('HTTP/1.1 200 OK\n')
conexao.send('Content-Type: text/html\n')
conexao.send('Connection: close\n\n')
conexao.sendall(html)
conexao.close()
except KeyboardInterrupt:
s.close()
estacao.active(False)
Mantenha o programa executando no Thonny e vamos passar para o
Node-RED. Adicione um novo fluxo, conforme ilustra a Figura 8.16.
No fluxo criado, insira dois nós do tipo inject e um nó http request e realize as
conexões da maneira mostrada na Figura 8.17.

Figura 8.16: Novo fluxo.

Figura 8.17: Fluxo com o HTTP Request.


Com um clique duplo, acesse o quadro de edição (Figura 8.18) de um dos
nós inject colocados no fluxo, defina a propriedade Payload com 1 e a
propriedade Name como Ligar, e pressione o botão Done para efetuar as
alterações.
Faça o mesmo com o outro nó inject, porém, defina a propriedade Payload
com 0 e a propriedade Name com o valor Desligar. Na sequência, edite o nó
http request, conforme mostrado na Figura 8.19. Note que na propriedade URL
deverá ser colocado o endereço IP atribuído ao NodeMCU.
Clique no botão Deploy para executar o fluxo. Ao clicar no nó inject Ligar o
LED deverá ser aceso; ao clicar no nó inject Desligar o LED irá apagar.
Figura 8.18: Configuração do nó.
Figura 8.19: Configuração do nó http request.

Interação com broker MQTT


O fluxo que será desenvolvido neste projeto irá demonstrar como o Node-
RED possibilita realizar a conexão a um broker MQTT e enviar uma
mensagem a um tópico. O circuito eletrônico utilizado é o mesmo do
projeto anterior, ou seja, consiste em um LED conectado à GPIO5 do
NodeMCU.
Ative o serviço do Eclipse Mosquitto. No Thonny, o programa mqtt-led.py,
desenvolvido anteriormente e mostrado a seguir, deverá estar executando,
pois consiste na implementação de um cliente MQTT, que aguarda o
recebimento das mensagens postadas em determinado tópico no broker.
Em ❶, lembre-se apenas de ajustar o endereço IP do servidor para acessar
o servidor instalado no seu computador ou o endereço do ambiente de
testes.
z mqtt-led.py
import network, machine
from umqtt.simple import MQTTClient
from machine import Pin

estacao = network.WLAN(network.STA_IF)
estacao.active(True)
estacao.connect('ap', 'senha')
while estacao.isconnected() == False:
pass
print('Conexao realizada.')
print(estacao.ifconfig())

def obter_mensagem(topico, mensagem):


print(topico, mensagem)
if mensagem == b'ligar':
led.value(1)
elif mensagem == b'desligar':
led.value(0)

led = Pin(5, Pin.OUT)

print ('Conectando ao servidor MQTT')


servidor = 'test.mosquitto.org' ❶
topico = 'atuador/led'
cliente = MQTTClient('NodeMCU', servidor, 1883)
cliente.set_callback(obter_mensagem)
cliente.connect()
cliente.subscribe(topico)
try:
while True:
cliente.wait_msg()
finally:
cliente.disconnect()
estacao.disconnect()
estacao.active(False)
print("Fim.")
No Node-RED, realize a criação de um fluxo. Em seguida, insira dois nós
do tipo inject e um nó mqtt out. Faça as conexões conforme mostra a
Figura 8.20.

Figura 8.20: Utilização de um broker MQTT.


Clique sobre um dos nós inject e defina a propriedade Payload com a string
ligar (Figura 8.21). Repita o mesmo procedimento para o outro nó inject,
mas defina a propriedade Payload com a string desligar.
Em seguida, dê um clique duplo sobre o nó mqtt out para entrar no modo
de edição do nó. Conforme podemos observar na Figura 8.22, na
propriedade Server, escolha a opção Add new mqtt-broker... e clique no
ícone Edição, simbolizado pelo ícone de um lápis e responsável pela edição
dos dados do servidor.
No painel que será mostrado (Figura 8.23), preencha o nome do broker
(Propriedade Name), por exemplo Mosquitto, e na propriedade Server
coloque o endereço IP. Após preencher os dados, clique no botão Add.
De volta ao painel de edição do nó (Figura 8.24), selecione na propriedade
Server o broker MQTT que foi criado. Na sequência, preencha a
propriedade Topic com atuador/led e clique no botão Done.
Figura 8.21: Alteração das propriedades do nó.
Figura 8.22: Adicionando um broker MQTT.

Figura 8.23: Configuração do servidor.


Clique no botão Deploy para executar o fluxo. Observe que ao clicar no nó
inject ligar o LED deverá ser aceso, e ao clicar no nó inject desligar o LED irá
apagar.

Figura 8.24: Definição do servidor e do tópico.

Dashboard
O Node-RED apresenta um conjunto de nós que possibilitam a
construção de interfaces gráficas que irão facilitar para o usuário a
interação e visualização das informações. Adicione à paleta o módulo
node-red-dashboard. Para isso, clique no menu principal e, em seguida, na
opção Manage palette, conforme ilustra a Figura 8.25.
Figura 8.25: Acesso ao menu do Node-RED.
Em seguida, clique na aba Install (Figura 8.26), procure pelo módulo node-
red-dashboard e clique no botão install.
No Node-RED, realize a criação de um fluxo. Em seguida, insira dois nós
do tipo switch e um nó mqtt out, realizando a conexão entre eles, conforme
mostra a Figura 8.27.
Entre na edição do nó switch, realizando um clique duplo do mouse sobre
ele. O primeiro passo consiste em criar um Grupo. Para isso, selecione a
opção Add new ui_group... presente no atributo Group e clique no botão de Edição,
que é identificado pelo ícone do lápis. Agora selecione o atributo Tab,
escolha a opção Add new ui_tab... e clique no botão de Edição (ícone do lápis).
Defina a propriedade Name com o valor Painel de Controle, conforme
mostra a Figura 8.28, e clique no botão Update.
Agora defina o atributo Nome com o valor LED e, para o atributo Tab,
selecione a opção Painel de Controle (Figura 8.29). Clique no botão Update
para finalizar a edição do nó dashboard group.
Figura 8.26: Instalação dos módulos.

Figura 8.27: Nós switch e mqtt out.


Figura 8.28: Criação do nó dashboard tab.
Figura 8.29: Configuração do nó dashboard group.
Ao retornar ao painel de edição do nó switch, na propriedade Group
selecione a opção LED. A propriedade Label deverá receber o valor
Ligar/Desligar. A mensagem a ser enviada no atributo On Payload é ligar e
no atributo Off Payload é desligar, conforme ilustra a Figura 8.30.
Figura 8.30: Configuração do nó switch.
No NodeMCU, use a montagem e o programa (mqtt-led.py) adotados no
projeto anterior. No Node-RED, clique no botão Deploy para executar o
fluxo. Abra uma nova aba no navegador e digite a URL
http://localhost:1880/ui. Na Figura 8.31, apresentamos a exibição do
painel de controle (dashboard) que foi criado.

Figura 8.31: Dashboard criado.


Sistema de monitoramento
Este projeto tem o intuito de demonstrar mais algumas possibilidades do
dashboard do Node-RED. Vamos desenvolver um sistema simples de
monitoramento a partir de um conjunto de dados obtidos dos sensores
BMP180 e BH1750 e enviados pelo broker MQTT. Identifique e separe os
seguintes materiais.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
2 Resistores de 10k Ohms (marrom, preto, laranja)
1 Sensor BMP180
1 Sensor BH1750
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 8.32,
caso esteja utilizando o NodeMCU (ESP8266).
Figura 8.32: Conexões (NodeMCU-ESP8266).
Adote como referência a Figura 8.33, se estiver utilizando o NodeMCU
(ESP32).
Em seguida, digite o seguinte programa no ambiente de desenvolvimento
Thonny. Em ❶, note que configuramos o I2C, na sequência o BMP180 e o
BH1750 são conectados logicamente ao barramento. Em ❷ , ❸ e ❹ é
realizada a conexão à rede e em ❺ , ❻ e ❼ fornecemos os dados
necessários (servidor e tópico) para a conexão ao broker (servidor)
MQTT. Lembre-se de em ❺ também ajustar o endereço IP do servidor
para acessar o servidor instalado no seu computador ou o endereço do
ambiente de testes.

Figura 8.33: Conexões (NodeMCU-ESP32).


Prosseguindo com a análise do código-fonte, os dados dos sensores são
obtidos em ❽ , ❾ , ❿ e ⓫ . Em ⓬ , criamos uma cadeia de caracteres em
formatoJSON com esses mesmos dados. Por fim, em ⓭ é realizada a
conexão ao broker, em ⓮ o envio dos dados no tópico selecionado e em ⓯
o encerramento da conexão.
z mqtt-bmp180-bh1750.py
from machine import Pin, I2C
from time import sleep
from bmp180 import BMP180
from bh1750 import BH1750
import network
from umqtt.simple import MQTTClient
import gc
gc.collect()

print('Iniciando...')
i2c = I2C(sda=Pin(5), scl=Pin(4)) ❶
bmp = BMP180(i2c)
bmp.oversample_sett = 2
bmp.baseline = 101325
bh = BH1750(i2c)

estacao = network.WLAN(network.STA_IF) ❷
estacao.active(True) ❸
estacao.connect('ap', 'senha') ❹
while estacao.isconnected() == False:
pass
print('Conexao realizada.')
print(estacao.ifconfig())

servidor = 'test.mosquitto.org' ❺
topico = 'sensor/bmp_bh' ❻
cliente = MQTTClient('NodeMCU', servidor, 1883) ❼
try:
while True:
temperatura = int(bmp.temperature) ❽
ressão = int(bmp.pressure / 100) ❾
altitude = int(bmp.altitude) ❿
luminosidade = int(bh.luminance(BH1750.ONCE_HIRES_1)) ⓫
conteudo = '{"temperatura" : ' + str(temperatura) + ', "pressao" :
'
+ str(pressao) + ', "altitude" : ' + str(altitude) + ',
"luminosidade" : '
+ str(luminosidade) + '}' ⓬
print('Publicando no servidor MQTT')
cliente.connect() ⓭
cliente.publish(topico.encode(), conteudo.encode()) ⓮
cliente.disconnect() ⓯
print ('Envio realizado.')
gc.collect()
sleep(60.0)
except KeyboardInterrupt:
estacao.disconnect()
estacao.active(False)
print("Fim.")
Execute o programa criado em MicroPython e, na sequência, passamos
para o desenvolvimento da aplicação no Node-RED. Conforme ilustra a
Figura 8.34, realize a criação de um fluxo, insira e conecte os nós mqtt in e
debug.

Figura 8.34: Leitura dos dados do broker MQTT.


Dê um clique duplo com o mouse sobre o nó mqtt in para entrar em modo
de edição. Realize a configuração do nó especificando o servidor e o
tópico, conforme podemos notar na Figura 8.35. É importante salientar
que tanto o servidor quanto o tópico deverão ser os mesmos usados no
programa em MicroPython.
Figura 8.35: Configuração do nó mqtt in.
No Node-RED, clique no botão Deploy para executar o fluxo. Os dados
deverão ser exibidos no painel debug de maneira similar ao mostrado na
Figura 8.36.

Figura 8.36: Dados obtidos.


Uma vez que certificamos que os dados já são obtidos do broker MQTT,
iremos realizar a criação da aplicação que usará o módulo dashboard
para criar uma representação gráfica. O primeiro passo consiste em
excluir o nó debug e depois inserir um nó json e quatro nós gauge. Realize a
conexão deles conforme indica a Figura 8.37.

Figura 8.37: Criação do dashboard.


O nó json não precisa ser configurado e ele será responsável pela conversão
dos dados recebidos em objetos JSON. Na sequência dê um clique duplo
sobre o nó gauge que será usado para exibir a temperatura e crie um grupo.
Para isso, selecione na propriedade Group a opção Add new ui_group... e
clique no botão de Edição (ícone do lápis). Na Figura 8.38, devemos notar
que a propriedade Name deve receber o texto Sistema de Monitoramento,
enquanto a propriedade Width irá receber o valor 12. Pressione o botão
Update após concluir a edição do grupo.
Retornando a edição do nó gauge, ajuste as propriedades Size: 6 x 4, Label:
Temperatura, Value format: {{payload.temperatura}}, Units: °C, Range min: 0.e
Range max: 100, conforme mostrado na Figura 8.39.
Figura 8.38: Criação do grupo.
Figura 8.39: Edição do nó gauge.
Repita esse processo para os outros três nós gauge, ajustando devidamente
os valores dos atributos, sendo que a unidade de pressão atmosférica é hPa
e a faixa de valores está entre 300 e 1.100, a altitude é expressa em metros
com valores entre -1.000 e 9.000 e, por último, a luminosidade é expressa
em lux com valores entre 0 e 10.000.
Clique no botão Deploy para executar o fluxo. Abra uma nova aba no
navegador e digite a URL http://localhost:1880/ui. Na Figura 8.40,
apresentamos a exibição do painel de controle (dashboard) que foi criado.
Figura 8.40: Painel de controle.

Armazenamento de dados no MongoDB


Quando usamos um broker MQTT, como o Eclipse Mosquitto,
percebemos que as mensagens são enviadas ao broker e, em seguida,
devem ser lidas por uma aplicação cliente. Note que não há o
armazenamento dos dados. Dessa forma, quando se torna necessário o
armazenamento, devemos utilizar um sistema gerenciador de banco de
dados.
Com o intuito de ilustrar a possibilidade de armazenamento das
mensagens obtidas do broker por uma aplicação cliente, vamos
desenvolver uma aplicação que usará como banco de dados o MongoDB,
que é um banco de dados do tipo NoSQL usando a JSON para realizar o
armazenamento dos dados. Apenas para fins didáticos e com o intuito de
facilitar o entendimento, comparando com um banco de dados relacional,
as tabelas no MongoDB são chamadas de coleções e os registros são
conhecidos como documentos. Mas devemos ter em mente que a
estrutura das coleções e dos documentos não é rígida como a estrutura
das tabelas e registros implementados nos bancos de dados relacionais.
 O MongoDB Community Server é gratuito, multiplataforma e pode ser baixado de
https://www.mongodb.com/download-center/community
Após realizar a instalação e iniciar o serviço, use a interface em linha de
comando do MongoDB. Para isso, acesse o prompt do sistema operacional
e digite mongo. A criação do banco de dados ou o acesso a um banco criado
anteriormente é realizado pelo comando use e o nome do banco de dados,
que neste exemplo será iot. Por último, crie um usuário com acesso ao
banco de dados, conforme podemos observar a seguir.
 mongo
use iot
db.create user( { user:'nodered', pwd:'123456', roles: ['readWrite'] })
O circuito eletrônico e o programa em MicroPython são os mesmos que
usamos no exemplo anterior (Sistema de Monitoramento). Dessa maneira,
podemos ir para o Node-RED e criar um fluxo.
Em seguida, adicione à paleta o módulo node-red-mongodb. Para isso, clique
no menu principal e, em seguida, na opção Manage palette, conforme ilustra a
Figura 8.41.

Figura 8.41: Acesso ao menu do Node-RED.


Em seguida, clique na aba Install (Figura 8.42), procure pelo módulo node-
red-mongodb e clique no botão install. Serão adicionados os nós mongodb in e
mongodb out, que permitirão a comunicação da nossa aplicação com o
MongoDB.
Figura 8.42: Módulo node-red-mongodb.
Coloque no fluxo os nós mqtt in, json, function, mongodb out e debug. Realize a
conexão entre eles da maneira indicada na Figura 8.43.

Figura 8.43: Fluxo.


Após inserir os nós, dê um clique duplo com o mouse sobre o nó mqtt in
para entrar em modo de edição. Realize a configuração do nó
especificando o servidor e o tópico, conforme podemos notar na
Figura 8.44. É importante salientar que tanto o servidor quanto o tópico
deverão ser os mesmos que foram usados no programa em MicroPython
que está em execução no NodeMCU.
O nó json não precisa ser editado, permanecendo com sua configuração
padrão. Coloque o nó function em modo e edição (Figura 8.45).

Figura 8.44: Configuração do nó mqtt in.


Figura 8.45: Edição do nó function.
Observe na propriedade function que em msg.payload vamos receber os
dados lidos do broker MQTT, isto é, temperatura, pressão, altitude e
intensidade luminosa. Em seguida, adicionamos a eles a data e hora
atuais, conforme podemos notar no código-fonte a seguir.
 msg.payload.data_hora = new Date();
return msg.payload;
Vamos passar para a edição do nó mongodb out. Selecione na propriedade
Host o item Add new mongodb... e clique no botão Edição. No painel que foi
aberto, preencha as propriedades Host, Database, Username, Password e Name,
conforme indicado na Figura 8.46.
Figura 8.46: Configuração da conexão ao MongoDB.
De volta ao painel de edição do nó mongodb out, devemos selecionar o
servidor, a coleção e a operação que, neste fluxo, será de inserção
(Figura 8.47).
Por último, edite o nó debug e selecione a opção complete msg object para a
propriedade Output. Com o programa em MicroPython executando no
NodeMCU, faça o Deploy do fluxo e observe na aba debug os dados sendo
recebidos do broker MQTT e inseridos no MongoDB (Figura 8.48).
Figura 8.47: Inserção dos dados no MongoDB.

Figura 8.48: Dados armazenados.


Uma vez que os dados enviados pelo NodeMCU estão armazenados no
banco de dados MongoDB, podemos adicionar ao fluxo que foi criado no
Node-RED um conjunto de nós que irá obter esses dados e mostrar em
uma tabela na Dashboard. Para isso, iremos usar os nós ui_button, mongodb in e
ui_template e conectá-los conforme indicado na Figura 8.49.

Figura 8.49: Consulta aos dados armazenados.


Coloque o nó ui_button no modo de edição e defina a propriedade Size com
o valor 2x1, Icon deve ter o valor fa-refresh e a propriedade Label deverá
conter o valor Atualizar (Figura 8.50).

Figura 8.50: Propriedades do nó ui_button.


Em seguida, entre na edição do nó mongodb in e selecione o mesmo servidor
que foi configurado anteriormente e a mesma coleção, isto é, bmp_bh. A
operação a ser realizada é a de consulta (find), conforme mostra a
Figura 8.51.
A exibição da tabela contendo os dados recuperados da coleção
armazenada do banco de dados se dará por intermédio do nó ui_template
(Figura 8.52). Selecione o grupo e o tamanho 12x18.
Em seguida, a propriedade Template deverá ser preenchida a partir do uso
de elementos HTML e CSS e que serão responsáveis pela construção da
tabela que será mostrada no Dashboard, conforme podemos notar no
código-fonte apresentado a seguir.

Figura 8.51: Configuração da consulta ao MongoDB.


Figura 8.52: Configuração da consulta ao MongoDB.
 <style>
table {
border-spacing: 0px;
}

th, td {
padding: 5px;
}

.titulo {
background-color: #1aa3ff;
color: white;
}

.linha {
background-color: #cce6ff;
}
</style>
<table>
<tr>
<td class='titulo'>Data/Hora</td>
<td class='titulo'>Temperatura</td>
<td class='titulo'>Pressão</td>
<td class='titulo'>Altitude</td>
<td class='titulo'>Luminosidade</td>
</tr>
<tr ng-repeat='(chave, valor) in msg.payload'>
<td ng-if='$even'>{{valor.data_hora
| date:'dd/MM/yyyy hh:mm'}}</td>
<td ng-if='$odd' class='linha'>{{valor.data_hora |
date:'dd/MM/yyyy hh:mm'}}</td>
<td ng-if='$even'>{{valor.temperatura}}°C</td>
<td ng-if='$odd' class='linha'>{{valor.temperatura}}°C</td>
<td ng-if='$even'>{{valor.pressao}} hPa</td>
<td ng-if='$odd' class='linha'>{{valor.pressao}} hPa</td>
<td ng-if='$even'>{{valor.altitude}} m.</td>
<td ng-if='$odd' class='linha'>{{valor.altitude}} m.</td>
<td ng-if='$even'>{{valor.luminosidade}} lux</td>
<td ng-if='$odd' class='linha'>{{valor.luminosidade}} lux</td>
</tr>
</table>
Note na criação da tabela o uso de alguns atributos que começam com o
prefixo ng-; eles são elementos do Angular, que são suportados pelos
componentes gráficos do Node-RED.
 O Angular consiste em uma plataforma de desenvolvimento e um framework para
projeto de aplicações para a web e para dispositivos móveis. Conheça mais em
https://angular.io/.
Após finalizar a configuração dos nós, clique no botão Deploy. Abra uma
nova aba no navegador e digite a URL http://localhost:1880/ui. Note que
nesse fluxo devemos pressionar o botão Atualizar sempre que desejar realizar
a atualização dos dados que estão sendo exibidos na tabela (Figura 8.53).
Figura 8.53: Exibição da tabela.

Comunicação entre serviços


O Node-RED possibilita realizar a integração entre dispositivos e diversos
serviços. Neste projeto, o objetivo é que o NodeMCU envie as informações
de temperatura e umidade, obtida por um sensor DHT11, para um broker
MQTT. No Node-RED, iremos nos conectar ao broker, buscar os dados
publicados e disponibilizá-los em uma página HTML. Vamos utilizar os
seguintes materiais.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Sensor de temperatura e umidade DHT11
1 Protoboard
Cabos de ligação
Realize a montagem da maneira indicada pela Figura 8.54, caso esteja
utilizando o NodeMCU (ESP8266).
Figura 8.54: Conexão do DHT11 ao NodeMCU-ESP8266.
Caso esteja usando o NodeMCU (ESP32), adote a Figura 8.55 como
referência.
No Thonny, implemente o programa mostrado a seguir (mqtt-dht11.py).
Observe no código-fonte que em ❶, ❷ e ❸ realizamos a conexão ao access
point. Em seguida, fornecemos os dados necessários (servidor e tópico)
para a conexão ao broker MQTT, conforme podemos observar em ❹, ❺ e
❻.
z mqtt-dht11.py
import time, network, machine
from dht import DHT11
from machine import Pin
from umqtt.simple import MQTTClient

print("Iniciando...")
dht = DHT11(Pin(12, Pin.IN, Pin.PULL_UP))

estacao = network.WLAN(network.STA_IF) ❶
estacao.active(True) ❷
estacao.connect('ap', 'senha') ❸
while estacao.isconnected() == False:
pass
print('Conexao realizada.')
print(estacao.ifconfig())

print ('Conectando ao servidor MQTT')


servidor = '192.168.100.72' ❹
topico = 'sensor/dht11' ❺
cliente = MQTTClient('NodeMCU', servidor, 1883) ❻
try:
while True:
dht.measure() ❼
temp = dht.temperature() ❽
umid = dht.humidity() ❾
print('Temperatura: %3.1f °C' %temp)
print('Umidade: %3.1f %%' %umid)
conteudo = '{"temperatura" : ' + str(temp) + ', "umidade" : ' +
str(umid) + '}'❿
print ('Conectando ao servidor MQTT')
cliente.connect() ⓫
cliente.publish(topico.encode(), conteudo.encode()) ⓬
cliente.disconnect()
print ('Envio realizado.')
time.sleep(60.0)
except KeyboardInterrupt:
estacao.disconnect()
estacao.active(False)
print("Fim.")
Prosseguindo a análise do código-fonte, os dados do sensor DHT11 são
obtidos em ❼, ❽ e ❾. Os dados são formatados para o formato JSON em
❿ . Por fim, em ⓫ é realizada a conexão ao broker e em ⓬ o envio dos
dados no tópico selecionado.
Na sequência, vamos passar para o desenvolvimento no Node-RED.
Conforme ilustra a Figura 8.56, realize a criação de um fluxo, insira um nó
do tipo mqtt in e outro nó do tipo change. Esses nós consistem na primeira
parte da aplicação no Node-RED e irão obter os dados de temperatura e
umidade do broker MQTT e armazená-los.

Figura 8.55: Conexão do DHT11 ao NodeMCU-ESP32.

Figura 8.56: Obtenção dos dados do broker MQTT.


Realize a configuração do nó mqtt in, definindo o servidor e o tópico,
conforme podemos notar na Figura 8.57.
Em seguida, a Figura 8.58 ilustra como deve ser realizada a configuração
do nó change. Defina o nome do nó como Armazenar dados e defina a regra
(rules) para que a msg.payload seja armazenada (set) na variável
flow.dados. Após realizar as devidas alterações, clique no botão Done.

Figura 8.57: Configuração do nó mqtt in.


Figura 8.58: Configuração do nó change.
No mesmo fluxo, vamos inserir os nós que serão realizados por
disponibilizar os dados recebidos pelo broker MQTT em uma página
web. Note que esses nós, apesar de estarem no mesmo fluxo, não devem
ser conectados aos nós anteriores. Dessa forma, observe na Figura 8.59
que devemos inserir e conectar os nós http in, change, json, template e http response.

Figura 8.59: Enviar dados para a página web.


Com um clique duplo sobre o nó http in entre no painel de edição
(Figura 8.60), defina a propriedade Method com o valor GET e a propriedade
URL com o valor /dht11. Dessa maneira, a página criada será acessível pelo
endereço e porta do Node-RED mais o valor definido na propriedade URL,
por exemplo, http://localhost:1880/dht11.

Figura 8.60: Edição do nó http in.


O próximo nó a ser editado é o change. Nesse nó vamos recuperar o valor
que foi armazenado na variável flow.dados e atribuí-lo à msg.payload para
que esteja disponível no próximo nó que está conectado, que, no nosso
exemplo, é o nó json. Dessa maneira, defina a propriedade Name como
Recuperar dados e defina a regra (rules) para que flow.dados seja
armazenada (set) em msg.payload, conforme ilustra a Figura 8.61.
Figura 8.61: Edição do nó change.
Na sequência, com um clique duplo sobre o nó json entre no painel de
edição (Figura 8.62), selecione a opção Convert between JSON String &
Object da propriedade Action e atribua msg.payload para Property. Lembre-
se de que esse nó é necessário, pois no programa em MicroPython que
desenvolvemos no NodeMCU os dados do sensor DHT11 são enviados
para o broker MQTT em formato JSON.
Na Figura 8.63, temos a edição do nó template. Esse nó irá definir a página
HTML que será exibida pelo navegador.
Figura 8.62: Edição do nó json.
Figura 8.63: Edição do nó template.
Preencha a propriedade Name com o valor ola e Property com msg.payload.
Em Template vamos definir o conteúdo HTML apresentado a seguir.
Observe que, para exibir os dados de temperatura e umidade, devemos
usar {{ payload.temperatura }} e {{ payload.umidade }}.
 <html>
<head>
<title>Olá</title>
</head>
<body>
<h1>Node-RED Olá!</h1>
Temperatura: {{ payload.temperatura }}°C<br>
Umidade relativa do ar: {{ payload.umidade }}%
</body>
</html>
O nó http response não precisa ser editado, então, vamos clicar no botão Deploy
para executar o fluxo. Em seguida, abra uma nova aba no navegador e
digite a URL http://localhost:1880/dht11. Os dados do sensor deverão ser
exibidos na página, conforme ilustra a Figura 8.64.

Figura 8.64: Dados de temperatura e umidade.


capítulo 9

IBM Watson IoT Platform

Neste capítulo abordaremos a utilização do NodeMCU para desenvolver


aplicações aplicando conceitos de Internet da Coisas (IoT – Internet of
Things) usando a Watson IoT Platform da IBM.
Atualmente muitos dispositivos eletrônicos possuem acesso à Internet,
como computadores, tablets, smartphones, televisores e assim por diante.
Além desses exemplos, também temos pequenos dispositivos
microcontrolados que podem ser usados para controlar a iluminação,
portas, janelas e outros elementos de uma residência ou, ainda, para
controlar remotamente a temperatura e umidade de uma estufa, apenas
para citar exemplos bem populares. Em resumo, existe uma infinidade de
possibilidades e aplicações que ilustram o conceito de IoT.
O Watson IoT Platform é um serviço gerenciado, altamente escalável e
hospedado em nuvem, projetado com o intuito de simplificar a conexão,
obtenção de dados e integração de dispositivos para IoT com diversos
tipos serviços.
 Acesse a IBM Cloud (https://cloud.ibm.com/) e crie uma conta de usuário
gratuita. Em seguida, crie os serviços da Plataforma IoT e também o serviço de
banco de dados NoSQL Cloudant, pois eles serão necessários no desenvolvimento
dos projetos apresentados neste capítulo.

Medidor de temperatura e umidade


O circuito eletrônico apresentado a seguir será usado como base para
demonstrar a integração do NodeMCU ao Watson IoT Platform. Vamos
utilizar os seguintes materiais.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Sensor de temperatura e umidade DHT11
1 Protoboard
Cabos de ligação
Realize a montagem da maneira indicada pela Figura 9.1, caso esteja
utilizando o NodeMCU (ESP8266).

Figura 9.1: Conexão do DHT11 ao NodeMCU-ESP8266.


Caso esteja usando o NodeMCU (ESP32), adote a Figura 9.2 como
referência.

Configuração do dispositivo e dos serviços


O objetivo inicial deste projeto é realizar o cadastro do NodeMCU no
Watson IoT, para que seja possível enviarmos os dados do sensor DHT11
para a nuvem. Após a instalação dos serviços, na lista de recursos da
nuvem da IBM (Figura 9.3), escolha Plataforma IoT.

Figura 9.2: Conexão do DHT11 ao NodeMCU-ESP32.


Figura 9.3: Lista de recursos.
Acesse o dashboard do Watson IOT (Figura 9.4) e clique no botão Incluir
dispositivo.

Figura 9.4: Dashboard do Watson IoT.


Conforme ilustra a Figura 9.5, defina o tipo do dispositivo e um ID, que
deverá ser único. Clique no botão Avançar. Na sequência, forneça as
informações solicitadas, utilize a opção para gerar um Token
automaticamente para o dispositivo e avance até concluir a criação.

Figura 9.5: Definição do dispositivo.


O passo seguinte consiste em criar uma chave API para que o dispositivo
possa se conectar à nuvem da IBM. Selecione Aplicativos no menu que está à
esquerda e depois clique no botão Gerar chave API (Figura 9.6).
Figura 9.6: Criação da chave API.
Forneça os dados solicitados e clique no botão Avançar até concluir a
criação. Nesse momento, é muito importante anotar a Chave API e Token
de Autenticação (Figura 9.7), pois essas informações não serão mais
visíveis e, caso sejam perdidas, é necessário excluir a chave e criar uma
nova.

Figura 9.7: Informações da chave API.


Após a criação do dispositivo e da chave API podemos passar para a
criação do programa em MicroPython que irá obter os dados do sensor
DHT11 e publicá-los no MQTT da nuvem da IBM.
 A biblioteca watson_iot que está disponível em
https://github.com/boneskull/micropython-watson-iot deverá ser usada. Faça o
download da pasta watson_iot para o seu computador e utilize o utilitário Ampy
para copiar a pasta e seu conteúdo para o NodeMCU.
Em seguida, no ambiente de desenvolvimento Thonny implemente o
seguinte código-fonte. Analisando o código-fonte observe que é necessário
realizar a conexão a um access point e depois, em ❶ , criamos um
dispositivo a partir das informações de dispositivo e chave API que
criamos no Watson IoT. Em ❷, publicamos na nuvem da IBM os dados de
temperatura e umidade obtidos do DHT11.
z dht11-watson-iot.py
import time, network, machine
from dht import DHT11
from machine import Pin
from watson_iot import Device
import gc
gc.collect()

print("Iniciando...")
dht = DHT11(Pin(12, Pin.IN, Pin.PULL_UP))

estacao = network.WLAN(network.STA_IF)
estacao.active(True)
estacao.connect('ap', 'senha')
while estacao.isconnected() == False:
machine.idle()
print('Conexao realizada.')
print(estacao.ifconfig())

device = Device(
device_id='nodemcu',
device_type='NodeMCU',
token='TOKEN_CRIADO',
org='ID_DE_USUARIO',
username='use-token-auth'
) ❶
try:
while True:
dht.measure()
temp = dht.temperature()
umid = dht.humidity()
print('Temperatura: %3.1f °C' %temp)
print('Umidade: %3.1f %%' %umid)
print ('Conectando a Watson IoT...')
device.connect()
device.publishEvent('dht11', {'temperatura': str(temp),
'umidade': str(umid)}, message_format='json', qos=1) ❷
device.disconnect()
print ('Envio realizado.')
gc.collect()
time.sleep(60.0)
except KeyboardInterrupt:
estacao.disconnect()
estacao.active(False)
print("Fim.")
Deixe o programa executando no Thonny e vá para o dashboard do
Watson IoT; selecione a opção Dispositivos no menu que está à esquerda da
janela. Depois, conforme ilustra a Figura 9.8, identifique o dispositivo e
clique na opção Eventos recentes para visualizar as informações recebidas.
Figura 9.8: Dados recebidos no Watson IoT.
Uma vez que os dados já estão sendo recebidos no Watson IoT, vamos
criar um quadro para exibição dos dados recebidos. No menu lateral da
esquerda, clique na opção Placas. Será mostrado um conjunto customizável
de painéis (Figura 9.9); clique no painel VISÃO GERAL DE UTILIZAÇÃO.

Figura 9.9: Dados recebidos no Watson IoT.


Clique no botão Incluir novo cartão e selecione o tipo de cartão Gráfico de linha. Na
janela seguinte, selecione o dispositivo e clique no botão Avançar. Na janela
seguinte, que deverá ser usada para definir os dados que serão mostrados
no cartão, use o botão Conectar novo conjunto de dados para configurar a exibição
dos dados de temperatura (Figura 9.10).

Figura 9.10: Configuração da exibição da temperatura.


Clique novamente no botão Conectar novo conjunto de dados para configurar a
exibição dos dados de umidade e depois clique em Avançar (Figura 9.11).
Figura 9.11: Configuração da exibição da umidade.
Clique no botão Avançar, escolha o tamanho do gráfico e depois o título e o
esquema de cores do cartão, e, por último, clique no botão Enviar para
concluir a criação. Na Figura 9.12, mostramos um exemplo da aparência
do cartão.
Figura 9.12: Visualização do cartão.
Os dados enviados para o Watson IoT ocorrem por intermédio de um
broker MQTT, disponível no serviço de nuvem da IBM. Dessa forma,
esses dados são mantidos temporariamente. Caso seja necessária a
manutenção de uma série histórica de dados precisamos conectar o
Watson IoT a um serviço de banco de dados.

Armazenamento no IBM Cloudant


O Cloudant é um serviço de banco de dados distribuído e não relacional
(NoSQL), disponível na nuvem da IBM. Neste projeto ele será usado para
armazenar de forma permanente os dados recebidos pelo broker MQTT.
Inicialmente devemos criar uma conexão entre os dois serviços, ou seja,
entre o Watson IoT e o Cloudant.
 Instale no seu computador um programa Client URL (cURL), pois ele será
necessário para realizarmos a criação do conector. O programa está disponível
gratuitamente em https://curl.haxx.se/.
Vamos agora descrever os passos para a criação do conector. No
dashboard do Watson IoT, clique no ícone de ajuda (?) e escolha a opção
API (Figura 9.13).

Figura 9.13: Visualização do cartão.


Em Historian Connectors, clique no botão View APIs, conforme ilustra a
Figura 9.14.

Figura 9.14: Historian Connector APIs.


Utilize o botão Authorize (Figura 9.15) para fornecer a chave API e o token de
autenticação obtidos durante a configuração do Watson IoT.

Figura 9.15: Autorização.


Expanda o painel Services e clique em POST /s2s/services, clique no botão Try it out
para fornecer o JSON contendo a configuração do serviço que será criado,
substituindo as informações de acesso (usuário, senha, servidor e URL)
obtidas durante a configuração do serviço do Cloudant.
 {
"name": "iot-cloudant",
"type": "cloudant",
"credentials": {
"username": "USUARIO",
"password": "SENHA",
"host": "SERVIDOR",
"port": 443,
"url": "URL"
}
}
Clique no botão Execute e copie para a área de transferência o conteúdo
mostrado no campo Curl (Figura 9.16).

Figura 9.16: Comando Curl.


Abra o prompt do seu sistema operacional e execute o comando que foi
copiado para a área de transferência para realizar a criação do serviço.
Anote o ID (do serviço) que será retornado ao término da execução do
comando. Em seguida, expanda o painel Historian Connector, clique em
POST /historianconnectors e depois no botão Try it out para fornecer o JSON que irá
criar e configurar o conector. Não se esqueça de colocar o ID do serviço
que foi criado na etapa anterior.
 {
"name": "iot-cloudant-connector",
"serviceId": "ID_DO_SERVICO",
"type": "cloudant",
"enabled": true
}
Clique no botão Execute, copie para a área de transferência o conteúdo
mostrado no campo Curl, execute o comando no prompt do sistema
operacional e, ao término da execução, anote o ID do conector.
Expanda o painel Destinations, clique em POST /historianconnectors/{connectorId}/destinations
e depois no botão Try it out para digitar o ID do conector e o JSON que irá
criar e configurar o destino.
 {
"name": "default",
"type": "cloudant",
"configuration": {
"bucketInterval": "DAY"
}
}
Clique no botão Execute, copie para a área de transferência o conteúdo
mostrado no campo Curl e execute o comando no prompt do sistema
operacional. A última etapa consiste em criar as regras de
encaminhamento. Para isso, expanda o painel Forwarding Rules, clique em
POST /historianconnectors/{connectorId}/forwardingrules e depois no botão Try it out para
digitar o ID do conector e o JSON.
 {
"name": "iot-cloudant-rule",
"destinationName": "default",
"type": "event",
"selector": {
"deviceType": "NodeMcu",
"eventId": "dht11"
}
}
Clique no botão Execute, copie para a área de transferência o conteúdo
mostrado no campo Curl e execute o comando no prompt do sistema
operacional.
A configuração foi concluída. Agora podemos ir ao dashboard do
Cloudant e observar os dados armazenados no banco de dados
(Figura 9.17).
Figura 9.17: Dados armazenados no Cloudant.
Conforme ilustra a Figura 9.18, ao clicar sobre um documento (item) na
lista, podemos notar os detalhes da estrutura enviada pelo Watson IoT.

Figura 9.18: Detalhes de um documento.


Front-end da aplicação
No Watson IoT, abordamos o envio dos dados do sensor para um broker
MQTT e o armazenamento permanente dos dados no Cloudant. O
último passo em uma aplicação IoT consiste em desenvolver a forma
como o usuário conseguirá visualizar os dados. Umas das alternativas que
vamos adotar neste projeto é desenvolver uma aplicação no Node-RED
que irá obter os dados do Cloudant e os apresentar em uma página web.
Antes de iniciar o Node-RED, instale o conector para o Cloudant. Para
isso, execute o utilitário npm a partir do prompt do sistema operacional.
 npm install node-red-contrib-cloudantplus-selector
Na Figura 9.19, temos a aplicação completa. Observe que iremos usar os
nós http in, cloudantplus-selector in, template, http response, json e debug. Após criar um
fluxo e colocar os nós, realize as devidas ligações.

Figura 9.19: Aplicação em Node-RED.


Neste ponto vamos passar para a configuração dos nós, começando pelo
http in. Para isso, dê um clique duplo sobre ele. Defina a propriedade Method
com o valor GET, a propriedade URL com o valor /watson-iot e pressione o
botão Done para concluir a edição do nó.
Na sequência, passamos para a configuração do nó cloudantplus-selector in.
Comece pelo painel que possibilita a configuração de acesso ao servidor
(Figura 9.20), salientando que essas informações foram obtidas durante a
instalação do serviço na nuvem da IBM. Clique no botão Update após
fornecer os dados para acesso ao servidor.
Figura 9.20: Configuração para acesso ao servidor.
Após a configuração do acesso ao servidor podemos realizar a escolha do
banco de dados e da visão que será usada. Observe na Figura 9.21 que,
nesse caso, vamos usar a visão que irá exibir os dados armazenados
seguindo uma ordem cronológica. Após preencher as propriedades do nó,
clique no botão Done.
O nó json não precisa ser configurado assim como o nó debug. Esses dois,
colocados para fins didáticos para entendermos o formato dos dados
recebidos pelo Node-RED, serão responsáveis pela exibição do resultado
da consulta ao banco de dados no painel de debug, conforme mostra a
Figura 9.22.
Figura 9.21: Escolha do banco de dados e visão.

Figura 9.22: Debug da aplicação.


O próximo nó a ser configurado é o template; ele irá conter a página web,
mostrada a seguir, que deverá ser exibida quando uma requisição for
recebida pelo nó http in.
 <html>
<head>
<title>Watson-IoT</title>
<script>
function formatarData(data) { ❶
var oData = new Date(data);
var dia = oData.getDate();
var mes = oData.getMonth() + 1;
var ano = oData.getFullYear();
var hora = oData.getHours();
var min = oData.getMinutes();
min = ((min < 10) ? '0' + min : min);
return(dia + '/' + mes + '/' + ano + ' ' + hora + ':' + min);
}
</script>
</head>
<body>
<h1>Watson-IoT</h1>
<h2>Dados do Sensor DHT11</h2>
<table border='1' cellspacing='0' cellpadding='5'>
<tr>
<td align='center'>Data/Hora</td>
<td>Temperatura</td>
<td>Umidade</td>
</tr>
{{#payload}} ❷
<tr>
<td align='center'><script>document.write(
formatarData('{{key}}'));</script></td> ❸
<td align='center'>
{{value.data.temperatura}}°C</td> ❹
<td align='center'>
{{value.data.umidade}}%</td> ❺
</tr>
{{/payload}} ❻
</table>
</body>
</html>
Observe em ❶ que definimos uma função para exibir a data no formato
utilizado no Brasil. Depois, em ❷, ❸, ❹, ❺ e ❻, realizamos a exibição dos
dados que estão armazenados no banco de dados Cloudant. Na
Figura 9.23, observamos um exemplo de execução da aplicação criada no
Node-RED após clicar no botão Deploy e realizar a requisição da página a
partir da URL http://localhost:1880/watson-iot.

Figura 9.23: Exemplo da página gerada.


Na página HTML mostrada a seguir, vamos melhorar o aspecto visual da
página, além de torná-la responsiva, com a utilização do framework
Bootstrap.
 <!DOCTYPE html>
<html>
<head>
<title>Watson-IoT</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-
scale=1.0">
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.
min.css">
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.mi
n.js">
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/
popper.min.js">
</script>
<script
src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootst
rap.min.js">
</script>
<script>
function formatarData(data) {
var oData = new Date(data);
var dia = oData.getDate();
var mes = oData.getMonth() + 1;
var ano = oData.getFullYear();
var hora = oData.getHours();
var min = oData.getMinutes();
min = ((min < 10) ? '0' + min : min)
return(dia + '/' + mes + '/' + ano + ' ' + hora + ':' + min);
}
</script>
</head>
<body>
<div class="container">
<div class="jumbotron">
<h1>Watson-IoT</h1>
<h2>Histórico de Temperatura</h2>
</div>
<table class="table table-hover">
<tr class="table-primary">
<td>Data e Hora</td>
<td>Temperatura</td>
<td>Umidade</td>
</tr>
{{#payload}}
<tr>
<td align='center'><script>
document.write(formatarData('{{key}}'));</script>
</td>
<td align='center'>
{{value.data.temperatura}}°C</td>
<td align='center'>
{{value.data.umidade}}%</td>
</tr>
{{/payload}}
</table>
</div>
</body>
</html>
Na Figura 9.24, mostramos um exemplo do aspecto visual da página.

Figura 9.24: Página usando Bootstrap.


 O Node-RED é um dos aplicativos disponíveis na nuvem da IBM. Dessa maneira,
nossos programas (fluxos) desenvolvidos com o Node-RED podem ser facilmente
portados para executar na nuvem.
Vamos disponibilizar o programa criado no Node-RED para executar na
nuvem, possibilitando, dessa forma, que ele seja acessível a partir da
Internet.
Acesse a lista de recursos na nuvem da IBM, clique no botão Criar recurso e
adicione o Node-RED, conforme podemos notar na Figura 9.25.

Figura 9.25: Adicionando o Node-RED.


Após realizar as devidas configurações e anotar as chaves que foram
criadas durante o processo, acesse o Node-RED a partir da URL do Aplicativo
que foi criada durante a instalação, conforme destacado na Figura 9.26.
Figura 9.26: URL do Node-RED na nuvem.
O programa (fluxo) em Node-RED que criamos na instância instalada
localmente no computador pode ser facilmente copiado para a instância
do Node-RED que está executando na nuvem. Na instância local, acesse o
menu principal, que está localizado no canto superior direito da janela, e
escolha a opção Export (Figura 9.27).

Figura 9.27: Opção para exportar o fluxo.


Use o botão Copy to clipboard para copiar o conteúdo do fluxo para a área de
transferência do sistema operacional, conforme ilustrado na Figura 9.28.
Figura 9.28: Opção para exportar o fluxo.
Agora abra a instância do Node-RED que está executando na nuvem,
entre no menu principal, escolha a opção Import e cole o conteúdo que foi
colocado na área de transferência. Para concluir, clique no botão Import
para concluir o processo e clique no botão Deploy para executar o fluxo.
Na Figura 9.29, mostramos o resultado da execução do programa (fluxo)
importado, sendo acessado a partir de um dispositivo móvel. Observe a
característica responsiva da página web, que se ajusta automaticamente a
diferentes tamanhos e resoluções de tela.
Figura 9.29: Execução da aplicação Node-RED na nuvem.

Comandos
Nos projetos anteriores, exploramos o envio de dados obtidos de sensores
para uma plataforma IoT em nuvem. Por outro lado, é possível criar
aplicações que irão, por intermédio do Watson IoT, enviar mensagens
(comandos) para dispositivos como o NodeMCU. Este projeto irá
demonstrar essa possibilidade. Comece identificando e separando os
materiais relacionados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
1 LED (qualquer cor)
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 9.30,
caso esteja utilizando o NodeMCU (ESP8266).

Figura 9.30: Circuito eletrônico (NodeMCU-ESP8266).


Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 9.31
como referência.
 A biblioteca watson_iot que está disponível em
https://github.com/boneskull/micropython-watson-iot deverá ser usada. Faça o
download da pasta watson_iot para o seu computador e utilize o utilitário Ampy
para copiar a pasta e seu conteúdo para o NodeMCU.
No Thonny, implemente o programa mostrado a seguir (led-watson-
iot.py). Após realizar a conexão ao access point, em ❶ definimos a
configuração do dispositivo que irá acessar a nuvem de IBM.
Figura 9.31: Circuito eletrônico (NodeMCU-ESP32).
z led-watson-iot.py
import network, machine
from watson_iot import Device
import gc
gc.collect()

print("Iniciando...")

led = machine.Pin(5, machine.Pin.OUT)

estacao = network.WLAN(network.STA_IF)
estacao.active(True)
estacao.connect('ap', 'senha')
while estacao.isconnected() == False:
machine.idle()
print('Conexao realizada.')
print(estacao.ifconfig())

device = Device(
device_id='nodemcu',
device_type='NodeMCU',
token='TOKEN_CRIADO',
org='ID_DE_USUARIO',
username='use-token-auth'
) ❶
def controle_led(dados): ❷
if 'acao' in dados.keys():
print('LED:', dados['acao'])
led.value(int(dados['acao']))
else:
print ('Chave não encontrada!')

device.set_command('led', controle_led) ❸
device.connect()
try:
while device.is_connected:
device.sync_loop() ❹
gc.collect()
except KeyboardInterrupt:
device.disconnect()
estacao.disconnect()
estacao.active(False)
led.value(0)
print('Fim.')
Prosseguindo com a análise do código-fonte, o passo seguinte consiste em
definir a função de callback, ou seja, a função que deverá ser executada
sempre que uma mensagem for publicada no Watson IoT. Essa função,
neste exemplo, foi chamada de controle_led e está definida em ❷ , sendo
que esta é associada ao dispositivo em ❸ pelo método set_command.
Por último, em ❹ o método sync_loop, que foi implementado dentro de
um laço de repetição que ficará em execução enquanto o dispositivo
permanecer conectado ao ambiente em nuvem, monitora se há mensagens
postadas. Então, quando uma mensagem é identificada, a função de
callback é executada, definindo o estado do LED que está conectado ao
GPIO5.
Mantenha o programa em execução no NodeMCU e, em seguida, acesse o
serviço do Node-RED que está em execução na nuvem da IBM. Crie um
fluxo, entre no menu principal e escolha Manage palette (Figura 9.32).

Figura 9.32: Menu do Node-RED.


Clique na aba Install, procure e instale o módulo node-red-contrib-scx-
ibmiotap. Ele será responsável pela conexão da aplicação Node-RED ao
Watson IoT. Insira e conecte os nós ibmiot in e debug (Figura 9.33). Esses nós
serão usados apenas para que seja possível visualizarmos as mensagens
recebidas no Watson IoT.

Figura 9.33: Nós ibmiot in e debug.


Realize um duplo clique sobre o nó ibmiot in para realizar a configuração do
nó. Selecionar API Key como método de autenticação e clicar no ícone do
lápis do atributo API Key. No novo painel que foi aberto (Figura 9.34),
especifique a API Key, API Token, Server-name e clique no botão Update.
Ao retornar ao painel de edição do nó ibmiot in (Figura 9.35), especifique o
Device Type e o Device Id, conforme definidos na especificação do
dispositivo no Watson IoT. Selecione Command para receber todos (All), QoS
igual a 1 e especifique a propriedade Name do nó. Pressione o botão Done ao
terminar a edição.
No mesmo fluxo, adicione dois nós inject e um nó ibmiot out e os conecte
conforme ilustra a Figura 9.36. Esses nós serão os responsáveis pelo envio
da mensagem ao Watson IoT.

Figura 9.34: Configuração do acesso.


Figura 9.35: Configuração do acesso.

Figura 9.36: Envio da mensagem.


Coloque o nó ibmiot out em modo de edição (Figura 9.37). Selecione API Key
como método de autenticação, usando a mesma API Key criada
anteriormente. No atributo Output Type, selecione Device Command e, na
sequência, especifique o Device Type e o Device Id, conforme definidos na
especificação do dispositivo no Watson IoT.
Figura 9.37: Edição do nó ibmiot out.
O atributo Command Type deverá ser especificado como led, o atributo
Format deverá receber o valor json, a propriedade Data deverá ser
preenchida com msg.payload e o valor 1 deverá ser selecionado para o QoS.
Por fim, defina o valor da propriedade Name e pressione o botão Done para
concluir a configuração do nó.
Em seguida, vamos realizar a edição dos nós inject. Um deles deverá enviar
a mensagem (comando) para acionar o LED, conforme podemos observar
na Figura 9.38. É importante salientar que o atributo Payload deverá conter
a mensagem em formato JSON, isto é, {"acao":"1"}.
Figura 9.38: Configuração do nó Ligar.
Edite o segundo nó inject que terá a função de desligar o LED. Nesse caso,
o atributo Payload deverá conter a mensagem {"acao":"0"} em formato
JSON.
Agora podemos clicar no botão Deploy para executar o fluxo. Selecione o
ícone para debug para poder visualizar a troca de mensagens entre sua
aplicação Node-RED e o Watson IoT (Figura 9.39). Clique nos nós inject
para enviar os comandos que irão ligar ou desligar o LED.
Figura 9.39: Envio e recepção de comandos.

Interação pela internet


Com base nos conceitos desenvolvidos sobre envio e recepção de
comandos entre o NodeMCU e o Watson IoT, podemos utilizar o Node-
RED para desenvolver uma página web que realizará a interface para
envio dos comandos. O circuito eletrônico e o programa em MicroPython
são os mesmos que usamos do projeto anterior.
Acesse o Node-RED na nuvem da IBM e crie um fluxo. Neste fluxo,
mostrado na Figura 9.40, vamos implementar a exibição da página no
navegador pelo nó http in que irá receber a requisição [get] /led.

Figura 9.40: Página da aplicação web.


O nó template irá receber a seguinte página web que implementará os
botões para envio dos comandos para ligar e desligar o LED, por meio de
requisições AJAX:
 <!DOCTYPE html>
<html lang="en">
<head>
<title>NodeMCU IoT</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-
scale=1">
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-
beta.2/css/bootstrap.min.css">
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.mi
n.js">
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.6/umd/
popper.min.js">
</script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-
beta.2/js/bootstrap.min.js">
</script>
<script>
$(document).ready(function(){
$("#on").click(function(){
$.ajax({url: "/led/1",
success: function(result){
$('#on').removeClass('btn-success').addClass('btn-
default');
$('#off').removeClass('btn-default').addClass('btn-
danger');
}});
});

$("#off").click(function(){
$.ajax({url: "/led/0", success: function(result){
$('#on').removeClass('btn-default').addClass('btn-
success');
$('#off').removeClass('btn-danger').addClass('btn-
default');
}});
});
});
</script>
</head>
<body>
<div class="container">
<h1>NodeMCU IoT</h1>
Controle do LED<br /><br />
<div class="btn-group">
<button id="on" type="button"
class="btn btn-success btn-lg">Acender</button><br><br>
<button id="off" type="button"
class="btn btn-default btn-lg">Apagar</button>
</div>
</div>
</body>
</html>
Em seguida, o nó http response irá enviar a página web para o navegador
(cliente) que realizou a requisição. No mesmo fluxo vamos, agora,
implementar os nós que serão responsáveis pela resposta às requisições
AJAX e envio dos respectivos comandos (mensagens) ao Watson IoT.
Observe na Figura 9.41 que será necessário realizar a inserção de dois nós
http in, um deles receberá requisição AJAX [get] /led/1, enquanto o outro
nó irá receber a requisição AJAX [get] /led/0.
Na sequência, coloque dois nós change. Entre na edição de cada um dos nós
e realize a operação Set em msg.payload e defina o comando, em formato
JSON, que será enviado para o Watson IoT, isto é, {"acao":"1"} para um
dos nós e {"acao":"0"} para o outro. Na Figura 9.42, mostramos o exemplo
de edição do nó quando a requisição para ligar o LED for recebida.

Figura 9.41: Resposta às requisições AJAX.


Figura 9.42: Resposta às requisições AJAX.
O nó ibmiot out deverá ser configurado (Figura 9.43). Da mesma maneira que
realizamos no projeto anterior, selecione API Key como método de
autenticação, usando a mesma API Key criada anteriormente. No atributo
Output Type, selecione Device Command e, na sequência, especifique o
Device Type e o Device Id, conforme definidos na especificação do
dispositivo no Watson IoT.
O atributo Command Type deverá ser especificado como led, o atributo
Format deverá receber o valor json, a propriedade Data deverá ser
preenchida com msg.payload e o valor 1 deverá ser selecionado para o QoS.
Por fim, defina o valor da propriedade Name e pressione o botão Done para
concluir a configuração do nó.
Concluindo a aplicação, realize a inserção dos nós template e http response.
Esses dois nós não precisam ser configurados.
Figura 9.43: Edição do nó ibmiot out.
Clique no botão Deploy para executar o fluxo, use o navegador para acessar
a URL que contém a página web que foi criada (Figura 9.44) e utilize os
botões para ligar ou desligar o LED. Lembre-se de que o programa led-
watson-iot.py estará sendo executado no NodeMCU.
Figura 9.44: Página da aplicação web.
capítulo 10

ThingSpeak

Neste capítulo, abordaremos a utilização NodeMCU para desenvolver


aplicações usando conceitos de IoT (Internet of Things – Internet da
Coisas) e a plataforma ThingSpeak.
A ThingSpeak é uma plataforma para IoT de código aberto, sendo
amplamente utilizada para armazenar e recuperar dados de sensores
usando os protocolos HTTP ou MQTT. Além de ser muito simples de
usar, a plataforma provê uma série de aplicativos, gráficos e análises
estatísticas.
 Acesse o site da plataforma ThingSpeak (https://thingspeak.com/) e crie uma
conta de usuário gratuita.

Medidor de temperatura e umidade


O circuito eletrônico apresentado a seguir será usado como base para
demonstrar a integração do NodeMCU à plataforma ThingSpeak. Vamos
utilizar os seguintes materiais.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Sensor de temperatura e umidade DHT11
1 Protoboard
Cabos de ligação
Realize a montagem da maneira indicada pela Figura 10.1, caso esteja
utilizando o NodeMCU (ESP8266).
Caso esteja usando o NodeMCU (ESP32), adote a Figura 10.2 como
referência.

Figura 10.1: Conexão do DHT11 ao NodeMCU-ESP8266.


Figura 10.2: Conexão do DHT11 ao NodeMCU-ESP32.

Canais
Após criar uma conta de usuário e realizar o acesso à plataforma,
devemos criar um canal para realizar o armazenamento dos dados. Para
fazer isso, selecione a opção Channels no menu, depois selecione My Channels e
clique no botão New Channel, conforme ilustra a Figura 10.3.

Figura 10.3: Criação do canal.


O canal a ser criado será chamado de DHT11 e deverá conter a temperatura
no Field 1 e a umidade no Field 2, de acordo com a Figura 10.4. Após
preencher essas informações, clique no botão Save Channel localizado no
rodapé da página.
Figura 10.4: Nome e estrutura do canal.
Ao concluir o processo de criação do canal, será mostrada a página
padrão do canal (Figura 10.5).
Após a criação do canal, precisamos obter as chaves que permitirão
escrever (write) e obter (read) os dados que serão armazenados no canal.
Na página padrão do canal, escolha a opção API Keys e gere uma nova chave
de escrita (write), conforme ilustra a Figura 10.6.
Neste ponto o nosso canal está pronto para receber os dados. Então,
podemos passar para o desenvolvimento do programa em MicroPython
que será responsável por obter as informações de temperatura e umidade
do sensor DHT11 e enviar para o canal implementado na plataforma
ThingSpeak.
Figura 10.5: Exibição do canal.
Figura 10.6: Geração da chave de escrita.
Utilize o Thonny para implementar o seguinte código-fonte. Observe que
utilizamos o protocolo MQTT, já abordado anteriormente, para realizar o
envio dos dados.
z dht11-thing-speak.py
import time, network, machine
from dht import DHT11
from machine import Pin
from umqtt.simple import MQTTClient

print("Iniciando...")
dht = DHT11(Pin(12, Pin.IN, Pin.PULL_UP))

estacao = network.WLAN(network.STA_IF)
estacao.active(True)
estacao.connect('ap', 'senha')
while estacao.isconnected() == False:
machine.idle()
print('Conexao realizada.')
print(estacao.ifconfig())

SERVIDOR = "mqtt.thingspeak.com" ❶
CHANNEL_ID = "COLOQUE_O_ID_DO_CANAL"❷
WRITE_API_KEY = "COLOQUE_A_CHAVE" ❸
topico = "channels/" + CHANNEL_ID + "/publish/" + WRITE_API_KEY ❹
cliente = MQTTClient("umqtt_client", SERVIDOR) ❺
try:
while True:
dht.measure()
temp = dht.temperature()
umid = dht.humidity()
print('Temperatura: %3.1f °C' %temp)
print('Umidade: %3.1f %%' %umid)
conteudo = "field1=" + str(temp) + "&field2=" + str(umid)
print ('Conectando a ThingSpeak...')
cliente.connect() ❻
cliente.publish(topico, conteudo) ❼
cliente.disconnect() ❽
print ('Envio realizado.')
time.sleep(600.0) ❾
except KeyboardInterrupt:
estacao.disconnect()
estacao.active(False)
print("Fim.")
Analisando o programa, em ❶ , ❷ , ❸ e ❹ devemos especificar os dados
para conexão à plataforma ThingSpeak. Em ❺ , o cliente MQTT é criado
e, posteriormente, em ❻ , ❼ e ❽ os dados são publicados no broker
MQTT da ThingSpeak. Em ❾, definimos a frequência de envio que, neste
exemplo, é 600 segundos, isto é, 10 minutos. Na Figura 10.7, temos um
exemplo da visualização dos dados do canal.

Figura 10.7: Visualização dos dados.

TalkBack App
A TalkBack App possibilita o envio de uma fila de comandos para um
dispositivo. O conceito básico é possibilitar o controle remoto e a
execução de ações pela Internet, sem que exista a necessidade de a
aplicação acessar diretamente o dispositivo. O projeto proposto irá
possibilitar ligar ou desligar um determinado equipamento remotamente.
Para isso, iremos utilizar os materiais relacionados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Módulo Relê de 5 Volts
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 10.8,
caso esteja utilizando o NodeMCU (ESP8266).

Figura 10.8: Circuito eletrônico (NodeMCU-ESP8266).


Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 10.9
como referência.
Após realizar a montagem do circuito eletrônico, vamos criar uma
TalkBack. Então, acesse a plataforma ThingSpeak
(https://thingspeak.com/), realize a devida autenticação com o usuário e
senha criados anteriormente. Em seguida, acesse o menu Apps e selecione
TalkBack (Figura 10.10).
Na página exibida no navegador (Figura 10.11), pressione o botão
New TalkBack.
Observe a Figura 10.12. Defina um nome para a TalkBack e anote a API
Key que será usada posteriormente, para que o programa que será
desenvolvido no MicroPython possa acessar a fila de comandos. Note
também que os comandos podem ser gravados em um canal, pela
propriedade Log to Channel. Caso deseje fazer isso, selecione o canal; caso
contrário, não preencha o campo. Clique no botão Save TalkBack para finalizar
a edição do canal.
Figura 10.9: Circuito eletrônico (NodeMCU-ESP32).

Figura 10.10: Menu com as apps.


Figura 10.11: Criação da TalkBack.

Figura 10.12: Configuração da TalkBack.


Podemos usar a própria página que exibe as TalkBacks para criarmos os
comandos. Para isso, apenas clique no botão View (Figura 10.13).
Figura 10.13: TalkBack.
Em seguida, observe a Figura 10.14 e pressione o botão Add a new command.

Figura 10.14: Adicionar comandos.


Neste projeto, na propriedade Command string você deve digitar LIGAR ou
DESLIGAR, clicando no botão Save após cada comando. Observe que a fila de
comandos vai sendo gerada (Figura 10.15).
Figura 10.15: Fila de comandos.
No ambiente de desenvolvimento Thonny, iremos implementar o
programa que deverá monitorar a TalkBack e processar a fila de
comandos. Após realizar a conexão à rede sem fio, em ❶, ❷ e ❸ forneça os
dados necessários para conexão à plataforma ThingSpeak.
Em seguida, em ❹ é realizado o post ao servidor para obter o próximo
comando que, porventura, estiver na fila. Em ❺ , verificamos se há uma
command_string no resultado retornado pelo servidor, pois a fila pode estar
vazia. Caso a verificação resulte em um valor verdadeiro (True),
processamos os comandos que irão ligar ou desligar o relé. Por fim, em ❻
definimos o tempo de espera para que a fila seja consultada novamente.
z talkback-rele.py
from machine import Pin
from time import sleep
import network
import urequests
import ujson
RELE = Pin(5, Pin.OUT)
estacao = network.WLAN(network.STA_IF)
estacao.active(True)
estacao.connect('ap', 'senha')
while estacao.isconnected() == False:
pass
print('Conexao realizada.')
print(estacao.ifconfig())

THINGSPEAK_API = 'api.thingspeak.com' ❶
TALKBACK_ID = 'id_da_talkback' ❷
TALKBACK_API_KEY = 'chave_da_api' ❸
URL = 'http://' + THINGSPEAK_API + '/talkbacks/'
+ TALKBACK_ID + '/commands/execute.json'
CABECALHO = {'content-type': 'application/json'}
DADOS = ujson.dumps({'api_key': TALKBACK_API_KEY})
try:
while True:
result = urequests.post(URL, headers=CABECALHO, data=DADOS).json()

if 'command_string' in result: ❺
if result['command_string'] == 'LIGAR':
RELE.value(1)
elif result['command_string'] == 'DESLIGAR':
RELE.value(0)
sleep(60.0) ❻
except KeyboardInterrupt:
RELE.value(0)
estacao.disconnect()
estacao.active(False)
É importante salientar que cada comando, uma vez processado, é retirado
da fila. Além disso, novos comandos serão sempre inseridos ao final da
fila.
A seguir vamos criar uma aplicação no Node-RED que possibilitará
adicionarmos comandos à fila da TalkBack. Após acessar o Node-RED e
criar um fluxo, adicione os nós inject, function, http request e debug, conectando-os
da maneira indicada na Figura 10.16.
Figura 10.16: Adicionar um comando à fila.
Os nós inject deverão conter na propriedade Payload os comandos LIGAR e
DESLIGAR. O nó function deverá ser editado e deverá conter o código-fonte
mostrado a seguir. Essa função será responsável pela definição do
conteúdo do cabeçalho (msg.headers) e dos dados (msg.payload) que serão
enviados pela requisição web.
 msg.headers = {};
msg.headers['content-type'] = 'application/json';
var dados = {'api_key':'chave_api', 'command_string':msg.payload};
msg.payload = dados;
return msg;
O passo seguinte consiste na edição do nó http request. Observe na
Figura 10.17 que devemos selecionar a opção POST para a propriedade
Method e a propriedade URL deverá conter o endereço da requisição, no
seguinte formato:
http://api.thingspeak.com/talkbacks/id_da_talkback/commands.json.
Conclua a configuração do nó selecionando a opção a parsed JSON object
para a propriedade Return.
Figura 10.17: Edição do nó http request.
Mantenha o programa em MicroPython (talkback-rele.py) em execução
no NodeMCU e clique no botão Deploy para executar o fluxo. Ao clicar nos
nós inject o respectivo comando será adicionado à fila da TalkBack.
Com base nesses conceitos podemos criar uma aplicação completa, onde
será implementada uma página web que possibilitará a adição dos
comandos. Adicione um fluxo no Node-RED, realize a inserção dos nós
http in, switch, function, http request, debug, template e http response, realizando as conexões
da maneira ilustrada na Figura 10.18.

Figura 10.18: Aplicação completa.


Em seguida, realize a edição do nó http in selecionando GET para o atributo
Method e definindo o atributo URL com o valor /talkback.
O próximo nó a ser configurado será o switch. Ele será responsável por
escolher se a página da aplicação será carregada quando o nó http in não
receber parâmetros ou se irá processar os dados enviados por meio de
uma chamada AJAX que irá enviar os dados que serão colocados,
posteriormente, na fila de comandos da talkback. Para isso, observe na
Figura 10.19 que iremos definir uma regra quando a mensagem recebida
(msg.payload) possuir dados (is not empty) e outra regra quando a
mensagem estiver vazia (is empty).

Figura 10.19: Edição do nó switch.


O nó template, conectado à regra is not empty, deverá ser deixado sem
conteúdo, isto é, a propriedade Template deverá ser deixada vazia, pois,
nesse caso, apenas o cabeçalho será enviado à aplicação cliente, indicando
que a chamada AJAX foi bem-sucedida. O segundo nó template que, nesse
caso, está conectado à regra is empty, deverá implementar a seguinte
página HTML, que consiste na interface da nossa aplicação.
 <!DOCTYPE html>
<html lang="en">
<head>
<title>TalkBack</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-
scale=1">
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.
min.css">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/poppe
r.min.js">
</script>
<script
src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootst
rap.min.js">
</script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/
gitbrent/[email protected]/css/bootstrap4-toggle.min.css" >
<script src="https://cdn.jsdelivr.net/gh/
gitbrent/[email protected]/js/bootstrap4-toggle.min.js"></script>
<script>
$(document).ready(function(){
$("#comando").change(function() {
$.ajax({
url: "/talkback",
method: "GET",
data: { command_string : ($("#comando").prop("checked")
=== true? "LIGAR": "DESLIGAR") },
dataType: "html",
success: function(result){}
});
});
});
</script>
</head>
<body>
<div class="container">
<div class="jumbotron">
<h1>TalkBack</h1>
MicroPython, NodeMCU e ThingSpeak<br /><br />
</div>
<input id="comando" type="checkbox" data-onstyle="success"
data-toggle="toggle" data-size="large">
</div>
</body>
</html>
O nó http response, no qual os dois nós templates são conectados, não precisa
ser editado, mantendo sua configuração padrão. Vamos agora editar o nó
function que está conectado à regra is not empty do nó switch. Adicione o
código-fonte mostrado a seguir. Essa função será responsável pela
definição do conteúdo do cabeçalho (msg.headers) e dos dados
(msg.payload) que serão enviados pela requisição web.
 msg.headers = {};
msg.headers['content-type'] = 'application/json';
var dados = {'api_key':'chave_api',
'command_string':msg.payload.command_string};
msg.payload = dados;
return msg;
O passo seguinte consiste na edição do nó http request. Observe na
Figura 10.20 que devemos selecionar a opção POST para a propriedade
Method e a propriedade URL deverá conter o endereço da requisição, ou seja:
http://api.thingspeak.com/talkbacks/id_da_talkback/commands.json.
Conclua a configuração do nó selecionando a opção a parsed JSON object
para a propriedade Return.
Figura 10.20: Edição do nó http request.
O nó debug não precisa ser editado, mantendo, dessa maneira, sua
configuração padrão. Mantenha o programa em MicroPython (talkback-
rele.py) em execução no NodeMCU e clique no botão Deploy para executar
o fluxo. No navegador, use a URL na qual o Node-RED está sendo
executado seguida por /talkback para acessar a aplicação (Figura 10.21).
Clique no botão para enviar os comandos de LIGAR ou DESLIGAR para a fila
de comandos na TalkBack.
Figura 10.21: Página da aplicação.
capítulo 11

IFTTT

IFTTT (If This Then That) é um serviço baseado na Internet que


possibilita a criação de instruções condicionais simples, que são
chamadas de applets. Esse serviço funciona como “receitas” (em uma
analogia com as ações que devem ser feitas com ingredientes),
combinando comandos (“se acontecer isso”) e ações (“então faça aquilo”).
Um applet é acionado por eventos (triggers) que são gerados por
dispositivos ou serviços disponíveis na Internet. Com o intuito de
entender como o IFTTT atua, vamos descrever os seguintes conceitos:
• Serviços: Descrevem uma série de dados de um determinado serviço da
web ou descrevem ações controladas por APIs.
• Gatilhos (Triggers): Equivalem ao "this" de um applet. Consistem nos
eventos que irão desencadear uma ação.
• Ações: São a parte "that" do applet.
• Applets: Consistem em regras condicionais formadas a partir de
gatilhos e ações.
• Ingredientes: Podem ser entendidos como dados disponíveis nos
gatilhos e ações.

Inserção de dados em uma planilha


O projeto a seguir irá demonstrar uma das inúmeras possibilidades de
integração entre NodeMCU e o IFTTT. Nesse caso, será realizada a
inserção dos dados obtidos de um sensor barométrico BMP180 em uma
planilha no Google Drive.
 Crie uma conta de usuário gratuita no IFTTT (ifttt.com) e outra no Gmail
(gmail.com).
Vamos criar o applet no IFTTT; dessa forma, acesse e faça login no
serviço. Em seguida, no menu (Figura 11.1) que está localizado no canto
direito superior da janela, escolha Create.

Figura 11.1: Menu.


Clique em +This (Figura 11.2) para realizar a seleção do serviço que será
utilizado pelo applet.

Figura 11.2: Criação do applet.


Na janela que será exibida, localize o serviço Webhooks, conforme ilustra a
Figura 11.3.
Figura 11.3: Seleção do serviço.
Em seguida, escolha o tipo de gatilho que será usado. Dessa maneira,
selecione Receive a web request (Figura 11.4).

Figura 11.4: Escolha do gatilho.


Após a escolha do gatilho, devemos definir um nome para o evento que,
neste projeto, será leitura_bmp180. Depois, clique no botão Create trigger para
finalizar o processo de criação (Figura 11.5).

Figura 11.5: Definição do nome do evento.


Na sequência, clique em +That (Figura 11.6) para iniciarmos a configuração
da ação que deverá ser realizada pelo applet.
Figura 11.6: Configuração da ação.
Observe na Figura 11.7 que devemos selecionar o serviço Google Sheets.

Figura 11.7: Seleção do serviço.


Prosseguindo com a criação do applet, será necessário escolher a ação que
deverá ser realizada na planilha (Figura 11.8). Escolha a opção
Add row to spreadsheet.

Figura 11.8: Escolha da ação.


Na Figura 11.9, devemos configurar a planilha a ser criada. Basicamente,
apenas defina um nome para a planilha, sendo que as demais informações
podem ser deixadas da forma sugerida.
Figura 11.9: Configuração da planilha.
Concluindo a criação do applet, defina um nome e clique no botão Finish
(Figura 11.10).
Figura 11.10: Nome do applet.
Após a criação do applet no IFTTT, separe os seguintes materiais para
realizar a montagem do circuito eletrônico:
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Sensor BMP180
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 11.11,
caso esteja utilizando o NodeMCU (ESP8266).
Figura 11.11: Conexões (NodeMCU-ESP8266).
Adote como referência a Figura 11.12, se estiver utilizando o NodeMCU
(ESP32).
Figura 11.12: Conexões (NodeMCU-ESP32).
 A biblioteca bmp180 possibilita o uso no sensor barométrico no MicroPython e está
disponível em: https://github.com/micropython-IMU/micropython-bmp180.
Realize o download do arquivo bmp180.py para o seu computador.
Antes de implementar o programa, utilize o utilitário Ampy para copiar a
biblioteca para o sistema de arquivos do NodeMCU. Troque a porta com6,
mostrada no comando a seguir, para a porta na qual o NodeMCU está
conectado ao seu computador.
 ampy --port com6 put bmp180.py
Em seguida, use o ambiente de desenvolvimento Thonny para
implementar o programa apresentado a seguir. Use a opção My Services
existente no menu do IFTTT, acesse WebHooks e clique no botão Documentation
para obter a URL e a chave do serviço, lembrando que o nome do gatilho
foi definido durante a criação do applet.
z ifttt-bmp180-planilha.py
import network
import urequests
import ujson
from machine import Pin, I2C, SPI
from time import sleep
from bmp180 import BMP180

estacao = network.WLAN(network.STA_IF)
estacao.active(True)
estacao.connect('ap', 'senha')
while estacao.isconnected() == False:
pass
print('Conexao realizada.')
print(estacao.ifconfig())

WEBHOOKS_URL = 'http://maker.ifttt.com/trigger/
NOME_GATILHO/with/key/
SUA_CHAVE_DO_WEBHOOKS' ❶
CABECALHO = {'content-type': 'application/json'} ❷
i2c = I2C(sda=Pin(5), scl=Pin(4))
bmp = BMP180(i2c) # 0x77
bmp.oversample_sett = 2
bmp.baseline = 101325

try:
while True:
temperatura = str(bmp.temperature).replace('.', ',')
pressao = str(bmp.pressure / 100).replace('.', ',')
altitude = str(bmp.altitude).replace('.', ',')
DADOS = {'value1': temperatura, 'value2': pressao, 'value3':
altitude} ❸
resp = urequests.post(WEBHOOKS_URL, headers=CABECALHO, json=DADOS)
if resp is not None and resp.status_code < 400:
print('Webhook: Sucesso:')
else:
print('Webhook: Falhou.')
sleep(600.0)
except KeyboardInterrupt:
estacao.disconnect()
estacao.active(False)
Analisando o código-fonte, observe que em ❶ e ❷ realizamos a
configuração da URL e do cabeçalho. Posteriormente, em ❸ preparamos
os dados, em formato JSON, para envio.
Na Figura 11.13, temos um exemplo dos dados enviados pelo NodeMCU
para o applet que, por sua vez, insere na planilha do Google Drive.

Figura 11.13: Dados recebidos na planilha.

Envio de notificações por e-mail


Neste projeto vamos criar um applet no IFTTT que irá enviar um e-mail
sempre que a temperatura obtida pelo sensor barométrico BMP180
ultrapassar um determinado valor.
Em primeiro lugar, vamos criar o applet no IFTTT. Após acessar o serviço,
vá até o menu (Figura 11.14) que está localizado no canto direito superior
da janela e escolha Create.
Figura 11.14: Menu.
Clique em +This (Figura 11.15) para realizar a seleção do serviço que será
utilizado pelo applet.

Figura 11.15: Criação do applet.


Na janela que será exibida, localize o serviço Webhooks, conforme ilustra a
Figura 11.16.

Figura 11.16: Seleção do serviço.


Em seguida, escolha o tipo de gatilho que será usado. Para isso, selecione
Receive a web request (Figura 11.17).
Figura 11.17: Escolha do gatilho.
Após a escolha do gatilho devemos definir um nome para o evento que,
neste projeto, será temperatura_elevada. Depois, clique no botão Create trigger
para finalizar o processo de criação (Figura 11.18).

Figura 11.18: Nome do evento.


Na sequência, clique em +That (Figura 11.19) para iniciarmos a configuração
da ação que deverá ser realizada pelo applet.

Figura 11.19: Configuração da ação.


Observe na Figura 11.20 que devemos selecionar o serviço Email.

Figura 11.20: Escolha do serviço.


Na próxima página que será mostrada no navegador, escolha a opção Send
me an email e, em seguida, ocorrerá a formatação do título e conteúdo do
email, conforme ilustrado pela Figura 11.21.

Figura 11.21: Formatação do email.


Finalizando a criação do applet, defina um nome e clique no botão Finish
(Figura 11.22).

Figura 11.22: Conclusão da criação do applet.


O circuito eletrônico usado será o mesmo do projeto anterior, consistindo
na conexão do BMP180 ao NodeMCU. Antes de implementar o programa,
utilize o utilitário Ampy para copiar o arquivo bmp180.py para o sistema de
arquivos do NodeMCU. Troque a porta com6, mostrada no comando a
seguir, para a porta na qual o NodeMCU está conectado ao seu
computador.
 ampy --port com6 put bmp180.py
Em seguida, use o ambiente de desenvolvimento Thonny para
implementar o programa apresentado a seguir. Use a opção My Services
existente no menu do IFTTT, acesse WebHooks e clique no botão Documentation
para obter a URL e a chave do serviço, lembrando que o nome do gatilho
foi definido durante a criação do applet.
z ifttt-bmp180-email.py
import network
import urequests
import ujson
from machine import Pin, I2C, SPI
from time import sleep
from bmp180 import BMP180

estacao = network.WLAN(network.STA_IF)
estacao.active(True)
estacao.connect('ap', 'senha')
while estacao.isconnected() == False:
pass
print('Conexao realizada.')
print(estacao.ifconfig())

WEBHOOKS_URL = 'http://maker.ifttt.com/trigger/
NOME_GATILHO/with/key/
SUA_CHAVE_DO_WEBHOOKS'
CABECALHO = {'content-type': 'application/json'}

i2c = I2C(sda=Pin(5), scl=Pin(4))


bmp = BMP180(i2c) # 0x77
bmp.oversample_sett = 2
bmp.baseline = 101325

try:
while True:
if bmp.temperature > 20.0: ❶
temperatura = str(bmp.temperature).replace('.', ',')
pressao = str(bmp.pressure / 100).replace('.', ',')
altitude = str(bmp.altitude).replace('.', ',')
DADOS = {'value1': temperatura, 'value2': pressao, 'value3':
altitude}
resp = urequests.post(WEBHOOKS_URL, headers=CABECALHO,
json=DADOS)
if resp is not None and resp.status_code < 400:
print('Webhook: Sucesso:')
print (DADOS)
else:
print('Webhook: Falhou.')
sleep(600.0)
except KeyboardInterrupt:
estacao.disconnect()
estacao.active(False)
Observe que o programa é muito parecido com aquele que foi
desenvolvido no projeto anterior, sendo que a diferença consiste no fato
de que a requisição é enviada ao IFTTT somente quando a temperatura
ultrapassa 20°C, conforme é indicado em ❶ . Na Figura 11.23, mostramos
um exemplo de email recebido por intermédio do applet que foi criado.

Figura 11.23: Email recebido.


capítulo 12

Interrupções, temporizadores e threads

Dependendo das características de um projeto, podemos deparar com a


necessidade de realizar a execução simultânea de processos (rotinas) ou
eliminar algum processo de forma involuntária (devido a algum evento).
No MicroPython existem diversos recursos que irão permitir a aplicação
desse conceito e vamos desenvolver alguns projetos que irão explorar as
possibilidades.

Sensor de presença
Neste projeto, vamos aplicar o conceito de interrupção criando um
sistema de alarme usando um sensor de presença infravermelho (PIR) e
um módulo relê, que poderá disparar uma campainha quando o sensor
for acionado.
Observe que a interrupção será gerada quando ocorrer uma mudança de
estado no sensor que irá, por sua vez, alterar o estado do pino em que a
interrupção foi programada.
As interrupções permitem que uma rotina seja executada em paralelo ao
programa principal quando ocorre um evento predeterminado. Os
materiais necessários para a montagem do projeto estão relacionados a
seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Módulo relê
1 Sensor de Presença Infravermelho (PIR)
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 12.1,
caso esteja utilizando o NodeMCU (ESP8266).

Figura 12.1: Montagem do circuito (NodeMCU-ESP8266).


Por outro lado, se estiver usando o NodeMCU (ESP32), adote a Figura 12.2
como referência.
No Thonny, implemente o código-fonte apresentado a seguir (pir-rele.py).
Observe em ❶ que ativamos a interrupção para o pino no qual o sensor
de movimento foi conectado, realizando a definição do evento (trigger) e
da função (handler) que deverá ser executada.
Figura 12.2: Montagem do circuito (NodeMCU-ESP32).
z pir-rele.py
from machine import Pin
from time import sleep

movimento = False

def movimento_detectado(pino): ❷
global movimento
movimento = True

rele = Pin(5, Pin.OUT)


pir = Pin(4, Pin.IN)
pir.irq(trigger=Pin.IRQ_RISING, handler=movimento_detectado) ❶
try:
while True:
if movimento:
print('Movimento detectado!')
rele.value(1)
sleep(5.0)
rele.value(0)
movimento = False
except KeyboardInterrupt:
rele.value(0)
print('Fim!')
Prosseguindo a análise do programa, em ❷ a função movimento_detectado
irá definir a variável global movimento com o valor verdadeiro. Dessa forma,
o programa principal irá acionar o relê por 5 segundos e, após esse tempo,
atribuir o valor falso para a variável movimento.

Matriz de LEDs
As matrizes de LEDs são largamente empregadas em letreiros e outros
dispositivos de sinalização. Os modelos mais populares e acessíveis são as
matrizes de LEDs de 8 linhas por 8 colunas, sendo que os módulos
podem ser interconectados possibilitando uma ampla área de exibição.
Neste projeto iremos usar um módulo de matriz de LEDs de 8x8 com
4 dígitos para ilustrar o uso de threads no NodeMCU. Os materiais
necessários para a montagem do projeto estão relacionados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Módulo Matriz de LEDs de 8x8 com 4 dígitos
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 12.3,
caso esteja utilizando o NodeMCU (ESP8266).
Caso utilize o NodeMCU (ESP32), a Figura 12.4 deverá ser adotada como
referência para a montagem do projeto.

Figura 12.3: Montagem do circuito (NodeMCU-ESP8266).


 A biblioteca MAX7219 deverá ser usada e está disponível em
https://github.com/mcauser/micropython-max7219. Faça o download do
arquivo max7219.py para o seu computador e, em seguida, utilize o utilitário ampy
para copiar o arquivo para o NodeMCU.
No Thonny, implemente o programa apresentado a seguir (m8x8-
mensagem.py).Observe que em ❶ e ❷ realizamos a configuração da
interface SPI que é utilizada pelo módulo matriz de LEDs. Em ❸ é
definido o objeto display. Note que no último parâmetro deve ser
indicado o número de matrizes que o módulo possui.
Em ❹, é realizada a digitação do texto. Por fim, é realizada a exibição com
rolagem (scroll) do texto na matriz de LEDs.

Figura 12.4: Montagem do circuito (NodeMCU-ESP32).


z m8x8-mensagem.py
from max7219 import Matrix8x8
from machine import Pin, SPI
from time import sleep

spi = SPI(sck=Pin(14), mosi=Pin(13), miso=Pin(12)) ❶


cs = Pin(15, Pin.OUT) ❷
display = Matrix8x8(spi, cs, 4) ❸
try:
while True:
mensagem = ' ' + input('Digite a mensagem: ') ❹
for i in range(len(mensagem)):
display.text(mensagem[i:i+4], 0, 0, 1)
display.show()
sleep(0.5)
display.fill(False)
display.show()
except KeyboardInterrupt:
display.fill(False)
display.show()
spi.deinit()
Observe que, nesse caso, só será permitida a digitação de um novo texto
após o término da exibição do texto anterior na matriz de LEDs. Podemos
contornar esse tipo de situação utilizando o conceito de thread, que irá
possibilitar que o texto a ser exibido seja modificado mesmo durante a
exibição da mensagem que foi digitada anteriormente. No programa
apresentado a seguir, iremos demonstrar a utilização de thread em
MicroPython.
z m8x8-mensagem-thread.py
from max7219 import Matrix8x8
from machine import Pin, SPI
from time import sleep
import _thread

spi = SPI(sck=Pin(14), mosi=Pin(13), miso=Pin(12))


cs = Pin(15, Pin.OUT)
display = Matrix8x8(spi, cs, 4)
mensagem = ' ?'
posicao = 0
fim = False

def exibir_mensagem():❶
global posicao, mensagem, fim
try:
while fim == False:
while posicao < len(mensagem) and fim == False:
display.text(mensagem[posicao: posicao+4], 0, 0, 1)
display.show()
posicao = posicao + 1
sleep(0.5)
display.fill(False)
display.show()
posicao = 0
except:
fim = True

try:
_thread.start_new_thread(exibir_mensagem, ()) ❷
while True:
mensagem = ' ' + input('Digite a mensagem: ')
posicao = 0
except:
fim = True
display.fill(False)
display.show()
spi.deinit()
Observe em ❶ que a função exibir_mensagem irá mostrar o texto na matriz
de LEDs realizando a rolagem (scroll). Essa função será executada em ❷ a
partir de uma thread, isto é, irá funcionar de modo paralelo à rotina
principal que é executada na instrução while. Dessa maneira, enquanto o
texto é rolado na matriz de LEDs, também é possível digitar a nova
mensagem a ser exibida e, quando a tecla Enter é pressionada, o conteúdo
é imediatamente atualizado na matriz de LEDs.
Web-Clock
O objetivo deste projeto é demonstrar o uso do conceito de
temporizadores (timers) a partir da construção de um relógio, que irá se
sincronizar com a World Time API, já usada anteriormente, de modo a
manter o horário exibido sempre atualizado. Observe que os
temporizadores podem ser programados para executar uma função
depois de um determinado tempo ou em intervalos regulares. Os
materiais necessários para a montagem do projeto são mostrados a seguir.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Módulo Matriz de LEDs de 8x8 com 4 dígitos
1 Protoboard
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 12.5,
caso esteja utilizando o NodeMCU (ESP8266).
Figura 12.5: Montagem do circuito (NodeMCU-ESP8266).
Caso utilize o NodeMCU (ESP32), a Figura 12.6 deverá ser adotada como
referência para a montagem do projeto.
 A biblioteca MAX7219 deverá ser usada e está disponível em
https://github.com/mcauser/micropython-max7219. Faça o download do
arquivo max7219.py para o seu computador e, em seguida, utilize o utilitário ampy
para copiar o arquivo para o NodeMCU.
Figura 12.6: Montagem do circuito (NodeMCU-ESP32).
No Thonny, implemente o programa apresentado a seguir (m8x8-
relogio.py). A função conectar_wlan, definida em ❶ , irá realizar a conexão
à rede sem fio. Em ❷ , temos a função sincronizar_relogio que utilizará a
World Time API para obter a data e hora atuais e atualizar o relógio de
tempo real (RTC) do NodeMCU. Na sequência do programa, as funções
mostrar_hora e mostrar_dois_pontos são usadas para formatar a hora que
será exibida na matriz.
Em ❸ , definimos o timer (temporizador) que será usado para sincronizar
periodicamente o relógio de tempo real com o serviço da Internet. Em ❹ ,
definimos os parâmetros do temporizador, ou seja, nesse programa a
função sincronizar_relogio será executada a cada 7.200.000 ms, ou seja,
2 horas.
z m8x8-relogio.py
from max7219 import Matrix8x8
from machine import Pin, SPI, RTC, Timer
from time import sleep
import network
import urequests
import utime

spi = SPI(sck=Pin(14), mosi=Pin(13),


miso=Pin(12))
cs = Pin(15, Pin.OUT)
display = Matrix8x8(spi, cs, 4)
rtc = RTC()
agora = utime.ticks_ms()

def conectar_wlan(): ❶
global estacao
estacao = network.WLAN(network.STA_IF)
estacao.active(True)
estacao.connect('ap', 'senha')
while estacao.isconnected() == False:
pass
print('Conexao realizada.')
print(estacao.ifconfig())

def desconectar_wlan():
global estacao
estacao.active(False)

def sincronizar_relogio(): ❷
global anterior
conectar_wlan()
url = "http://worldtimeapi.org/api/timezone/America/Sao_Paulo"
resposta = urequests.get(url)
if resposta.status_code == 200:
#print("JSON:", resposta.text)
json = resposta.json()
agora = str(json["datetime"])
ano = int(agora[0:4])
mes = int(agora[5:7])
dia = int(agora[8:10])
hora = int(agora[11:13])
minuto = int(agora[14:16])
segundo = int(agora[17:19])
subsegundo = int(round(int(agora[20:26]) / 10000))
# Atualizar o RTC do NodeMCU
rtc.datetime((ano, mes, dia, 0, hora, minuto, segundo, subsegundo))
print('RTC atualizado:', *rtc.datetime())
else:
print('Atenção: RTC não atualizado!')
desconectar_wlan()
anterior = ''

def limpar():
display.fill(False)
display.show()

def mostrar_hora(digito):
display.text(digito[0], 0, 0, 1)
display.text(' ' + digito[1], -1, 0, 1)
display.text(' ' + digito[3], +1, 0, 1)
display.text(' ' + digito[4], 0, 0, 1)
display.show()

def mostrar_dois_pontos(ponto):
display.pixel(15, 1, ponto)
display.pixel(15, 2, ponto)
display.pixel(16, 1, ponto)
display.pixel(16, 2, ponto)
display.pixel(15, 4, ponto)
display.pixel(15, 5, ponto)
display.pixel(16, 4, ponto)
display.pixel(16, 5, ponto)
display.show()

ponto = True
anterior = ''
sincronizar_relogio()
try:
timer = Timer(-1) ❸
# 2 horas: 7200000ms
timer.init(period=7200000, mode=Timer.PERIODIC,
callback=lambda t:sincronizar_relogio()) ❹
while True:
horario = "{4:02d}:{5:02d}".format(*rtc.datetime())
if horario != anterior:
limpar()
mostrar_hora(horario)
mostrar_dois_pontos(ponto)
anterior = horario
ponto = not ponto
sleep(0.5)
except KeyboardInterrupt:
limpar()
timer.deinit()
spi.deinit()

Deep sleep
Este projeto tem como objetivo exemplificar o uso da prática de deep
sleep, que consiste em economizar no consumo de energia elétrica em
dispositivos embarcados. Usualmente projetos com microcontroladores se
utilizam de fontes de energia finitas, como baterias. Portanto, em
determinado momento podemos fazer com que nosso dispositivo
"hiberne" quando não precisar mais fazer alguma tarefa, promovendo
uma economia no consumo de bateria.
Uma vez que o dispositivo esteja em estado de hibernação, devemos
implementar alguma maneira de acordá-lo. Nesse projeto a seguir,
faremos com que o dispositivo desperte dando um reset, e fazendo com
que o programa retorne assim que seja feito o seu boot.
 Relação de materiais
1 NodeMCU (ESP8266 ou ESP32)
1 Resistor de 220 Ohms (vermelho, vermelho, marrom) ou 330 Ohms
(laranja, laranja, marrom)
2 Resistores de 10k Ohms (marrom, preto, laranja)
1 LED (qualquer cor)
2 Chaves tácteis
Cabos de ligação
Em seguida, realize a montagem da maneira indicada pela Figura 12.7,
caso esteja utilizando o NodeMCU (ESP8266).
Figura 12.7: Montagem do circuito (NodeMCU-ESP8266).
Caso utilize o NodeMCU (ESP32), a Figura 12.8 deverá ser adotada como
referência para a montagem do projeto.
No Thonny, implemente o programa apresentado a seguir (deep_sleep.py).
A função pressionou_dormir, definida em ❶, será chamada quando a chave
táctil for pressionada. Em ❷, vemos os parâmetros de chamada da função
pressionou_dormiu. Essa função faz com que a variável pressionada mude
de valor, fazendo com que a linha indicada em ❸ execute a função
deepsleep, fazendo com que o dispositivo hiberne. Será possível notar que
o piscar do led irá cessar e aparecerá a mensagem "Dormindo..." antes da
hibernação.

Figura 12.8: Montagem do circuito (NodeMCU-ESP32).


z deep_sleep.py
import machine
from machine import Pin
from time import sleep

pressionou = False

def pressionou_dormir(pino): ❶
global pressionou
pressionou = True

led = Pin (4, Pin.OUT)


botao = Pin(2, Pin.IN)
botao.irq(trigger=Pin.IRQ_RISING, handler=pressionou_dormir) ❷
try:
while True:
led.value(1)
sleep(0.5)
led.value(0)
sleep(0.5)
if pressionou:
led.value(0)
print('Dormindo...')
machine.deepsleep() ❸
except KeyboardInterrupt:
led.value(0)
print('Fim!')
Note que na montagem do circuito no NodeMCU (ESP8266) há uma
chave táctil conectada ao pino RST e no NodeMCU (ESP32) está
conectada ao pino EN. Em ambos os casos, ao ser pressionada, essa chave
irá ativar novamente a placa, executando o arquivo boot.py, que é o
programa inicial em nossa placa. Para que o nosso programa seja
reiniciado no momento que reativamos a placa, precisamos inserir uma
chamada do arquivo de nosso programa em uma linha do boot.py.
Supondo que nosso arquivo de código seja o deep_sleep.py, insira essa
linha ao final do código presente em boot.py e salve.
 Import deep_sleep
Isso fará com que seu programa seja executado toda vez que a placa for
reinicializada. Abaixo a Figura 12.9 mostra um exemplo da inserção da
linha no boot.py.
Figura 12.9: Exemplo de alteração no boot.py
Para alterar novamente o boot.py, fazendo com que ele volte na
configuração anterior, basta encerrar o programa deep_sleep.py, abrir
novamente o boot.py e remover a linha que foi adicionada e salvar.

Você também pode gostar