Skip to content

Instantly share code, notes, and snippets.

@thoukydides
Last active June 30, 2021 21:15
Show Gist options
  • Save thoukydides/27eb6abd1bb84c78f2f9a4f0d9d111a2 to your computer and use it in GitHub Desktop.
Save thoukydides/27eb6abd1bb84c78f2f9a4f0d9d111a2 to your computer and use it in GitHub Desktop.
Low-latency button press and motion events for homebridge-skybell
# /etc/default/skybell-sniff
# Copyright © 2017 Alexander Thoukydides
# SkyBell HD doorbell hostname (or IP address) and name
SKYBELL_HOST=skybell
SKYBELL_NAME='Doorbell'
# Configuration for homebridge-skybell webhooks
HOMEBRIDGE_SKYBELL_PORT=47569
HOMEBRIDGE_SKYBELL_SECRET='My webhooks secret'
# Gateway/router hostname and ssh username
ROUTER_HOST=192.168.0.1
ROUTER_USER=root
# Command used to sniff the doorbell traffic
SKYBELL_CMD_TCPDUMP="ssh ${ROUTER_USER}@${ROUTER_HOST} \"/usr/sbin/tcpdump -lpnttti eth0 host ${SKYBELL_HOST} and port 5683\""
# Command executed when a button press or motion is detected
SKYBELL_CMD_MOTION="curl -d '{\"secret\":\"${HOMEBRIDGE_SKYBELL_SECRET}\",\"name\":\"${SKYBELL_NAME}\"}' http://localhost:${HOMEBRIDGE_SKYBELL_PORT}/homebridge-skybell/trigger/motion"
#!/usr/bin/perl
# Copyright © 2017 Alexander Thoukydides
use strict;
use warnings;
use Socket;
# Ensure that standard output is not buffered
$| = 1, select $_ for select STDOUT;
# Process the command line, substituting environment variables
die "$0 SKYBELL-HOST TCPDUMP-COMMAND MOTION-COMMAND\n" unless scalar @ARGV == 3;
foreach my $arg (@ARGV)
{
$arg =~ s/\$\{(\w+)}/$ENV{$1}/ge;
}
my ($skybell_host, $cmd_tcpdump, $cmd_motion) = @ARGV;
# Timeout (in seconds) to recognise a packet sequence
my $timeout = 10;
# Resolve hostname to a numeric IP address (since that is what tcpdump outputs)
my $skybell_ip_packed = gethostbyname($skybell_host)
or die "Failed to resolve $skybell_host: $!\n";
my $skybell_ip = inet_ntoa($skybell_ip_packed);
# Start monitoring the SkyBell HD CoAP traffic
open(my $pipe, '-|', $cmd_tcpdump)
or die "Failed to spawn '$cmd_tcpdump': $!\n";
# Monitor the SkyBell traffic
print "Monitoring SkyBell HD $skybell_host ($skybell_ip)\n";
my $state = 'idle';
my $time = 0;
while (<$pipe>)
{
# Parse the tcpdump output
if (!/(\d+):(\d+):(\d+.\d+) IP (\d+(?:\.\d+){3})\.\d+ > [\.\d]+: UDP, length (\d+)\s*$/)
{
print "Unexpected tcpdump format: $_";
next;
}
my $time_delta = (($1 *60) + $2) * 60 + $3;
my $from_skybell = $4 eq $skybell_ip;
my $length = $5 + 0;
#printf "%10.6f seconds %4d bytes %4s %s\n",
# $time_delta, $length, ($from_skybell ? 'from' : 'to'), $skybell_host;
# Check for a timeout from the start of the sequence
if ($state ne 'idle' and $timeout < ($time += $time_delta))
{
print "(Returning to idle)\n";
$state = 'idle';
$time = 0;
}
# Process the sniffed packet
if ($state eq 'idle')
{
if ($from_skybell and $length == 465)
{
print "(Possible motion detected)\n";
$state = 'armed';
}
elsif (not $from_skybell and 800 < $length)
{
print "On-demand requested\n";
$state = 'on-demand';
}
}
elsif ($state eq 'armed')
{
if(not $from_skybell and $length == 49)
{
print "Motion detected\n";
$state = 'motion';
system($cmd_motion) == 0
or warn "Failed to execute command: $?\n";
}
}
}
# Should never reach this point
die "tcpdump process died unexpectedly\n";
# /etc/systemd/system/skybell-sniff.service
# Copyright © 2017 Alexander Thoukydides
[Unit]
Description=SkyBell HD event detection
After=network-online.target
[Service]
Type=simple
User=root
EnvironmentFile=/etc/default/skybell-sniff
ExecStart=/usr/local/bin/skybell-sniff.pl ${SKYBELL_HOST} ${SKYBELL_CMD_TCPDUMP} ${SKYBELL_CMD_MOTION}
StandardOutput=journal
Restart=on-failure
RestartSec=10
KillMode=process
[Install]
WantedBy=multi-user.target
@jolaca01
Copy link

jolaca01 commented Feb 7, 2018

Hi, it seems that there's a new issue with Skybell binary_sensors. As some of you here really know what you're talking about, please take a look here:
home-assistant/core#11975
Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment