Da qualche tempo posseggo un Raspberry Pi 3 B+ e lo utilizzo prevalentemente come console per Retro Gaming. Preso dalla voglia di un progetto serio, ho pensato di creare una telecamera di video sorveglianza statica (cioè fissa in un punto). Dopo alcune prove con la PI 3B+ ho deciso di comprare un kit Raspberry Pi Zero W, meno potente, più piccolo e con case più adatto.
Il kit del Raspberry PI 3 A+ e B+ contiene:
Il kit per Raspberry PI Zero W 1 o 2 contiene:
La camera è molto facile da montare comunque ci sono tantissimi video su Youtube.
Per il progetto ho utilizzato la classico e ottimo Raspberry Pi OS (per l'installazione vedere qui). Una volta portata a termine l'installazione del sistema operativo è necessario avviare il sistema, loggarci (utente pi password raspberry) attivare il supporto ssh e camera (per questi primi minuti ci servono un monitor e una tastiera) utilizzando il tool raspi-config:
sudo raspi-config
Prima di tutto cambiamo la password dell'utente (la default non è il massimo della sicurezza), quindi scelta 1. Dopo di che possiamo attivare SSH (scelta 5 -> 2) e la PiCamera (Scelta 5 -> 1) . Dalla serie mai tralasciare le cose ovvie, ci muoviamo con il tasto Tab e con le frecce.

Riportato di seguito lo script della documentazione ufficiale della PI Camera leggermente modificato da me medesimo. Ho aggiunto la possibilità di avviarlo senza usare il comando python3 (#!/bin/env python3 all'inizio), ho personalizzato il codice html della pagina, ho cambiato la risoluzione (sia in html che più sotto) e ho aggiunta metodo per la rotazione (#camera.rotation = 90 commentato ma attivabile alla bisogna). Potete copiare su un nuovo file il codice dello script, personalmente ho creato il file camera.py nella home dell'utente pi, quindi /home/pi/camera.py
#!/bin/env python3
import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server
PAGE="""\
<html>
<head>
<title>PiCamera Telecamera di sorveglianza </title>
</head>
<body>
<h1>PiCamera Telecamera di sorveglanza</h1>
<img src="stream.mjpg" width="800" height="600"/>
</body>
</html>
"""
class StreamingOutput(object):
def __init__(self):
self.frame = None
self.buffer = io.BytesIO()
self.condition = Condition()
def write(self, buf):
if buf.startswith(b'\xff\xd8'):
# New frame, copy the existing buffer's content and notify all
# clients it's available
self.buffer.truncate()
with self.condition:
self.frame = self.buffer.getvalue()
self.condition.notify_all()
self.buffer.seek(0)
return self.buffer.write(buf)
class StreamingHandler(server.BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/':
self.send_response(301)
self.send_header('Location', '/index.html')
self.end_headers()
elif self.path == '/index.html':
content = PAGE.encode('utf-8')
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.send_header('Content-Length', len(content))
self.end_headers()
self.wfile.write(content)
elif self.path == '/stream.mjpg':
self.send_response(200)
self.send_header('Age', 0)
self.send_header('Cache-Control', 'no-cache, private')
self.send_header('Pragma', 'no-cache')
self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
self.end_headers()
try:
while True:
with output.condition:
output.condition.wait()
frame = output.frame
self.wfile.write(b'--FRAME\r\n')
self.send_header('Content-Type', 'image/jpeg')
self.send_header('Content-Length', len(frame))
self.end_headers()
self.wfile.write(frame)
self.wfile.write(b'\r\n')
except Exception as e:
logging.warning(
'Removed streaming client %s: %s',
self.client_address, str(e))
else:
self.send_error(404)
self.end_headers()
class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
allow_reuse_address = True
daemon_threads = True
with picamera.PiCamera(resolution='800x600', framerate=24) as camera:
output = StreamingOutput()
#Uncomment the next line to change your Pi's Camera rotation (in degrees)
#camera.rotation = 90
camera.start_recording(output, format='mjpeg')
try:
address = ('', 8000)
server = StreamingServer(address, StreamingHandler)
server.serve_forever()
finally:
camera.stop_recording()
Lanciamo lo script e facciamolo partire in automatico
Per poter lanciare lo script dobbiamo dare prima di tutto i permessi di esecuzione al file che lo contiene:
chmod a+x /home/pi/camera.py
Essendo una telecamera di sorveglianza privata ma raggiungibile dall'esterno ho preferito non lasciare sempre lo script attivo. Quando necessito della telecamera mi collego via SSH al Raspberry facendo partire lo script. Per avviare automaticamente lo script al login è necessario inserire il comando seguente alla fine del file di configurazione .profile, presente nella home dell'utente pi (attenzione a non toccare altro, potreste compromettere il login):
/home/pi/camera.py >> log.txt 2>&1 &
Lo script parte in background (liberando cioè la shell) "sparando" ogni output (>> per lo standard output e 2>&1 per lo standard error) sul file log.txt. Per terminare lo script (e non lasciare trasmettere la telecamera quando non ci serve) è necessario terminare ogni istanza del processo python3. Per evitare di dimenticarcelo, lo facciamolo eseguire alla disconnessione della sessione, per farlo basta inserire la riga seguente alla fine del file /home/pi/.bash_logout:
killall python3
Lo script ha aperto un server Web sulla porta 8000 dove, utilizzando l'indirizzo IP associato alla nostra scheda, possiamo collegarci. Vediamo come reperire l'IP, se abbiamo collegato il Raspberry via cavo:
ifconfig eth0
o se siamo collegati via Wireless:
ifconfig wlan0
Alla voce inet troviamo un indirizzo che inizia con 192.168. (nel mio caso è 1.216). Usiamolo da un altro device (PC, Tablet, Smartphone, SmartTV o altro), connesso alla stessa rete per collegarci al Raspberry: nel browser inseriamo l'URL http://192.168.x.x:8000 (nel mio caso http://192.168.1.216:8000). Ecco il risultato:

Con pochi euro e tanto divertimento siamo riusciti a creare un ottimo servizio di sorveglianza in streaming.
Costo esiguo. Abbiamo una telecamera ma, visto che ci gira un sistema operativo completo, possiamo nel frattempo fargli fare di tutto.
La telecamera che ho acquistato non è il massimo (per 10 euro me l'aspettavo) quindi funziona perfettamente solo con una buona luce. Praticamente possono entrarmi in casa dopo le 16.30 da Novembre a Marzo.