Questo sito utilizza cookie di profilazione di terze parti. Se prosegui nella navigazione o clicchi X acconsenti all’uso di cookie.
Clicca qui per più informazioni sui cookie.
Mappa del sitoHomeElettronicaRaspberry PiC64

Gestire il RPi con Whatsapp


Attivare javascript per utilizzare il sito!



yowsup In questa pagina vedremo come poter comunicare con il nostro Raspberry utilizzando la libreria Yowsup.
Ho realizzato uno script in Python (scaricabile qui) che resta in attesa di un messaggio da parte mia tramite whatsapp, analizza il contenuto e se trova un comando specifico mi risponde sempre utilizzando Whatsapp.

Lo script è molto semplice e può essere notevolmente migliorato. Comunque potete utilizzarlo come base di partenza per un sistema di automazione della casa.

Una breve nota: la soluzione migliore sarebbe stata l'utilizzo delle librerie direttamente nello script, ma per semplicità ho preferito sfruttare lo script per la linea di comando già presente in Yowsup, modificando semplicemente alcune parti come indicato in seguito.

Per la descrizione prenderò come cartella di installazione /home/pi/yowsup (che è quella utilizzata nella pagina di installazione e configurazione).

Innanzitutto dovrete modificare il file yowsup/src/Example/ListenerClient.py per fare in modo che non resti fermo in ascolto e per salvare il messaggio ricevuto in un file.


Le sezioni da modificare solo le seguenti (in grassetto le mie modifiche):

def login(self, username, password):
    self.username = username
    self.methodsInterface.call("auth_login", (username, password))
    time.sleep(1)
    #while True:
        #raw_input()

e

def onMessageReceived(self, messageId, jid, messageContent, timestamp, wantsReceipt, pushName, isBroadCast):
    formattedDate = datetime.datetime.fromtimestamp(timestamp).strftime('%d-%m-%Y %H:%M')
    #print("%s [%s]:%s"%(jid, formattedDate, messageContent))
    with open ("/home/pi/message.msg","w") as mss: mss.write(jid[:12]+messageContent)
    if wantsReceipt and self.sendReceipts:
        self.methodsInterface.call("message_ack", (jid, messageId))


Nel caso la cartella utilizzata sia differente, modificate il percorso di salvataggio del messaggio presente nella seconda definizione.

