Telecamera di sorveglianza con Raspberry PI

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.

Hardware

Cosa serve 

Tutti i link riportati sotto sono sponsorizzati, cioè finanziano il sito con una percentuale sulle vendite (dal 3 al 10%).

Il kit del Raspberry PI 3 B+ contiene:

  • Raspberry PI 3 B+
  • alimentatore italia/usa scomodo e senza pulsante
  • scheda SD da 16 GB marchiata Raspberry (con il lampone fa la sua figura)
  • Cavo HDMI
  • Case (non molto adatto allo scopo, non c’è il buco per la telecamera, quindi telecamera fuori e tappo aperto)

Il kit per Raspberry PI Zero W contiene:

  • il minuscolo Raspberry PI Zero W
  • Pin GPIO da saldare sulla scheda (esiste una versione Zero WH con i PIN già saldati, tenetela in considerazione se avete in mente anche altri progetti)
  • Adattatore da MicroHDMI ad HDMI
  • Adattatore da MicroUSB a USB
  • Slitta mini per PiCamera (quindi prima di procedere al montaggio dovete sostituirla)
  • Case con 3 “tappi”: intero, apertura GPIO, foro centrale per Pi Camera

La camera è molto facile da montare comunque ci sono tantissimi video su Youtube.

Software

Sistema operativo

Per il progetto ho utilizzato la classica e ottima Raspbian (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.

sorveglianza_raspi-config

Script Python per gestire la telecamera e il server Web

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 copaire 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.pi

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

Colleghiamoci

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:

sorveglianza_attivata

Accedere dall’esterno

La nostra telecamera adesso funziona ma è raggiungibile solo dalla nostra rete locale. Abbiamo anche il problema che il suo indirizzo IP varia ad ogni accesso alla rete (il 99% dei router è configurato con DHCP). Dobbiamo quindi fissare l’indirizzo del nostro Raspberry e aprire le porte del nostro Router reindirizzando il traffico.

Configurazione del router

Ho preso come esempio il mio Router (uno Zixel, fornitomi dal mio ISP per la fibra) ma i passi da fare sono gli stessi per tutti i modelli. Per le opzioni da usare controllate il manuale utente del vostro dispositivo.

IP Statico 

Per poter configurare correttamente i passi successivi necessitiamo di configurare un DHCP statico. Con un DHCP statico il Router assegnerà ad ogni collegamento lo stesso IP al nostro Raspberry. Sul mio Router la configurazione è reperibile al menu’ Impostazione di rete -> Rete locale LAN -> DHCP Statico. Lo screenshot che segue viene dal manuale:

sorveglianza_dhcp_statico

La configurazione qui è molto semplice. Scegliamo fra i device collegati il Raspberry, così da compilare automaticamente il campo indirizzo MAC (il codice univoco che identifica ogni scheda di rete) e scegliamo l’indirizzo IP.

Configurazione NAT

Per poter accedere alla porta 8000 del nostro Raspberry da remoto dobbiamo abilitare il  Port Forwarding. Il mio Router permette di configurare il Port Forwarding dal menu’ Impostazioni di rete -> Nat. Anche in questo caso lo screenshot che segue viene dal manuale:

sorveglianza_router

 

Ho fatto due regole:

  • SSH (ho preferito cambiare la porta di default per SSH per incorrere in meno problemi di sicurezza)
    • Porta iniziale 2443 
    • Porta finale 2443
    • Porta di transazione iniziale 22
    • Porta di transazione finale 22
    • Indirizzo IP 192.168.1.216
    • Protocollo TCP/UDP (forse bastava solo TCP ma tanto cambia poco)
  • Videosorveglia (sulla falsariga della registrazione precedente ho messo una porta sequenziale)
    • Porta iniziale 2444
    • Porta finale 2444
    • Porta di transazione iniziale 8000
    • Porta di transazione finale 8000
    • Indirizzo IP 192.168.1.216
    • Protocollo TCP/UDP (idem come sopra)

Adesso possiamo collegarci anche utilizzando l’indirizzo pubblico della rete. L’indirizzo pubblico è reperibile su diversi siti specializzati, io ho usato ifconfig.me

IP dinamico? Creiamo un dominio DDNS

Anche l’IP della nostra connessione Internet cambia ogni volta che ci colleghiamo. Per poterci collegare da remoto dobbiamo sempre sapere l’IP, abbiamo alcune strade da percorrere:

  • richiedere al nostro ISP un carissimo IP statico;
  • configurare il nostro device in modo che ogni volta che si connette ad Internet ci invii un messaggio, una mail o un piccione, con il suo attuale IP esterno (reperibile con il comando curl ifconfig.me). Il metodo è ingegnoso ma crea una quantità esorbitante di spam (o di escrementi se si usa il piccione). 
  • iscriverci ad un sevizio gratuito (magari supportato dal nostro Router) che ad ogni connessione associa all’IP corrente un URL da noi scelto. Personalmente ho optato per questa soluzione.

Il mio Router può essere configurato per collegarsi periodicamente al servizio comunicando l’IP. Vediamo come con il solito screen dal manuale (menu’ Impostazioni di rete -> DNS ->Dynamic DNS).

sorveglianza_ddms

 

Il mio Router supporta una serie di servizi, anche gratuiti, valutate secondo le vostre necessità.

Conclusioni

Con pochi euro e tanto divertimento siamo riusciti a creare un ottimo servizio di sorveglianza in streaming.

Pregi 

Costo esiguo. Abbiamo una telecamera ma, visto che ci gira un sistema operativo completo, possiamo nel frattempo fargli fare di tutto.

Difetti

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.

Conclusioni 2

Il case per Raspberry PI Zero W è perfetto ma non ha, almeno visivamente, la possibilità di essere attaccato al muro. Ho optato per questa soluzione riutilizzando una vecchia cornice digitale non funzionante.

sorveglianza_creazione

Ho “incollato” il case con un semplice pasta adesiva modellabile (quella per i poster) rimovibile senza lasciare sporco e/o residui (l’ho comprata al supermercato il link è solo esemplificativo)

Fonte randomnerdtutorials.com
Fonte PiCamera Documentation

Autore dell'articolo: fabrizio

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *