# list usb devices
sudo usermod -a -G audio utilisateur1
sudo apt-get  install alsa-base alsa-utils  #  alsa-base est déjà la version la plus récente
apt install v4l-utils
v4l2-ctl --all  # show webcams
v4l2-ctl --all | grep "Pixel Format"
#== Pixel Format      : 'YUYV' (YUYV 4:2:2)

amixer info
#== Card default 'b1'/'bcm2835 HDMI 1'
#== Mixer name	: 'Broadcom Mixer'
#== Components	: ''
#== Controls      : 2
#== Simple ctrls  : 1

amixer -D pulse set Master toggle  # toggle sound on/off
amixer -D pulse set Master 100% unmute

arecord -l      # show microphones (so here we can access to **plughw:2,0**)
arecord -l
#== **** Liste des Périphériques Matériels CAPTURE ****
#== carte 2: Silver [Classic Silver], périphérique 0: USB Audio [USB Audio]
#== Sous-périphériques: 1/1
#== Sous-périphérique #0: subdevice #0
#== This means that the built-in microphone is located on hardware 1, periph 0

arecord -L  # show audio devices
#== null
#== default
#== jack
#== pulse
#== usbstream:CARD=b1
#== usbstream:CARD=Headphones
#== hw:CARD=Silver,DEV=0
#== plughw:CARD=Silver,DEV=0
#== sysdefault:CARD=Silver
#== front:CARD=Silver,DEV=0
#== dsnoop:CARD=Silver,DEV=0
#== usbstream:CARD=Silver

arecord -D plughw:2,0 test.wav 
#== Capture WAVE 'test.wav' : Signed 16 bit Little Endian, Fréquence 8000 Hz, Mono
arecord --device=hw:2,0 --format S16_LE --rate 44100 -c1 test.wav -V mono
#== Capture WAVE 'test.wav' Mono

# show audio devices
cat /proc/asound/cards
#==  0 [b1             ]: bcm2835_hdmi - bcm2835 HDMI 1
#==  1 [Headphones     ]: bcm2835_headpho - bcm2835 Headphones
#==  2 [Silver         ]: USB-Audio - Classic Silver
#==                       Guillemot Corporation Classic Silver at usb-0000:01:00.0-1.2, high speed

usb-devices | grep Product
#== S:  Product=xHCI Host Controller
#== S:  Product=USB2.0 Hub
#== S:  Product=Classic Silver
#== S:  Product=USB Receiver
#== S:  Product=xHCI Host Controller  
      
# pactl list | grep alsa.card_name
#== alsa.card_name = "bcm2835 HDMI 1"
#== alsa.card_name = "bcm2835 Headphones"
#== alsa.card_name = "Classic Silver"

#== Store the settings so that they persist on reboot.
sudo alsactl store
#== list devices
v4l2-ctl --list-devices
#== list formats for each device
v4l2-ctl --list-formats-ext

#== list device capabilities
ffmpeg -f v4l2 -list_formats all -i /dev/video0
[video4linux2,v4l2 @ 0xaaaaf383c060] Raw:     yuyv422:           YUYV 4:2:2 : 640x480 352x288 320x240 176x144 160x120

#== simple encode for 30 seconds
ffmpeg -f v4l2 -framerate 25 -video_size 320x240 -i /dev/video0 -t 00:00:30 output.mkv

#== take a picture
ffmpeg -f v4l2 -video_size 1280x720 -i /dev/video0 -frames 1 out.jpg
ffmpeg -f v4l2 -video_size 640x480 -i /dev/video0 -frames 1 out.jpg
fswebcam -d v4l2:/dev/video0 -r 640x480 --jpeg 85 -D 1 --no-banner  webcam.jpg
cvlc v4l2:///dev/video0:chroma=h264 :input-slave=alsa://hw:1,0 --sout '#transcode{acodec=mpga,ab=128,channels=2,samplerate=44100,threads=4,audio-sync=1}:standard{access=http,mux=ts,mime=video/ts,dst=:8080}'

# Send mp3 via UDP 
cvlc test.mp3  --sout=udp://192.168.1.12:1234
# Receive UDP 
cvlc udp://@0.0.0.0:1234

# get webcam image
vlc -vvv avcapture://         # on macos
vlc -vvv v4l2:///dev/video0   # on linux

