Remote Control - Web interface

Controllo remoto di utenze da interfaccia web con la GPIO di Raspberry Pi, Python e Flask


Avere la possibilità di controllare da remoto le utenze domestiche tramite un qualunque dispositivo connesso ad Internet, come uno smartphone, tablet o PC portatile, offre tanti spunti alla remotizzazione di cio’ che non si può avere sempre a portata di mano o che per contingenze varie è ubicato in un luogo diverso da quello dove si vive abitualmente. Nel caso specifico di una stazione radio, si può pensare di installare antenne e apparati in un luogo più consono a questo tipo di attività, come la casa in campagna e disporne comodamente dall’appartamento di città. O anche di essere costretti a trascorrere lunghi periodi fuori dalla propria abitazione e non voler rinunciare all’opportunità di fare QSO dalla propria stazione.
Raspberry Pi con la sua versatile interfaccia GPIO (General Purpose Input Output) si presta in modo ottimale alla realizzazione di un server web, grazie all’utilizzo di Python con RPi.GPIO, per la gestione degli input/output e Flask, un micro framework per la realizzazione di pagine web dinamiche ed interfacciabili con l’hardware.
 

Flask

Flask
Flask logo

Flask [1] è un microframework per Python, sviluppato da Armin Ronacher, per la realizzazione di un web server con contenuti dinamici. Flask è un framework molto semplice e leggero nel quale però possono essere integrate una serie di estensioni che consentono la creazioni di siti web anche complessi. Nel nostro caso ciò che riveste maggiore interesse è che sia sviluppato in Python, consentendone quindi un facile interfacciamento alle funzioni hardware del Rapsberry Pi.
In alternativa, ovvero disponendo di un web server classico come Apache o NGINX, ci si dovrà preoccupare di richiamare tramite PHP uno script in Python, C o altri linguaggi senza avere la diretta integrazione degli stessi nella pagina web e con un carico aggiuntivo di consumo delle risorse del sistema.
 

RPi.GPIO

RPi.GPIO [2], ovvero raspberry-gpio-python di Ben Croston, è un modulo Python per il controllo delle porte GPIO del Raspberry Pi.
Fare attenzione perché RPi.GPIO identifica le porte in base alla numerazione del processore Broadcom o alla disposizione sul connettore GPIO della scheda RPi. Negli esempi seguenti utilizzeremo la seconda opzione, in modo che i pin utilizzati siano facilmente identificabili ed il codice indipendente dalla versione di RPi.
 

Installazione

Supponendo di avere il nostro Raspberry Pi con sistema operativo Raspbian installato e aggiornato, quindi con Python 3 già incluso, si procede con l’installazione di Flask. Poiché Flask supporta Python 3 (versione 3.3 o superiore), è opportuno cominciare un nuovo sviluppo da questa versione, essendo la 2 non più supportata.

Installiamo innanzitutto PIP (Python Package Index), il gestore di librerie di Python 3
sudo apt-get install python3-pip

Quindi Flask, il micro framework Python
sudo pip3 install flask

E la libreria Python RPi.GPIO, per la gestione dell’interfaccia di I/O del Raspberry Pi, modulo che di solito è già installato
sudo pip3 install rpi.gpio

Creare la cartella dove verranno conservati gli script Python, ad esempio con il nome “flask-webserver”
mkdir flask-webserver

Ora testiamo l’installazione di Flask con un codice prova. Entriamo nella cartella e creiamo il file per lo script
cd flask-webserver
nano flask-test.py

Inserire all’interno il seguente codice

<br />
from flask import Flask<br />
app = Flask(__name__)</p>
<p>@app.route(&quot;/&quot;)<br />
def index():<br />
    return &quot;&lt;html&gt;&lt;body&gt;&lt;h1&gt;Flask test&lt;/h1&gt;OK&lt;/body&gt;&lt;/html&gt;&quot;</p>
<p>if __name__ == &quot;__main__&quot;:<br />
    app.run(host='0.0.0.0', port=80, debug=True)<br />

