Usando Node.js e o framework Express para acessar os pinos de GPIO da Colibri VF61 via Web

Node

Este artigo é direcionado a qualquer pessoa que esteja começando a desenvolver uma aplicação web em Linux embarcado para acessar os pinos de uso geral de uma placa, que serão referidos neste artigo como GPIO, de tal maneira que o usuário possa controlar e/ou monitorar um sistema remotamente. A aplicação aqui desenvolvida é implementada na placa Colibri VF61 COM (Computador em Módulo) da Toradex + Placa Base Iris, apresentada na figura 1, em conjunto com uma placa na qual há  LEDs e chaves. O objetivo principal é guiar o leitor pelo processo de desenvolver código em Node para acessar os pinos da placa através do sistema de arquivos, construindo uma interface simples, mas amigável, e usando o framework Express para hospedar um servidor web básico que se comunica com o cliente usando o método AJAX. Para melhor entendimento da aplicação desenvolvida para o cliente (client-side), é recomendado o conhecimento prévio básico de HTML+CSS, jQuery e AJAX, embora o leitor possa abstrair esta parte e focar na aplicação do servidor, caso você deseje obter somente uma visão geral sobre Node. Todos os códigos desenvolvidos neste guia podem ser copiados dos seguintes repositórios do Github: nodeGPIOdemo, WebNodeGPIOdemo e WebNodeMultiGPIOdemo.

 

node-VF61-01
Figura 1: Toradex VF61 + Placa Base Iris

 

 

Node.js

 

Node.js é um ambiente interpretador da linguagem Javascript desenvolvido para rodar no servidor (server-side). Uma vez que em Linux é possível usar o sistema de arquivos como um meio para acessar o hardware do sistema e o Node possui um módulo nativo para trabalhar com o sistema de arquivos, uma aplicação pode ser desenvolvida com o objetivo de acessar os pinos de GPIO providos pelo sistema. Node também possui outros módulos como o HTTP, que podem ser usados para implementar um servidor web, mas o framework Express torna esta tarefa muito mais fácil, e essa é a razão pela qual vamos usá-lo. Uma visão geral sobre Node.js/Javascript, assim como diversas outras linguagens de programação aplicadas a sistemas embarcados, pode ser encontrada aqui e diversas informações, curiosidades, dicas e artigos dedicados exclusivamente ao Node podem ser encontradas no NodeBR.

 

 

Javascript

 

Javascript é uma linguagem de programação interpretada pelo cliente, o que significa que ela é processada pelo navegador do usuário, neste caso. Combinada com HTML e CSS, Javascript possibilita a criação de páginas web interativas, conhecidas como design responsivo. Uma vez que programar em Javascript pode ser um pouco demorado, existe uma biblioteca cross-browser chamada jQuery que foi pensada para simplificar tarefas como manipulação do DOM e de eventos, e o uso simplificado de métodos AJAX; este sendo um conjunto de técnicas usadas para comunicação assíncrona com o servidor e, portanto, possibilitando a atualização dinâmica do conteúdo da página web. Para aprender um pouco mais, este site tem uma ótima introdução à linguagem e você pode aprender colocando a mão na massa. Caso você tenha um pouco de domínio do inglês, uma quantidade enorme de informações úteis e ótima fonte de consulta podem ser obtidas tanto para Javascript, quanto para jQuery.

 

 

O módulo Colibri VF61 e a Placa-base Iris

 

Node-Colibri-VF61-02
Figura 2: Colibri VF61

 

Com relação ao módulo Colibri VF61, apresentado na figura 2, este possui até 99 pinos que podem ser configurados para uso como GPIO. Como estamos usando o módulo com a placa-base Iris, indicada na figura 3, temos 8 pinos de GPIO que podem ser usados diretamente, dos quais vamos usar 6 neste tutorial e outros 18 pinos que precisariam de configuração extra para serem usados como GPIO.

 

Node-Iris-Carrier-Board-03
Figura 3: Iris Carrier Board (placa-base)

 

