Version 0.9.17a1. Revised starting and stopping the threads. Fixed stopping the command server thread. Moved one-wire tempeature sensors resolution correction to the one-wire thread. The devices thread fetches temperatures from the one-wire thread. The one-wire thread does everything for the temperature sensors. The command server uses private sockets. Still, only one session at the same time is handled.

Fri, 05 Apr 2024 16:19:39 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Fri, 05 Apr 2024 16:19:39 +0200
changeset 660
a28ef4d9afa4
parent 659
bfab45f4d5cd
child 661
8c1e7a52e24f

Version 0.9.17a1. Revised starting and stopping the threads. Fixed stopping the command server thread. Moved one-wire tempeature sensors resolution correction to the one-wire thread. The devices thread fetches temperatures from the one-wire thread. The one-wire thread does everything for the temperature sensors. The command server uses private sockets. Still, only one session at the same time is handled.

configure file | annotate | diff | comparison | revisions
configure.ac file | annotate | diff | comparison | revisions
thermferm/Makefile file | annotate | diff | comparison | revisions
thermferm/devices.c file | annotate | diff | comparison | revisions
thermferm/one-wire.c file | annotate | diff | comparison | revisions
thermferm/panel.c file | annotate | diff | comparison | revisions
thermferm/server.c file | annotate | diff | comparison | revisions
thermferm/simulator.c file | annotate | diff | comparison | revisions
thermferm/thermferm.c file | annotate | diff | comparison | revisions
thermferm/thermferm.h file | annotate | diff | comparison | revisions
--- a/configure	Wed Apr 03 19:33:38 2024 +0200
+++ b/configure	Fri Apr 05 16:19:39 2024 +0200
@@ -2037,7 +2037,7 @@
 
 
 PACKAGE="mbsePi-apps"
-VERSION="0.9.17"
+VERSION="0.9.17a1"
 COPYRIGHT="Copyright (C) 2014-2024 Michiel Broek, All Rights Reserved"
 CYEARS="2014-2024"
 
--- a/configure.ac	Wed Apr 03 19:33:38 2024 +0200
+++ b/configure.ac	Fri Apr 05 16:19:39 2024 +0200
@@ -8,7 +8,7 @@
 dnl General settings
 dnl After changeing the version number, run autoconf!
 PACKAGE="mbsePi-apps"
-VERSION="0.9.17"
+VERSION="0.9.17a1"
 COPYRIGHT="Copyright (C) 2014-2024 Michiel Broek, All Rights Reserved"
 CYEARS="2014-2024"
 AC_SUBST(PACKAGE)
--- a/thermferm/Makefile	Wed Apr 03 19:33:38 2024 +0200
+++ b/thermferm/Makefile	Fri Apr 05 16:19:39 2024 +0200
@@ -57,7 +57,7 @@
 # Dependencies generated by make depend
 mqtt.o: thermferm.h rdconfig.h devices.h xutil.h delay.h mqtt.h
 thermferm.o: lock.h rdconfig.h server.h thermferm.h devices.h delay.h simulator.h lcd-pcf8574.h lcd-buffer.h slcd.h panel.h one-wire.h futil.h xutil.h pid.h mqtt.h
-one-wire.o: thermferm.h statetbl.h one-wire.h xutil.h
+one-wire.o: thermferm.h statetbl.h one-wire.h devices.h delay.h futil.h xutil.h
 panel.o: thermferm.h delay.h lcd-pcf8574.h slcd.h panel.h
 devices.o: thermferm.h delay.h devices.h rc-switch.h panel.h xutil.h
 lcd-buffer.o: thermferm.h lcd-buffer.h lcd-pcf8574.h slcd.h panel.h
--- a/thermferm/devices.c	Wed Apr 03 19:33:38 2024 +0200
+++ b/thermferm/devices.c	Fri Apr 05 16:19:39 2024 +0200
@@ -28,10 +28,10 @@
 #include "xutil.h"
 
 
+int			my_devices_shutdown = 0;
 int			my_devices_state = 0;
 
 extern sys_config	Config;
-extern int		my_shutdown;
 extern pthread_mutex_t  mutexes[5];
 extern w1_list		*w1_devices;
 
@@ -314,8 +314,10 @@
 
 			    if ((write_w1(device->address, (char *)"output", output)) == 0) {
 			    	syslog(LOG_NOTICE, "DS2413 PIO%c value=%d (%s)", (device->subdevice == 0) ? 'A' : 'B', (value == 0) ? 0 : 1, device->comment);
+				pthread_mutex_lock(&mutexes[LOCK_DEVICES]);
 				device->value = (value == 0) ? 0 : 1;
 				device->timestamp = time(NULL);
+				pthread_mutex_unlock(&mutexes[LOCK_DEVICES]);
 			    }
 			}
 		    }
@@ -419,7 +421,8 @@
 	}
 
 	if (found == FALSE) {
-	    for (i = 0; i < dev_w1->subdevices; i++) {
+	    subdevices = (strcmp(dev_w1->family, (char *)"3a") == 0) ? 2:1;
+	    for (i = 0; i < subdevices; i++) {
 		ndev = (devices_list *)malloc(sizeof(devices_list));
 		ndev->next = NULL;
 		ndev->uuid = malloc(37);
@@ -714,12 +717,13 @@
 void *my_devices_loop(void *threadid)
 {
     devices_list	*device;
+    w1_list		*dev_w1;
 #ifdef USE_SIMULATOR
     simulator_list	*simulator;
 #endif
-    char		*addr = NULL, line1[60], line2[60], *p = NULL;
-    FILE		*fp;
-    int			temp, rc;
+//    char		*addr = NULL, line1[60], line2[60], *p = NULL;
+//    FILE		*fp;
+    int			rc, found;
     time_t		now;
 
     my_devices_state = 1;
@@ -735,27 +739,27 @@
     /*
      * Set the temperature sensors to 12 bits resolution and write it in EEPROM
      */
-    for (device = Config.devices; device; device = device->next) {
-	if ((device->type == DEVTYPE_W1) &&
-	    ((strncmp(device->address, (char *)"10", 2) == 0) ||
-             (strncmp(device->address, (char *)"22", 2) == 0) ||
-             (strncmp(device->address, (char *)"28", 2) == 0) ||
-             (strncmp(device->address, (char *)"3b", 2) == 0) ||
-             (strncmp(device->address, (char *)"42", 2) == 0))) {
-	    addr = xstrcpy((char *)"/sys/bus/w1/devices/");
-            addr = xstrcat(addr, device->address);
-            addr = xstrcat(addr, (char *)"/w1_slave");
-            if ((fp = fopen(addr, "w"))) {
-		rc = fprintf(fp, "12\n0\n");	// According to the kernel documentation. Seems to work.
-		fclose(fp);
-		if (rc != 5) {
-		    syslog(LOG_NOTICE, "Program 12 bits resolution error rc=%d for %s", rc, addr);
-                }
-	    }
-	    free(addr);
-	    addr = NULL;
-	}
-    }
+//    for (device = Config.devices; device; device = device->next) {
+//	if ((device->type == DEVTYPE_W1) &&
+//	    ((strncmp(device->address, (char *)"10", 2) == 0) ||
+  //           (strncmp(device->address, (char *)"22", 2) == 0) ||
+//             (strncmp(device->address, (char *)"28", 2) == 0) ||
+//             (strncmp(device->address, (char *)"3b", 2) == 0) ||
+//             (strncmp(device->address, (char *)"42", 2) == 0))) {
+//	    addr = xstrcpy((char *)"/sys/bus/w1/devices/");
+//            addr = xstrcat(addr, device->address);
+//            addr = xstrcat(addr, (char *)"/w1_slave");
+//            if ((fp = fopen(addr, "w"))) {
+//		rc = fprintf(fp, "12\n0\n");	// According to the kernel documentation. Seems to work.
+//		fclose(fp);
+//		if (rc != 5) {
+//		    syslog(LOG_NOTICE, "Program 12 bits resolution error rc=%d for %s", rc, addr);
+//                }
+//	    }
+//	    free(addr);
+//	    addr = NULL;
+//	}
+//    }
 
     /*
      * Loop forever until the external shutdown variable is set.
@@ -767,7 +771,7 @@
     	 */
     	for (device = Config.devices; device; device = device->next) {
 
-	    if (my_shutdown)
+	    if (my_devices_shutdown)
 		break;
 
 	    switch (device->type) {
@@ -781,51 +785,23 @@
 			    (strncmp(device->address, (char *)"28", 2) == 0) ||
 			    (strncmp(device->address, (char *)"3b", 2) == 0) ||
 			    (strncmp(device->address, (char *)"42", 2) == 0)) {
-			    addr = xstrcpy((char *)"/sys/bus/w1/devices/");
-			    addr = xstrcat(addr, device->address);
-			    addr = xstrcat(addr, (char *)"/w1_slave");
-			    if ((fp = fopen(addr, "r"))) {
-				fgets(line1, 50, fp);	// Read 2 lines
-				fgets(line2, 50, fp);
-				fclose(fp);
-				/*
-				 * 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
-				 */
-				line1[strlen(line1)-1] = '\0';
-				if ((line1[36] == 'Y') && (line1[37] == 'E')) {
-				    /* CRC is Ok, continue */
-				    if (device->present != DEVPRESENT_YES) {
-					syslog(LOG_NOTICE, "sensor %s is Ok", device->address);
-					pthread_mutex_lock(&mutexes[LOCK_DEVICES]);
+			    found = FALSE;
+			    for (dev_w1 = w1_devices; dev_w1; dev_w1 = dev_w1->next) {
+				if (strcmp(device->address, dev_w1->address) == 0) {
+				    syslog(LOG_NOTICE, "sensor %s value %d", dev_w1->address, dev_w1->value);
+				    found = TRUE;
+				    if ((dev_w1->value == -1) || (dev_w1->value < -55000)) {
+					syslog(LOG_NOTICE, "sensor %s value error %d", device->address, dev_w1->value);
+					device->present = DEVPRESENT_ERROR;
+				    } else {
+					device->value = dev_w1->value;
+					device->timestamp = time(NULL);
 					device->present = DEVPRESENT_YES;
-					pthread_mutex_unlock(&mutexes[LOCK_DEVICES]);
 				    }
+				}
+			    }
 
-				    line2[strlen(line2)-1] = '\0';
-				    strtok(line2, (char *)"=");
-				    p = strtok(NULL, (char *)"=");
-				    rc = sscanf(p, "%d", &temp);
-				    if ((rc == 1) && (device->value != temp)) {
-					pthread_mutex_lock(&mutexes[LOCK_DEVICES]);
-					if (temp < -55000) {
-					    syslog(LOG_NOTICE, "sensor %s value error '%d` '%s`", device->address, temp, line1);
-					    device->present = DEVPRESENT_ERROR;
-					} else {
-					    device->value = temp;
-				    	    device->timestamp = time(NULL);
-					    device->present = DEVPRESENT_YES;
-					}
-					pthread_mutex_unlock(&mutexes[LOCK_DEVICES]);
-				    }
-				} else {
-				    syslog(LOG_NOTICE, "sensor %s CRC error '%s`", device->address, line1);
-				    pthread_mutex_lock(&mutexes[LOCK_DEVICES]);
-				    device->present = DEVPRESENT_ERROR;
-				    pthread_mutex_unlock(&mutexes[LOCK_DEVICES]);
-				}
-			    } else {
+			    if (found == FALSE) {
 				if (device->present != DEVPRESENT_NO) {
 				    syslog(LOG_NOTICE, "sensor %s is missing", device->address);
 				    pthread_mutex_lock(&mutexes[LOCK_DEVICES]);
@@ -833,8 +809,7 @@
 				    pthread_mutex_unlock(&mutexes[LOCK_DEVICES]);
 				}
 			    }
-			    free(addr);
-			    addr = NULL;
+
 			} /* if temperature sensor */
 
 			break;
@@ -914,12 +889,14 @@
 			break;
 	    }
 
+	    if (my_devices_shutdown)
+		break;
 	    /*
 	     * Delay a bit after procesing a device.
 	     */
 	    mDelay(10);
 	}
-	if (my_shutdown)
+	if (my_devices_shutdown)
 	    break;
 	/*
 	 * Delay a bit after all devices
--- a/thermferm/one-wire.c	Wed Apr 03 19:33:38 2024 +0200
+++ b/thermferm/one-wire.c	Fri Apr 05 16:19:39 2024 +0200
@@ -28,12 +28,14 @@
 #include "futil.h"
 #include "xutil.h"
 
+#define	W1_TEMP_RESOLUTION	12
+
 
 extern sys_config	Config;
-extern int		my_shutdown;
 extern pthread_mutex_t	mutexes[5];
 
 int			my_one_wire_state = 0;
+int			my_one_wire_shutdown = 0;
 w1_list			*w1_devices = NULL;
 
 
@@ -66,17 +68,17 @@
     ScanNew,
     ScanDel,
     Read2413,
-    Reading,
+    ReadTemp,
     Missing
 SM_NAMES
     (char *)"ScanNew",
     (char *)"ScanDel",
     (char *)"Read2413",
-    (char *)"Reading",
+    (char *)"ReadTemp",
     (char *)"Missing"
 SM_EDECL
 
-    int			found, i, rc;
+    int			found, i, rc, value, conv_time;
     FILE		*fp;
     devices_list	*device;
     w1_list		*dev_w1, *n_w1, *cur_w1 = NULL;
@@ -87,7 +89,7 @@
 
 SM_STATE(ScanNew)
 
-    if (my_shutdown) {
+    if (my_one_wire_shutdown) {
 	SM_SUCCESS;
     }
 
@@ -122,9 +124,9 @@
 			pthread_mutex_unlock(&mutexes[LOCK_ONE_WIRE]);
 			for (device = Config.devices; device; device = device->next) {
 			    if (strcmp(dev_w1->address, device->address) == 0) {
-				pthread_mutex_lock(&mutexes[LOCK_DEVICES]);
+//				pthread_mutex_lock(&mutexes[LOCK_DEVICES]);
 				device->present = DEVPRESENT_YES;
-				pthread_mutex_unlock(&mutexes[LOCK_DEVICES]);
+//				pthread_mutex_unlock(&mutexes[LOCK_DEVICES]);
 			    }
 			}
 		    }
@@ -139,7 +141,8 @@
 		strncpy(n_w1->family, buffer, 2);
 		n_w1->family[2] = '\0';
 		n_w1->present = DEVPRESENT_YES;
-		n_w1->subdevices = (strcmp(w1type, (char *)"3a") == 0) ? 2:1;
+		n_w1->value = (strcmp(w1type, (char *)"3a") == 0) ? 3:-1;
+//		n_w1->subdevices = (strcmp(w1type, (char *)"3a") == 0) ? 2:1;
 		n_w1->timestamp = time(NULL);
 
 		pthread_mutex_lock(&mutexes[LOCK_ONE_WIRE]);
@@ -165,7 +168,7 @@
 
 SM_STATE(ScanDel)
 
-    if (my_shutdown) {
+    if (my_one_wire_shutdown) {
 	SM_SUCCESS;
     }
 
@@ -192,19 +195,21 @@
 		}
 	    }
 	}
+	free(devfile);
+	devfile = NULL;
     }
 
     SM_PROCEED(Read2413);
 
 SM_STATE(Read2413)
 
-    if (my_shutdown) {
+    if (my_one_wire_shutdown) {
 	SM_SUCCESS;
     }
 
     for (dev_w1 = w1_devices; dev_w1; dev_w1 = dev_w1->next) {
 	if (strcmp(dev_w1->family, "3a") == 0) {
-	    syslog(LOG_NOTICE, "ds2413 %s", dev_w1->address);
+//	    syslog(LOG_NOTICE, "ds2413 %s", dev_w1->address);
 	    for (i = 0; i < 2; i++) {
 		for (device = Config.devices; device; device = device->next) {
 		    if ((strcmp(dev_w1->address, device->address) == 0) && (device->subdevice == i) && (device->direction == DEVDIR_IN_BIN)) {
@@ -216,7 +221,7 @@
 			    state = (unsigned int)rc;
 			    output = ((state & 0x02) >> 1) + ((state & 0x08) >> 2);		/* Both latch states	*/
 			    if ((i == 0) && ((state & 0x02) == 0)) {				/* Fix A side		*/
-				syslog(LOG_NOTICE, "One-wire device %s-%d out %04x -> %04x", dev_w1->address, i, output, output | 0x01);
+				syslog(LOG_NOTICE, "One-wire device %s-%d out %02x -> %02x", dev_w1->address, i, output, output | 0x01);
 				output |= 0x01;
 				write_w1(device->address, (char *)"output", output);
 				mDelay(10);
@@ -224,7 +229,7 @@
 				    state = (unsigned int)rc;
 			    }
 			    if ((i == 1) && ((state & 0x08) == 0)) {				/* Fix B side		*/
-				syslog(LOG_NOTICE, "One-wire device %s-%d out %04x -> %04x", dev_w1->address, i, output, output | 0x02);
+				syslog(LOG_NOTICE, "One-wire device %s-%d out %02x -> %02x", dev_w1->address, i, output, output | 0x02);
 				output |= 0x02;
 				write_w1(device->address, (char *)"output", output);
 				mDelay(10);
@@ -232,16 +237,19 @@
 				    state = (unsigned int)rc;
 			    }
 
-			    pthread_mutex_lock(&mutexes[LOCK_DEVICES]);
+			    dev_w1->value = ((state & 0x04) >> 1) + (state & 0x01);
+			    syslog(LOG_NOTICE, "One-wire device %s-%d in %02x value %d", dev_w1->address, i, state, dev_w1->value);
+
+//			    pthread_mutex_lock(&mutexes[LOCK_DEVICES]);
 			    /*
 			     * Read PIOA or PIOB pin state bits
 			     */
 			    if (device->subdevice == 0)
-				device->value = (rc & 0x01) ? 0 : 1;
+				device->value = (state & 0x01) ? 0 : 1;
 			    else if (device->subdevice == 1)
-				device->value = (rc & 0x04) ? 0 : 1;
+				device->value = (state & 0x04) ? 0 : 1;
 			    device->timestamp = time(NULL);
-			    pthread_mutex_unlock(&mutexes[LOCK_DEVICES]);
+//			    pthread_mutex_unlock(&mutexes[LOCK_DEVICES]);
 			}
 			mDelay(20);
 		    }
@@ -250,11 +258,11 @@
 	}
     }
 
-    SM_PROCEED(Reading);
+    SM_PROCEED(ReadTemp);
 
-SM_STATE(Reading)
+SM_STATE(ReadTemp)
 
-    if (my_shutdown) {
+    if (my_one_wire_shutdown) {
 	SM_SUCCESS;
     }
 
@@ -265,17 +273,80 @@
 
 	if ((strcmp(cur_w1->family, (char *)"10") == 0) || (strcmp(cur_w1->family, (char *)"22") == 0) || (strcmp(cur_w1->family, (char *)"28") == 0) ||
 	    (strcmp(cur_w1->family, (char *)"3b") == 0) || (strcmp(cur_w1->family, (char *)"42") == 0)) {
-	    syslog(LOG_NOTICE, "Reading %s", cur_w1->address);
-	    sleep(1);
+//	    syslog(LOG_NOTICE, "Reading %s", cur_w1->address);
+	    /*
+	     * 1. Read sensor resolution. This is a present check too.
+	     * 2. Fix resolution if wrong.
+	     * 3. Read conversion time.
+	     * 4. Open temperature for read.
+	     * 5. Wait conversion time.
+	     * 6. Read temperature.
+	     */
+	    devfile = xstrcpy((char *)"/sys/bus/w1/devices/");
+	    devfile = xstrcat(devfile, cur_w1->address);
+	    devfile = xstrcat(devfile, (char *)"/resolution");
+	    if ((fp = fopen(devfile, "r+"))) {
+		if ((fgets(buffer, 25, fp))) {
+		     sscanf(buffer, "%d", &value);
+		     if (value != W1_TEMP_RESOLUTION) {
+			syslog(LOG_NOTICE, "One-wire device %s set resolution from %d to %d", cur_w1->address, value, W1_TEMP_RESOLUTION);
+			fseek(fp, 0L, SEEK_SET);
+			sprintf(buffer, "%d", W1_TEMP_RESOLUTION);
+			fputs(buffer, fp);
+		     }
+		}
+		fclose(fp);
+		free(devfile);
+
+		conv_time = 760;
+		devfile = xstrcpy((char *)"/sys/bus/w1/devices/");
+		devfile = xstrcat(devfile, cur_w1->address);
+		devfile = xstrcat(devfile, (char *)"/conv_time");
+		if ((fp = fopen(devfile, "r"))) {
+		    if ((fgets(buffer, 25, fp))) {
+			sscanf(buffer, "%d", &conv_time);
+		    }
+		    fclose(fp);
+		}
+		free(devfile);
+
+		devfile = xstrcpy((char *)"/sys/bus/w1/devices/");
+		devfile = xstrcat(devfile, cur_w1->address);
+		devfile = xstrcat(devfile, (char *)"/temperature");
+		if ((fp = fopen(devfile, "r"))) {
+		    syslog(LOG_NOTICE, "One-wire device %s temperature is open, delay %d", cur_w1->address, conv_time);
+		    mDelay(conv_time);
+		    if ((fgets(buffer, 25, fp))) {
+			sscanf(buffer, "%d", &value);
+			syslog(LOG_NOTICE, "One-wire device %s temperature read %d", cur_w1->address, value);
+			cur_w1->value = value;		/* devices.c will pick this up */
+		    } else {
+			syslog(LOG_NOTICE, "One-wire device %s temperature read error", cur_w1->address);
+		    }
+		    fclose(fp);
+		}
+
+	    } else {
+		syslog(LOG_NOTICE, "One-wire device %s open: %s", cur_w1->address, strerror(errno));
+	    }
+	    free(devfile);
+	    devfile = NULL;
 	}
 
-	if (cur_w1->next != NULL) {
-	    cur_w1 = cur_w1->next;
-	} else {
-	    cur_w1 = w1_devices;
+	for (;;) {
+	    if (cur_w1->next != NULL) {
+	    	cur_w1 = cur_w1->next;
+	    } else {
+	    	cur_w1 = w1_devices;
+	    }
+	    if ((strcmp(cur_w1->family, (char *)"10") == 0) || (strcmp(cur_w1->family, (char *)"22") == 0) || (strcmp(cur_w1->family, (char *)"28") == 0) ||
+		(strcmp(cur_w1->family, (char *)"3b") == 0) || (strcmp(cur_w1->family, (char *)"42") == 0))
+		break;
 	}
+	syslog(LOG_NOTICE, "One-wire device %s next sensor %s", cur_w1->address, cur_w1->family);
 
     } else {
+	syslog(LOG_NOTICE, "cur_w1 == NULL");
     	sleep(1);
     }
 
@@ -283,7 +354,7 @@
 
 SM_STATE(Missing)
 
-    if (my_shutdown) {
+    if (my_one_wire_shutdown) {
 	SM_SUCCESS;
     }
 
--- a/thermferm/panel.c	Wed Apr 03 19:33:38 2024 +0200
+++ b/thermferm/panel.c	Fri Apr 05 16:19:39 2024 +0200
@@ -46,7 +46,6 @@
 
 
 
-extern int		my_shutdown;
 extern int		debug;
 extern int		setupmenu;
 extern uint16_t		keys;
@@ -55,6 +54,7 @@
 extern pthread_mutex_t  mutexes[5];
 
 int			my_panel_state = 0;
+int			my_panel_shutdown = 0;
 int			Key_Enter = FALSE;
 int			Key_Enter_Long = FALSE;
 int			Key_Up = FALSE;
@@ -123,7 +123,7 @@
      * Loop forever until the external shutdown variable is set.
      */
     for (;;) {
-	if (my_shutdown)
+	if (my_panel_shutdown)
 	    break;
 
 #ifdef HAVE_WIRINGPI_H
--- a/thermferm/server.c	Wed Apr 03 19:33:38 2024 +0200
+++ b/thermferm/server.c	Fri Apr 05 16:19:39 2024 +0200
@@ -30,7 +30,6 @@
 #include "mqtt.h"
 
 
-extern int		my_shutdown;
 extern int		debug;
 extern int		run_pause;
 extern int		run_hold;
@@ -46,7 +45,8 @@
 
 
 int			my_server_state = 0;	/* Thread running state		*/
-int			s;			/* connected socket		*/
+int			my_server_shutdown = 0;	/* Thread shutdown		*/
+//int			s;			/* connected socket		*/
 int			ls;			/* listen socket		*/
 
 struct sockaddr_in	myaddr_in;		/* for local socket address	*/
@@ -83,7 +83,7 @@
 /*
  * Send message to client
  */
-int srv_send(const char *format, ...)
+int srv_send(int s, const char *format, ...)
 {
     char        out[SS_BUFSIZE];
     va_list     va_ptr;
@@ -120,7 +120,7 @@
  * Return -1 if error, else the number of received
  * character. \n is line end, ignore \r.
  */
-int srv_recv(char *buffer)
+int srv_recv(int s, char *buffer)
 {
     int			bytesloaded = 0;
     ssize_t		ret;
@@ -304,7 +304,7 @@
  * DEVICE GET uuid
  * DEVICE PUT uuid
  */
-int cmd_device(char *buf)
+int cmd_device(int s, char *buf)
 {
     char		*opt, *param, *kwd, *val, ibuf[SS_BUFSIZE];
     devices_list	*device, *tmpd;
@@ -315,35 +315,35 @@
     opt = strtok(NULL, " \0");
 
     if (opt == NULL) {
-	srv_send((char *)"501 Subcommand missing");
+	srv_send(s, (char *)"501 Subcommand missing");
 	return 0;
     }
     param = strtok(NULL, "\0");
 
     if (strcmp(opt, (char *)"HELP") == 0) {
-	srv_send((char *)"100 Help text follows:");
-	srv_send((char *)"Recognized commands:");
-	srv_send((char *)"DEVICE ADD type               Add device (RC433/DHT/I2C/SPI)");
-	srv_send((char *)"DEVICE DEL uuid               Delete device by uuid");
-	srv_send((char *)"DEVICE LIST                   List all devices");
-	srv_send((char *)"DEVICE GET uuid               Read device by uuid parameters");
-	srv_send((char *)"DEVICE PUT uuid               Write device by uuid parameters");
-	srv_send((char *)".");
+	srv_send(s, (char *)"100 Help text follows:");
+	srv_send(s, (char *)"Recognized commands:");
+	srv_send(s, (char *)"DEVICE ADD type               Add device (RC433/DHT/I2C/SPI)");
+	srv_send(s, (char *)"DEVICE DEL uuid               Delete device by uuid");
+	srv_send(s, (char *)"DEVICE LIST                   List all devices");
+	srv_send(s, (char *)"DEVICE GET uuid               Read device by uuid parameters");
+	srv_send(s, (char *)"DEVICE PUT uuid               Write device by uuid parameters");
+	srv_send(s, (char *)".");
 	return 0;
     }
 
     if (strcmp(opt, (char *)"LIST") == 0) {
-	srv_send((char *)"212 Devices list follows:");
+	srv_send(s, (char *)"212 Devices list follows:");
 	for (device = Config.devices; device; device = device->next) {
-	    srv_send((char *)"%s,%s,%d,%d,%s,%s,%d", device->uuid, device->address, device->subdevice,
+	    srv_send(s, (char *)"%s,%s,%d,%d,%s,%s,%d", device->uuid, device->address, device->subdevice,
 			    device->inuse, device->comment, DEVDIR[device->direction], device->value + device->offset);
 	}
-	srv_send((char *)".");
+	srv_send(s, (char *)".");
 	return 0;
     }
 
     if (param == NULL) {
-	srv_send((char *)"502 Parameter missing");
+	srv_send(s, (char *)"502 Parameter missing");
 	return 1;
     }
 
@@ -383,11 +383,11 @@
 	    }
 	    pthread_mutex_unlock(&mutexes[LOCK_DEVICES]);
 	    syslog(LOG_NOTICE, "Device %s added", device->uuid);
-	    srv_send((char *)"211 Device %s added", device->uuid);
+	    srv_send(s, (char *)"211 Device %s added", device->uuid);
 	    return 1;
 
 	} else {
-	    srv_send((char *)"503 Parameter error");
+	    srv_send(s, (char *)"503 Parameter error");
 	    return 0;
 	}
     }
@@ -399,10 +399,10 @@
 	pthread_mutex_unlock(&mutexes[LOCK_DEVICES]);
 	if (rc) {
 	    syslog(LOG_NOTICE, "Device %s deleted", param);
-	    srv_send((char *)"211 Device %s deleted", param);
+	    srv_send(s, (char *)"211 Device %s deleted", param);
 	    return 1;
 	} else {
-	    srv_send((char *)"440 No such device");
+	    srv_send(s, (char *)"440 No such device");
 	    return 0;
 	}
     }
@@ -414,24 +414,24 @@
 		int	my_value = device->value;
 		int	my_timestamp = (int)device->timestamp;
 		pthread_mutex_unlock(&mutexes[LOCK_DEVICES]);
-		srv_send((char *)"213 Device record follows:");
-		srv_send((char *)"TYPE,%s", DEVTYPE[device->type]);
-		srv_send((char *)"ADDRESS,%s", device->address);
-		srv_send((char *)"DIRECTION,%s", DEVDIR[device->direction]);
-		srv_send((char *)"VALUE,%d", my_value);
-		srv_send((char *)"OFFSET,%d", device->offset);
-		srv_send((char *)"PRESENT,%s", DEVPRESENT[device->present]);
-		srv_send((char *)"SUBDEVICE,%d", device->subdevice);
-		srv_send((char *)"GPIOPIN,%d", device->gpiopin);
-		srv_send((char *)"DESCRIPTION,%s", device->description);
-		srv_send((char *)"INUSE,%d", device->inuse);
-		srv_send((char *)"COMMENT,%s", device->comment);
-		srv_send((char *)"TIMESTAMP,%d", my_timestamp);
-		srv_send((char *)".");
+		srv_send(s, (char *)"213 Device record follows:");
+		srv_send(s, (char *)"TYPE,%s", DEVTYPE[device->type]);
+		srv_send(s, (char *)"ADDRESS,%s", device->address);
+		srv_send(s, (char *)"DIRECTION,%s", DEVDIR[device->direction]);
+		srv_send(s, (char *)"VALUE,%d", my_value);
+		srv_send(s, (char *)"OFFSET,%d", device->offset);
+		srv_send(s, (char *)"PRESENT,%s", DEVPRESENT[device->present]);
+		srv_send(s, (char *)"SUBDEVICE,%d", device->subdevice);
+		srv_send(s, (char *)"GPIOPIN,%d", device->gpiopin);
+		srv_send(s, (char *)"DESCRIPTION,%s", device->description);
+		srv_send(s, (char *)"INUSE,%d", device->inuse);
+		srv_send(s, (char *)"COMMENT,%s", device->comment);
+		srv_send(s, (char *)"TIMESTAMP,%d", my_timestamp);
+		srv_send(s, (char *)".");
 		return 0;
 	    }
 	}
-	srv_send((char *)"440 No such device");
+	srv_send(s, (char *)"440 No such device");
 	return 0;
     }
 
@@ -439,13 +439,13 @@
 	for (device = Config.devices; device; device = device->next) {
 	    if (strcmp(device->uuid, param) == 0) {
 		while (1) {
-		    rlen = srv_recv(ibuf);
+		    rlen = srv_recv(s, ibuf);
     		    if (rlen == -1) {
 			return 0;
 		    }
 		    if (strlen(ibuf)) {
 			if (strcmp(ibuf, (char *)".") == 0) {
-			    srv_send((char *)"219 Accepted Device record");
+			    srv_send(s, (char *)"219 Accepted Device record");
 			    return 1;
 			}
 			kwd = strtok(ibuf, ",\0");
@@ -559,11 +559,11 @@
 		}
 	    }
 	}
-	srv_send((char *)"440 No such device");
+	srv_send(s, (char *)"440 No such device");
 	return 0;
     }
 
-    srv_send((char *)"504 Subcommand error");
+    srv_send(s, (char *)"504 Subcommand error");
     return 0;
 }
 
