# 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.