Controle de Luzes e Sensores pela Internet com Raspberry Pi

Vamos habilitar nossa página Web para comandar lâmpadas, tomadas e aparelhos em toda a casa!

Acionando as GPIO com Fast CGI

No tutorial passado já havíamos habilitada o mod de Fast CGI, caso você não tenha realizado, no post Web Server.

O motivo de estarmos utilizando Fast CGI (FCGI abreviando) é devido ao fato dele deixar o script Python rodando em memória, enquanto as chamadas através do CGI requerem uso do interpretador Python a cada acionamento tornando o processamento mais lento.

Vamos editar o arquivo ‘fcgi.py’ que se encontra em home/pi/www/cgi-bin/

sudo nano /home/pi/www/cgi-bin/fcgi.py

Acrescentaremos o código abaixo:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

from gpiozero import LED
from flup.server.fcgi import WSGIServer
import sys, urlparse

#Definindo as portas dos LEDs
meuLed = [LED(2), LED(3), LED(4)]

def app(environ, start_response):
start_response("200 OK", [("Content-Type","text/html")])
params = urlparse.parse_qs(environ["QUERY_STRING"])
yield(" ")
# exemplo de string http GET
# /fcgi.py?L=1&SW=0
# L : indica qual LED ira ser operado
# SW : 0-desligar ou 1-ligar
id = -1
sw = -1

if "L" in params:
id = int(params["L"][0]) - 1
else:
id = -1

if "SW" in params:
sw = int(params["SW"][0])
else:
id = -1

if(id>-1 and sw>-1):
if(sw == 1):
meuLed[id].on()
else:
meuLed[id].off()

# Flup irá integrar nosso webserver e cuidar do app rodando
WSGIServer(app).run()

Para que o webserver execute este shell em Python, precisamos torná-lo executável através do comando:

sudo chmod 755 fcgi.py

Agora para executá-lo na linha de comando não será mais necessário digitar ‘sudo python fcgi.py’, podemos apenas digitar:

./fcgi.py

E se fizermos isso neste momento teremos a seguinte resposta:

fcgi-error

O que é perfeitamente normal e na verdade, uma ótima notícia: pois indica que o WSGIServer não recebeu os parâmetros da string URL com os parâmetros que configuramos (ex: L1=1).

Se você obtiver algum erro de compilação em Python neste momento irá aparecer, portante esta verificação é importante.

Nesta altura você deve ter reparado que importamos uma biblioteca chamada FLUP no início do código, esta irá nos auxiliar na comunicação entre o FCGI e o webserver Lighttpd.

Portanto, é hora de instalar o FLUP!

Instalando o FLUP | WSGI Server no Raspberry Pi

Para instalar o flup:

sudo apt-get install python-flup

Até agora nossa solução envolveu várias bibliotecas e serviços e está mais ou menos assim:

fullsizerender
Raspberry Pi Web Server c/ Lighttp + Fast CGI  + Pyhon + Flup + GPIOZERO

Chamando FCGI a partir de HTML com Javascript

Precisamos agora refatorar nossa index.html para que contenha os elementos visuais necessários para interagirmos com os 3 leds e também acrescentar a chamada para o Fast CGI que está no servidor (web server).

Esta chamada será realizada via Javascript (parte do código cercado pela tag ) embutido dentro do código HTML.

<html>
<head>
<title>RPi3 WWW 2</title>
</head>
<body>

<h1>RPi3 - Web server e Fast CGI</h1>
<p>Controle os 3 LEDs conectados na GPIO via HTML</p>
<br/>
<table>
    <tr>
       <td>
          <img id="led1" src="pic_bulboff.gif" width="100" height="100">
       </td>
       <td>
          <img id="led2" src="pic_bulboff.gif" width="100" height="100">
       </td>
       <td>
          <img id="led3" src="pic_bulboff.gif" width="100" height="100">
       </td>
     </tr>
     <tr>
       <td>
          <p>
          <button type="button" onclick="ledswitch(1,1)">ON</button>
          <button type="button" onclick="ledswitch(1,0)">OFF</button>
          </p>
       </td>
       <td>
          <button type="button" onclick="ledswitch(2,1)">ON</button>
          <button type="button" onclick="ledswitch(2,0)">OFF</button>
       </td>
       <td>
           <button type="button" onclick="ledswitch(3,1)">ON</button>
           <button type="button" onclick="ledswitch(3,0)">OFF</button>
       </td>
    </tr>
</table>


    var xmlhttp = new XMLHttpRequest();

    function ledswitch(_id,_state) {
       var pic;
       if (_state == 1) {
          pic = "img/ledon.gif"
       } else {
          pic = "img/ledoff.gif"
       }
       var ledId = "led"+_id
       document.getElementById(ledId).src = pic;

       xmlhttp.open("GET","cgi-bin/fcgi.py?L="+_id+"&SW="+_state, true);
       xmlhttp.send();
}

</body>
</html>

Entendendo que temos no RPi 3 rodando nosso webserver, se acessar neste momento em qualquer browser seu IP (caso não se lembre como fazer isso veja aqui: # 03 Conectando-se ao Raspberry Pi 3 via SSH – 5 Min Maker) você deverá se deparar com uma nova página HTML, porém com alguns links quebrados das imagens.

Isto é porque não criamos o arquivo de imagens e também não colocamos nenhuma imagem lá dentro. Precisamos então criar o diretório www/img e colocar nele as imagens as quais fizemos referências: ledon.png e ledoff.png.

~ cd www

mkdir img

Dentro do diretório, vamos baixar as imagens utilizando o comando WGET captando a URL da imagem na internet.

 

wget http://www.iconsdb.com/icons/preview/red/led-diode-xxl.png

wget http://www.iconsdb.com/icons/preview/black/led-diode-xxl.png

 

Ok! Acessando a página conseguiremos ver as imagens e o javascript vai executar as funções de atualização dinâmica dos seus estados de ON e OFF trocando as imagens.

Ligando os LEDs na GPIO

Vou dar um salto quântico aqui, visto que nós já aprendemos a ligar LEDs nas GPIOs – caso você não acompanhou segue nosso post sobre o assunto: #02 Construindo c/ LEDs um Game de Roleta no Raspberry Pi 3 – 5 Min Maker

Tudo conectado vamos clicar na página e ver os LEDs brilharem… opa… nada aconteceu… Mas porque?

Em resumo (recordando o diagrama que coloquei mais acima): o web server tenta executar o nosso script Python ‘fcgi.py’, porém a diretiva Python não tem poderes ‘sudo’ (sigla para Super User DO). Lembre-se que toda vez que vamos rodar os scripts Python na linhda de comando precisamos colocar ‘sudo’ antes, pois apesar do usuário ‘Pi’ (nosso usuário de login) não ser um ‘super user’ ou ‘root’, temos permissão para utilizar esta diretiva.

Como o usuário do web server lighttpd é o ‘www-data’, este não conseguiria executar nem se tivessemos acrescido o sudo.

Uma tática simples, porém que deve ser realizada com muita cautela, é realizarmos uma cópia do interpretador Python, criando um novo, porém este novo com acesso Root e passarmos a utilizá-lo no script fcgi.py.

Criando um novo Python com acesso Root

Primeiro devemos verificar qual a versão de Python estamos utilizando. A minha é 2.7, portanto as referências seguirão assim. Ajuste os comandos de acordo com a sua versão.

$ ls -l /usr/bin/python

retornará algo como (no meu caso):

lrwxrwxrwx 1 root root 9 Mar 28 2015 /usr/bin/python -> python2.7

Ok. Agora criaremos uma cópia, por exemplo, pythonRoot:

$ sudo cp /usr/bin/python2.7 /usr/bin/pythonRoot

E daremos ao novo arquivo ‘pythonRoot’ o nível de permissão Root

$ sudo chmod u+s /usr/bin/pythonRoot

Se consultarmos agora o arquivo PythonRoot veremos que a ação foi efetiva:

$ ls -l /usr/bin/pythonRoot
-rwsr-xr-x 1 root root 3201580 Jan 4 15:32 /usr/bin/pythonRoot

Nosso último ponto é retornar ao arquivo ‘fcgi.py’ e colocar agora este super poderoso root Python para ser o executor do nosso script.

~ cd www/cgi-bin

sudo nano fcgi.py

Só precisamos alterar a primeira linha substituindo o antigo ‘python’ por ‘pythonRoot’

#! usr/bin/pythonRoot

Vamos forçar a reciclagem do nosso webserver e voilá!

sudo service lighttpd force-reload

Se captarmos o status do servidor veremos que o ‘binding’ (a conexão) do Web Server com o arquivo ‘fcgi.py’ (Fast CGI server) está realizada e pronta para interpretar as chamadas urls http com parâmetros.

pythonroot-binded

Agora é só acessar nossa página, clicar nos botões e ver funcionando.

Curiosidade: Requisições GET e POST

Caso você queira testar as ações sem utilizar a página HTML é só digitar na barra do navegador, por exemplo, no meu caso se eu quiser acescender o Led 1.

10.0.1.9:8080/fcgi.py?L=1&SW=1

Isto só é possível porque estamos utilizando o método GET, onde parâmetros são enviados na própria URL da requisição HTTP.

Uma outra maneira de fazer isso é através de requisições do tipo POST, maneira mais segura, pois os parâmetros não são visíveis. Normalmente utilizamos o método POST para dados mais sensíveis como login e password ou dados pessoais. No caso de serviços é comum utilizarmos o método GET.

Para entender mais sobre estas requisições HTTP consulte aqui.


DC

 

Anúncios

Um comentário sobre “Controle de Luzes e Sensores pela Internet com Raspberry Pi

  1. Infelizmente deu erro… não sei bem o que aconteceu. pediu pra endentar alguns trechos do arquivo python…. fiz mas mesmo assim continua o erro:

    #! usr/bin/pythonRoot
    # -*- coding: UTF-8 -*-

    from gpiozero import LED
    from flup.server.fcgi import WSGIServer
    import sys, urlparse

    #Definindo as portas dos LEDs
    meuLed = [LED(2), LED(3), LED(4)]

    def app(environ, start_response):
    start_response(“200 OK”, [(“Content-Type”,”text/html”)])
    params = urlparse.parse_qs(environ[“QUERY_STRING”])

    # exemplo de string http GET
    # /fcgi.py?L=1&SW=0
    # L : indica qual LED ira ser operado
    # SW : 0-desligar ou 1-ligar
    id = -1
    sw = -1

    if “L” in params:
    id = int(params[“L”][0]) – 1
    else:
    id = -1

    if “SW” in params:
    sw = int(params[“SW”][0])
    else:
    id = -1

    if(id>-1 and sw>-1):
    if(sw == 1):
    meuLed[id].on()
    else:
    meuLed[id].off()

    # Flup irá integrar nosso webserver e cuidar do app rodando
    WSGIServer(app).run()

    Se puder me ajudar com isso fico muito agradecido!

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

w

Conectando a %s