Quantcast
Channel: Framboise 314, le Raspberry Pi à la sauce française….
Viewing all articles
Browse latest Browse all 1014

Interphone wifi multi-postes avec un Raspberry Pi

$
0
0

Je vous propose de découvrir un objet qui amuse beaucoup les enfants, mais qu’on peut aussi adapter comme interphone de porte.

Bonjour à tous, je m’appelle Pascal, bidouilleur du dimanche, c’est la première fois que j’ai l’occasion de poster un article ici.

Cliquez pour avoir des infos sur les niveaux

Interphone wifi multi-postes avec un Raspberry Pi

J’ai beaucoup cherché une façon pour streamer de l’audio par le wifi, et finalement j’ai réalisé mon projet de la façon qui me semble la plus simple: en utilisant une connexion SSH et les commandes arecord/aplay du pilote ALSA de la sortie sonore de notre Raspberry Pi. Le principe est simple, on presse le bouton quand on parle, et notre interlocuteur nous entend 🙂 Dans ma version j’utilise un bouton rotatif avec plusieurs interphones, mais on peut évidement n’en utiliser que deux et ainsi ne mettre qu’un seul bouton. Sinon j’utilise un micophone USB, un Haut-parleur amplifié, et un fichier Python.

Liste du matériel (pour un interphone)

1 Raspberry Pi
1 Micro SD Card
1 adaptateur secteur (j’ai utilisé un 5v 6A pour alimenter aussi l’ampli)
1 Microphone USB
1 Haut-parleur 8 Ohms 10W (en fonction de l’ampli)
1 ampli pour le HP (moi j’ai utilisé celui d’Adafruit 20W MAX9744)
1 câble avec 2 prises Jack
1 Led rouge 10mm (témoin d’émission)
2 Boutons poussoir au minimum (un pour parler et un pour éteindre le Raspberry)
1 résistance de 100 Ohms
1 résistance de 10 KOhms
1 platine en bakélite

si plusieurs interphones:
1 encodeur rotatif de sélection
plusieurs Leds (le même nombre qu’il y a de postes)
2 Boutons poussoir (pour déclencher un buzzer, et le mode « absent »)
1 buzzer et son transistor NPN
X résistances de 100 Ohms et 10 KOhms (le même nombre qu’il y a de postes)

Le code python

#!/usr/bin/python
# -*- coding: utf-8 -*-
'''
Ce script fonctionne avec 2 interphones, par souci de clarté du code je n'ai pas mis la partie de gestion de plusieurs interphones avec
le bouton encodeur rotatif ni le bouton qui rend ce poste "absent". Pour + d'info sur l'encodeur rotatif voir le tuto dans les sources.

Fonctionnement:
Lorsqu'on appuie sur le bouton "Parler" on génère un flux audio en ssh qu'on lit sur le terminal destinataire.
Le fait de relâcher ce bouton, termine le flux.

Quand on appuie sur le bouton "Buzzer" pour faire sonner l'interphone qu'on appelle: en fait on crée un fichier appelé "sonne" sur le poste
distant. Celui-ci check la présence de ce fichier en boucle, quand il existe il fait sonner son buzzer avant de supprimer le fichier "sonne"

Pour terminer, j'utilise le synthétiseur vocal pico2wave pour générer un son lors d'erreurs (Surtout utilisé si on tente de communiquer
avec un interphone qui a enclenché son bouton "Absent" cela génère une phrase comme quoi il est impossible de le contacter..)
'''
import RPi.GPIO as gpio
import time
import os

# Configuration des variables
ce_terminal = 'a' # ce script est sur le terminal rasptalk-a
destinataire = 'j' # ce script envoie sur -j (sera modifiable avec le bouton rotatif)
etat_absent = 0 # etat du bouton absent (1 si bouton enfoncé)
etat_parler = 0 # etat du bouton parler (rec)
etat_buzzer = 0
print("- - - Ce terminal est: " + ce_terminal + " et notre destinataire: " + destinataire + " - - -")

# on definit les numero des gpio
# Les Entrées (les boutons)
bouton_absent = 18
bouton_parler = 23
bouton_buzzer = 24
bouton_shutdown = 25
bouton_select1 = 16
bouton_select2 = 21
# Les Sorties (les leds)
le_buzzer = 22
led_absent = 17
led_parle = 27
led_rec = 5
led_posteA = 6
led_posteB = 13
led_posteC = 19
led_posteD = 26

