[SOLVED] Piettetech DHT library not working with DHT11

I have a DHT11 sensor hooked to pin D0 of a Photon (with a 5.6K pullup resistor). I first tested the device with the Adafruit DHT library and it runs fine. Next I tested with the Piettetech library and the code seems to lock up and never return from DHT.acquiteAndWait(). In fact, it causes the Photon to go into breathing green mode and I have to fiddle with the buttons to get the Photon back to where I can flash code.

Here is a dump of what is printed from the serial port:

Press any key to start.
DHT Simple program using DHT.acquireAndWait
LIB version: 0.4

0: Retrieving information from sensor: Read sensor:

At this point, the Photon just hangs. Any ideas on what might be wrong? The sensor I am using came from China and the little PC board is not identical to the Adafruit version, but the sensor itself seems to be the same and it works fine with Adafruit.

I really need the Piettetech library because my application requires non-blocking code.

PLEASE DISREGARD MY PREVIOUS POSTING. I changed the data pin to D2 and it works OK. D0 does not work with this library.

Glad to hear it! Marking the thread as resolved.

The problem in its most simple form is solved.

I took a quick look at my own issues with a DHT22 sensor, and discovered that this library will crash the Photon if there are any hardware issues and the Photon is not talking to the sensor. Things like the wrong pin assignment or connecting it up incorrectly will guarantee a crash.

I hope to come back to this and do a PR on this library.
My thought is to add a number of re-tries in reading the sensor and to then send a message to Serial for a suspected Hardware issue.
At the moment, I am working on another library … ParticleSoftKLine (ISO 9141, KWP2000 and LIN bus)…

@cyclin_al: Thank you for doing all of this. I would like to suggest that, on your next pass through the library, you update the comments to delete D0 as an acceptable sensor data pin. I am sure that this is a Particle issue and not a library issue, but it would help others avoid this same problem.

You are correct about the crash issue, but rather than retry, would it be possible to return from acquire() with an error code? Retries won’t likely resolve a hardware issue. Getting stuck at interrupt level is a big problem because it locks up the Photon from even being able to be flashed again (yes, this is recoverable, but novice Photon users might get really stuck!). So, even just timing out the DHT communication with a long (non-blocking) timeout - e.g. 500 ms - would help, as this would let the user recover to investigate the hardware problem further.

There is a easy a acquireAndWait() function that should be used, but that's not working as is.
But with this fix it works as expected

int PietteTech_DHT::acquireAndWait(uint32_t timeout) {
    acquire();
    uint32_t start = millis();
    while(acquiring() && (timeout == 0 || ((millis()-start) < timeout))) Particle.process();
    if (acquiring())
    {
        _status = DHTLIB_ERROR_RESPONSE_TIMEOUT;
    }
    return getStatus();
}

I have opened an issue about that a while back
Problem with acquireAndWait(timeout) ¡ Issue #11 ¡ piettetech/PietteTech_DHT ¡ GitHub

But what exactly do you mean with "crash the Photon"?

But the reason why D0 didn't work is that you can't use D0 as interrupt source on the Photon (A5 neither).
That's also stated wrong in the library, since the comments there only refer to the Spark Core and won't fit the Photon/P0/P1/Electron devices.

Another issue with that lib will arise when building for 0.6.1-rc.2 (and later), due to a missing compiler condition

#if !defined(word) // 0.6.1-rc.2 and later will have their own keyword `word` 
uint16_t word(uint8_t high, uint8_t low) {
    uint16_t ret_val = low;
    ret_val += (high << 8);
    return ret_val;
}
#endif

@BobG: Just a clarification, this is not my library, but I was planning on submitting a PR (pull request) so the owner could have the chance to incorporate my changes back into the library. It seems there are a number of changes recommended; is there a mechanism to contact the owner and transfer library maintenance to someone else?

I find I always have to clarify, I suppose I have to work on my communications. A number of re-tries was meant to indicate a limited number. A number of re-tries might be useful when there is a long cable length or similar case with intermittent failures to communicate with the sensor. Good suggestion to include an error code along with sending a message to serial.

@ScruffR, My memory says that “crash” should be a SOS code; I used vague wording since I did not have a Photon handy at the time. I went and actually verified using the DHT-SIMPLE.INO example and it cycles between breathing cyan and breathing green. The Serial monitor stops outputting, which I think means the library is caught in an endless loop trying to read the sensor and is blocking. Im my thinking, I considered the application crashed.

Yup, if @mtnscott isn't maintaining the lib anymore, I could apply for transfer to me.

In my testing, the Photon went from breathing cyan to breathing green and never cycled back to anything else. At this point, code could not be flashed to the Photon, so I would call this condition “crashed” as well. As I previously stated, the condition is recoverable by pressing the reset and mode buttons and holding the mode button until it flashes purple, at which point it is again possible to flash code to the Photon.

That is not what we call crashed. This would be called blocked as in blocking code causes the cloud to get disconnected (brathing green).
https://docs.particle.io/guide/getting-started/modes/photon/ (CLOUD NOT CONNECTED)