# record audio flux for 10 seconds
vlc test.mp3 --sout "#duplicate{dst=std{access=file,mux=raw,dst=OUT.mp3}" --stop-time 10 vlc://quit

# 
vlc http://<ip_address_of_webcam_host>:8080/stream.wmv

cvlc v4l2:///dev/video0 :v4l2-standard= :input-slave=alsa://hw:0,0 :live-caching=300 :sout="#transcode{vcodec=WMV2, vb=800, scale=1, acodec=wma2, ab=128, channels=2, samplerate=44100}:http{dst=:8080/stream.wmv}"

  # example
  # envoyer le son de la webcam à dest.local:1234
  ffmpeg -re -f alsa -i plughw:2,0 -acodec libmp3lame  -ar 11025  -f rtp  rtp://dest.local:1234
  # recevoir le son sur le port 1234
  ffplay rtp://192.168.1.1:1234

ffplay -f alsa -i plughw:2,0 -acodec pcm_s16le -ac 1 -ar 96000


#############
# User Parameters
#############

# Doorbell pin
DOORBELL_PIN = 26
# Number of seconds to keep the call active
DOORBELL_SCREEN_ACTIVE_S = 60
# ID of the JITSI meeting room
JITSI_ID = None  # If None, the program generates a random UUID
# JITSI_ID = "hackershackdoorbellexample"
# Path to the SFX file
RING_SFX_PATH = None  # If None, no sound effect plays
# RING_SFX_PATH = "/home/pi/ring.wav"
# Enables email notifications
ENABLE_EMAIL = False
# Email you want to send the notification from (only works with gmail)
FROM_EMAIL = 'sender@gmail.com'
# You can generate an app password here to avoid storing your password in plain text
# this should also come from an environment variable
# https://support.google.com/accounts/answer/185833?hl=en
FROM_EMAIL_PASSWORD = 'password'
# Email you want to send the update to
TO_EMAIL = 'receiver@gmail.com'


#############
# Program
#############

import time
import os
import signal
import subprocess
import smtplib
import uuid

from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage

try:
    import RPi.GPIO as GPIO
except RuntimeError:
    print("Error importing RPi.GPIO. This is probably because you need superuser. Try running again with 'sudo'.")


def show_screen():
    os.system("tvservice -p")
    os.system("xset dpms force on")


def hide_screen():
    os.system("tvservice -o")


def send_email_notification(chat_url):
    if ENABLE_EMAIL:
        sender = EmailSender(FROM_EMAIL, FROM_EMAIL_PASSWORD)
        email = Email(
            sender,
            'Video Doorbell',
            'Notification: A visitor is waiting',
            'A video doorbell caller is waiting on the virtual meeting room. Meet them at %s' % chat_url
        )
        email.send(TO_EMAIL)


def ring_doorbell(pin):
    SoundEffect(RING_SFX_PATH).play()

    chat_id = JITSI_ID if JITSI_ID else str(uuid.uuid4())
    video_chat = VideoChat(chat_id)
    send_email_notification(video_chat.get_chat_url())
   
    show_screen()

    video_chat.start()
    time.sleep(DOORBELL_SCREEN_ACTIVE_S)
    video_chat.end()

    hide_screen()


class SoundEffect:
    def __init__(self, filepath):
        self.filepath = filepath

    def play(self):
        if self.filepath:
            subprocess.Popen(["aplay", self.filepath])


class VideoChat:
    def __init__(self, chat_id):
        self.chat_id = chat_id
        self._process = None

    def get_chat_url(self):
        return "http://meet.jit.si/%s" % self.chat_id

    def start(self):
        if not self._process and self.chat_id:
            self._process = subprocess.Popen(["chromium-browser", "-kiosk", self.get_chat_url()])
        else:
            print("Can't start video chat -- already started or missing chat id")

    def end(self):
        if self._process:
            os.kill(self._process.pid, signal.SIGTERM)


class EmailSender:
    def __init__(self, email, password):
        self.email = email
        self.password = password


class Email:
    def __init__(self, sender, subject, preamble, body):
        self.sender = sender
        self.subject = subject
        self.preamble = preamble
        self.body = body

    def send(self, to_email):
        msgRoot = MIMEMultipart('related')
        msgRoot['Subject'] = self.subject
        msgRoot['From'] = self.sender.email
        msgRoot['To'] = to_email
        msgRoot.preamble = self.preamble

        msgAlternative = MIMEMultipart('alternative')
        msgRoot.attach(msgAlternative)
        msgText = MIMEText(self.body)
        msgAlternative.attach(msgText)

        smtp = smtplib.SMTP('smtp.gmail.com', 587)
        smtp.starttls()
        smtp.login(self.sender.email, self.sender.password)
        smtp.sendmail(self.sender.email, to_email, msgRoot.as_string())
        smtp.quit()