gpio.setmode(gpio.BCM) # on utilise les Gpio en mode BCM
gpio.setup(bouton_absent, gpio.IN) # on défini ces ports comme entrées pour lire les positions des boutons
gpio.setup(bouton_parler, gpio.IN)
gpio.setup(bouton_buzzer, gpio.IN)
gpio.setup(bouton_shutdown, gpio.IN)
gpio.setup(bouton_select1, gpio.IN)
gpio.setup(bouton_select2, gpio.IN)

gpio.setup(led_absent, gpio.OUT) # et ceux-ci comme sorties pour allumer/éteindre les led
gpio.setup(le_buzzer, gpio.OUT)
gpio.setup(led_parle, gpio.OUT)
gpio.setup(led_rec, gpio.OUT)
gpio.setup(led_posteA, gpio.OUT)
gpio.setup(led_posteB, gpio.OUT)
gpio.setup(led_posteC, gpio.OUT)
gpio.setup(led_posteD, gpio.OUT)

# On génère un son de bienvenue avec le synthétiseur vocal pico2wave
os.system('pico2wave -l fr-FR -w 0.wav "Bienvenue sur ce terminal. il est prêt a fonctionner." && aplay 0.wav && rm 0.wav')


while True: # boucle infinie
    # Gestion bouton parler
    if(gpio.input(bouton_parler) == True): # si le "bouton parler" est pressé: (Parfois mettre False au lieu de True si notre bouton est off (on) ou on (off) c'est à dire qu'il coupe quand on appuie..
        if etat_absent == 0: # etat du bouton absent (ici le terminal n'est pas sur absent)
            gpio.output(led_rec, gpio.HIGH) # on allume la led rec
            if etat_parler == 0: # si le bouton rec n'a pas déjà été pressé -> on envoie un flux audio par ssh
                etat_parler = 1 # on met la variable à 1
                print("Le terminal desinataire n'est pas absent -> envoi du flux audio")
                os.system('sudo ./record-' + destinataire + '.py &') # on execute record-j.py en arrière plan, et on kill son processus quand on relâche le bouton "parler"
            else: # le bouton rec a déjà été pressé dans une autre boucle -> on ne fait rien
                print ("le bouton rec a déjà été pressé on ne fait rien car le flux audio est déjà en cours")
        else: # si etat du bouton absent = 1
            # On génère un son d'erreur pour prévenir que personne ne peut nous contacter
            os.system('pico2wave -l fr-FR -w 0.wav "Votre bouton, absent, est effoncé, il est impossible de communiquer." && aplay 0.wav && rm 0.wav')
    else: # si le "bouton parler" n'est pas pressé
        if etat_parler == 1: # le bouton rec n'était pas encore relâché -> on arrête l'enregistrement en tuant son processus
            etat_parler = 0 # on remet la variable à 0
            gpio.output(led_rec, gpio.LOW) # on éteint la led rec
            print ("Le bouton rec vient d'être relâché -> on tue les processus ayant comme nom: arecord")
            os.system('killall arecord')


    # Gestion bouton absent
    if(gpio.input(bouton_absent) == True): # si le "bouton absent" est pressé:
        if etat_parler == 0: # on check qu'on ne soie pas en train de parler (si c'est le cas on ne fait rien)
            if etat_absent == 0: # si on ne parle pas et on est pas deja absent
                print("Le bouton absent est enfoncé et on est pas en mode absent: etat_absent -> 1")
                etat_absent = 1 # on bascule l'état absent à 1
                # on envoie le fichier "absent-ce_terminal" sur tous les destinataires
                os.system('ssh pi@rasptalk-' + destinataire + ' "touch /home/pi/rasptalk/absent-' + ce_terminal + '"')
                gpio.output(led_absent, gpio.HIGH) # on allume la led absent
                time.sleep(0.8)
            else: # si on ne parle pas mais on est deja absent
                print("Le bouton absent est enfoncé mais on est deja en mode absent: etat_absent -> 0")
                etat_absent = 0 # on bascule l'état absent à 0
                os.system('ssh pi@rasptalk-' + destinataire + ' "rm /home/pi/rasptalk/absent-' + ce_terminal + '"')
                gpio.output(led_absent, gpio.LOW) # on éteint la led absent
                time.sleep(0.8)
        if etat_parler == 1: # on a enfoncé le bouton "absent" alors qu'on est déjà en train de parler
            print("On ne tient pas compte de l'enfoncement du bouton absent car le bouton parle est aussi pressé")


    # Gestion bouton buzzer
    if(gpio.input(bouton_buzzer) == False): # si le "bouton buzzer" est pressé:
        if etat_absent == 1: # si on est absent
            # On génère un son d'erreur pour prévenir que personne ne peut nous contacter
            os.system('pico2wave -l fr-FR -w 0.wav "Votre bouton, absent, est effoncé, il est impossible de communiquer." && aplay 0.wav && rm 0.wav')
        else: # si "bouton buzzer" est pressé et si on est pas "absent"
            # On génère un son avec le buzzer du correspondant en créant le fichier "sonne"
            os.system('ssh pi@rasptalk-' + destinataire + ' "touch /home/pi/rasptalk/sonne"')
            print("Le fichier sonne a été créé sur pi@rasptalk-" + destinataire + " pour faire sonner son buzzer")
            time.sleep(0.8)


    # Gestion bouton shutdown
    if(gpio.input(bouton_shutdown) == False): # si le "bouton shutdown" est pressé:
            print("Bouton shutdown -> au revoir!")
            # On génère un son de fin de programme
            os.system('pico2wave -l fr-FR -w 0.wav "Le système va séteindre. Attendez au moins 2 minute avant de retirer la prise." && aplay 0.wav && rm 0.wav')
            for i in range(0,4): # on fait cligoter 4x toutes les leds
                gpio.output(led_absent, gpio.LOW)
                gpio.output(led_parle, gpio.LOW)
                gpio.output(led_rec, gpio.LOW)
                gpio.output(led_posteA, gpio.LOW)
                gpio.output(led_posteB, gpio.LOW)
                gpio.output(led_posteC, gpio.LOW)
                time.sleep(0.4)
                gpio.output(led_absent, gpio.HIGH)
                gpio.output(led_parle, gpio.HIGH)
                gpio.output(led_rec, gpio.HIGH)
                gpio.output(led_posteA, gpio.HIGH)
                gpio.output(led_posteB, gpio.HIGH)
                gpio.output(led_posteC, gpio.HIGH)
                time.sleep(0.4)
            os.system('sudo shutdown -h now') # on éteint le système


    # Gestion fichier "sonne"
    if os.path.isfile("/home/pi/rasptalk/sonne"): # On check si on a reçu un fichier "sonne"
        print("Oh il y a un fichier 'sonne' -> on déclenche le buzzer")
        os.system('rm /home/pi/rasptalk/sonne') # on efface le fichier "sonne"
        gpio.output(le_buzzer, gpio.HIGH) # on allume le buzzer
        time.sleep(0.7)
        gpio.output(le_buzzer, gpio.LOW) # on l'éteint


    time.sleep(0.3)  # pour diminuer la charge CPU

