VSCode Python RasberryPI
RasberryPI + Visual Studio Code + Python + Flask
Oggi vedremo come sviluppare remotamente in Python su RaspberryPI.
Come tutti coloro che si interessano di informatica sanno, RaspberryPI è un Single Board Computer che dispone di un modulo di interfaccia hardware che può essere usata per pilotare sensori elettronici. Molti sanno anche che il Sistema Operativo preferenziale è una versione di Debian chiamata Raspbian e che promuove l'utilizzo del linguaggio di programmazione Python.
Se vogliamo programmare in Python per pilotare sensori, siamo obbligati a lavorare direttamente sulla macchina, non possiamo siluppare su un sistema diverso e poi portare i sorgenti per il semplice fatto che abbiamo la necessità di testare i sensori che sono fisicamente presenti.
Programmare in Python su RaspberryPI può essere complicato perché senza disporre di una IDE di programmazione è difficile fare il debug delle applicazioni. Quindi abbiamo 3 alternative:
- Scrivere i programmi Python con un semplice editor di testo.
- Installare PyCharm community edition
- Utilizzare Visual Studio Code per il debug remoto via SSH
La soluzione n. 1 non consente il debug interattivo e quindi rende difficoltoso lo sviluppo di soluzioni complesse e la consiglio solo per fare piccoli test.
La soluzione n. 2 è ottima e probabilmente è più facile da implementare della soluzione 3 anche se presenta qualche difficoltà.
Infine la soluzione n. 3 forse è più complessa, ma ha alcuni vantaggi:
- Non ho la necessità di collegare il RaspberryPI a tastiera, mouse e video, ma posso lavorare in remoto.
- Posso applicare la tecnica imparata per usarla con altri Single Board Computer oppure con macchine remote VPS o anche con container Docker.
- Visual Studio Code supporta molti linguaggi perciò posso usare un unico strumento per progetti diversi.
Ci sono alcune avvertenza. Siccome con il metodo descritto si devono installare alcune cose nella macchina remota, è necessario che la piattaforma hardware remota sia supportata da VSCode. Al momento oltre alla piattaforma Intel è supportato Arm7 che è quella su cui è basato RasberryPI. Su altre architetture basate ad esempio su Arm8 il sistema non funzionarà.
La nostra guida utilizza come computer host una una macchina Ubuntu ma con qualche passaggio riusciremo a fare la stessa cosa anche con Windows o Mac.
Nel momento in cui scrivo, ho già fatto funzionare la ricetta, perciò non sono sicuro di elencare con precisione tutti i passi necessari, ma sicuramente darò una indicazione precisa del percorso necessario per portare a buon fine il lavoro.
RaspberryPI
Diamo per scontato di aver installato Raspbian sul nostro RaspberryPI e di non aver modificato le impostazioni predefinite. Lo possiamo collegare alla nostra rete domestica tramite WiFi, oppure tramite cavo di rete. Per questo tutorial non serve collegare video, mouse e tastiera, perché tutto il lavoro sarà fatto da remoto.
Se abbiamo la configurazione standard di RaspberryPI, la macchina ha abilitato il DHCP e può essere raggiunta da remoto tramite il comando ssh. Qundi se la colleghiamo alla nostra rete la prima cosa da fare è individuare il suo indirizzo IP: dalla nostra macchina host la possiamo cercare usando un programma che fa la scansione della rete ad esempio: Angry IP Scanner dopo aver individuato l'indirizzo (ad esempio 192.168.1.25) possiamo provere se funziona SSH.
ssh pi@192.168.1.25
ci chiede la password e digitiamo
raspberry
Se funziona tutto possiamo proseguire. Una cosa che possiamo fare e che è consigliata, anche se non obbligatoria, è quella di usare una chiave RSA per accedere al RaspberryPI senza digitare la password. Se non lo abbiamo ancora fatto, creiamo una chiave sul nostro computer host con
ssh-keygen
e copiamo la parte pubblica della chiave sul RaspberryPI con:
ssh-copy-id pi@192.168.1.25
ci viene chiesta la password e dopo averla digitata entriamo nuovamente con ssh:
ssh pi@192.168.1.25
Da questa volta in poi non ci viene più chiesta la password.
Dato che ci siamo variamo un parametro di configurazione che ci tornerà buono in seguito. Con il comando:
sudo nano /etc/sysctl.conf
modifichiamo il file ed alla fine del testo aggiungiamo la riga:
fs.inotify.max_user_watches=524288
poi riavviamo la configurazione con:
sudo sysctl -p
Questo ci permette di aprire molti files da remoto quando accederemo con VSCode. Ora installiamo anche tutto quello che ci serve di Python con:
sudo apt install python3 python3-pip python3-venv
Ubuntu (host)
Come sul RaspberryPI, anche sulla macchina host ci dobbiamo accertare di disporre di una installazione completa di Python, consigliamo di usare Python 3 dato che il supporto per Python 2 sta per finire. Installiamo quindi:
sudo apt install python3 python3-pip python3-venv python3 -m pip install -U pip --user
Visual Studio Code
Come abbiamo già avuto modo di dire, Visual Studio Code è una ottima IDE per programmatori. È leggera ma molto potente ed ha il vantaggio indubbio di supportare molti linguaggi di programmazione. La installeremo sul computer host e ci permetterà di lavorare remotamente sul nostro RaspberryPI. Per installarla su un sistema Ubuntu consiglio di usare l'utility ubuntu-make che permette di tenere aggiornato il programma ed anche di installare altri tools per sviluppatori.
sudo apt install ubuntu-make umake ide visual-studio-code
Per trovare il programma nel menù della applicazioni di Ubuntu, dovete terminare la sessione e rifare il login per dare modo al sistema di riconoscere che è stato installato un programma nuovo, oppure potete lanciare il programma direttamente da riga di comando con:
~/.local/share/umake/ide/visual-studio-code/bin/code
consigliamo di aggiungere il percorso del programma al nostro file .bashrc in modo da lanciarlo semplicemente digitando:
code
Configurazione di VSCode (Python debugger)
Prima di tutto dobbiamo installare l'estensione Python per VSCode, apriamo il tool delle estensioni di VSCcode facendo clic sulla icona a sinistra con i quadratini, oppure digitando Ctrl+Shift+X , sopra scriviamo python ed installano il modulo Microsoft per Python.
Possiamo provare subito a vedere se funziona, da terminale digitiamo:
cd ~ mkdir python_test touch python_test/test.py
quindi andiamo su VSCode ed apriamo la cartella da menu oppure digitando Ctrl+K Ctrl+O . Appena apriamo il nostro file test.py
, VSCode ci chiede di installare alcune cose di Python che gli servono per la ricerca intelligente. Ora scriviamo il nostro programma di test:
import sys print(sys.path)
per provere il programma lanciamo il debugger facendo clic sulla icona a sinistra con l'insetto oppure digitando Ctrl+Shif+D . La prima volta il programma chiede la configurazione di debug che desideriamo. Scagliamo Python File ed il programma scrive un file di configurazione di nome launch.json nella cartella .vscode sotto la cartella corrente.
A questo punto possiamo andare sul nostro file test.py, mettere un punto di interruzione in corrispondenza della istruzione print, ed avviare il debugger scegliendo "Python: Current File" nella finestrella di debug che compare in alto.
Se abbiamo fatto tutto bene, il programma si avvia e si arresta nel punto prescelto, e proseguendo stampa il nostro sys.path
Configurazione di VSCode (remote - SSH)
Per sviluppare sulla RaspberryPI remota dal nostro VSCcode, dobbiamo installare il modulo remote - SSH, Premiamo Ctrl+Shift+X e cerchiamo Remote -SSH, installiamo il modulo e comparirà una nuova icona sulla sinistra che raffigura uno schermo con un cerchietto che indica la connessione. Facciamo clic sull'icona e sulla sezione "SSH TARGETS" facciamo clic sulla icona con l'ingranaggio. Scegliamo il primo file proposto e scriviamo:
Host RaspberryPI HostName 192.168.1.25 User pi
Salviamo e sulla sinistra sotto SSH TARGET dovrebbe comparire la nostra configurazione. Se facciamo clic sulla icona con la cartellina sulla riga della nostra configurazione VSCode si dovrebbe aprire un'altra finestra con la connessione al nostro RaspberryPI.
Nella nuova finestra, nella parte bassa a sinistra si dovrebbe vedere lo stato della connessione, alla fine dovrebbe comparire "SSH: RaspberryPI" che indica che la connessione è andata a buon file.
Ora sulla nuova finestra facciamo clic sulla incona in alto a sinistra con l'immagine di due fogli che permette di aprire una cartella. Compare la sessione "Open Folder" che permette di scegliere la cartella e noi scegliamo /home/pi.
Debug remoto di applicazioni Python
Finalmente siamo pronti!
Configurazione RasberryPI
Andiamo nella finestra di SSH con:
ssh pi@192.168.1.25
e prepariamo un po' di cose per Python. Purtroppo non sono riuscito a fare il debug con un Virtualenv nella macchina remota, perciò installeremo tutte le cose che servono per Python nella cartella utente 'pi'. Di solito questo può andare bene, perché probabilmente non si faranno girare molte applicazione nel nostro RaspberryPI.
Quindi digitiamo:
python3 -m pip install -U pip --user python3 -m pip install flask --user mkdir ~/python touch ~/python/hello.py touch ~/python/flaskapp.py mkdir ~/.vscode
Per il nostro test, proveremo uno script semplice Python ed un "Hello World!" con il server Web Flask. Per ora i files sono vuoti, ma poi potremo inserire i nostri sorgenti.
Io non conosco niente di sensori ed elettronica perciò faccio un applicativo Web che mi permette di testare un po' di cose, ma chi si interessa di elettronica potrà fare applicativi specifici usando le molte librerie e la molta documentazione che si trova. E se desidera, visto che c'è, può approntare una interfaccia Web.
Ora per risparmiare tempo prepariamo già i files di configurazione per VSCode che funzionano in modo corretto:
nano ~/.vscode/launch.json
e scriviamo il testo:
{ "version": "0.2.0", "configurations": [ { "name": "Python: Current Falsk", "type": "python", "request": "launch", "module": "flask", "cwd": "${fileDirname}", "env": { "FLASK_APP": "${file}", "FLASK_ENV": "development", "FLASK_SETTINGS": "settings.cfg" }, "args": [ "run", "--no-debugger", "--no-reload", "--host=0.0.0.0", "--port=5050" ], "jinja": true }, { "name": "Python: Current File", "type": "python", "request": "launch", "program": "${file}", "console": "integratedTerminal" } ] }
Questa configurazione prepara un ambiente Flask funzionante, con due particolarità. Il parametro "--host=0.0.0.0" consente di accedere al server Flask da qualsiasi indirizzo IP ed il parametro "--port=5050" cambia la porta di default del server Web che di solito in Flask è 5000, naturalmente si può cambiare con qualsiasi porta comresa la porta 80 che è quella di default per il Web.
poi con
nano ~/.vscode/settings.json
scriviamo il testo:
{ "python.pythonPath": "/usr/bin/python3" }
Che istruisce VSCode che desideriamo utiizzare l'interprete python3
Avvio del debugger VSCcode
In VSCode nella nostra pagina con la configurazione remota, dobbiamo installare in remoto l'estensione di Python, come al solito premiamo Ctrl+Shift+X ed installiamo l'estensione, ci mette un po' di tempo, alla fine ricarichiamo la pagina e siamo pronti.
Facciamo clic sul nostro file ~/python/flaskapp.py
ed il sistema riconosce che si tratta di un file Python, ci chiede di installare un po' di cose e forse va in errore su qualcosa, ma dovrebbe funzionare ugualmente.
Il testo da scrivere è:
from flask import Flask app = Flask(__name__) @app.route('/') def index(): return '<h1>Hello, World!</h1>'
Mentre invece nel file file ~/python/hello.py
scriviamo il nostro solito:
import sys print(sys.path)
Abbiamo quasi finito, non resta che avviare il debugger. Come abbiamo fatto in precedenza per fare il test locale premiamo Ctrl+Shift+X per avviare il debugger, forse in questo momento VSCode installerà ancora qualcosa nel RaspberryPI remoto.
Fortunatamente avevamo già preparato la configurazione per il debugger e quindi scegliamo il file ~/python/hello.py
e lanciamo la configurazione di debug di nome "Python: Current File" e nel terminale dovrebbe comparire la lista dei percorsi del path di Python.
Infine scegiamo il file ~/python/flaskapp.py
, avviamo il debugger e scegliamo la configurazione "Python: Current Falsk".
Se siamo stati bravi (ed anche un po' fortunati) nel terminale dovrebbe comparire qualcosa simile a:
* Serving Flask app "/home/pi/python/flaskapp.py" * Environment: development * Debug mode: on * Running on http://0.0.0.0:5050/ (Press CTRL+C to quit)
HURRA!!!
Abbiamo un server Web.
Non ci resta che andare nel nostro browser e nella riga degli indirizzi digirare:
http://192.168.1.25:5050
e nella nostra pagina comparirà il mitico
Hello, World!
Mettiamolo in produzione
Ora avete un sistema efficiente che vi permetterà di risparmiare molto tempo in fase di sviluppo. Ed alla fine riuscirete senz'altro a realizzare il vostro magnifico applicativo.
È giunto perciò il momento di mettere in funzione il nostro RaspberryPI per lo scopo a cui è stato destinato. Questo significa che senza alcun intervento da parte dell'operatore, quando si dà l'alimentazione il sistema deve partire ed avviare tutto ciò che serve. Dobbiamo fare due cose.
Avvio automatico del server Web
Nel nostro caso vogliamo che quando accendiamo il RaspberryPI parta automaticamente il server Web, ma potrebbe essere anche un altro applicativo.
Entriamo nel RaspberryPI con SSH
ssh pi@192.168.1.25
e per prima cosa scriviamo uno script bash per avviare il nostro server Web con il comando:
nano ~/python/startapp.sh
e scriviamo il testo:
#!/bin/bash cd /home/pi/python export PYTHONUNBUFFERED=1 export FLASK_APP=flaskapp.py python3 -m flask run --host=0.0.0.0 --port=5050 &
da notare il carattere "&" alla fine del comando che fa partire il server, la sua presenza indica al sistema operativo di avviare il programma in background e di terminare lo script.
ora lo dobbiamo renderlo avviabile e lo dobbiamo provare con:
chmod +x ~/python/startapp.sh ~/python/startapp.sh
Dovrebbe partire il server Web.
Ora dobbiamo fare in modo che il programma parta alla accensione del RaspberryPI. Ci sono tanti modi per farlo. Se avete installato RaspberryPI con la configurazione di default che fa il login automatico con l'utente 'pi', il sistema più semplice modificare il file /home/pi/.bashrc
che verrà avviato automaticamente con il login di 'pi'. Quindi scriviamo:
nano /home/pi/.bashrc
ed alla fine del testo aggiungiamo la riga:
/home/pi/python/startapp.sh
salviamo e facciamo il reboot con:
sudo reboot
Il nostro RaspberryPI si riavvia ci mette alcuni secondi. Quando il led verde che indica l'attività del disco smette di lampeggiare, possiamo provare a vedere se funziona aprendo il browser e digitando l'indirizzo:
http://192.168.1.25:5050
bene, ora il server parte alla accensione del RaspberryPI. Se torniamo ad entrare con SSH, alla fine del login comparirà un messaggio d'errore nella cui ultima riga c'è scritto:
OSError: [Errno 98] Address already in use
questo è normale, perché all'avvio della macchina il server è già partito e facendo un nuovo login lui tenta di riavviarlo, ma la porta è già impegnata.
Se vogliamo fermare il server possiamo digitare:
ps -e | grep python3
che ci comunica il numero di processo che fa girare il server, ad esempio
709 tty1 00:00:02 python3
poi con il comando
kill 709
fermiamo lo script e siamo pronti per fare ulteriori modifiche
IP statico
Ora il nostro server Web parte all'avvio del RaspberryPI, però l'indirizzo IP della macchina su cui gira è stato assegnato del server DHCP che di solito sta nel nostro router. Normalmente i server DHCP ricordano gli indirizzi assegnati alle periferiche collegate, ma se non usiamo una periferica per un certo periodo, oppure se per qualsiasi motivo la memoria DHCP viene resettata, è molto probabile che il nostro RaspberryPI prenda un indirizzo IP diverso, perciò è opportuno assegnargliene uno statico.
Anche in questo caso su Internet si trovano molti tutorial che spiegano in dettaglio come fare. Qui noi semplifichiamo un po' indicando solo le fasi essenziali.
I vari modelli di RaspberryPI, possono avere la scheda Ethernet per il collegamento via cavo o anche la connessione WiFi integrata, quando è possibile è meglio usare la connessione cablata, ma se è complicato tirare i cavi, si può usare anche quella WiFi.
Prima di tutto configuriamo il WiFi. Per individuare le reti WiFi disponibili possiamo dare il comando:
sudo iwlist wlan0 scan | grep ESSID
e possiamo inserire la nostra rete prescelta tra quelle che vengono avviate automaticamente modificando il file:
sudo nano /etc/wpa_supplicant/wpa_supplicant.conf
Se non è già stato fatto, configuriamo la rete WiFi dando i nostri parametri di configurazione con:
network={ ssid="My WiFi connector" psk="MySuperSecretPassword" key_mgmt=WPA-PSK }
Questo ci garantisce che alla accensione venga attivata automaticamente la rete WiFi prescelta.
Non ho provato, ma è molto probabile che se configuro più di un network
vengano provati in sequenza e venga avviato il primo che fornisce la connessione.
Ora riavviamo il RaspberryPI
sudo reboot
Aspettiamo, rientriamo con SSH ed è giunto il momento di rendere statici i nostri indirizzi IP.
Se scriviamo:
ip r
otteniamo la lista delle connessioni attive. Dovremmo vedere qualcosa del tipo:
default via 192.168.1.1 dev eth0 src 192.168.1.25 metric 202 default via 192.168.1.1 dev wlan0 proto dhcp src 192.168.1.97 metric 303 192.168.1.0/24 dev eth0 proto dhcp scope link src 192.168.1.25 metric 202 192.168.1.0/24 dev wlan0 proto dhcp scope link src 192.168.1.97 metric 303
questo ci indica che la nostra rete cablata eth0 risponde all'indirizzo 192.168.1.25 e la rete WiFi wlan0 risponde all'indirizzo 192.168.1.97, possiamo rendere statici entrambe le connessioni oppure solo una modificando il file:
sudo nano /etc/resolv.conf
Alla fine del file aggiungiamo queste righe:
# Static IP cable interface eth0 static ip_address=192.168.1.25/24 static routers=192.168.1.1 static domain_name_servers=192.168.1.1 8.8.8.8 # Static IP wifi interface wlan0 static ip_address=192.168.1.97 static routers=192.168.1.1 static domain_name_servers=192.168.1.1 8.8.8.8
D'ora in poi ogni volta che riavviamo il nostro RaspberryPI, verrà avviato il server Web all'indirizzo http://192.168.1.25:5050
semplicemente collegando il cavo di alimentazione.
Conclusione
In questo tutorial abbiamo toccato molti argomenti, ognuno dei quali meriterebbe una trattazione molto più approfondita. Ma dovendo portare a termine il risultato abbiamo dovuto per forza essere un po' sbrigativi.
Vi invito percò ad approfondire tutti gli argomenti facendo ricerce specifiche su Internet, così come ho fatto io per scrivere il tutorial e renderlo funzionante.
Mi chiamo Claudio Driussi, mi occupo da molti anni di sviluppo di software gestionale e di integrazione di sistemi.
Per commenti e suggerimenti mi potete mandare una mail a claudio.driussi@gmail.com