#include #include #include #include #include #include "sia.h" #include "email.h" #include "mqtt.h" #include "util.h" 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); 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, 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 */ static char account[SIA_MAX_DATA_LENGTH + 1]; static char event[SIA_MAX_DATA_LENGTH + 1]; static char ascii[SIA_MAX_DATA_LENGTH + 1]; unsigned len = sia_data_length (b); if (sia_ack_if_needed (fd, b)) return -1; switch (b->function) { case SIA_FN_ACCOUNT_ID: memcpy (account, b->data, len); account[len] = 0; break; case SIA_FN_NEW_EVENT: case SIA_FN_OLD_EVENT: memcpy (event, b->data, len); event[len] = 0; if (!have_ascii_messages) msg (account, event, "", log, email, state_file, mqtt_host); break; case SIA_FN_ASCII: have_ascii_messages = 1; memcpy (ascii, b->data, len); ascii[len] = 0; msg (account, event, ascii, log, email, state_file, mqtt_host); break; } return 0; } void periodic_task (void) { }