# HG changeset patch # User Michiel Broek # Date 1711296743 -3600 # Node ID 62c5ed1b9cfdac03e594fc9e37fb8f8ba62f1be0 # Parent fcd85176ea2e0367c37ad9e266326487350ce963 Better detection of the DHT11 sensors. Read DHT11 with errors detection and reapeated tries. diff -r fcd85176ea2e -r 62c5ed1b9cfd thermferm/devices.c --- 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. */ diff -r fcd85176ea2e -r 62c5ed1b9cfd thermferm/devices.h --- 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 diff -r fcd85176ea2e -r 62c5ed1b9cfd thermferm/thermferm.c --- 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();