SISTEMA DE CONTROLE DE ACESSO A RECURSOS … · 2019. 9. 24. · criação de usuários via Web por...
Transcript of SISTEMA DE CONTROLE DE ACESSO A RECURSOS … · 2019. 9. 24. · criação de usuários via Web por...
SISTEMA DE CONTROLE DE ACESSO A RECURSOS
COMPARTILHADOS
Felipe Campos De Leo
Projeto de Graduação apresentado ao Curso de
Engenharia Eletrônica e de Computação da Escola
Politécnica, Universidade Federal do Rio de
Janeiro, como parte dos requisitos necessários à
obtenção do título de Engenheiro.
Orientadores: Flávio Luis de Mello
Heraldo Luis Silveira de Almeida
Rio de Janeiro
Setembro de 2019
iv
UNIVERSIDADE FEDERAL DO RIO DE JANEIRO
Escola Politécnica – Departamento de Eletrônica e de Computação
Centro de Tecnologia, bloco H, sala H-217, Cidade Universitária
Rio de Janeiro – RJ CEP 21949-900
Este exemplar é de propriedade da Universidade Federal do Rio de Janeiro, que
poderá incluí-lo em base de dados, armazenar em computador, microfilmar ou adotar
qualquer forma de arquivamento.
É permitida a menção, reprodução parcial ou integral e a transmissão entre
bibliotecas deste trabalho, sem modificação de seu texto, em qualquer meio que esteja
ou venha a ser fixado, para pesquisa acadêmica, comentários e citações, desde que sem
finalidade comercial e que seja feita a referência bibliográfica completa.
Os conceitos expressos neste trabalho são de responsabilidade do(s) autor(es).
v
AGRADECIMENTO
Depois de passar tantos anos nessa Universidade, praticamente 1/3 da minha
vida, ficaria inviável mencionar todos que me ajudaram de uma forma ou de outra, a
enfrentar os desafios dessa jornada, seja me ajudando em aulas, nesse projeto, seja
tornando possível através do cotidiano, da saúde e do controle emocional.
Aos professores da UFRJ, um agradecimento especial ao Jomar Gozzi e Carlos
José Ribas D’avilla por me ajudarem principalmente no aspecto psicológico e emocional
durante a minha jornada. Agradeço aos meus orientadores Flávio Luis de Mello e
Heraldo Luís Almeida pelo apoio, suporte, e feedbacks durante a execução desse
trabalho, além de boas conversas. Agradeço também ao professor Antônio Cláudio
Gomez de Sousa por me apoiar em uma tentativa anterior de projeto enquanto tentava
conciliar concomitantemente com um emprego.
Outros professores também foram importantes durante a minha jornada nesse
curso, dentre eles destaco: Wallace Martins, Carlos Teodósio, Sérgio Palma, Gélson,
Oswaldo. Além disso os professores de outros departamentos que também me apoiaram
em momentos importantes na minha jornada. Róbson Dias, que me ajudou e deu suporte
na gestão, além do Walter Suemitsu, Antônio Ferreira que se fizeram dispostos e
colaboraram o quanto possível para a realização das atividades no do Ramo Estudantil
do IEEE da UFRJ. José Stockler Canabrava Filho, que nos ajudou na equipe de
competição Minerva Baja UFRJ. que estiveram de portas abertas e ajudaram com o que
lhes foi possível para o desenvolvimento de atividades no Ramo Estudantil do IEEE.
A muitos colegas que passaram semanas estudando comigo, me ajudando de
alguma forma a enfrentar os desafios do curso de Engenharia Eletrônica e de
Computação e que sem eles, essa jornada seria muito mais difícil e complicada: Felipe
Moraes, Rafaela Berberick, Pedro Ribeiro, Pedro Boechat, Luciana Reys, Vinícius
Allemand, Eduardo Niemeyer, Tiago Monteiro, Herón Silva, José Vitor Leite, Bruno
Andrade, Rodrigo Pollo, Silvino Vieira, Hugo Andrade, Marcelo Castro, Marcelo
Hryniewicz, Hélio Machado, Rafael Estevam, Vitor Antunes, Luciana Reys, Filipe
Barretto, Natalie Nobre, João Guilherme Mattos, Hugo Coqueijo, Henrique Faria,
Evelyn Soares, Bony Conteville, Augusto Tundis, Lívia Lisandro, Diego Wanderley,
Vinícius Ferrão, Michel Ferreira, Lucas Cavazzani, Virgínia Licério, Laís Crispino.
Bernardo Dornellas, Jamil Oliveira.
vi
Aos meus colegas com quem trabalhei na equipe Minerva Baja: Luíz Neto (Lui),
Fábio Padovani, Paulo Biriba, Victor Lopes, Brenno Giansante, Felipe Sarabando,
Felipe Cristaldi.
Alérm disso, tive colegas que foram exemplos e inspirações de alguma forma
para mim no meu tempo nessa Universidade. São eles: Clélio de Paula, Frederico Fróes,
Dhiana Deva, Rafael Dahis, Andressa Sivolella e Igor Chame.
Aos meus amigos que me deram apoio durante o desenvolvimento desse projeto:
Felipe Menezes, Ramon Leôncio, Leon Porto, Silvino Vieira.
Aos amigos que fiz durante o meu tempo de trabalho na empresa Gemalto (agora
Thales): Michelle Amorim, Lucas Azevedo, Renata Gomes, Bruno Silva, Fabiano
Pellicione. Douglas Galetti, Luciana Daré.
Também não poderia esquecer da minha família, sem a qual eu não teria
conseguido nem iniciar a minha jornada nessa Universidade. Agradeço aos meus pais,
Fernanda De Leo e Alberto De Leo Jr. e a minha irmã Aline Campos De Leo.
Agradeço também aos contribuintes, o povo brasileiro, que paga seus impostos,
dos quais essa Universidade também depende.
vii
RESUMO
O presente trabalho trata do controle de acesso a recursos físicos
compartilhados, através de relés, com a utilização de microcontroladores e da tecnologia
NFC. O sistema consiste no uso de microcontroladores, com um leitor NFC, um
servidor Web para o cadastro de usuários e a geração de um registro de operação.
O objetivo do trabalho é propor um controle de acesso confiável, com registro
de utilização, gestão de usuários, que compartilhem um número limitado de recursos
entre um número maior de potenciais usuários, para que possam usá-los de forma
comunitária, mas que ao mesmo tempo tenha um controle de gestão desses recursos.
Palavras-Chave: Arduino, esp32, NFC, log, CSV, operação, Web, Web Server, Controle
de Acesso, autenticação, controle, relé.
viii
ABSTRACT
The present work is about the access control to shared physical resources,
through relays, with the use of microcontrollers and NFC technology. The system uses
the following features: microcontrollers, a NFC reader, a web server for the user
registration and generates an operational log.
The goal of this work is to propose a reliable access control, with operational
log, user management, that share a limited number of resources between a bigger
number of potential users, so that they can share the resources among them, but at the
same time have control and management of those resources.
Key-words: Arduino, Microcontroller, esp32, NFC, log, csv, operation, web, web
server, access control, authentication, control, relay.
ix
SIGLAS
CI – Circuito Integrado
CMOS – Complementary Metal Oxide Semiconductor
COM – Component Object Model
CSV – Comma-Separated Values
GPIO – General Purpose Input/Output
HSU – High Speed UART
HTML – Hyper Text Markup Language
HTTP – HyperText Transfer Protocol
I/O – Input/Output
I2C – Inter-Integrated Circuit
IDE – Integrated Development Environment
IOT – Internet of Things
IP – Internet Protocol
JSON – JavaScript Object Notation
NDEF – NFC Data Exchange Format
NFC – Near-Field Communication
NTP – Network Time Protocol
OEM – Original Equipment Manufacturer
OSI – Open System Interconnection
RF – Rádio Frequência
RTC – Real Time Clock
SPI – Serial Peripheral Interface
SPIFFS – SPI Flash File System
TCP – Transmission Control Protocol
TTL – Transistor-transistor logic
UART - Universal Asynchronous Receiver/Transmitter
UFRJ – Universidade Federal do Rio de Janeiro
URL – Uniform Resource Locator
UTC – Universal Time Coordinated
x
Sumário
1 - Introdução .................................................................................................................. 1
1.1 – Tema .................................................................................................................... 1
1.2 – Delimitação .......................................................................................................... 1
1.3 – Justificativa .......................................................................................................... 2
1.4 – Objetivos .............................................................................................................. 2
1.5 – Metodologia ......................................................................................................... 3
1.6 – Descrição ............................................................................................................. 4
2 - Fundamentação Teórica ........................................................................................... 5
2.1 – Microcontroladores .............................................................................................. 5
2.1.1 – Arduino ......................................................................................................... 5
2.1.2 – ESP32 ........................................................................................................... 6
2.2 – Comunicação Serial ............................................................................................. 7
2.2.1 – I2C (Inter-Integrated Circuit) ....................................................................... 7
2.2.2 – UART ........................................................................................................... 9
2.2.3 – Conversor de Nível Lógico......................................................................... 10
2.3 – NFC ................................................................................................................... 11
2.4 – NTP .................................................................................................................... 12
2.5 – Servidor Web ..................................................................................................... 14
3 - Desenvolvimento ...................................................................................................... 15
3.1 - Estrutura de Dados ............................................................................................. 15
3.1.1 - Usuários ....................................................................................................... 15
3.1.2 – Registro de Operações ................................................................................ 16
3.2 - Ambiente de Desenvolvimento .......................................................................... 17
3.3 – Funcionalidades ................................................................................................. 20
3.3.1 - Cadastro de Usuários ................................................................................... 20
3.3.2 - Operações de liberação/devolução de carrinhos ......................................... 23
xi
3.4 - Conexões ............................................................................................................ 29
4 - Resultados ................................................................................................................ 33
5 - Conclusão ................................................................................................................. 39
5.1 - Trabalhos Futuros ............................................................................................... 40
5.1.1 - Complementação da solução ....................................................................... 40
5.1.2 - Implementações similares ........................................................................... 41
Bibliografia .................................................................................................................... 42
Apêndice A – Diagramas e esquemáticos ................................................................... 47
Apêndice B – Logs de Execução .................................................................................. 49
Apêndice C – Código Fonte do Arduino ..................................................................... 52
Apêndice D – Código Fonte do Cadastro de Usuários – ESP32 ............................... 55
Apêndice E – Código Fonte da Operação – ESP32 ................................................... 64
xii
Lista de Figuras
Figura 1 - Conexão I2C para a comunicação entre Master e Slave. ................................. 8
Figura 2 - Estrutura de quadros da mensagem em I2C..................................................... 9
Figura 3 - Conexão para a comunicação entre UARTs. ................................................. 10
Figura 4 - Estrutura de quadros dos pacotes em comunicação entre UARTs. ............... 10
Figura 5 - Conversor de nível lógico .............................................................................. 11
Figura 6 - Funcionamento físico da comunicação NFC. ................................................ 12
Figura 7 - Topologia do NTP em camdas....................................................................... 13
Figura 8 - Seleção de placas no Arduino IDE. ............................................................... 18
Figura 9 - Configuração da placa do Arduino. ............................................................... 18
Figura 10 - Configuração da placa do ESP32................................................................. 19
Figura 11 - Boards Manager com placas Sparkfun. ....................................................... 19
Figura 12 - Boards Manager com placas ESP32. ........................................................... 20
Figura 13 - Diagrama de Alto Nível do Sistema. ........................................................... 20
Figura 14 - Formulário para cadastro de usuários. ......................................................... 21
Figura 15 - Fluxograma de autenticação de usuário para liberação. .............................. 24
Figura 16 - Configuração com o servidor NTP para a aquisição de data e hora. ........... 25
Figura 17 - Protótipo das funções de aquisição de data e hora [45]. .............................. 26
Figura 18 - Implementação da função getTime. ............................................................. 26
Figura 19 - Funções para a escrita do registro de operações. ......................................... 26
Figura 20 - Inicialização do sistema de arquivos ........................................................... 27
Figura 21 - Implementação da função readFile. ............................................................ 28
Figura 22 - Implementação da função appendFile. ........................................................ 28
Figura 23 - Implementação da função deleteFile. .......................................................... 28
Figura 24 - Implementação da função listDir. ................................................................ 29
Figura 25 - Arduino Pro Micro. ...................................................................................... 30
Figura 26 - Heltec ESP32 WiFi Kit 32. .......................................................................... 30
Figura 27 - PN532 - Leitor. ............................................................................................ 30
Figura 28 - Conversor de nível lógico. ........................................................................... 31
Figura 29 - Relé de dois canais. ...................................................................................... 31
xiii
Figura 30 - Conexões do sistema. ................................................................................... 32
Figura 31 - Foto do circuito montado. ............................................................................ 33
Figura 32 - Diagrama de conexão e pinagem entre os componentes. ............................ 34
Figura 33 - Conexão entre Arduino e leitor NFC PN532. .............................................. 35
Figura 34 - Switch de configuração de modo de comunicação no PN532. .................... 36
Figura 35 - Leitura de tags NFC pelo Arduino via I2C. ................................................. 37
Figura 36 - Configuração de comunicação serial. .......................................................... 38
xiv
Lista de Tabelas
Tabela 1 - Exemplo de arquivo com informações de usuários. ...................................... 15
Tabela 2 - Exemplo de arquivo com informações das operações................................... 16
1
1 - Introdução
1.1 – Tema
Este trabalho tem como tema o desenvolvimento e implementação de um
sistema de controle de acesso a recursos físicos compartilhados. O projeto consiste em
utilizar microcontroladores para acionar um relé, que atuará na abertura e fechamento
de carrinhos de supermercado, compartilhados para uso de moradores dentro de um
condomínio, a partir de tags de identificação NFC. Além disso, o sistema possibilita a
criação de usuários via Web por parte dos administradores, assim como o registro de
todas as operações realizadas.
1.2 – Delimitação
Este projeto focará na utilização do controle de acesso a carrinhos de
supermercado disponibilizados em condomínios para o uso de seus respectivos
moradores, cabendo à administração do condomínio a responsabilidade do cadastro de
usuários no sistema.
O cadastro desses usuários é realizado através de uma interface Web, disponível
apenas na rede local para a administração. Os usuários podem ser cadastrados através do
preenchimento de um formulário de cadastro e aproximação de uma tag de identificação
NFC única que será associada ao usuário cadastrado.
A autenticação dos moradores do condomínio se dará através da leitura das tags
de identificação NFC por um leitor próximo aos carrinhos. A partir dessa leitura, o
sistema irá identificar se o usuário possui cadastro e está autorizado a realizar as
operações de liberação ou devolução do carrinho.
A cada operação realizada, um registro da mesma é gerado e escrito em um
arquivo de operações. Nesse arquivo são guardadas informações, referentes a cada
operação, linha a linha. No contexto desse trabalho, as informações julgadas relevantes
que serão guardadas são: Data, Hora, Usuário, Carrinho, Operação.
2
A solução não irá abordar detalhes como: conexão de relé com fechadura para os
carrinhos, housekeeping de dados acumulados ao longo do tempo, número de terminais
(relés) maior do que dois, segurança de dados. A proposta é justamente ser um protótipo
funcional, podendo ser posteriormente aprimorado.
Essa solução também pode ser adaptada a outros contextos com pequenos
ajustes específicos de onde será utilizada. Alguns desses contextos incluem, por
exemplo: bicicletas/patinetes nas ruas, compartilhamento de notebooks em uma
empresa, automatização de empréstimos de livros em uma biblioteca.
1.3 – Justificativa
Atualmente, muitos dos mecanismos de controle utilizados nesse tipo de
aplicação – carrinhos de supermercado em condomínios – não são tão confiáveis, tanto
na usabilidade, quanto no controle dos carrinhos. Alguns utilizam somente cadeados
com chaves que ficam aos cuidados de porteiros, outros utilizam cartões que são
utilizados em trancas mecânicas que somente detectam a presença de um cartão para a
liberação, que fica retido até a devolução do carrinho.
Esses mecanismos, além de possuírem falhas de confiabilidade do controle do
uso dos carrinhos, não possuem nenhum registro do uso dos mesmos. Por isso, este
trabalho visa utilizar um mecanismo de entrada que seja confiável – relação direta do
usuário externo com uma identificação interna dentro do sistema – e ter um registro de
operações realizadas para futuras consultas e investigações do uso.
1.4 – Objetivos
O objetivo geral é, então, desenvolver um sistema prático, tanto para os
administradores (condomínio), como para os usuários comuns (moradores) para a
operação desse controle de acesso. Ter registradas essas informações de operações,
tanto os usuários cadastrados, quanto cada operação realizada com um registro
histórico. Esses registros devem conter informações de: Data, Hora, Usuário, Carrinho,
Operação.
3
Deve ser possível que os administradores autorizem quais usuários devem poder
utilizar ou não o serviço (de controle de acesso), guardar as informações relativas aos
mesmos em um cadastro: Tag, Nome, Apartamento, Bloco.
O sistema deve autorizar para que realizem as operações, somente usuários
previamente cadastrados por um administrador. Além disso, somente os usuários que
retiraram o carrinho devem poder devolvê-los, e caso um usuário não tenha devolvido
um carrinho, não poderá retirar outro enquanto não houver a devolução do anterior.
1.5 – Metodologia
Para atingir os objetivos do trabalho, foi decidido usar um microcontrolador
como elemento principal, devido à sua possibilidade de conexão com os principais
componentes necessários, relés e input de autenticação do usuário (no caso, um leitor
NFC), e sua facilidade de customização e adaptação.
A partir dele, foram analisadas questões de compatibilidade e viabilidade técnica
para definir como seria a arquitetura da solução. Alguns testes foram realizados e
confirmados e outros caminhos inicialmente planejados tiveram que ser adaptados.
A entrada dos usuários é realizada por meio de aproximação de tags NFC a um
leitor correspondente conectado a um Arduino Pro Micro, que transfere essas
informações por comunicação serial para um ESP32 Wifi Kit 32, que contém a lógica
principal do sistema.
O ESP32 é configurado de forma a aguardar a aproximação de uma tag NFC,
consequentemente um input pela comunicação serial, e assim que ela é realizada, valida
se a mesma corresponde a um usuário autorizado ou não para a abertura/fechamento ou
negação da operação no relé do carrinho. Em paralelo, há também a execução de um
servidor web dentro do próprio ESP32, que se conecta através de uma rede Wi-Fi local
e que gera uma interface Web para o cadastro de usuários por parte do administrador.
Tanto o cadastro de usuários quanto o registro das operações (de
abertura/fechamento dos relés) são realizados em arquivos texto do tipo CSV dentro de
um sistema de arquivos, também internamente ao ESP32.
4
1.6 – Descrição
O presente trabalho está divido em 5 capítulos, sendo que o capítulo 1
apresentou uma introdução ao tema do projeto.
No capítulo 2 serão apresentados os fundamentos teóricos para o
desenvolvimento do projeto.
O capítulo 3 aborda o desenvolvimento do projeto, os materiais empregados no
modelo físico construído, bem como a estrutura de software.
O capítulo 4 descreve os resultados obtidos e, finalmente, o capítulo 5 expõe as
principais conclusões do estudo.
5
Capítulo 2
2 - Fundamentação Teórica
2.1 – Microcontroladores
Um microcontrolador é um microcomputador com alguns dispositivos
adicionais para aplicações específicas em um único chip. É uma parte integrada em um
sistema de controle ou comunicação em tempo real.[1] O uso de microcontroladores
permite conectar outros circuitos complementares e periféricos em seus pinos de
entrada/saída de forma a personalizar o sistema, ao mesmo tempo que o controle central
– programação utilizada dentro do microcontrolador – pode ser adaptado conforme as
necessidades e conexões no circuito.
Além de ter todos os recursos que os primeiros computadores pessoais
possuíam, apresenta outros recursos, como por exemplo: memórias RAM, memórias
EEPROM, memória flash, pinos de entrada/saída (digitais ou analógicos), conectores
USB, dispositivos seriais síncronos e assíncronos, conversores analógico-digitais.[2]
[3]
2.1.1 – Arduino
Arduino é uma plataforma de prototipagem eletrônica programável de hardware e
software livres. A sua linguagem foi baseada no projeto Wiring[4] e é baseada
essencialmente em C/C++, podendo ser programada dentro do seu ambiente de
desenvolvimento, Arduino IDE[5]. Foi criada em 2005 na Itália, como uma ferramenta
de prototipação fácil e rápida para estudantes que não tenham conhecimento de
eletrônica ou computação.
6
O Arduino possui uma experiência de usuário simples e acessível. Ele é simples de
usar para iniciantes e, ao mesmo tempo, flexível suficiente para usuários mais
experientes. Dentre as principais vantagens do Arduino se encontram:
• seu custo baixo de aquisição comparado a outros microcontroladores,
• multiplataforma – pode ser executado em Windows, MAC e Linux,
ambiente de programação fácil de usar, hardware e software de código
aberto[6].
Projetos com automação e Arduino já estão sendo utilizados com certa frequência
há algum tempo. Dentre suas aplicações encontramos alguns exemplos na literatura para
ilustrar: um sistema de automatização do gerenciamento de uma biblioteca [7], um
sistema de irrigação inteligente [8] e um sistema de automação residencial inteligente e
seguro[9]. Em todos eles, vemos como o Arduino foi uma peça fundamental na
construção dos sistemas, e o quão versátil ele pode ser para inúmeras aplicações e temas
diferentes.
2.1.2 – ESP32
ESP32 é uma série de placas eletrônicas voltadas para aplicações de IoT,
microcontroladores de baixo custo e baixo consumo de energia com módulos de Wi-fi e
Bluetooth integrados[10]. Essas placas possuem adaptação com a IDE do Arduino,
podendo também ser programadas através dela, sendo necessário somente baixar as
bibliotecas correspondentes.
O seu design foi feito pela Espressif Systems, e começou a ser produzido em
larga escala, comercialmente, em 2016 por diversos OEMs, e já estão sendo produzidas
placas por diversos fabricantes diferentes.[11]
Para a manipulação de arquivos, o ESP32 utiliza o sistema de arquivos chamado
SPIFFS, do inglês Serial Peripheral Interface Flash File System. O SPIFFS é um
sistema de arquivos projetado para dispositivos flash SPI NOR em sistemas embarcados
[12][13].O SPIFFS é alocado em uma parte da memória. Essa parte é dividida em
blocos lógicos, que por sua vez são divididos em páginas lógicas. O tamanho dos blocos
lógicos e das páginas lógicas são uniformes. Uma página define o menor elemento de
dados conhecido pelo SPIFFS. [14]
Dispositivos flash SPI são divididos fisicamente em blocos. Em alguns
7
dispositivos, os blocos ainda são divididos em setores. É comum que memórias flash
SPI tenham entre 512kb e 8MB de memória. Apagar dados da memória só pode ser
feito por blocos ou setores. Normalmente, memórias flash SPI podem ser apagadas de
100.000 a 1.000.000 de ciclos antes de falharem. [14]
De fábrica, o ESP32 vem com um bootloader instalado que tem como
comportamento padrão inicializar o FreeRTOS – sistema operacional padrão – e um
segundo bootloader para inicializar o programa principal. Porém é possível instalar
alguns sistemas operacionais para a operação no ESP32, como por exemplo: Mongoose
OS, Espruino , Lua RTOS, MicroPython, entre outros. [11]
Já encontramos algumas aplicações com automação sendo realizadas com essas
placas. Na literatura, foram encontrados exemplos de sistemas de controle de irrigação
[15], assim como automação residencial [16] [17].
2.2 – Comunicação Serial
Comunicação serial é o processo de enviar dados de forma sequencial bit a bit por meio
de um canal de comunicação ou um barramento de dados.
No contexto desse trabalho, esse tipo de comunicação foi utilizado em dois momentos:
1. Para a comunicação entre um leitor NFC e o Arduino – via I2C
2. Para a comunicação entre o Arduino e o ESP32 – via UART
2.2.1 – I2C (Inter-Integrated Circuit)
No início da década de 1980, foi desenvolvido pela Phillips Semiconductors,
agora NXP Semiconductors, um barramento bidirecional de dois fios para a
comunicação eficiente entre CIs chamado de I2C. Todos os dispositivos compatíveis
com o barramento I2C possuem uma interface que viabiliza a comunicação entre eles
através desse barramento. [18]
2.2.1.1 – Protocolo de Comunicação I2C
Os dois fios ou I/Os utilizados pelo barramento I2C são chamados de SDA
8
(Serial Data) – usado para a transferência de dados bit a bit - e SCL (Serial Clock) –
usado para o sincronismo entre dispositivos através de um sinal de Clock. Nesse tipo de
conexão, é possível ter múltiplos circuitos Slaves e apenas um Master ou múltiplos
Masters controlando múltiplos Slaves. O sinal de sincronismo utilizado é sempre
controlado pelo Master.[18]
Figura 1 - Conexão I2C para a comunicação entre Master e Slave. Fonte: Circuit Basics [19].
Em uma mensagem combinada, cada leitura ou escrita começa com um bit de
início e o endereço do Slave. Podem ocorrer bits de início entre quadros de transmissão
da mesma mensagem combinada, porém o bit de parada só irá ocorrer ao fim da
transmissão completa. Cada envio de mensagens nesse protocolo é estruturado com os
seguintes dados:[18]
• Um endereço binário do Slave que vai receber a mensagem
• Um ou mais frames com dados da mensagem.
• Condição de início
• Condição de parada
• Bits de leitura/escrita
• Bits de acknowledgement / negative-acknowledgement.
9
Figura 2 - Estrutura de quadros da mensagem em I2C. Fonte: Circuit Basics [19].
Condição de início: A linha do SDA muda do valor lógico alto para o baixo
antes que a linha do SCL mude de alto para baixo.
Condição de parada: A linha do SDA muda do valor lógico baixo para o alto
depois que a linha do SCL mude de baixo para alto.
Quadro de endereço: Uma sequência única de cada escravo de 7 a 10 bits
identifica o escravo quando o mestre quer falar com ele.
Bit de Leitura/Escrita: Um bit único que especifica se o mestre está mandando
dados (nível lógico baixo) para o escrevo ou pedindo dados dele (nível lógico alto).
Bit de ACK/NACK: Cada quadro de uma mensagem é seguido por um bit de
acknowledge/negative-acknowlege. Se um quadro de endereço ou de dados for recebido
com sucesso, um bit de ACK é retornado para dispositivo emissor.[18]
2.2.2 – UART
UART do inglês Universal Asynchronous Receiver/Transmitter é um
componente eletrônico cujo principal fim é transmitir e receber dados serial. Um UART
se comunica com outros UARTs, de forma que a mensagem recebida de forma serial é
convertida em forma paralela para o dispositivo, assim como o contrário é
verdadeiro.[20]
Para a conexão entre UARTs, cada um possui um pino TX (Transmit) e um de
RX (Receive). Esses pinos devem ser conectados de forma alternada – o TX do emissor
no RX do receptor. A comunicação é full-duplex, logo cada fio possui um fluxo de
dados em uma direção.[21]
10
Figura 3 - Conexão para a comunicação entre UARTs. Fonte: Circuit Basics [21].
Os dados na comunicação entre UARTs são organizados em pacotes, que
possuem:[21]
• 1 bit de início
• 5-9 bits de dados
• 1 bit de paridade – opcional.
• 1 ou 2 bits de parada.
Figura 4 - Estrutura de quadros dos pacotes em comunicação entre UARTs. Fonte: Circuit Basics [21].
2.2.3 – Conversor de Nível Lógico
O conversor de nível lógico é um circuito capaz de converter um sinal de 3,3V
para um de 5V assim como um sinal de 5V para um de 3,3V. Ele permite que um
circuito de nível lógico de 5V se comunique com um de nível lógico 3,3V. [11]
11
Figura 5 - Conversor de nível lógico Fonte: SparkFun Electronics [22].
2.3 – NFC
NFC, do inglês Near-Field Communication, é um conjunto de protocolos de
comunicação sem fio de curta-distância desenvolvidos em conjunto pela NXP
Semicondutores (antiga Philips Semicondutores) e Sony em 2002 como um avanço das
tecnologias de RFID (Radiofrequency Identification). A comunicação se dá a curta
distância (de 4cm a 10cm), é half-duplex e é realizada por meio da indução
eletromagnética entre dois dispositivos indutivos acoplados, numa frequência central de
13,56MHz e a sua comunicação de dados pode ir de 106 Kbit/s até 424Kbit/s. [23]
[24][25]
12
Figura 6 - Funcionamento físico da comunicação NFC. Fonte: Wireless Battery-less Sensor Device [26].
Os detalhes de especificação para que um dispositivo possa se comunicar via
NFC se encontram em padrões. Eles definem modulação, codificação, formato de
quadros e taxas de transferências. São eles o ECMA-340[27] e ISO/IEC 18092[24].
2.4 – NTP
O NTP (Network Time Protocol) é um protocolo que permite a sincronização
dos relógios de dispositivos de uma rede a partir de referências de tempo confiáveis, é
assim que mantemos os relógios de computadores sincronizados. Os servidores NTP
formam uma topologia hierárquica, dividida em camadas ou estratos (em inglês: strata)
numerados de 0 (zero) a 16 (dezesseis). O estrato 0 (stratum 0) na verdade não faz parte
da rede de servidores NTP, mas representa a referência primária de tempo, que é
geralmente um receptor do Sistema de Posicionamento Global (GPS) ou um relógio
atômico. O estrato 16 indica que um determinado servidor está inoperante.[28]
13
Figura 7 - Topologia do NTP em camdas. Fonte: NTP.br [29].
O estrato 0, ou relógio de referência, fornece o tempo correto para o estrato 1,
que por sua vez fornece o tempo para o estrato 2 e assim por diante. O NTP é então,
simultaneamente, servidor (fornece o tempo) e cliente (consulta o tempo). A topologia
está ilustrada na Figura 7. De forma geral, quanto mais perto da raiz, ou seja, do estrato
0, maior a exatidão do tempo. O estrato ao qual o servidor pertence é a principal métrica
utilizada pelo NTP para escolher dentre vários, qual o melhor servidor para fornecer o
tempo.[28]
Um dispositivo faz o papel de cliente, solicitando informações sobre o tempo a
um servidor. O cliente tem conhecimento das associações com os servidores e do estado
da troca de pacotes. Outro dispositivo faz o papel de servidor, respondendo à solicitação
do cliente com informações sobre o tempo. O servidor não armazena informações sobre
o diálogo com o cliente ou sobre sua associação com o mesmo. Um cliente pode criar
associações com vários servidores simultaneamente (na verdade é recomendável que
seja assim), e um servidor pode fornecer tempo a diversos clientes
simultaneamente. [28]
As mensagens do NTP são baseadas no protocolo UDP, que é um protocolo não
confiável e não orientado à conexão. A troca de mensagens entre cliente e servidor
permite que o cliente descubra qual seu deslocamento (offset) em relação ao servidor, ou
seja, o quanto seu relógio local difere do relógio do servidor. Através da troca de
mensagens, o NTP consegue as informações de atraso e deslocamento de um servidor.
Essa troca de mensagens não é realizada uma única vez. Ela se repete periodicamente,
com o período dinamicamente controlado pelo NTP.[28]
14
2.5 – Servidor Web
Servidor web é um software responsável por aceitar pedidos em HTTP de
clientes, geralmente navegadores e servi-los com respostas em HTTP, incluindo páginas
web com documentos (HTML) e mídias (imagens, vídeos, áudios). Esse software
normalmente se encontra em algum computador (hardware) com acesso a Internet para
que essa comunicação entre o cliente e o servidor seja feita.
O protocolo HTTP, do inglês HyperText Transfer Protocol, é um protocolo de
comunicação – na camada de aplicação do modelo OSI – utilizado para sistemas de
informação de hipermídia, distribuídos e colaborativos. Ele é a base para a comunicação
de dados da World Wide Web.
Apesar de normalmente encontrarmos servidores web em DataCenters ou “na
nuvem”, também é possível a configuração de servidores web em microcontroladores.
Servidores web em sistemas embarcados possuem algumas vantagens, como, baixo
custo de desenvolvimento, pouca memória e processamento necessários. [30]
Existem aplicações de servidores web embarcados que utilizam-no
principalmente para a comunicação, seja a aquisição de dados de sensores e/ou
processamentos internos do microcontrolador para um usuário externo – em um
browser[31][32][33] ou um processamento externo em um outro servidor para análises
mais complexas – quanto de dados de entrada de fora para dentro do controlador, seja
para processamento, seja para controle[34][35][36][37].
15
Capítulo 3
3 - Desenvolvimento
3.1 - Estrutura de Dados
O projeto possui dentro da sua estrutura, dois arquivos – em formato CSV
(Comma-separated Values)[38] – correspondentes aos usuários do sistema e ao registro
das operações.
3.1.1 - Usuários
O arquivo de usuários (“users.csv”), é responsável por armazenar as informações
dos usuários registrados no sistema e, portanto, aptos a serem identificados
internamente e assim podendo passar pelo processo de autenticação, assim como de
registro a cada operação realizada.
Para o escopo desse trabalho, quanto a informações administrativas relevantes
de cada usuário (morador do condomínio), foram escolhidas: nome, apartamento e
bloco. Além delas, informações necessárias para o sistema são: tag ID (Tag NFC usada
para a autenticação de cada usuário), e situação.
Logo, a estrutura desse arquivo é demonstrada a partir de um modelo tal qual a
Tabela 1.
Tabela 1 - Exemplo de arquivo com informações de usuários.
ID NOME APT BLOCO SITUAÇÃO
4A69AC14 USUARIO1 101 1 ATIVA
6A631D10 USUARIO2 302 1 ATIVA
4A69AC10 USUARIO3 101 2 BLOQUEADO
16
Definição sobre cada campo:
ID – É um valor Hexadecimal de 8 dígitos, referente a tag NFC que cada usuário
receberá no momento de seu cadastro no sistema e, que será a sua identificação dentro
do sistema.
Nome – Nome próprio do usuário/morador.
Apt – Apartamento do usuário/morador.
Bloco – Bloco do apartamento do morador dentro do condomínio.
Situação – Sinalizador de autorização do usuário para retirada ou não de
carrinho de supermercado.
• ATIVA – Usuário está autorizado a retirada de carrinho.
• BLOQUEADO – Usuário não está autorizado a retirada do carrinho.
Um novo usuário pode ser adicionado no sistema a partir da interface de
“Cadastro de usuário”.
3.1.2 – Registro de Operações
O arquivo de registro de operações (“operation.csv”), é responsável por registrar
todas as operações realizadas no sistema (de liberação e devolução de carrinhos). Para o
escopo desse trabalho, foram definidos os seguintes campos para o armazenamento de
informações sobre cada operação: DATA, HORA, USUARIO, SLOT e OPERACAO.
Logo, a estrutura desse arquivo é demonstrada a partir de um modelo tal qual a
Tabela 3.
Tabela 2 - Exemplo de arquivo com informações das operações.
DATA HORA USUARIO SLOT OPERACAO
20/08/2019 14:27:00 6A631D10 1 LIBERAÇÃO
21/08/2019 07:30:00 6A631D10 1 DEVOLUÇÃO
22/08/2019 20:00:00 4A69AC10 2 LIBERAÇÃO
17
Definição sobre cada campo:
DATA – Data na qual a operação foi realizada.
HORA – Horário no qual a operação foi realizada.
USUARIO – ID do usuário que realizou a operação
SLOT – Slot do carrinho no qual a operação foi realizada
OPERACAO – Tipo de operação realizada. Se o carrinho foi retirado/liberado
(LIBERAÇÃO) ou se o carrinho foi devolvido (DEVOLUÇÃO).
3.2 - Ambiente de Desenvolvimento
Nesse trabalho, temos dois microcontroladores – Arduino e ESP32 – que serão
programados para que realizem as tarefas desejadas. Em ambos utilizamos a IDE do
Arduino [39] para essa função. Na IDE, antes de compilar cada programa, devemos
selecionar a placa que está sendo utilizada, conforme mostra a Figura 8. Essa
configuração de placas é importante porque placas diferentes tem diferentes CPUs,
taxas de transferência de dados, assim como componentes adicionais que são
configurados especificamente pra elas na IDE.
No caso, do presente trabalho, os modelos de placas utilizadas para a execução
foram:
• SparkFun Pro Micro – processador ATmega32U4 (5V, 16MHz) – para
o Arduino, conforme mostra a Figura 9.
• Heltec Wifi Kit 32 – para o ESP32, conforme mostra a Figura 10.
Essas duas placas, não vieram instaladas nativamente na IDE do Arduino. Por
isso, tiveram que ser instaladas a parte. Para a placa do Arduino, a Figura 11 mostra o
Boards Manager – opção na IDE para busca de configurações de placas – com a opção
de download das placas AVR da Sparkfun. Já para a placa do ESP32, foi preciso
primeiro adicionar algumas configurações na IDE conforme descrito pelo fabricante
[40]. Após essas mudanças, foi possível encontrar os arquivos de configuração para as
placas ESP32 no Boards Manager, conforme mostra a Figura 12.
18
Figura 8 - Seleção de placas no Arduino IDE.
Figura 9 - Configuração da placa do Arduino.
19
Figura 10 - Configuração da placa do ESP32.
Figura 11 - Boards Manager com placas Sparkfun.
20
Figura 12 - Boards Manager com placas ESP32.
3.3 – Funcionalidades
O diagrama da Figura 13 descreve as funcionalidades presentes no sistema e
seus relacionamentos:
Figura 13 - Diagrama de Alto Nível do Sistema.
3.3.1 - Cadastro de Usuários
A interface para o cadastro de usuários foi definida que seria via formulário
Web, aproveitando o dispositivo de conexão Wi-Fi presente no ESP32. Foi utilizada a
biblioteca ESPAsyncWebServer[41] que por sua vez possui a biblioteca AsyncTCP[42]
21
como dependência. O objetivo dessa interface é que o administrador do condomínio
possa acessá-la através de um navegador, preencha um formulário com as informações
do usuário e envie para o servidor. O servidor, por sua vez, deve receber essas
informações do usuário e escrevê-las no arquivo de usuários.
Visando atender esse objetivo, nas configurações do microcontrolador ESP32
para um servidor web assíncrono, foram definidos três caminhos:
• “/” – Correspondente a página de cadastro. Nesse caminho, foi
configurada uma requisição do tipo GET, que envia o código da página
HTML a ser renderizada para o cadastro.
• “/form” – Correspondente ao caminho para o envio do formulário com
os dados do usuário. Nesse caminho, o servidor recebe os parâmetros do
formulário, realiza as operações para o parse dos dados e escreve no
arquivo de usuários. Após a realização das operações o navegador é
redirecionado de volta a página de cadastro.
• “/tag” – Correspondente a leitura de tag NFC para o cadastro. Nesse
caminho, o servidor verifica se há uma tag NFC presente no leitor NFC e
preenche a mesma no formulário em seu respectivo campo.
O caminho raiz do servidor configurado é correspondente ao IP atribuído ao
ESP32 após a sua conexão na rede Wi-Fi. Por exemplo http://localhost/ , iria direcionar
para o caminho “/” e a página de cadastro seria exibida, como mostra a Figura 14.
Figura 14 - Formulário para cadastro de usuários.
22
Nesse formulário o administrador deverá preencher os seguintes campos,
correspondentes a detalhes usuário a ser cadastrado:
• Nome;
• Apartamento;
• Bloco;
Além de aproximar a tag NFC a ser registrada para o respectivo usuário no leitor
e clicar no botão “Ler TAG” – que está apontado para o caminho “/tag” - e enviar o
formulário através do botão “Cadastrar” – que está apontado para o caminho “/form” -
, enviando as informações para a escrita no arquivo de usuários. O sistema irá receber as
variáveis e processá-las no formato da estrutura de dados do arquivo “users.csv”
conforme mencionado anteriormente, e adicionada uma nova linha no arquivo com as
informações do respectivo usuário. Por padrão, todo usuário novo cadastrado recebe o
estado de situação ATIVA.
23
3.3.2 - Operações de liberação/devolução de carrinhos
As operações liberação e devolução de um carrinho – através do seu respectivo
relé – se dá sempre através da leitura de uma tag NFC válida, tanto para a liberação
quanto para a devolução. Para que um usuário possa liberar um carrinho e utilizá-lo, o
primeiro pré-requisito é que ele esteja cadastrado no sistema, e possua uma tag NFC
correspondente ao seu cadastro para realizar a autenticação e liberar o relé do carrinho.
No caso da devolução, o mesmo usuário que realizou a liberação deve aproximar
a tag do leitor para que o relé do carrinho correspondente seja fechado e outro usuário
possa liberá-lo em um próximo uso. Somente o usuário que liberou o carrinho poderá
devolvê-lo. Outros usuários caso precisem liberar um carrinho, liberarão o segundo slot,
caso este esteja disponível.
O processo de verificação dos usuários e autorização para as operações se dá
segundo o fluxograma da Figura 15:
24
Figura 15 - Fluxograma de autenticação de usuário para liberação.
O próximo passo, após a autorização e realização da operação com o
carrinho, é a escrita dessa operação no registro de operações. No contexto desse
trabalho, não serão registradas operações inválidas (tentativas de operações
negadas). Esse processo se dá através da obtenção e concatenação das variáveis
correspondentes a operação.
Essas variáveis são:
• Data – Data em que a operação foi realizada;
• Horário – Horário em que a operação foi realizada;
• Usuário – Identificação do usuário que realizou a operação – no caso
desse arquivo, seria o próprio valor da sua TAG correspondente;
• Slot – Slot correspondente do relé em que a operação foi realizada –
relés 1 ou 2;
• Operação – Tipo de operação que foi realizada - operação de
LIBERAÇÃO ou DEVOLUÇÃO;
Nesse caso, na própria autenticação, o sistema já obteve os dados de
Usuário, Slot e Operação. Portanto, para continuar com o processo, será explicado
como é realizada a obtenção da Data e Horário correspondentes.
25
Data e Hora
Para adquirir as informações de data e hora de forma confiável no sistema, dado
que o microcontrolador não possui um relógio próprio, a solução escolhida foi a de
conectar-se a internet por wi-fi – um módulo embarcado já disponível dentro do ESP32
– e com isso usar o Network Time Protocol (NTP)[28]. O ESP32 se conecta a um
servidor NTP através do protocolo UDP e ocorre a troca de pacotes de forma a
sincronizar o tempo entre eles.
Além disso, para que se possa trabalhar com esses dados de tempo, é necessário
adaptar a estrutura de dados para a atribuição de valores em variáveis (Dias, horas,
minutos, segundos). Por isso, foi utilizada a biblioteca time.h que já vem presente no
framework com bibliotecas básicas do ESP32 para a Arduino IDE[43].
A implementação da configuração do tempo a partir do servidor NTP começa
com a configuração do servidor utilizado e do fuso-horário desejado, assim como se
esse fuso-horário possui horário de verão. Essa configuração é mostrada na Figura 16, e
o protótipo da função externa configTime é mostrado na Figura 17, onde usamos os
seguintes parâmetros:
• gmtOffset_sec – Valor de deslocamento com relação a UTC em
segundos – com 3600 segundos a cada hora, temos um desvio deem
relação a UTC na configuração de fuso-horário.
• daylightOffset_sec – Diferença em segundos no horário de verão = 3600
segundos = 1 hora.
• ntpServer – Servidor NTP desejado para a sincronização do tempo. Foi
utilizado o servidor principal do NTP.[44]
Figura 16 - Configuração com o servidor NTP para a aquisição de data e hora.
26
Figura 17 - Protótipo das funções de aquisição de data e hora [45].
A função getTime foi criada de forma a modularizar o tratamento de erros, assim
como a manipulação do timestamp para o padrão desejado de uso dentro do projeto –
formato de Darta e Hora, DD-MM-YYYY e hh:mm:ss – e chamada na função principal
sempre que necessário. A implementação da função segue conforme a Figura 18.
Figura 18 - Implementação da função getTime.
Com essas implementações, já é possível obter o tempo de forma rápida pela
função getTime. Logo, para a escrita do registro de operações já sabemos como obter
todas as variáveis necessárias. Utilizamos strings para a manipulação desses dados para
concatená-los e formatá-los como CSV e transformá-los em um char array para a
escrita em arquivo. O código dessa implementação se encontra na Figura 19.
Figura 19 - Funções para a escrita do registro de operações.
A priorização da ordem de aquisição dos dados é feita de acordo com a estrutura
do arquivo de operações “operation.csv”, conforme descrito anteriormente. Primeiro, a
data e hora são salvos em uma char array, stringBuffer, através do uso da função
27
getTime, e começando a compor a string principal que será escrita em arquivo,
operationString.
Depois, ela é completada com o valor da Tag do usuário autenticado, que já
havia sido recebido no momento da validação, junto com a separação por vírgulas de
acordo com o formato CSV, seguido pelos valores do relé do carrinho correspondente a
operação (PIN1_SLOT) e o seu valor (0 ou 1 para ABERTO ou FECHADO). Por
último a string é transformada em um char array e escrita dentro do arquivo de registro
de operações “operations.csv”.
Operações de manipulação de arquivos
O ESP32 possui uma memória interna pequena, porém razoável para o nosso
intuito, de forma a poder armazenar os dados dos usuários e do registro de operações
através da utilização do SPIFFS. Temos 4MB de memória SPI flash nele. Inicialmente,
é necessário inicializar o sistema de arquivos no programa, que é feito através do uso da
biblioteca SPIFFS.h[46] e a implementação é realizada segunda a Figura 20. Após a
inicialização do sistema, é possível realizar operações de manipulação de arquivos
usando a biblioteca FS.h[47],
Figura 20 - Inicialização do sistema de arquivos
Para facilitar o trabalho, foram criadas funções modularizadas para cada tipo de
operação de forma a realizar o tratamento de erros e verificações necessárias de forma a
evitar problemas. As funções criadas foram: readFile(), appendFile(), deleteFile() e
listDir(). Suas implementações estão descritas em Figura 21, Figura 22, Figura 23 e
Figura 24 respectivamente.
28
Figura 21 - Implementação da função readFile.
Figura 22 - Implementação da função appendFile.
Figura 23 - Implementação da função deleteFile.
29
Figura 24 - Implementação da função listDir.
3.4 - Conexões
O sistema é composto de alguns componentes eletrônicos conectados entre si
além da sua programação. Serão listados os componentes e suas conexões abaixo
para ilustrar.
Componentes utilizados:
• 1 OSOYOO Arduino Pro Micro 5V / 16Mhz;
• 1 Heltec ESP32 WiFi Kit 32;
• 1 PN532 NFC RFID Module;
• 1 Conversor de nível lógico bi-direcional;
• 1 Módulo relé de 2 canais 5V;
30
Figura 25 - Arduino Pro Micro. Fonte: OSOYOO [48]
Figura 26 - Heltec ESP32 WiFi Kit 32. Fonte: Heltec Automation [49].
Figura 27 - PN532 - Leitor. Fonte: Elechouse [50].
31
Figura 28 - Conversor de nível lógico. Fonte: Baú da Eletrônica [51].
Figura 29 - Relé de dois canais. Fonte: Vida de Silício [52].
Temos as seguintes conexões, conforme mostra a Figura 30:
• Leitor NFC (PN532 Module) com o Arduino (Arduino Pro Micro);
• Arduino com o conversor de nível lógico;
• ESP32 (Heltec ESP32 WiFi Kit 32) com o conversor de nível lógico;
• ESP32 com os relés (módulo relé de 2 canais 5V);
32
Figura 30 - Conexões do sistema.
33
Capítulo 4
4 - Resultados
Conforme mencionado no capítulo anterior quanto a conexão do circuito para o
sistema, o resultado final da montagem é mostrado na Figura 31. E a pinagem de
conexão entre todos os componentes na Figura 32.
Figura 31 - Foto do circuito montado.
34
Figura 32 - Diagrama de conexão e pinagem entre os componentes.
Na etapa do projeto da conexão do módulo PN532, leitor NFC, a ideia era de se
comunicar diretamente com o ESP32 e não haveria a necessidade do uso do Arduino
Pro Micro (até então fora do projeto). Porém, ao baixar bibliotecas distintas
[53][54][55], e realizar alguns testes diferentes e investigar se seria possível resolver o
problema, foi decidido mudar a estratégia. Com nenhuma das bibliotecas foi possível
compilar nem um programa de exemplo com a placa do ESP32, ao testar a compilação
de exemplos - da própria biblioteca - com o Arduino Pro Micro foi obtido sucesso.
A partir disso, foi avaliado se o projeto poderia ser migrado todo para o Arduino
somente, ou se haveria alguma forma de comunicar os dados do leitor pelo Arduino e
depois para o ESP32. Por conta da ausência de conexão com a internet – sem nenhum
shield adicional – e impossibilidade de armazenar arquivos texto na própria memória
interna, foi decidido manter o ESP32 e usar o Arduino como interface direta com o
leitor NFC, PN532. A Figura 33 mostra a conexão entre os dois.
35
Figura 33 - Conexão entre Arduino e leitor NFC PN532.
O leitor PN532 pode operar em três modos de conexão serial distintos e a
operação escolhida deve ser configurada por um switch presente no chip, conforme
mostra a Figura 34. Para essa aplicação nenhuma delas seria restritiva, logo o critério de
decisão foi em relação aos pinos disponíveis para a respectiva comunicação serial no
microcontrolador – Arduino – e os testes nas possíveis que se mostrassem funcionais –
comportamento esperado do leitor NFC.
36
Figura 34 - Switch de configuração de modo de comunicação no PN532. Fonte: Elechouse [50]
Os três modos possíveis são: HSU, I2C e SPI. Os três foram testados, porém
somente o I2C teve o resultado obtido com sucesso, conforme mostra a Figura 35. Por
isso, foi o escolhido para a implementação. Com isso iniciaram os testes para entender o
funcionamento do leitor, adaptar o código para as necessidades do projeto, e entender
melhor o processo de comunicação, estrutura de dados recebidos e os métodos da
biblioteca do leitor.
Após a leitura ter sido realizada com sucesso pelo Arduino, foi preciso descobrir
como repassar a informação de leitura de tags para o sistema principal – no ESP32. A
forma de comunicação escolhida foi serial. A partir dos pinos RX e TX de cada
microcontrolador, seria possível estabelecer a comunicação entre os dois aproveitando
do dispositivo UART contido em cada um deles.
37
Figura 35 - Leitura de tags NFC pelo Arduino via I2C.
Porém, um outro problema encontrado com a comunicação entre os dois
microcontroladores seria o fato dos dois não usarem a mesma tensão de nível lógico. O
ESP32 trabalha com nível lógico ALTO de 3,3V CMOS enquanto o Arduino com nível
lógico ALTO de 5V TTL. Para resolver esse problema, foi utilizado um circuito
conversor de nível lógico para fazer a transição de tensões entre dispositivos. Assim, um
sinal de nível lógico ALTO de 5V seria convertido para 3,3V e vice-versa, de acordo
com a direção que ele estivesse indo.
Na comunicação serial direta e assíncrona, foi estabelecido um Baud Rate –
velocidade de transferência em bits por segundo - de 9600 com a codificação 8N1 – 8
bits de dados, sem paridade, com 1 bit de parada. O código de configuração – que deve
38
estar igual nos dois dispositivos – para essa configuração está na Figura 35. Exemplo do
código no ESP32 em que a configuração Serial com Baud Rate de 115200 é
configurada para o monitor serial – onde as informações do console são apresentadas –
e o 2º canal serial, Serial2 é usado para a configuração de comunicação com o outro
dispositivo – o Arduino. Nesse caso a constante de “BAUD_RATE” é igual a 9600 –
como mencionado anteriormente – e as constantes “RXD2” e “TXD2” dos canais de
Receive e Transfer respectivamente, são os pinos relativos a esses canais no ESP32.
Figura 36 - Configuração de comunicação serial.
39
5 - Conclusão
O projeto conseguiu atender seu objetivo principal, ao realizar a autenticação
dos usuários de forma correta, realizar o chaveamento dos relés quando desejado e
fornecer corretamente o registro das operações realizadas. Foram colocados em prática
conceitos de eletrônica embarcada, programação, comunicações, além da oportunidade
da realização de um protótipo de início e fim e toda a sua documentação. Isso trouxe um
grande aprendizado, proporcionando a oportunidade de vivenciar o processo para a
realização de uma solução para um problema real, o qual me senti capaz de resolver.
Ter consciência de que imprevistos acontecem, que muitas vezes estamos equivocados e
podemos subestimar a realização de certas tarefas. Essa experiência mostrou exatamente
a realidade disso, ao ter que fazer todas as etapas sozinho, sem participar de uma equipe
que possui uma maior organização e divisão de tarefas.
A parte que pensei ter a menor probabilidade de “problemas” foi onde tive o
maior gargalo. Ao conectar o leitor NFC, tive que ver um problema atrás do outro,
quase tive que mudar a maior parte do que já havia realizado do trabalho para adaptar
para um microcontrolador diferente, dada a incompatibilidade que ocorreu na prática, e
tive que utilizar um microcontrolador adicional, somente para receber essa informação e
repassá-la para o principal, adotando essa flexibilidade no trabalho para que conseguisse
atingir o objetivo funcional.
Aconteceram imprevistos e muito tempo gasto com a resolução de problemas
relacionados à adaptação de drivers para as placas na IDE do Arduino, compatibilidade
de bibliotecas e configurações de frequência de operação para a comunicação de dados.
O uso de novas tecnologias com pouca informação na literatura e muitas dependências
sendo atualizadas, ou até algumas nem existentes, também foi um desafio a se ter em
mente para futuros trabalhos, em relação ao risco associado da utilização de tecnologias
mais recentes.
40
5.1 - Trabalhos Futuros
O sistema ainda pode ter outros recursos que o complementem, além de ser
possível ampliá-lo. Além disso, essa mesma solução pode ser implementada em uma
variedade de aplicações de forma similar (tanto a eletrônica, quanto o software).
Portanto, esta seção será dividida em duas: Complementação da solução e
Implementações similares.
5.1.1 - Complementação da solução
Essa solução ainda pode ter diversas complementações, por exemplo:
• Interface completa para gestão de usuário - com edição e remoção além
do cadastro;
• Servidor Web hospedado externamente em um outro servidor para maior
escala e armazenamento de dados;
• Armazenamento de dados em servidor externo, seja arquivos texto, seja
um banco de dados;
• Criptografia para guardar, cadastrar e autenticar os usuários;
• Escalamento do número de relés e de leitores de tags NFC;
• Adaptação das regras de negócio para a liberação ou não dos relés em
condições distintas, assim como para os campos registrados nos arquivos
CSV;
• Integração de dispositivos eletromecânicos para a aplicação dos relés;
• Geração de relatórios estatísticos de acordo com o uso dos carrinhos,
trazendo insights para a administração sobre o padrão de uso dos
usuários – tempo médio entre retirar e devolver um carrinho – e também
de identificação de comportamentos fora da média.
• Operar em modo offline, sem a necessidade da sincronização contínua do
NTP através do uso de um RTC para a sincronização do tempo.
41
5.1.2 - Implementações similares
Esse mesmo projeto, com pequenas mudanças de adaptação para um contexto
diferente, pode ser usado em outras aplicações. Alguns desses exemplos seriam:
• Controle no uso compartilhado de bicicletas e/ou patinetes;
• Controle de armários de academias e/ou albergues para seus usuários;
• Uso compartilhado de notebooks em uma empresa;
• Automatização de empréstimos de livros em uma biblioteca “sem
funcionários”;
• Controle de uso de equipamentos em hospitais;
42
Bibliografia
[1] R. Kamal, Microcontrollers: Architecture, Programming, Interfacing and System
Design. Prentice Hall, 2009.
[2] P. A. Laplante e S. J. Ovaska, Real-Time Systems Design and Analysis. Hoboken,
NJ, USA: John Wiley & Sons, Inc., 2011.
[3] S. MONK, Programação com Arduino: Começando com Sketches. Porto Alegre:
Bookman, 2017.
[4] Wiring, “About \ Wiring”, 2016. [Online]. Available at:
http://wiring.org.co/about.html. [Acessado: 05-jul-2019].
[5] D. Wheat e D. Wheat, “Arduino Software”, Arduino Internals, 2011. [Online].
Available at: https://www.arduino.cc/en/Main/Software.
[6] “Arduino - Introduction”, Arduino, 2017. [Online]. Available at:
https://www.arduino.cc/en/Guide/Introduction. [Acessado: 14-mar-2019].
[7] B. Barma, S. Ghosh, A. Chaudhury, e B. Ganguly, “Microcontroller Based
Robotic Arm Development for Library Management System”. 2018.
[8] C. Gilarranz Casado, M. Loizu, e S. Altares López, “Intelligent Irrigation System
Based on Arduino”, 2018.
[9] J. C. A, N. Ramalingam, K. Satheeshkumar, N. Ajithkumar, P. A. Gopinath, e S.
Ranjithkumar, “Intelligent Smart Home Automation and Security System Using
Arduino and Wi-fi”, International Journal Of Engineering And Computer
Science, 2017.
[10] Espressif, “ESP32 Overview | Espressif Systems”, 2017. [Online]. Available at:
https://www.espressif.com/en/products/hardware/esp32/overview. [Acessado: 04-
ago-2019].
[11] N. KOLBAN, Kolban’s book on ESP32. 2017.
[12] P. Andersson, “SPIFFS (SPI Flash File System)”, 2017. [Online]. Available at:
https://github.com/pellepl/spiffs. [Acessado: 12-ago-2019].
[13] Espressif, “SPIFFS Filesystem”. [Online]. Available at:
https://docs.espressif.com/projects/esp-idf/en/latest/api-
reference/storage/spiffs.html. [Acessado: 04-ago-2019].
[14] P. Andersson, “spiffs/TECH_SPEC”.
43
[15] S. Bipasha Biswas e M. Tariq Iqbal, “Solar Water Pumping System Control
Using a Low Cost ESP32 Microcontroller”, in 2018 IEEE Canadian Conference
on Electrical Computer Engineering (CCECE), 2018, p. 1–5.
[16] G. R. P. da Silva, “Implantação de um sistema de automação predial utilizando
plataforma em nuvem.”, Universidade Federal de Ouro Preto, 2018.
[17] C. Rajendra Prasad, “Internet of Things Based Home Monitoring and Device
Control Using Esp32”, International Journal of Recent Technology and
Engineering (IJRTE), vol. 8, p. 58–62, 2019.
[18] N. X. P. Semiconductors, “UM10204 I2C-bus specification and user manual”,
Semiconductors. p. 1–64, 2014.
[19] Circuit Basics, “Basics of the I2C Communication Protocol”, 2016. [Online].
Available at: http://www.circuitbasics.com/basics-of-the-i2c-communication-
protocol/. [Acessado: 07-ago-2019].
[20] F. Durda, “Tutorial sobre comunicações seriais e UART”, FreeBSD, 1996.
[Online]. Available at: https://www.freebsd.org/doc/pt_BR/articles/serial-
uart/article.html. [Acessado: 20-ago-2019].
[21] Circuit Basics, “Basics of UART Communication”, Electronics Hub, 2017.
[Online]. Available at: https://www.electronicshub.org/basics-uart-
communication/.
[22] S. Electronics, “Bi-Directional Logic Level Converter Hookup Guide”, SparkFun
Electronics. [Online]. Available at: https://learn.sparkfun.com/tutorials/bi-
directional-logic-level-converter-hookup-guide. [Acessado: 07-ago-2019].
[23] V. Coskun, B. Ozdenizci, e K. Ok, “A Survey on Near Field Communication
(NFC) Technology”, Wireless Personal Communications, vol. 71, no 3, p. 2259–
2294, ago. 2013.
[24] ISO, “ISO/IEC18092 - Information technology — Telecommunications and
information exchange between systems — Near Field Communication —
Interface and Protocol (NFCIP-1)”. International Organization for
Standardization, p. 52, 2013.
[25] K. Finkenzeller, RFID Handbook: Fundamentals and Applications in Contactless
Smart Cards, Radio Frequency Identification and Near-Field Communication.
2010.
[26] M. Mueggenberg, “Wireless Battery-less Sensor Device Using NFC”. 2017.
44
[27] E. International, “Standard ECMA-340 - Near Field Communication - Interface
and Protocol (NFCIP-1)”. ECMA International, p. 52, 2013.
[28] NIC.BR, “O NTP”, NIC.BR. [Online]. Available at: https://ntp.br/ntp.php.
[Acessado: 11-ago-2019].
[29] P. R. Torres Jr., “Caracterização da rede de sincronização na Internet”, 2007.
[30] V. Billy Rakesh Roy, S. Dessai, S. G Shiva, e P. Yadav, “Design and
Development of ARM Processor Based Web Server”, POSTER PAPER
International Journal of Recent Trends in Engineering, vol. 1, 2009.
[31] I. Allafi e T. Iqbal, “Design and implementation of a low cost web server using
ESP32 for real-time photovoltaic system monitoring”, in 2017 IEEE Electrical
Power and Energy Conference (EPEC), 2017, p. 1–5.
[32] D. Gupta, “Low cost data logger and monitoring system for a small solar PV
energy system”, 2018.
[33] M. Sahani, C. Nanda, A. K. Sahu, e B. Pattnaik, “Web-based online embedded
door access control and home security system based on face recognition”, in
2015 International Conference on Circuits, Power and Computing Technologies
[ICCPCT-2015], 2015, p. 1–6.
[34] C. Rajendra Prasad, “Internet of Things Based Home Monitoring and Device
Control Using Esp32”, vol. 8, p. 58–62, 2019.
[35] F. Y. Limpraptono, H. Sudibyo, A. A. P. Ratna, e A. S. Arifin, “The design of
embedded web server for remote laboratories microcontroller system
experiment”, in TENCON 2011 - 2011 IEEE Region 10 Conference, 2011, p.
1198–1202.
[36] R. G. Koshatwar e S. D. Sawant, “Remote monitoring and control of industrial
parameters using embedded web server”, in 2016 10th International Conference
on Intelligent Systems and Control (ISCO), 2016, p. 1–4.
[37] X. Yi, M. Zhou, e J. Liu, “Design of smart home control system by Internet of
Things based on ZigBee”, in 2016 IEEE 11th Conference on Industrial
Electronics and Applications (ICIEA), 2016, p. 128–133.
[38] Y. Shafranovich, “RFC 4180 Common Format and MIME Type for CSV Files”,
2005. 2005.
[39] Arduino, “Arduino Software (IDE)”. [Online]. Available at:
https://www.arduino.cc/en/Guide/Environment. [Acessado: 30-ago-2019].
45
[40] Espressif Systems, “Installation instructions using Arduino IDE Boards
Manager”. [Online]. Available at: https://github.com/espressif/arduino-
esp32/blob/master/docs/arduino-ide/boards_manager.md. [Acessado: 11-jan-
2019].
[41] Espressif Systems, “Async Web Server for ESP8266 and ESP32”. [Online].
Available at: https://github.com/me-no-dev/ESPAsyncWebServer. [Acessado:
20-jun-2019].
[42] Espressif Systems, “Async TCP Library for ESP32”. [Online]. Available at:
https://github.com/me-no-dev/AsyncTCP. [Acessado: 20-jun-2019].
[43] Espressif Systems, “Arduino core for ESP32 WiFi chip”. [Online]. Available at:
https://github.com/espressif/arduino-esp32. [Acessado: 12-jan-2019].
[44] H. Bjorn, “Introduction”. [Online]. Available at: https://www.ntppool.org/pt/.
[Acessado: 30-ago-2019].
[45] Espressif Systems, “Main include file for the Arduino SDK”. [Online]. Available
at: https://github.com/espressif/arduino-
esp32/blob/master/cores/esp32/Arduino.h. [Acessado: 29-ago-2019].
[46] H. Gochkov, “arduino-esp32/SPIFFS.h at master - espressif/arduino-esp32”,
Espressif Systems. [Online]. Available at: https://github.com/espressif/arduino-
esp32/blob/master/libraries/SPIFFS/src/SPIFFS.h. [Acessado: 24-mar-2019].
[47] Espressif Systems, “FS.h - File System Wrapper”, Espressif Systems. [Online].
Available at: https://github.com/espressif/arduino-
esp32/blob/master/libraries/FS/src/FS.h. [Acessado: 11-mar-2019].
[48] Osoyoo, “Osoyoo Pro Micro Board”. [Online]. Available at:
http://osoyoo.com/2018/06/25/osoyoo-pro-micro-board/. [Acessado: 28-ago-
2019].
[49] Heltec Automation, “Wifi Kit 32”. [Online]. Available at:
http://www.heltec.cn/download/WIFI_Kit_32-Diagram.pdf. [Acessado: 28-ago-
2019].
[50] Elechouse, “Pn532 Nfc Rfid Module User Guide”. [Online]. Available at:
http://www.elechouse.com/elechouse/images/product/PN532 NFC
Module/PN532 NFC RFID Module Manual.pdf. [Acessado: 28-ago-2019].
[51] Baú da Eletrônica, “Conversor de Nível Lógico 3,3-5V Bidirecional”. [Online].
Available at: http://www.baudaeletronica.com.br/conversor-de-nivel-logico-3-3-
46
5v-bidirecional.html. [Acessado: 28-ago-2019].
[52] Vida de Silício, “Módulo Relé 2 Canais 5V”. [Online]. Available at:
https://www.vidadesilicio.com.br/modulo-rele-2-canais. [Acessado: 28-ago-
2019].
[53] Elechouse, “NFC library for Arduino”. [Online]. Available at:
https://github.com/elechouse/PN532. [Acessado: 22-abr-2019].
[54] Adafruit, “Adafruit-PN532”. [Online]. Available at:
https://github.com/adafruit/Adafruit-PN532. [Acessado: 20-abr-2019].
[55] L. Faccin, “Port of Adafruit PN532 Library for Arduino to ESP32”. [Online].
Available at: https://github.com/lucafaccin/esp-pn532. [Acessado: 15-maio-
2019].
47
Apêndice A – Diagramas e esquemáticos
Diagrama de pinagem do Arduino Pro Micro.
48
Diagrama de Pinagem do ESP32.
49
Apêndice B – Logs de Execução
Leitura de TAGS NFC pela interface Serial do Arduino.
50
Teste do registro de operações, escrita no arquivo conforme operações.
51
Exemplo de cadastro de usuários.
52
Apêndice C – Código Fonte do Arduino
/* When the number after #if set as 1, it will be switch to SPI Mode*/
#if 0
#include <SPI.h>
#include <PN532_SPI.h>
#include "PN532.h"
PN532_SPI pn532spi(SPI, 10);
PN532 nfc(pn532spi);
/* When the number after #elif set as 1, it will be switch to HSU Mode*/
#elif 0
#include <PN532_HSU.h>
#include <PN532.h>
PN532_HSU pn532hsu(Serial1);
PN532 nfc(pn532hsu);
/* When the number after #if & #elif set as 0, it will be switch to I2C Mode*/
#else
#include <Wire.h>
#include <PN532_I2C.h>
#include <PN532.h>
#include <NfcAdapter.h>
PN532_I2C pn532i2c(Wire);
PN532 nfc(pn532i2c);
#endif
/* File Manipulation Libraries */
#include <EEPROM.h>
#define BAUD_RATE 9600
// Serial 1 = 0, 1 (Arduino Pro Micro) / Serial = USB Connection
uint8_t uidMatrix[2][7] = {{ 0, 0, 0, 0, 0, 0, 0 } , { 0, 0, 0, 0, 0, 0, 0 } };
void setup(void) {
Serial.begin(115200);
Serial.println("Hello!");
53
Serial1.begin(BAUD_RATE, SERIAL_8N1); // Baud Rate for the UART serial
connection configured on Serial1 - MUST BE the same on both channels
Serial.println("Serial Communication Initialized at the Baud Rate");
//Serial.print();
nfc.begin(); // Initialize NFC Communication
uint32_t versiondata = nfc.getFirmwareVersion();
if (! versiondata) {
Serial.print("Didn't find PN53x board");
while (1); // halt
}
// Got ok data, print it out!
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
// Set the max number of retry attempts to read from a card
// This prevents us from waiting forever for a card, which is
// the default behaviour of the PN532.
nfc.setPassiveActivationRetries(0xFF);
// configure board to read RFID tags
nfc.SAMConfig();
Serial.println("Waiting for an ISO14443A card");
}
void loop(void) {
boolean success;
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on
ISO14443A card type)
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
// 'uid' will be populated with the UID, and uidLength will indicate
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0],
&uidLength);
54
if (success) {
Serial.println("Found a card!");
Serial.print("UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
Serial.print("UID Value: ");
uint8_t uidBuffer [] = { 0, 0, 0, 0, 0, 0, 0 };
for (uint8_t i=0; i < uidLength; i++)
{
Serial.print(" 0x");
Serial.print(uid[i], HEX);
uidBuffer[i] = uid[i];
// Passing data through Serial1 to ESP32
Serial1.print(uid[i], HEX);
}
Serial.println("");
}
/* END - VALIDATION CODE */
else
{
// PN532 probably timed out waiting for a card
Serial.println("Timed out waiting for a card");
}
delay(1000);
}
55
Apêndice D – Código Fonte do Cadastro
de Usuários – ESP32
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include "String.h"
#include "SPIFFS.h"
// Serial Communication - NFC Data from Arduino
#define RXD2 16
#define TXD2 17
#define BAUD_RATE 9600 // Baud rate for the Serial Communication
#define BUFFER_SZ 100
#define TAG_BUFFER 9
// WEB ACCESS
const char* ssid = "SSID";
const char* password = "password";
//WiFiServer server(80);
AsyncWebServer server(80);
const char htmlCode[] PROGMEM = {"<!DOCTYPE html><html lang=\"pt-
br\"><head> <meta charset=\"utf-8\"> <meta name=\"viewport\"
content=\"width=device-width, initial-scale=1, shrink-to-fit=no\"> <link
rel=\"stylesheet\"
href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">
<title>SisCARC</title> <script type=\"text/javascript\">function getTag(){var
xhttp=new XMLHttpRequest(); xhttp.onreadystatechange=function(){if
56
(this.readyState==4 && this.status==200){console.log(this.responseText); var
tag=this.responseText; var element=document.getElementById('tag1').value=tag;}};
xhttp.open(\"GET\", \"./tag\", true); xhttp.send();}</script> </head><body> <div
class=\"container mt-5\"> <form action=\"./post\" method=\"POST\"> <div
class=\"form-group row\"> <input type=\"button\" onclick=\"getTag();\" value=\"Ler
TAG\" class=\"col-sm-2 col-form-label btn btn-primary\"> <div class=\"col-sm-3\">
<input type=\"text\" class=\"form-control\" name=\"tag\" id=\"tag1\">
</div></div><div class=\"form-group row\"> <label for=\"nome\" class=\"col-sm-2
col-form-label\">Nome:</label> <div class=\"col-sm-6\"> <input type=\"text\"
class=\"form-control\" name=\"nome\"> </div></div><div class=\"form-group row\">
<label for=\"apartamento\" class=\"col-sm-2 col-form-label\">Apartamento:</label>
<div class=\"col-sm-3\"> <input type=\"text\" class=\"form-control\" name=\"apto\">
</div></div><div class=\"form-group row\"> <label for=\"bloco\" class=\"col-sm-2
col-form-label\">Bloco:</label> <div class=\"col-sm-3\"> <input type=\"text\"
class=\"form-control\" name=\"block\"> </div></div><div class=\"row\"> <div
class=\"col-sm-6 text-center\"> <button type=\"submit\" class=\"btn btn-
primary\">Cadastrar</button> </div></div></form> </div></body></html>"};
const char* PARAM_MESSAGE = "message";
// User Data
#define NUMBER_USERDATA 4
#define MAX_SIZE_USER_REG 100
// char userRegBuffer[MAX_SIZE_USER_REG] = "";
//#define MAX_LENGTH_USERDATA 20
//String userData[NUMBER_USERDATA];
#define STRING1_LENGTH 29
// File Operations
const char * userFile = "/users.csv";
char userHead[STRING1_LENGTH] = "ID,NOME,APT,BLOCO,SITUACAO\n";
// SubFunctions
57
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\r\n", dirname);
File root = fs.open(dirname);
if(!root){
Serial.println("- failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println(" - not a directory");
return;
}
File file = root.openNextFile();
while(file){
if(file.isDirectory()){
Serial.print(" DIR : ");
Serial.println(file.name());
if(levels){
listDir(fs, file.name(), levels -1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print("\tSIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void appendFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Appending to file: %s\r\n", path);
58
File file = fs.open(path, FILE_APPEND);
if(!file){
Serial.println("- failed to open file for appending");
return;
}
if(file.print(message)){
Serial.println("- message appended");
} else {
Serial.println("- append failed");
}
}
int readFile(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\r\n", path);
File file = fs.open(path);
if(!file || file.isDirectory()){
Serial.println("- failed to open file for reading");
return 1;
}
Serial.println("- read from file:");
while(file.available()){
Serial.write(file.read());
}
return 0;
}
void deleteFile(fs::FS &fs, const char * path){
Serial.printf("Deleting file: %s\r\n", path);
if(fs.remove(path)){
Serial.println("- file deleted");
59
} else {
Serial.println("- delete failed");
}
}
void notFound(AsyncWebServerRequest *request) {
request->send(404, "text/plain", "Not found");
}
void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t
index, size_t total){
if(!index){
Serial.printf("BodyStart: %u B\n", total);
}
for(size_t i=0; i<len; i++){
Serial.write(data[i]);
}
if(index + len == total){
Serial.printf("BodyEnd: %u B\n", total);
}
}
void setup()
{
Serial.begin(115200);
Serial2.begin(BAUD_RATE, SERIAL_8N1, RXD2, TXD2); // Setting Serial UART
Communication
Serial.println();
// FileSystem Initialization
if(!SPIFFS.begin(true)){
Serial.println("SPIFFS Mount Failed");
return;
}
60
listDir(SPIFFS, "/", 0);
deleteFile(SPIFFS, userFile);
// If File doesnt exist
if (readFile(SPIFFS, userFile)){
//Serial.println("Teste File Not Found");
appendFile(SPIFFS, userFile, userHead);
}
readFile(SPIFFS, userFile);
// Connecting to a WiFi network
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// Web Server Setup for webpage
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/html", htmlCode);
});
/* TEST FOR TAG AUTHENTICATION */
server.on("/tag", HTTP_GET, [](AsyncWebServerRequest *request){ // /tag
while (!Serial2.available()){
61
// Wait stuck on this loop while there is no serial data
}
char serialBuffer[TAG_BUFFER] = "";
int c = 0;
size_t pos = 0;
while (Serial2.available()){
c = Serial2.read();
if (pos < TAG_BUFFER-1) {
serialBuffer[pos++] = c;
}
}
/* TAG INFO ON THE BUFFER */
if (pos > 0){
Serial.println("TAG Detected: ");
pos = 0;
String serialBufferString = String(serialBuffer);
Serial.println(serialBufferString);
request->send(200, "text/html", serialBufferString);
}
});
/* END OF TEST FOR TAG AUTHENTICATION */
// Send a POST request to <IP>/post with a form field message set to <message>
server.on("/post", HTTP_POST, [](AsyncWebServerRequest *request){ // /form
String message;
if (request->hasParam(PARAM_MESSAGE, true)) {
message = request->getParam(PARAM_MESSAGE, true)->value();
} else {
message = "No message sent";
// Try to redirect back to the form page and or give a success message (maybe
after user is written inside the file)
}
62
// Check parameters
String userData[NUMBER_USERDATA];
String userFileString ="";
//userData[0] = "00000000"; // Temporary initialization before TAG Registering
int args = request->args();
for(int i=0;i<args;i++){
// Save args on a data array
//Serial.printf("ARG[%s]: %s\n", request->argName(i).c_str(), request-
>arg(i).c_str());
// Handle number of arguments > array length
// Initialize userData[0] as a fixed tag length for now => [i+1]
userData[i] = request->arg(i); // Saving variables to array for user data
//strcpy (userData[i], request->arg(i).c_str());
//Serial.println("Variable Saved.");
//Serial.print("Value i is ");
//Serial.println(userData[i]);
userData[i].concat(","); //Separate the values by Comma
}
/* Write String array into the file as registered Users */
Serial.println("Printing User Data to be registered on file...");
for(int i=0;i<NUMBER_USERDATA;i++){
userFileString += userData[i];
//strlcat (userRegBuffer, userData[i].c_str() , (MAX_SIZE_USER_REG -
strlen(userRegBuffer)) ); // Stream user data buffer to writefile
// OR USE APPEND FILE DIRECTLY ?
//Serial.println(userFileString);
//Serial.println(",");
}
/* Write New User Information on file */
/* if no information sent */
if (userFileString.length() <= 10){
Serial.println("Informações de usuário insuficientes");
Serial.println("Tente novamente preenchendo o formulário.");
63
}
else{
userFileString += "ATIVA\n"; // STATUS + end of line to write on file
Serial.println("Ready to write on file");
Serial.println(userFileString);
appendFile(SPIFFS, userFile, userFileString.c_str());
Serial.println("User Registered Successfully");
Serial.println("New Registered Users File:");
readFile(SPIFFS, userFile);
// request->send(200, "text/plain", "Hello, POST: " + message);
// Print redirect page on POST page
delay(1000);
request->send(200, "text/html", "<html><head><meta http-equiv=\"Refresh\"
content=\"0; url=./\"></head></html>");
}
});
server.onNotFound(notFound);
server.begin();
}
//int value = 0;
void loop(){
}
64
Apêndice E – Código Fonte da Operação
– ESP32
// FileSystem Libraries
#include "FS.h"
#include "SPIFFS.h"
#include "String.h"
// WiFi Access
#include <WiFi.h>
// Date & Time
#include "time.h"
/* DEFINITIONS - GLOBAL VARIABLES & CONSTANTS */
#define USERS "/users.csv" // file used for registered users
#define CARTS "/carts.csv" // file used for registered users
#define OPERATIONS "/operation.csv" // file used for registered users
// Dummy Data
#define STRING1_LENGTH 100
#define STRING2_LENGTH 40
// USERS FILE
char string1[STRING2_LENGTH] = "ID,NOME,APT,BLOCO,SITUACAO\n";
char string2[STRING2_LENGTH] = "4A69AC14,RAMON,152,A,ATIVA\n";
65
char string3[STRING2_LENGTH] = "6A631D10,ROMULO,152,A,ATIVA\n";
char string4[STRING2_LENGTH] = "460519A8,FELIPE,345,C,ATIVA\n";
String tag1 = String("4A69AC14");
// LOG FILE
char stringBuffer[STRING1_LENGTH] = "";
//char cartBuffer[STRING2_LENGTH] = "";
// CARTS FILE
//char stringCart[STRING2_LENGTH] = "SLOT,SITUACAO,TAG_ID\n";
// Serial Communication - NFC Data from Arduino
#define RXD2 16
#define TXD2 17
#define BAUD_RATE 9600 // Baud rate for the Serial Communication
/* Definition of variables for the main program */
// Data Validation definitions
#define BUFFER_SZ 100
#define TAG_BUFFER 9
String cart1Flag = "00000000";
String cart2Flag = "00000000";
66
// Relay
#define PIN1 22
#define PIN2 18
#define PIN1_SLOT 1 // HIGH = CLOSED / LOW = OPEN
#define PIN2_SLOT 2
// File Read
int c; // byte buffer
size_t pos = 0; // current write position in buffer
char fileBuffer[BUFFER_SZ]; // File Read Buffer
// WEB ACCESS
const char* ssid_1 = "SSID";
const char* password_1 = "Password";
WiFiServer server(80);
// DATE & TIME
const char* ntpServer = "pool.ntp.org";
// OffSet for the desired Timezone
const long gmtOffset_sec = -14400;
const int daylightOffset_sec = 3600;
67
// Operation Log
//const char * OPERATIONS = "/operation.csv";
// 1 = Fechado (disponivel no slot) / 2 = Aberto (carrinho indisponivel / em uso)
/* External Functions */
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\r\n", dirname);
File root = fs.open(dirname);
if(!root){
Serial.println("- failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println(" - not a directory");
return;
}
File file = root.openNextFile();
while(file){
if(file.isDirectory()){
Serial.print(" DIR : ");
Serial.println(file.name());
if(levels){
listDir(fs, file.name(), levels -1);
}
68
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print("\tSIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void appendFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Appending to file: %s\r\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file){
Serial.println("- failed to open file for appending");
return;
}
if(file.print(message)){
Serial.println("- message appended");
} else {
Serial.println("- append failed");
}
}
int readFile(fs::FS &fs, const char * path){
69
Serial.printf("Reading file: %s\r\n", path);
File file = fs.open(path);
if(!file || file.isDirectory()){
Serial.println("- failed to open file for reading");
return 1;
}
Serial.println("- read from file:");
while(file.available()){
Serial.write(file.read());
}
return 0;
}
void deleteFile(fs::FS &fs, const char * path){
Serial.printf("Deleting file: %s\r\n", path);
if(fs.remove(path)){
Serial.println("- file deleted");
} else {
Serial.println("- delete failed");
}
}
void wifiSetup (const char* ssid, const char* password){
// We start by connecting to a WiFi network
70
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
}
void getTime(char * timeString){
struct tm timeinfo;
if(!getLocalTime(&timeinfo)){
Serial.println("Failed to obtain time");
71
return;
}
// Function to format the "timeinfo" variable and copy it to a string "timeString"
strftime(timeString, STRING2_LENGTH-1, "%d-%m-%Y,%H:%M:%S", &timeinfo);
}
// Procurar expressao em arquivo => seekFile (SPIFFS, nomeDoArquivo, String que
receberá expressão)
void seekFile (fs::FS &fs, const char * path, String seekBuffer ){
// Declare Variables
byte r = 0; //read characters from file
size_t index = 0;
size_t line = 0; // Checar nome de variável depois
char seekChar[BUFFER_SZ];
// Check file availability
Serial.printf("Seeking text on file: %s\r\n", path);
File file = fs.open(path);
if(!file || file.isDirectory()){
Serial.println("- failed to open file for reading");
return;
}
// Condition for getting values
while (file.peek() != -1) { // Or file.available() ?
// If we get a delimiter, then we have a complete element.
if (file.peek() == ',') {
72
r = file.read();
seekChar[index] = '\0'; // terminate the string
seekChar[index++] = r;
}
else if (file.peek() == '\n'){
file.read();
line++;
index = 0;
String seekBuffer = String(seekChar);
//String stringCart = String(stringCart);
seekBuffer = seekBuffer.substring(0,seekBuffer.indexOf(","));
}
}
// Varre o arquivo inteiro, mas ai teria que saber o que quer encontrar ou retornar
sempre que encontrar algum valor e inserir essa função dentro de um loop (seekBuffer é
o valor encontrado)
}
/* Initialization Program */
void setup() {
Serial.begin(115200);
Serial2.begin(BAUD_RATE, SERIAL_8N1, RXD2, TXD2); // Setting Serial UART
Communication
// Mount FileSystem
if(!SPIFFS.begin(true)){
Serial.println("SPIFFS Mount Failed");
73
return;
}
Serial.println("SPIFFS Mounted Successfully");
listDir(SPIFFS, "/", 0);
// Erase Dummy File if it already exists
//deleteFile(SPIFFS, USERS);
if (readFile(SPIFFS, USERS)){
appendFile(SPIFFS, USERS, string1);
}
/* Creating the Dummy File */
/*appendFile(SPIFFS, USERS, string2);
appendFile(SPIFFS, USERS, string3);
appendFile(SPIFFS, USERS, string4);*/
/* End of Dummy Data */
Serial.println("File Written:");
readFile(SPIFFS, USERS);
readFile(SPIFFS, OPERATIONS);
deleteFile(SPIFFS, OPERATIONS);
/* Relay Pins Setup */
pinMode(PIN1, OUTPUT);
pinMode(PIN2, OUTPUT);
digitalWrite(PIN2, HIGH);
digitalWrite(PIN1, HIGH); // HIGH state is turned off
74
/* WiFi Connection */
wifiSetup(ssid_1 , password_1);
/* Date & Time Configuration */
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
getTime(stringBuffer);
//Serial.println("Time Initialized");
//Serial.println(stringBuffer);
/* Carts File */
//deleteFile(SPIFFS, CARTS); // clean-up
/*Serial.printf("Reading file: %s\r\n", CARTS);
File carts = SPIFFS.open(CARTS);
if(!carts || carts.isDirectory()){
Serial.println("- failed to open file for reading");
appendFile(SPIFFS, CARTS, stringCart);
}
readFile(SPIFFS, CARTS);*/
// CARTS FLAG INITIALIZED
}
/* Main Program - Loop */
void loop() {
/* CURRENT RELAYS STATUS */
//Serial.printf("Carrinho 1: %i\r\n", digitalRead(PIN1));
//Serial.printf("Carrinho 2: %i\r\n", digitalRead(PIN2));
75
/* TAG PRESENCE VERIFICATION */
Serial.println("Esperando por TAG...");
while (!Serial2.available()){
// Wait stuck on this loop while there is no serial data
}
/* BUFFER SERIAL DATA (FROM NFC SENSOR ON SERIAL INPUT) */
char serialBuffer[TAG_BUFFER] = "";
while (Serial2.available()){
c = Serial2.read();
if (pos < TAG_BUFFER-1) { // To not overflow the Buffer Size
serialBuffer[pos++] = c;
}
// else ?? - ERROR - EXCEEDED BUFF LIMIT
}
/* TAG INFO ON THE BUFFER */
if (pos > 0){
Serial.println("TAG Detectada: ");
pos = 0;
String serialBufferString = String(serialBuffer);
Serial.println(serialBufferString);
// Initialize Operation String
String operationString = String(""); // Only on TAG Validated, reorganize it after
/* END OF - TAG PRESENCE VERIFICATION */
76
// Serial.println("Getting tags for each line...");
// Open File to work with
File file = SPIFFS.open(USERS);
if(!file || file.isDirectory()){
Serial.println("- Falha ao abrir o arquivo de usuários");
return;
}
/* 1) Scan file
*
* Scan files until the end.
* Get the first variable on each line of the CSV file
*
* - Open File and starting reading it on position 0
* - Get buffer variable to get file information char by char
* - Conditionals for "," and "\n"
* - Print on Serial each variable it takes - validate that later
* - EOF = When there is no more file.available()
*/
// Initialize local variables for iteration
size_t line = 0; // File reading line counter
// boolean authentication = false;
/* Read file - all the logic on iterations should be inside this loop */
// Consider reviewing and trying file.read(buf, len) - with some specific len? (issues
77
with data not available on file ? any precaution but able to use it?)
/* FILE SCANNING - BEGIN */
while (file.peek() != -1) { // Or file.available() ?
// If we get a delimiter, then we have a complete element.
if (file.peek() == ',') {
c = file.read();
fileBuffer[pos] = '\0'; // terminate the string
fileBuffer[pos++] = c;
}
else if (file.peek() == '\n'){
file.read();
line++;
pos = 0;
String fileBufferString = String(fileBuffer);
String stringCart = String(stringCart);
fileBufferString = fileBufferString.substring(0,fileBufferString.indexOf(",")); //
Get only the first element before the "," on each line
if ((fileBufferString.compareTo(serialBufferString)) == 0) { // Compares TAG in
the buffer with the one on INPUT
/* TAG VALIDATED */
// authentication = true;
Serial.println("TAG Autorizada!");
// TEST FOR CARTS FLAG
//Serial.println("Test for Carts Flag");
//Serial.printf("Carrinho 1 Current ID: %s\r\n", cart1Flag.c_str());
78
//Serial.printf("Carrinho 2 Current ID: %s\r\n", cart2Flag.c_str());
getTime(stringBuffer);
/* VALIDATION FLOW */
/* CASE 1 - USER HAS CART TO DELIVER */
/* CASE 1.1 - CART 1 TO BE DELIVERED */
if (cart1Flag == serialBufferString){ // Adicionar um OR || e englobar um if filho
para cada carrinho
digitalWrite(PIN1, 1); // closes SLOT 1
cart1Flag = "00000000"; //removes the flag from the cart
//Serial.printf("Carrinho 1 Current ID: %s\r\n", cart1Flag.c_str());
// Write on Operations File
operationString += String(stringBuffer) + "," + serialBufferString + "," +
String(PIN1_SLOT) + "," + digitalRead(PIN1) + "\n";
}
/* CASE 1.2 - CART 2 TO BE DELIVERED */
else if (cart2Flag == serialBufferString){
digitalWrite(PIN2, 1); // closes SLOT 2
cart2Flag = "00000000"; //removes the flag from the cart
//Serial.printf("Carrinho 2 Current ID: %s\r\n", cart2Flag.c_str());
// Write on Operations File
operationString += String(stringBuffer) + "," + serialBufferString + "," +
String(PIN2_SLOT) + "," + digitalRead(PIN2) + "\n";
}
/* CASE 2 - CART 1 IS AVAILABLE */
else if (digitalRead(PIN1) == 1){
digitalWrite(PIN1, 0); // opens SLOT 1
79
// Set Cart 1 flag
cart1Flag = serialBufferString;
//Serial.printf("Carrinho 1 Current ID: %s\r\n", cart1Flag.c_str());
operationString += String(stringBuffer) + "," + serialBufferString + "," +
String(PIN1_SLOT) + "," + digitalRead(PIN1) + "\n";
}
/* CASE 3 - CART 1 IS UNAVAILABLE AND CART 2 IS AVAILABLE */
else if (digitalRead(PIN1) == 0 && digitalRead(PIN2) == 1){
digitalWrite(PIN2, 0); // closes SLOT 2
// Sets Cart2 Flag
cart2Flag = serialBufferString;
//Serial.printf("Carrinho 2 Current ID: %s\r\n", cart2Flag.c_str());
//Serial.printf("Carrinho 2: %i\r\n", digitalRead(PIN2));
// OPERATIONAL LOG
operationString += String(stringBuffer) + "," + serialBufferString + "," +
String(PIN2_SLOT) + "," + digitalRead(PIN2) + "\n";
}
/* CASE 4 - NO CARTS AVAILABLE */
else if (digitalRead(PIN1) == 0 && digitalRead(PIN2) == 0){
Serial.println("Não temos mais carrinhos disponíveis no momento.");
Serial.println("Tente mais tarde.");
}
operationString.toCharArray(stringBuffer, STRING1_LENGTH);
appendFile(SPIFFS, OPERATIONS, stringBuffer);
readFile(SPIFFS, OPERATIONS);
return;
80
}
}
// Otherwise, store the character in the buffer.
else if (pos < BUFFER_SZ-1) {
c = file.read();
fileBuffer[pos++] = c;
}
}
/* USER TAG NOT REGISTERED */
Serial.println("TAG Invalida!");
getTime(stringBuffer);
Serial.println(stringBuffer);
}
/* NO SERIAL INFO FOUND
Set debug message ?
Set delay between attempts?
*/
// Serial.println("Waiting for Tag");
// delay(10000);
}