Quindi lanciare lo script (visto che è stata selezionata la porta http 80 sono richiesti i privilegi di amministratore)
sudo python3 flask-test.py

Flask test
Flask test

Dal PC aprire il browser ed inserire l’indirizzo IP del proprio Raspberry, apparirà la seguente pagina

Flask test web
Flask test web

Remote Control

Dopo aver verificato il funzionamento di Flask si può procedere con lo scopo che ci eravamo prefissati. Scaricare il file zip allegato Remote 1.0beta, copiarne il contenuto nella cartella di lavoro ed eseguirlo
sudo python3 remote.py

Il file remote.py contiene il seguente codice, adeguatamente commentato per descriverne il funzionamento:

<br />
# RPi Remote control web interface<br />
# by IZ8EWD www.pianetaradio.it<br />
# v 1.0 beta</p>
<p>import RPi.GPIO as GPIO<br />
import datetime</p>
<p>from flask import Flask, render_template</p>
<p>app = Flask(__name__)</p>
<p>GPIO.setmode(GPIO.BOARD)</p>
<p>#Create a dictionary called port_io to store the pin number, name and status<br />
port_io = {<br />
 11 : {'name' : 'Device 1', 'status' : GPIO.LOW},<br />
 13 : {'name' : 'Device 2', 'status' : GPIO.LOW},<br />
 15 : {'name' : 'Device 3', 'status' : GPIO.LOW},<br />
 16 : {'name' : 'Device 4', 'status' : GPIO.LOW}<br />
}</p>
<p>#Set each pin as an output and make it low<br />
for pin in port_io:<br />
   GPIO.setup(pin, GPIO.OUT)<br />
   GPIO.output(pin, GPIO.LOW)</p>
<p>#Create the dynamic content of main page<br />
@app.route(&quot;/&quot;)<br />
def index():</p>
<p>#For each pin, read the pin state and store it in the port_io dictionary<br />
 for pin in port_io:<br />
  port_io[pin]['state'] = GPIO.input(pin)</p>
<p>#Read current time<br />
 time = datetime.datetime.now()<br />
 time_string = time.strftime(&quot;%Y-%m-%d %H:%M&quot;)</p>
<p>#Dictionary with return data for the html page<br />
 return_data = {<br />
  'port_io' : port_io,<br />
  'return_message' : &quot;Welcome&quot;,<br />
  'return_time' : time_string<br />
 }</p>
<p>#Create html page from template<br />
 return render_template('remote_template.html', **return_data)</p>
<p>#Switch the pin status on user request and update the web interface<br />
@app.route(&quot;/&lt;pin_control&gt;/&quot;, methods=['POST'])<br />
def GPIO_control(pin_control):</p>
<p> pin_control = int(pin_control)</p>
<p> if port_io[pin_control]['status'] == GPIO.LOW:<br />
  GPIO.output(pin_control, GPIO.HIGH) #Set the pin high</p>
<p> else:<br />
  port_io[pin_control]['status'] = GPIO.LOW<br />
  GPIO.output(pin_control, GPIO.LOW) #Set the pin low</p>
<p> port_io[pin_control]['status'] = GPIO.input(pin_control) #Read the pin value and assign to pin status in port_io</p>
<p>#Upadate the time<br />
 time = datetime.datetime.now()<br />
 time_string = time.strftime(&quot;%Y-%m-%d %H:%M&quot;)</p>
<p>#Update the return data in the html page<br />
 return_data = {<br />
  'port_io' : port_io,<br />
  'return_message' : port_io[pin_control]['name'] + &quot; is &quot; + str(port_io[pin_control]['status']),<br />
  'return_time' : time_string<br />
 }</p>
<p> return render_template('remote_template.html', **return_data)</p>
<p>if __name__ == &quot;__main__&quot;:<br />
 app.run(host=&quot;0.0.0.0&quot;, port=80, debug=False) #Web server running on localhost, port 80<br />