@@ -573,7 +573,7 @@
  * GLOBAL GET
  * GLOBAL PUT
  */
-int cmd_global(char *buf)
+int cmd_global(int s, char *buf)
 {
     char	*opt, *kwd, *val, ibuf[SS_BUFSIZE];
     int		ival, rlen;
@@ -582,53 +582,53 @@
     opt = strtok(NULL, "\0");
 
     if (opt == NULL) {
-	srv_send((char *)"501 Subcommand missing");
+	srv_send(s, (char *)"501 Subcommand missing");
 	return 0;
     }
 
     if (strcmp(opt, (char *)"HELP") == 0) {
-	srv_send((char *)"100 Help text follows:");
-	srv_send((char *)"Recognized commands:");
-	srv_send((char *)"GLOBAL GET                    Get global settings");
-	srv_send((char *)"GLOBAL PUT                    Put global settings");
-	srv_send((char *)".");
+	srv_send(s, (char *)"100 Help text follows:");
+	srv_send(s, (char *)"Recognized commands:");
+	srv_send(s, (char *)"GLOBAL GET                    Get global settings");
+	srv_send(s, (char *)"GLOBAL PUT                    Put global settings");
+	srv_send(s, (char *)".");
 	return 0;
     }
 
     if (strcmp(opt, (char *)"GET") == 0) {
-	srv_send((char *)"213 Global Settings record follows:");
-	srv_send((char *)"RELEASE,%s", VERSION);
-	srv_send((char *)"NAME,%s", Config.name);
-	srv_send((char *)"PORT,%d", Config.my_port);
-	srv_send((char *)"TEMPFORMAT,%c", Config.tempFormat);
-	srv_send((char *)"TEMP_ADDRESS,%s", Config.temp_address);
-	srv_send((char *)"TEMP_STATE,%s", TEMPSTATE[Config.temp_state]);
-	srv_send((char *)"TEMP_VALUE,%.1f", Config.temp_value / 1000.0);
-	srv_send((char *)"HUM_ADDRESS,%s", Config.hum_address);
-	srv_send((char *)"HUM_STATE,%s", TEMPSTATE[Config.hum_state]);
-	srv_send((char *)"HUM_VALUE,%.0f", Config.hum_value / 1000.0);
-	srv_send((char *)"TEMP_HUM_IDX,%d", Config.temp_hum_idx);
-	srv_send((char *)"LCD_COLS,%d", Config.lcd_cols);
-	srv_send((char *)"LCD_ROWS,%d", Config.lcd_rows);
-	srv_send((char *)"NEXT_UNIT,%d", Config.next_unit);
-	srv_send((char *)"MQTT_HOST,%s", Config.mqtt_host);
-	srv_send((char *)"MQTT_PORT,%d", Config.mqtt_port);
-	srv_send((char *)"MQTT_USER,%s", Config.mqtt_username);
-	srv_send((char *)"MQTT_PASS,%s", Config.mqtt_password);
-	srv_send((char *)".");
+	srv_send(s, (char *)"213 Global Settings record follows:");
+	srv_send(s, (char *)"RELEASE,%s", VERSION);
+	srv_send(s, (char *)"NAME,%s", Config.name);
+	srv_send(s, (char *)"PORT,%d", Config.my_port);
+	srv_send(s, (char *)"TEMPFORMAT,%c", Config.tempFormat);
+	srv_send(s, (char *)"TEMP_ADDRESS,%s", Config.temp_address);
+	srv_send(s, (char *)"TEMP_STATE,%s", TEMPSTATE[Config.temp_state]);
+	srv_send(s, (char *)"TEMP_VALUE,%.1f", Config.temp_value / 1000.0);
+	srv_send(s, (char *)"HUM_ADDRESS,%s", Config.hum_address);
+	srv_send(s, (char *)"HUM_STATE,%s", TEMPSTATE[Config.hum_state]);
+	srv_send(s, (char *)"HUM_VALUE,%.0f", Config.hum_value / 1000.0);
+	srv_send(s, (char *)"TEMP_HUM_IDX,%d", Config.temp_hum_idx);
+	srv_send(s, (char *)"LCD_COLS,%d", Config.lcd_cols);
+	srv_send(s, (char *)"LCD_ROWS,%d", Config.lcd_rows);
+	srv_send(s, (char *)"NEXT_UNIT,%d", Config.next_unit);
+	srv_send(s, (char *)"MQTT_HOST,%s", Config.mqtt_host);
+	srv_send(s, (char *)"MQTT_PORT,%d", Config.mqtt_port);
+	srv_send(s, (char *)"MQTT_USER,%s", Config.mqtt_username);
+	srv_send(s, (char *)"MQTT_PASS,%s", Config.mqtt_password);
+	srv_send(s, (char *)".");
 	return 0;
     }
 
     if (strcmp(opt, (char *)"PUT") == 0) {
 	int mqtt_reconnect = 0;
 	while (1) {
-	    rlen = srv_recv(ibuf);
+	    rlen = srv_recv(s, ibuf);
 	    if (rlen == -1) {
 		return 0;
 	    }
 	    if (strlen(ibuf)) {
 		if (strcmp(ibuf, (char *)".") == 0) {
-		    srv_send((char *)"219 Accepted Global record");
+		    srv_send(s, (char *)"219 Accepted Global record");
 		    if (mqtt_reconnect)
 			mqtt_connect();
 		    return 1;
@@ -759,7 +759,7 @@
 	}
     }
 
-    srv_send((char *)"504 Subcommand error");
+    srv_send(s, (char *)"504 Subcommand error");
     return 0;
 }
 
@@ -768,7 +768,7 @@
 /*
  * LIST
  */
-int cmd_list(char *buf)
+int cmd_list(int s, char *buf)
 {
     char		*opt;
     units_list		*unit;
@@ -780,22 +780,22 @@
 	/*
 	 * Default, list available units
 	 */
-	srv_send((char *)"212 Fermenter list follows:");
+	srv_send(s, (char *)"212 Fermenter list follows:");
 	for (unit = Config.units; unit; unit = unit->next) {
-	    srv_send((char *)"%s,%s,%s", unit->uuid, unit->alias, UNITMODE[unit->mode]);
+	    srv_send(s, (char *)"%s,%s,%s", unit->uuid, unit->alias, UNITMODE[unit->mode]);
 	}
-	srv_send((char *)".");
+	srv_send(s, (char *)".");
 	return 0;
 
     } else if (strcmp(opt, (char *)"HELP") == 0) {
-	srv_send((char *)"100 Help text follows:");
-	srv_send((char *)"Recognized commands:");
-	srv_send((char *)"LIST                           List available units");
-	srv_send((char *)".");
+	srv_send(s, (char *)"100 Help text follows:");
+	srv_send(s, (char *)"Recognized commands:");
+	srv_send(s, (char *)"LIST                           List available units");
+	srv_send(s, (char *)".");
 	return 0;
     }
 
-    srv_send((char *)"504 Subcommand error");
+    srv_send(s, (char *)"504 Subcommand error");
     return 0;
 }
 
@@ -844,7 +844,7 @@
  * SIMULATOR GET uuid
  * SIMULATOR PUT uuid
  */
-int cmd_simulator(char *buf)
+int cmd_simulator(int s, char *buf)
 {
     char		*opt, *param, *kwd, *val, ibuf[SS_BUFSIZE];
     simulator_list	*simulator, *tmps;
@@ -856,34 +856,34 @@
     opt = strtok(NULL, " \0");
 
     if (opt == NULL) {
-	srv_send((char *)"501 Subcommand missing");
+	srv_send(s, (char *)"501 Subcommand missing");
 	return 0;
     }
     param = strtok(NULL, "\0");
 
     if (strcmp(opt, (char *)"HELP") == 0) {
-	srv_send((char *)"100 Help text follows:");
-	srv_send((char *)"Recognized commands:");
-	srv_send((char *)"SIMULATOR ADD name            Add a new Simulator with name");
-	srv_send((char *)"SIMULATOR DEL uuid            Delete Simulator by uuid");
-	srv_send((char *)"SIMULATOR LIST                List all Simulators");
-	srv_send((char *)"SIMULATOR GET uuid            Get Simulator record by uuid");
-	srv_send((char *)"SIMULATOR PUT uuid            Put Simulator record by uuid");
-	srv_send((char *)".");
+	srv_send(s, (char *)"100 Help text follows:");
+	srv_send(s, (char *)"Recognized commands:");
+	srv_send(s, (char *)"SIMULATOR ADD name            Add a new Simulator with name");
+	srv_send(s, (char *)"SIMULATOR DEL uuid            Delete Simulator by uuid");
+	srv_send(s, (char *)"SIMULATOR LIST                List all Simulators");
+	srv_send(s, (char *)"SIMULATOR GET uuid            Get Simulator record by uuid");
+	srv_send(s, (char *)"SIMULATOR PUT uuid            Put Simulator record by uuid");
+	srv_send(s, (char *)".");
 	return 0;
     }
 
     if (strcmp(opt, (char *)"LIST") == 0) {
-	srv_send((char *)"212 Simulators list follows:");
+	srv_send(s, (char *)"212 Simulators list follows:");
 	for (simulator = Config.simulators; simulator; simulator = simulator->next) {
-	    srv_send((char *)"%s,%s", simulator->uuid, simulator->name);
+	    srv_send(s, (char *)"%s,%s", simulator->uuid, simulator->name);
 	}
-	srv_send((char *)".");
+	srv_send(s, (char *)".");
 	return 0;
     }
 
     if (param == NULL) {
-	srv_send((char *)"502 Parameter missing");
+	srv_send(s, (char *)"502 Parameter missing");
 	return 0;
     }
 
@@ -893,7 +893,7 @@
 	 * For now, only one simulator is allowed.
 	 */
 	if (Config.simulators) {
-	    srv_send((char *)"441 Maximum simulators reached");
+	    srv_send(s, (char *)"441 Maximum simulators reached");
 	    return 0;
 	}
 
@@ -931,7 +931,7 @@
 	}
 
 	syslog(LOG_NOTICE, "Simulator %s added", simulator->uuid);
-	srv_send((char *)"211 Simulator %s added", simulator->uuid);
+	srv_send(s, (char *)"211 Simulator %s added", simulator->uuid);
 	return 1;
     }
 
@@ -939,10 +939,10 @@
 	rc = delete_Simulator(param);
 	if (rc) {
 	    syslog(LOG_NOTICE, "Simulator %s deleted", param);
-	    srv_send((char *)"211 Simulator %s deleted", param);
+	    srv_send(s, (char *)"211 Simulator %s deleted", param);
 	    return 1;
 	} else {
-	    srv_send((char *)"440 No such simulator");
+	    srv_send(s, (char *)"440 No such simulator");
 	    return 0;
 	}
     }
@@ -950,29 +950,29 @@
     if (strcmp(opt, (char *)"GET") == 0) {
 	for (simulator = Config.simulators; simulator; simulator = simulator->next) {
 	    if (strcmp(simulator->uuid, param) == 0) {
-		srv_send((char *)"213 Simulator record follows:");
-		srv_send((char *)"NAME,%s", simulator->name);
-		srv_send((char *)"VOLUME_AIR,%d", simulator->volume_air);
-		srv_send((char *)"VOLUME_BEER,%d", simulator->volume_beer);
-		srv_send((char *)"ROOM_TEMPERATURE,%.1f", simulator->room_temperature);
-		srv_send((char *)"ROOM_HUMIDITY,%.1f", simulator->room_humidity);
-		srv_send((char *)"AIR_TEMPERATURE,%.3f", simulator->air_temperature);
-		srv_send((char *)"BEER_TEMPERATURE,%.3f", simulator->beer_temperature);
-		srv_send((char *)"CHILLER_TEMPERATURE,%.3f", simulator->chiller_temperature);
-		srv_send((char *)"COOLER_TEMP,%.1f", simulator->cooler_temp);
-		srv_send((char *)"COOLER_TIME,%d", simulator->cooler_time);
-		srv_send((char *)"COOLER_SIZE,%.3f", simulator->cooler_size);
-		srv_send((char *)"HEATER_TEMP,%.1f", simulator->heater_temp);
-		srv_send((char *)"HEATER_TIME,%d", simulator->heater_time);
-		srv_send((char *)"HEATER_SIZE,%.3f", simulator->heater_size);
-		srv_send((char *)"HEATER_STATE,%d", simulator->heater_state);
-		srv_send((char *)"COOLER_STATE,%d", simulator->cooler_state);
-		srv_send((char *)"FRIGO_ISOLATION,%.3f", simulator->frigo_isolation);
-		srv_send((char *)".");
+		srv_send(s, (char *)"213 Simulator record follows:");
+		srv_send(s, (char *)"NAME,%s", simulator->name);
+		srv_send(s, (char *)"VOLUME_AIR,%d", simulator->volume_air);
+		srv_send(s, (char *)"VOLUME_BEER,%d", simulator->volume_beer);
+		srv_send(s, (char *)"ROOM_TEMPERATURE,%.1f", simulator->room_temperature);
+		srv_send(s, (char *)"ROOM_HUMIDITY,%.1f", simulator->room_humidity);
+		srv_send(s, (char *)"AIR_TEMPERATURE,%.3f", simulator->air_temperature);
+		srv_send(s, (char *)"BEER_TEMPERATURE,%.3f", simulator->beer_temperature);
+		srv_send(s, (char *)"CHILLER_TEMPERATURE,%.3f", simulator->chiller_temperature);
+		srv_send(s, (char *)"COOLER_TEMP,%.1f", simulator->cooler_temp);
+		srv_send(s, (char *)"COOLER_TIME,%d", simulator->cooler_time);
+		srv_send(s, (char *)"COOLER_SIZE,%.3f", simulator->cooler_size);
+		srv_send(s, (char *)"HEATER_TEMP,%.1f", simulator->heater_temp);
+		srv_send(s, (char *)"HEATER_TIME,%d", simulator->heater_time);
+		srv_send(s, (char *)"HEATER_SIZE,%.3f", simulator->heater_size);
+		srv_send(s, (char *)"HEATER_STATE,%d", simulator->heater_state);
+		srv_send(s, (char *)"COOLER_STATE,%d", simulator->cooler_state);
+		srv_send(s, (char *)"FRIGO_ISOLATION,%.3f", simulator->frigo_isolation);
+		srv_send(s, (char *)".");
 		return 0;
 	    }
 	}
-	srv_send((char *)"440 No such simulator");
+	srv_send(s, (char *)"440 No such simulator");
 	return 0;
     }
 
