Skip to content
Snippets Groups Projects
Commit c582512b authored by clohr's avatar clohr
Browse files

Un détecteur de mouvements xAAL a bas cout

git-svn-id: https://redmine.imt-atlantique.fr/svn/xaal/code/C/trunk@867 b32b6428-25c9-4566-ad07-03861ab6144f
parent 9282459c
Branches
No related tags found
No related merge requests found
PROG = generic-sender
CFLAGS = -Wall -I. -g
LDFLAGS = -ljson-c -luuid -L. -lxaal
SHELL = /bin/bash
all: $(PROG)
clean:
-rm -f *.o *~
proper: clean
-rm -f $(PROG)
test: $(PROG)
-rm -f ./generic-sender.pipe
-LD_LIBRARY_PATH+=:. ./generic-sender -a 224.0.29.200 -p 1234 -P ./generic-sender.pipe -D motion_sensor.basic &
-trap 'killall generic-sender' SIGINT; motion -c ./motion.conf
Makefile.dep: $(PROG).c
$(CC) $(CFLAGS) -MM $^ > $@
include Makefile.dep
generic-sender.o: generic-sender.c xaal.h
## generic-sender
This is a dummy xAAL device.
It waits for (json) data on a named unix pipe.
Then it sends those data on the xAAL bus via attributesChange notifications.
It also can reply to getAttributes request with the last known data and the associated date.
* Motion
To be hosnest, this small xAAL device was designed to work with "motion"
http://www.lavrsen.dk/foswiki/bin/view/Motion/WebHome
Motion is a program that monitors one or many local or remote webcams and detect motions on pictures.
It then can record frames, movies, log events on databases, etc.
Among those functionnalities, it can execute a command when it detects motions.
I propose to use this.
For instance, let's start "motion" and "generic-sender" in parallel.
Le's "./generic-sender.pipe" be the named pipe listened by generic-sender
The config file of motion could contain:
on_event_start echo '{"motion":"start"}' > ./generic-sender.pipe
on_event_end echo '{"motion":"end"}' > ./generic-sender.pipe
on_motion_detected echo '{"motion":"detected"}' > ./generic-sender.pipe
See "motion.conf" for details.
Finally, one get a powerfull xAAL motion sensor without efforts.
File added
/* xAAL generic-sender
* (c) 2015 Christophe Lohr <christophe.lohr@telecom-bretagne.eu>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <json-c/json.h>
#include <uuid/uuid.h>
#include <xaal.h>
#define ALIVE_PERIOD 60
/* setup device info */
xAAL_devinfo_t device = { .devType = "basic.basic",
.alivemax = 2 * ALIVE_PERIOD,
.vendorId = "Team IHSEV",
.productId = "Dummy generic-sender device",
.version = "0.1",
.parent = xAAL_UUID0,
.url = "http://recherche.telecom-bretagne.eu/xaal/documentation/",
.info = NULL,
.unsupportedAttributes = NULL,
.unsupportedMethods = NULL,
.unsupportedNotifications = NULL
};
char *pipe_name = "generic-sender.pipe";
int fd_pipe = -1;
xAAL_businfo_t bus;
void alive_sender(int sig) {
if ( !xAAL_notify_alive(&bus, &device) )
fprintf(xAAL_error_log, "Could not send spontaneous alive notification.\n");
alarm(ALIVE_PERIOD);
}
bool reply_getAttributes(const xAAL_businfo_t *bus,
const xAAL_devinfo_t *device,
const char *target,
struct json_object *attribute,
time_t date) {
struct json_object *jbody;
jbody = json_object_get(attribute);
json_object_object_add(jbody, "date", json_object_new_int64(date));
return xAAL_write_busl(bus, device, "reply", "getAttributes", jbody, target, NULL);
}
bool send_attribute(const xAAL_businfo_t *bus,
const xAAL_devinfo_t *device,
struct json_object *attribute) {
struct json_object *jbody;
jbody = json_object_get(attribute);
return xAAL_write_busl(bus, device, "notify", "attributesChange", jbody, NULL);
}
/* Manage received xAAL message */
void manage_msg(const xAAL_businfo_t *bus, xAAL_devinfo_t *device, struct json_object *attribute, time_t date) {
struct json_object *jmsg, *jtargets;
const char *version, *source, *msgType, *devType, *action,
*cipher, *signature;
time_t timestamp;
/* Recive a message */
if (!xAAL_read_bus(bus, &jmsg, &version, &source, &jtargets, &msgType,
&devType, &action, &cipher, &signature, &timestamp))
return;
if ( !xAAL_targets_match(jtargets, device->addr) ) {
/* This is not for me */
json_object_put(jmsg);
return;
}
if (strcmp(msgType, "request") == 0) {
if ( (strcmp(action, "isAlive") == 0)
&& xAAL_isAliveDevType_match(jmsg, device->devType) ) {
if ( !xAAL_notify_alive(bus, device) )
fprintf(xAAL_error_log, "Could not reply to isAlive\n");
} else if ( strcmp(action, "getDescription") == 0 ) {
if ( !xAAL_reply_getDescription(bus, device, source) )
fprintf(xAAL_error_log, "Could not reply to getDescription\n");
} else if ( strcmp(action, "getAttributes") == 0 ) {
if ( !reply_getAttributes(bus, device, source, attribute, date) )
fprintf(xAAL_error_log, "Could not reply to getAttributes\n");
} else if ( strcmp(action, "getBusConfig") == 0 ) {
if ( !xAAL_reply_getBusConfig(bus, device, source) )
fprintf(xAAL_error_log, "Could not reply to getBusConfig\n");
} else if ( strcmp(action, "setBusConfig") == 0 ) {
if ( !xAAL_reply_setBusConfig(bus, device, source) )
fprintf(xAAL_error_log, "Could not reply to setBusConfig\n");
} else if ( strcmp(action, "getCiphers") == 0 ) {
if ( !xAAL_reply_getCiphers(bus, device, source) )
fprintf(xAAL_error_log, "Could not reply to getCiphers\n");
} else if ( strcmp(action, "setCiphers") == 0 ) {
if ( !xAAL_reply_setCiphers(bus, device, source) )
fprintf(xAAL_error_log, "Could not reply to setCiphers\n");
}
}
json_object_put(jmsg);
}
/* Manage received message on the pipe */
void manage_pipe(int fd_pipe, const xAAL_businfo_t *bus, xAAL_devinfo_t *device, struct json_object *attribute, time_t *date) {
static char buf[xAAL_BUF_SIZE];
ssize_t nread;
struct json_tokener *tok;
enum json_tokener_error jerr;
struct json_object *jpipe;
nread = read(fd_pipe, buf, xAAL_BUF_SIZE);
if (nread == -1)
return;
/* Use the json-c library */
tok = json_tokener_new();
jpipe = json_tokener_parse_ex(tok, buf, nread);
jerr = json_tokener_get_error(tok);
json_tokener_free(tok);
if (jerr != json_tokener_success) {
// printf("JSON error: %s\n", json_tokener_error_desc(jerr));
return;
}
if (json_object_is_type(jpipe, json_type_object)) {
json_object_put(attribute);
attribute = json_object_get(jpipe);
time(date);
if (!send_attribute(bus, device, attribute))
fprintf(xAAL_error_log, "Could not send attributesChange\n");
}
json_object_put(jpipe);
}
/* Called at exit */
void terminate() {
close(fd_pipe);
unlink(pipe_name);
}
/* Handler for Ctrl-C &co. */
void cancel(int s) {
terminate();
exit(EXIT_SUCCESS);
}
/* main */
int main(int argc, char **argv) {
int opt;
char *addr=NULL, *port=NULL;
uuid_t uuid;
int hops = -1;
bool arg_error = false;
struct json_object *attribute = json_object_new_object();
time_t date;
struct sigaction act_alarm;
fd_set rfds, rfds_;
int fd_max;
xAAL_error_log = stderr;
uuid_clear(uuid);
/* Parse cmdline arguments */
while ((opt = getopt(argc, argv, "a:p:h:u:P:D:")) != -1) {
switch (opt) {
case 'a':
addr = optarg;
break;
case 'p':
port = optarg;
break;
case 'h':
hops = atoi(optarg);
break;
case 'u':
if ( uuid_parse(optarg, uuid) == -1 ) {
fprintf(stderr, "Warning: invalid uuid '%s'\n", optarg);
uuid_clear(uuid);
} else
strcpy(device.addr, optarg);
break;
case 'P':
pipe_name = optarg;
break;
case 'D':
device.devType = optarg;
break;
default: /* '?' */
arg_error = true;
}
}
if (optind < argc) {
fprintf(stderr, "Unknown argument %s\n", argv[optind]);
arg_error = true;
}
if (!addr || !port || arg_error) {
fprintf(stderr, "Usage: %s -a <addr> -p <port> [-h <hops>] [-u <uuid>] [-P <pipe name>] [-D <devType>]\n",
argv[0]);
exit(EXIT_FAILURE);
}
/* Make named pipe */
if (mkfifo(pipe_name, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
perror("mkfifo");
exit(EXIT_FAILURE);
}
atexit(terminate);
fd_pipe = open(pipe_name, O_RDWR);
if (fd_pipe < 0) {
perror("open pipe");
exit(EXIT_FAILURE);
}
/* Manage Ctrl-C &co. */
signal(SIGHUP, cancel);
signal(SIGINT, cancel);
signal(SIGQUIT, cancel);
signal(SIGTERM, cancel);
/* Join the xAAL bus */
if ( !xAAL_join_bus(addr, port, hops, 1, &bus) )
exit(EXIT_FAILURE);
/* Generate device address if needed */
if ( uuid_is_null(uuid) ) {
uuid_generate(uuid);
uuid_unparse(uuid, device.addr);
printf("Device: %s\n", device.addr);
}
/* Manage alive notifications */
act_alarm.sa_handler = alive_sender;
act_alarm.sa_flags = ~SA_RESETHAND;
sigemptyset(&act_alarm.sa_mask);
sigaction(SIGALRM, &act_alarm, NULL);
alarm(ALIVE_PERIOD);
if ( !xAAL_notify_alive(&bus, &device) )
fprintf(xAAL_error_log, "Could not send initial alive notification.\n");
FD_ZERO(&rfds);
FD_SET(fd_pipe, &rfds);
fd_max = fd_pipe;
FD_SET(bus.sfd, &rfds);
fd_max = (fd_max > bus.sfd)? fd_max : bus.sfd;
/* Main loop */
for (;;) {
rfds_ = rfds;
if ( (select(fd_max+1, &rfds_, NULL, NULL, NULL) == -1) && (errno != EINTR) )
fprintf(xAAL_error_log, "select(): %s\n", strerror(errno));
if (FD_ISSET(bus.sfd, &rfds_))
manage_msg(&bus, &device, attribute, date);
if (FD_ISSET(fd_pipe, &rfds_))
manage_pipe(fd_pipe, &bus, &device, attribute, &date);
}
}
File added
../libxaal/libxaal.so
\ No newline at end of file
# Start in daemon (background) mode and release terminal (default: off)
daemon off
# Level of log messages [1..9] (EMR, ALR, CRT, ERR, WRN, NTC, INF, DBG, ALL). (default: 6 / NTC)
log_level 6
# Filter to log messages by type (COR, STR, ENC, NET, DBL, EVT, TRK, VID, ALL). (default: ALL)
log_type all
# Videodevice to be used for capturing (default /dev/video0)
videodevice /dev/video0
# Image width (pixels). Valid range: Camera dependent, default: 352
width 320
# Image height (pixels). Valid range: Camera dependent, default: 288
height 240
# Maximum number of frames to be captured per second.
# Valid range: 2-100. Default: 100 (almost no limit).
framerate 2
# Event Gap is the seconds of no motion detection that triggers the end of an event.
# An event is defined as a series of motion images taken within a short timeframe.
# Recommended value is 60 seconds (Default). The value -1 is allowed and disables
# events causing all Motion to be written to one single movie file and no pre_capture.
# If set to 0, motion is running in gapless mode. Movies don't have gaps anymore. An
# event ends right after no more motion is detected and post_capture is over.
; event_gap 60
event_gap 0
# Output 'normal' pictures when motion is detected (default: on)
# Valid values: on, off, first, best, center
output_pictures off
# Use ffmpeg to encode movies in realtime (default: off)
ffmpeg_output_movies off
# The mini-http server listens to this port for requests (default: 0 = disabled)
; stream_port 8081
stream_port 0
# TCP/IP port for the http server to listen on (default: 0 = disabled)
; webcontrol_port 8082
webcontrol_port 0
# Command to be executed when an event starts. (default: none)
# An event starts at first motion detected after a period of no motion defined by event_gap
; on_event_start value
on_event_start echo '{"motion":"start"}' > ./generic-sender.pipe
# Command to be executed when an event ends after a period of no motion
# (default: none). The period of no motion is defined by option event_gap.
; on_event_end value
on_event_end echo '{"motion":"end"}' > ./generic-sender.pipe
# Command to be executed when a motion frame is detected (default: none)
; on_motion_detected value
on_motion_detected echo '{"motion":"detected"}' > ./generic-sender.pipe
../libxaal/xaal.h
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment