Zoneminder SMTP Triggers

My CCTV server died recently, so I took the opportunity to try an alternative from my tried and trusted ZoneMinder installation, and looked to Shinobi.

For the most part it's great, it feels much more modern than ZoneMinder, it's architected in a way I prefer (nodejs and pm2 vs many monolithic perl scripts), and it's more user-friendly. However, I just couldn't get it to work reliably - it occasionally stopped recording, or recorded files of a single frame with a timestamp from hours ago etc, not great for CCTV so back to ZoneMinder...

One thing that Shiobi has built in is an SMTP trigger, allowing an eMail from the camera to trigger recording in Shinobi. ZoneMinder has a comprehensive trigger system, but doesn't support SMTP out of the box. This proved really useful as (especially on a low spec box) the Hikvision motion detection (and line crossing detection) is far better than trying to get an ancient linux box to do it.

Firstly you need to enable OPT_TRIGGERS in the ZoneMinder Options, and restart Zoneminder. You can check it's running with ps auxwf | grep zmtrigger and you should see /usr/bin/perl -wT /usr/bin/zmtrigger.pl as a running process.

By default this listens on port 6802 and awaits simple commands to trigger recording, so all we need to do is send a trigger on this port when we receive an eMail.

Which brings me to this quick and dirty little script, run under pm2 it creates a small SMTP server with one purpose, triggering zoneminder. (Someone else might find it useful)

#!/usr/local/bin/node
/*
 * Hikvision (and others) SMTP to ZoneMinder
 * ** NB This is a quick and dirty hack for INTERNAL networks
 * **    it should NOT be exposed to the public internet!
 *
 * http://rsmck.co.uk/blog/hikvision-zoneminder-smtp-triggers
 *
 */
const SMTPServer = require("smtp-server").SMTPServer;
const simpleParser = require('mailparser').simpleParser;
const net = require('net');

function zmtrigger(message) {
  var client = new net.Socket();
  client.connect(6802, '127.0.0.1', function() {
    client.write(message);
    client.end();
  });
  console.log(Date.now()+" ZM "+message);
}

const server = new SMTPServer({
  secure: false,
  disabledCommands: ['STARTTLS', 'AUTH'],
  authOptional: true,
  onData(stream, session, callback) {
    simpleParser(stream, {}, (err, parsed) => {
      var parts = parsed.to.value[0].address.split('@');
      var monitor = parts[0];
      var subject = parsed.subject.replace(/(.*): /,'');
      zmtrigger(monitor+'|on+90|10|External|'+subject+'|EXT');
      callback(null, "Message Queued");
    });
  }
 });

server.listen(25);

Then, in your Hikvision camera, simply set up SMTP as follows (no authentication, no encryption, just a receiver address of id@<anything> where the id the monitor ID in Zoneminder.

Click the Test button and shortly after you should find a recording in ZoneMinder with the cause as "External" and a description beneath it;

Now you can still use ZoneMinder for recording, but take advantage of some of Hikvision's own detection algorithms such as Motion Detection, Video Tampering, Intrusion Detection, Line Crossing Detection, ANPR/ALPR etc (where the camera supports it)