@@ -980,13 +980,13 @@
 	for (simulator = Config.simulators; simulator; simulator = simulator->next) {
 	    if (strcmp(simulator->uuid, param) == 0) {
 		while (1) {
-		    rlen = srv_recv(ibuf);
+		    rlen = srv_recv(s, ibuf);
 		    if (rlen == -1) {
 			return 0;
 		    }
 		    if (strlen(ibuf)) {
 			if (strcmp(ibuf, (char *)".") == 0) {
-			    srv_send((char *)"219 Accepted Simulator record");
+			    srv_send(s, (char *)"219 Accepted Simulator record");
 			    return 1;
 			}
 			kwd = strtok(ibuf, ",\0");
@@ -1119,11 +1119,11 @@
 		}
 	    }
 	}
-	srv_send((char *)"440 No such simulator");
+	srv_send(s, (char *)"440 No such simulator");
 	return 0;
     }
 
-    srv_send((char *)"504 Subcommand error");
+    srv_send(s, (char *)"504 Subcommand error");
     return 0;
 }
 #endif
@@ -1285,7 +1285,7 @@
  * UNIT GET uuid
  * UNIT PUT uuid
  */
-int cmd_unit(char *buf)
+int cmd_unit(int s, char *buf)
 {
     char                *opt, *param = NULL, *kwd, *val, ibuf[SS_BUFSIZE];
     units_list          *unit, *tmpu;
@@ -1297,38 +1297,38 @@
     opt = strtok(NULL, " \0");
 
     if (opt == NULL) {
-	srv_send((char *)"501 Subcommand missing");
+	srv_send(s, (char *)"501 Subcommand missing");
 	return 0;
     }
     param = strtok(NULL, "\0");
 
     if (strcmp(opt, (char *)"HELP") == 0) {
-	srv_send((char *)"100 Help text follows:");
-	srv_send((char *)"Recognized commands:");
-	srv_send((char *)"UNIT ADD name                 Add a new Unit with name");
-	srv_send((char *)"UNIT DEL uuid                 Delete Unit by uuid");
-	srv_send((char *)"UNIT LIST                     List all Units");
-	srv_send((char *)"UNIT GET uuid                 Get Unit record by uuid");
-	srv_send((char *)"UNIT PUT uuid                 Put Unit record by uuid");
-	srv_send((char *)".");
+	srv_send(s, (char *)"100 Help text follows:");
+	srv_send(s, (char *)"Recognized commands:");
+	srv_send(s, (char *)"UNIT ADD name                 Add a new Unit with name");
+	srv_send(s, (char *)"UNIT DEL uuid                 Delete Unit by uuid");
+	srv_send(s, (char *)"UNIT LIST                     List all Units");
+	srv_send(s, (char *)"UNIT GET uuid                 Get Unit record by uuid");
+	srv_send(s, (char *)"UNIT PUT uuid                 Put Unit record by uuid");
+	srv_send(s, (char *)".");
 	return 0;
     }
 
     if ((strcmp(opt, (char *)"LIST") == 0) && (param == NULL)) {
-	srv_send((char *)"212 Fermenter list follows:");
+	srv_send(s, (char *)"212 Fermenter list follows:");
 	for (unit = Config.units; unit; unit = unit->next) {
 	    if (strlen(unit->product_code) && strlen(unit->product_name)) {
-		srv_send((char *)"%s,%s %s,%s", unit->uuid, unit->product_code, unit->product_name, UNITMODE[unit->mode]);
+		srv_send(s, (char *)"%s,%s %s,%s", unit->uuid, unit->product_code, unit->product_name, UNITMODE[unit->mode]);
 	    } else {
-	    	srv_send((char *)"%s,%s,%s", unit->uuid, unit->alias, UNITMODE[unit->mode]);
+	    	srv_send(s, (char *)"%s,%s,%s", unit->uuid, unit->alias, UNITMODE[unit->mode]);
 	    }
 	}
-	srv_send((char *)".");
+	srv_send(s, (char *)".");
 	return 0;
     }
 
     if (param == NULL) {
-	srv_send((char *)"502 Parameter missing");
+	srv_send(s, (char *)"502 Parameter missing");
 	return 0;
     }
 
@@ -1396,7 +1396,7 @@
 	run_pause = FALSE;
 
 	syslog(LOG_NOTICE, "Unit %s added", unit->uuid);
-	srv_send((char *)"211 Unit %s added", unit->uuid);
+	srv_send(s, (char *)"211 Unit %s added", unit->uuid);
 	return 1;
     }
 
@@ -1417,10 +1417,10 @@
 
 	if (rc) {
 	    syslog(LOG_NOTICE, "Unit %s deleted", param);
-	    srv_send((char *)"211 Unit %s deleted", param);
+	    srv_send(s, (char *)"211 Unit %s deleted", param);
 	    return 1;
 	} else {
-	    srv_send((char *)"440 No such unit");
+	    srv_send(s, (char *)"440 No such unit");
 	    return 0;
 	}
     }