Os pinos da Iris escolhidos para uso foram do 13 até o 18, sendo o interfaceamento para 3 chaves ativas em nível baixo (pinos 13-15) e 3 LEDs ativos em nível alto (pinos 16-18). Você pode acessar o datasheet da Colibri VF61 e o datasheet técnico da placa-base Iris, caso queira configurar mais/outros pinos de GPIO. Como fonte de alimentação há um pino +5V, um pino +3.3V e 5 pinos de terra disponíveis no conector da barra de pinos, mas atente-se ao fato de que, caso o seu hardware adicional precise de mais do que [email protected] e/ou [email protected], então você precisa usar uma fonte separada. Se você tem alguma dúvida com relação ao número dos pinos, você pode se referir rapidamente à tabela 1 e, em mais detalhes, aos links dos datasheets fornecidos acima e a uma tabela que relaciona o nome dos pinos do SoC VF61 com os nomes usados pelo Linux.

 

Tabela 1: Correspondência entre os nomes dos pinos da Iris, conector SODIMM, Vybrid e Kernel.

Iris (x16)

SODIMM (x1)

Vybrid

Kernel

GPIO padrão

Iris (x16)

SODIMM (x1)

Vybrid

Kernel

GPIO padrão

01

26

reset

  

21

 

gnd*

  

02

 

gnd*

  

22

02

adc**

  

03

 

gnd*

  

23

04

adc**

  

04

87

reset

  

24

06

adc**

  

05

194

ptb15

37

 

25

08

adc**

  

06

196

ptb14

36

 

26

 

agnd*

  

07

 

gnd*

  

27

35

ptb10

32

 

08

88

ptd8

87

 

28

33

ptb11

33

 

09

86

ptd5

84

 

29

32

ptd3

82

 

10

90

ptd6

85

 

30

34

ptd2

81

 

11

92

ptd7

86

 

31

36

ptd1

80

 

12

 

+5V*

  

32

38

ptd0

97

 

13

98

ptc1

46

x

33

 

+3,3V*

  

14

133

ptd9

88

x

34

19

ptb5

27

 

15

103

ptc3

48

x

35

21

ptb4

26

 

16

101

ptc2

47

x

36

 

gnd

  

17

97

ptc5

50

x

37

59

ptb0/ptc7

22/52

 

18

85

ptc8

53

x

38

28

ptb8

30

 

19

79

ptc4

49

x

39

30

ptb1

23

 

20

45

ptb19

41

x

40

67

ptb9/ptc6

31/51

 

* Estes pinos não estão necessariamente conectados aos pinos do Vybrid. A informação apresentada é somente para referência e deve ser verificada no datasheet.

** Para mais informações sobre o ADC, verifique a documentação/datasheet.

 

 

Configuração do ambiente

 

O primeiro passo é ter uma imagem do Linux rodando no módulo VF61, caso você ainda não tenha uma. Primeiro você precisa fazer o download de uma imagem pré-compilada - recomendo que use a imagem Colibri_VF_LinuxConsoleImage - e gravar a imagem no módulo. Assumindo que você esteja usando uma distribuição do Linux no seu computador de desenvolvimento, primeiro é preciso extrair a imagem pré-compilada com privilégios de administrador (root) e então rodar um script para colocá-la em um cartão uSD fomatado como FAT:

 

 

Após isso você precisa acessar o console usando uma interface serial: uma possibilidade é usar um cabo USB para RS-232 e um cabo adaptador DB9 para IDC10. Primeiro insira o cartão uSD na Iris e conecte o cabo serial para USB na sua máquina, então abra uma aplicação de terminal com 115200 baud, 8 bits de dados, sem paridade e 1 bit de parada. Energize a placa e pressione qualquer tecla imediatamente para parar o processo de boot. Então execute os seguintes comandos para fazer o update do módulo:

 

 

O login padrão para os módulos da Toradex é user:root sem senha. Instruções detalhadas sobre como gravar uma imagem no seu módulo podem ser encontradas aqui. Você também poderia compilar sua própria imagem customizada usando o framework OpenEmbedded.

 

