Skip to content

Record video when alarm is ringing

Thomas T. Jarløv edited this page Oct 7, 2018 · 2 revisions

The tutorial below uses an external Raspberry Pi - not the one where NimHA is running.

Main features

  • Power to the camera is disabled when it's not recording to enhance privacy
  • When the alarm is ringing, the camera will record and save to user specified folder

Requirements

  • mosquitto_sub
  • ffmpeg
  • USB camera (optional with microphone)

Identify inputs

You need to find the input for both video and audio (optional).

Video

ls -ltrh /dev/video*

The result could be /dev/video0 if you only have 1 camera device.

Audio

arecord -l

Output

**** List of CAPTURE Hardware Devices ****
card 1: CameraB409241 [USB Camera-B4.09.24.1], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Grab the identifier, in this case CameraB409241

USB power control

To enhance privacy you can turn of the power supply when it's not used.

USB port

Firstly you have to find your USB port - this could 1-1.4. But it is also possible to turn off all USB ports (and ethernet) when just defining 1-1.

for device in $(ls /sys/bus/usb/devices/*/product); do echo $device;cat $device;done

Output

/sys/bus/usb/devices/1-1.4/product
USB Camera-B4.09.24.1
/sys/bus/usb/devices/usb1/product
DWC OTG Controller

On/Off scripts

mkdir /home/pi/nimha/usbcontrol

Off script

nano /home/pi/nimha/usbcontrol/usboff.sh
# insert
echo '1-1' |sudo tee /sys/bus/usb/drivers/usb/unbind
# run
chmod +x /home/pi/nimha/usbcontrol/usboff.sh
sudo chown root:root /home/pi/nimha/usbcontrol/usboff.sh

On script

nano /home/pi/nimha/usbcontrol/usbon.sh
# insert
echo '1-1' |sudo tee /sys/bus/usb/drivers/usb/bind
# run
chmod +x /home/pi/nimha/usbcontrol/usbon.sh
sudo chown root:root /home/pi/nimha/usbcontrol/usbon.sh

service file

When starting the main program (below) through systemctl, it can be tricky due to the need for root access to turn the USB on and off. Either edit sudo visudo or run the service file with systemctl with user as root (take care).

FFMPEG command

The ffmpeg command needs to be adjusted to your input video, input audio and output folder.

ffmpeg is called within Nim. Edit:

ffmpeg = startProcess("ffmpeg -timelimit 900 -f video4linux2 -framerate 25 -video_size 640x480 -i /dev/video0 -f alsa -i plughw:CameraB409241,0 -ar 22050 -ab 64k -strict experimental -acodec aac -vcodec mpeg4 -vb 20M -y /mnt/nimha/media/" & filename & ".mp4", options = {poEvalCommand})

Nim program

This helper program needs to executed on the RPi. You should make it is as a service and enable it on boot.

import asyncdispatch
import json
import os
import osproc
import strutils
import streams
import times


var ffmpeg: Process
var usbOn = true

template jn*(json: JsonNode, data: string): string =
  ## Avoid error in parsing JSON
  try:
    json[data].getStr()
  except:
    ""


proc mqttParser(payload: string) {.async.} =
  ## Parse the raw output from Mosquitto sub
  ## and start action

  let topicName = payload.split(" ")[0]
  let message   = parseJson(payload.replace(topicName & " ", ""))
  
  let status = jn(message, "status")

  if status == "ringing":
    if not usbOn:
      discard execCmd("/home/pi/nimha/usbcontrol/usbon.sh")
      usbOn = true
      sleep(6000) # Waiting time for camera to initialize
    let filename = multiReplace($getTime(), [(":", "-"), ("+", "_"), ("T", "_")])
    ffmpeg = startProcess("ffmpeg -timelimit 900 -f video4linux2 -framerate 25 -video_size 640x480 -i /dev/video1 -f alsa -i plughw:CameraB409241,0 -ar 22050 -ab 64k -strict experimental -acodec aac -vcodec mpeg4 -vb 20M -y /mnt/nimha/media/" & filename & ".mp4", options = {poEvalCommand})

  elif status in ["disarmed", "armAway", "armHome"]:
    if usbOn:
      discard execCmd("/home/pi/nimha/usbcontrol/usboff.sh")
      usbOn = off



let s_mqttPathSub   = "/usr/bin/mosquitto_sub"
let s_mqttPassword  = "secretPassword"
let s_clientName    = "secretUsername"
let s_mqttIp        = "ip"
let s_mqttPort      = "8883"
let s_topic         = "alarminfo"

proc mosquittoSub() =
  var mqttProcess = startProcess(s_mqttPathSub & " -v -t " & s_topic & " -u " & s_clientName & " -P " & s_mqttPassword & " -h " & s_mqttIp & " -p " & s_mqttPort, options = {poEvalCommand})

  while running(mqttProcess):
    asyncCheck mqttParser(readLine(outputStream(mqttProcess)))


mosquittoSub()
quit()