@@ -1428,102 +1428,102 @@
     if (strcmp(opt, (char *)"GET") == 0) {
 	for (unit = Config.units; unit; unit = unit->next) {
 	    if (strcmp(param, unit->uuid) == 0) {
-		srv_send((char *)"213 Unit listing follows:");
-		srv_send((char *)"UUID,%s", unit->uuid);
-		srv_send((char *)"ALIAS,%s", unit->alias);
-		srv_send((char *)"PRODUCT_NAME,%s", unit->product_name);
-		srv_send((char *)"PRODUCT_CODE,%s", unit->product_code);
-		srv_send((char *)"MODE,%s", UNITMODE[unit->mode]);
-		srv_send((char *)"STAGE,%s", UNITSTAGE[unit->stage]);
-		srv_send((char *)"VOLUME,%2f", unit->volume);
-		srv_send((char *)"AIR_ADDRESS,%s", unit->air_address);
-		srv_send((char *)"AIR_STATE,%s", TEMPSTATE[unit->air_state]);
-		srv_send((char *)"AIR_TEMPERATURE,%.3f", unit->air_temperature / 1000.0);
-		srv_send((char *)"AIR_IDX,%d", unit->air_idx);
-		srv_send((char *)"BEER_ADDRESS,%s", MBSE_SS(unit->beer_address));
-		srv_send((char *)"BEER_ADDRESS2,%s", MBSE_SS(unit->beer_address2));
-		srv_send((char *)"BEER_STATE,%s", TEMPSTATE[unit->beer_state]);
-		srv_send((char *)"BEER_TEMPERATURE,%.3f", unit->beer_temperature / 1000.0);
-		srv_send((char *)"BEER_IDX,%d", unit->beer_idx);
-		srv_send((char *)"CHILLER_ADDRESS,%s", MBSE_SS(unit->chiller_address));
-		srv_send((char *)"CHILLER_STATE,%s", TEMPSTATE[unit->chiller_state]);
-		srv_send((char *)"CHILLER_TEMPERATURE,%.3f", unit->chiller_temperature / 1000.0);
-		srv_send((char *)"CHILLER_IDX,%d", unit->chiller_idx);
-		srv_send((char *)"HEATER_ADDRESS,%s", unit->heater_address);
-		srv_send((char *)"HEATER_STATE,%d", unit->heater_state);
-		srv_send((char *)"HEATER_DELAY,%d", unit->heater_delay);
-		srv_send((char *)"HEATER_USAGE,%d", unit->heater_usage);
-		srv_send((char *)"HEATER_IDX,%d", unit->heater_idx);
+		srv_send(s, (char *)"213 Unit listing follows:");
+		srv_send(s, (char *)"UUID,%s", unit->uuid);
+		srv_send(s, (char *)"ALIAS,%s", unit->alias);
+		srv_send(s, (char *)"PRODUCT_NAME,%s", unit->product_name);
+		srv_send(s, (char *)"PRODUCT_CODE,%s", unit->product_code);
+		srv_send(s, (char *)"MODE,%s", UNITMODE[unit->mode]);
+		srv_send(s, (char *)"STAGE,%s", UNITSTAGE[unit->stage]);
+		srv_send(s, (char *)"VOLUME,%2f", unit->volume);
+		srv_send(s, (char *)"AIR_ADDRESS,%s", unit->air_address);
+		srv_send(s, (char *)"AIR_STATE,%s", TEMPSTATE[unit->air_state]);
+		srv_send(s, (char *)"AIR_TEMPERATURE,%.3f", unit->air_temperature / 1000.0);
+		srv_send(s, (char *)"AIR_IDX,%d", unit->air_idx);
+		srv_send(s, (char *)"BEER_ADDRESS,%s", MBSE_SS(unit->beer_address));
+		srv_send(s, (char *)"BEER_ADDRESS2,%s", MBSE_SS(unit->beer_address2));
+		srv_send(s, (char *)"BEER_STATE,%s", TEMPSTATE[unit->beer_state]);
+		srv_send(s, (char *)"BEER_TEMPERATURE,%.3f", unit->beer_temperature / 1000.0);
+		srv_send(s, (char *)"BEER_IDX,%d", unit->beer_idx);
+		srv_send(s, (char *)"CHILLER_ADDRESS,%s", MBSE_SS(unit->chiller_address));
+		srv_send(s, (char *)"CHILLER_STATE,%s", TEMPSTATE[unit->chiller_state]);
+		srv_send(s, (char *)"CHILLER_TEMPERATURE,%.3f", unit->chiller_temperature / 1000.0);
+		srv_send(s, (char *)"CHILLER_IDX,%d", unit->chiller_idx);
+		srv_send(s, (char *)"HEATER_ADDRESS,%s", unit->heater_address);
+		srv_send(s, (char *)"HEATER_STATE,%d", unit->heater_state);
+		srv_send(s, (char *)"HEATER_DELAY,%d", unit->heater_delay);
+		srv_send(s, (char *)"HEATER_USAGE,%d", unit->heater_usage);
+		srv_send(s, (char *)"HEATER_IDX,%d", unit->heater_idx);
 		if (unit->PID_heat) {
-		    srv_send((char *)"PIDH_IMAX,%.1f", unit->PID_heat->iMax);
-		    srv_send((char *)"PIDH_IDLERANGE,%.2f", unit->PID_heat->idleRange);
-		    srv_send((char *)"PIDH_PGAIN,%.3f", unit->PID_heat->pGain);
-		    srv_send((char *)"PIDH_IGAIN,%.3f", unit->PID_heat->iGain);
-		    srv_send((char *)"PIDH_DGAIN,%.3f", unit->PID_heat->dGain);
-		    srv_send((char *)"PIDH_SV,%.2f", unit->PID_heat->SetP);
+		    srv_send(s, (char *)"PIDH_IMAX,%.1f", unit->PID_heat->iMax);
+		    srv_send(s, (char *)"PIDH_IDLERANGE,%.2f", unit->PID_heat->idleRange);
+		    srv_send(s, (char *)"PIDH_PGAIN,%.3f", unit->PID_heat->pGain);
+		    srv_send(s, (char *)"PIDH_IGAIN,%.3f", unit->PID_heat->iGain);
+		    srv_send(s, (char *)"PIDH_DGAIN,%.3f", unit->PID_heat->dGain);
+		    srv_send(s, (char *)"PIDH_SV,%.2f", unit->PID_heat->SetP);
 		}
-		srv_send((char *)"COOLER_ADDRESS,%s", unit->cooler_address);
-		srv_send((char *)"COOLER_STATE,%d", unit->cooler_state);
-		srv_send((char *)"COOLER_DELAY,%d", unit->cooler_delay);
-		srv_send((char *)"COOLER_USAGE,%d", unit->cooler_usage);
-		srv_send((char *)"COOLER_IDX,%d", unit->cooler_idx);
+		srv_send(s, (char *)"COOLER_ADDRESS,%s", unit->cooler_address);
+		srv_send(s, (char *)"COOLER_STATE,%d", unit->cooler_state);
+		srv_send(s, (char *)"COOLER_DELAY,%d", unit->cooler_delay);
+		srv_send(s, (char *)"COOLER_USAGE,%d", unit->cooler_usage);
+		srv_send(s, (char *)"COOLER_IDX,%d", unit->cooler_idx);
 		if (unit->PID_cool) {
-		    srv_send((char *)"PIDC_IMAX,%.1f", unit->PID_cool->iMax);
-		    srv_send((char *)"PIDC_IDLERANGE,%.2f", unit->PID_cool->idleRange);
-		    srv_send((char *)"PIDC_PGAIN,%.3f", unit->PID_cool->pGain);
-		    srv_send((char *)"PIDC_IGAIN,%.3f", unit->PID_cool->iGain);
-		    srv_send((char *)"PIDC_DGAIN,%.3f", unit->PID_cool->dGain);
-		    srv_send((char *)"PIDC_SV,%.2f", unit->PID_cool->SetP);
+		    srv_send(s, (char *)"PIDC_IMAX,%.1f", unit->PID_cool->iMax);
+		    srv_send(s, (char *)"PIDC_IDLERANGE,%.2f", unit->PID_cool->idleRange);
+		    srv_send(s, (char *)"PIDC_PGAIN,%.3f", unit->PID_cool->pGain);
+		    srv_send(s, (char *)"PIDC_IGAIN,%.3f", unit->PID_cool->iGain);
+		    srv_send(s, (char *)"PIDC_DGAIN,%.3f", unit->PID_cool->dGain);
+		    srv_send(s, (char *)"PIDC_SV,%.2f", unit->PID_cool->SetP);
 		}
-		srv_send((char *)"FAN_ADDRESS,%s", unit->fan_address);
-		srv_send((char *)"FAN_STATE,%d", unit->fan_state);
-		srv_send((char *)"FAN_DELAY,%d", unit->fan_delay);
-		srv_send((char *)"FAN_USAGE,%d", unit->fan_usage);
-		srv_send((char *)"FAN_IDX,%d", unit->fan_idx);
-		srv_send((char *)"LIGHT_ADDRESS,%s", unit->light_address);
-		srv_send((char *)"LIGHT_STATE,%d", unit->light_state);
-		srv_send((char *)"LIGHT_DELAY,%d", unit->light_delay);
-		srv_send((char *)"LIGHT_USAGE,%d", unit->light_usage);
-		srv_send((char *)"LIGHT_IDX,%d", unit->light_idx);
-		srv_send((char *)"DOOR_ADDRESS,%s", unit->door_address);
-		srv_send((char *)"DOOR_STATE,%d", unit->door_state);
-		srv_send((char *)"DOOR_IDX,%d", unit->door_idx);
-		srv_send((char *)"PSU_ADDRESS,%s", unit->psu_address);
-		srv_send((char *)"PSU_STATE,%d", unit->psu_state);
-		srv_send((char *)"PSU_IDX,%d", unit->psu_idx);
-		srv_send((char *)"FRIDGE_SET_LO,%.1f", unit->fridge_set_lo);
-		srv_send((char *)"FRIDGE_SET_HI,%.1f", unit->fridge_set_hi);
-		srv_send((char *)"BEER_SET_LO,%.1f", unit->beer_set_lo);
-		srv_send((char *)"BEER_SET_HI,%.1f", unit->beer_set_hi);
+		srv_send(s, (char *)"FAN_ADDRESS,%s", unit->fan_address);
+		srv_send(s, (char *)"FAN_STATE,%d", unit->fan_state);
+		srv_send(s, (char *)"FAN_DELAY,%d", unit->fan_delay);
+		srv_send(s, (char *)"FAN_USAGE,%d", unit->fan_usage);
+		srv_send(s, (char *)"FAN_IDX,%d", unit->fan_idx);
+		srv_send(s, (char *)"LIGHT_ADDRESS,%s", unit->light_address);
+		srv_send(s, (char *)"LIGHT_STATE,%d", unit->light_state);
+		srv_send(s, (char *)"LIGHT_DELAY,%d", unit->light_delay);
+		srv_send(s, (char *)"LIGHT_USAGE,%d", unit->light_usage);
+		srv_send(s, (char *)"LIGHT_IDX,%d", unit->light_idx);
+		srv_send(s, (char *)"DOOR_ADDRESS,%s", unit->door_address);
+		srv_send(s, (char *)"DOOR_STATE,%d", unit->door_state);
+		srv_send(s, (char *)"DOOR_IDX,%d", unit->door_idx);
+		srv_send(s, (char *)"PSU_ADDRESS,%s", unit->psu_address);
+		srv_send(s, (char *)"PSU_STATE,%d", unit->psu_state);
+		srv_send(s, (char *)"PSU_IDX,%d", unit->psu_idx);
+		srv_send(s, (char *)"FRIDGE_SET_LO,%.1f", unit->fridge_set_lo);
+		srv_send(s, (char *)"FRIDGE_SET_HI,%.1f", unit->fridge_set_hi);
+		srv_send(s, (char *)"BEER_SET_LO,%.1f", unit->beer_set_lo);
+		srv_send(s, (char *)"BEER_SET_HI,%.1f", unit->beer_set_hi);
 		if (unit->profile_uuid) {
-		    srv_send((char *)"PROFILE_UUID,%s", unit->profile_uuid);
-		    srv_send((char *)"PROFILE_NAME,%s", unit->profile_name);
-		    srv_send((char *)"PROFILE_INITTEMP_LO,%.1f", unit->profile_inittemp_lo);
-		    srv_send((char *)"PROFILE_INITTEMP_HI,%.1f", unit->profile_inittemp_hi);
-		    srv_send((char *)"PROFILE_FRIDGE_MODE,%d", unit->profile_fridge_mode);
-		    srv_send((char *)"PROFILE_DURATION,%d", unit->profile_duration);
-		    srv_send((char *)"PROFILE_TOTALSTEPS,%d", unit->profile_totalsteps);
-		    srv_send((char *)"PROF_STARTED,%d", (int)unit->prof_started);
+		    srv_send(s, (char *)"PROFILE_UUID,%s", unit->profile_uuid);
+		    srv_send(s, (char *)"PROFILE_NAME,%s", unit->profile_name);
+		    srv_send(s, (char *)"PROFILE_INITTEMP_LO,%.1f", unit->profile_inittemp_lo);
+		    srv_send(s, (char *)"PROFILE_INITTEMP_HI,%.1f", unit->profile_inittemp_hi);
+		    srv_send(s, (char *)"PROFILE_FRIDGE_MODE,%d", unit->profile_fridge_mode);
+		    srv_send(s, (char *)"PROFILE_DURATION,%d", unit->profile_duration);
+		    srv_send(s, (char *)"PROFILE_TOTALSTEPS,%d", unit->profile_totalsteps);
+		    srv_send(s, (char *)"PROF_STARTED,%d", (int)unit->prof_started);
 		    if (unit->prof_state == PROFILE_RUN) {
-		    	srv_send((char *)"PROF_STATE,%s %d%%", PROFSTATE[unit->prof_state], unit->prof_percent);
+		    	srv_send(s, (char *)"PROF_STATE,%s %d%%", PROFSTATE[unit->prof_state], unit->prof_percent);
 		    } else {
-		    	srv_send((char *)"PROF_STATE,%s", PROFSTATE[unit->prof_state]);
+		    	srv_send(s, (char *)"PROF_STATE,%s", PROFSTATE[unit->prof_state]);
 		    }
-		    srv_send((char *)"PROF_TARGET_LO,%.3f", unit->prof_target_lo);
-		    srv_send((char *)"PROF_TARGET_HI,%.3f", unit->prof_target_hi);
-		    srv_send((char *)"PROF_FRIDGE_MODE,%d", unit->prof_fridge_mode);
-		    srv_send((char *)"PROF_PEAK_ABS,%.3f", unit->prof_peak_abs);
-		    srv_send((char *)"PROF_PEAK_REL,%.3f", unit->prof_peak_rel);
-		    srv_send((char *)"PROF_PRIMARY_DONE,%d", (int)unit->prof_primary_done);
+		    srv_send(s, (char *)"PROF_TARGET_LO,%.3f", unit->prof_target_lo);
+		    srv_send(s, (char *)"PROF_TARGET_HI,%.3f", unit->prof_target_hi);
+		    srv_send(s, (char *)"PROF_FRIDGE_MODE,%d", unit->prof_fridge_mode);
+		    srv_send(s, (char *)"PROF_PEAK_ABS,%.3f", unit->prof_peak_abs);
+		    srv_send(s, (char *)"PROF_PEAK_REL,%.3f", unit->prof_peak_rel);
+		    srv_send(s, (char *)"PROF_PRIMARY_DONE,%d", (int)unit->prof_primary_done);
 		}
-		srv_send((char *)"TEMP_SET_MIN,%.1f", unit->temp_set_min);
-		srv_send((char *)"TEMP_SET_MAX,%.1f", unit->temp_set_max);
-		srv_send((char *)"ALARM,%d", unit->alarm_flag);
-		srv_send((char *)".");
+		srv_send(s, (char *)"TEMP_SET_MIN,%.1f", unit->temp_set_min);
+		srv_send(s, (char *)"TEMP_SET_MAX,%.1f", unit->temp_set_max);
+		srv_send(s, (char *)"ALARM,%d", unit->alarm_flag);
+		srv_send(s, (char *)".");
 		return 0;
 	    }
 	}
-	srv_send((char *)"440 No such unit");
+	srv_send(s, (char *)"440 No such unit");
 	return 0;
     }
 