Então você deve plugar sua placa à rede. Se você está seguindo este artigo e não quer plugar sua placa à LAN em que está conectado, veja este guia sobre como configurar uma rede para o desenvolvimento de aplicação de Linux embarcado. Caso contrário, simplesmente ajuste o endereço IP da placa para estático, usando connman, assim você poderá acessar a placa facilmente por uma conexão SSH e/ou pelo browser. Nas instruções a seguir você não precisa achar o número do ethernet_xxxxxxxxxxxx_cable, simplesmente digite config e pressione tab para completar, já que só deve haver um serviço rodando. Além disso, o endereço de IP e máscara de rede devem ser ajustados de acordo com as configurações de sua rede:

 

 

Para confirmar que esta operação foi bem sucedida, simplesmente acesse sua placa via SSH. Caso você seja perguntado sobre host key, aceite. Daqui para a frente não é mais preciso usar a interface serial para acessar a placa e você pode fazê-lo de qualquer ponto de sua rede local. Abaixo está um exemplo de primeiro acesso à placa via SSH:

 

 

A primeira coisa necessária para começar a programar é instalar o Node.js na placa. Isso pode ser feito executando os seguintes comandos para instalar e verificar que tudo está funcionando:

 

 

Antes de começar, saiba que os códigos desenvolvidos neste artigo estão disponíveis completamente comentados (em inglês) em repositórios git. Ao longo do artigo, os comentários serão omitidos por questão de clareza e porque você será guiado por eles. Caso você não esteja familiarizado com o git, aqui estão as instruções para você copiar um repositório na sua placa - neste caso, o repositório do primeiro exemplo desenvolvido:

 

 

Mesmo que tudo o que você precise para rodar uma aplicação em Node seja executar o comando node seuapp.js no terminal, há um programa monitor chamado nodemon que verifica mudanças feitas nos arquivos fonte da aplicação e dá um restart automático quando algo muda, evitando o desgaste de reiniciar manualmente enquanto desenvolvendo a aplicação. O framework Express também será necessário mais tarde, então vamos aproveitar para instalá-lo. Também vamos instalar o middleware body-parser, que analisa strings codificadas no formato JSON. O procedimento abaixo instala o nodemon, Express e body-parser e executa uma aplicação qualquer (caso ela exista). Antes disso, é preciso instalar o tar e o npm (node package manager), e isto pode demorar um pouco.

 

 

 

Introdução a GPIO e acesso pelo terminal

 

Após fazer login na placa, o primeiro passo para usar um pino específico de GPIO é configurá-lo. Por padrão, após um reset todos os pinos de GPIO são configurados de tal modo que o buffer de saída e o pull up/down estão desativados, o que significa que os pinos estão no estado de alta impedância.

 

Para usar os pinos através do sysfs, primeiramente é necessário exportá-los. Isso é feito escrevendo o número do pino desejado para o arquivo /sys/class/gpio/export. Se você checar o conteúdo do diretório /sys/class/gpio irá encontrar:

 

 

Export e unexport são arquivos aos quais você pode escrever o número dos pinos que deseja usar ou liberar para o Kernel, respectivamente. Note que se você tentar exportar um pino que já está em uso pelo Kernel, receberá uma mensagem de erro. Os gpiochipN são os controladores de GPIO e cada um deles gerencia 32 pinos - se você quiser saber qual controlador é responsável por qual pino, isto pode ser calculado usando a seguinte fórmula:

 

numero_pino = gpioN[pino] + 32*N

 

Por exemplo, o pino 88 que usaremos corresponde ao pino 24 do controlador 2, ou gpio2[24]. Há uma maneira mais fácil de encontrar o pino correspondente para o VF61, checando as colunas GPIO Pad e GPIO Port do datasheet do módulo.

 

Vamos exportar os pinos de GPIO que usaremos neste artigo, e então verificar novamente o diretório /sys/class/gpio:

 

 

Agora, como você pode ver, todos os pinos exportados tem um diretório, então vamos checar o conteúdo de um deles:

 

 

Como tudo é feito com operações de leitura e escrita, para configurar um pino a única ação necessária é escrever in ou out no arquivo direction - os pinos são configurados como entrada quando exportados após um reset do sistema. O arquivo value é usado para setar ou obter o valor do pino e retorna 0/1 mesmo se você ler um pino configurado como saída; quanto a modificar o valor de um pino, qualquer valor numérico diferente de 0 será interpretado como 1.

 