E nella cartella templates il file remote_template.html con il template di pagina utilizzato da flask per realizzare la pagina web dinamica:

<br />
&lt;! DOCTYPE html&gt;<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&lt;style&gt;<br />
table {<br />
    border-collapse: collapse;<br />
}<br />
table, th, td {<br />
    border: 1px solid black;<br />
	padding: 10px;<br />
}<br />
&lt;/style&gt;<br />
&lt;title&gt;Remote&lt;/title&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&lt;h1&gt;RPi GPIO Remote Control&lt;/h1&gt;<br />
&lt;hr style=&quot;color:blue&quot; /&gt;<br />
&lt;p&gt;{{ return_time }}&lt;/p&gt;<br />
&lt;table&gt;<br />
&lt;tr&gt;&lt;th&gt;ID&lt;/th&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Status&lt;/th&gt;&lt;th&gt;Switch&lt;/th&gt;&lt;/tr&gt;<br />
{% for pin in port_io %}<br />
&lt;tr&gt;&lt;td&gt;{{ pin }}&lt;/td&gt;<br />
&lt;td&gt;{{ port_io[pin].name }}&lt;/td&gt;<br />
{% if port_io[pin].status == 1 %}<br />
&lt;td style=&quot;color:green;&quot;&gt;On<br />
{% else %}<br />
&lt;td style=&quot;color:red;&quot;&gt;Off<br />
{% endif %}<br />
&lt;/td&gt;<br />
&lt;td&gt;&lt;form action=&quot;/{{ pin }}/&quot; method=&quot;post&quot;&gt;&lt;button name=&quot;status&quot; type=&quot;submit&quot;&gt; on / off &lt;/button&gt;&lt;/form&gt;&lt;/td&gt;&lt;/tr&gt;<br />
{% endfor %}<br />
&lt;/table&gt;<br />
&lt;p&gt;Message: {{ return_message }}&lt;/p&gt;<br />
&lt;hr style=&quot;color:blue&quot; /&gt;<br />
&lt;p&gt;by Gianfranco IZ8EWD, &lt;a href=&quot;https://www.pianetaradio.it&quot; target=&quot;_blank&quot;&gt;PianetaRadio.it&lt;/a&gt;, v1.0 beta&lt;/p&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;<br />

Dal PC aprire il browser ed inserire l’indirizzo IP del proprio Raspberry, apparirà la seguente pagina

Remote Control - Web interface
Remote Control – Web interface

Cliccando sui pulsanti si abilitano o disabilitano le rispettive uscite della GPIO, come visibile dall’acquisizione degli stati eseguita con analizzatore logico, dove le quattro porte, inizialmente spente, sono state abilitate in sequenza

Remote Control - GPIO
Remote Control – GPIO

Sviluppo

Quanto presentato è solo un esempio delle potenzialità di questo sistema, ma va completato con ulteriori funzionalità e soprattutto la gestione del login di accesso per motivi di sicurezza. Pertanto in futuro sono previsti aggiornamenti e sviluppi. Nel frattempo sono ben accetti commenti e suggerimenti.
 

Hardware

La parte hardware è composta, oltre che dal Raspberry e suo alimentatore, da una scheda relè 5V optoisolata, di quelle che si trovano comunemente sul web. La scheda andrà opportunamente interconnessa ai pin della GPIO per il pilotaggio e l’alimentazione.
 

Riferimenti

  1. Flask;
  2. RPi.GPIO
  3. Flask installation guide by Matt Richardson;
  4. Raspberry Pi Web Server using Flask to Control GPIOs, Random Nerd Tutorials;
  5. Flask – un web server in Python su Raspberry, Meccanismo Complesso;
  6. The Flask Mega-Tutorial, by Miguel Grinberg.

Licenza Creative Commons Questa opera è distribuita con:
licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Italia.

Si declina ogni responsabilità per eventuali errori ed omissioni e gli eventuali danni che ne dovessero conseguire. Per ulteriori informazioni consultare le note legali.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *