/trunk/Server/config.py |
---|
2,3 → 2,6 |
motion_stream_port = 8081; |
enable_motion_detect = 1; |
enable_doorbell_listener = 1; |
/trunk/Server/daemon.py |
---|
10,8 → 10,10 |
import subprocess |
import config |
import threading |
import subprocess as sp |
g_subscribed = [] |
g_bellListenerProc = None |
class S(BaseHTTPRequestHandler): |
def _output(self, code, content): |
126,6 → 128,7 |
# --- |
global g_subscribed |
global g_bellListenerProc |
if pvget(postvars, "action")[0] == "client_subscribe": # 1.3.6.1.4.1.37476.2.4.1.1 |
client_ip = self.client_address[0] |
184,11 → 187,16 |
if pvget(postvars, "action")[0] == "motion_on": # 1.3.6.1.4.1.37476.2.4.1.100 |
print "Motion start" |
if config.enable_motion_detect: |
os.system(os.path.dirname(os.path.abspath(__file__)) + "/motion/motion_start_safe") |
if config.enable_doorbell_listener: |
g_bellListenerProc = sp.Popen(['python3',os.path.dirname(os.path.abspath(__file__)) + "/doorbell/bell_listener.py"]) |
if pvget(postvars, "action")[0] == "motion_off": # 1.3.6.1.4.1.37476.2.4.1.101 |
print "Motion stop" |
if config.enable_motion_detect: |
os.system(os.path.dirname(os.path.abspath(__file__)) + "/motion/motion_stop_safe") |
if config.enable_doorbell_listener: |
sp.Popen.terminate(g_bellListenerProc) |
self._output(200, '') |
/trunk/Server/doorbell/bell_listener.py |
---|
0,0 → 1,123 |
#!/usr/bin/env python3 |
# This script listens to the microphone and detects a doorbell that plays 2 sounds ("ding" "dong") |
# Please configure and adjust the script to your needings |
import pyaudio |
import wave |
import numpy as np |
import time |
import os |
CHUNK = 2*4096 # number of data points to read at a time |
RATE = 48000 # time resolution of the recording device (Hz) |
DEVICE = 1 # Webcam |
TARGET_FREQ_DING = 3232 # Hz, in AudaCity, select "Analyze > Spectrum" to find out the frequency of your doorbell |
TARGET_FREQ_DONG = 2781 # Hz |
DING_TRES = 1.5 |
DONG_TRES = 2.4 |
DING_DONG_INTERVAL = 4 # max seconds between "ding" and "dong" |
#SIMULATE_WAVEFILE = "test/doorbell_test.wav" |
SIMULATE_WAVEFILE = "" |
DEBUG = 2 |
# ------------------------------------------------------------- |
p = pyaudio.PyAudio() |
if SIMULATE_WAVEFILE == "": |
RATE = 48000 # TODO: read from hw-params |
DTYPE = np.int16 # TODO: read from hw-params? |
stream=p.open(format=pyaudio.paInt16,channels=1,rate=RATE,input=True, input_device_index=DEVICE, frames_per_buffer=CHUNK) |
else: |
wf = wave.open(SIMULATE_WAVEFILE, 'rb') |
DTYPE = np.int16 # TODO: read from wave file? |
RATE = wf.getframerate() |
col_target_ding = [] |
col_target_dong = [] |
col_other = [] |
last_detected_ding = 0 |
last_detected_dong = 0 |
max_intensity_ding = 0 |
max_intensity_dong = 0 |
while True: |
if SIMULATE_WAVEFILE == "": |
indata = np.fromstring(stream.read(CHUNK),dtype=DTYPE) |
else: |
d = wf.readframes(CHUNK) |
if len(d) == 0: |
break; |
indata = np.fromstring(d,dtype=DTYPE) |
fftData = np.fft.fft(indata) |
freqs = np.fft.fftfreq(fftData.size) |
magnitudes = fftData[1:int(fftData.size/2)] |
# Find out volume of target "ding" frequency |
idx = (np.abs(freqs-TARGET_FREQ_DING/RATE)).argmin() |
volume_target_ding = np.sum(np.abs(magnitudes[int(idx-1):int(idx+1)])) / 3 |
# Find out volume of target "dong" frequency |
idx = (np.abs(freqs-TARGET_FREQ_DONG/RATE)).argmin() |
volume_target_dong = np.sum(np.abs(magnitudes[int(idx-1):int(idx+1)])) / 3 |
# Find out the general volume |
volume_other = np.mean(np.abs(magnitudes)) |
#volume_other = np.median(np.abs(magnitudes)) |
# Filter peaks |
col_other.append(volume_other) |
while len(col_other) > 5: |
col_other.pop(0) |
volume_other = (np.sum(col_other) + 10*volume_other) / 15 |
col_target_ding.append(volume_target_ding) |
while len(col_target_ding) > 5: |
col_target_ding.pop(0) |
volume_target_ding = (np.sum(col_target_ding) + 10*volume_target_ding) / 15 |
col_target_dong.append(volume_target_dong) |
while len(col_target_dong) > 5: |
col_target_dong.pop(0) |
volume_target_dong = (np.sum(col_target_dong) + 10*volume_target_dong) / 15 |
# Debug |
if DEBUG > 1: |
print("Debug: DING", volume_target_ding/volume_other, "DONG", volume_target_dong/volume_other) |
# Check ratio |
if (volume_target_ding/volume_other > DING_TRES): |
if DEBUG > 0: |
print("Detected: DING with intensity {}>{}".format(volume_target_ding/volume_other,DING_TRES)) |
last_detected_ding = time.time() |
max_intensity_ding = max(max_intensity_ding, volume_target_ding/volume_other) |
if (volume_target_dong/volume_other > DONG_TRES): |
if DEBUG > 0: |
print("Detected: DONG with intensity {}>{}".format(volume_target_dong/volume_other,DONG_TRES)) |
last_detected_dong = time.time() |
max_intensity_dong = max(max_intensity_dong, volume_target_dong/volume_other) |
interval = last_detected_dong - last_detected_ding |
if (last_detected_ding > 0) and (last_detected_dong > 0) and (interval > 0) and (interval < DING_DONG_INTERVAL): |
if DEBUG > 0: |
print("Detected: DING DONG! with max intensity ding {} dong {}".format(max_intensity_ding, max_intensity_dong)) |
else: |
print("DING DONG!") |
os.system(os.path.dirname(os.path.abspath(__file__)) + "/detect.py") |
last_detected_ding = 0 |
last_detected_dong = 0 |
max_intensity_ding = 0 |
max_intensity_dong = 0 |
if SIMULATE_WAVEFILE == "": |
stream.close() |
p.terminate() |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/trunk/Server/doorbell/detect.d/client_alert |
---|
0,0 → 1,48 |
#!/usr/bin/php |
<?php |
# --- PLEASE MODIFY: |
# To which daemon server should the alarm be sent? |
$url = "http://127.0.0.1:8085"; |
# Which targets should be reported? |
$targets = array( |
"1.3.6.1.4.1.37476.2.4.2.0", // Any |
"1.3.6.1.4.1.37476.2.4.2.2001", // Sound, doorbell |
"1.3.6.1.4.1.37476.1.2.1.2" // PRIVATE: Doorbell of Daniel Marschall |
); |
# --- DON'T MODIFY AFTER THIS LINE |
$fields = array(); |
$fields[] = "action=server_alert"; // 1.3.6.1.4.1.37476.2.4.1.2 |
foreach ($targets as $target) { |
// Note: We are not using http_build_query(), because it sends targets[0]=...&targets[1]=..., |
// which is not what we need. We want targets=...&targets=... |
$fields[] = "targets=".urlencode($target); |
} |
$fields_string = implode('&', $fields); |
echo urldecode($fields_string)."\n"; |
$ch = curl_init(); |
curl_setopt($ch, CURLOPT_URL, $url); |
curl_setopt($ch, CURLOPT_POST, true); |
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string); |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
$result = curl_exec($ch); |
echo $result; |
// Note: We are not using Python to send the alert, because the "import" command is extremely |
// slow, and we need to send an alarm withhin milliseconds! |
/* |
import requests |
d = {"action": "server_alert", "targets": [ |
"...", |
"..." |
]} |
requests.post("http://127.0.0.1:8085", data=d) |
*/ |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/trunk/Server/doorbell/detect.d |
---|
Property changes: |
Added: svn:ignore |
+stop_spotify |
/trunk/Server/doorbell/detect.py |
---|
0,0 → 1,10 |
#!/usr/bin/env python3 |
import os |
dir=os.path.dirname(os.path.abspath(__file__)) + "/detect.d/" |
for root, dirs, files in os.walk(dir): |
for fname in files: |
os.system(dir + fname + " &") |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/trunk/Server/doorbell/test/doorbell_test.wav |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/trunk/Server/doorbell/test/freq_test.py |
---|
0,0 → 1,34 |
#!/usr/bin/env python3 |
import pyaudio |
import numpy as np |
CHUNK = 2*4096 # number of data points to read at a time |
RATE = 48000 # time resolution of the recording device (Hz) |
DEVICE = 1 # Webcam |
p = pyaudio.PyAudio() |
stream=p.open(format=pyaudio.paInt16,channels=1,rate=RATE,input=True, input_device_index=DEVICE, |
frames_per_buffer=CHUNK) |
while True: |
indata = np.fromstring(stream.read(CHUNK),dtype=np.int16) |
# Take the fft and square each value |
fftData=abs(np.fft.rfft(indata))**2 |
# find the maximum |
which = fftData[1:].argmax() + 1 |
# use quadratic interpolation around the max |
if which != len(fftData)-1: |
y0,y1,y2 = np.log(fftData[which-1:which+2:]) |
x1 = (y2 - y0) * .5 / (2 * y1 - y2 - y0) |
# find the frequency and output it |
thefreq = (which+x1)*RATE/CHUNK |
print("The freq is %f Hz." % (thefreq)) |
else: |
thefreq = which*RATE/CHUNK |
print("The freq is %f Hz." % (thefreq)) |
stream.close() |
p.terminate() |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/trunk/Server/doorbell/test/record.sh |
---|
0,0 → 1,3 |
#!/bin/bash |
arecord --device=plughw:1,0 --format S16_LE --rate 44100 -c1 /tmp/test.wav |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/trunk/Server/motion/motion_start_safe |
---|
11,5 → 11,7 |
system(escapeshellcmd(__DIR__.'/usbreset').' '.escapeshellarg("/dev/bus/usb/".$m[1]."/".$m[2])); |
} |
sleep(10); |
system("service motion start"); |