Às vezes, sistemas de GPIO tem significados divergentes no que diz respeito ao seu estado ativo e o valor lógico lido pelo sistema - por exemplo, todas as chaves usadas neste artigo são ativas em nível baixo, o que significa que se você ler 0 no pino correspondente, isto significa que a pushbutton está pressionada, ou seja, ativa. Isto pode causar confusão na hora de programar, então existe a opção de inverter o estado lógico lido, escrevendo 1 ao arquivo active_low: então sempre que for lido/escrito 1 para o arquivo value isso significa que o estado lógico do pino será 0.

 

Alguns pinos possuem o arquivo edge disponível, o que significa que eles podem ser configurados como geradores de interrupção. O arquivo aceita as opções none, rising, falling e both, com relação às bordas que podem gerar interrupção. Para usar esta possibilidade, é preciso amostrar o arquivo até que uma interrupção seja gerada. Neste artigo não detalharemos este processo, porém mais informações sobre como usar interrupções de GPIO com Node podem ser encontradas aqui.

  

 

Usando Node.js para acessar a GPIO


Vamos começar a desenvolver nosso código. Assumindo que você está começando do zero, crie um arquivo na pasta home da sua placa, chamado server.js e abra ele no seu editor de texto favorito - eu escolhi usar a IDE Eclipse para acessar e editar os arquivos a partir do computador de desenvolvimento usando o Remote System Explorer, mas você pode preferir outra IDE ou simplesmente um editor de texto. Agora que seu arquivo está aberto, a primeira coisa a fazer é exportar o módulo File System. Outra boa ideia é atribuir o número dos pinos a serem usados a constantes, por clareza e flexibilidade na hora de modificar o código.

 

 

Então nós criamos funções para configurar, ler e escrever em um pino de GPIO. Como este é um guia introdutório, não nos preocuparemos com checagem de erros, mas é altamente recomendado que você adicione esta funcionalidade se precisa de um código mais robusto; considere criar um módulo com estas funções para que possa reutilizar este código facilmente.

 

 

As funções rdGPIO e wrGPIO são bem diretas: elas somente encapsulam as funções de leitura e escrita em arquivo e juntam os argumentos para que o código principal fique mais limpo. A função cfGPIO checa se o pino já está exportado e o faz, caso necessário, para em seguida configurar a direção do pino. A parte da checagem é essencial, já que ela vai gerar erro caso um pino seja exportado mais de uma vez. O uso de funções síncronas também deve ser notado: como Node é assíncrono, se o uso de funções síncronas não for forçado, há o risco de que uma operação de leitura/escrita ocorra antes/durante a configuração do pino, o que também pode causar um erro.

 

O próximo passo é chamar a função de configuração para cada pino - e nós faremos isto da maneira mais simples, embora você possa implementar uma abordagem baseada em  loop, o que facilita para o caso genérico de n pinos serem usados. Agora nós estamos prontos para focar na funcionalidade da aplicação, então vamos fazer algo básico como ponto de partida: ler as chaves por varredura e copiar o valor delas nos respectivos LEDs. A função nativa setInterval é usada para chamar outra função periodicamente: o primeiro argumento é a função a ser chamada e o segundo é a periodicidade, em milissegundos, que em nossa aplicação pode ser interpretada como um anti-repique por software. Note o uso de setImmediate - ele é necessário devido ao comportamento assíncrono do Node, para garantir que os pinos serão configurados antes que o código comece a varredura.

 

 

Agora vamos reiniciar a placa antes de rodar nossa aplicação, para que possamos checar se os pinos estão sendo corretamente exportados e configurados, e que o resto também está funcionando (é preciso reconectar no SSH após o reboot). Separe um tempo para testar o hardware, também.

 

 

Algumas ideias para você tentar/implementar:

  • Pressione as pushbuttons para ver o sistema funcionando;
  • Tente mudar o tempo de debouncing para um valor maior, por exemplo 1000, e note o atraso entre segurar uma chave apertada e o LED mudar de estado;
  • Você também poderia implementar na função cfGPIO um parâmetro opcional para configurar o arquivo active_low, para que não haja necessidade de inverter o valor das chaves em nosso código antes de passar para os LEDs;
  • Se você quer um código robusto, adicione verificação de erros ao código;
  • Considere escrever um módulo para as funções e procedimentos de GPIO.

 

 