@@ -1542,14 +1542,14 @@
 	     if (strcmp(unit->uuid, param) == 0) {
 		while (1) {
 		    unit->mqtt_flag = 0;
-		    rlen = srv_recv(ibuf);
+		    rlen = srv_recv(s, ibuf);
 		    if (rlen == -1) {
 			run_pause = FALSE;
 			return 0;
 		    }
 		    if (strlen(ibuf)) {
 			if (strcmp(ibuf, (char *)".") == 0) {
-			    srv_send((char *)"219 Accepted Unit record");
+			    srv_send(s, (char *)"219 Accepted Unit record");
 			    run_pause = FALSE;
 			    return 1;
 			}
@@ -2068,74 +2068,74 @@
 		}
 	    }
 	}
-	srv_send((char *)"440 No such unit");
+	srv_send(s, (char *)"440 No such unit");
 	run_pause = FALSE;
 	return 0;
     }
 
-    srv_send((char *)"504 Subcommand error");
+    srv_send(s, (char *)"504 Subcommand error");
     return 0;
 }
 
 
 
-void cmd_server(void)
+void cmd_server(int s)
 {
     char                buf[SS_BUFSIZE];
     int                 rlen;
 
-    rlen = srv_recv(buf);
+    rlen = srv_recv(s, buf);
     if (rlen != -1) {
 	if (strlen(buf)) {
 	    /*
 	     * Process commands from the client
 	     */
 	    if (strncmp(buf, "DEVICE", 6) == 0) {
-		if (cmd_device(buf))
+		if (cmd_device(s, buf))
 		    wrconfig();
 
 	    } else if (strncmp(buf, "GLOBAL", 6) == 0) {
-		if (cmd_global(buf))
+		if (cmd_global(s, buf))
 		    wrconfig();
 
 	    } else if (strncmp(buf, "HELP", 4) == 0) {
-		srv_send((char *)"100 Help text follows");
-		srv_send((char *)"Recognized commands:");
-		srv_send((char *)"");
+		srv_send(s, (char *)"100 Help text follows");
+		srv_send(s, (char *)"Recognized commands:");
+		srv_send(s, (char *)"");
 //                                12345678901234567890123456789012345678901234567890123456789012345678901234567890
-		srv_send((char *)"DEVICE <CMD> [parameters]     Device commands");
-		srv_send((char *)"DEVICE HELP                   Device help screen");
-		srv_send((char *)"GLOBAL <CMD> [parameters]     Global commands");
-		srv_send((char *)"GLOBAL HELP                   Global help screen");
-		srv_send((char *)"LIST <CMD> [parameters]       List commands");
-		srv_send((char *)"LIST HELP                     List help screen");
-		srv_send((char *)"PING                          Check if server is alive");
+		srv_send(s, (char *)"DEVICE <CMD> [parameters]     Device commands");
+		srv_send(s, (char *)"DEVICE HELP                   Device help screen");
+		srv_send(s, (char *)"GLOBAL <CMD> [parameters]     Global commands");
+		srv_send(s, (char *)"GLOBAL HELP                   Global help screen");
+		srv_send(s, (char *)"LIST <CMD> [parameters]       List commands");
+		srv_send(s, (char *)"LIST HELP                     List help screen");
+		srv_send(s, (char *)"PING                          Check if server is alive");
 #ifdef USE_SIMULATOR
-		srv_send((char *)"SIMULATOR <CMD> [parameters]  Simulator commands");
-		srv_send((char *)"SIMULATOR HELP                Simulator help screen");
+		srv_send(s, (char *)"SIMULATOR <CMD> [parameters]  Simulator commands");
+		srv_send(s, (char *)"SIMULATOR HELP                Simulator help screen");
 #endif
-		srv_send((char *)"UNIT <CMD> [parameters]       Unit commands");
-		srv_send((char *)"UNIT HELP                     Unit help screen");
-		srv_send((char *)".");
+		srv_send(s, (char *)"UNIT <CMD> [parameters]       Unit commands");
+		srv_send(s, (char *)"UNIT HELP                     Unit help screen");
+		srv_send(s, (char *)".");
 
 	    } else if (strncmp(buf, "LIST", 4) == 0) {
-		cmd_list(buf);
+		cmd_list(s, buf);
 
 	    } else if (strncmp(buf, "PING", 4) == 0) {
-		srv_send((char *)"101 PONG");
+		srv_send(s, (char *)"101 PONG");
 
 #ifdef USE_SIMULATOR
 	    } else if (strncmp(buf, "SIMULATOR", 9) == 0) {
-		if (cmd_simulator(buf))
+		if (cmd_simulator(s, buf))
 		    wrconfig();
 
 #endif
 	    } else if (strncmp(buf, "UNIT", 4) == 0) {
-		if (cmd_unit(buf))
+		if (cmd_unit(s, buf))
 		    wrconfig();
 
 	    } else {
-		srv_send((char *)"500 Unknown command");
+		srv_send(s, (char *)"500 Unknown command");
 	    }
 	}
     }
@@ -2144,17 +2144,31 @@
 }
 
 
