Better detection of the DHT11 sensors. Read DHT11 with errors detection and reapeated tries.

Sun, 24 Mar 2024 17:12:23 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Sun, 24 Mar 2024 17:12:23 +0100
changeset 648
62c5ed1b9cfd
parent 647
fcd85176ea2e
child 649
64cfc01ec024

Better detection of the DHT11 sensors. Read DHT11 with errors detection and reapeated tries.

thermferm/devices.c file | annotate | diff | comparison | revisions
thermferm/devices.h file | annotate | diff | comparison | revisions
thermferm/thermferm.c file | annotate | diff | comparison | revisions
--- a/thermferm/devices.c	Sat Mar 23 20:28:17 2024 +0100
+++ b/thermferm/devices.c	Sun Mar 24 17:12:23 2024 +0100
@@ -43,19 +43,13 @@
 #endif
 
 
-#define MAXTIMINGS 100
-
 /*
  * Since kernel version 4 there is a module, and a dtoverlay so that the
  * temperature and humidity can simply read from the /sys filesystem.
- * But this isn't as reliable as this userspace function, so we leave
- * that here.
  */
-
 int             dht11_temperature = -1;
 int             dht11_humidity = -1;
-int             dht11_valid = FALSE;
-int		dht11_present = FALSE;
+int		dht11_state = DEVPRESENT_UNDEF;
 time_t		dht11_last = (time_t)0;
 
 
@@ -63,67 +57,90 @@
 /*
  * DHT11 sensor read.
  */