Construindo um webserver e uma interface web para acessar a placa

 

Daqui para a frente nós começaremos a usar o módulo debug, que é instalado junto com o Express, para mostrar mensagens de log no terminal. Para usá-lo, à variável DEBUG deve ser atribuído o nome usado no código, ou * para mostrar todas as mensagens de debug possíveis. O diretório do Github correspondente a esta seção do artigo pode ser encontrado aqui.

 

 

Este é o momento de implementar o webserver com Express. Primeiro nós vamos requerer os módulos relacionados ao Express e ao debug, então adicionaremos ao código as constantes relativas ao endereço de IP da nossa placa e uma porta para o webserver escutar. Tudo o que nós precisamos para mostrar uma página web para nossa aplicação é apontar um diretório no qual estão os arquivos estáticos, como CSS, Javascript, imagens, etc e ouvir a um endereço de IP e porta específicos. A constante __dirname se refere ao mesmo diretório no qual está o código em Node. As partes do código que foram modificadas/adicionadas são:

 

 

O código do cliente precisa ser escrito. O nome index.html será usado porque o servidor busca por este nome de arquivo por padrão, embora isso possa ser modificado. Nós também criaremos um arquivo chamado client.js para escrever a parte Javascript/jQuery do código. Abaixo a primeira versão do index.html é apresentada e é importante notar os elementos input e label, porque eles serão usados para controlar os LEDs na sequência. Observe que na seção head, a biblioteca do jQuery e o arquivo client.js  já foram incluídos para o uso posterior. Para uma abordagem prática em linguagens web, métodos, bibliotecas e mais, um bom começo é este site.

 

 

Se você abrir um navegador e for ao endereço no qual o servidor está escutando, deverá obter a resposta da figura 2. Observe que você pode checar a caixa, mas isso não gera nenhuma ação.

 

Node-design-web-04
Figura 4 - Primeiro design da aplicação web

 

Abaixo está implementado o código Javascript do cliente client.js que adiciona responsividade à nossa página e também faz a comunicação com o servidor. Primeiramente, jQuery captura o evento de click para todos os elementos com a classe btn. Então uma estrutura condicional verifica se o botão já estava pressionado ou não e muda a legenda de acordo, setando as propriedades id e value do objeto btn_status de acordo com o botão que foi pressionado, para enviar para o servidor. Por fim, jQuery é usado para enviar um POST HTTP usando AJAX para o servidor, contendo o objeto btn_status previamente mencionado, codificado como uma string JSON.

 

 

Antes de efetivamente usar a aplicação, é necessário modificar um pouco o código do servidor (server.js) para receber o POST HTTP e executar decisões baseadas nos dados recebidos. Também é essencial remover a varredura das chaves, ou ambas as partes entrarão em conflito e o comportamento esperado não será atingido. A primeira coisa necessária é configurar o uso do body-parser - e deve ser feito antes de configurar o caminho. Então o caminho é setado e seu nome deve ser igual ao usado na aplicação do cliente, mas desde que ambos sejam iguais você pode escolher o nome que quiser - adicionalmente você pode configurar mais de um caminho. Então a função que trata das requisições POST recebidas é escrita: ela recebe os valores recebidos pelo servidor e muda o estado dos LEDs correspondentes de acordo, e então envia uma resposta para o servidor - que poderia ser, por exemplo, um conjunto de dados a serem checados pelo cliente, para assegurar que tudo ocorreu conforme planejado.  

 

 

Temos uma aplicação web responsiva e você pode controlar os LEDs a partir dela! Este é o mais simples exemplo de como controlar pela web uma GPIO configurada como saída, usando AJAX para comunicar com o servidor Node. Aqui estão algumas coisas que você pode tentar por si:

  • Adicionar uma propriedade de status à resposta do servidor e checá-la no cliente - poderia ser algo como mensagens "success" e "fail" combinadas com a implementação de checagem de erros a ser adicionada nas funções de GPIO do código do servidor;
  • Usar a função setInterval na aplicação do cliente para fazer uma varredura do estado de uma chave. Enviar requisições POST periodicamente, pedindo o status atual da chave. Se você não conseguir fazer isso, não se preocupe, pois na próxima seção vamos desenvolver uma aplicação para varrer o status das chaves e atualizar a interface de usuário com estes valores.

 

 