Adesso analizziamo le varie parti del mio script. Come prima cosa la sezione iniziale delle variabili (tralascio l'importazione dei moduli):

base="/home/pi/"
recipient="390000000000"
mac="00:00:00:00:00:00"
iprange="192.168.0.1-50"
counter=0
status=0
starting="Raspberry Pi started."
phonewaiting=360
#tempo=0.0


base indica la cartella di installazione. Se avete seguito le istruzioni sul mio sito non dovrete modificarla.
recipient è il numero di telefono da cui ricevere i comandi e al quale inviare le risposte. Deve comprendere il codice internazionale senza il carattere '+'.
mac è l'indirizzo mac del mio telefono. Serve per sapere quando sono connesso alla mia rete wi-fi.
iprange è il range di indirizzi da controllare per sapere se il telefono è connesso alla rete wi-fi.
counter e status sono utilizzati dallo script e non devono essere modificati.
starting è il messaggio inviato all'avvio dello script. Se avviate lo script al boot vi manderà il messaggio quando accenderete il RPi.
phonewaiting è il numero di cicli da attendere dopo la disconnessione del telefono dalla rete wi-fi prima di inviare un nuovo messaggio.
tempo (normalmente commentato) serve per conoscere la durata di un ciclo, in modo da configurare correttamente la variabile phonewaiting.

Di seguito trovate la definizione della funzione che invia il messaggio al destinatario ed eventualmente cancella il file del messaggio ricevuto. Non è necessario modificarla.

Sotto alla funzione di invio c'è il comando che si occupa di mandare il messaggio iniziale. Se commentate la variabile starting non sarà inviato nulla.

try:
    Answer(starting)
except:
    pass


Infine troviamo il ciclo principale che sarà eseguito indefinitamente grazie all'istruzione:

while(1):


Le prime tre righe del ciclo servono per verificare la durata. Potete visualizzare o memorizzare in un file il tempo trascorso semplicemente rimuovendo il commento dalle relative righe (la prima visualizza, la seconda memorizza nel file di log e la terza fa il calcolo):

#print time.time()-tempo
#with open(base+"whatsapp.log", "a") as myfile: myfile.write(str(time.time()-tempo)+"\n")
#tempo=time.time()


La riga successiva prova a connettersi a Whatsapp per ricevere un messaggio:

os.system("python "+base+"yowsup/src/yowsup-cli -c "+base+"yowsup/src/config -l -a -k")


Il cuore dello script è all'interno del comando try:. La clausola except: serve solo per non generare un errore se il file non è presente (messaggio non ricevuto). Lo stesso risultato si può ovviamente ottenere con altri metodi.

Le istruzioni seguenti tentano di leggere il messaggio e lo convertono tutto in minuscolo. Questo ci consente di ignorare il fatto che un comando potrebbe avere ad esempio la maiuscola iniziale.

with open(base+"message.msg") as mss: received=mss.readline()
received=received.lower()


Viene poi controllato se il numero da cui proviene il messaggio è quello corretto. In caso contrario viene memorizzato un errore nel file whatsapp.log per notificare il fatto.

if received[:len(recipient)]==recipient:
    received=received[len(recipient):]
    .
    .
    .
else:
    with open(base+"whatsapp.log", "a") as myfile: myfile.write("Message from wrong sender: "+received[:len(recipient)]+"\n")
    if os.path.exists(base+"message.msg"): os.remove(base+"message.msg")


Se tutto va bene, si controlla le presenza di un comando valido semplicemente confrontando il messaggio ricevuto con un testo fisso. Vediamo alcuni esempi.

Il primo test controlla se arriva un saluto e risponde con lo stesso saluto. Il numero presente dentro le parentesi (in questo caso [:5]) è il numero di caratteri da controllare. In questo modo il comando funziona anche scrivendo un messaggio come "Hello my RPi!".

if received[:5]=="hello":
    Answer("Hello!")


I test successivi utilizzano il comando elif per eseguire la verifica solo se quella precedente è risultata negativa.

Il secondo test ci consente di fare un reboot del RPi:

elif received[:7]=="restart":
    Answer("I am restarting...")
    os.system("sudo reboot")


Ovviamente è possibile fare test più complessi, rispondendo nello stesso modo a due comandi diversi:

elif received[:11]=="goodmorning" or received[:12]=="good morning":
    Answer("Goodmorning to You!")


I prossimi due test ci consentono di controllare lo spazio sulla scheda SD e la temperatura del RPi:

elif received[:6]=="memory":
    result=subprocess.check_output("df -h .", shell=True)
    righe=result.split()
    Answer("Main memory:\nTotal: "+righe[9]+"\nUsed: "+righe[10]+" ("+righe[12]+")\nFree: "+righe[11])
elif received[:11]=="temperature":
    t=float(subprocess.check_output(["/opt/vc/bin/vcgencmd measure_temp | cut -c6-9"], shell=True)[:-1])
    ts=str(t)
    Answer("My temperature is "+ts+" °C")


Infine, se non abbiamo trovato un comando valido, il RPi ci può informare della cosa.

else:
    Answer("Sorry, I cannot understand what You mean!")


L'ultima parte serve a controllare se il telefono è connesso alla rete di casa. Nel momento in cui si connette viene inviato un messaggio di benvenuto. Per inviare nuovamente questo messaggio il telefono deve restare disconnesso per il numero di cicli specificato (nel mio caso l'attesa sarà di circa un ora).
Fate attenzione che alcuni telefoni si disconnettono quando sono in stand-by.

finally:
    result=subprocess.check_output("sudo nmap -sn "+iprange, shell=True)
    if (mac in result) and (status==0):
        Answer("Welcome back!")
        status=1
    if (mac in result) and (status==1):
        counter=0
    if (mac not in result) and (status==1):
        counter=counter+1
    if (status==1) and (counter>phonewaiting):
        status=0
        counter=0
    time.sleep(4.5)


Questi sono dei comandi molto semplici e si può fare molto di più! Ad esempio aggiungendo un po' di elettronica potreste usare questo metodo per accendere e spegnere una luce, oppure per settare un termostato.

Attualmente sto facendo delle prove per farmi inviare a comando un immagine presa dalla webcam (cosa che si potrebbe fare anche in automatico se viene rilevato un movimento).

Le possibilità come vedete sono innumerevoli.





Queste sono le pagine del RPi:
F.A.Q.
Base
SiriProxy
Emulatore C64
Web server
Installare Yowsup
Usare Whatsapp