+static void cleanup_handler(void *arg)
+{
+    syslog(LOG_NOTICE, "Thread my_server_loop stopped (cleanup_handler)");
+    close(ls);
+    my_server_state = 0;
+}
+
 
 void *my_server_loop(void *threadid)
 {
     socklen_t   addrlen;
-    int         optval = 1;
+    int         s, optval = 1;
 
     my_server_state = 1;
     syslog(LOG_NOTICE, "Thread my_server_loop started");
     if (debug)
 	fprintf(stdout, "Thread my_server_loop started\n");
 
+    /*
+     * Prepare thread to stop in blocking accept() call.
+     */
+    pthread_cleanup_push(cleanup_handler, NULL);
+    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+
     memset((char *)&myaddr_in, 0, sizeof(struct sockaddr_in));
     memset((char *)&peeraddr_in, 0, sizeof(struct sockaddr_in));
     myaddr_in.sin_family = AF_INET;
@@ -2176,12 +2190,12 @@
 	return 0;
     }
 
-    if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
-	syslog(LOG_NOTICE, "Can't setsockopt SO_REUSEADDR socket: %s", strerror(errno));
-	close(ls);
-	my_server_state = 0;
-	return 0;
-    }
+//    if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
+//	syslog(LOG_NOTICE, "Can't setsockopt SO_REUSEADDR socket: %s", strerror(errno));
+//	close(ls);
+//	my_server_state = 0;
+//	return 0;
+//    }
 
     if (bind(ls, (struct sockaddr *)&myaddr_in, sizeof(struct sockaddr_in)) == -1) {
 	syslog(LOG_NOTICE, "Can't bind to listen socket: %s", strerror(errno));
@@ -2199,7 +2213,6 @@
 
     syslog(LOG_NOTICE, "listen socket created %d", ls);
 
-
     /*
      * Loop forever until the external shutdown variable is set.
      */
@@ -2213,25 +2226,26 @@
 	 * descriptor, s, for that connection.
 	 */
 	s = accept(ls, (struct sockaddr *)&peeraddr_in, &addrlen);
+	syslog(LOG_NOTICE, "my_server_loop accept socket %d", s);
 	if (s == -1) {
 	    syslog(LOG_NOTICE, "my_server_loop accept failed %s", strerror(errno));
-	    if (debug)
-		fprintf(stdout, "my_server_loop accept failed %s\n", strerror(errno));
-	    my_server_state = 0;
-	    return 0;
+	    break;
 	}
-
-	cmd_server();
+	if (my_server_shutdown)
+	    break;
 
-	if (my_shutdown) {
-	    syslog(LOG_NOTICE, "Thread my_server_loop stopped");
-	    if (debug)
-		fprintf(stdout, "Thread my_server_loop stopped\n");
-	    my_server_state = 0;
-	    return 0;
-	}
+	cmd_server(s);
+
+	if (my_server_shutdown)
+	    break;
 	mDelay(100);
     }
+
+    close(ls);
+    pthread_cleanup_pop(my_server_state);
+    syslog(LOG_NOTICE, "Thread my_server_loop stopped");
+    my_server_state = 0;
+    return 0;
 }
 
 
--- a/thermferm/simulator.c	Wed Apr 03 19:33:38 2024 +0200
+++ b/thermferm/simulator.c	Fri Apr 05 16:19:39 2024 +0200
@@ -28,9 +28,9 @@
 
 #ifdef USE_SIMULATOR
 
-extern int		my_shutdown;
 extern sys_config	Config;
 
+int			my_simulator_shutdown = 0;
 int			SIMcooling = 0;
 int			SIMheating = 0;
 int			SIMfan = 0;
@@ -56,11 +56,11 @@
     }
 
     for (;;) {
-	if (my_shutdown)
+	if (my_simulator_shutdown)
 	    break;
 
 	for (simulator = Config.simulators; simulator; simulator = simulator->next) {
-	    if (my_shutdown)
+	    if (my_simulator_shutdown)
 	    	break;
 
 	    now = time(NULL);
--- a/thermferm/thermferm.c	Wed Apr 03 19:33:38 2024 +0200
+++ b/thermferm/thermferm.c	Fri Apr 05 16:19:39 2024 +0200
@@ -49,15 +49,29 @@
 extern int		lcdHandle;
 extern int		slcdHandle;
 extern int		my_devices_state;
+extern int		my_devices_shutdown;
 extern int		my_panel_state;
+extern int		my_panel_shutdown;
 extern int		my_server_state;
+extern int		my_server_shutdown;
 extern int		my_simulator_state;
+#ifdef USE_SIMULATOR
+extern int		my_simulator_shutdown;
+#endif
 extern int		my_one_wire_state;
+extern int		my_one_wire_shutdown;
 int			setupmenu = MENU_NONE;
 units_list		*current_unit = NULL;		/* In panel editor this points to the current unit. */
 float			temp_temp = 20.0;
 
-pthread_t		threads[5];
+pthread_t		my_one_wire_thread;
+pthread_t		my_devices_thread;
+pthread_t		my_panel_thread;
+pthread_t		my_server_thread;
+#ifdef USE_SIMULATOR
+pthread_t		my_simulator_thread;
+#endif
+
 pthread_mutex_t		mutexes[5];
 
 extern const char       UNITMODE[5][8];
@@ -1040,13 +1054,13 @@
     /*
      * First scan the one-wire bus
      */
-    rc = pthread_create(&threads[t], NULL, my_one_wire_loop, (void *)t );
+    rc = pthread_create(&my_one_wire_thread, NULL, my_one_wire_loop, (void *)t );
     if (rc) {
 	fprintf(stderr, "my_one_wire_loop thread didn't start rc=%d\n", rc);
 	syslog(LOG_NOTICE, "my_one_wire_loop thread didn't start rc=%d", rc);
     } else {
 	t++;
-	mDelay(250);	/* Wait a while to detect the devices */
+	mDelay(2500);	/* Wait a while to detect the devices */
     }
 
     if ((rc = devices_detect())) {
@@ -1054,7 +1068,7 @@
 	wrconfig();
     }
 
-    rc = pthread_create(&threads[t], NULL, my_devices_loop, (void *)t );
+    rc = pthread_create(&my_devices_thread, NULL, my_devices_loop, (void *)t );
     if (rc) {
 	fprintf(stderr, "my_devices_loop thread didn't start rc=%d\n", rc);
 	syslog(LOG_NOTICE, "my_devices_loop thread didn't start rc=%d", rc);
@@ -1062,7 +1076,7 @@
 	t++;
     }
 
-    rc = pthread_create(&threads[t], NULL, my_server_loop, (void *)t );
+    rc = pthread_create(&my_server_thread, NULL, my_server_loop, (void *)t );
     if (rc) {
 	fprintf(stderr, "my_server_loop thread didn't start rc=%d\n", rc);
 	syslog(LOG_NOTICE, "my_server_loop thread didn't start rc=%d", rc);
@@ -1070,7 +1084,7 @@
 	t++;
     }
 
-    rc = pthread_create(&threads[t], NULL, my_panel_loop, (void *)t );
+    rc = pthread_create(&my_panel_thread, NULL, my_panel_loop, (void *)t );
     if (rc) {
 	fprintf(stderr, "my_panel_loop thread didn't start rc=%d\n", rc);
 	syslog(LOG_NOTICE, "my_panel_loop thread didn't start rc=%d", rc);
@@ -1079,7 +1093,7 @@
     }
 
 #ifdef USE_SIMULATOR
-    rc = pthread_create(&threads[t], NULL, my_simulator_loop, (void *)t );
+    rc = pthread_create(&my_simulator_thread, NULL, my_simulator_loop, (void *)t );
     if (rc) {
 	fprintf(stderr, "my_simulator_loop thread didn't start rc=%d\n", rc);
 	syslog(LOG_NOTICE, "my_simulator_loop thread didn't start rc=%d", rc);
@@ -1925,13 +1939,38 @@
 	}
 	syslog(LOG_NOTICE, "Unit `%s' stopped in mode %s", unit->alias, UNITMODE[unit->mode]);
     }
-    syslog(LOG_NOTICE, "Out of loop");
+    syslog(LOG_NOTICE, "Out of loop, stopping threads..");
+
+    /*
+     * Stop threads
+     */
+#ifdef USE_SIMULATOR
+    my_simulator_shutdown = 1;
+    while (my_simulator_state) { mDelay(50); };
+#endif
+    my_panel_shutdown = 1;
+    while (my_panel_state) { mDelay(50); };
 
     /*
-     * Note that we don't care if the command server is stopped, this one
-     * does almost certain keep running but that doesn't harm.
+     * Cancel command and shutdown via variable, one of them
+     * will stop this thread. Includes a failsafe.
      */
-    while ((my_devices_state + my_panel_state + my_simulator_state + my_one_wire_state) > 0) { sleep(1); };
+    my_server_shutdown = 1;
+    rc = pthread_cancel(my_server_thread);
+    rc = 0;
+    while (my_server_state) {
+	mDelay(50);
+	if (rc++ > 20) {
+	    syslog(LOG_NOTICE, "Cannot terminate my_server_loop()");
+	    break;
+	}
+    }
+
+    my_devices_shutdown = 1;
+    while (my_devices_state) { mDelay(50); };
+    my_one_wire_shutdown = 1;
+    while (my_one_wire_state) { mDelay(50); };
+
     mqtt_disconnect();
 
     stopLCD();
--- a/thermferm/thermferm.h	Wed Apr 03 19:33:38 2024 +0200
+++ b/thermferm/thermferm.h	Fri Apr 05 16:19:39 2024 +0200
@@ -313,7 +313,8 @@
     char			*address;	///< Device address
     char			family[3];	///< Device family
     int				present;	///< Present on bus
-    int				subdevices;	///< Number of subdevices
+    int				value;		///< Last value
+//    int				subdevices;	///< Number of subdevices
     time_t			timestamp;	///< Last seen
 } w1_list;
 

mercurial