Adicionando estilo e usando para múltiplos LEDs/chaves

 

Embora o código da seção anterior possa ser útil no mundo real, a interface de usuário não é muito amigável. Observe, por exemplo, o resultado do uso de nossa aplicação em um smartphone, na figura 3, emulado pelo device mode do terminal do Google Chrome. Tendo em vista estes resultados, vamos adaptar nosso código para uso com o framework Bootstrap, majoritariamente implementado em CSS e mobile-first. Usar outros frameworks, como o PhoneGap, que cria apps para dispositivos móveis a partir de uma aplicação web como a nossa, e/ou adicionar estilo à interface de usuário usando CSS puro são outras possíveis escolhas que você deve checar.

 

Node-smartphone-05
Figura 5 -  Aplicação da seção anterior emulada em uma tela de smartphone

 

A primeira coisa que faremos é adaptar nossos códigos para usar o Bootstrap, começando pelo arquivo HTML. Embora à primeira vista pareça que muitas mudanças foram feitas, lembre-se que a maioria não afetará como a aplicação funciona, mas sim como ela é vista pelo usuário. Na seção head nós adicionaremos uma tag meta para prover suporte prioritário a dispositivos móveis e os links para as bibliotecas CSS e Javascript do Bootstrap. A seguir, na seção body nós primeiramente adicionaremos uma div do tipo container, que é responsiva e de largura fixa, na qual nossa aplicação ficará contida. Dentro dela, nós adicionaremos uma div de linha, uma vez que o Bootstrap trabalha com um sistema de grid - e dentro desta div uma coluna, também provida pelo Bootstrap com largura 4 (de um máximo de 12) será adicionada.  

 

A maior diferença implementada na nossa aplicação é que nós paramos de usar o par checkbox/label e passamos a usar button em seu lugar: as configurações são feitas no atributo class, nas quais btn e btn_block são classes do Bootstrap, e true_btn será usada por nós para diferenciar chaves de LEDs. O processo de mudar o estilo/legenda também fica muito mais fácil, pois não há necessidade de achar a label correspondente à checkbox.

 

 

Agora se você rodar a aplicação, verá que há uma enorme diferença na interface de usuário, mas a aplicação parou de funcionar conforme o esperado. Antes de consertar isso, vamos: 

  • adicionar mais dois botões dentro da div da linha mudando somente o índice de suas id - estes botões serão nossos controladores/indicadores dos LEDs;
  • criar outra linha depois da que contém os indicadores dos LEDs e adicionar mais 3 botões com id SW1, SW2 e SW3 - eles serão os indicadores de status das chaves;
  • antes dos indicadores de LEDs, adicionar uma linha com largura cheia, id "MSG" e value "application running" - este botão será o indicador de que nossa aplicação está funcionando;
  • adicionar títulos para cada linha, para indicar ao usuário quais botões representam LEDs e quais representam chaves.

 

Após realizar as mudança acima, você pode checar o código HTML completo aqui. Até o final do artigo, este código não precisará de mais mudanças. Agora vamos modificar o código do servidor para que ele se ajuste à nossa nova interface de usuário. Primeiramente, para ajudar na reusabilidade do código, vamos modificar a função que configura todos os pinos para que em um loop ela verifique todas as GPIOs e as configure como LEDs ou chaves, o que permite usar esta função para configurar um número indeterminado de pinos. Para que isto seja feito, nós também criaremos um objeto com todos os pinos de GPIO usados. Abaixo estão as partes modificadas do código previamente elaborado:

 

 

Então, a parte que cuida das requisições POST recebidas precisa ser reescrita. Primeiro, como convenção, vamos assumir que o cliente vai atribuir "getGPIO" a id se ele precisar que o servidor envie o status atual dos pinos de GPIO - se esse for o caso, o servidor lê o estado de todas as GPIO e o retorna para o cliente. Caso contrário, assume-se que o cliente enviou o id de um pino e o valor a ser escrito nele - neste caso, o servidor mudará o estado do pino correspondente. O trecho do código modificado deve estar de acordo com o seguinte:

 

 