@ScruffR: re. your fix for acquireAndWait(): thank you for this fix. I am not sure, however, about the hangup being in acquireAndWait(). I believe that when there is a hardware issue (such as using D0 for interrupts) acquireAndWait() hangs up inside of the method acquire() that it calls. Therefore, the timeout that you added needs to be inside of acquire() itself.

I originally tried the non-blocking acquire() (the actual functionality that I need) and that is where I first experienced the hangup. I did not call acquireAndWait(); I called acquire() directly and found out that the code never returned. acquire(), or at least parts of it, run at interrupt level and I believe that if the code hangs up there (due to a hardware issue), that this is where the Internet communication gets blocked.

Hmm, I'm not sure which part in acquire() would be blocking execution.
Can you point me to that place?

It's not that attachInterrupt(D0, ...) would block your code, it's just that the interrupt would never fire.
So I really can't see any way acquire() could be blocking.

@ScruffR: I did not go into the library itself to debug. What I can confirm is that DHT.acquire() never returns if the DHT11 data is on pin D0. You can try this with a Photon and the PietteTech non-blocking example code. Don’t connect any sensor at all and you will see that the serial data shows that it hangs (never returns) after the first DHT.acquire(). This is also the case if you put a powered DHT11 on D0 (with appropriate pullup) but it works if you use D2 instead (and probably any other valid interrupt pin, albeit I have tested only D0 and D2).

If you are refering to this code, then there is another explanation than blocking inside acquire()

void loop()
{
  // Check if we need to start the next sample
  if (millis() > DHTnextSampleTime) {
	if (!bDHTstarted) {		// start the sample
	    Serial.print("\n");
	    Serial.print(n);
	    Serial.print(": Retrieving information from sensor: ");
	    DHT.acquire();
	    bDHTstarted = true;
	}

	if (!DHT.acquiring()) {		// has sample completed?

	    // get DHT status
	    int result = DHT.getStatus();

	    Serial.print("Read sensor: ");
	    switch (result) {
		case DHTLIB_OK:
		    Serial.println("OK");
		    break;
		case DHTLIB_ERROR_CHECKSUM:
		    Serial.println("Error\n\r\tChecksum error");
		    break;
		case DHTLIB_ERROR_ISR_TIMEOUT:
		    Serial.println("Error\n\r\tISR time out error");
		    break;
		case DHTLIB_ERROR_RESPONSE_TIMEOUT:
		    Serial.println("Error\n\r\tResponse time out error");
		    break;
		case DHTLIB_ERROR_DATA_TIMEOUT:
		    Serial.println("Error\n\r\tData time out error");
		    break;
		case DHTLIB_ERROR_ACQUIRING:
		    Serial.println("Error\n\r\tAcquiring");
		    break;
		case DHTLIB_ERROR_DELTA:
		    Serial.println("Error\n\r\tDelta time to small");
		    break;
		case DHTLIB_ERROR_NOTSTARTED:
		    Serial.println("Error\n\r\tNot started");
		    break;
		default:
		    Serial.println("Unknown error");
		    break;
	    }

	    Serial.print("Humidity (%): ");
	    Serial.println(DHT.getHumidity(), 2);

	    Serial.print("Temperature (oC): ");
	    Serial.println(DHT.getCelsius(), 2);

	    Serial.print("Temperature (oF): ");
	    Serial.println(DHT.getFahrenheit(), 2);

	    Serial.print("Temperature (K): ");
	    Serial.println(DHT.getKelvin(), 2);

	    Serial.print("Dew Point (oC): ");
	    Serial.println(DHT.getDewPoint());

	    Serial.print("Dew Point Slow (oC): ");
	    Serial.println(DHT.getDewPointSlow());

	    n++;  // increment counter
	    bDHTstarted = false;  // reset the sample flag so we can take another
	    DHTnextSampleTime = millis() + DHT_SAMPLE_INTERVAL;  // set the time for next sample
	}
    }
}

Since without an interrupt triggering these two conditions will never be satisfied

	if (!bDHTstarted) {		// start the sample
          ...
	}

	if (!DHT.acquiring()) {		// has sample completed?
          ...
        }

and hence none of the Serial.print() statements will ever be executed anymore.

If you add an unconditional Serial.print() you may see it’s not actually blocking - I guess.

@ScruffR: You are probably correct about this. A timeout/recovery could perhaps be implemented outside of the library itself, if non-blocking methods are used. This still does not explain why this code will set the Photon into breathing green “blocked” mode. This, too, should be avoided in the timeout/recovery.

In any event, it is important that users understand that D0 interrupts do not (currently?) work on the Photon and therefore D0 is not an allowed option for wiring the DHT data signal to.

Thanks @BobG, we do have that documented here:

https://docs.particle.io/reference/firmware/photon/#attachinterrupt-

Photon: All pins with the exception of D0 and A5 (since at present Mode Button external interrupt(EXTI) line is shared with D0, A5). Also please note following are the pins for which EXTI lines are shared so only one can work at a time:
D1, A4
D2, A0, A3
D3, DAC
D4, A1

1 Like

@BDub: Thanks. My comment about the documentation was aimed at anyone who updates the PietteTech_DHT library to also change the comment that includes D0 as a possible DHT data pin.

1 Like

I think the above code doesn't end up breathing green, and my adapted code does fix that issue for acquireAndWait().