Quand on enfonce le bouton « Parler » le programme ci-dessus lance le script ci-dessous, de cette façon la boucle infinie peut continuer et attendre le moment où l’on relâche le bouton et ainsi tuer le processus de ce 2ème script:

#!/usr/bin/python
# -*- coding: utf-8 -*-
'''
Quand on enfonce le bouton "parler" le programme principal lance ce script en arrière plan avec la commande:
os.system('sudo ./record-a.py &')

De cette façon, la boucle infinie du programme principal peut continuer et checker le moment où l'on relâche le bouton "parler" et à ce moment on tuera son processus avec la commande:
os.system('killall arecord')
'''
import os
os.system('if [ -f "/home/pi/rasptalk/absent-a" ]; then pico2wave -l fr-FR -w 0.wav "Le bouton, absent, est effoncé chez votre correspondant. Il est impossible de lui parler."; aplay 0.wav; rm 0.wav; else arecord -D plughw:1 -f dat | ssh -C pi@rasptalk-a aplay -f dat; fi')

 

Le schéma électronique

Cliquez pour agrandir

Configuration du système

On modifie les noms des raspberry en « rasptalk-a », « rasptalk-b », « rasptalk-c » …

sudo nano /etc/hostname -> modifier le nom 
puis dans sudo nano /etc/hosts -> idem tout en bas

Mise en place d’un certificat SSH

Pour pouvoir utiliser une connexion ssh sans avoir à entrer un mot de passe, nous allons créer un certificat sous forme de clef privée, clef publique.
S’il n’existe pas, créer le répertoire .ssh

mkdir $HOME/.ssh
 sudo chmod 700 $HOME/.ssh

Aller dans le répertoire .ssh

cd $HOME/.ssh

Nous allons générer nos clés, -b 4096 permet d’augmenter la sécurité de votre clé au lieu de 2096 par défaut, le -C « commentaire » servira à repérer la clef publique parmi d’autres dans le fichier ~/.ssh/authorized_keys que nous créerons plus tard sur le serveur.

ssh-keygen -b 4096 -C "pi@rasptalk-a"