O código do servidor está pronto e pode ser verificado aqui, se você quiser. Mas ainda há algumas modificações necessárias para que a aplicação funcione: o código do cliente em Javascript/jQuery também precisa ser modificado e isso é o que nós faremos daqui para a frente. Primeiramente, a função clickHandling será renomeada e colocada fora do que passaremos a nos referir como a função main do nosso código e, quando algum botão da classe true_btn for clicado, a função btnHandling será chamada - isto nos permite distinguir quais botões devem mudar o estado dos LEDs e quais não. Nós também colocaremos a requisição AJAX POST em uma função chamada changeLedState, para facilitar o entendimento do código e possibilitar seu reuso:

 

 

A principal diferença com relação ao código sem Bootstrap é a checagem do botão. Uma vez que adicionar as classes btn-success ou btn-danger deixa o botão verde ou vermelho, respectivamente, nós nos aproveitaremos disto não somente para indicar se o LED correspondente está ligado/desligado, mas também para verificar isso em nosso código, por meio do método indexOf na string class do botão, que retorna -1 se a string passada como argumento não está contida na string à qual é aplicado o método. Então nós mudamos a classe do botão e requisitamos ao servidor que inverta o estado do LED, chamando a função changeLedState.

 

Outra funcionalidade necessária é a leitura do estado dos pinos de GPIO após carregar a página, para que as primeiras operações com os LEDs não sejam mal interpretadas. Para isto, nós precisaremos das funções getGPIO e updateCurrentStatus. A getGPIO não retornará os valores, mas chamará uma função de callback para a qual eles serão passados; essa função também aproveitará o fato de que o servidor retorna o status da GPIO quando a id "getGPIO" é enviada. A função updateCurrentStatus somente recebe os valores retornados do servidor e muda a classe dos botões correspondentes. Note que o estado das chaves precisa ser invertido, pois elas são ativas em nível baixo; se no começo do artigo nós tivéssemos configurado os arquivos /sys/class/gpio/gpiox/active_low para inverter as entradas, não precisaríamos invertê-las agora. Por fim, é preciso chamar as funções dentro da main  para atualizar o status dos botões.

 

 

Então, faremos varredura da GPIO a cada 0,2s e adicionaremos uma função a cada chave, assim não ficamos entediados! Para isso, usaremos a função setInterval para chamar getGPIO periodicamente e sua callback, que será swAction, irá implementar as funcionalidades das chaves:

  • SW1 mudará o LED selecionado;
  • SW2 inverterá o estado do LED selecionado;
  • SW3 pausará a aplicação parando a função setInterval - é por isso que colocamos o botão MSG no código HTML: para que ele reinicie a aplicação;
  • O botão MSG, se clicado quando a aplicação estiver pausada, chamará resumeApp, que por sua vez chama setInterval e recomeça a varredura;
  • Também existirá a necessidade de criar duas variáveis globais: uma que aponte para o LED selecionado e outra para indicar quantos LEDs existem (que é na verdade uma constante).

 

 

Agora nosso exemplo sobre como acessar a GPIO por meio de uma interface de usuário amigável está completo. Se você quiser, pode checar o código final da aplicação do cliente. Observe a interface nas figuras 4/5 e perceba que ela está muito mais bonita do que a apresentada no início desta seção. Há também um vídeo mostrando o funcionamento da aplicação.

 

Node-interface-amigavel-smartphone-06
Figura 6 -  Interface de usuário amigável emulada em uma tela de smartphone
Node-interface-amigavel-navegador-07
Figura 7 - Interface de usuário amigável rodando em um navegador com tela grande

 

 

Há muitos links ao longo deste artigo sobre conceitos que nós aplicamos, caso você queira mais informações, e eu também espero que este artigo lhe tenha sido útil!

NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

1
Deixe um comentário

avatar
 
1 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
Alexandre Bernardo Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
Alexandre Bernardo
Visitante
Alexandre Bernardo

Muito bom e bem didático este artigo, parabéns Leonardo!!!