-void dht11Read(void)
+void dht11Read(char *address)
 {
-    int         	tries, temp, hum;
+    int         	tries = 5, temp, hum;
     int			fd, rc, err;
-    char		buffer[25];
-
-    dht11_valid = FALSE;
-    dht11_present = FALSE;
-    dht11_temperature = -1;
-    dht11_humidity = -1;
+    char		buffer[25], *dhtpath = NULL;
 
-    /*
-     * Read DHT11 name. This only means the kernel module is loaded,
-     * it doesn't show if the chip is really present.
-     */
-    fd = open("/sys/bus/iio/devices/iio:device0/name", O_RDONLY);
-    if (fd == -1) {
-	syslog(LOG_NOTICE, "no DHT11 device");
-	return;
-    }
-
-    memset(&buffer, 0, 25);
-    read(fd, buffer, 25);
-    close(fd);
-    buffer[strlen(buffer) - 1] = '\0';
-    syslog(LOG_NOTICE, "dht11 name %s", buffer);
-
-    tries = 5;
     while (tries) {
 
-	fd = open("/sys/bus/iio/devices/iio:device0/in_temp_input", O_RDONLY);
+	dht11_temperature = -1;
+	dht11_humidity = -1;
+	dht11_state = DEVPRESENT_UNDEF;
+	dhtpath = xstrcpy((char *)"/sys/bus/iio/devices/");
+	dhtpath = xstrcat(dhtpath, address);
+	dhtpath = xstrcat(dhtpath, (char *)"/in_temp_input");
+
+	fd = open(dhtpath, O_RDONLY);
+	if (fd < 0) {
+	    /*
+	     * The sensor is gone.
+	     */
+	    free(dhtpath);
+	    dht11_state = DEVPRESENT_NO;
+	    break;
+	}
 	rc = read(fd, buffer, 25);
 	if (rc == -1) {
 	    err = errno;
+	    if (err == 110) {
+		dht11_state = DEVPRESENT_NO;	/* Device is gone */
+		break;
+	    } else {
+		dht11_state = DEVPRESENT_ERROR;
+	    }
 	    syslog(LOG_NOTICE, "DHT11 read temperature: %d %s", err, strerror(err));
 	    dht11_temperature = -1;
 	} else {
 	    sscanf(buffer, "%d", &temp);
 	    syslog(LOG_NOTICE, "read temp rc=%d %f", rc, temp / 1000.0);
 	    dht11_temperature = temp;
+	    dht11_state = DEVPRESENT_YES;
 	}
 	close(fd);
+	free(dhtpath);
+	dhtpath = NULL;
 
-	fd = open("/sys/bus/iio/devices/iio:device0/in_humidityrelative_input", O_RDONLY);
-	rc = read(fd, buffer, 25);
-	if (rc == -1) {
-	    err = errno;
-	    syslog(LOG_NOTICE, "DHT11 read temperature: %d %s", err, strerror(err));
-	    dht11_humidity = -1;
-	} else {
-	    sscanf(buffer, "%d", &hum);
-	    syslog(LOG_NOTICE, "read hum  rc=%d %f", rc, hum / 1000.0);
-	    dht11_humidity = hum;
+	/*
+	 * Only read humidity if state is DEVPRESENT_YES
+	 */
+	if (dht11_state == DEVPRESENT_YES) {
+	    dhtpath = xstrcpy((char *)"/sys/bus/iio/devices/");
+	    dhtpath = xstrcat(dhtpath, address);
+	    dhtpath = xstrcat(dhtpath, (char *)"/in_humidityrelative_input");
+
+	    fd = open(dhtpath, O_RDONLY);
+	    rc = read(fd, buffer, 25);
+	    if (rc == -1) {
+	    	err = errno;
+		if (err == 110) {
+		    dht11_state = DEVPRESENT_NO;
+		    break;
+		} else {
+		    dht11_state = DEVPRESENT_ERROR;
+		}
+	    	syslog(LOG_NOTICE, "DHT11 read temperature: %d %s", err, strerror(err));
+	    	dht11_humidity = -1;
+	    } else {
+	    	sscanf(buffer, "%d", &hum);
+	    	syslog(LOG_NOTICE, "read hum  rc=%d %f", rc, hum / 1000.0);
+	    	dht11_humidity = hum;
+		dht11_state = DEVPRESENT_YES;
+	    }
+	    close(fd);
+	    free(dhtpath);
+	    dhtpath = NULL;
 	}
-	close(fd);
 
-	tries = 0;
+	if (dht11_state == DEVPRESENT_YES) {
+	    break;
+	}
+	if (tries > 0)
+	    tries--;
     }
 
-    dht11_valid = TRUE;
-    syslog(LOG_NOTICE, "dht11 t:%d h:%d tries:%d", dht11_temperature, dht11_humidity, 6-tries);
+    syslog(LOG_NOTICE, "dht11 t:%d h:%d tries:%d state:%d", dht11_temperature, dht11_humidity, 6-tries, dht11_state);
 }
 
 
@@ -384,7 +401,6 @@
 {
     struct dirent	*de;
     DIR			*fd;
-    int			fi;
     devices_list	*device, *ndev;
     int			found, subdevices, ival, i, rc = 0;
     char		buf[40];
@@ -411,15 +427,13 @@
 		    strncpy(buf, de->d_name, 2);
 		    buf[2] = '\0';
 		    sscanf(buf, "%02x", &ival);
-		    syslog(LOG_NOTICE, "Scan 1-wire %02x %d", ival, ival);
 		    subdevices = 0;
+
 		    /*
 		     * ival is zero when a ghost sensor is detected.
 		     */
 		    if (ival > 0)
 		    	subdevices = 1;
-		    if (strcmp(buf, (char *)"29") == 0)
-			subdevices = 8;
 		    if (strcmp(buf, (char *)"3a") == 0)
 			subdevices = 2;
 		    for (i = 0; i < subdevices; i++) {
@@ -435,13 +449,13 @@
 			    ndev->description = xstrcpy((char *)"DS18S20 Digital thermometer");
 			} else if (strcmp(buf, (char *)"22") == 0) {
 			    ndev->direction = DEVDIR_IN_ANALOG;
-			    ndev->description = xstrcpy((char *)"DS1820 Digital thermometer");
+			    ndev->description = xstrcpy((char *)"DS1822 Digital thermometer");
 			} else if (strcmp(buf, (char *)"28") == 0) {
 			    ndev->direction = DEVDIR_IN_ANALOG;
 			    ndev->description = xstrcpy((char *)"DS18B20 Digital thermometer");
 			} else if (strcmp(buf, (char *)"3a") == 0) {
+			    ndev->direction = DEVDIR_IN_BIN;
 			    ndev->description = xstrcpy((char *)"DS2413 Dual channel addressable switch");
-			    ndev->direction = DEVDIR_IN_BIN;
 			} else if (strcmp(buf, (char *)"3b") == 0) {
 			    ndev->direction = DEVDIR_IN_ANALOG;
 			    ndev->description = xstrcpy((char *)"DS1825 Digital thermometer");
@@ -462,6 +476,8 @@
 			ndev->comment = xstrcpy((char *)"Auto detected device");
 			ndev->timestamp = time(NULL);
 
+			syslog(LOG_NOTICE, "New W1 device %s, subdevice %d, %s", ndev->address, ndev->subdevice, ndev->description);
+
 			if (Config.devices == NULL) {
 			    Config.devices = ndev;
 			} else {
@@ -481,19 +497,28 @@
     }
 
     /*
-     * DHT11 as kernel module.
+     * DHT11 as kernel module. The number after the @ is the hexadecimal
+     * number of the BCM gpio pin. Since we use pin 22 at connector pin 15
+     * the number is 16.
      */
-    if ((fi = open((char *)"/sys/bus/iio/devices/iio:device0/name", O_RDONLY))) {
-	char buffer[25];
+    char *dhtaddr = NULL;
+    if ((fd = opendir((char *)"/sys/devices/platform/dht11@16"))) {
+	while ((de = readdir(fd))) {
+	    if (de->d_name[0] != '.') {
+		if (strncmp(de->d_name, (char *)"iio", 3) == 0) {
+		    dhtaddr = xstrcpy(de->d_name);
+		}
+	    }
+	}
+	closedir(fd);
+    }
+    syslog(LOG_NOTICE, "%s", dhtaddr);
 
-	memset(&buffer, 0, 25);
-	read(fi, buffer, 25);
-	close(fi);
-	buffer[strlen(buffer) - 1] = '\0';
+    if (dhtaddr) {
 
 	found = FALSE;
 	for (device = Config.devices; device; device = device->next) {
-	    if (strcmp(device->address, buffer) == 0) {
+	    if (strcmp(device->address, dhtaddr) == 0) {
 		found = TRUE;
 		break;
 	    }
@@ -514,12 +539,14 @@
 		    ndev->description = xstrcpy((char *)"DHT11 humidity sensor");
 		ndev->value = ndev->offset = ndev->inuse = 0;
 	        ndev->present = DEVPRESENT_YES;
-		ndev->address = xstrcpy(buffer);
+		ndev->address = xstrcpy(dhtaddr);
 		ndev->subdevice = i;
 		ndev->gpiopin = -1;
 		ndev->comment = xstrcpy((char *)"Auto detected device");
 		ndev->timestamp = time(NULL);
 
+		syslog(LOG_NOTICE, "New DHT11 device %s, subdevice %d, %s", ndev->address, ndev->subdevice, ndev->description);
+
 		if (Config.devices == NULL) {
 		    Config.devices = ndev;
 		} else {
@@ -608,6 +635,8 @@
 	    	}
 	    	pin++;
 
+		syslog(LOG_NOTICE, "New GPIO device %s, subdevice %d, %s", ndev->address, ndev->subdevice, ndev->description);
+
 	    	if (Config.devices == NULL) {
 		    Config.devices = ndev;
 	    	} else {
@@ -689,6 +718,8 @@
 			break;
 	}
 
+	syslog(LOG_NOTICE, "New Simulator device %s, subdevice %d, %s", ndev->address, ndev->subdevice, ndev->description);
+
 	if (Config.devices == NULL) {
 	    Config.devices = ndev;
 	} else {
@@ -896,32 +927,28 @@
 
 		case DEVTYPE_DHT:
 			/*
-			 * Make sure we don't read the sensor within 2 seconds.
+			 * Don't read these to often, 2 seconds minimum delay.
 			 * But we use 30 seconds interval.
 			 */
 			now = time(NULL);
 			if ((int)(now - dht11_last) > 30) {
 			    if (device->subdevice == 0) {
 				/* Read once during subdevice 0 */
-			    	dht11Read();
+			    	dht11Read(device->address);
 				pthread_mutex_lock(&mutexes[LOCK_DEVICES]);
-			    	if (dht11_valid) {
+				device->present = dht11_state;
+			    	if (dht11_state == DEVPRESENT_YES) {
 				    device->value = dht11_temperature;
 				    device->timestamp = time(NULL);
-				    device->present = DEVPRESENT_YES;
-			    	} else {
-				    device->present = DEVPRESENT_ERROR;
 			    	}
 				pthread_mutex_unlock(&mutexes[LOCK_DEVICES]);
 			    } else if (device->subdevice == 1) {
 				/* Data already present */
 				pthread_mutex_lock(&mutexes[LOCK_DEVICES]);
-			    	if (dht11_valid) {
+				device->present = dht11_state;
+			    	if (dht11_state == DEVPRESENT_YES) {
 				    device->value = dht11_humidity;
 				    device->timestamp = time(NULL);
-				    device->present = DEVPRESENT_YES;
-			    	} else {
-				    device->present = DEVPRESENT_ERROR;
 			    	}
 				pthread_mutex_unlock(&mutexes[LOCK_DEVICES]);
 				dht11_last = now;	/* Okay for a new reading. */
--- a/thermferm/devices.h	Sat Mar 23 20:28:17 2024 +0100
+++ b/thermferm/devices.h	Sun Mar 24 17:12:23 2024 +0100
@@ -6,10 +6,6 @@
 int device_in(char *, int *);
 int devices_detect(void);
 
-#ifdef HAVE_WIRINGPI_H
-PI_THREAD (my_devices_loop);
-#else
 void *my_devices_loop(void *);
-#endif
 
 #endif
--- a/thermferm/thermferm.c	Sat Mar 23 20:28:17 2024 +0100
+++ b/thermferm/thermferm.c	Sun Mar 24 17:12:23 2024 +0100
@@ -1911,7 +1911,7 @@
      * Note that we don't care if the command server is stopped, this one
      * does almost certain keep running but tat doesn't harm.
      */
-    while ((my_devices_state + my_panel_state + my_simulator_state) > 0) {};
+    while ((my_devices_state + my_panel_state + my_simulator_state) > 0) { sleep(1); };
     mqtt_disconnect();
 
     stopLCD();

mercurial