mirror of https://github.com/billw2/pikrellcam.git
motion_detects_fifo for reading all motion detects.
V 4.2.0 ~/pikrellcam/www/motion_detects_fifo can be read to get all motion detects regardless of motion videos enabled state. Moved Setup->Config->Times/* and Setup->Settings->Startup_Motion to Setup->Config->Motion
This commit is contained in:
parent
0172d45cce
commit
1e970587b8
|
@ -1,6 +1,7 @@
|
||||||
scripts
|
scripts
|
||||||
www/.htpasswd
|
www/.htpasswd
|
||||||
www/FIFO
|
www/FIFO
|
||||||
|
www/motion_events_FIFO
|
||||||
www/audio_FIFO
|
www/audio_FIFO
|
||||||
www/media
|
www/media
|
||||||
www/config-user*
|
www/config-user*
|
||||||
|
|
BIN
pikrellcam
BIN
pikrellcam
Binary file not shown.
|
@ -0,0 +1,100 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# tab-width: 4
|
||||||
|
|
||||||
|
# This is an example of an external script that will read all motion detects
|
||||||
|
# from PiKrellCam whether or not motion videos are enabled.
|
||||||
|
#
|
||||||
|
# Use it a starting point for a motion detect front end application that is
|
||||||
|
# independent of motion video enabled state.
|
||||||
|
#
|
||||||
|
# Run this script from a terminal on a Pi running PiKrellCam and watch for
|
||||||
|
# motion detects to be printed.
|
||||||
|
#
|
||||||
|
# This script can be terminated with a terminal ^C or by sending an "off"
|
||||||
|
# command to PiKrellCam:
|
||||||
|
# echo "motion_detects_fifo_enable off" > /home/pi/pikrellcam/www/FIFO
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import signal
|
||||||
|
import fcntl
|
||||||
|
import atexit
|
||||||
|
import select
|
||||||
|
import StringIO
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
# Turn on pikrellcam motion detects writing to the motion_detects_FIFO
|
||||||
|
#
|
||||||
|
os.system('echo "motion_detects_fifo_enable on" > /home/pi/pikrellcam/www/FIFO')
|
||||||
|
|
||||||
|
# If ^C interrupted, send "off" to the command FIFO
|
||||||
|
# If external program sends "off", then this script will get an <off> tag
|
||||||
|
# read from the motion_detects_FIFO and exit.
|
||||||
|
#
|
||||||
|
def signal_handler(signum, frame):
|
||||||
|
print ' Turning off motion_detects_fifo_enable'
|
||||||
|
os.system('echo "motion_detects_fifo_enable off" > /home/pi/pikrellcam/www/FIFO')
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
|
|
||||||
|
|
||||||
|
motion_detects_FIFO = '/home/pi/pikrellcam/www/motion_detects_FIFO'
|
||||||
|
detects_fifo = os.open(motion_detects_FIFO, os.O_RDONLY | os.O_NONBLOCK)
|
||||||
|
|
||||||
|
bufferSize = 1024
|
||||||
|
state = 'wait'
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# Wait until there is data to read from the fifo. May be multiple lines.
|
||||||
|
#
|
||||||
|
select.select([detects_fifo],[],[detects_fifo])
|
||||||
|
data = os.read(detects_fifo, bufferSize)
|
||||||
|
|
||||||
|
# Split the data into lines and process motion type lines between
|
||||||
|
# <motion>...</motion> tags
|
||||||
|
# If a motion detect has external or audio, there may not be a frame vector.
|
||||||
|
# A motion detect with actual motion always has an overall 'f' frame vector.
|
||||||
|
# If there is an 'f' frame vector, there can also be one or more region
|
||||||
|
# vectors only, or a burst vector only, or both burst and one or more
|
||||||
|
# region vectors. If you care only about overall frame motion, look
|
||||||
|
# for 'f' frame vectors.
|
||||||
|
#
|
||||||
|
lines = StringIO.StringIO(data)
|
||||||
|
for line in lines.readlines():
|
||||||
|
line = line.strip('\n')
|
||||||
|
print "FIFO read: " + line
|
||||||
|
|
||||||
|
# If some program sends a "motion_detects_fifo_enable off" to the
|
||||||
|
# command FIFO, an <off> tag will be written to the motion_detects_FIFO.
|
||||||
|
#
|
||||||
|
if (line.find('<off>') == 0):
|
||||||
|
print " detected motion_detects_fifo_enable off - exiting."
|
||||||
|
sys.exit(1)
|
||||||
|
elif (line.find('<motion') == 0):
|
||||||
|
state = 'motion'
|
||||||
|
# <motion t > where t is system time with .1 second precision
|
||||||
|
m, t, b = line.split()
|
||||||
|
print " motion detected - system time " + t + " => " + time.asctime( time.localtime( int(float(t)) ) )
|
||||||
|
elif (line.find('</motion>') == 0):
|
||||||
|
print ""
|
||||||
|
state = 'wait'
|
||||||
|
elif (state == 'motion'):
|
||||||
|
if (line[0] == "f"):
|
||||||
|
r, x, y, dx, dy, mag, count = line.split()
|
||||||
|
print " motion vector - frame:" + " mag=" + mag + " count=" + count
|
||||||
|
elif (line[0].isdigit()):
|
||||||
|
r, x, y, dx, dy, mag, count = line.split()
|
||||||
|
print " motion vector - region " + line[0] + ": mag=" + mag + " count=" + count
|
||||||
|
elif (line[0] == "b"):
|
||||||
|
b, count = line.split()
|
||||||
|
print " burst detect - count=" + count
|
||||||
|
elif (line[0] == "e"):
|
||||||
|
e, code = line.split()
|
||||||
|
print " external trigger - code: " + code
|
||||||
|
elif (line[0] == "a"):
|
||||||
|
a, level = line.split()
|
||||||
|
print " audio trigger - level=" + level
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* PiKrellCam
|
/* PiKrellCam
|
||||||
|
|
|
|
||||||
| Copyright (C) 2015-2017 Bill Wilson billw@gkrellm.net
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
|
||||||
|
|
|
|
||||||
| PiKrellCam is free software: you can redistribute it and/or modify it
|
| PiKrellCam is free software: you can redistribute it and/or modify it
|
||||||
| under the terms of the GNU General Public License as published by
|
| under the terms of the GNU General Public License as published by
|
||||||
|
|
45
src/config.c
45
src/config.c
|
@ -1,6 +1,6 @@
|
||||||
/* PiKrellCam
|
/* PiKrellCam
|
||||||
|
|
|
|
||||||
| Copyright (C) 2015-2017 Bill Wilson billw@gkrellm.net
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
|
||||||
|
|
|
|
||||||
| PiKrellCam is free software: you can redistribute it and/or modify it
|
| PiKrellCam is free software: you can redistribute it and/or modify it
|
||||||
| under the terms of the GNU General Public License as published by
|
| under the terms of the GNU General Public License as published by
|
||||||
|
@ -303,6 +303,7 @@ rotation_control_set(char *option, char *setting)
|
||||||
MMAL_STATUS_T status = MMAL_EINVAL;
|
MMAL_STATUS_T status = MMAL_EINVAL;
|
||||||
|
|
||||||
value = ((value % 360 ) / 90) * 90;
|
value = ((value % 360 ) / 90) * 90;
|
||||||
|
pikrellcam.rotation_value = value;
|
||||||
for (i = 0; i < MAX_CAMERA_PORTS; ++i)
|
for (i = 0; i < MAX_CAMERA_PORTS; ++i)
|
||||||
{
|
{
|
||||||
status = mmal_port_parameter_set_int32(camera.component->output[i],
|
status = mmal_port_parameter_set_int32(camera.component->output[i],
|
||||||
|
@ -604,6 +605,18 @@ static Config config[] =
|
||||||
"#",
|
"#",
|
||||||
"loop_diskusage_percent", "30", FALSE, {.value = &pikrellcam.loop_diskusage_percent}, config_value_int_set},
|
"loop_diskusage_percent", "30", FALSE, {.value = &pikrellcam.loop_diskusage_percent}, config_value_int_set},
|
||||||
|
|
||||||
|
#ifdef MOTION_STILLS
|
||||||
|
{ "\n# -------------------- Motion Still Recording -----------------------\n"
|
||||||
|
"# Take still images instead of recording videos when motion is enabled.\n"
|
||||||
|
"#",
|
||||||
|
"motion_stills_enable", "off", FALSE, {.value = &pikrellcam.motion_stills_enable}, config_value_bool_set},
|
||||||
|
|
||||||
|
{ "# Motion still images per minute range from 1 to 60 which gives a\n"
|
||||||
|
"# max rate range of 1 per minute to 1 per second.\n"
|
||||||
|
"# Stills are taken at motion detects separated by at least this rate.\n"
|
||||||
|
"#",
|
||||||
|
"motion_stills_per_minute", "30", TRUE, {.value = &pikrellcam.motion_stills_per_minute}, config_value_int_set },
|
||||||
|
#endif
|
||||||
|
|
||||||
{ "\n# -------------------- Motion Detect Options -----------------------\n"
|
{ "\n# -------------------- Motion Detect Options -----------------------\n"
|
||||||
"# PiKrellCam V3.0 stores some motion detect settings in preset-xxx.conf\n"
|
"# PiKrellCam V3.0 stores some motion detect settings in preset-xxx.conf\n"
|
||||||
|
@ -657,7 +670,7 @@ static Config config[] =
|
||||||
"motion_pre_capture", "5", TRUE, {.value = &pikrellcam.motion_times.pre_capture}, config_value_int_set },
|
"motion_pre_capture", "5", TRUE, {.value = &pikrellcam.motion_times.pre_capture}, config_value_int_set },
|
||||||
|
|
||||||
{ "# Seconds of video that will be recorded after the last motion event.\n"
|
{ "# Seconds of video that will be recorded after the last motion event.\n"
|
||||||
"# motion_post_caputure must be <= motion_event_gap.\n"
|
"# motion_post_capture must be <= motion_event_gap.\n"
|
||||||
"#",
|
"#",
|
||||||
"motion_post_capture", "5", TRUE, {.value = &pikrellcam.motion_times.post_capture}, config_value_int_set },
|
"motion_post_capture", "5", TRUE, {.value = &pikrellcam.motion_times.post_capture}, config_value_int_set },
|
||||||
|
|
||||||
|
@ -745,6 +758,12 @@ static Config config[] =
|
||||||
"#",
|
"#",
|
||||||
"motion_stats", "off", FALSE, {.value = &pikrellcam.motion_stats}, config_value_bool_set },
|
"motion_stats", "off", FALSE, {.value = &pikrellcam.motion_stats}, config_value_bool_set },
|
||||||
|
|
||||||
|
{ "# Enable writing all motion detects to ~/pikrellcam/www/motion_detects_fifo\n"
|
||||||
|
"# Motion detects are written regardless of motion videos enabled state,\n"
|
||||||
|
"# so this provides a front end motion detect function for another app.\n"
|
||||||
|
"#",
|
||||||
|
"motion_detects_fifo_enable", "off", FALSE, {.value = &pikrellcam.motion_detects_fifo_enable}, config_value_bool_set },
|
||||||
|
|
||||||
{ "# Command/script to run when receiving a user defined multicast\n"
|
{ "# Command/script to run when receiving a user defined multicast\n"
|
||||||
"# pkc-message sent by other PiKrellCams or separate scripts on your LAN.\n"
|
"# pkc-message sent by other PiKrellCams or separate scripts on your LAN.\n"
|
||||||
"# Use this to run a script needing PiKrellCam variables passed to it,\n"
|
"# Use this to run a script needing PiKrellCam variables passed to it,\n"
|
||||||
|
@ -1203,6 +1222,8 @@ config_set_defaults(char *home_dir)
|
||||||
|
|
||||||
pikrellcam.version = strdup(PIKRELLCAM_VERSION);
|
pikrellcam.version = strdup(PIKRELLCAM_VERSION);
|
||||||
pikrellcam.timelapse_format = strdup("tl_$n_$N.jpg");
|
pikrellcam.timelapse_format = strdup("tl_$n_$N.jpg");
|
||||||
|
pikrellcam.motion_stills_name_format = strdup("motion_%F_%H.%M.%S_$N.jpg");
|
||||||
|
|
||||||
pikrellcam.preview_pathname = strdup("");
|
pikrellcam.preview_pathname = strdup("");
|
||||||
pikrellcam.thumb_name = strdup("");
|
pikrellcam.thumb_name = strdup("");
|
||||||
pikrellcam.multicast_group_IP = "225.0.0.55";
|
pikrellcam.multicast_group_IP = "225.0.0.55";
|
||||||
|
@ -1290,6 +1311,11 @@ config_load(char *config_file)
|
||||||
)
|
)
|
||||||
pikrellcam.motion_record_time_limit = 10;
|
pikrellcam.motion_record_time_limit = 10;
|
||||||
|
|
||||||
|
if (pikrellcam.motion_stills_per_minute > 60)
|
||||||
|
pikrellcam.motion_stills_per_minute = 60;
|
||||||
|
else if (pikrellcam.motion_stills_per_minute < 1)
|
||||||
|
pikrellcam.motion_stills_per_minute = 1;
|
||||||
|
|
||||||
if (pikrellcam.diskfree_percent < 5)
|
if (pikrellcam.diskfree_percent < 5)
|
||||||
pikrellcam.diskfree_percent = 5;
|
pikrellcam.diskfree_percent = 5;
|
||||||
if (pikrellcam.loop_diskusage_percent < 5)
|
if (pikrellcam.loop_diskusage_percent < 5)
|
||||||
|
@ -1357,6 +1383,21 @@ config_load(char *config_file)
|
||||||
|
|
||||||
if (pikrellcam.config_sequence_new != pikrellcam.config_sequence)
|
if (pikrellcam.config_sequence_new != pikrellcam.config_sequence)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
|
if ( pikellcam.config_sequence <= 45
|
||||||
|
&& ( pikrellcam.rotation_value == 90
|
||||||
|
|| pikrellcam.rotation_value == 270
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
n = pikrellcam.video_width;
|
||||||
|
pikrellcam.video_width = pikrellcam.video_height;
|
||||||
|
pikrellcam.video_height = n;
|
||||||
|
n = pikrellcam.still_width;
|
||||||
|
pikrellcam.still_width = pikrellcam.still_height;
|
||||||
|
pikrellcam.still_height = n;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
pikrellcam.config_sequence = pikrellcam.config_sequence_new;
|
pikrellcam.config_sequence = pikrellcam.config_sequence_new;
|
||||||
pikrellcam.config_modified = TRUE;
|
pikrellcam.config_modified = TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* PiKrellCam
|
/* PiKrellCam
|
||||||
|
|
|
|
||||||
| Copyright (C) 2015-2016 Bill Wilson billw@gkrellm.net
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
|
||||||
|
|
|
|
||||||
| PiKrellCam is free software: you can redistribute it and/or modify it
|
| PiKrellCam is free software: you can redistribute it and/or modify it
|
||||||
| under the terms of the GNU General Public License as published by
|
| under the terms of the GNU General Public License as published by
|
||||||
|
@ -50,7 +50,7 @@ MotionTimes motion_times_temp;
|
||||||
#define IMAGE_EFFECT 16
|
#define IMAGE_EFFECT 16
|
||||||
#define MOTION_LIMIT 17
|
#define MOTION_LIMIT 17
|
||||||
#define SETTINGS 18
|
#define SETTINGS 18
|
||||||
#define MOTION_TIME 19
|
#define MOTION_SETTINGS 19
|
||||||
#define SERVO_SETTINGS 20
|
#define SERVO_SETTINGS 20
|
||||||
#define LOOP_SETTINGS 21
|
#define LOOP_SETTINGS 21
|
||||||
#define AUDIO_SETTINGS 22
|
#define AUDIO_SETTINGS 22
|
||||||
|
@ -70,7 +70,7 @@ static DisplayCommand display_commands[] =
|
||||||
{ ">", RIGHT_ARROW },
|
{ ">", RIGHT_ARROW },
|
||||||
{ ">>", REPEAT_RIGHT_ARROW },
|
{ ">>", REPEAT_RIGHT_ARROW },
|
||||||
{ "back", BACK },
|
{ "back", BACK },
|
||||||
{ "motion_time", MOTION_TIME },
|
{ "motion_settings", MOTION_SETTINGS },
|
||||||
{ "motion_limit", MOTION_LIMIT },
|
{ "motion_limit", MOTION_LIMIT },
|
||||||
{ "video_presets", VIDEO_PRESET },
|
{ "video_presets", VIDEO_PRESET },
|
||||||
{ "still_presets", STILL_PRESET },
|
{ "still_presets", STILL_PRESET },
|
||||||
|
@ -607,7 +607,7 @@ motion_draw(uint8_t *i420)
|
||||||
MotionRegion *mreg;
|
MotionRegion *mreg;
|
||||||
CompositeVector *vec;
|
CompositeVector *vec;
|
||||||
SList *mrlist;
|
SList *mrlist;
|
||||||
char *msg, info[100], status[100];
|
char *msg, *fifo_msg, info[100], status[100];
|
||||||
int16_t color; /* just B&W */
|
int16_t color; /* just B&W */
|
||||||
int i, x, y, dx, dy, r, r_unit;
|
int i, x, y, dx, dy, r, r_unit;
|
||||||
int t_record, t_hold;
|
int t_record, t_hold;
|
||||||
|
@ -627,6 +627,7 @@ motion_draw(uint8_t *i420)
|
||||||
JUSTIFY_RIGHT(0), "Vectors: ON");
|
JUSTIFY_RIGHT(0), "Vectors: ON");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fifo_msg = "";
|
||||||
if (!inform_shown && (mf->show_preset || pikrellcam.preset_notify))
|
if (!inform_shown && (mf->show_preset || pikrellcam.preset_notify))
|
||||||
{
|
{
|
||||||
for (mrlist = mf->motion_region_list; mrlist; mrlist = mrlist->next)
|
for (mrlist = mf->motion_region_list; mrlist; mrlist = mrlist->next)
|
||||||
|
@ -707,6 +708,9 @@ motion_draw(uint8_t *i420)
|
||||||
|
|
||||||
if (pikrellcam.on_preset && !pikrellcam.preset_notify)
|
if (pikrellcam.on_preset && !pikrellcam.preset_notify)
|
||||||
{
|
{
|
||||||
|
if (pikrellcam.motion_detects_fifo_enable)
|
||||||
|
fifo_msg = "Motion FIFO ON ";
|
||||||
|
|
||||||
if (mf->frame_window > 0 && mf->motion_status == MOTION_NONE)
|
if (mf->frame_window > 0 && mf->motion_status == MOTION_NONE)
|
||||||
{
|
{
|
||||||
snprintf(status, sizeof(status), "confirming[%d]", mf->frame_window);
|
snprintf(status, sizeof(status), "confirming[%d]", mf->frame_window);
|
||||||
|
@ -735,16 +739,19 @@ motion_draw(uint8_t *i420)
|
||||||
if (pikrellcam.motion_show_counts)
|
if (pikrellcam.motion_show_counts)
|
||||||
{
|
{
|
||||||
snprintf(info, sizeof(info),
|
snprintf(info, sizeof(info),
|
||||||
"any:%-3d(%.1f) rej:%-3d spkl:%-3d(%.1f) %s",
|
"%sany:%-3d(%.1f) rej:%-3d spkl:%-3d(%.1f) %s",
|
||||||
mf->any_count, mf->any_count_expma,
|
fifo_msg, mf->any_count, mf->any_count_expma,
|
||||||
mf->reject_count, mf->sparkle_count, mf->sparkle_expma,
|
mf->reject_count, mf->sparkle_count, mf->sparkle_expma,
|
||||||
status);
|
status);
|
||||||
i420_print(&bottom_status_area, normal_font, 0xff, 0, 0, 0,
|
i420_print(&bottom_status_area, normal_font, 0xff, 0, 0, 0,
|
||||||
JUSTIFY_LEFT, info);
|
JUSTIFY_LEFT, info);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
snprintf(info, sizeof(info), "%s%s", fifo_msg, status);
|
||||||
i420_print(&bottom_status_area, normal_font, 0xff, 0, 0, 0,
|
i420_print(&bottom_status_area, normal_font, 0xff, 0, 0, 0,
|
||||||
JUSTIFY_LEFT, status);
|
JUSTIFY_LEFT, info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -779,7 +786,7 @@ motion_draw(uint8_t *i420)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
t_hold = pikrellcam.motion_times.event_gap -
|
t_hold = pikrellcam.motion_times.event_gap -
|
||||||
(pikrellcam.t_now - vcb->motion_last_detect_time);
|
(pikrellcam.t_now - pikrellcam.motion_last_detect_time);
|
||||||
snprintf(info, sizeof(info), "REC (%s) %d:%02d hold %d:%02d",
|
snprintf(info, sizeof(info), "REC (%s) %d:%02d hold %d:%02d",
|
||||||
pikrellcam.external_motion ?
|
pikrellcam.external_motion ?
|
||||||
(mf->fifo_detects ? mf->fifo_trigger_code : "Audio")
|
(mf->fifo_detects ? mf->fifo_trigger_code : "Audio")
|
||||||
|
@ -825,6 +832,10 @@ motion_draw(uint8_t *i420)
|
||||||
i420_print(&bottom_status_area, normal_font, 0xff, 1, 1, 0,
|
i420_print(&bottom_status_area, normal_font, 0xff, 1, 1, 0,
|
||||||
JUSTIFY_LEFT, msg);
|
JUSTIFY_LEFT, msg);
|
||||||
|
|
||||||
|
if (pikrellcam.motion_detects_fifo_enable && !*fifo_msg)
|
||||||
|
i420_print(&bottom_status_area, normal_font, 0xff, 0, 1, 0,
|
||||||
|
JUSTIFY_LEFT, "Motion FIFO ON");
|
||||||
|
|
||||||
if (time_lapse.show_status)
|
if (time_lapse.show_status)
|
||||||
{
|
{
|
||||||
int p = time_lapse.period,
|
int p = time_lapse.period,
|
||||||
|
@ -923,8 +934,8 @@ static int menu_white_balance_index;
|
||||||
static SList *menu_image_effect_list;
|
static SList *menu_image_effect_list;
|
||||||
static int menu_image_effect_index;
|
static int menu_image_effect_index;
|
||||||
|
|
||||||
static SList *menu_motion_time_list;
|
static SList *menu_motion_settings_list;
|
||||||
static int menu_motion_time_index;
|
static int menu_motion_settings_index;
|
||||||
|
|
||||||
static SList *menu_motion_limit_list;
|
static SList *menu_motion_limit_list;
|
||||||
static int menu_motion_limit_index;
|
static int menu_motion_limit_index;
|
||||||
|
@ -1092,17 +1103,24 @@ static Adjustment picture_adjustment[] =
|
||||||
/* Adjustment changes made to a temp struct to avoid thrashing malloc/free
|
/* Adjustment changes made to a temp struct to avoid thrashing malloc/free
|
||||||
| of huge circular buffer. Final change is applied if/when SEL is clicked.
|
| of huge circular buffer. Final change is applied if/when SEL is clicked.
|
||||||
*/
|
*/
|
||||||
Adjustment motion_time_adjustment[] =
|
Adjustment motion_settings_adjustment[] =
|
||||||
{
|
{
|
||||||
|
{ "Startup_Motion", 0, 1, 1, 0, 0, 0, "", NULL, &pikrellcam.startup_motion_enable },
|
||||||
{ "Confirm_Gap", 0, 30, 1, 0, 0, 0, "", NULL, &motion_times_temp.confirm_gap },
|
{ "Confirm_Gap", 0, 30, 1, 0, 0, 0, "", NULL, &motion_times_temp.confirm_gap },
|
||||||
{ "Pre_Capture", 1, 180, 1, 0, 0, 0, "", NULL, &motion_times_temp.pre_capture },
|
{ "Pre_Capture", 1, 180, 1, 0, 0, 0, "", NULL, &motion_times_temp.pre_capture },
|
||||||
{ "Event_Gap", 1, 300, 1, 0, 0, 0, "", NULL, &motion_times_temp.event_gap },
|
{ "Event_Gap", 1, 300, 1, 0, 0, 0, "", NULL, &motion_times_temp.event_gap },
|
||||||
{ "Post_Capture", 1, 180, 1, 0, 0, 0, "", NULL, &motion_times_temp.post_capture },
|
{ "Post_Capture", 1, 180, 1, 0, 0, 0, "", NULL, &motion_times_temp.post_capture },
|
||||||
{ "Motion_Time_Limit", 0, 1800, 10, 0, 0, 0, "sec", NULL, &pikrellcam.motion_record_time_limit }
|
{ "Video_Time_Limit", 0, 1800, 10, 0, 0, 0, "sec", NULL, &pikrellcam.motion_record_time_limit }
|
||||||
|
|
||||||
|
// XXX
|
||||||
|
#ifdef MOTION_STILLS
|
||||||
|
{ "Motion_Stills_(no_videos)", 0, 1, 1, 0, 0, 0, "", NULL, &pikrellcam.motion_stills_enable },
|
||||||
|
{ "Max_Stills_per_Minute", 1, 60, 1, 0, 0, 0, "", NULL, &pikrellcam.motion_stills_per_minute}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define N_MOTION_TIME_ADJUSTMENTS \
|
#define N_MOTION_SETTINGS_ADJUSTMENTS \
|
||||||
(sizeof(motion_time_adjustment) / sizeof(Adjustment))
|
(sizeof(motion_settings_adjustment) / sizeof(Adjustment))
|
||||||
|
|
||||||
Adjustment motion_limit_adjustment[] =
|
Adjustment motion_limit_adjustment[] =
|
||||||
{
|
{
|
||||||
|
@ -1121,7 +1139,6 @@ Adjustment motion_limit_adjustment[] =
|
||||||
*/
|
*/
|
||||||
Adjustment settings_adjustment[] =
|
Adjustment settings_adjustment[] =
|
||||||
{
|
{
|
||||||
{ "Startup_Motion", 0, 1, 1, 0, 0, 0, "", NULL, &pikrellcam.startup_motion_enable },
|
|
||||||
// { "Vertical_Filter", 0, 1, 1, 0, 0, 0, "", NULL, &pikrellcam.motion_vertical_filter },
|
// { "Vertical_Filter", 0, 1, 1, 0, 0, 0, "", NULL, &pikrellcam.motion_vertical_filter },
|
||||||
{ "Check_Media_Diskfree", 0, 1, 1, 0, 0, 0, "", NULL, &pikrellcam.check_media_diskfree },
|
{ "Check_Media_Diskfree", 0, 1, 1, 0, 0, 0, "", NULL, &pikrellcam.check_media_diskfree },
|
||||||
{ "Check_Archive_Diskfree", 0, 1, 1, 0, 0, 0, "", NULL, &pikrellcam.check_archive_diskfree },
|
{ "Check_Archive_Diskfree", 0, 1, 1, 0, 0, 0, "", NULL, &pikrellcam.check_archive_diskfree },
|
||||||
|
@ -1241,7 +1258,7 @@ apply_adjustment(void)
|
||||||
|
|
||||||
if (!adjustments || !cur_adj)
|
if (!adjustments || !cur_adj)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (adjustments == &motion_time_adjustment[0])
|
if (adjustments == &motion_settings_adjustment[0])
|
||||||
{
|
{
|
||||||
pikrellcam.motion_times.confirm_gap = motion_times_temp.confirm_gap;
|
pikrellcam.motion_times.confirm_gap = motion_times_temp.confirm_gap;
|
||||||
pikrellcam.motion_times.post_capture = motion_times_temp.post_capture;
|
pikrellcam.motion_times.post_capture = motion_times_temp.post_capture;
|
||||||
|
@ -1549,10 +1566,14 @@ display_adjustment(uint8_t *i420)
|
||||||
|
|
||||||
if (boolean_flag)
|
if (boolean_flag)
|
||||||
snprintf(buf, sizeof(buf), "%s", cur_adj->value ? "ON" : "OFF");
|
snprintf(buf, sizeof(buf), "%s", cur_adj->value ? "ON" : "OFF");
|
||||||
|
else if ( adjustments == &motion_settings_adjustment[0]
|
||||||
|
&& cur_adj->value == 0
|
||||||
|
)
|
||||||
|
snprintf(buf, sizeof(buf), "OFF");
|
||||||
else
|
else
|
||||||
snprintf(buf, sizeof(buf), "%d", cur_adj->value);
|
snprintf(buf, sizeof(buf), "%d", cur_adj->value);
|
||||||
i420_print(da, font, 0xff, 0, adj_x, 0, JUSTIFY_CENTER_AT_X, buf);
|
|
||||||
|
|
||||||
|
i420_print(da, font, 0xff, 0, adj_x, 0, JUSTIFY_CENTER_AT_X, buf);
|
||||||
i420_print(da, font, 0xff, 2, 0, 0, JUSTIFY_CENTER, cur_adj->name);
|
i420_print(da, font, 0xff, 2, 0, 0, JUSTIFY_CENTER, cur_adj->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1579,9 +1600,9 @@ display_draw_menu(uint8_t *i420)
|
||||||
adjustments = &motion_limit_adjustment[0];
|
adjustments = &motion_limit_adjustment[0];
|
||||||
cur_adj_start = TRUE;
|
cur_adj_start = TRUE;
|
||||||
break;
|
break;
|
||||||
case MOTION_TIME:
|
case MOTION_SETTINGS:
|
||||||
display_state = DISPLAY_ADJUSTMENT;
|
display_state = DISPLAY_ADJUSTMENT;
|
||||||
adjustments = &motion_time_adjustment[0];
|
adjustments = &motion_settings_adjustment[0];
|
||||||
cur_adj_start = TRUE;
|
cur_adj_start = TRUE;
|
||||||
break;
|
break;
|
||||||
case SETTINGS:
|
case SETTINGS:
|
||||||
|
@ -1783,11 +1804,11 @@ display_command(char *cmd)
|
||||||
display_menu = DISPLAY_MENU_NONE;
|
display_menu = DISPLAY_MENU_NONE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MOTION_TIME:
|
case MOTION_SETTINGS:
|
||||||
display_menu_list = menu_motion_time_list;
|
display_menu_list = menu_motion_settings_list;
|
||||||
display_menu_index = &menu_motion_time_index;
|
display_menu_index = &menu_motion_settings_index;
|
||||||
display_state = DISPLAY_MENU;
|
display_state = DISPLAY_MENU;
|
||||||
display_menu = MOTION_TIME;
|
display_menu = MOTION_SETTINGS;
|
||||||
break;
|
break;
|
||||||
case MOTION_LIMIT:
|
case MOTION_LIMIT:
|
||||||
display_menu_list = menu_motion_limit_list;
|
display_menu_list = menu_motion_limit_list;
|
||||||
|
@ -2117,17 +2138,17 @@ display_init(void)
|
||||||
bottom_status_area.x0, bottom_status_area.y0,
|
bottom_status_area.x0, bottom_status_area.y0,
|
||||||
bottom_status_area.width, bottom_status_area.height);
|
bottom_status_area.width, bottom_status_area.height);
|
||||||
}
|
}
|
||||||
if (!menu_motion_time_list)
|
if (!menu_motion_settings_list)
|
||||||
{
|
{
|
||||||
for (i = 0, position = 0; i < N_MOTION_TIME_ADJUSTMENTS; ++i)
|
for (i = 0, position = 0; i < N_MOTION_SETTINGS_ADJUSTMENTS; ++i)
|
||||||
{
|
{
|
||||||
adj = &motion_time_adjustment[i];
|
adj = &motion_settings_adjustment[i];
|
||||||
entry = calloc(1, sizeof(MenuEntry));
|
entry = calloc(1, sizeof(MenuEntry));
|
||||||
entry->name = adj->name;
|
entry->name = adj->name;
|
||||||
entry->length = strlen(entry->name);
|
entry->length = strlen(entry->name);
|
||||||
entry->line_position = position;
|
entry->line_position = position;
|
||||||
position += entry->length + 1;
|
position += entry->length + 1;
|
||||||
menu_motion_time_list = slist_append(menu_motion_time_list, entry);
|
menu_motion_settings_list = slist_append(menu_motion_settings_list, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!menu_motion_limit_list)
|
if (!menu_motion_limit_list)
|
||||||
|
|
40
src/event.c
40
src/event.c
|
@ -1,6 +1,6 @@
|
||||||
/* PiKrellCam
|
/* PiKrellCam
|
||||||
|
|
|
|
||||||
| Copyright (C) 2015-2017 Bill Wilson billw@gkrellm.net
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
|
||||||
|
|
|
|
||||||
| PiKrellCam is free software: you can redistribute it and/or modify it
|
| PiKrellCam is free software: you can redistribute it and/or modify it
|
||||||
| under the terms of the GNU General Public License as published by
|
| under the terms of the GNU General Public License as published by
|
||||||
|
@ -123,6 +123,9 @@ expand_command(char *command, char *arg)
|
||||||
case 't':
|
case 't':
|
||||||
fmt_arg = pikrellcam.thumb_dir;
|
fmt_arg = pikrellcam.thumb_dir;
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
fmt_arg = pikrellcam.motion_record_mode;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'T':
|
case 'T':
|
||||||
snprintf(buf, sizeof(buf), "%d", time_lapse.period);
|
snprintf(buf, sizeof(buf), "%d", time_lapse.period);
|
||||||
|
@ -398,6 +401,20 @@ event_still_capture_cmd(char *cmd)
|
||||||
exec_wait(cmd, NULL);
|
exec_wait(cmd, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_motion_still_capture(void *t)
|
||||||
|
{
|
||||||
|
time_t motion_time = (time_t) t;
|
||||||
|
char *path, buf[50];
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "%d", pikrellcam.motion_stills_sequence++);
|
||||||
|
path = media_pathname(pikrellcam.still_dir,
|
||||||
|
pikrellcam.motion_stills_name_format, motion_time,
|
||||||
|
'N', buf, 'H', pikrellcam.hostname);
|
||||||
|
still_capture(path, motion_time);
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
|
||||||
static boolean
|
static boolean
|
||||||
diskfree_is_low(char *dir)
|
diskfree_is_low(char *dir)
|
||||||
{
|
{
|
||||||
|
@ -772,6 +789,12 @@ state_file_write(void)
|
||||||
f = fopen(fname_part, "w");
|
f = fopen(fname_part, "w");
|
||||||
|
|
||||||
fprintf(f, "motion_enable %s\n", mf->motion_enable ? "on" : "off");
|
fprintf(f, "motion_enable %s\n", mf->motion_enable ? "on" : "off");
|
||||||
|
|
||||||
|
#ifdef MOTION_STILLS
|
||||||
|
fprintf(f, "motion_stills_enable %s\n",
|
||||||
|
pikrellcam.motion_stills_enable ? "on" : "off");
|
||||||
|
#endif
|
||||||
|
|
||||||
fprintf(f, "show_preset %s\n", mf->show_preset ? "on" : "off");
|
fprintf(f, "show_preset %s\n", mf->show_preset ? "on" : "off");
|
||||||
fprintf(f, "show_vectors %s\n", mf->show_vectors ? "on" : "off");
|
fprintf(f, "show_vectors %s\n", mf->show_vectors ? "on" : "off");
|
||||||
|
|
||||||
|
@ -814,6 +837,15 @@ state_file_write(void)
|
||||||
state = "stop";
|
state = "stop";
|
||||||
fprintf(f, "video_record_state %s\n", state);
|
fprintf(f, "video_record_state %s\n", state);
|
||||||
|
|
||||||
|
if (vcb->state & VCB_STATE_MOTION_RECORD)
|
||||||
|
state = "video";
|
||||||
|
else if (pikrellcam.motion_stills_record)
|
||||||
|
state = "stills";
|
||||||
|
else
|
||||||
|
state = "none";
|
||||||
|
fprintf(f, "motion_record_state %s\n", state);
|
||||||
|
|
||||||
|
|
||||||
fprintf(f, "video_last %s\n",
|
fprintf(f, "video_last %s\n",
|
||||||
pikrellcam.video_last ? pikrellcam.video_last : "none");
|
pikrellcam.video_last ? pikrellcam.video_last : "none");
|
||||||
fprintf(f, "video_last_frame_count %d\n", pikrellcam.video_last_frame_count);
|
fprintf(f, "video_last_frame_count %d\n", pikrellcam.video_last_frame_count);
|
||||||
|
@ -840,6 +872,9 @@ state_file_write(void)
|
||||||
fprintf(f, "timelapse_video_last %s\n",
|
fprintf(f, "timelapse_video_last %s\n",
|
||||||
pikrellcam.timelapse_video_last ? pikrellcam.timelapse_video_last : "none");
|
pikrellcam.timelapse_video_last ? pikrellcam.timelapse_video_last : "none");
|
||||||
|
|
||||||
|
fprintf(f, "motion_detects_fifo_enable %s\n",
|
||||||
|
pikrellcam.motion_detects_fifo_enable ? "on" : "off");
|
||||||
|
|
||||||
fprintf(f, "current_minute %d\n",
|
fprintf(f, "current_minute %d\n",
|
||||||
pikrellcam.tm_local.tm_hour * 60 + pikrellcam.tm_local.tm_min);
|
pikrellcam.tm_local.tm_hour * 60 + pikrellcam.tm_local.tm_min);
|
||||||
fprintf(f, "dawn %d\n", sun.dawn);
|
fprintf(f, "dawn %d\n", sun.dawn);
|
||||||
|
@ -1332,6 +1367,9 @@ at_commands_config_save(char *config_file)
|
||||||
"# renamed after the video ends.\n"
|
"# renamed after the video ends.\n"
|
||||||
"# $S - still files directory full path\n"
|
"# $S - still files directory full path\n"
|
||||||
"# $s - last still saved full path filename\n"
|
"# $s - last still saved full path filename\n"
|
||||||
|
#ifdef MOTION_STILLS
|
||||||
|
"# $r - motion record mode: stills or videos\n"
|
||||||
|
#endif
|
||||||
"# $L - timelapse files directory full path\n"
|
"# $L - timelapse files directory full path\n"
|
||||||
"# $l - timelapse current series filename format: tl_sssss_%%05d.jpg\n"
|
"# $l - timelapse current series filename format: tl_sssss_%%05d.jpg\n"
|
||||||
"# in timelapse sub directory. If used in any script\n"
|
"# in timelapse sub directory. If used in any script\n"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* PiKrellCam
|
/* PiKrellCam
|
||||||
|
|
|
|
||||||
| Copyright (C) 2015-2016 Bill Wilson billw@gkrellm.net
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
|
||||||
|
|
|
|
||||||
| PiKrellCam is free software: you can redistribute it and/or modify it
|
| PiKrellCam is free software: you can redistribute it and/or modify it
|
||||||
| under the terms of the GNU General Public License as published by
|
| under the terms of the GNU General Public License as published by
|
||||||
|
@ -306,6 +306,12 @@ still_jpeg_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
|
||||||
if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)
|
if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)
|
||||||
{
|
{
|
||||||
fclose(still_jpeg_encoder.file);
|
fclose(still_jpeg_encoder.file);
|
||||||
|
|
||||||
|
#ifdef MOTION_STILLS
|
||||||
|
if (pikrellcam.motion_stills_capture_time > 0)
|
||||||
|
motion_events_write(&motion_frame, MOTION_EVENTS_STILL, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (pikrellcam.still_capture_event)
|
if (pikrellcam.still_capture_event)
|
||||||
{
|
{
|
||||||
event_add("still capture command", pikrellcam.t_now, 0,
|
event_add("still capture command", pikrellcam.t_now, 0,
|
||||||
|
@ -330,6 +336,7 @@ still_jpeg_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
|
||||||
PIKRELLCAM_TIMELAPSE_SUBDIR);
|
PIKRELLCAM_TIMELAPSE_SUBDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pikrellcam.motion_stills_capture_time = 0;
|
||||||
pikrellcam.still_capture_event = FALSE;
|
pikrellcam.still_capture_event = FALSE;
|
||||||
pikrellcam.timelapse_capture_event = FALSE;
|
pikrellcam.timelapse_capture_event = FALSE;
|
||||||
bytes_written = 0;
|
bytes_written = 0;
|
||||||
|
@ -750,12 +757,14 @@ video_h264_encoder_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *mmalbuf)
|
||||||
|
|
||||||
if (mf->fifo_trigger_time_limit > 0)
|
if (mf->fifo_trigger_time_limit > 0)
|
||||||
{
|
{
|
||||||
vcb->motion_sync_time = vcb->t_cur + mf->fifo_trigger_time_limit;
|
vcb->motion_sync_time = vcb->t_cur
|
||||||
|
+ mf->fifo_trigger_time_limit;
|
||||||
vcb->max_record_time = mf->fifo_trigger_time_limit;
|
vcb->max_record_time = mf->fifo_trigger_time_limit;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vcb->motion_sync_time = vcb->t_cur + pikrellcam.motion_times.post_capture;
|
vcb->motion_sync_time = vcb->t_cur
|
||||||
|
+ pikrellcam.motion_times.post_capture;
|
||||||
vcb->max_record_time = pikrellcam.motion_record_time_limit;
|
vcb->max_record_time = pikrellcam.motion_record_time_limit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -915,7 +924,8 @@ video_h264_encoder_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *mmalbuf)
|
||||||
|
|
||||||
if ( force_stop
|
if ( force_stop
|
||||||
|| ( mf->fifo_trigger_time_limit == 0
|
|| ( mf->fifo_trigger_time_limit == 0
|
||||||
&& vcb->t_cur >= vcb->motion_last_detect_time + pikrellcam.motion_times.event_gap
|
&& vcb->t_cur >= pikrellcam.motion_last_detect_time
|
||||||
|
+ pikrellcam.motion_times.event_gap
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
204
src/motion.c
204
src/motion.c
|
@ -1,6 +1,6 @@
|
||||||
/* PiKrellCam
|
/* PiKrellCam
|
||||||
|
|
|
|
||||||
| Copyright (C) 2015-2017 Bill Wilson billw@gkrellm.net
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
|
||||||
|
|
|
|
||||||
| PiKrellCam is free software: you can redistribute it and/or modify it
|
| PiKrellCam is free software: you can redistribute it and/or modify it
|
||||||
| under the terms of the GNU General Public License as published by
|
| under the terms of the GNU General Public License as published by
|
||||||
|
@ -354,7 +354,7 @@ motion_stats_write(VideoCircularBuffer *vcb, MotionFrame *mf)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
motion_event_write(VideoCircularBuffer *vcb, MotionFrame *mf, boolean start)
|
motion_events_write(MotionFrame *mf, int type, float detect_time)
|
||||||
{
|
{
|
||||||
static FILE *f;
|
static FILE *f;
|
||||||
CompositeVector *cvec, *frame_vec = &mf->frame_vector;
|
CompositeVector *cvec, *frame_vec = &mf->frame_vector;
|
||||||
|
@ -365,7 +365,7 @@ motion_event_write(VideoCircularBuffer *vcb, MotionFrame *mf, boolean start)
|
||||||
int burst, i, pan, tilt;
|
int burst, i, pan, tilt;
|
||||||
boolean dir_motion;
|
boolean dir_motion;
|
||||||
|
|
||||||
if (start)
|
if (type & MOTION_EVENTS_HEADER)
|
||||||
{
|
{
|
||||||
f = fopen(pikrellcam.motion_events_filename, "w");
|
f = fopen(pikrellcam.motion_events_filename, "w");
|
||||||
fprintf(f, "<header>\n");
|
fprintf(f, "<header>\n");
|
||||||
|
@ -394,10 +394,11 @@ motion_event_write(VideoCircularBuffer *vcb, MotionFrame *mf, boolean start)
|
||||||
}
|
}
|
||||||
fprintf(f, "</header>\n");
|
fprintf(f, "</header>\n");
|
||||||
}
|
}
|
||||||
if (f && ((vcb->state & VCB_STATE_MOTION_RECORD) || start))
|
// if (f && ((vcb->state & VCB_STATE_MOTION_RECORD) || start))
|
||||||
|
if (f && (type & MOTION_EVENTS_DETECT))
|
||||||
{
|
{
|
||||||
fprintf(f, "<motion %6.3f>\n",
|
fprintf(f, "<motion %6.3f >\n", detect_time);
|
||||||
(float) vcb->frame_count / (float) pikrellcam.camera_adjust.video_fps);
|
// (float) vcb->frame_count / (float) pikrellcam.camera_adjust.video_fps);
|
||||||
fprintf(f, "f %3d %3d %3d %3d %3.0f %4d\n",
|
fprintf(f, "f %3d %3d %3d %3d %3.0f %4d\n",
|
||||||
frame_vec->x, frame_vec->y, -frame_vec->vx, -frame_vec->vy,
|
frame_vec->x, frame_vec->y, -frame_vec->vx, -frame_vec->vy,
|
||||||
sqrt((float)frame_vec->mag2), frame_vec->mag2_count);
|
sqrt((float)frame_vec->mag2), frame_vec->mag2_count);
|
||||||
|
@ -431,7 +432,9 @@ motion_event_write(VideoCircularBuffer *vcb, MotionFrame *mf, boolean start)
|
||||||
fprintf(f, "</motion>\n");
|
fprintf(f, "</motion>\n");
|
||||||
fflush(f);
|
fflush(f);
|
||||||
}
|
}
|
||||||
else if (f && (vcb->state == VCB_STATE_NONE))
|
else if (f && (type & MOTION_EVENTS_STILL))
|
||||||
|
fprintf(f, "<still %s>\n", pikrellcam.still_last);
|
||||||
|
else if (f && (type & MOTION_EVENTS_END))
|
||||||
{
|
{
|
||||||
fprintf(f, "<end>\n");
|
fprintf(f, "<end>\n");
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
@ -440,6 +443,132 @@ motion_event_write(VideoCircularBuffer *vcb, MotionFrame *mf, boolean start)
|
||||||
/* else a MANUAL record state */
|
/* else a MANUAL record state */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
motion_detects_fifo_write(MotionFrame *mf)
|
||||||
|
{
|
||||||
|
CompositeVector *cvec, *frame_vec = &mf->frame_vector;
|
||||||
|
MotionRegion *mreg;
|
||||||
|
SList *mrlist;
|
||||||
|
char buf[256];
|
||||||
|
int burst, i;
|
||||||
|
boolean dir_motion;
|
||||||
|
static int fd = -1;
|
||||||
|
static boolean warned = FALSE;
|
||||||
|
|
||||||
|
if (!mf)
|
||||||
|
{
|
||||||
|
if (!pikrellcam.motion_detects_fifo_enable && fd >= 0)
|
||||||
|
{
|
||||||
|
write(fd, "<off>\n", 6);
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
}
|
||||||
|
else if (pikrellcam.motion_detects_fifo_enable && fd < 0)
|
||||||
|
fd = open(pikrellcam.motion_detects_fifo, O_WRONLY | O_NONBLOCK);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pikrellcam.motion_detects_fifo_enable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
fd = open(pikrellcam.motion_detects_fifo, O_WRONLY | O_NONBLOCK);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
if (!warned)
|
||||||
|
log_printf("Open failed: %s. %m\n", pikrellcam.motion_detects_fifo);
|
||||||
|
warned = TRUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
warned = FALSE;
|
||||||
|
|
||||||
|
i = snprintf(buf, sizeof(buf), "<motion %d.%d >\n",
|
||||||
|
(int) pikrellcam.tv_now.tv_sec,
|
||||||
|
(int) pikrellcam.tv_now.tv_usec / 100000);
|
||||||
|
write(fd, buf, i);
|
||||||
|
|
||||||
|
/* Write same data as motion_events_write() but to fd for the nonblocking
|
||||||
|
| fifo instead of a buffered FILE.
|
||||||
|
*/
|
||||||
|
snprintf(buf, sizeof(buf), "f %3d %3d %3d %3d %3.0f %4d\n",
|
||||||
|
frame_vec->x, frame_vec->y, -frame_vec->vx, -frame_vec->vy,
|
||||||
|
sqrt((float)frame_vec->mag2), frame_vec->mag2_count);
|
||||||
|
write(fd, buf, strlen(buf));
|
||||||
|
|
||||||
|
if (mf->motion_status & MOTION_BURST)
|
||||||
|
{
|
||||||
|
burst = frame_vec->mag2_count + mf->reject_count;
|
||||||
|
snprintf(buf, sizeof(buf), "b %3d\n", burst);
|
||||||
|
write(fd, buf, strlen(buf));
|
||||||
|
}
|
||||||
|
if (mf->motion_status & MOTION_AUDIO)
|
||||||
|
{
|
||||||
|
snprintf(buf, sizeof(buf), "a %3d\n", pikrellcam.audio_level_event);
|
||||||
|
write(fd, buf, strlen(buf));
|
||||||
|
}
|
||||||
|
if (mf->motion_status & MOTION_FIFO)
|
||||||
|
{
|
||||||
|
snprintf(buf, sizeof(buf), "e %s\n", mf->fifo_trigger_code);
|
||||||
|
write(fd, buf, strlen(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mf->motion_status & MOTION_DIRECTION)
|
||||||
|
{
|
||||||
|
for (i = 0, mrlist = mf->motion_region_list; mrlist;
|
||||||
|
mrlist = mrlist->next, ++i)
|
||||||
|
{
|
||||||
|
mreg = (MotionRegion *)mrlist->data;
|
||||||
|
dir_motion = mreg->motion
|
||||||
|
& (MOTION_TYPE_DIR_SMALL | MOTION_TYPE_DIR_NORMAL);
|
||||||
|
if (!dir_motion)
|
||||||
|
continue;
|
||||||
|
cvec = &mreg->vector;
|
||||||
|
snprintf(buf, sizeof(buf), "%d %3d %3d %3d %3d %3.0f %4d\n",
|
||||||
|
i, cvec->x, cvec->y, -cvec->vx, -cvec->vy,
|
||||||
|
sqrt((float)cvec->mag2), cvec->mag2_count);
|
||||||
|
write(fd, buf, strlen(buf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write(fd, "</motion>\n", 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
motion_stills_record(MotionFrame *mf)
|
||||||
|
{
|
||||||
|
PiKrellCam *pkc = &pikrellcam;
|
||||||
|
float period_usec, capture_diff_usec;
|
||||||
|
struct timeval tv_diff;
|
||||||
|
static struct timeval tv_motion_still;
|
||||||
|
|
||||||
|
if (!pkc->motion_stills_record) /* stills record start */
|
||||||
|
{
|
||||||
|
motion_events_write(mf, MOTION_EVENTS_HEADER, 0);
|
||||||
|
pkc->motion_stills_start_time = pkc->t_now;
|
||||||
|
tv_motion_still = pkc->tv_now;
|
||||||
|
if (mf->fifo_trigger_time_limit > 0)
|
||||||
|
pkc->motion_stills_max_time = mf->fifo_trigger_time_limit;
|
||||||
|
else
|
||||||
|
pkc->motion_stills_max_time = pkc->motion_record_time_limit;
|
||||||
|
pkc->motion_stills_sequence = 1;
|
||||||
|
}
|
||||||
|
timersub(&pkc->tv_now, &tv_motion_still, &tv_diff);
|
||||||
|
capture_diff_usec = (float)(tv_diff.tv_sec * 1e6) + (float)tv_diff.tv_usec;
|
||||||
|
period_usec = 60.0 / (float) pkc->motion_stills_per_minute * 1e6;
|
||||||
|
|
||||||
|
if ( !pkc->motion_stills_record /* First capture */
|
||||||
|
|| capture_diff_usec > period_usec
|
||||||
|
)
|
||||||
|
{
|
||||||
|
pkc->motion_stills_record = TRUE;
|
||||||
|
tv_motion_still = pkc->tv_now;
|
||||||
|
|
||||||
|
event_add("event_motion_still_capture", pkc->t_now, 0,
|
||||||
|
event_motion_still_capture, (void *) pkc->t_now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
motion_frame_process(VideoCircularBuffer *vcb, MotionFrame *mf)
|
motion_frame_process(VideoCircularBuffer *vcb, MotionFrame *mf)
|
||||||
{
|
{
|
||||||
|
@ -450,6 +579,7 @@ motion_frame_process(VideoCircularBuffer *vcb, MotionFrame *mf)
|
||||||
boolean burst_density_pass, motion_enabled;
|
boolean burst_density_pass, motion_enabled;
|
||||||
char tbuf[50], *msg;
|
char tbuf[50], *msg;
|
||||||
int x0, y0, x1, y1, t;
|
int x0, y0, x1, y1, t;
|
||||||
|
float detect_time;
|
||||||
static int mfp_number, motion_burst_frame;
|
static int mfp_number, motion_burst_frame;
|
||||||
|
|
||||||
/* Allow some startup camera settle time before motion detecting.
|
/* Allow some startup camera settle time before motion detecting.
|
||||||
|
@ -593,6 +723,7 @@ motion_frame_process(VideoCircularBuffer *vcb, MotionFrame *mf)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if ( !(vcb->state & VCB_STATE_MOTION_RECORD)
|
if ( !(vcb->state & VCB_STATE_MOTION_RECORD)
|
||||||
|
&& !pikrellcam.motion_stills_record
|
||||||
&& mf->frame_window == 0
|
&& mf->frame_window == 0
|
||||||
&& pikrellcam.motion_times.confirm_gap > 0
|
&& pikrellcam.motion_times.confirm_gap > 0
|
||||||
)
|
)
|
||||||
|
@ -692,11 +823,15 @@ motion_frame_process(VideoCircularBuffer *vcb, MotionFrame *mf)
|
||||||
|| ( (mf->motion_status & MOTION_FIFO) && motion_enabled)
|
|| ( (mf->motion_status & MOTION_FIFO) && motion_enabled)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
vcb->motion_last_detect_time = pikrellcam.t_now;
|
pikrellcam.motion_last_detect_time = pikrellcam.t_now;
|
||||||
|
|
||||||
/* Motion detection will be ignored if a manual record is in progress.
|
/* Motion recording ignored if a manual record is in progress.
|
||||||
|
| If loop recording, no motion stills recording and turn the
|
||||||
|
| loop video into a motion video.
|
||||||
*/
|
*/
|
||||||
if ( vcb->state == VCB_STATE_NONE
|
if ( ( vcb->state == VCB_STATE_NONE
|
||||||
|
&& !pikrellcam.motion_stills_record
|
||||||
|
)
|
||||||
|| ( (vcb->state & VCB_STATE_LOOP_RECORD)
|
|| ( (vcb->state & VCB_STATE_LOOP_RECORD)
|
||||||
&& !(vcb->state & VCB_STATE_MOTION_RECORD)
|
&& !(vcb->state & VCB_STATE_MOTION_RECORD)
|
||||||
)
|
)
|
||||||
|
@ -707,17 +842,34 @@ motion_frame_process(VideoCircularBuffer *vcb, MotionFrame *mf)
|
||||||
| callback can immediately schedule the on_preview_save command
|
| callback can immediately schedule the on_preview_save command
|
||||||
| so there is no wait to execute it.
|
| so there is no wait to execute it.
|
||||||
*/
|
*/
|
||||||
if (!(vcb->state & VCB_STATE_LOOP_RECORD))
|
if ( !(vcb->state & VCB_STATE_LOOP_RECORD)
|
||||||
|
&& !pikrellcam.motion_stills_enable
|
||||||
|
)
|
||||||
video_record_start(vcb, VCB_STATE_MOTION_RECORD_START);
|
video_record_start(vcb, VCB_STATE_MOTION_RECORD_START);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* Either a current loop video to be turned into a motion
|
||||||
|
| video or start motion stills recording.
|
||||||
|
*/
|
||||||
pikrellcam.do_preview_save = TRUE;
|
pikrellcam.do_preview_save = TRUE;
|
||||||
motion_event_write(vcb, &motion_frame, TRUE);
|
if (vcb->state & VCB_STATE_LOOP_RECORD)
|
||||||
vcb->state |= VCB_STATE_MOTION_RECORD;
|
{
|
||||||
|
vcb->state |= VCB_STATE_MOTION_RECORD;
|
||||||
|
motion_events_write(&motion_frame, MOTION_EVENTS_START,
|
||||||
|
(float) vcb->frame_count
|
||||||
|
/ (float) pikrellcam.camera_adjust.video_fps);
|
||||||
|
}
|
||||||
|
else if (pikrellcam.motion_stills_enable)
|
||||||
|
motion_stills_record(mf);
|
||||||
|
|
||||||
if (*pikrellcam.on_motion_begin_cmd)
|
if (*pikrellcam.on_motion_begin_cmd)
|
||||||
|
{
|
||||||
|
pikrellcam.motion_record_mode = pikrellcam.motion_stills_enable
|
||||||
|
? "stills" : "videos";
|
||||||
event_add("motion begin", pikrellcam.t_now, 0,
|
event_add("motion begin", pikrellcam.t_now, 0,
|
||||||
event_motion_begin_cmd,
|
event_motion_begin_cmd,
|
||||||
pikrellcam.on_motion_begin_cmd);
|
pikrellcam.on_motion_begin_cmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(pikrellcam.motion_preview_save_mode, "first"))
|
if (!strcmp(pikrellcam.motion_preview_save_mode, "first"))
|
||||||
|
@ -743,13 +895,16 @@ motion_frame_process(VideoCircularBuffer *vcb, MotionFrame *mf)
|
||||||
if (pikrellcam.verbose_motion && !pikrellcam.verbose)
|
if (pikrellcam.verbose_motion && !pikrellcam.verbose)
|
||||||
printf("***Motion record start: %s\n\n", pikrellcam.video_pathname);
|
printf("***Motion record start: %s\n\n", pikrellcam.video_pathname);
|
||||||
}
|
}
|
||||||
else if (vcb->state & VCB_STATE_MOTION_RECORD)
|
else if ( vcb->state & VCB_STATE_MOTION_RECORD
|
||||||
|
|| pikrellcam.motion_stills_record
|
||||||
|
)
|
||||||
{
|
{
|
||||||
/* Already recording, so each motion trigger bumps up the record
|
/* Already recording, so each motion trigger bumps up the record
|
||||||
| time to now + post capture time.
|
| time to now + post capture time.
|
||||||
| If mode "best" and better composite vector, save a new preview.
|
| If mode "best" and better composite vector, save a new preview.
|
||||||
*/
|
*/
|
||||||
vcb->motion_sync_time = pikrellcam.t_now + pikrellcam.motion_times.post_capture;
|
vcb->motion_sync_time = pikrellcam.t_now
|
||||||
|
+ pikrellcam.motion_times.post_capture;
|
||||||
|
|
||||||
if (mf->motion_status & (MOTION_DIRECTION | MOTION_BURST))
|
if (mf->motion_status & (MOTION_DIRECTION | MOTION_BURST))
|
||||||
pikrellcam.external_motion = FALSE;
|
pikrellcam.external_motion = FALSE;
|
||||||
|
@ -778,15 +933,30 @@ motion_frame_process(VideoCircularBuffer *vcb, MotionFrame *mf)
|
||||||
++mf->audio_detects;
|
++mf->audio_detects;
|
||||||
if (mf->motion_status & MOTION_FIFO)
|
if (mf->motion_status & MOTION_FIFO)
|
||||||
++mf->fifo_detects;
|
++mf->fifo_detects;
|
||||||
motion_event_write(vcb, mf, FALSE);
|
if (vcb->state & VCB_STATE_MOTION_RECORD)
|
||||||
|
detect_time = (float) vcb->frame_count
|
||||||
|
/ (float) pikrellcam.camera_adjust.video_fps;
|
||||||
|
else
|
||||||
|
detect_time = (float) (pikrellcam.motion_stills_capture_time
|
||||||
|
- pikrellcam.motion_stills_start_time);
|
||||||
|
motion_events_write(mf, MOTION_EVENTS_DETECT, detect_time);
|
||||||
|
|
||||||
if (pikrellcam.verbose_motion)
|
if (pikrellcam.verbose_motion)
|
||||||
printf("==>Motion record bump: %s\n\n", pikrellcam.video_pathname);
|
printf("==>Motion record bump: %s\n\n", pikrellcam.video_pathname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pikrellcam.motion_stills_enable)
|
||||||
|
motion_stills_record(mf);
|
||||||
|
|
||||||
if (pikrellcam.motion_stats)
|
if (pikrellcam.motion_stats)
|
||||||
motion_stats_write(vcb, mf);
|
motion_stats_write(vcb, mf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( mf->motion_status & MOTION_DETECTED
|
||||||
|
&& !pikrellcam.servo_moving
|
||||||
|
&& (pikrellcam.on_preset || pikrellcam.motion_off_preset)
|
||||||
|
)
|
||||||
|
motion_detects_fifo_write(mf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* PiKrellCam
|
/* PiKrellCam
|
||||||
|
|
|
|
||||||
| Copyright (C) 2015-2016 Bill Wilson billw@gkrellm.net
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
|
||||||
|
|
|
|
||||||
| PiKrellCam is free software: you can redistribute it and/or modify it
|
| PiKrellCam is free software: you can redistribute it and/or modify it
|
||||||
| under the terms of the GNU General Public License as published by
|
| under the terms of the GNU General Public License as published by
|
||||||
|
|
111
src/pikrellcam.c
111
src/pikrellcam.c
|
@ -1,6 +1,6 @@
|
||||||
/* PiKrellCam
|
/* PiKrellCam
|
||||||
|
|
|
|
||||||
| Copyright (C) 2015-2017 Bill Wilson billw@gkrellm.net
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
|
||||||
|
|
|
|
||||||
| PiKrellCam is free software: you can redistribute it and/or modify it
|
| PiKrellCam is free software: you can redistribute it and/or modify it
|
||||||
| under the terms of the GNU General Public License as published by
|
| under the terms of the GNU General Public License as published by
|
||||||
|
@ -296,7 +296,7 @@ camera_restart(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean
|
boolean
|
||||||
still_capture(char *fname)
|
still_capture(char *fname, time_t motion_time)
|
||||||
{
|
{
|
||||||
Event *event;
|
Event *event;
|
||||||
int n;
|
int n;
|
||||||
|
@ -348,6 +348,7 @@ still_capture(char *fname)
|
||||||
event_notify_expire, &pikrellcam.still_notify);
|
event_notify_expire, &pikrellcam.still_notify);
|
||||||
pikrellcam.still_capture_event = TRUE;
|
pikrellcam.still_capture_event = TRUE;
|
||||||
pikrellcam.still_notify = TRUE;
|
pikrellcam.still_notify = TRUE;
|
||||||
|
pikrellcam.motion_stills_capture_time = motion_time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -600,7 +601,9 @@ video_record_start(VideoCircularBuffer *vcb, int start_state)
|
||||||
&& (vcb->motion_stats_file = fopen(stats_path, "w")) != NULL
|
&& (vcb->motion_stats_file = fopen(stats_path, "w")) != NULL
|
||||||
)
|
)
|
||||||
vcb->motion_stats_do_header = TRUE;
|
vcb->motion_stats_do_header = TRUE;
|
||||||
motion_event_write(vcb, &motion_frame, TRUE);
|
motion_events_write(&motion_frame, MOTION_EVENTS_START,
|
||||||
|
(float) vcb->frame_count
|
||||||
|
/ (float) pikrellcam.camera_adjust.video_fps);
|
||||||
if (*pikrellcam.on_motion_begin_cmd != '\0')
|
if (*pikrellcam.on_motion_begin_cmd != '\0')
|
||||||
event_add("motion begin", pikrellcam.t_now, 0,
|
event_add("motion begin", pikrellcam.t_now, 0,
|
||||||
event_motion_begin_cmd, pikrellcam.on_motion_begin_cmd);
|
event_motion_begin_cmd, pikrellcam.on_motion_begin_cmd);
|
||||||
|
@ -927,7 +930,7 @@ video_record_stop(VideoCircularBuffer *vcb)
|
||||||
pikrellcam.external_motion = FALSE;
|
pikrellcam.external_motion = FALSE;
|
||||||
|
|
||||||
vcb->state = VCB_STATE_NONE;
|
vcb->state = VCB_STATE_NONE;
|
||||||
motion_event_write(vcb, mf, FALSE);
|
motion_events_write(mf, MOTION_EVENTS_END, 0);
|
||||||
pikrellcam.state_modified = TRUE;
|
pikrellcam.state_modified = TRUE;
|
||||||
vcb->pause = FALSE;
|
vcb->pause = FALSE;
|
||||||
vcb->record_hold =FALSE;
|
vcb->record_hold =FALSE;
|
||||||
|
@ -971,6 +974,26 @@ loop_record(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MOTION_STILLS
|
||||||
|
void
|
||||||
|
motion_stills_stop_check(void)
|
||||||
|
{
|
||||||
|
PiKrellCam *pkc = &pikrellcam;
|
||||||
|
time_t expire_time;
|
||||||
|
|
||||||
|
expire_time = pkc->motion_stills_max_time > 0
|
||||||
|
? pkc->motion_stills_start_time + pkc->motion_stills_max_time
|
||||||
|
: pkc->motion_last_detect_time + pkc->motion_times.event_gap;
|
||||||
|
|
||||||
|
if (pkc->motion_stills_enable && pkc->t_now < expire_time)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pikrellcam.motion_stills_record = FALSE;
|
||||||
|
pikrellcam.motion_stills_sequence = 1;
|
||||||
|
motion_events_write(&motion_frame, MOTION_EVENTS_END, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
get_arg_pass1(char *opt, char *arg)
|
get_arg_pass1(char *opt, char *arg)
|
||||||
{
|
{
|
||||||
|
@ -1085,6 +1108,12 @@ typedef enum
|
||||||
|
|
||||||
motion_cmd,
|
motion_cmd,
|
||||||
motion_enable,
|
motion_enable,
|
||||||
|
|
||||||
|
#ifdef MOTION_STILLS
|
||||||
|
motion_stills_enable,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
motion_detects_fifo_enable,
|
||||||
display_cmd, /* Placement above here can affect OSD. If menu */
|
display_cmd, /* Placement above here can affect OSD. If menu */
|
||||||
/* or adjustment is showing, above commands redirect */
|
/* or adjustment is showing, above commands redirect */
|
||||||
/* to cancel the menu or adjustment. */
|
/* to cancel the menu or adjustment. */
|
||||||
|
@ -1138,6 +1167,12 @@ static Command commands[] =
|
||||||
{ "motion", motion_cmd, 1, FALSE },
|
{ "motion", motion_cmd, 1, FALSE },
|
||||||
{ "motion_enable", motion_enable, 1, TRUE },
|
{ "motion_enable", motion_enable, 1, TRUE },
|
||||||
|
|
||||||
|
#ifdef MOTION_STILLS
|
||||||
|
{ "motion_stills_enable", motion_stills_enable, 1, TRUE },
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{ "motion_detects_fifo_enable", motion_detects_fifo_enable, 1, TRUE },
|
||||||
|
|
||||||
/* Above commands are redirected to abort a menu or adjustment display
|
/* Above commands are redirected to abort a menu or adjustment display
|
||||||
*/
|
*/
|
||||||
{ "display", display_cmd, 1, FALSE },
|
{ "display", display_cmd, 1, FALSE },
|
||||||
|
@ -1277,12 +1312,23 @@ command_process(char *command_line)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case loop:
|
case loop:
|
||||||
pthread_mutex_lock(&vcb->mutex);
|
|
||||||
n = pikrellcam.loop_enable;
|
n = pikrellcam.loop_enable;
|
||||||
config_set_boolean(&pikrellcam.loop_enable, args);
|
config_set_boolean(&n, args);
|
||||||
|
if (n && pikrellcam.motion_stills_enable)
|
||||||
|
{
|
||||||
|
display_inform("\"Cannot enable loop videos\" 3 3 1");
|
||||||
|
display_inform("\"while motion_stills are enabled.\" 4 3 1");
|
||||||
|
display_inform("timeout 2");
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (n != pikrellcam.loop_enable)
|
if (n != pikrellcam.loop_enable)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&vcb->mutex);
|
||||||
video_record_stop(vcb); // override motion & manual
|
video_record_stop(vcb); // override motion & manual
|
||||||
pthread_mutex_unlock(&vcb->mutex);
|
pthread_mutex_unlock(&vcb->mutex);
|
||||||
|
}
|
||||||
|
pikrellcam.loop_enable = n;
|
||||||
|
pikrellcam.state_modified = TRUE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case still:
|
case still:
|
||||||
|
@ -1292,7 +1338,7 @@ command_process(char *command_line)
|
||||||
'N', buf,
|
'N', buf,
|
||||||
'H', pikrellcam.hostname);
|
'H', pikrellcam.hostname);
|
||||||
pikrellcam.still_sequence += 1;
|
pikrellcam.still_sequence += 1;
|
||||||
still_capture(path);
|
still_capture(path, 0);
|
||||||
free(path);
|
free(path);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1440,6 +1486,37 @@ command_process(char *command_line)
|
||||||
event_motion_enable_cmd, pikrellcam.on_motion_enable_cmd);
|
event_motion_enable_cmd, pikrellcam.on_motion_enable_cmd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case motion_detects_fifo_enable:
|
||||||
|
config_set_boolean(&pikrellcam.motion_detects_fifo_enable, args);
|
||||||
|
motion_detects_fifo_write(NULL); /* Open or close fifo */
|
||||||
|
pikrellcam.config_modified = TRUE;
|
||||||
|
pikrellcam.state_modified = TRUE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef MOTION_STILLS
|
||||||
|
case motion_stills_enable:
|
||||||
|
n = pikrellcam.motion_stills_enable;
|
||||||
|
config_set_boolean(&n, args);
|
||||||
|
if (n && pikrellcam.loop_enable)
|
||||||
|
{
|
||||||
|
display_inform("\"Cannot enable motion stills\" 3 3 1");
|
||||||
|
display_inform("\"while loop videos are enabled.\" 4 3 1");
|
||||||
|
display_inform("timeout 2");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (n && !pikrellcam.motion_stills_enable)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&vcb->mutex);
|
||||||
|
if (vcb->state == VCB_STATE_MOTION_RECORD)
|
||||||
|
video_record_stop(vcb);
|
||||||
|
pthread_mutex_unlock(&vcb->mutex);
|
||||||
|
}
|
||||||
|
pikrellcam.motion_stills_enable = n;
|
||||||
|
pikrellcam.config_modified = TRUE;
|
||||||
|
pikrellcam.state_modified = TRUE;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
case video_fps:
|
case video_fps:
|
||||||
if ((n = atoi(args)) < 1)
|
if ((n = atoi(args)) < 1)
|
||||||
n = 1;
|
n = 1;
|
||||||
|
@ -1842,7 +1919,7 @@ main(int argc, char *argv[])
|
||||||
char *opt, *arg, *equal_arg, *user;
|
char *opt, *arg, *equal_arg, *user;
|
||||||
char *line, *eol, buf[4096];
|
char *line, *eol, buf[4096];
|
||||||
int t_usleep;
|
int t_usleep;
|
||||||
struct timeval tv;
|
// struct timeval tv;
|
||||||
|
|
||||||
pgm_name = argv[0];
|
pgm_name = argv[0];
|
||||||
setlocale(LC_TIME, "");
|
setlocale(LC_TIME, "");
|
||||||
|
@ -1997,6 +2074,7 @@ main(int argc, char *argv[])
|
||||||
check_modes(buf, 0775);
|
check_modes(buf, 0775);
|
||||||
|
|
||||||
asprintf(&pikrellcam.command_fifo, "%s/www/FIFO", pikrellcam.install_dir);
|
asprintf(&pikrellcam.command_fifo, "%s/www/FIFO", pikrellcam.install_dir);
|
||||||
|
asprintf(&pikrellcam.motion_detects_fifo, "%s/www/motion_detects_FIFO", pikrellcam.install_dir);
|
||||||
asprintf(&pikrellcam.audio_fifo, "%s/www/audio_FIFO", pikrellcam.install_dir);
|
asprintf(&pikrellcam.audio_fifo, "%s/www/audio_FIFO", pikrellcam.install_dir);
|
||||||
asprintf(&pikrellcam.scripts_dir, "%s/scripts", pikrellcam.install_dir);
|
asprintf(&pikrellcam.scripts_dir, "%s/scripts", pikrellcam.install_dir);
|
||||||
asprintf(&pikrellcam.scripts_dist_dir, "%s/scripts-dist", pikrellcam.install_dir);
|
asprintf(&pikrellcam.scripts_dist_dir, "%s/scripts-dist", pikrellcam.install_dir);
|
||||||
|
@ -2007,6 +2085,7 @@ main(int argc, char *argv[])
|
||||||
asprintf(&pikrellcam.loop_converting, "%s/loop_converting", pikrellcam.tmpfs_dir);
|
asprintf(&pikrellcam.loop_converting, "%s/loop_converting", pikrellcam.tmpfs_dir);
|
||||||
|
|
||||||
log_printf_no_timestamp("command FIFO: %s\n", pikrellcam.command_fifo);
|
log_printf_no_timestamp("command FIFO: %s\n", pikrellcam.command_fifo);
|
||||||
|
log_printf_no_timestamp("motion_detects FIFO : %s\n", pikrellcam.motion_detects_fifo);
|
||||||
log_printf_no_timestamp("audio FIFO : %s\n", pikrellcam.audio_fifo);
|
log_printf_no_timestamp("audio FIFO : %s\n", pikrellcam.audio_fifo);
|
||||||
log_printf_no_timestamp("mjpeg stream: %s\n", pikrellcam.mjpeg_filename);
|
log_printf_no_timestamp("mjpeg stream: %s\n", pikrellcam.mjpeg_filename);
|
||||||
|
|
||||||
|
@ -2073,9 +2152,11 @@ main(int argc, char *argv[])
|
||||||
"Failed to create archive directory, continuing anyway.\n");
|
"Failed to create archive directory, continuing anyway.\n");
|
||||||
|
|
||||||
|
|
||||||
|
if (!make_fifo(pikrellcam.motion_detects_fifo))
|
||||||
|
log_printf_no_timestamp("Failed to create motion_detects FIFO.\n");
|
||||||
if (!make_fifo(pikrellcam.audio_fifo))
|
if (!make_fifo(pikrellcam.audio_fifo))
|
||||||
log_printf_no_timestamp("Failed to create audio FIFO.\n");
|
log_printf_no_timestamp("Failed to create audio FIFO.\n");
|
||||||
|
|
||||||
if ((fifo = open(pikrellcam.command_fifo, O_RDONLY | O_NONBLOCK)) < 0)
|
if ((fifo = open(pikrellcam.command_fifo, O_RDONLY | O_NONBLOCK)) < 0)
|
||||||
{
|
{
|
||||||
log_printf("Failed to open FIFO: %s. %m\n", pikrellcam.command_fifo);
|
log_printf("Failed to open FIFO: %s. %m\n", pikrellcam.command_fifo);
|
||||||
|
@ -2111,18 +2192,24 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (gettimeofday(&tv, NULL) < 0)
|
if (gettimeofday(&pikrellcam.tv_now, NULL) < 0)
|
||||||
{
|
{
|
||||||
log_printf(" XXX gettimeofday error: %m\n");
|
log_printf(" XXX gettimeofday error: %m\n");
|
||||||
usleep(100000);
|
usleep(100000);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
t_usleep = (int) (100000 - (tv.tv_usec % 100000)); /* EVENT_LOOP_FREQUENCY!! */
|
/* EVENT_LOOP_FREQUENCY!! */
|
||||||
|
t_usleep = (int) (100000 - (pikrellcam.tv_now.tv_usec % 100000));
|
||||||
usleep(t_usleep + 1);
|
usleep(t_usleep + 1);
|
||||||
}
|
}
|
||||||
time(&pikrellcam.t_now);
|
time(&pikrellcam.t_now);
|
||||||
|
|
||||||
|
#ifdef MOTION_STILLS
|
||||||
|
if (pikrellcam.motion_stills_record)
|
||||||
|
motion_stills_stop_check();
|
||||||
|
#endif
|
||||||
|
|
||||||
event_process();
|
event_process();
|
||||||
multicast_recv();
|
multicast_recv();
|
||||||
tcp_poll_connect();
|
tcp_poll_connect();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* PiKrellCam
|
/* PiKrellCam
|
||||||
|
|
|
|
||||||
| Copyright (C) 2015-2017 Bill Wilson billw@gkrellm.net
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
|
||||||
|
|
|
|
||||||
| PiKrellCam is free software: you can redistribute it and/or modify it
|
| PiKrellCam is free software: you can redistribute it and/or modify it
|
||||||
| under the terms of the GNU General Public License as published by
|
| under the terms of the GNU General Public License as published by
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#define PIKRELLCAM_VERSION "4.1.6"
|
#define PIKRELLCAM_VERSION "4.2.0"
|
||||||
|
|
||||||
|
|
||||||
//TCP Stream Server
|
//TCP Stream Server
|
||||||
|
@ -257,7 +257,16 @@ typedef struct
|
||||||
}
|
}
|
||||||
MotionRegion;
|
MotionRegion;
|
||||||
|
|
||||||
|
/* Motion types for writing the /run/pikrellcam/motion-events file
|
||||||
|
*/
|
||||||
|
#define MOTION_EVENTS_HEADER 1
|
||||||
|
#define MOTION_EVENTS_DETECT 2
|
||||||
|
#define MOTION_EVENTS_START (MOTION_EVENTS_HEADER | MOTION_EVENTS_DETECT)
|
||||||
|
#define MOTION_EVENTS_STILL 4
|
||||||
|
#define MOTION_EVENTS_END 8
|
||||||
|
|
||||||
|
/* Motion detect state/types for the MotionFrame
|
||||||
|
*/
|
||||||
#define MOTION_NONE 0
|
#define MOTION_NONE 0
|
||||||
#define MOTION_DETECTED 1
|
#define MOTION_DETECTED 1
|
||||||
#define MOTION_DIRECTION 2
|
#define MOTION_DIRECTION 2
|
||||||
|
@ -267,7 +276,7 @@ typedef struct
|
||||||
#define MOTION_PENDING_BURST 0x20
|
#define MOTION_PENDING_BURST 0x20
|
||||||
#define MOTION_AUDIO 0x40
|
#define MOTION_AUDIO 0x40
|
||||||
|
|
||||||
/* Possible motion types for a region
|
/* Additional motion types for motion in regions.
|
||||||
*/
|
*/
|
||||||
#define MOTION_TYPE_DIR_SMALL 1
|
#define MOTION_TYPE_DIR_SMALL 1
|
||||||
#define MOTION_TYPE_DIR_NORMAL 2
|
#define MOTION_TYPE_DIR_NORMAL 2
|
||||||
|
@ -405,8 +414,7 @@ typedef struct
|
||||||
int record_start_frame_index;
|
int record_start_frame_index;
|
||||||
float actual_fps;
|
float actual_fps;
|
||||||
|
|
||||||
time_t motion_last_detect_time,
|
time_t motion_sync_time;
|
||||||
motion_sync_time;
|
|
||||||
}
|
}
|
||||||
VideoCircularBuffer;
|
VideoCircularBuffer;
|
||||||
|
|
||||||
|
@ -523,7 +531,12 @@ typedef struct
|
||||||
{
|
{
|
||||||
|
|
||||||
time_t t_now,
|
time_t t_now,
|
||||||
t_start;
|
t_start,
|
||||||
|
motion_last_detect_time;
|
||||||
|
|
||||||
|
struct timeval
|
||||||
|
tv_now;
|
||||||
|
|
||||||
struct tm tm_local;
|
struct tm tm_local;
|
||||||
int second_tick;
|
int second_tick;
|
||||||
int pi_model;
|
int pi_model;
|
||||||
|
@ -542,6 +555,7 @@ typedef struct
|
||||||
*command_fifo,
|
*command_fifo,
|
||||||
*state_filename,
|
*state_filename,
|
||||||
*motion_events_filename,
|
*motion_events_filename,
|
||||||
|
*motion_detects_fifo,
|
||||||
*video_converting,
|
*video_converting,
|
||||||
*loop_converting;
|
*loop_converting;
|
||||||
|
|
||||||
|
@ -570,6 +584,7 @@ typedef struct
|
||||||
*longitude;
|
*longitude;
|
||||||
|
|
||||||
boolean startup_motion_enable,
|
boolean startup_motion_enable,
|
||||||
|
motion_detects_fifo_enable,
|
||||||
external_motion,
|
external_motion,
|
||||||
state_modified,
|
state_modified,
|
||||||
preset_state_modified,
|
preset_state_modified,
|
||||||
|
@ -581,22 +596,35 @@ typedef struct
|
||||||
|
|
||||||
MotionTimes
|
MotionTimes
|
||||||
motion_times;
|
motion_times;
|
||||||
|
|
||||||
int motion_vectors_dimming,
|
int motion_vectors_dimming,
|
||||||
motion_magnitude_limit,
|
motion_magnitude_limit,
|
||||||
motion_magnitude_limit_count,
|
motion_magnitude_limit_count,
|
||||||
motion_burst_count,
|
motion_burst_count,
|
||||||
motion_burst_frames,
|
motion_burst_frames,
|
||||||
motion_record_time_limit;
|
motion_record_time_limit;
|
||||||
|
|
||||||
|
char *motion_stills_name_format;
|
||||||
|
int motion_stills_sequence,
|
||||||
|
motion_stills_per_minute,
|
||||||
|
motion_stills_max_time;
|
||||||
|
time_t motion_stills_start_time,
|
||||||
|
motion_stills_capture_time;
|
||||||
|
boolean motion_stills_enable,
|
||||||
|
motion_stills_record;
|
||||||
|
|
||||||
char *on_motion_begin_cmd,
|
char *on_motion_begin_cmd,
|
||||||
*on_motion_end_cmd,
|
*on_motion_end_cmd,
|
||||||
*on_motion_enable_cmd,
|
*on_motion_enable_cmd,
|
||||||
*on_manual_end_cmd,
|
*on_manual_end_cmd,
|
||||||
*on_loop_end_cmd,
|
*on_loop_end_cmd,
|
||||||
*motion_regions_name;
|
*motion_regions_name,
|
||||||
|
*motion_record_mode;
|
||||||
char *preview_pathname,
|
char *preview_pathname,
|
||||||
*thumb_name;
|
*thumb_name;
|
||||||
char *motion_preview_save_mode,
|
char *motion_preview_save_mode,
|
||||||
*on_motion_preview_save_cmd;
|
*on_motion_preview_save_cmd;
|
||||||
|
|
||||||
boolean motion_preview_clean,
|
boolean motion_preview_clean,
|
||||||
motion_vertical_filter,
|
motion_vertical_filter,
|
||||||
motion_stats,
|
motion_stats,
|
||||||
|
@ -731,7 +759,8 @@ typedef struct
|
||||||
boolean video_notify,
|
boolean video_notify,
|
||||||
still_notify,
|
still_notify,
|
||||||
timelapse_notify;
|
timelapse_notify;
|
||||||
int notify_duration;
|
int notify_duration,
|
||||||
|
rotation_value;
|
||||||
|
|
||||||
char *sharpness,
|
char *sharpness,
|
||||||
*contrast,
|
*contrast,
|
||||||
|
@ -857,7 +886,7 @@ boolean resizer_create(char *name, CameraObject *resizer,
|
||||||
void mjpeg_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
|
void mjpeg_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
|
||||||
void I420_video_callback(MMAL_PORT_T *port,
|
void I420_video_callback(MMAL_PORT_T *port,
|
||||||
MMAL_BUFFER_HEADER_T *buffer);
|
MMAL_BUFFER_HEADER_T *buffer);
|
||||||
boolean still_capture(char *fname);
|
boolean still_capture(char *fname, time_t motion_time);
|
||||||
void still_jpeg_callback(MMAL_PORT_T *port,
|
void still_jpeg_callback(MMAL_PORT_T *port,
|
||||||
MMAL_BUFFER_HEADER_T *buffer);
|
MMAL_BUFFER_HEADER_T *buffer);
|
||||||
void video_h264_encoder_callback(MMAL_PORT_T *port,
|
void video_h264_encoder_callback(MMAL_PORT_T *port,
|
||||||
|
@ -904,8 +933,8 @@ boolean motion_regions_config_load(char *config_file, boolean inform);
|
||||||
void motion_preview_file_event(void);
|
void motion_preview_file_event(void);
|
||||||
void motion_preview_area_fixup(void);
|
void motion_preview_area_fixup(void);
|
||||||
void print_cvec(char *str, CompositeVector *cvec);
|
void print_cvec(char *str, CompositeVector *cvec);
|
||||||
void motion_event_write(VideoCircularBuffer *vcb, MotionFrame *mf,
|
void motion_events_write(MotionFrame *mf, int type, float detect_time);
|
||||||
boolean start);
|
void motion_detects_fifo_write(MotionFrame *mf);
|
||||||
|
|
||||||
/* On Screen Display
|
/* On Screen Display
|
||||||
*/
|
*/
|
||||||
|
@ -935,6 +964,7 @@ void event_process(void);
|
||||||
void event_motion_enable_cmd(char *cmd);
|
void event_motion_enable_cmd(char *cmd);
|
||||||
void event_motion_begin_cmd(char *cmd);
|
void event_motion_begin_cmd(char *cmd);
|
||||||
void event_still_capture_cmd(char *cmd);
|
void event_still_capture_cmd(char *cmd);
|
||||||
|
void event_motion_still_capture(void *arg);
|
||||||
|
|
||||||
void event_video_diskfree_percent(char *type);
|
void event_video_diskfree_percent(char *type);
|
||||||
void event_archive_diskfree_percent(char *type);
|
void event_archive_diskfree_percent(char *type);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
/* PiKrellCam
|
/* PiKrellCam
|
||||||
|
|
|
|
||||||
| Copyright (C) 2015-2016 Bill Wilson billw@gkrellm.net
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
|
||||||
|
|
|
|
||||||
| PiKrellCam is free software: you can redistribute it and/or modify it
|
| PiKrellCam is free software: you can redistribute it and/or modify it
|
||||||
| under the terms of the GNU General Public License as published by
|
| under the terms of the GNU General Public License as published by
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
/* PiKrellCam
|
/* PiKrellCam
|
||||||
|
|
|
|
||||||
| Copyright (C) 2015-2016 Bill Wilson billw@gkrellm.net
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
|
||||||
|
|
|
|
||||||
| PiKrellCam is free software: you can redistribute it and/or modify it
|
| PiKrellCam is free software: you can redistribute it and/or modify it
|
||||||
| under the terms of the GNU General Public License as published by
|
| under the terms of the GNU General Public License as published by
|
||||||
|
|
321
www/help.php
321
www/help.php
|
@ -68,6 +68,13 @@ And there is a Raspberry Pi
|
||||||
<span style='font-size: 1.5em; font-weight: 650;'>Release Notes</span><hr>
|
<span style='font-size: 1.5em; font-weight: 650;'>Release Notes</span><hr>
|
||||||
<div class='indent0'>
|
<div class='indent0'>
|
||||||
|
|
||||||
|
Version 4.2.0
|
||||||
|
<div class='indent1'>
|
||||||
|
<a href="help.php#MOTION_EVENTS_FIFO">motion_detects_FIFO</a> can be read
|
||||||
|
to get all motion detects regardless of motion videos enabled state.<br>
|
||||||
|
Moved Setup->Config->Times/* and Setup->Settings->Startup_Motion to Setup->Config->Motion.
|
||||||
|
</div>
|
||||||
|
|
||||||
Version 4.1.5
|
Version 4.1.5
|
||||||
<div class='indent1'>
|
<div class='indent1'>
|
||||||
Archive directory <a href="help.php#ARCHIVING">NFS mount examples.</a><br>
|
Archive directory <a href="help.php#ARCHIVING">NFS mount examples.</a><br>
|
||||||
|
@ -368,7 +375,7 @@ event will cause the video to be tagged as having a motion event and the web
|
||||||
page thumb will be labeled to show that.
|
page thumb will be labeled to show that.
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
Loop videos with no motion event will end with
|
Loop videos with no motion detect will end with
|
||||||
<span style='font-weight:700'>_0.mp4</span>.
|
<span style='font-weight:700'>_0.mp4</span>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
@ -812,6 +819,67 @@ Preset group and there will be no Servo button in the Config group.
|
||||||
<p>
|
<p>
|
||||||
<span style='font-size: 1.2em; font-weight: 680;'>Config</span>
|
<span style='font-size: 1.2em; font-weight: 680;'>Config</span>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li><span style='font-weight:700'>Motion</span>
|
||||||
|
<ul>
|
||||||
|
<li><span style='font-weight:700'>Startup_Motion</span> - set to
|
||||||
|
<span style='font-weight:700'>ON</span> for motion detection to be enabled each time
|
||||||
|
PiKrellCam starts. Motion detection can be
|
||||||
|
enabled from the web page or a script.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li><span style='font-weight:700'>Confirm_Gap</span> - for motion direction detects,
|
||||||
|
require a second motion detect within this period of seconds before triggering a
|
||||||
|
motion record event. This adds a level of noise rejection to motion direction detecting
|
||||||
|
but may be set to zero to disable a second detect requirement if fast detection is desired.
|
||||||
|
This setting does not apply to motion burst detects because the Burst_Frames setting
|
||||||
|
provides a confirm time for that method.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li><span style='font-weight:700'>Pre_Capture</span> - seconds of video to record prior
|
||||||
|
to the first motion detect event. This value should be greater than or equal to the
|
||||||
|
Confirm_Gap. Pre capture does not apply when motion stills recording.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li><span style='font-weight:700'>Event_Gap</span> - number of seconds that must pass
|
||||||
|
since the last motion detect before a motion event recording can end.
|
||||||
|
When an Event_Gap period does expire without a new motion detect occurring,
|
||||||
|
videos will end with an end time of the last motion detect time plus the
|
||||||
|
Post_Capture time (but see Post_Capture).
|
||||||
|
Set this higher for animals or walking people that may pause for
|
||||||
|
periods of time before resuming motion. Set lower for active scenes where events
|
||||||
|
are frequent and you want to bias towards shorter videos
|
||||||
|
that capture more events separately.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li><span style='font-weight:700'>Post_Capture</span> - seconds of video
|
||||||
|
that will be recorded after the last occurring motion event. This time must be
|
||||||
|
less than or equal to the Event_Gap time because post capture time is accumulated
|
||||||
|
in the circular buffer while the video is recording. An expiring Event_Gap time
|
||||||
|
ends the video immediately and no more Post_Capture time can be accumulated.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li><span style='font-weight:700'>Video_Time_Limit</span> - range is 0 - 1800
|
||||||
|
seconds (30 minutes) and is the maximum seconds of motion video
|
||||||
|
that will be recorded after the first occurring motion detect. So the total
|
||||||
|
video length max will be the Pre_Capture time + the Time_Limit.
|
||||||
|
If this is set to zero, there will be no time limit enforced. This limit
|
||||||
|
does not apply to manual recordings - see FIFO examples for that.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
<div class='indent1'>
|
||||||
|
<span style='font-weight:700'>Note:</span>
|
||||||
|
Videos can be started only on key frame boundaries. When waiting for a motion
|
||||||
|
event to start, PiKrellCam requests key frames from the camera once per second,
|
||||||
|
so a Pre_Capture time setting of T will actually record somewhere between
|
||||||
|
T and T+1 seconds.
|
||||||
|
Also, if there is a new motion event immediately following a previous motion
|
||||||
|
video end, there may not be the configured Pre_Capture time accumulated in the
|
||||||
|
circular buffer and so the actual pre capture time will be less than what
|
||||||
|
is configured.
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li><span style='font-weight:700'>Video Res</span> - selects the video resolution for
|
<li><span style='font-weight:700'>Video Res</span> - selects the video resolution for
|
||||||
motion and manual videos. Different resolutions may have different fields of view. So
|
motion and manual videos. Different resolutions may have different fields of view. So
|
||||||
one reason for selecting
|
one reason for selecting
|
||||||
|
@ -819,17 +887,14 @@ Preset group and there will be no Servo button in the Config group.
|
||||||
<span style='font-weight:700'>1080p</span> would be to get a wider field of view. Resolutions
|
<span style='font-weight:700'>1080p</span> would be to get a wider field of view. Resolutions
|
||||||
will have either 16:9 or 4:3 aspect ratio.
|
will have either 16:9 or 4:3 aspect ratio.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><span style='font-weight:700'>Still Res</span> - selecting different resolutions
|
<li><span style='font-weight:700'>Still Res</span> - selecting different resolutions
|
||||||
gives different fields of view and aspect ratios.
|
gives different fields of view and aspect ratios.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<a name="DISKFREE">
|
<a name="DISKFREE">
|
||||||
<li><span style='font-weight:700'>Settings</span>
|
<li><span style='font-weight:700'>Settings</span>
|
||||||
<ul>
|
<ul>
|
||||||
<li><span style='font-weight:700'>Startup_Motion</span> - set to
|
|
||||||
<span style='font-weight:700'>ON</span> for motion detection to be enabled each time
|
|
||||||
PiKrellCam starts. Motion detection can be
|
|
||||||
enabled from the web page or a script.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li><span style='font-weight:700'>Check_Media_Diskfree</span>
|
<li><span style='font-weight:700'>Check_Media_Diskfree</span>
|
||||||
- if set <span style='font-weight:700'>ON</span>, when new motion
|
- if set <span style='font-weight:700'>ON</span>, when new motion
|
||||||
|
@ -850,6 +915,7 @@ Preset group and there will be no Servo button in the Config group.
|
||||||
moving media videos and except for some directory structure overhead
|
moving media videos and except for some directory structure overhead
|
||||||
is not increasing disk usage.
|
is not increasing disk usage.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><span style='font-weight:700'>Diskfree_Percent</span>
|
<li><span style='font-weight:700'>Diskfree_Percent</span>
|
||||||
- maintain this minimum free percent on media and archive
|
- maintain this minimum free percent on media and archive
|
||||||
file systems when checking is enabled for those file systems
|
file systems when checking is enabled for those file systems
|
||||||
|
@ -862,31 +928,38 @@ Preset group and there will be no Servo button in the Config group.
|
||||||
and its quality. Adjust up if it improves video quality. Adjust down if you want
|
and its quality. Adjust up if it improves video quality. Adjust down if you want
|
||||||
to reduce the size of the videos.
|
to reduce the size of the videos.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><span style='font-weight:700'>video_fps</span> - typically this should be no higher
|
<li><span style='font-weight:700'>video_fps</span> - typically this should be no higher
|
||||||
than 24 or the motion detecting preview jpeg camera stream may start dropping frames.
|
than 24 or the motion detecting preview jpeg camera stream may start dropping frames.
|
||||||
(I have no data on the effect GPU overclocking might have on this limitation).
|
(I have no data on the effect GPU overclocking might have on this limitation).
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><span style='font-weight:700'>video_mp4box_fps</span> - keep this value set to zero
|
<li><span style='font-weight:700'>video_mp4box_fps</span> - keep this value set to zero
|
||||||
unless you want to create fast or slow motion videos. When zero, mp4 boxing fps will be
|
unless you want to create fast or slow motion videos. When zero, mp4 boxing fps will be
|
||||||
the same as video_fps which is normally what you want. But this value can be set to a
|
the same as video_fps which is normally what you want. But this value can be set to a
|
||||||
non zero value different from video_fps if you want fast or slow motion videos.
|
non zero value different from video_fps if you want fast or slow motion videos.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><span style='font-weight:700'>mjpeg_divider</span> - this value is divided into
|
<li><span style='font-weight:700'>mjpeg_divider</span> - this value is divided into
|
||||||
the video_fps value to get the preview jpeg rate. The preview is updated at this rate
|
the video_fps value to get the preview jpeg rate. The preview is updated at this rate
|
||||||
and it is the rate that motion vector frames are checked for motion.
|
and it is the rate that motion vector frames are checked for motion.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><span style='font-weight:700'>still_quality</span> - adjust up if it improves
|
<li><span style='font-weight:700'>still_quality</span> - adjust up if it improves
|
||||||
still jpeg quality. Adjust down if you want to reduce the size of still jpegs.
|
still jpeg quality. Adjust down if you want to reduce the size of still jpegs.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><span style='font-weight:700'>Vector_Counts</span> - enable showing of vector count
|
<li><span style='font-weight:700'>Vector_Counts</span> - enable showing of vector count
|
||||||
statistics when showing a Preset. This information may help when setting motion detect
|
statistics when showing a Preset. This information may help when setting motion detect
|
||||||
limits.
|
limits.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><span style='font-weight:700'>Vector_Dimming</span> - sets a percentage dimming
|
<li><span style='font-weight:700'>Vector_Dimming</span> - sets a percentage dimming
|
||||||
of the preview jpeg image when the
|
of the preview jpeg image when the
|
||||||
<span style='font-weight:700'>Vectors</span> display is enabled. This is to improve
|
<span style='font-weight:700'>Vectors</span> display is enabled. This is to improve
|
||||||
the contrast of the drawn motion vectors.
|
the contrast of the drawn motion vectors.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><span style='font-weight:700'>Preview_Clean</span> - if set to
|
<li><span style='font-weight:700'>Preview_Clean</span> - if set to
|
||||||
<span style='font-weight:700'>OFF</span>, whatever text or graphics that happen to be
|
<span style='font-weight:700'>OFF</span>, whatever text or graphics that happen to be
|
||||||
drawn on the preview jpeg at the time a motion preview save or thumb save occurs will
|
drawn on the preview jpeg at the time a motion preview save or thumb save occurs will
|
||||||
|
@ -896,56 +969,6 @@ Preset group and there will be no Servo button in the Config group.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><span style='font-weight:700'>Times</span>
|
|
||||||
<ul>
|
|
||||||
<li><span style='font-weight:700'>Confirm_Gap</span> - for motion direction detects,
|
|
||||||
require a second motion detect within this period of seconds before triggering a
|
|
||||||
motion detect event. This adds a level of noise rejection to motion direction detecting
|
|
||||||
but may be set to zero to disable a second detect requirement if fast detection is desired.
|
|
||||||
This setting does not apply to motion burst detects because the Burst_Frames setting
|
|
||||||
provides a confirm time for that method.
|
|
||||||
</li>
|
|
||||||
<li><span style='font-weight:700'>Pre_Capture</span> - seconds of video to record prior
|
|
||||||
to the first motion detect event. This value should be greater than or equal to the
|
|
||||||
Confirm_Gap.
|
|
||||||
</li>
|
|
||||||
<li><span style='font-weight:700'>Event_Gap</span> - number of seconds that must pass
|
|
||||||
since the last motion detect event before a motion video record can end.
|
|
||||||
When an Event_Gap period does expire without a new motion event occurring,
|
|
||||||
the video will end with an end time of the last motion detect time plus the
|
|
||||||
Post_Capture time (but see Post_Capture).
|
|
||||||
Set this higher for animals or walking people that may pause for
|
|
||||||
periods of time before resuming motion. Set lower for active scenes where events
|
|
||||||
are frequent and you want to bias towards shorter videos
|
|
||||||
that capture more events separately.
|
|
||||||
</li>
|
|
||||||
<li><span style='font-weight:700'>Post_Capture</span> - seconds of video
|
|
||||||
that will be recorded after the last occurring motion event. This time must be
|
|
||||||
less than or equal to the Event_Gap time because post capture time is accumulated
|
|
||||||
in the circular buffer while the video is recording. An expiring Event_Gap time
|
|
||||||
ends the video immediately and no more Post_Capture time can be accumulated.
|
|
||||||
</li>
|
|
||||||
<li><span style='font-weight:700'>Time_Limit</span> - range is 10 - 1800
|
|
||||||
seconds (30 minutes) and is the maximum seconds of motion video
|
|
||||||
that will be recorded after the first occurring motion event. So the total
|
|
||||||
video length max will be the Pre_Capture time + the Time_Limit.
|
|
||||||
If this is set to zero, there will be no time limit enforced. This limit
|
|
||||||
does not apply to manual recordings - see FIFO examples for that.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p>
|
|
||||||
<div class='indent1'>
|
|
||||||
<span style='font-weight:700'>Note:</span>
|
|
||||||
Videos can be started only on key frame boundaries. When waiting for a motion
|
|
||||||
event to start, PiKrellCam requests key frames from the camera once per second,
|
|
||||||
so a Pre_Capture time setting of T will actually record somewhere between
|
|
||||||
T and T+1 seconds.
|
|
||||||
Also, if there is a new motion event immediately following a previous motion
|
|
||||||
video end, there may not be the configured Pre_Capture time accumulated in the
|
|
||||||
circular buffer and so the actual pre capture time will be less than what
|
|
||||||
is configured.
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<a name="DISKUSAGE">
|
<a name="DISKUSAGE">
|
||||||
<li><span style='font-weight:700'>Loop</span><br>
|
<li><span style='font-weight:700'>Loop</span><br>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -954,9 +977,11 @@ Preset group and there will be no Servo button in the Config group.
|
||||||
be enabled each time PiKrellCam starts. Loop recording can be
|
be enabled each time PiKrellCam starts. Loop recording can be
|
||||||
enabled from the web page or a script or an at-command.
|
enabled from the web page or a script or an at-command.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><span style='font-weight:700'>Time_Limit</span>
|
<li><span style='font-weight:700'>Time_Limit</span>
|
||||||
- loop video length in seconds.
|
- loop video length in seconds.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><span style='font-weight:700'>Diskusage_Percent</span>
|
<li><span style='font-weight:700'>Diskusage_Percent</span>
|
||||||
- Limit disk space used by loop videos to this percent
|
- Limit disk space used by loop videos to this percent
|
||||||
by deleting oldest loop videos as new ones are recorded.
|
by deleting oldest loop videos as new ones are recorded.
|
||||||
|
@ -972,7 +997,7 @@ Preset group and there will be no Servo button in the Config group.
|
||||||
<ul>
|
<ul>
|
||||||
<li><span style='font-weight:700'>Audio_Trigger_Video</span>
|
<li><span style='font-weight:700'>Audio_Trigger_Video</span>
|
||||||
- set to <span style='font-weight:700'>ON</span>
|
- set to <span style='font-weight:700'>ON</span>
|
||||||
to enable audio events to be treated as motion events to trigger
|
to enable audio detects to be treated as motion detects to trigger
|
||||||
motion videos.
|
motion videos.
|
||||||
</li>
|
</li>
|
||||||
<li><span style='font-weight:700'>Audio_Trigger_Level</span>
|
<li><span style='font-weight:700'>Audio_Trigger_Level</span>
|
||||||
|
@ -1829,6 +1854,7 @@ tl_end
|
||||||
tl_hold [on|off|toggle]
|
tl_hold [on|off|toggle]
|
||||||
tl_show_status [on|off|toggle]
|
tl_show_status [on|off|toggle]
|
||||||
motion_enable [on|off|toggle]
|
motion_enable [on|off|toggle]
|
||||||
|
motion_detects_fifo_enable [on|off|toggle]
|
||||||
motion limits magnitude count
|
motion limits magnitude count
|
||||||
motion burst count frames
|
motion burst count frames
|
||||||
motion trigger code # code is digit N or N:ID N is 0 or 1 and ID is a string (see Examples)
|
motion trigger code # code is digit N or N:ID N is 0 or 1 and ID is a string (see Examples)
|
||||||
|
@ -2081,7 +2107,7 @@ frequency time "command"
|
||||||
time period (say started during the day versus started at night) when
|
time period (say started during the day versus started at night) when
|
||||||
PiKrellCam is started, you need to have your own script that checks the time.
|
PiKrellCam is started, you need to have your own script that checks the time.
|
||||||
Such a script can parse the PiKrellCam state file
|
Such a script can parse the PiKrellCam state file
|
||||||
<span style='font-weight:700'>/var/run/pikrellcam/state</span>
|
<span style='font-weight:700'>/run/pikrellcam/state</span>
|
||||||
to get the
|
to get the
|
||||||
<span style='font-weight:700'>current_minute</span>
|
<span style='font-weight:700'>current_minute</span>
|
||||||
and compare it to todays sun times from the state file:
|
and compare it to todays sun times from the state file:
|
||||||
|
@ -2229,27 +2255,28 @@ motion_state=${line#motion_enable}
|
||||||
<a name="MOTION_EVENTS">
|
<a name="MOTION_EVENTS">
|
||||||
<span style='font-size: 1.2em; font-weight: 700;'>/run/pikrellcam/motion-events</span>
|
<span style='font-size: 1.2em; font-weight: 700;'>/run/pikrellcam/motion-events</span>
|
||||||
<div class='indent1'>
|
<div class='indent1'>
|
||||||
This is new in PiKrellCam 3.1.0 and it's possible there will be small
|
This file is for processing motion detects during a motion video
|
||||||
changes in its format in coming versions.
|
or stills record event
|
||||||
|
in real time as they occur while recording is in progress. It is intended
|
||||||
|
to be processed by an on_motion_begin command configured in
|
||||||
|
pikrellcam.conf.
|
||||||
<p>
|
<p>
|
||||||
Motion detect events are written to this file during each motion video
|
See the motion_detects_FIFO below if you want to process a continuous
|
||||||
recording. An on_motion_begin command configured to run in pikrellcam.conf
|
stream of motion detects whether or not a motion event is recording.
|
||||||
can read this file to get
|
|
||||||
a reasonably fast notification of motion
|
|
||||||
events as they occur while the video is recording. Scripts can determine
|
|
||||||
where motion is in the video frame (by x,y position or motion region
|
|
||||||
number) and then take some action such as sending multicast alarms and/or
|
|
||||||
moving servos.
|
|
||||||
<p>
|
<p>
|
||||||
This file is overwritten with new event data for each new motion video
|
This file is overwritten with new detect data for each new motion
|
||||||
recording so
|
recording and the on_motion_begin command is run
|
||||||
it is intended for use by on_motion_begin commands which are run
|
|
||||||
immediately after the motion-events file writing begins.
|
immediately after the motion-events file writing begins.
|
||||||
The output to the file is
|
The output to the file is
|
||||||
flushed after data for each motion detect is written.
|
flushed after data for each motion detect is written.
|
||||||
See script-dist/example-motion-send-alarm2 for an example reading of this
|
See script-dist/example-motion-send-alarm2 for an example reading of this
|
||||||
file in an on_motion_begin script.
|
file in an on_motion_begin script.
|
||||||
<p>
|
<p>
|
||||||
|
Scripts can determine
|
||||||
|
where motion is in the video frame (by x,y position or motion region
|
||||||
|
number) and then take some action such as sending multicast alarms and/or
|
||||||
|
moving servos.
|
||||||
|
<p>
|
||||||
The format of the file is a header block followed by one or more
|
The format of the file is a header block followed by one or more
|
||||||
motion blocks and a final end tag.
|
motion blocks and a final end tag.
|
||||||
Inside of motion blocks are the data
|
Inside of motion blocks are the data
|
||||||
|
@ -2262,50 +2289,144 @@ to be documented...
|
||||||
</header>
|
</header>
|
||||||
...
|
...
|
||||||
<motion 3.667>
|
<motion 3.667>
|
||||||
b 0
|
|
||||||
f 49 43 57 -2 57 263
|
f 49 43 57 -2 57 263
|
||||||
1 44 42 53 -4 53 144
|
1 44 42 53 -4 53 144
|
||||||
2 55 44 61 0 61 119
|
2 55 44 61 0 61 119
|
||||||
a 45
|
</motion>
|
||||||
e 0
|
<motion 4.100>
|
||||||
|
f 10 36 69 52 86 290
|
||||||
|
b 949
|
||||||
|
</motion>
|
||||||
|
<motion 5.120>
|
||||||
|
f 0 0 0 0 0 0
|
||||||
|
e PIR
|
||||||
|
</motion>
|
||||||
|
<motion 6.000>
|
||||||
|
f 0 0 0 0 0 0
|
||||||
|
a 45
|
||||||
</motion>
|
</motion>
|
||||||
...
|
...
|
||||||
<end>
|
<end>
|
||||||
</pre>
|
</pre>
|
||||||
shows data for a detect at 3.667 seconds into the video
|
shows data for a first detect at 3.667 seconds into the video
|
||||||
(including precapture).
|
(including precapture).
|
||||||
Each line inside the motion block begins with a single character code:
|
Each line inside a motion block begins with a single character code:
|
||||||
<ul>
|
<ul>
|
||||||
<li> <span style='font-weight:700'>b</span> - this line shows burst counts.
|
<li> <span style='font-weight:700'>f x y dx dy magnitude count</span>
|
||||||
For this detect the burst count did not exceed the burst count limit, so zero
|
- where the first character code is 'f'.<br>
|
||||||
is reported.
|
This line is the data for
|
||||||
|
the total frame vector (composite of all the motion region vectors).
|
||||||
|
There is always a frame vector reported but may be a zero vector for
|
||||||
|
audio or external only detects. A non-zero frame vector passes
|
||||||
|
the configured magnitude and count limits and there can be a passing
|
||||||
|
frame vector without any passing region vectors.
|
||||||
</li>
|
</li>
|
||||||
<li> <span style='font-weight:700'>f</span> - this line is the data for
|
<li> <span style='font-weight:700'>n x y dx dy magnitude count</span>
|
||||||
the total frame vector (composite of all the motion region vectors)
|
- where the first character code n is a digit.<br>
|
||||||
and has the format:
|
These lines are for motion vectors for a motion region detects.
|
||||||
<pre>
|
There will be a line for each region having motion and no line for
|
||||||
code x y dx dy magnitude count
|
regions not having motion. Just like the overall frame vector, for a
|
||||||
</pre>
|
motion region to have motion, the configured magnitude and count limits
|
||||||
</li>
|
must be met.
|
||||||
<li> <span style='font-weight:700'>n</span> - where n is a digit. These
|
|
||||||
lines are for motion vectors for a motion region and have the same
|
|
||||||
format as the frame vector.
|
|
||||||
There is one
|
|
||||||
line for each region having motion and no line for regions not having
|
|
||||||
motion. Just like the overall frame vector, for a motion region to have
|
|
||||||
motion, the configured magnitude and count limits must be met.
|
|
||||||
For this detect there was motion in regions 1 and 2.
|
For this detect there was motion in regions 1 and 2.
|
||||||
</li>
|
</li>
|
||||||
<li> <span style='font-weight:700'>a|e</span>
|
<li> <span style='font-weight:700'>b</span> - this line shows burst counts.
|
||||||
- shows audio or external triggers. If an audio level exceeded the
|
If no regions individually passed detection magnitude and count limits,
|
||||||
audio_trigger_level value it is printed, otherwise 0 is shown. If there
|
the overall frame vector must pass for a burst count detect so a burst
|
||||||
was an external trigger (motion trigger command into the FIFO), then
|
detect with no region detects still always has a frame vector.
|
||||||
the e line will show 1, otherwise 0.
|
</li>
|
||||||
|
<li> <span style='font-weight:700'>a level</span>
|
||||||
|
- shows an audio trigger if an audio level exceeded the configured
|
||||||
|
audio_trigger_level value.
|
||||||
|
If there was only an audio trigger, then the overall
|
||||||
|
motion frame vector 'f' line will show a zero vector.
|
||||||
|
</li>
|
||||||
|
<li> <span style='font-weight:700'>e code</span>
|
||||||
|
- shows there was an external trigger (motion trigger command into the
|
||||||
|
FIFO). The code will either be "FIFO" or a custom code supplied in
|
||||||
|
the external trigger command.
|
||||||
|
If there was only an external trigger, then the overall
|
||||||
|
motion frame vector 'f' line will show a zero vector.
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
The end tag is written when the motion video ends.
|
The end tag is written when the motion video ends.
|
||||||
</div
|
</div>
|
||||||
<a name="MULTICAST_INTERFACE">
|
|
||||||
|
<a name="MOTION_EVENTS_FIFO">
|
||||||
|
<span style='font-size: 1.5em; font-weight: 650;'>Motion Detects FIFO</span><hr>
|
||||||
|
<div class='indent0'>
|
||||||
|
<span style='font-size: 1.2em; font-weight:700'>~/pikrellcam/www/motion_detects_FIFO</span>
|
||||||
|
<p>
|
||||||
|
This named pipe fifo is for near real time processing of all PiKrellCam
|
||||||
|
motion detects regardless of motion recording enabled state and so
|
||||||
|
can be a general purpose motion detect front end interface for a user
|
||||||
|
application with its own motion detect policy. If motion video recordings are
|
||||||
|
enabled and there is a configured non-zero confirm gap, then this fifo will
|
||||||
|
report motion events that do not trigger a motion video if the second
|
||||||
|
confirming motion detect required for video recordings did not happen.
|
||||||
|
<p>
|
||||||
|
This fifo is not intended for use by an on_motion_begin command.
|
||||||
|
See the
|
||||||
|
<nobr><span style='font-weight:700'>/run/pikrellcam/motion-events</span></nobr>
|
||||||
|
file section above for motion detect processing on a per motion record event
|
||||||
|
basis via an on_motion_begin command.
|
||||||
|
<p>
|
||||||
|
To enable or disable writing all motion detects to the motion_detects_FIFO,
|
||||||
|
send to the command FIFO:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
echo "motion_detects_fifo_enable [on|off|toggle]" > ~/pikrellcam/www/FIFO
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Motion detect data blocks are written to the motion_detects_FIFO in the same
|
||||||
|
format as is written into the
|
||||||
|
<nobr><span style='font-weight:700'>/run/pikrellcam/motion-events</span></nobr>
|
||||||
|
file as described above except that the time in the motion tag will be
|
||||||
|
the current system time in seconds (with .1 second precision) instead of
|
||||||
|
the time elapsed into a video.
|
||||||
|
Also this is a continuous stream of motion blocks with no header blocks
|
||||||
|
written.
|
||||||
|
If the motion_detects_FIFO reading app needs any information other than
|
||||||
|
motion detects, it should read the
|
||||||
|
<nobr><span style='font-weight:700'>/run/pikrellcam/state</span></nobr>
|
||||||
|
file.
|
||||||
|
<p>
|
||||||
|
If the enable is "on" it will stay enabled across pikrellcam
|
||||||
|
restarts until an "off" command or pikrellcam.conf is edited. Once enabled,
|
||||||
|
pikrellcam tries to write all motion detects into the motion_detects_FIFO
|
||||||
|
and an external app can read the detects from the motion_detects_FIFO.
|
||||||
|
The external app can be started by hand, by a command in the
|
||||||
|
at-commands.conf file, or by cron.
|
||||||
|
<br>
|
||||||
|
When a "motion_detects_fifo_enable off" command is sent to the command FIFO,
|
||||||
|
an <off> tag is written to the motion_detects_FIFO so the user app can
|
||||||
|
know the motion_detects_fifo_enable has been turned off.
|
||||||
|
<p>
|
||||||
|
Read the example script
|
||||||
|
<span style='font-weight:700'>~/pikrellcam/scripts-dist/example-motion-detects-fifo</span>
|
||||||
|
for more information. If this script is run by hand from a terminal,
|
||||||
|
a stream of all motion detects is printed.
|
||||||
|
<p>
|
||||||
|
To test the example script on a Pi running pikrellcam, open a terminal
|
||||||
|
(SSH terminal if the Pi is headless) and run the example script:<br>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
$ ~/pikrellcam/scripts-dist/example-motion-detects-fifo
|
||||||
|
# The script enables motion_detects_FIFO and motion detects are printed here.
|
||||||
|
# Terminate the script with ^C or send an off command in another termial:
|
||||||
|
# $ echo "motion_detects_fifo_enable off" > ~/pikrellcam/www/FIFO
|
||||||
|
</pre>
|
||||||
|
Commands in at-commands.conf can coordinate times when you want
|
||||||
|
PiKrellCam to have motion recordings and times when you might want to run
|
||||||
|
a custom motion detect app that reads from the motion_detects_FIFO.
|
||||||
|
As is done in the example-motion-detects-fifo script, your app can enable
|
||||||
|
the motion_detects_FIFO or it can be enabled with an at-commands.conf command
|
||||||
|
before or after your script starts.
|
||||||
|
And an at-command can turn the motion_detects_FIFO off at a certain time
|
||||||
|
if you want to signal your app to self terminate.
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a name="MULTICAST_INTERFACE">
|
<a name="MULTICAST_INTERFACE">
|
||||||
<span style='font-size: 1.5em; font-weight: 650;'>Multicast Interface</span><hr>
|
<span style='font-size: 1.5em; font-weight: 650;'>Multicast Interface</span><hr>
|
||||||
<div class='indent0'>
|
<div class='indent0'>
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 25 KiB |
|
@ -421,9 +421,13 @@ echo "<span style=\"color: $default_text_color\"> Enable:</span>";
|
||||||
<td>
|
<td>
|
||||||
<?php echo "<span style=\"font-weight:600; color: $default_text_color\">Config</span>"; ?>
|
<?php echo "<span style=\"font-weight:600; color: $default_text_color\">Config</span>"; ?>
|
||||||
<div>
|
<div>
|
||||||
<input type="button" value="Video Res"
|
<input type="button" value="Motion"
|
||||||
class="btn-menu"
|
class="btn-menu"
|
||||||
style="margin-left:40px"
|
style="margin-left:40px"
|
||||||
|
onclick="fifo_command('display motion_settings');"
|
||||||
|
>
|
||||||
|
<input type="button" value="Video Res"
|
||||||
|
class="btn-menu"
|
||||||
onclick="fifo_command('display video_presets');"
|
onclick="fifo_command('display video_presets');"
|
||||||
>
|
>
|
||||||
<input type="button" value="Still Res"
|
<input type="button" value="Still Res"
|
||||||
|
@ -434,10 +438,6 @@ echo "<span style=\"color: $default_text_color\"> Enable:</span>";
|
||||||
class="btn-menu"
|
class="btn-menu"
|
||||||
onclick="fifo_command('display settings');"
|
onclick="fifo_command('display settings');"
|
||||||
>
|
>
|
||||||
<input type="button" value="Times"
|
|
||||||
class="btn-menu"
|
|
||||||
onclick="fifo_command('display motion_time');"
|
|
||||||
>
|
|
||||||
<input type="button" value="Loop"
|
<input type="button" value="Loop"
|
||||||
class="btn-menu"
|
class="btn-menu"
|
||||||
onclick="fifo_command('display loop_settings');"
|
onclick="fifo_command('display loop_settings');"
|
||||||
|
|
Loading…
Reference in New Issue