From 338dcccc8d8532a446fa60dc65092b5510c06e3a Mon Sep 17 00:00:00 2001 From: root Date: Sat, 9 Apr 2022 11:57:42 +0100 Subject: various improvements --- Makefile | 26 ++++++---- email.c | 51 +----------------- net_rx.c | 23 ++++++-- rx.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- serial_rx.c | 26 +++++++--- sia.c | 1 + util.c | 66 +++++++++++++++++++++++ util.h | 2 + 8 files changed, 290 insertions(+), 75 deletions(-) diff --git a/Makefile b/Makefile index b55dec5..99f1d77 100644 --- a/Makefile +++ b/Makefile @@ -3,12 +3,15 @@ PKG_CONFIG=pkg-config CURSES_CFLAGS=$(shell ${PKG_CONNFIG} --cflags ncursesw) CURSES_LIBS=$(shell ${PKG_CONFIG} --libs ncursesw) -#OPENWRT_BASE=/root/projects/openwrt/gl-inet-mt300n-v2/master-d20f4fc -#TOOLCHAIN=${OPENWRT_BASE}/staging_dir/toolchain-mipsel_24kc_gcc-7.3.0_musl -#CC=${TOOLCHAIN}/bin/mipsel-openwrt-linux-musl-gcc -#STAGING_DIR=${OPENWRT_BASE}/staging_dir/target-mipsel_24kc_musl -#export STAGING_DIR -#CFLAGS=-I${STAGING_DIR}/include -I${TOOLS_DIR}/include +ifeq (${STAGING_DIR},) + OPENWRT_BASE=/root/projects/openwrt/gl-inet-mt300n-v2/master-d20f4fc + TOOLCHAIN=${OPENWRT_BASE}/staging_dir/toolchain-mipsel_24kc_gcc-7.3.0_musl + CC=${TOOLCHAIN}/bin/mipsel-openwrt-linux-musl-gcc + STAGING_DIR:=${OPENWRT_BASE}/staging_dir/target-mipsel_24kc_musl + export STAGING_DIR + CFLAGS=-I${STAGING_DIR}/include -I${TOOLS_DIR}/include + LDFLAGS= +endif PROGS=net_rx net_arm serial_rx serial_arm serial_keypad net_keypad #test_email @@ -20,9 +23,9 @@ install: ${PROGS} mkdir -p ${DESTDIR}/${PREFIX}/bin for i in ${PROGS}; do install -m 755 $$i ${DESTDIR}/${PREFIX}/bin/$$i; done -net_rx:util.o sia.o net_rx.o rx.o email.o -net_arm:util.o sia.o net_arm.o arm.o -serial_rx:util.o sia.o serial_rx.o rx.o email.o +net_rx:util.o sia.o net_rx.o rx.o email.o mqtt.o +net_arm:util.o sia.o net_arm.o arm.o +serial_rx:util.o sia.o serial_rx.o rx.o email.o mqtt.o serial_arm:util.o sia.o serial_arm.o arm.o test_email:test_email.o email.o @@ -37,3 +40,8 @@ tidy: clean: /bin/rm -f *.o + +deploy: + rsync net_rx galaxy:/usr/bin/net_rx + ssh galaxy killall net_rx + ssh galaxy killall sleep diff --git a/email.c b/email.c index 0ee47ff..7374c34 100644 --- a/email.c +++ b/email.c @@ -8,60 +8,11 @@ #include +#include "util.h" #include "email.h" -static int daemonish (int nochdir, int noclose) -{ - pid_t pid; - int status; - - if (!nochdir && chdir ("/")) - return -1; - - if (!noclose) { - int fd, failed = 0; - - if ((fd = open ("/dev/null", O_RDWR)) < 0) return -1; - - if (dup2 (fd, 0) < 0 || dup2 (fd, 1) < 0 || dup2 (fd, 2) < 0) - failed++; - - if (fd > 2) close (fd); - - if (failed) return -1; - } - - switch ((pid = fork())) { - case 0: - break; - - case -1: - return -1; - - default: - waitpid (pid, &status, 0); - return 1;; - } - - if (setsid() < 0) return -1; - - switch (fork()) { - case 0: - break; - - case -1: - return -1; - - default: - _exit (0); - } - - return 0; -} - - static void write_complete (int fd, const void *_buf, size_t len) { ssize_t writ; diff --git a/net_rx.c b/net_rx.c index 15e181b..7bcc01e 100644 --- a/net_rx.c +++ b/net_rx.c @@ -10,13 +10,14 @@ #include "util.h" #include "sia.h" -extern int new_block (int fd, SIA_Block *b, int log, const char *email); +extern int new_block (int fd, SIA_Block *b, int log, const char *email, const char *state_file, const char *mqtt_host); extern void periodic_task (void); +extern void dump_state (const char *); static int usage (const char *name) { fprintf (stderr, "Usage:\n"); - fprintf (stderr, "%s [ -l ] [ -p listen_port ] [ -m email address]\n\n", name); + fprintf (stderr, "%s [ -l ] [ -p listen_port ] [ -e email address] [ -s state_file ] [ -m mqtt_host ]\n\n", name); fprintf (stderr, "listen_port defaults to 10002\n"); return 1; @@ -39,9 +40,11 @@ int main (int argc, char *argv[]) unsigned ptr = 0; const char *email = NULL; + const char *state_file = NULL; + const char *mqtt_host = NULL; - while ((opt = getopt (argc, argv, "p:lm:")) != -1) { + while ((opt = getopt (argc, argv, "p:le:s:m:")) != -1) { switch (opt) { case 'p': port = atoi (optarg); @@ -51,10 +54,18 @@ int main (int argc, char *argv[]) log++; break; - case 'm': + case 'e': email = optarg; break; + case 's': + state_file = optarg; + break; + + case 'm': + mqtt_host = optarg; + break; + default: /* '?' */ return usage (argv[0]); } @@ -72,6 +83,8 @@ int main (int argc, char *argv[]) set_blocking (fd); + if (state_file) + dump_state (state_file); // Epically budget TCP server @@ -123,7 +136,7 @@ int main (int argc, char *argv[]) break; default: /*Valid block */ - new_block (afd, &b, log, email); + new_block (afd, &b, log, email, state_file, mqtt_host); ptr = 0; break; } diff --git a/rx.c b/rx.c index 427dcd3..7f39d6d 100644 --- a/rx.c +++ b/rx.c @@ -6,33 +6,191 @@ #include "sia.h" #include "email.h" +#include "mqtt.h" +#include "util.h" -static void msg (char *account, char *event, char *ascii, int log, const char *email) + +typedef struct thing_struct { + struct thing_struct *next; + char *msg; + unsigned seq; +} Thing; + +static Thing *thing_list = NULL; + +void dump_state (const char *file) +{ + Thing *thing; + FILE *f; + char fn[1024]; + + strcpy (fn, file); + strcat (fn, ".next"); + + f = fopen (fn, "w"); + + if (!f) return; + + for (thing = thing_list; thing; thing = thing->next) { + fprintf (f, "%d ", thing->seq); + fputs (thing->msg, f); + fputc ('\n', f); + } + + fclose (f); + + rename (fn, file); +} + + +static void maintain_state (const char *msg, const char *state_file) +{ + Thing *thing; + + + switch (*msg) { + case '+': + case '-': + break; + + default: + return; + } + + + for (thing = thing_list; thing; thing = thing->next) { + + if (!strcmp (&msg[1], &thing->msg[1])) { + strcpy (thing->msg, msg); + dump_state (state_file); + return; + } + } + + thing = malloc (sizeof (Thing)); + thing->next = thing_list; + thing->msg = strdup (msg); + thing->seq = 1; + + thing_list = thing; + + dump_state (state_file); +} + + + +static void send_mqtt (const char *msg, const char *host) +{ + char value[1024]; + char topic[1024]; + char prefix[] = "stat/alarm/"; + const char *rptr; + char *wptr; + int retain = 0; + + + if (!host) return; + + + switch (*msg) { + case '+': + case '-': + retain = 1; + break; + } + + + + for (rptr = msg, wptr = value; (*rptr) && ((*rptr) != ' '); rptr++, wptr++) + *wptr = *rptr; + + if (!*rptr) return; + + *wptr = 0; + + while (*rptr == ' ') rptr++; + + strcpy (topic, prefix); + + wptr = topic + (sizeof (prefix) - 1); + + if (!*rptr) + strcpy (wptr, value + 1); + + else { + for (; *rptr; rptr++, wptr++) { + if (local_isalnum (*rptr)) + *wptr = *rptr; + + else + *wptr = '_'; + } + + *wptr = 0; + } + + mqtt (host, topic, value, retain); + +#if 0 + /* JMM and an ugly hack */ + + if (!strcmp (topic, "stat/alarm/Rain_Sensor")) { + if (value[0] == '+') + mqtt (host, "cmnd/vent/POWER1", "0", 0); + + else if (value[0] == '-') + mqtt (host, "cmnd/vent/POWER1", "1", 0); + } + +#endif +} + +static void msg (char *account, char *event, char *ascii, int log, const char *email, const char *state_file, const char *mqtt_host) { char body[256]; char subject[256]; + if (state_file) + maintain_state (ascii, state_file); + + if (strstr (ascii, "FULL SET")) + send_mqtt ("+ARMED SYSTEM", mqtt_host); + + else if (strstr (ascii, "UNSET")) + send_mqtt ("-ARMED SYSTEM", mqtt_host); + + else + send_mqtt (ascii, mqtt_host); + snprintf (body, sizeof (body) - 1, "%s %64s %s", account, event, ascii); body[sizeof (body) - 1] = 0; if (log) syslog (LOG_WARNING, "SIA: %s", body); - printf ("%s\n", body); if (!email) return; if (strstr (body, "HEARTBT")) return; + if (strstr (body, "Valid")) return; + + if (strstr (body, "Rejct")) return; + + if (strstr (body, "CUSTOM")) return; + + if (strstr (body, "LOG")) return; + + snprintf (subject, sizeof (subject) - 1, "Galaxy SIA: %s", ascii); send_email (email, subject, body); } -int new_block (int fd, SIA_Block *b, int log, const char *email) +int new_block (int fd, SIA_Block *b, int log, const char *email, const char *state_file, const char *mqtt_host) { static int have_ascii_messages = 0; /*SIA level 3 doesn't have ascii, SIA level 4 does */ @@ -56,7 +214,7 @@ int new_block (int fd, SIA_Block *b, int log, const char *email) memcpy (event, b->data, len); event[len] = 0; - if (!have_ascii_messages) msg (account, event, "", log, email); + if (!have_ascii_messages) msg (account, event, "", log, email, state_file, mqtt_host); break; @@ -65,7 +223,7 @@ int new_block (int fd, SIA_Block *b, int log, const char *email) memcpy (ascii, b->data, len); ascii[len] = 0; - msg (account, event, ascii, log, email); + msg (account, event, ascii, log, email, state_file, mqtt_host); break; } @@ -77,3 +235,5 @@ void periodic_task (void) } + + diff --git a/serial_rx.c b/serial_rx.c index 6165a01..340420b 100644 --- a/serial_rx.c +++ b/serial_rx.c @@ -9,14 +9,15 @@ #include "sia.h" -extern int new_block (int fd, SIA_Block *b, int log, const char *email); +extern int new_block (int fd, SIA_Block *b, int log, const char *email, const char *state_file, const char *mqtt_host); +extern void dump_state (const char *); //extern void periodic_task(void); static int usage (const char *name) { fprintf (stderr, "Usage:\n"); - fprintf (stderr, "%s [ -l ] [ -b baud ] -p serial_device [ -m email address ]\n\n", name); + fprintf (stderr, "%s [ -l ] [ -b baud ] -p serial_device [ -e email address ] [ -s state_file ] [ -m mqtt_host ]\n\n", name); fprintf (stderr, "baud defaults to 9600\n"); return 1; @@ -32,13 +33,15 @@ int main (int argc, char *argv[]) SIA_Block b; ssize_t red; int log = 0; - const char *email = NULL; unsigned char buf[SIA_MAX_BLOCK_LENGTH]; unsigned ptr = 0; + const char *email = NULL; + const char *state_file = NULL; + const char *mqtt_host = NULL; - while ((opt = getopt (argc, argv, "p:b:lm:")) != -1) { + while ((opt = getopt (argc, argv, "p:b:le:s:m:")) != -1) { switch (opt) { case 'p': port = optarg; @@ -48,10 +51,18 @@ int main (int argc, char *argv[]) baud = atoi (optarg); break; - case 'm': + case 'e': email = optarg; break; + case 's': + state_file = optarg; + break; + + case 'm': + mqtt_host = optarg; + break; + case 'l': log++; break; @@ -73,6 +84,9 @@ int main (int argc, char *argv[]) set_blocking (fd); + if (state_file) + dump_state (state_file); + for (;;) { red = read (fd, &buf[ptr], 1); @@ -95,7 +109,7 @@ int main (int argc, char *argv[]) break; default: /*Valid block */ - new_block (fd, &b, log, email); + new_block (fd, &b, log, email, state_file, mqtt_host); ptr = 0; break; } diff --git a/sia.c b/sia.c index 3c47c8b..6047117 100644 --- a/sia.c +++ b/sia.c @@ -228,6 +228,7 @@ int sia_login (int fd, SIA_Block *b) { const char *pin = "543210"; //JMM: Oh yes! and there's no way to change it from the panel, you need the £3k bit of software to do that + b->reverse_channel = 0; b->request_ack = 1; b->function = SIA_FN_REMOTE_LOGIN; diff --git a/util.c b/util.c index 21c1eb9..052b382 100644 --- a/util.c +++ b/util.c @@ -8,6 +8,7 @@ #include #include #include +#include @@ -296,6 +297,7 @@ int open_tcp_client (const char *host, unsigned port) if (fd < 0) return -1; + sin.sin_port = htons (port); if (connect (fd, (struct sockaddr *)&sin, sizeof (sin))) { @@ -339,3 +341,67 @@ int open_tcp_server (unsigned port) +int daemonish (int nochdir, int noclose) +{ + pid_t pid; + int status; + + if (!nochdir && chdir ("/")) + return -1; + + if (!noclose) { + int fd, failed = 0; + + if ((fd = open ("/dev/null", O_RDWR)) < 0) return -1; + + if (dup2 (fd, 0) < 0 || dup2 (fd, 1) < 0 || dup2 (fd, 2) < 0) + failed++; + + if (fd > 2) close (fd); + + if (failed) return -1; + } + + switch ((pid = fork())) { + case 0: + break; + + case -1: + return -1; + + default: + waitpid (pid, &status, 0); + return 1;; + } + + if (setsid() < 0) return -1; + + switch (fork()) { + case 0: + break; + + case -1: + return -1; + + default: + _exit (0); + } + + return 0; +} + + +int local_isalnum (char c) +{ + if ((c >= '0') && (c <= '9')) return 1; + + if ((c >= 'A') && (c <= 'Z')) return 1; + + if ((c >= 'a') && (c <= 'z')) return 1; + + return 0; +} + + + + diff --git a/util.h b/util.h index 55f6e38..aadab9c 100644 --- a/util.h +++ b/util.h @@ -10,5 +10,7 @@ extern int fd_drain (int fd); extern int open_tty (const char *path, int baud); extern int open_tcp_client (const char *host, unsigned port); extern int open_tcp_server (unsigned port); +extern int daemonish (int nochdir, int noclose); +extern int local_isalnum (char c); #endif /* _util_h_ */ -- cgit v1.2.3