"Después del juego es antes del juego"
Sepp Herberger

domingo, 22 de mayo de 2016

Montemos una IP-Webcam barata - Reloaded I.

Esto es un sinfín. Reconozco que esta entrada y sus predecesoras han tenido mucho éxito gracias a la llegada de gente desde el estupendo foro de Openwrt de SeguridadWireless y, como tengo en producción el sistema desde que escribí el primer post, sigo con ello realizando retoques y mejoras con cierta frecuencia.

La último ha sido unos problemas derivados de la caída del servidor donde se almacenan las capturas. Como ya vimos es un servidor remoto desde el que montamos una carpeta por sshfs. He tenido diversos problemas con dicho servidor e inoportunas caídas del servicio. Los problemas detectados son:
  1. Cuando se interrumpe la conexión sshfs ya no se recupera hasta que se reinicia el router. Ese reinicio lo tengo programado una vez al día a medianoche.
  2. Si se interrumpe la conexión el guardado de las imágenes se hace en /mnt local, con lo cual los pocos megas de espacio de almacenamiento interno del router se llenan rápidamente y dejan el OpenWrt malfuncionando. Al reiniciar el router ese espacio se libera borrando las capturas.
  3. En general, las capturas hechas durante el tiempo que está el sshfs caído se pierden como lágrimas en la lluvia, ya que muchas veces no se llegan a enviar por problemas derivados del llenado del almacenamiento interno.
Para evitar estos problemas he implementado cambios orientados a detectar que no está montado el sshfs, intentar remontarlo y, si no se puede, adaptarnos a esta situación. En líneas generales:
  1. He ordenado un poco el código creando varias funciones, sacando al programita de los años 50 del siglo pasado.
  2. He creado un fichero local llamado /mnt/testigo que solo será visible si el sistema remoto no está montado por sshfs.
  3. Al principio pregunto si el sistema sshfs está montado y en caso negativo intento re-montarlo.
  4. Si no hay manera de remontarlo y no hay movimiento detectado, el fichero con la imagen *snapshot* no se almacena en la memoria interna: se borra.
  5. Si no hay manera de remontarlo y hay movimiento detectado, los ficheros con la secuencia son guardados en el espacio de almacenamiento interno de forma local y, cuando llegan a ser 10, empaquetados y enviados por correo, borrándose luego. El "10" es un número arbitrario que cada cual puede variar para ajustarlo a su espacio de almacenamiento
Y ya está, veamos el código:
# cat /root/controlador.sh 
#!/bin/ash

log() {
   test $montado -eq 1 && echo "$1" >> /mnt/snapshot/log.txt  
}

email() {
   test $email -eq 1 && echo -e "$1" | sendmail correo.aviso@gmail.com
}

monta_sshfs() {
  sshfs -o ssh_command="ssh -i /root/.ssh/id_rsa -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" -o nonempty openwrt@172.21.21.75:/home/openwrt /mnt
}

envia_secuencia() {

   if [ -e /tmp/motion.txt ]
   then

      #Recopila todos los ficheros de /tmp/motion/txt y los envia en un correo

      ficheros=$(cat /tmp/motion.txt | tr '\n' ' ')
      rm /tmp/motion.txt

      log "Historia de capturas $ficheros"
      zip -9 /mnt/escena.zip $ficheros

      echo "Secuencia $1" > /mnt/mensaje.txt
      test $email -eq 1 && mutt -s "Evento camara" correo.aviso@gmail.com -a /mnt/escena.zip < /mnt/mensaje.txt

      rm /mnt/escena.zip
      #Si no hay acceso al almacenamiento remoto, borramos las capturas para no llenar el disco del router.

      test $montado -eq 0 && rm -rf $destino

   fi

}

#Parametro 1: start, picture, end
#Parametro 2: fecha
#Parametro 3: nombre fichero (opcional)

#Obtenemos fecha y hora por si queremos poner algun filtro sobre ella y solo avisar en determinados
#momentos

time=$(date +%s)
anio=$(date +%Y @$time)
mes=$(date +%m @$time)
dia=$(date +%d @$time)
hora=$(date +%H @$time)
minuto=$(date +%M @$time)
diasemana=$(date +%u @$time) #El 1 es lunes
destino="/mnt/snapshot/$anio-$mes-$dia"
montado=1
email==0

if [ $diasemana -ge 6 -o $hora -le 7 -o $hora -ge 17 ]  # sabado/domingo o cualquier dia antes de las 8:00 o despues de las 17:00
then
   email=1
fi

#Si existe el fichero /mnt/testigo no se ha montado directorio remoto por sshfs,
#Intentamos montarlo y otra vez y luego preguntamos de nuevo.
#Si no se ha montado nada es que no se puede guardar nada de forma permanente ya que estamos escribiendo en la
#memoria interna del router y eso se llena rapido

test -e /mnt/testigo && monta_sshfs

if test -e /mnt/testigo
then
   montado=0
   #No hay almacenamiento organizado por dias, no vamos a guardar tanto tiempo el fichero.
   destino="/mnt/snapshot"
fi

test -d $destino || mkdir -p $destino

case $1 in

   "start")
        log "Detectado inicio de movimiento $2" 
        email "Subject: Evento camara\r\n\r\nDetectado inicio de movimiento $2"
        #El fichero motion.txt tiene dos finalidades: 1) testigo para indicar que estamos detectando movimiento 
        #                                             2) guarda los nombres de los ficheros de captura de las fotos
        touch /tmp/motion.txt
        ;;
   "picture")
        fichero=$(basename $3)
        log "Guardando imagen $2 : $destino/$fichero" 
     
        #Si estamos en una ráfaga de movimiento detectado, guardamos el nombre de fichero con la foto.
        test -e /tmp/motion.txt && echo "$destino/$fichero" >> /tmp/motion.txt

        #Se guarda el fichero en el almacenamiento destino
        mv "$3" "$destino/$fichero"
  
        #Si no está montado el almacenamiento remoto y vemos que llevamos mas de 10 imagenes en
        #movimiento tenemos que borrarlas y enviarlas ya mismo, para no saturar el espacio.
        if [ $montado -eq 0 ]
        then
           #Si estamos en una ráfaga de movimiento detectado....
           if [ -e /tmp/motion.txt ]
           then
              lineas=$(wc -l /tmp/motion.txt | cut -d" " -f1)
              test $lineas -gt 10 && envia_secuencia $2
           else
              #Si no lo estamos, es una captura *snapshot* regular sin interés, la borramos.
              rm -f "$destino/$fichero"
           fi  
        fi
        ;;
   "end") 
        log "Detectado fin de movimiento $2"
        envia_secuencia $2
        ;;
    *) log "Evento $1"
esac


#Borra fichero "sent" creado por sendmail si existe, para liberar espacio
rm -rf /root/sent
rm -rf /sent

exit 0
Por otro lado, el fichero /etc/rc.local se modifica para crear el fichero /mnt/testigo en el arranque.
# cat /etc/rc.local 
# Put your custom commands here that should be executed once
# the system init finished. By default this file does nothing.

sleep 40

#Desmontamos /mnt por si acaso
umount /mnt

#Borramos /mnt/snapshot local si tuviera algo
rm -rf /mnt/snapshot

#Creamos testigo para detectar que no se ha montado el almacen remoto
touch /mnt/testigo

#Montamos almacen remoto por sshfs
sshfs -o ssh_command="ssh -i /root/.ssh/id_rsa -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" -o nonempty openwrt@172.19.231.4:/home/openwrt /mnt

exit 0
Bueno, pues esto quedá asi hasta el siguiente ciclo de mejoras.

No hay comentarios:

Publicar un comentario