PiFace Digital 2: Applicazioni avanzate in Python

piface

In questo articolo vedremo come realizzare delle applicazioni più avanzate per il nostro PiFace Digital. In particolare vi mostrerò come creare un’applicazione multithread, ovvero come definire dei sottoprogrammi all’interno della nostra applicazione, che andranno a fare polling (si metteranno in ascolto) su diverse porte di input, eseguendo task differenti. Vedremo inoltre come condividere una variabile tra i thread in esecuzione e come gestire la pressione prolungata di un tasto.

Se vi siete persi il primo articolo al riguardo, vi consiglio di leggerlo.

Il programma di esempio che andremo a vedere, crea quattro thread che saranno lanciati parallelamente in esecuzione. I primi tre svolgono essenzialmente le stesse operazioni, ovvero aggiornano e poi stampano a video il valore della variabile condivisa che è stata creata. Il quarto thread invece, alla pressione prolungata per almeno 2 secondi, accende in sequenza tutti i led presenti sulla scheda PiFace. Di seguito è mostrato il codice che poi andremo a commentare. Suppongo che il lettore abbia già conoscenza del linguaggio Python, dunque eviterò di dare spiegazioni dettagliate per ciò che riguarda la sintassi e la logica del linguaggio.

#!/usr/bin/env python3

from time import sleep
from timeit import default_timer
import pifaceio
import threading

pfio = pifaceio.PiFace()

#------ Shared variable -------
class Variable(object):
   value = None

myVar = Variable()

def myVarSet(stato):
   myVar.value = stato

def myVarValue():
   return myVar.value


#----- Pin read and write methods -----
def read_pin(pin):
   pfio.read()
   return pfio.read_pin(pin)

def write_pin(pin, state):
   pfio.write_pin(pin, state)
   pfio.write()


#------ Threads defining-------
class myThread (threading.Thread):
   def __init__(self, name):
      threading.Thread.__init__(self)
      self.name = name
 
   def run(self):
      if self.name == 'f1':
         f1()
      elif self.name == 'f2':
         f2()
      elif self.name == 'f3':
         f3()
      elif self.name == 'ledShow':
         ledShow()

def f1():
   while True: 
      if read_pin(0):
         print 'Previous state: ', myVarValue()
         myVarSet(1)
         print 'Current state: ', myVarValue()
         sleep(1)
      if read_pin(0) and read_pin(2):
         print 'Thread 1 terminated'
         break

def f2():
   while True: 
      if read_pin(1):
         print 'Previous state: ', myVarValue()
         myVarSet(2)
         print 'Current state: ', myVarValue()
         sleep(1)
      if read_pin(0) and read_pin(2):
         print 'Thread 2 terminated'
         break

def f3():
   while True: 
      if read_pin(2):
         print 'Previous state: ', myVarValue()
         myVarSet(3)
         print 'Current state: ', myVarValue()
         sleep(1)
      if read_pin(0) and read_pin(2):
         print 'Thread 3 terminated'
         break 


def ledShow():
   while True:
      if read_pin(3):
         start = default_timer()
         now = default_timer()
         endsBefore = False
         while ((now - start) <= 2):
            if not read_pin(3):
               endsBefore = True
               break
            now = default_timer() 

         if not endsBefore:
            leds = range(0,8)
            for led in leds:
               write_pin(led, 1)
               sleep(0.5)
               write_pin(led, 0)

      if read_pin(0) and read_pin(2):
         print 'Thread 4 terminated'
         break 


#---- Shared variable initialiting
myVarSet(0)


#---- Starting threads -----
func1 = myThread('f1')
func2 = myThread('f2')
func3 = myThread('f3')
func4 = myThread('ledShow')

func1.start()
func2.start()
func3.start()
func4.start()

print 'Hold down the buttons 0 and 2 to terminate the program'

func1.join()
func2.join()
func3.join()
func4.join()

Come si può vedere dal codice, è stata definita una classe myThread per la creazione dei threads. Quando un nuovo oggetto della classe myThread viene istanziato e lanciato, viene eseguita una specifica funzione in base al parametro name passato al costruttore. Questo approccio ha consentito di definire una singola classe dinamica per la creazione dei thread. Per poter condividere una variabile tra i vari thread in esecuzione, è necessario creare un oggetto e inizializzare il valore della variabile in esso contenuta solo dopo la definizione delle varie ‘funzioni thread’. Il quarto thread, che corrisponde alla funzione ledShow, effettua polling sull’input 3 e una volta che viene trovato attivo, controlla che per i prossimi 2 secondi resti in quello stato; in caso positivo entra nel blocco if successivo e accende tutti i led in sequenza.

Sulla base del programma appena visto potrete creare applicazioni avanzate e personalizzate per il vostro PiFace Digital, dando spazio alla creatività. I thread visti in questo esempio eseguono azioni molto banali, ma potrebbero eseguire operazioni molto più interessanti come l’invio di un’email, lo scatto di una foto da una webcam, accendere il sistema di riscaldamento di casa, ecc. Dunque non dovete fare altro che dare spazio all’immaginazione e creare il vostro sistema IoT!

Sulla pagina ufficiale di PiFace potete trovare moltissime idee e guide su come realizzarle (in lingua inglese) .

 

3 commenti

  1. Moooooolto interessante questo articolo !!!!!!! sarei molto interessato su come inviare una o più mail all´ingresso di uno o più stati, il massimo sarebbe ad ogni input (chiusura contatto) una mail o gruppo di mail . Non sono riuscito a trovare niente a riguardo…. mi puoi dare qualche link con qualche esempio magari !! :-).
    PS. anche lo scatto di una foto non sarebbe male con invio su un server http://FTP…. chiedo troppo ?
    Grazieee

    1. Ciao, ti è sufficiente cambiare il corpo di una delle funzioni con uno script per l’invio di una mail. Ti basta cercare su Google come inviate email in Python. Adesso sono in vacanza quindi non posso risponderti in maniera dettagliata dallo smartphone. Per le foto prova a vedere MotionEyeOS che è molto completo e ti consente di gestire anche più telecamere, di impostare dei generatori di allarme via email quando rileva dei movimenti ecc. (ti sconsiglio peró di usare il rilevamento dei movimenti all’esterno perché anche una foglia potrebbe far scattare un falso allarme 😄). Siccome è pesante come software sarebbe l’ideale installarlo su un raspberry o comunque un device dedicato..

      1. OK grazie magari quando torni se mi fai un esempio da cui partire devo capire come collegare l´invio della mail con la chiusura di un contatto in input al pface digital 2
        Saluti

Lascia un commento

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

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.