www.errorediridondanzaciclicodotcom

  • Home
  • CAMPANELLO INTERATTIVO
  • BACK P.P.

  • Un campanello per casa con il raspi

    Il campanello interattivo secondo me

    Ci sono molti esempi sul web di campanelli interattivi che permettono, ad esempio, di inviare SMS, quando premuti.
    Io invece ho voluto puntare l’attenzione sulla possibilità di inviare informazioni, stringhe di testo, sul visore del campanello in modo da poter comunicare con le persone che suonano tale campanello.

    Tutto è basato sui socket, protocollo di comunicazione che permette il trasferimento di messaggi all’interno della rete tra diversi device.
    Il mio obiettivo sarebbe stato quello di avere un Raspberry principale con funzione di campanello e diversi Raspberry con funzioni di risponditori. Purtroppo ho dovuto abbandonare le intenzioni iniziali e mi sono dovuto concentrare su sistema basato su un campanello e un solo risponditore. Ciò perché la mia funzione di risposta alla chiamata del campanello presuppone l’invio di un messaggio grafico che permette di cancellare le chiamate pervenute sui risponditori. Il problema era che la risposta provocava solo la scomparsa della finestra sul risponditore che si utilizzava per rispondere, non annullando il messaggio sugli altri risponditori.
    Utilizzando solo messaggi testuali, come in una chat, non avevo problemi. Probabilmente ciò è dovuto alle mie modeste conoscenze di programmazione e alla fine mi sono accontentato di avere un sistema duale, campanello + risponditore.

    Nella foto vedete il disegno del campanello sul touchscreen del Raspberry che, una volta premuto, invia attraverso il socket il messaggio al client.
    Questo messaggio fa partire la suoneria (il suono del campanello) e nello stesso tempo fa comparire i pulsanti di risposta progettati attraverso Tkinter.

    Qui si vedono tre pulsanti (a mia scelta) che permettono di inviare le tre rispettive risposte al campanello.
    Una volta premuto uno dei tre pulsanti, il suono, eventualmente ancora presente, cessa e il messaggio collegato al pulsante premuto viene inviato al campanello.
    La persona che ha premuto il campanello potrà leggere il messaggio inviato sullo schermo.
    Ovviamente, dei tre pulsanti, quello realmente utile, almeno in casa mia che non è tanto grande, è quello “arrivo” perché permette di informare il visitatore che sono in casa e che sto per aprire.

    In caso non venga premuto nessuno dei tre pulsanti, perché non c’è nessuno in casa, dopo un certo periodo comparirà il messaggio “nessuno in casa”.

    C’è poi un quarto messaggio che può comparire una volta premuto un pulsante (fisico) esterno, il messaggio è: “sono sotto la doccia”.
    A volte capita di essere sotto la doccia e di sentire suonare il campanello.
    Per questa situazione ho deciso di installare un ricevitore a radio frequenza sul Raspberry che permette di ricevere il segnale da un trasmettitore via radio.
    Sul ricevitore c’è un relais che chiude un contatto, questo contatto chiuso viene poi letto dal Raspberry che provvederà, attraverso il programma in python, ad inviare il messaggio al campanello.
    Per il momento non è ancora utilizzato realmente (si tratta solo di un telecomando di prova) perché devo ancora studiare un sistema di un pulsante da inserire nel box doccia che sia impermeabile.

    Materiale necessario:

    Raspberry (nr 2)
    Schermo touch Hannspree da 15”
    Scheda relay della Waveshare
    Ricevitore radio
    Trasmettitore radio
    Schermo touch 3.2” per il server

    Raspberry con touch 3.2” con funzione Server

    Il server (ovvero il pulsante da "suonare")

    Ho installato raspbian jessie su una pi di seconda generazione. Per il touch ho scelto lo schermo della Waveshare da 3.2” che ho installato abbastanza facilmente. Il driver però deve essere quello per jessie quindi si installa il LCD-show-151020. Nessun programma particolare a parte unclutter per evitare di vedere la freccia del mouse sul touch screen (settato a 10”).
    Le icone legate al campanello le ho disegnate direttamente con openoffice draw.
    Per l’alimentazione ho passato due cavi da 1.5 mm2 nel corrugato per una lunghezza di 5mt circa. Sono entrato poi con un connettore dc nell’alimentatore da 5v collegato ad una presa muro.

    La custodia non mi è venuta molta ben rifinita ma ho intenzione a breve a rifarla per mettere uno schermo da 5”.
    Lo script in python è basato su Tkinter che ho scelto per semplicità e leggerezza.

    Qui sotto il core dello script. Questa funzione è quella relativa alla pressione sul campanello:
    def Bellbuttonpressed(self):
    #questo serve a sollevare subito un errore in caso di mancata risposta dal client
    sock.setblocking(False)

    try:
    connection, address = sock.accept() #connessione al socket
    data='yyy' #questo è il messaggio inviato al client, senza alcun significato.
    connection.sendall(data.encode('utf-8')) #questa linea invia il dato ai client
    time.sleep(0.5)

    #quando il client invierà la risposta questa verrà ricevuta dal server
    data =connection.recv(1024)
    data =data.decode('utf-8') #questa linea rende leggibile il dato ricevuto

    #cosa fa se il client non è pronto e non invia dati
    if not data:
    data='ripr. tra 2 minuti'

    #qui sotto prepara la casella dove comparirà il messaggio dal client
    T = Text(root, height=1, background="black",foreground="white", font=("arial", 16))
    T.pack()
    T.insert(INSERT, data)
    T.tag_config("center", justify='center')
    T.tag_add("center", 1.0, "end")

    #dopo avere mostrato il messaggio e dopo 5” la casella scompare
    root.after(5000, T.destroy)

    #l’immagine del campanello iniziale ricompare, per la successiva suonata
    self.Bellbutton.configure(background="red", image=self.image)

    #questa è l’eccezione se qualcosa va storto
    except socket.error:

    self.Bellbutton.configure(background="yellow", image=self.image2)

    Come detto prima, alla pressione del pulsante sul sever si avvia una comunicazione socket con il client il quale vedrà comparire sullo schermo dei pulsanti di risposta.
    Premuto uno di questi (compreso quello esterno della doccia) il client manderà il messaggio relativo al server (il campanello) e spengerà il suono.

    Vediamo ora il lato Client


    #Quella che segue è la classe per il pulsante doccia che deve essere strutturata in Thread perché se si avvia Tkinter, questo è bloccante e richiede tutta l’attenzione per sè.

    class Button_Wash(Thread):

    def __init__(self):

    Thread.__init__(self)

    La variabile playing serve per evitare che una pressione del pulsante doccia senza essere stato suonato il campanello possa innescare una reazione. Infatti si vede che il metodo controlla che playing sia True (cioè sta suonando il campanello). Avendo premuto il pulsante di risposta rimette uguale a False la variabile. Notare che la variabile deve uscire dal metodo ed essere globale perché possa essere utilizzata e cambiata da altre parti di codice (i guru del python inorridiranno per aver usato “global” ma non mi è venuta in mente nessuna alternativa).

    def checkloop(self):
    while True:
    global playing
    if GPIO.input(ButPin) == 0 and playing == True:
    playing=False
    pygame.mixer.music.stop()
    datar='Sono sotto la doccia'
    sock.sendall(datar.encode('utf-8'))
    time.sleep(2)
    radice.after(2000,outtime1) #Dopo due secondi si avvia una funzione che semplicemente fa il destroy del frame tkinter (la funzione separata è necessaria per evitare loop del destroy)
    continue

    #Questa è la classe per definire i pulsanti, seguita dai metodi relativi alle azioni per ogni pulsante.
    class MiaApp:
    def __init__(self, genitore):

    larghezza_pulsanti = 15
    imb_pulsantey = "10m"
    self.myRoot = genitore
    self.myRoot.geometry("500x550")
    self.quadro_nomi_pulsanti = Frame(genitore,background = "blue")
    self.quadro_nomi_pulsanti.pack(fill=BOTH)

    self.pulsanteAnnulla = Button(self.quadro_nomi_pulsanti,
    text = "ANNULLA",
    font= ('Courier New',30),
    background = "red",
    width = larghezza_pulsanti,
    pady = imb_pulsantey)
    self.pulsanteAnnulla.pack(side = BOTTOM, pady=30)
    self.pulsanteAnnulla.bind("", self.pulsanteAnnullaPremuto)
    self.pulsanteAnnulla.bind("", self.pulsanteAnnullaPremuto)

    self.quadroPulsanteBell = Frame(self.quadro_nomi_pulsanti,background = "blue")
    self.quadroPulsanteBell.pack(side = BOTTOM)

    self.pulsanteBell = Button(self.quadroPulsanteBell,
    text = "ARRIVO",font= ('Courier New',30),
    background = "green",
    width = larghezza_pulsanti,
    pady = imb_pulsantey)
    self.pulsanteBell.pack(side = BOTTOM, pady=30)
    self.pulsanteBell.bind("", self.pulsanteBellPremuto)
    self.pulsanteBell.bind("", self.pulsanteBellPremuto)

    self.quadroPulsanteBell1 = Frame(self.quadro_nomi_pulsanti,background = "blue")
    self.quadroPulsanteBell1.pack(side = BOTTOM)
    self.pulsanteBell1 = Button(self.quadroPulsanteBell,
    text = "RIPASSARE",font= ('Courier New',30),
    background = "green",
    width = larghezza_pulsanti,
    pady = imb_pulsantey)
    self.pulsanteBell1.pack(side = BOTTOM, pady=30)
    self.pulsanteBell1.bind("", self.pulsanteBellPremuto1)
    self.pulsanteBell1.bind("", self.pulsanteBellPremuto)

    def pulsanteAnnullaPremuto(self,event):
    global playing
    playing=False
    pygame.mixer.music.stop()
    datar='Riprova tra 10 minuti'
    sock.sendall(datar.encode("UTF-8"))
    self.myRoot.destroy()

    def pulsanteBellPremuto(self,event):
    global playing
    playing=False
    pygame.mixer.music.stop()
    datar='Un Attimo!! ARRIVOO!'
    sock.sendall(datar.encode('utf-8'))
    self.myRoot.destroy()

    def pulsanteBellPremuto1(self,event):
    global playing
    playing=False
    pygame.mixer.music.stop()
    datar='Ripassare tra 30 min'
    sock.sendall(datar.encode('utf-8'))
    self.myRoot.destroy()

    def outtime1():
    radice.destroy()
    time.sleep(1)

    def outtime():
    playing=False
    pygame.mixer.music.stop()
    datar='nessuno in casa'
    sock.sendall(datar.encode('utf-8'))
    radice.destroy()
    time.sleep(1)

    #Qui si crea l’istanza del Thread e si lancia

    chk1 = Button_Wash()
    c1 = Thread(target=chk1.checkloop)
    c1.start()

    if __name__ == "__main__":

    playing=False
    while True:
    try:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect(('192.168.xxx.xxx', 9xxx))
    data=sock.recv(1024)
    data=data.decode("utf-8")
    now=datetime.now().strftime("%B %d, %I:%M%p")
    if data:
    playing=True
    pygame.mixer.music.load('/home/pi/Bell/Test.wav')
    pygame.mixer.music.play(0)
    file=open("/home/pi/Bell/RingLogs.txt", "a")
    file.write(now + "\n")
    file.close()
    radice = Tk()
    radice.overrideredirect(1)
    radice.configure()
    miaApp = MiaApp(radice)
    radice.after(60000,outtime)
    radice.mainloop()
    time.sleep(2)
    except:
    print('server off, check it')
    time.sleep(1)

    sock.close()

    Nel main sopra si vede un open file che serve a scrivere i log del campanello in modo da avere uno storico delle scampanellate con data e ora.

    Un semplice orologio con qualche funzione in più

    Nella schermata più sopra, dietro i tastoni di risposta al campanello, si vede svettare un normale orologio simil-digitale.
    Sotto ci sono poi delle informazioni utili: alcune sono legate alle temperature ed alla caldaia e le potete vedere nelle pagine dedicate.
    Oltre a quelle ci sono anche dei tasti per delle utilità:
    Un tasto per uscire dallo script
    Un tasto per accedere ad un calendario “famigliare” dove annotare appuntamenti non solo personali.
    Un tasto per accendere le luci di lettura.
    Un tasto per entrare nella gestione lista spesa (vedere pagina dedicata).
    Un tasto per abilitare la tastiera virtuale sul touch in caso di scomparsa di quella caricata automaticamente al boot.

    Le luci di lettura sono dei faretti che ho messo sopra il divano, di tipo spot, che possono essere accesi singolarmente per ogni postazione di lettura (nel mio caso sono 3).
    Vengono comandati attraverso l’applicazione del modulo relay della Waveshare.

    Nell’immagine sopra vedete la schermata, disponibile anche su smartphone (sotto), per accendere i faretti da server web

    Sotto invece l'applicazione che ho da diversi anni per gestire tramite web-server le luci esterne da remoto: