# HG changeset patch # User Michiel Broek # Date 1400441095 -7200 # Node ID f534ace74eea99fba4db16c4e020cc3577275769 # Parent dafbbd5e99227b89bf7083a130846a2f58784c3e Code preparation for client/server communication diff -r dafbbd5e9922 -r f534ace74eea configure --- a/configure Sat May 17 23:06:39 2014 +0200 +++ b/configure Sun May 18 21:24:55 2014 +0200 @@ -2028,7 +2028,7 @@ ac_config_headers="$ac_config_headers config.h" -SUBDIRS="lib coolers dht11 rc433 thermometers" +SUBDIRS="lib dht11 rc433 thermferm thermometers" PACKAGE="mbsePi-apps" diff -r dafbbd5e9922 -r f534ace74eea configure.ac --- a/configure.ac Sat May 17 23:06:39 2014 +0200 +++ b/configure.ac Sun May 18 21:24:55 2014 +0200 @@ -2,7 +2,7 @@ AC_INIT(thermometers/main.c) AM_CONFIG_HEADER(config.h) -SUBDIRS="lib coolers dht11 rc433 thermometers" +SUBDIRS="lib dht11 rc433 thermferm thermometers" AC_SUBST(SUBDIRS) dnl General settings diff -r dafbbd5e9922 -r f534ace74eea coolers/Makefile --- a/coolers/Makefile Sat May 17 23:06:39 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -# Makefile for the mbsePi-apps/coolers. - -include ../Makefile.global - -SRCS = $(wildcard *.c) -HDRS = $(wildcard *.h) -OBJS = $(SRCS:.c=.o) -SLIBS = -lpthread ../lib/libmbse.a -TARGET = coolers -OTHER = Makefile - -############################################################################# - -.c.o: - ${CC} ${CFLAGS} ${INCLUDES} ${DEFINES} -c $< - -all: ${TARGET} - -coolers: ${OBJS} ${SLIBS} - ${CC} -o coolers ${OBJS} ${LDFLAGS} ${LIBS} ${SLIBS} - -clean: - rm -f ${TARGET} *.o *.h~ *.c~ core filelist Makefile.bak - -install: all - ${INSTALL} -c -s -g root -o root -m 0755 thermometers ${BINDIR} - -filelist: Makefile - BASE=`pwd`; \ - BASE=`basename $${BASE}`; \ - (for f in ${SRCS} ${HDRS} ${OTHER} ;do echo ${PACKAGE}-${VERSION}/$${BASE}/$$f; done) >filelist - -depend: - @rm -f Makefile.bak; \ - mv Makefile Makefile.bak; \ - sed -e '/^# DO NOT DELETE/,$$d' Makefile.bak >Makefile; \ - ${ECHO} '# DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT' \ - >>Makefile; \ - ${ECHO} '# Dependencies generated by make depend' >>Makefile; \ - for f in ${SRCS}; \ - do \ - ${ECHO} "Dependencies for $$f:\c"; \ - ${ECHO} "`basename $$f .c`.o:\c" >>Makefile; \ - for h in `sed -n -e \ - 's/^#[ ]*include[ ]*"\([^"]*\)".*/\1/p' $$f`; \ - do \ - ${ECHO} " $$h\c"; \ - ${ECHO} " $$h\c" >>Makefile; \ - done; \ - ${ECHO} " done."; \ - ${ECHO} "" >>Makefile; \ - done; \ - ${ECHO} '# End of generated dependencies' >>Makefile - -# DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT -# Dependencies generated by make depend -coolers.o: ../lib/mbselib.h coolers.h mosquitto.h sensors.h -sensors.o: ../lib/mbselib.h sensors.h -mosquitto.o: ../lib/mbselib.h mosquitto.h -# End of generated dependencies diff -r dafbbd5e9922 -r f534ace74eea coolers/coolers.c --- a/coolers/coolers.c Sat May 17 23:06:39 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,423 +0,0 @@ -/***************************************************************************** - * Copyright (C) 2014 - * - * Michiel Broek - * - * This file is part of the mbsePi-apps - * - * This 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 2, or (at your option) any - * later version. - * - * mbsePi-apps 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 EC-65K; see the file COPYING. If not, write to the Free - * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - *****************************************************************************/ - -#include "../lib/mbselib.h" -#include "coolers.h" -#include "mosquitto.h" -#include "sensors.h" - -#ifdef HAVE_WIRINGPI_H - - -int tempA = 80; -int tempB = 80; -int coolerA = 0; -int coolerB = 0; - -bool my_shutdown = false; -static pid_t pgrp, mypid; - -extern bool debug; -extern sys_config Config; -extern int lcdHandle; -int lcdupdate; - -int sock = -1; /* Datagram socket */ -struct sockaddr_un servaddr; /* Server address */ -struct sockaddr_un from; /* From address */ -static char spath[PATH_MAX]; /* Socket path */ -socklen_t fromlen; - - -int server(void); -void help(void); -void die(int); - - -void help(void) -{ - fprintf(stdout, "mbsePi-apps coolers v%s starting\n\n", VERSION); - fprintf(stdout, "Usage: coolers [-d] [-h]\n"); - fprintf(stdout, " -d --debug Debug and run in foreground\n"); - fprintf(stdout, " -h --help Display this help\n"); -} - - - -void die(int onsig) -{ - switch (onsig) { - case SIGHUP: syslog(LOG_NOTICE, "Got SIGHUP, shutting down"); - break; - case SIGINT: syslog(LOG_NOTICE, "Keyboard interrupt, shutting down"); - break; - case SIGTERM: syslog(LOG_NOTICE, "Got SIGTERM, shutting down"); - break; - default: syslog(LOG_NOTICE, "die() on signal %d", onsig); - } - - my_shutdown = true; -} - - - -void stopLCD(void) -{ - mb_lcdClear(lcdHandle); - setBacklight(0); -} - - - -void stopRCswitch(void) -{ - rc_switch *tmp, *old; - char *cmd = NULL; - int rc; - - for (tmp = Config.rcswitch; tmp; tmp = old) { - old = tmp->next; - cmd = xstrcpy(tmp->address); - cmd = xstrcat(cmd, (char *)",0"); - rc = toggleSwitch(cmd); - if (debug) - fprintf(stdout, "Switch %s rc=%d\n", cmd, rc); - syslog(LOG_NOTICE, "Switch %s rc=%d", cmd, rc); - free(cmd); - cmd = NULL; - } -} - - - -int main(int argc, char *argv[]) -{ - int rc, c, i; - pid_t frk; - char buf[80]; - - while (1) { - int option_index = 0; - static struct option long_options[] = { - {"debug", 0, 0, 'c'}, - {"help", 0, 0, 'h'}, - {0, 0, 0, 0} - }; - - c = getopt_long(argc, argv, "dh", long_options, &option_index); - if (c == -1) - break; - - switch (c) { - case 'd': debug = true; - break; - case 'h': help(); - return 1; - } - } - - openlog("coolers", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_USER); - syslog(LOG_NOTICE, "mbsePi-apps coolers v%s starting", VERSION); - if (debug) - fprintf(stdout, "mbsePi-apps coolers v%s starting\n", VERSION); - - if (rdconfig((char *)"coolers.conf")) { - fprintf(stderr, "Error reading configuration\n"); - syslog(LOG_NOTICE, "halted"); - return 1; - } - - /* - * Catch all the signals we can, and ignore the rest. Note that SIGKILL can't be ignored - * but that's live. This daemon should only be stopped by SIGTERM. - * Don't catch SIGCHLD. - */ - for (i = 0; i < NSIG; i++) { - if ((i != SIGCHLD) && (i != SIGKILL) && (i != SIGSTOP)) - signal(i, (void (*))die); - } - - if (wiringPiSetup () ) - return 1; - - if ((rc = initLCD (16, 2))) { - fprintf(stderr, "Cannot initialize LCD display, rc=%d\n", rc); - return 1; - } - - lcdPosition(lcdHandle, 0, 0); - sprintf(buf, "Coolers"); - mb_lcdPuts(lcdHandle, buf); - lcdPosition(lcdHandle, 0, 1); - sprintf(buf, "Version %s", VERSION); - mb_lcdPuts(lcdHandle, buf); - - if (Config.tx433 != -1) { - if (debug) - fprintf(stdout, "Using 433 MHz transmitter on pin %d\n", Config.tx433); - syslog(LOG_NOTICE, "Using 433 MHz transmitter on pin %d", Config.tx433); - enableTransmit(Config.tx433); - } - - if (debug) { - /* - * For debugging run in foreground. - */ - rc = server(); - } else { - /* - * Server initialization is complete. Now we can fork the - * daemon and return to the user. We need to do a setpgrp - * so that the daemon will no longer be assosiated with the - * users control terminal. This is done before the fork, so - * that the child will not be a process group leader. Otherwise, - * if the child were to open a terminal, it would become - * associated with that terminal as its control terminal. - */ - if ((pgrp = setpgid(0, 0)) == -1) { - syslog(LOG_NOTICE, "setpgpid failed"); - } - - frk = fork(); - switch (frk) { - case -1: - syslog(LOG_NOTICE, "Daemon fork failed: %s", strerror(errno)); - syslog(LOG_NOTICE, "Finished, rc=1"); - stopLCD(); - exit(1); - case 0: /* - * Run the daemon - */ - fclose(stdin); - if (open("/dev/null", O_RDONLY) != 0) { - syslog(LOG_NOTICE, "Reopen of stdin to /dev/null failed"); - _exit(2); - } - fclose(stdout); - if (open("/dev/null", O_WRONLY | O_APPEND | O_CREAT,0600) != 1) { - syslog(LOG_NOTICE, "Reopen of stdout to /dev/null failed"); - _exit(2); - } - fclose(stderr); - if (open("/dev/null", O_WRONLY | O_APPEND | O_CREAT,0600) != 2) { - syslog(LOG_NOTICE, "Reopen of stderr to /dev/null failed"); - _exit(2); - } - mypid = getpid(); - rc = server(); - break; - /* Not reached */ - default: - /* - * Here we detach this process and let the child - * run the deamon process. - */ - syslog(LOG_NOTICE, "Starting daemon with pid %d", frk); - exit(0); - } - } - - syslog(LOG_NOTICE, "Finished, rc=%d", rc); - return rc; -} - - - -int server(void) -{ - char buf[1024]; - w1_therm *tmp1, *old1; - rc_switch *tmp2, *old2; - int rc, run = 0, temp, rlen; - struct pollfd pfd[1]; - - - if (lockprog((char *)"coolers")) { - syslog(LOG_NOTICE, "Can't lock"); - return 1; - } - - my_mosquitto_init(); - - rc = piThreadCreate(my_sensors_loop); - if (rc) { - fprintf(stderr, "my_sensors_loop thread didn't start rc=%d\n", rc); - syslog(LOG_NOTICE, "my_sensors_loop thread didn't start rc=%d", rc); - } - - /* - * Setup socket so that clients can communicate with this server. - */ - if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { - fprintf(stderr, "Can't create socket\n"); - return 1; - } - - snprintf(spath, PATH_MAX, "/var/run/coolers.sock"); - memset(&servaddr, 0, sizeof(servaddr)); - servaddr.sun_family = AF_UNIX; - strcpy(servaddr.sun_path, spath); - - if (bind(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { - close(sock); - sock = -1; - fprintf(stderr, "Can't bind socket %s\n", spath); - return 1; - } - if (chmod(spath, 0666)) { - fprintf(stderr, "Can't chmod 0666 %s\n", spath); - close(sock); - sock = -1; - unlink(spath); - return 1; - } - if (debug) - fprintf(stdout, "Unix socket created\n"); - - snprintf(buf, 1023, "tempA,coolerA,tempB,coolerB"); - logger((char *)"coolers.log", (char *)"coolers", buf); - - do { - /* - * Poll UNIX Datagram socket the defined timeout of one second. - * This means we listen if a client program has something to tell us. - * Timeout is one second, after the timeout the rest of the mainloop is executed. - */ - pfd[0].fd = sock; - pfd[0].events = POLLIN; - pfd[0].revents = 0; - rc = poll(pfd, 1, 1000); - - if (rc == -1) { - /* - * Poll can be interrupted by a finished child so that's not a real error. - */ - if (errno != EINTR) { - syslog(LOG_NOTICE, "poll() rc=%d sock=%d, events=%04x", rc, sock, pfd[0].revents); - } - } else if (rc) { - if (pfd[0].revents & POLLIN) { - /* - * Process the clients request for mbtask commands. - */ - memset(&buf, 0, sizeof(buf)); - fromlen = sizeof(from); - rlen = recvfrom(sock, buf, sizeof(buf) -1, 0, (struct sockaddr *)&from, &fromlen); - if (rlen == -1) { - syslog(LOG_NOTICE, "recvfrom() for socket receiver"); - } else { -// do_cmd(buf); - } - } - } - - lcdupdate = FALSE; - - run = my_mosquitto_loop(); - - tmp1 = Config.w1therms; - tmp2 = Config.rcswitch; - if (((tmp1->lastval / 100) < (tempA - 5)) && (coolerA == 1)) { - my_mosquitto_switch(tmp2->address, 0); - coolerA = 0; - syslog(LOG_NOTICE, "Temperature A is %.1f, switched cooler off", (tmp1->lastval / 1000.0)); - lcdupdate = TRUE; - } - if (((tmp1->lastval / 100) > (tempA + 5)) && (coolerA == 0)) { - my_mosquitto_switch(tmp2->address, 1); - coolerA = 1; - syslog(LOG_NOTICE, "Temperature A is %.1f, switched cooler on", (tmp1->lastval / 1000.0)); - lcdupdate = TRUE; - } - old1 = tmp1->next; - tmp1 = old1; - old2 = tmp2->next; - tmp2 = old2; - if (((tmp1->lastval / 100) < (tempB - 5)) && (coolerB == 1)) { - my_mosquitto_switch(tmp2->address, 0); - coolerB = 0; - syslog(LOG_NOTICE, "Temperature B is %.1f, switched cooler off", (tmp1->lastval / 1000.0)); - lcdupdate = TRUE; - } - if (((tmp1->lastval / 100) > (tempB + 5)) && (coolerB == 0)) { - my_mosquitto_switch(tmp2->address, 1); - coolerB = 1; - syslog(LOG_NOTICE, "Temperature B is %.1f, switched cooler on", (tmp1->lastval / 1000.0)); - lcdupdate = TRUE; - } - - if (run && lcdupdate) { - lcdPosition(lcdHandle, 0, 0); - tmp1 = Config.w1therms; - snprintf(buf, 16, "%4.1f %cC %c %s ", tmp1->lastval / 1000.0, 0xdf, coolerA ? '+' : ' ', tmp1->alias); - mb_lcdPuts(lcdHandle, buf); - temp = tmp1->lastval; - old1 = tmp1->next; - tmp1 = old1; - lcdPosition(lcdHandle, 0, 1); - snprintf(buf, 16, "%4.1f %cC %c %s ", tmp1->lastval / 1000.0, 0xdf, coolerB ? '+' : ' ', tmp1->alias); - mb_lcdPuts(lcdHandle, buf); - snprintf(buf, 1023, "%.1f,%s,%.1f,%s", temp / 1000.0, coolerA ? (char *)"on" : (char *)"off", - tmp1->lastval / 1000.0, coolerB ? (char *)"on" : (char *)"off"); - logger((char *)"coolers.log", (char *)"coolers", buf); - } - usleep(100000); - - } while (run); - - if (debug) - fprintf(stdout, (char *)"Out of loop\n"); - - /* - * Give threads time to cleanup - */ - usleep(1500000); - - if (Config.tx433 != -1) { - stopRCswitch(); - } - - my_mosquitto_exit(); - stopLCD(); - disableTransmit(); - - ulockprog((char *)"coolers"); - unlink(spath); - - if (debug) - fprintf(stdout, "Goodbye\n"); - - return 0; -} - -#else - - -int main(int argc, char *argv[]) -{ - fprintf(stderr, "Compiled on a system without a wiringPi library.\n"); - fprintf(stderr, "This program is useless and will do nothing.\n"); - return 0; -} - - -#endif diff -r dafbbd5e9922 -r f534ace74eea coolers/coolers.h --- a/coolers/coolers.h Sat May 17 23:06:39 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -#ifndef _MAIN_H -#define _MAIN_H - - -#define TRUE 1 -#define FALSE 0 - - -#endif diff -r dafbbd5e9922 -r f534ace74eea coolers/mosquitto.c --- a/coolers/mosquitto.c Sat May 17 23:06:39 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,369 +0,0 @@ -/***************************************************************************** - * Copyright (C) 2014 - * - * Michiel Broek - * - * This file is part of the mbsePi-apps - * - * This 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 2, or (at your option) any - * later version. - * - * mbsePi-apps 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 EC-65K; see the file COPYING. If not, write to the Free - * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - *****************************************************************************/ - -#include "../lib/mbselib.h" -#include "mosquitto.h" - -#ifdef HAVE_WIRINGPI_H - - -#define STATUS_CONNECTING 0 -#define STATUS_CONNACK_RECVD 1 -#define STATUS_WAITING 2 - -/* Global variables for use in callbacks. */ -struct mosquitto *mymosq = NULL; -char *myhostname; -static int qos = 0; -static int status = STATUS_CONNECTING; -static int mid_sent = 0; -static int last_mid = -1; -static int last_mid_sent = -1; -static bool connected = true; -static bool disconnect_sent = false; -static bool connect_lost = false; - -extern bool my_shutdown; -extern bool debug; -extern sys_config Config; -extern int lcdHandle; -extern int lcdupdate; - - -void my_connect_callback(struct mosquitto *mosq, void *obj, int result) -{ - if (connect_lost) { - connect_lost = false; - syslog(LOG_NOTICE, "Reconnect: %s", mosquitto_connack_string(result)); - } - - if (!result) { - status = STATUS_CONNACK_RECVD; - } else { - syslog(LOG_NOTICE, "my_connect_callback: %s\n", mosquitto_connack_string(result)); - } -} - - - -void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc) -{ - if (my_shutdown) { - syslog(LOG_NOTICE, "Acknowledged DISCONNECT from %s", Config.mosq_host); - connected = false; - } else { - /* - * The remove server was brought down. We must keep running - */ - syslog(LOG_NOTICE, "Received DISCONNECT from %s, connection lost", Config.mosq_host); - connect_lost = true; - } -} - - - -void my_publish_callback(struct mosquitto *mosq, void *obj, int mid) -{ - last_mid_sent = mid; -} - - - -void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str) -{ - syslog(LOG_NOTICE, "MQTT: %s", str); - printf("MQTT: %s\n", str); -} - - - -int my_mosquitto_init(void) -{ - char *id = NULL, *state = NULL; - char buf[1024]; - int try, rc, keepalive = 60; - unsigned int max_inflight = 20; - char err[1024]; - w1_therm *tmp1, *old1; - rc_switch *tmp2, *old2; - char *alias; - - /* - * Initialize mosquitto communication - */ - mosquitto_lib_init(); - - gethostname(buf, 255); - myhostname = xstrcpy(buf); - - /* - * Build MQTT id - */ - id = xstrcpy((char *)"coolers/"); - id = xstrcat(id, myhostname); - if(strlen(id) > MOSQ_MQTT_ID_MAX_LENGTH) { - /* - * Enforce maximum client id length of 23 characters - */ - id[MOSQ_MQTT_ID_MAX_LENGTH] = '\0'; - } - - mymosq = mosquitto_new(id, true, NULL); - if (!mymosq) { - switch(errno) { - case ENOMEM: - syslog(LOG_NOTICE, "mosquitto_new: Out of memory"); - break; - case EINVAL: - syslog(LOG_NOTICE, "mosquitto_new: Invalid id"); - break; - } - mosquitto_lib_cleanup(); - return 1; - } - - if (debug) { - mosquitto_log_callback_set(mymosq, my_log_callback); - } - - /* - * Set our will - */ - state = xstrcpy((char *)"clients/"); - state = xstrcat(state, myhostname); - state = xstrcat(state, (char *)"/coolers/state"); - sprintf(buf, "0"); - if ((rc = mosquitto_will_set(mymosq, state, strlen(buf), buf, qos, true))) { - if (rc == MOSQ_ERR_INVAL) { - syslog(LOG_NOTICE, "mosquitto_will_set: input parameters invalid"); - } else if (rc == MOSQ_ERR_NOMEM) { - syslog(LOG_NOTICE, "mosquitto_will_set: Out of Memory"); - } else if (rc == MOSQ_ERR_PAYLOAD_SIZE) { - syslog(LOG_NOTICE, "mosquitto_will_set: invalid payload size"); - } - mosquitto_lib_cleanup(); - return rc; - } - - mosquitto_max_inflight_messages_set(mymosq, max_inflight); - mosquitto_connect_callback_set(mymosq, my_connect_callback); - mosquitto_disconnect_callback_set(mymosq, my_disconnect_callback); - mosquitto_publish_callback_set(mymosq, my_publish_callback); - - try = 10; rc = -1; - while (try && rc) { - if ((rc = mosquitto_connect(mymosq, Config.mosq_host, Config.mosq_port, keepalive))) { - if (rc == MOSQ_ERR_ERRNO) { - strerror_r(errno, err, 1024); - syslog(LOG_NOTICE, "mosquitto_connect: error: %s, try=%d", err, 11-try); - } else { - syslog(LOG_NOTICE, "mosquitto_connect: unable to connect (%d)", rc); - } - sleep(2); - try--; - } - } - if (rc) { - syslog(LOG_NOTICE, "mosquitto_connect: too many tries, giving up"); - mosquitto_lib_cleanup(); - return rc; - } - syslog(LOG_NOTICE, "Connected with %s:%d", Config.mosq_host, Config.mosq_port); - - /* - * Initialise is complete, report our presence state - */ - mosquitto_loop_start(mymosq); - sprintf(buf, "1"); - rc = mosquitto_publish(mymosq, &mid_sent, state, strlen(buf), buf, qos, 1); - - /* - * Report alias names - */ - for (tmp1 = Config.w1therms; tmp1; tmp1 = old1) { - old1 = tmp1->next; - - alias = xstrcpy((char *)"/raw/"); - alias = xstrcat(alias, myhostname); - alias = xstrcat(alias, (char *)"/coolers/w1/"); - alias = xstrcat(alias, tmp1->master); - alias = xstrcat(alias, (char *)"/"); - alias = xstrcat(alias, tmp1->name); - alias = xstrcat(alias, (char *)"/alias"); - - sprintf(buf, "%s", tmp1->alias); - if ((rc = mosquitto_publish(mymosq, &mid_sent, alias, strlen(buf), buf, qos, 1))) { - if (rc == MOSQ_ERR_NO_CONN) - mosquitto_reconnect(mymosq); - else - syslog(LOG_NOTICE, "mainloop: error %d from mosquitto_publish", rc); - } - - free(alias); - alias = NULL; - } - - for (tmp2 = Config.rcswitch; tmp2; tmp2 = old2) { - old2 = tmp2->next; - - alias = xstrcpy((char *)"/raw/"); - alias = xstrcat(alias, myhostname); - alias = xstrcat(alias, (char *)"/coolers/rcswitch/"); - alias = xstrcat(alias, tmp2->address); - alias = xstrcat(alias, (char *)"/alias"); - - sprintf(buf, "%s", tmp2->alias); - if ((rc = mosquitto_publish(mymosq, &mid_sent, alias, strlen(buf), buf, qos, 1))) { - if (rc == MOSQ_ERR_NO_CONN) - mosquitto_reconnect(mymosq); - else - syslog(LOG_NOTICE, "my_mosquitto_init: error %d from mosquitto_publish", rc); - } - - free(alias); - alias = NULL; - my_mosquitto_switch(tmp2->address, 0); - } - - return 0; -} - - - -int my_mosquitto_switch(char *address, int state) -{ - char *cmd = NULL, buf[10]; - int rc; - - cmd = xstrcpy(address); - if (state) - cmd = xstrcat(cmd, (char *)",1"); - else - cmd = xstrcat(cmd, (char *)",0"); - rc = toggleSwitch(cmd); - if (debug) - fprintf(stdout, "Switch %s rc=%d\n", cmd, rc); - syslog(LOG_NOTICE, "Switch %s rc=%d", cmd, rc); - free(cmd); - - cmd = xstrcpy((char *)"/raw/"); - cmd = xstrcat(cmd, myhostname); - cmd = xstrcat(cmd, (char *)"/coolers/rcswitch/"); - cmd = xstrcat(cmd, address); - cmd = xstrcat(cmd, (char *)"/state"); - sprintf(buf, "%d", state); - - if ((rc = mosquitto_publish(mymosq, &mid_sent, cmd, strlen(buf), buf, qos, 1))) { - if (rc == MOSQ_ERR_NO_CONN) - mosquitto_reconnect(mymosq); - else - syslog(LOG_NOTICE, "my_mosquitto_switch: error %d from mosquitto_publish", rc); - } - - free(cmd); - cmd = NULL; - - return rc; -} - - - -int my_mosquitto_loop(void) -{ - w1_therm *tmp1, *old1; - char buf[1024], *alias, *state = NULL; - int rc; - - if (status == STATUS_CONNACK_RECVD) { - /* - * Here send our 1-wire sensors values - */ - for (tmp1 = Config.w1therms; tmp1; tmp1 = old1) { - old1 = tmp1->next; - - if (tmp1->update) { - /* - * Build path and alias topic - */ - alias = xstrcpy((char *)"/raw/"); - alias = xstrcat(alias, myhostname); - alias = xstrcat(alias, (char *)"/coolers/w1/"); - alias = xstrcat(alias, tmp1->master); - alias = xstrcat(alias, (char *)"/"); - alias = xstrcat(alias, tmp1->name); - alias = xstrcat(alias, (char *)"/temperature"); - - /* - * Publish the temperature. - */ - sprintf(buf, "%.1f", tmp1->lastval / 1000.0); - if ((rc = mosquitto_publish(mymosq, &mid_sent, alias, strlen(buf), buf, qos, 1))) { - if (rc == MOSQ_ERR_NO_CONN) - mosquitto_reconnect(mymosq); - else - syslog(LOG_NOTICE, "mainloop: error %d from mosquitto_publish", rc); - } - tmp1->update = FALSE; - lcdupdate = TRUE; - - free(alias); - alias = NULL; - } - } - - if (my_shutdown) { - /* - * Final publish 0 to clients//coolers/state - */ - sprintf(buf, "0"); - mosquitto_publish(mymosq, &mid_sent, state, strlen(buf), buf, qos, true); - last_mid = mid_sent; - status = STATUS_WAITING; - mb_lcdClear(lcdHandle); -// lcdPosition(lcdHandle, 0, 0); - mb_lcdPuts(lcdHandle, "Shuting down ..."); - } - - } else if (status == STATUS_WAITING) { - if (debug) - fprintf(stdout, (char *)"Waiting\n"); - if (last_mid_sent == last_mid && disconnect_sent == false) { - mosquitto_disconnect(mymosq); - disconnect_sent = true; - } - } - rc = MOSQ_ERR_SUCCESS; - - return (rc == MOSQ_ERR_SUCCESS && connected); -} - - - -void my_mosquitto_exit(void) -{ - mosquitto_loop_stop(mymosq, false); - mosquitto_destroy(mymosq); - mosquitto_lib_cleanup(); -} - - -#endif diff -r dafbbd5e9922 -r f534ace74eea coolers/mosquitto.h --- a/coolers/mosquitto.h Sat May 17 23:06:39 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -#ifndef MY_MOSQUITTO_H -#define MY_MOSQUITTO_H - -#ifdef HAVE_WIRINGPI_H - -int my_mosquitto_switch(char *, int); -int my_mosquitto_init(void); -int my_mosquitto_loop(void); -void my_mosquitto_exit(void); - -#endif - -#endif diff -r dafbbd5e9922 -r f534ace74eea coolers/sensors.c --- a/coolers/sensors.c Sat May 17 23:06:39 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +0,0 @@ -/***************************************************************************** - * Copyright (C) 2014 - * - * Michiel Broek - * - * This file is part of the mbsePi-apps - * - * This 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 2, or (at your option) any - * later version. - * - * mbsePi-apps 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 EC-65K; see the file COPYING. If not, write to the Free - * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - *****************************************************************************/ - -#include "../lib/mbselib.h" -#include "sensors.h" - -#ifdef HAVE_WIRINGPI_H - - -extern bool debug; -extern sys_config Config; -extern int my_shutdown; - - - -PI_THREAD (my_sensors_loop) -{ - w1_therm *tmp1, *old1; - char *device, line[60], *p = NULL; - FILE *fp; - int temp, rc, deviation; - - syslog(LOG_NOTICE, "Thread my_sensors_loop started"); - if (debug) - fprintf(stdout, "Thread my_sensors_loop started\n"); - - /* - * Loop forever until the external shutdown variable is set. - */ - for (;;) { - /* - * Here send our 1-wire sensors values - */ - for (tmp1 = Config.w1therms; tmp1; tmp1 = old1) { - old1 = tmp1->next; - - if (my_shutdown) { - syslog(LOG_NOTICE, "Thread my_sensors_loop stopped"); - if (debug) - fprintf(stdout, "Thread my_sensors_loop stopped\n"); - return 0; - } - - /* - * Build path to the on-wire sensor - */ - device = xstrcpy((char *)"/sys/bus/w1/devices/"); - device = xstrcat(device, tmp1->master); - device = xstrcat(device, (char *)"/"); - device = xstrcat(device, tmp1->name); - device = xstrcat(device, (char *)"/w1_slave"); - - /* - * Read sensor data - */ - if ((fp = fopen(device, "r"))) { - /* - * The output looks like: - * 72 01 4b 46 7f ff 0e 10 57 : crc=57 YES - * 72 01 4b 46 7f ff 0e 10 57 t=23125 - */ - fgets(line, 50, fp); - line[strlen(line)-1] = '\0'; - if ((line[36] == 'Y') && (line[37] == 'E')) { - /* - * CRC is Ok, continue - */ - fgets(line, 50, fp); - line[strlen(line)-1] = '\0'; - strtok(line, (char *)"="); - p = strtok(NULL, (char *)"="); - rc = sscanf(p, "%d", &temp); - if ((rc == 1) && (tmp1->lastval != temp)) { - /* - * It is possible to have read errors or extreme values. - * This can happen with bad connections so we compare the - * value with the previous one. If the difference is too - * much, we don't send that value. That also means that if - * the next value is ok again, it will be marked invalid too. - * Maximum error is 20 degrees for now. - */ - deviation = 20000; - if ( (tmp1->lastval == 0) || - (tmp1->lastval && (temp > (tmp1->lastval - deviation)) && (temp < (tmp1->lastval + deviation))) ) { - /* - * Temperature is changed and valid, set flag. - */ - tmp1->update = TRUE; - } else { - syslog(LOG_NOTICE, "deviation error deviation=%d, old=%d new=%d", deviation, tmp1->lastval, temp); - if (debug) { - fprintf(stdout, "deviation error deviation=%d, old=%d new=%d\n", deviation, tmp1->lastval, temp); - } - } - tmp1->lastval = temp; - } - } else { - syslog(LOG_NOTICE, "sensor %s/%s CRC error", tmp1->master, tmp1->name); - } - fclose(fp); - tmp1->present = 1; - } else { - tmp1->present = 0; - if (debug) - printf("sensor %s is missing\n", tmp1->name); - } - - free(device); - device = NULL; - } - } -} - - - -#endif diff -r dafbbd5e9922 -r f534ace74eea coolers/sensors.h --- a/coolers/sensors.h Sat May 17 23:06:39 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -#ifndef MY_SENSORS_H -#define MY_SENSORS_H - -#ifdef HAVE_WIRINGPI_H - -PI_THREAD (my_sensors_loop); - -#endif - -#endif diff -r dafbbd5e9922 -r f534ace74eea lib/lcd-pcf8574.c --- a/lib/lcd-pcf8574.c Sat May 17 23:06:39 2014 +0200 +++ b/lib/lcd-pcf8574.c Sun May 18 21:24:55 2014 +0200 @@ -28,8 +28,8 @@ #ifdef HAVE_WIRINGPI_H -int lcdHandle; -static unsigned char lcdbuf[MAX_LCDS][20][4]; +int lcdHandle; +unsigned char lcdbuf[MAX_LCDS][20][4]; struct lcdDataStruct { diff -r dafbbd5e9922 -r f534ace74eea thermferm/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/Makefile Sun May 18 21:24:55 2014 +0200 @@ -0,0 +1,60 @@ +# Makefile for the mbsePi-apps/thermferm. + +include ../Makefile.global + +SRCS = $(wildcard *.c) +HDRS = $(wildcard *.h) +OBJS = $(SRCS:.c=.o) +SLIBS = -lpthread ../lib/libmbse.a +TARGET = thermferm +OTHER = Makefile + +############################################################################# + +.c.o: + ${CC} ${CFLAGS} ${INCLUDES} ${DEFINES} -c $< + +all: ${TARGET} + +thermferm: ${OBJS} ${SLIBS} + ${CC} -o thermferm ${OBJS} ${LDFLAGS} ${LIBS} ${SLIBS} + +clean: + rm -f ${TARGET} *.o *.h~ *.c~ core filelist Makefile.bak + +install: all + ${INSTALL} -c -s -g root -o root -m 0755 thermometers ${BINDIR} + +filelist: Makefile + BASE=`pwd`; \ + BASE=`basename $${BASE}`; \ + (for f in ${SRCS} ${HDRS} ${OTHER} ;do echo ${PACKAGE}-${VERSION}/$${BASE}/$$f; done) >filelist + +depend: + @rm -f Makefile.bak; \ + mv Makefile Makefile.bak; \ + sed -e '/^# DO NOT DELETE/,$$d' Makefile.bak >Makefile; \ + ${ECHO} '# DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT' \ + >>Makefile; \ + ${ECHO} '# Dependencies generated by make depend' >>Makefile; \ + for f in ${SRCS}; \ + do \ + ${ECHO} "Dependencies for $$f:\c"; \ + ${ECHO} "`basename $$f .c`.o:\c" >>Makefile; \ + for h in `sed -n -e \ + 's/^#[ ]*include[ ]*"\([^"]*\)".*/\1/p' $$f`; \ + do \ + ${ECHO} " $$h\c"; \ + ${ECHO} " $$h\c" >>Makefile; \ + done; \ + ${ECHO} " done."; \ + ${ECHO} "" >>Makefile; \ + done; \ + ${ECHO} '# End of generated dependencies' >>Makefile + +# DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT +# Dependencies generated by make depend +thermferm.o: ../lib/mbselib.h thermferm.h mosquitto.h sensors.h +sensors.o: ../lib/mbselib.h sensors.h +mosquitto.o: ../lib/mbselib.h mosquitto.h +# End of generated dependencies diff -r dafbbd5e9922 -r f534ace74eea thermferm/mosquitto.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/mosquitto.c Sun May 18 21:24:55 2014 +0200 @@ -0,0 +1,369 @@ +/***************************************************************************** + * Copyright (C) 2014 + * + * Michiel Broek + * + * This file is part of the mbsePi-apps + * + * This 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 2, or (at your option) any + * later version. + * + * mbsePi-apps 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 EC-65K; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +#include "../lib/mbselib.h" +#include "mosquitto.h" + +#ifdef HAVE_WIRINGPI_H + + +#define STATUS_CONNECTING 0 +#define STATUS_CONNACK_RECVD 1 +#define STATUS_WAITING 2 + +/* Global variables for use in callbacks. */ +struct mosquitto *mymosq = NULL; +char *myhostname; +static int qos = 0; +static int status = STATUS_CONNECTING; +static int mid_sent = 0; +static int last_mid = -1; +static int last_mid_sent = -1; +static bool connected = true; +static bool disconnect_sent = false; +static bool connect_lost = false; + +extern bool my_shutdown; +extern bool debug; +extern sys_config Config; +extern int lcdHandle; +extern int lcdupdate; + + +void my_connect_callback(struct mosquitto *mosq, void *obj, int result) +{ + if (connect_lost) { + connect_lost = false; + syslog(LOG_NOTICE, "Reconnect: %s", mosquitto_connack_string(result)); + } + + if (!result) { + status = STATUS_CONNACK_RECVD; + } else { + syslog(LOG_NOTICE, "my_connect_callback: %s\n", mosquitto_connack_string(result)); + } +} + + + +void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc) +{ + if (my_shutdown) { + syslog(LOG_NOTICE, "Acknowledged DISCONNECT from %s", Config.mosq_host); + connected = false; + } else { + /* + * The remove server was brought down. We must keep running + */ + syslog(LOG_NOTICE, "Received DISCONNECT from %s, connection lost", Config.mosq_host); + connect_lost = true; + } +} + + + +void my_publish_callback(struct mosquitto *mosq, void *obj, int mid) +{ + last_mid_sent = mid; +} + + + +void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str) +{ + syslog(LOG_NOTICE, "MQTT: %s", str); + printf("MQTT: %s\n", str); +} + + + +int my_mosquitto_init(void) +{ + char *id = NULL, *state = NULL; + char buf[1024]; + int try, rc, keepalive = 60; + unsigned int max_inflight = 20; + char err[1024]; + w1_therm *tmp1, *old1; + rc_switch *tmp2, *old2; + char *alias; + + /* + * Initialize mosquitto communication + */ + mosquitto_lib_init(); + + gethostname(buf, 255); + myhostname = xstrcpy(buf); + + /* + * Build MQTT id + */ + id = xstrcpy((char *)"thermferm/"); + id = xstrcat(id, myhostname); + if(strlen(id) > MOSQ_MQTT_ID_MAX_LENGTH) { + /* + * Enforce maximum client id length of 23 characters + */ + id[MOSQ_MQTT_ID_MAX_LENGTH] = '\0'; + } + + mymosq = mosquitto_new(id, true, NULL); + if (!mymosq) { + switch(errno) { + case ENOMEM: + syslog(LOG_NOTICE, "mosquitto_new: Out of memory"); + break; + case EINVAL: + syslog(LOG_NOTICE, "mosquitto_new: Invalid id"); + break; + } + mosquitto_lib_cleanup(); + return 1; + } + + if (debug) { + mosquitto_log_callback_set(mymosq, my_log_callback); + } + + /* + * Set our will + */ + state = xstrcpy((char *)"clients/"); + state = xstrcat(state, myhostname); + state = xstrcat(state, (char *)"/thermferm/state"); + sprintf(buf, "0"); + if ((rc = mosquitto_will_set(mymosq, state, strlen(buf), buf, qos, true))) { + if (rc == MOSQ_ERR_INVAL) { + syslog(LOG_NOTICE, "mosquitto_will_set: input parameters invalid"); + } else if (rc == MOSQ_ERR_NOMEM) { + syslog(LOG_NOTICE, "mosquitto_will_set: Out of Memory"); + } else if (rc == MOSQ_ERR_PAYLOAD_SIZE) { + syslog(LOG_NOTICE, "mosquitto_will_set: invalid payload size"); + } + mosquitto_lib_cleanup(); + return rc; + } + + mosquitto_max_inflight_messages_set(mymosq, max_inflight); + mosquitto_connect_callback_set(mymosq, my_connect_callback); + mosquitto_disconnect_callback_set(mymosq, my_disconnect_callback); + mosquitto_publish_callback_set(mymosq, my_publish_callback); + + try = 10; rc = -1; + while (try && rc) { + if ((rc = mosquitto_connect(mymosq, Config.mosq_host, Config.mosq_port, keepalive))) { + if (rc == MOSQ_ERR_ERRNO) { + strerror_r(errno, err, 1024); + syslog(LOG_NOTICE, "mosquitto_connect: error: %s, try=%d", err, 11-try); + } else { + syslog(LOG_NOTICE, "mosquitto_connect: unable to connect (%d)", rc); + } + sleep(2); + try--; + } + } + if (rc) { + syslog(LOG_NOTICE, "mosquitto_connect: too many tries, giving up"); + mosquitto_lib_cleanup(); + return rc; + } + syslog(LOG_NOTICE, "Connected with %s:%d", Config.mosq_host, Config.mosq_port); + + /* + * Initialise is complete, report our presence state + */ + mosquitto_loop_start(mymosq); + sprintf(buf, "1"); + rc = mosquitto_publish(mymosq, &mid_sent, state, strlen(buf), buf, qos, 1); + + /* + * Report alias names + */ + for (tmp1 = Config.w1therms; tmp1; tmp1 = old1) { + old1 = tmp1->next; + + alias = xstrcpy((char *)"/raw/"); + alias = xstrcat(alias, myhostname); + alias = xstrcat(alias, (char *)"/thermferm/w1/"); + alias = xstrcat(alias, tmp1->master); + alias = xstrcat(alias, (char *)"/"); + alias = xstrcat(alias, tmp1->name); + alias = xstrcat(alias, (char *)"/alias"); + + sprintf(buf, "%s", tmp1->alias); + if ((rc = mosquitto_publish(mymosq, &mid_sent, alias, strlen(buf), buf, qos, 1))) { + if (rc == MOSQ_ERR_NO_CONN) + mosquitto_reconnect(mymosq); + else + syslog(LOG_NOTICE, "mainloop: error %d from mosquitto_publish", rc); + } + + free(alias); + alias = NULL; + } + + for (tmp2 = Config.rcswitch; tmp2; tmp2 = old2) { + old2 = tmp2->next; + + alias = xstrcpy((char *)"/raw/"); + alias = xstrcat(alias, myhostname); + alias = xstrcat(alias, (char *)"/thermferm/rcswitch/"); + alias = xstrcat(alias, tmp2->address); + alias = xstrcat(alias, (char *)"/alias"); + + sprintf(buf, "%s", tmp2->alias); + if ((rc = mosquitto_publish(mymosq, &mid_sent, alias, strlen(buf), buf, qos, 1))) { + if (rc == MOSQ_ERR_NO_CONN) + mosquitto_reconnect(mymosq); + else + syslog(LOG_NOTICE, "my_mosquitto_init: error %d from mosquitto_publish", rc); + } + + free(alias); + alias = NULL; + my_mosquitto_switch(tmp2->address, 0); + } + + return 0; +} + + + +int my_mosquitto_switch(char *address, int state) +{ + char *cmd = NULL, buf[10]; + int rc; + + cmd = xstrcpy(address); + if (state) + cmd = xstrcat(cmd, (char *)",1"); + else + cmd = xstrcat(cmd, (char *)",0"); + rc = toggleSwitch(cmd); + if (debug) + fprintf(stdout, "Switch %s rc=%d\n", cmd, rc); + syslog(LOG_NOTICE, "Switch %s rc=%d", cmd, rc); + free(cmd); + + cmd = xstrcpy((char *)"/raw/"); + cmd = xstrcat(cmd, myhostname); + cmd = xstrcat(cmd, (char *)"/thermferm/rcswitch/"); + cmd = xstrcat(cmd, address); + cmd = xstrcat(cmd, (char *)"/state"); + sprintf(buf, "%d", state); + + if ((rc = mosquitto_publish(mymosq, &mid_sent, cmd, strlen(buf), buf, qos, 1))) { + if (rc == MOSQ_ERR_NO_CONN) + mosquitto_reconnect(mymosq); + else + syslog(LOG_NOTICE, "my_mosquitto_switch: error %d from mosquitto_publish", rc); + } + + free(cmd); + cmd = NULL; + + return rc; +} + + + +int my_mosquitto_loop(void) +{ + w1_therm *tmp1, *old1; + char buf[1024], *alias, *state = NULL; + int rc; + + if (status == STATUS_CONNACK_RECVD) { + /* + * Here send our 1-wire sensors values + */ + for (tmp1 = Config.w1therms; tmp1; tmp1 = old1) { + old1 = tmp1->next; + + if (tmp1->update) { + /* + * Build path and alias topic + */ + alias = xstrcpy((char *)"/raw/"); + alias = xstrcat(alias, myhostname); + alias = xstrcat(alias, (char *)"/thermferm/w1/"); + alias = xstrcat(alias, tmp1->master); + alias = xstrcat(alias, (char *)"/"); + alias = xstrcat(alias, tmp1->name); + alias = xstrcat(alias, (char *)"/temperature"); + + /* + * Publish the temperature. + */ + sprintf(buf, "%.1f", tmp1->lastval / 1000.0); + if ((rc = mosquitto_publish(mymosq, &mid_sent, alias, strlen(buf), buf, qos, 1))) { + if (rc == MOSQ_ERR_NO_CONN) + mosquitto_reconnect(mymosq); + else + syslog(LOG_NOTICE, "mainloop: error %d from mosquitto_publish", rc); + } + tmp1->update = FALSE; + lcdupdate = TRUE; + + free(alias); + alias = NULL; + } + } + + if (my_shutdown) { + /* + * Final publish 0 to clients//thermferm/state + */ + sprintf(buf, "0"); + mosquitto_publish(mymosq, &mid_sent, state, strlen(buf), buf, qos, true); + last_mid = mid_sent; + status = STATUS_WAITING; + mb_lcdClear(lcdHandle); +// lcdPosition(lcdHandle, 0, 0); + mb_lcdPuts(lcdHandle, "Shuting down ..."); + } + + } else if (status == STATUS_WAITING) { + if (debug) + fprintf(stdout, (char *)"Waiting\n"); + if (last_mid_sent == last_mid && disconnect_sent == false) { + mosquitto_disconnect(mymosq); + disconnect_sent = true; + } + } + rc = MOSQ_ERR_SUCCESS; + + return (rc == MOSQ_ERR_SUCCESS && connected); +} + + + +void my_mosquitto_exit(void) +{ + mosquitto_loop_stop(mymosq, false); + mosquitto_destroy(mymosq); + mosquitto_lib_cleanup(); +} + + +#endif diff -r dafbbd5e9922 -r f534ace74eea thermferm/mosquitto.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/mosquitto.h Sun May 18 21:24:55 2014 +0200 @@ -0,0 +1,13 @@ +#ifndef MY_MOSQUITTO_H +#define MY_MOSQUITTO_H + +#ifdef HAVE_WIRINGPI_H + +int my_mosquitto_switch(char *, int); +int my_mosquitto_init(void); +int my_mosquitto_loop(void); +void my_mosquitto_exit(void); + +#endif + +#endif diff -r dafbbd5e9922 -r f534ace74eea thermferm/sensors.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/sensors.c Sun May 18 21:24:55 2014 +0200 @@ -0,0 +1,135 @@ +/***************************************************************************** + * Copyright (C) 2014 + * + * Michiel Broek + * + * This file is part of the mbsePi-apps + * + * This 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 2, or (at your option) any + * later version. + * + * mbsePi-apps 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 EC-65K; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +#include "../lib/mbselib.h" +#include "sensors.h" + +#ifdef HAVE_WIRINGPI_H + + +extern bool debug; +extern sys_config Config; +extern int my_shutdown; + + + +PI_THREAD (my_sensors_loop) +{ + w1_therm *tmp1, *old1; + char *device, line[60], *p = NULL; + FILE *fp; + int temp, rc, deviation; + + syslog(LOG_NOTICE, "Thread my_sensors_loop started"); + if (debug) + fprintf(stdout, "Thread my_sensors_loop started\n"); + + /* + * Loop forever until the external shutdown variable is set. + */ + for (;;) { + /* + * Here send our 1-wire sensors values + */ + for (tmp1 = Config.w1therms; tmp1; tmp1 = old1) { + old1 = tmp1->next; + + if (my_shutdown) { + syslog(LOG_NOTICE, "Thread my_sensors_loop stopped"); + if (debug) + fprintf(stdout, "Thread my_sensors_loop stopped\n"); + return 0; + } + + /* + * Build path to the on-wire sensor + */ + device = xstrcpy((char *)"/sys/bus/w1/devices/"); + device = xstrcat(device, tmp1->master); + device = xstrcat(device, (char *)"/"); + device = xstrcat(device, tmp1->name); + device = xstrcat(device, (char *)"/w1_slave"); + + /* + * Read sensor data + */ + if ((fp = fopen(device, "r"))) { + /* + * The output looks like: + * 72 01 4b 46 7f ff 0e 10 57 : crc=57 YES + * 72 01 4b 46 7f ff 0e 10 57 t=23125 + */ + fgets(line, 50, fp); + line[strlen(line)-1] = '\0'; + if ((line[36] == 'Y') && (line[37] == 'E')) { + /* + * CRC is Ok, continue + */ + fgets(line, 50, fp); + line[strlen(line)-1] = '\0'; + strtok(line, (char *)"="); + p = strtok(NULL, (char *)"="); + rc = sscanf(p, "%d", &temp); + if ((rc == 1) && (tmp1->lastval != temp)) { + /* + * It is possible to have read errors or extreme values. + * This can happen with bad connections so we compare the + * value with the previous one. If the difference is too + * much, we don't send that value. That also means that if + * the next value is ok again, it will be marked invalid too. + * Maximum error is 20 degrees for now. + */ + deviation = 20000; + if ( (tmp1->lastval == 0) || + (tmp1->lastval && (temp > (tmp1->lastval - deviation)) && (temp < (tmp1->lastval + deviation))) ) { + /* + * Temperature is changed and valid, set flag. + */ + tmp1->update = TRUE; + } else { + syslog(LOG_NOTICE, "deviation error deviation=%d, old=%d new=%d", deviation, tmp1->lastval, temp); + if (debug) { + fprintf(stdout, "deviation error deviation=%d, old=%d new=%d\n", deviation, tmp1->lastval, temp); + } + } + tmp1->lastval = temp; + } + } else { + syslog(LOG_NOTICE, "sensor %s/%s CRC error", tmp1->master, tmp1->name); + } + fclose(fp); + tmp1->present = 1; + } else { + tmp1->present = 0; + if (debug) + printf("sensor %s is missing\n", tmp1->name); + } + + free(device); + device = NULL; + } + } +} + + + +#endif diff -r dafbbd5e9922 -r f534ace74eea thermferm/sensors.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/sensors.h Sun May 18 21:24:55 2014 +0200 @@ -0,0 +1,10 @@ +#ifndef MY_SENSORS_H +#define MY_SENSORS_H + +#ifdef HAVE_WIRINGPI_H + +PI_THREAD (my_sensors_loop); + +#endif + +#endif diff -r dafbbd5e9922 -r f534ace74eea thermferm/thermferm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/thermferm.c Sun May 18 21:24:55 2014 +0200 @@ -0,0 +1,354 @@ +/***************************************************************************** + * Copyright (C) 2014 + * + * Michiel Broek + * + * This file is part of the mbsePi-apps + * + * This 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 2, or (at your option) any + * later version. + * + * mbsePi-apps 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 EC-65K; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +#include "../lib/mbselib.h" +#include "thermferm.h" +#include "mosquitto.h" +#include "sensors.h" + +#ifdef HAVE_WIRINGPI_H + + +int tempA = 80; +int tempB = 80; +int coolerA = 0; +int coolerB = 0; + +bool my_shutdown = false; +static pid_t pgrp, mypid; + +extern bool debug; +extern sys_config Config; +extern int lcdHandle; +extern unsigned char lcdbuf[MAX_LCDS][20][4]; +int lcdupdate; + + +int server(void); +void help(void); +void die(int); + + +void help(void) +{ + fprintf(stdout, "mbsePi-apps thermferm v%s starting\n\n", VERSION); + fprintf(stdout, "Usage: thermferm [-d] [-h]\n"); + fprintf(stdout, " -d --debug Debug and run in foreground\n"); + fprintf(stdout, " -h --help Display this help\n"); +} + + + +void die(int onsig) +{ + switch (onsig) { + case SIGHUP: syslog(LOG_NOTICE, "Got SIGHUP, shutting down"); + break; + case SIGINT: syslog(LOG_NOTICE, "Keyboard interrupt, shutting down"); + break; + case SIGTERM: syslog(LOG_NOTICE, "Got SIGTERM, shutting down"); + break; + default: syslog(LOG_NOTICE, "die() on signal %d", onsig); + } + + my_shutdown = true; +} + + + +void stopLCD(void) +{ + mb_lcdClear(lcdHandle); + setBacklight(0); +} + + + +void stopRCswitch(void) +{ + rc_switch *tmp, *old; + char *cmd = NULL; + int rc; + + for (tmp = Config.rcswitch; tmp; tmp = old) { + old = tmp->next; + cmd = xstrcpy(tmp->address); + cmd = xstrcat(cmd, (char *)",0"); + rc = toggleSwitch(cmd); + if (debug) + fprintf(stdout, "Switch %s rc=%d\n", cmd, rc); + syslog(LOG_NOTICE, "Switch %s rc=%d", cmd, rc); + free(cmd); + cmd = NULL; + } +} + + + +int main(int argc, char *argv[]) +{ + int rc, c, i; + pid_t frk; + char buf[80]; + + while (1) { + int option_index = 0; + static struct option long_options[] = { + {"debug", 0, 0, 'c'}, + {"help", 0, 0, 'h'}, + {0, 0, 0, 0} + }; + + c = getopt_long(argc, argv, "dh", long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'd': debug = true; + break; + case 'h': help(); + return 1; + } + } + + openlog("thermferm", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_USER); + syslog(LOG_NOTICE, "mbsePi-apps thermferm v%s starting", VERSION); + if (debug) + fprintf(stdout, "mbsePi-apps thermferm v%s starting\n", VERSION); + + if (rdconfig((char *)"thermferm.conf")) { + fprintf(stderr, "Error reading configuration\n"); + syslog(LOG_NOTICE, "halted"); + return 1; + } + + /* + * Catch all the signals we can, and ignore the rest. Note that SIGKILL can't be ignored + * but that's live. This daemon should only be stopped by SIGTERM. + * Don't catch SIGCHLD. + */ + for (i = 0; i < NSIG; i++) { + if ((i != SIGCHLD) && (i != SIGKILL) && (i != SIGSTOP)) + signal(i, (void (*))die); + } + + if (wiringPiSetup () ) + return 1; + + if ((rc = initLCD (16, 2))) { + fprintf(stderr, "Cannot initialize LCD display, rc=%d\n", rc); + return 1; + } + + lcdPosition(lcdHandle, 0, 0); + sprintf(buf, " Thermferm"); + mb_lcdPuts(lcdHandle, buf); + lcdPosition(lcdHandle, 0, 1); + sprintf(buf, " Version %s", VERSION); + mb_lcdPuts(lcdHandle, buf); + + if (Config.tx433 != -1) { + if (debug) + fprintf(stdout, "Using 433 MHz transmitter on pin %d\n", Config.tx433); + syslog(LOG_NOTICE, "Using 433 MHz transmitter on pin %d", Config.tx433); + enableTransmit(Config.tx433); + } + + if (debug) { + /* + * For debugging run in foreground. + */ + rc = server(); + } else { + /* + * Server initialization is complete. Now we can fork the + * daemon and return to the user. We need to do a setpgrp + * so that the daemon will no longer be assosiated with the + * users control terminal. This is done before the fork, so + * that the child will not be a process group leader. Otherwise, + * if the child were to open a terminal, it would become + * associated with that terminal as its control terminal. + */ + if ((pgrp = setpgid(0, 0)) == -1) { + syslog(LOG_NOTICE, "setpgpid failed"); + } + + frk = fork(); + switch (frk) { + case -1: + syslog(LOG_NOTICE, "Daemon fork failed: %s", strerror(errno)); + syslog(LOG_NOTICE, "Finished, rc=1"); + stopLCD(); + exit(1); + case 0: /* + * Run the daemon + */ + fclose(stdin); + if (open("/dev/null", O_RDONLY) != 0) { + syslog(LOG_NOTICE, "Reopen of stdin to /dev/null failed"); + _exit(2); + } + fclose(stdout); + if (open("/dev/null", O_WRONLY | O_APPEND | O_CREAT,0600) != 1) { + syslog(LOG_NOTICE, "Reopen of stdout to /dev/null failed"); + _exit(2); + } + fclose(stderr); + if (open("/dev/null", O_WRONLY | O_APPEND | O_CREAT,0600) != 2) { + syslog(LOG_NOTICE, "Reopen of stderr to /dev/null failed"); + _exit(2); + } + mypid = getpid(); + rc = server(); + break; + /* Not reached */ + default: + /* + * Here we detach this process and let the child + * run the deamon process. + */ + syslog(LOG_NOTICE, "Starting daemon with pid %d", frk); + exit(0); + } + } + + syslog(LOG_NOTICE, "Finished, rc=%d", rc); + return rc; +} + + + +int server(void) +{ + char buf[1024]; + w1_therm *tmp1, *old1; + rc_switch *tmp2, *old2; + int rc, run = 0, temp; + + + if (lockprog((char *)"thermferm")) { + syslog(LOG_NOTICE, "Can't lock"); + return 1; + } + + my_mosquitto_init(); + + rc = piThreadCreate(my_sensors_loop); + if (rc) { + fprintf(stderr, "my_sensors_loop thread didn't start rc=%d\n", rc); + syslog(LOG_NOTICE, "my_sensors_loop thread didn't start rc=%d", rc); + } + + snprintf(buf, 1023, "tempA,coolerA,tempB,coolerB"); + logger((char *)"thermferm.log", (char *)"thermferm", buf); + + do { + lcdupdate = FALSE; + + run = my_mosquitto_loop(); + + tmp1 = Config.w1therms; + tmp2 = Config.rcswitch; + if (((tmp1->lastval / 100) < (tempA - 5)) && (coolerA == 1)) { + my_mosquitto_switch(tmp2->address, 0); + coolerA = 0; + syslog(LOG_NOTICE, "Temperature A is %.1f, switched cooler off", (tmp1->lastval / 1000.0)); + lcdupdate = TRUE; + } + if (((tmp1->lastval / 100) > (tempA + 5)) && (coolerA == 0)) { + my_mosquitto_switch(tmp2->address, 1); + coolerA = 1; + syslog(LOG_NOTICE, "Temperature A is %.1f, switched cooler on", (tmp1->lastval / 1000.0)); + lcdupdate = TRUE; + } + old1 = tmp1->next; + tmp1 = old1; + old2 = tmp2->next; + tmp2 = old2; + if (((tmp1->lastval / 100) < (tempB - 5)) && (coolerB == 1)) { + my_mosquitto_switch(tmp2->address, 0); + coolerB = 0; + syslog(LOG_NOTICE, "Temperature B is %.1f, switched cooler off", (tmp1->lastval / 1000.0)); + lcdupdate = TRUE; + } + if (((tmp1->lastval / 100) > (tempB + 5)) && (coolerB == 0)) { + my_mosquitto_switch(tmp2->address, 1); + coolerB = 1; + syslog(LOG_NOTICE, "Temperature B is %.1f, switched cooler on", (tmp1->lastval / 1000.0)); + lcdupdate = TRUE; + } + + if (run && lcdupdate) { + lcdPosition(lcdHandle, 0, 0); + tmp1 = Config.w1therms; + snprintf(buf, 16, "%4.1f %cC %c %s ", tmp1->lastval / 1000.0, 0xdf, coolerA ? '+' : ' ', tmp1->alias); + mb_lcdPuts(lcdHandle, buf); + temp = tmp1->lastval; + old1 = tmp1->next; + tmp1 = old1; + lcdPosition(lcdHandle, 0, 1); + snprintf(buf, 16, "%4.1f %cC %c %s ", tmp1->lastval / 1000.0, 0xdf, coolerB ? '+' : ' ', tmp1->alias); + mb_lcdPuts(lcdHandle, buf); + snprintf(buf, 1023, "%.1f,%s,%.1f,%s", temp / 1000.0, coolerA ? (char *)"on" : (char *)"off", + tmp1->lastval / 1000.0, coolerB ? (char *)"on" : (char *)"off"); + logger((char *)"thermferm.log", (char *)"thermferm", buf); + } + usleep(100000); + + } while (run); + + if (debug) + fprintf(stdout, (char *)"Out of loop\n"); + + /* + * Give threads time to cleanup + */ + usleep(1500000); + + if (Config.tx433 != -1) { + stopRCswitch(); + } + + my_mosquitto_exit(); + stopLCD(); + disableTransmit(); + + ulockprog((char *)"thermferm"); + + if (debug) + fprintf(stdout, "Goodbye\n"); + + return 0; +} + +#else + + +int main(int argc, char *argv[]) +{ + fprintf(stderr, "Compiled on a system without a wiringPi library.\n"); + fprintf(stderr, "This program is useless and will do nothing.\n"); + return 0; +} + + +#endif diff -r dafbbd5e9922 -r f534ace74eea thermferm/thermferm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/thermferm.h Sun May 18 21:24:55 2014 +0200 @@ -0,0 +1,9 @@ +#ifndef _MAIN_H +#define _MAIN_H + + +#define TRUE 1 +#define FALSE 0 + + +#endif