La commande nous demande d’indiquer le nom du fichier dans lequel sauver les clefs:
On fait juste [ENTER] de sorte que la clef soie générée et placée dans le dossier .ssh/id_rsa
Puis on laisse la passphrase vide afin qu’il ne la demande pas
Nous voilà avec une clé privée (id_rsa) et une clé publique (id_rsa.pub)

La clé privée doit être gardée dans le répertoire .ssh et la publique est celle à mettre sur le serveur qui veut se connecter.

Il faut maintenant ajouter de la clé publique au fichier authorized_keys situé dans le dossier /home/user/.ssh du serveur:

cat id_rsa.pub | ssh <nom_utilisateur>@<adresse_ip> 'cat >> ~/.ssh/authorized_keys'

La ligne est ajoutée au fichier ~/.ssh/authorized_keys du serveur sous la forme: ssh-rsa <clé-cryptée> commentaire

On va finir avec la modification de la configuration du service SSH: (donc en local pas sur le serveur..)

sudo nano /etc/ssh/sshd_config

On dé-commente les lignes suivantes:

PubkeyAuthentication yes
RSAAuthentication yes
AuthorizedKeysFile %h/.ssh/authorized_keys

Maintenant une dernière chose, si on veut qu’un script exécuté par root puisse aussi utiliser la connexion ssh sans mot de passe:
On définit un mot de passe à l’administrateur du raspberry:

sudo passwd root

puis on se connecte en tant que root avec la commande:

su

Vérifiez que le dossier /root/.ssh existe (s’il n’existe pas: mkdir /root/.ssh)
Donnez-lui ces droits:

chmod 700 /root/.ssh

Puis retourner dans $HOME/.ssh

cd $HOME/.ssh

Envoyer les fichiers authorized_keys et id_rsa dans /root/.ssh

cp authorized_keys /root/.ssh
 cp id_rsa /root/.ssh

Enfin on redémarre ssh:

sudo service ssh restart

Un synthétiseur pour vocaliser les erreurs

Installation d’un synthétiseur vocal qui lit les erreurs, par exemple si le correspondant est éteint:

sudo apt-get install libttspico-utils

test de création du fichier .wav et lecture du fichier:

pico2wave -l fr-FR -w fichier.wav "Bienvenue en cette belle journée!"
aplay fichier.wav

Configuer le microphone

vérifier que le micro soit vu sur le port USB:

lsusb

qui donne genre: Bus 001 Device 008: ID 0d8c:0139 C-Media Electronics, Inc.

On peut vérifier que l’utilisateur pi soit bien dans le groupe audio:

groups pi

Sinon on l’ajoute avec:

sudo usermod -a -G audio pi

On va configurer le port du microphone et la carte audio:

alsamixer

qui donne un shéma de réglage, utiliser F6 pour sélectionner la carte son:
bcm2835 est le raspberry (pour la sortie jack & hdmi)
et pour l’entrée mic: USB PnP sound device avec comme numéro de la carte: 1
Maintenant sur le shéma on peut monter le son du HP et du mic au moins à 50%
Tout à droite on a le ctrl automatique du gain en pressant la touche M (moi je le laisse auto)
Enfin enregistrer ces paramètres:

sudo alsactl store 1

1 est le numéro de votre carte.
Pour tester l’enregistrement: un son de 4 secondes en 8 bit (venant du périphérique 1: -D plughw: 1) et on le lit avec aplay:

arecord -D plughw:1 -d 4 test.wav
 aplay test.wav

Voilà, une dernière petite chose à faire attention:
si vous utilisez comme moi un jack pour le son, on met la sortie audio du raspberry en analogique et non sur HDMI (bouton droit sur l’HP à coté de l’horloge)

Booter directement sur un disque dur

Moi personnellement j’ai utilisé un pidrive, mais il est possible d’utiliser un vieux disque dur ou même une clé USB, voici un bon tuto:
http://www.framboise314.fr/boot-simplifie-sur-usb-avec-les-raspberry-pi-1-2-et-3/

Conclusions

J’ai eu un immense plaisir à vous présenter ma réalisation sur le blog de la framboise314 et j’en profite pour remercier François pour son accueil en ces pages!

C’est fou comme une idée simple n’est jamais simple à mettre en oeuvre, mais qu’on fasse n’importe quel projet on apprend à chaque fois plein de choses 🙂

Sources

Cet article Interphone wifi multi-postes avec un Raspberry Pi a été publié en premier sur Framboise 314, le Raspberry Pi à la sauce française.....


Viewing all articles
Browse latest Browse all 1014

Trending Articles