class Doorbell:
    def __init__(self, doorbell_button_pin):
        self._doorbell_button_pin = doorbell_button_pin

    def run(self):
        try:
            print("Starting Doorbell...")
            hide_screen()
            self._setup_gpio()
            print("Waiting for doorbell rings...")
            self._wait_forever()

        except KeyboardInterrupt:
            print("Safely shutting down...")

        finally:
            self._cleanup()

    def _wait_forever(self):
        while True:
            time.sleep(0.1)

    def _setup_gpio(self):
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(self._doorbell_button_pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
        GPIO.add_event_detect(self._doorbell_button_pin, GPIO.RISING, callback=ring_doorbell, bouncetime=2000)

    def _cleanup(self):
        GPIO.cleanup(self._doorbell_button_pin)
        show_screen()


if __name__ == "__main__":
    doorbell = Doorbell(DOORBELL_PIN)
    doorbell.run()

# Smart-Doorbell
A wifi-connected raspberry pi doorbell with video chat

Github repository for the Smart Doorbell Hackershack video

This project was run on a Raspberry Pi 3 with Raspbian Buster. The video call wasn't as smooth as I would've liked, so it would probably be better to run this on a Pi 4. However, I haven't run this on the Pi 4, so I can't guarantee that it works.

## Instructions

###  Enable the Camera

Enable the camera with raspi-config

In the terminal, type:

```
sudo raspi-config
```

Navigate to `Interfacing Options`

Navigate to `camera`

Select `yes` and reboot

Test that the camera is working by running the following command in the terminal to save an image to your home directory

```
sudo raspistill -o test.jpg
```

### Enable the Microphone

Open the sound input settings

```
alsamixer -c l
```

Press `F4` to open the capture settings and bump the level up to 100. Press `Esc` to exit.

Test the audio capture with the following command:

```
arecord --device=hw:1,0 --format S16_LE --rate 44100 -c1 test.wav -V mono
```

press `control-c` to stop. It will generate a audio file in your local directory called `test.wav`

You can play the file with

```
aplay test.wav
```

Store the settings so that they persist on reboot

```
sudo alsactl store
```

### Enable Video Calls

Visit [Jitsi Meet](https://meet.jit.si/) and configure the site to use your camera/microphone

My settings were:

```
Camera: mmal service 16.1
Microphone: USB PnP Sound Device, USB Audio-Default Audio Device
```

### Download the Code

I navigated to the repo from my Raspberry Pi in the browser and clicked "Download Zip". I extracted the package to my home directory and them moved the doorbell.py file to `/home/pi/doorbell.py`.

You can test that the program works by running

```
python doorbell.py
```

from `/home/pi`.

To edit the file, install vim and open the file

```
apt-get install vim

vim doorbell.py
```

press, `i` to enter edit mode then make your changes. To exit, press `esc` then upper-case `ZZ` to save.

The variables for the code are documented at the top. Feel free to change any of these for your program. 

### Rotate the Screen

Open the boot.txt file with vim

```
sudo vim /boot/config.txt
```

press `i` to enter insert mode then add a line

```
display_rotate=1
```

press `esc` then `ZZ` to save and exit. Reboot.


### Start the Program on Boot

Create a autostart directory

```
mkdir /home/pi/.config/autostart
```

Create a file to run the doorbell program

```
vim /home/pi/.config/autostart/doorbell.desktop
```

press `i`, then add the following to the file

```
[Desktop Entry]
Type=Application
Name=Doorbell
Exec=python /home/pi/doorbell
```

press `esc` and `ZZ` to save and exit.

*WARNING: This will make your local display unusable. Make sure you have a way to connect to the pi through VNC or SSH to remove this file if you want to stop the program from starting at boot.

Reboot.

If you have any issues getting the doorbell to start, please leave an issue on this repository and the community will help you get it working.


  • perso/broadcast.txt
  • Dernière modification : 2021/11/22 15:49
  • de 127.0.0.1