AM2302 DHT sensor does not measure negative temp, reports as positive...

I have a temp/humid monitoring system built with an ESP8266 module (ESP-07) and 3 sensors AM2302 each connected to a separate I/O pin. The sensors are placed in 3 positions in my attic to check on temperature and humidity. I am using the DHT library to read the sensors.
The system has been on-line for almost 3 months now and the data have been as expected regarding the temperatures, where they track each other inside less than a degree C.
But now that winter is approaching and I am getting below freezing temperatures I have discovered a strange problem:
One of the sensors does not produce negative temperatures! Even though the temperature is well below zero this sensor reports positive temperatures of approximate the same magnitude as the negative of the other two sensors!
The sensors that are working OK are from an earlier batch and the problem sensor comes from a new set of 10 sensors I bought in beginning of 2018.
Is this a known issue with these sensors?

Here is the code the library uses to read temperature:

//boolean S == Scale.  True == Fahrenheit; False == Celcius
float DHT::readTemperature(bool S, bool force) {
  float f = NAN;

  if (read(force)) {
    switch (_type) {
    case DHT11:
      f = data[2];
      if(S) {
        f = convertCtoF(f);
      }
      break;
    case DHT22:
    case DHT21:
      f = data[2] & 0x7F;
      f *= 256;
      f += data[3];
      f *= 0.1;
      if (data[2] & 0x80) {
        f *= -1;
      }
      if(S) {
        f = convertCtoF(f);
      }
      break;
    }
  }
  return f;
}

I have replaced the sensor with a different one from the same batch thinking it was faulty, but the new sensors also registers the negative temperatures as the positive value (like sending the absolute value).
And this is only happening with one of the 3 sensors. Furthermore if I sign reverse the bad sensor's values they track very well with the good sensor values...

Well, you have replaced the hardware, so that is not the problem. That leaves just your software.

Paul

Yes I replaced the sensor hardware but using another device from the same batch of 10 I bought back in March.
The only difference I see between the sensors are actually the age of them and the GPIO pins they are hooked up to.

The 3 sensors are handled by the exact same software
This is the code from the ino file used by my sketch (apart from the DHT library of course).

#include "DHT.h"

// DHT sensor variables:
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
DHT dht1(14, DHTTYPE);  //Sensor 1 on GPIO14/pin5
DHT dht2(12, DHTTYPE);  //Sensor 2 on GPIO12/pin6
DHT dht3(13, DHTTYPE);  //Sensor 3 on GPIO13/pin7
DHT dht4(4,  DHTTYPE);  //Sensor 4 on GPIO4/pin13

void setup()
{
....
    //Start the DHT sensors:
    byte dhtcnt = ESPConf.numsensors; //bitmap of active sensors
    if (dhtcnt & 1) dht1.begin();
    if (dhtcnt & 2) dht2.begin();
    if (dhtcnt & 4) dht3.begin();
    if (dhtcnt & 8) dht4.begin();
....
}

void HandleDHTsensors(unsigned long tickcnt)
{
    float hum1=0, hum2=0, hum3=0, hum4=0;
    float temp1=0, temp2=0, temp3=0, temp4=0;
    byte dhtcnt;
    dhtcnt = ESPConf.numsensors;

    unsigned long t1 = millis();
    if ((dhtcnt & 1) > 0)
    {
        hum1 = dht1.readHumidity();
        temp1 = dht1.readTemperature(); //Uses cached result from humid read cycle
    }
    if ((dhtcnt & 2) > 0)
    {
        hum2 = dht2.readHumidity();
        temp2 = dht2.readTemperature();
    }
    if ((dhtcnt & 4) > 0)
    {
        hum3 = dht3.readHumidity();
        temp3 = dht3.readTemperature();
    }
    if ((dhtcnt & 8) > 0)
    {
        hum4 = dht4.readHumidity();
        temp4 = dht4.readTemperature();
    }
    unsigned long t2 = millis();

    // Check if any reads failed and exit early (to try again).
    if (!(isnan(hum1) || isnan(temp1) || isnan(hum2) || isnan(temp2) || isnan(hum3) || isnan(temp3) || isnan(hum4) || isnan(temp4))) //Process data if reading was OK
    {
        unsigned long t0 = t2-t1; //Calculate read time
        SerialDebug.print("Tmeas: ");
        SerialDebug.print(t0);
        SerialDebug.print(" ms\t");
        lasttickcount = tickcnt;    //Increment to next trigger time

        //Post data to website database
        if ((dhtcnt & 1) > 0) SendData(1, temp1, hum1);
        if ((dhtcnt & 2) > 0) SendData(2, temp2, hum2);
        if ((dhtcnt & 4) > 0) SendData(3, temp3, hum3);
        if ((dhtcnt & 8) > 0) SendData(4, temp4, hum4);
    }
}

void loop()
{
   ....
	//Check if a new DHT reading is requested:
	unsigned long tickcount = millis();
	if ((interval > 0) && ((unsigned long)(tickcount - lasttickcount) >= interval))
	{
		HandleDHTsensors(tickcount);
	}
   ...
}

I attach the temperature plot made where I saw the sign reversal of sensor Temp3.
Check the two circled areas where the green trace is mirrored on the X axis...

Today I have moved sensors around and it seems like there is some kind of problem with the wiring towards the sensor location #3. When I move the sensor from position 3 and connect it directly to the central unit it behaves sensibly and another sensor moved to location #3 shows strange values, for example positive even though the temp is negative.
Or humidity at 99.9% or so....
Right now sensor #3 reports +4.4C and 82.4% even though the sensors #1 and #2 show temp -3.9 and -3.1C respectively.

I modified my sketch so that it will no longer require !nan as value for all used sensors in order to report to the database. Instead it will send the values for sensors with a good reading even though another sensor failed.
Now I see in the report that randomly there is no value from #3 indicating that for this cycle it has reported nan (because it could not read) and at other times it reports a value but then the temp is positive when in fact it is very cold at -5 C or so.

My house is 20 m long and sensors are placed in each end and in the middle. The electronics box is placed in the middle too. So the wires from sensors 1 and 3 are about 10m long. But sensor #1 has never failed once and it uses the same length wiring, might even be a meter or so longer.

I have read that the DHT sensors behave better when running on 5V, though I am currently using 3.3V on the sensor because the ESP8266 is a 3.3V device and cannot handle higher input voltages...
So how could I solve this (if it is a voltage level problem)?

Maybe:
If I connect a 1.5V battery between incoming +3.3V and the DHT sensor Vcc pin (1) and connect the pull-up resistor between DHT pin 2 (communication) and incoming 3.3V?
Then the DHT will see 4.8V supply whereas the signal level will be 3.3V max (pull-up to 3.3V).
This of course needs sensor battery replacements now and then, I don’t know how often though…

So how could I solve this (if it is a voltage level problem)?

Use a level shifter.

Have you cleanly soldered all your connections to the boards?

A simple level shifter does not work on a bidirectional bus like the AM2302 uses. The ESP must both be able to send and receive data on this bus.
But adding 1.5V to the supply of the DHT (through a battery) might work while at the same time keeping the pull-up connected to the 3.3V supply and the bus line.
I don't have a 5V supply in the electronic box, the input voltage is 12V and from this there is a brick type down converter making the 3.3V for the ESP and the DHT circuitry.
So I must use something else like a battery to increase the supply voltage for the sensors.
Mind you, this is just a shot in the dark just now.
Right now I am getting good readings from 3 sensors, after I added sensor #4 to the proximity of the electronics box, but randomly getting NAN or positive temperature from sensor #3. This sits at the same distance as #1 but the other way from the ESP-07 box.

Concerning soldering:
Yes everything is soldered properly except for the actual connections to the sensor cables where I use terminal strips with screws. Otherwise I cannot exchange sensors up in the attic (it is not really a proper attic, it is only 55 cm high so access is by way of small hatches in the walls...).

    if (dhtcnt & 1) dht1.begin();
    if (dhtcnt & 2) dht2.begin();
    if (dhtcnt & 4) dht3.begin();
    if (dhtcnt & 8) dht4.begin();

This doesn't look right. If there are four sensors then, presumably dhtcnt is 4. In that case this code will only initialize dht3. If there are 3 sensors it will only initialize dht1 an dht2.
Or, do you have one bit per sensor so that four sensors would require dhtcnt to be set to 15 (= 0b1111)?

Pete

Ah, OK.
byte dhtcnt = ESPConf.numsensors; //bitmap of active sensors

Pete

Originally I had a count so I could activate a number of sensors. But then I found that I needed to be able to switch each of the 4 sensors off/on individually.
So I changed the sketch such tha the dhtcnt variable now meant a bitmap with range 1..15 so I could set it to any combination. Not changing the variable name meant less code changes at the time (I started out with a conditional define to switch the firmware between the two meanings).
So this code is OK even though the variable name is a bit misleading.
I also now have this when sending data out:

    unsigned long t1 = millis();
    if ((dhtcnt & 1) > 0)
    {
        hum1 = dht1.readHumidity();
        temp1 = dht1.readTemperature();
        DebugMsg += "S1: T=" + String(temp1) + "C H=" + String(hum1) + "%\n";
    }
    if ((dhtcnt & 2) > 0)
    {
        hum2 = dht2.readHumidity();
        temp2 = dht2.readTemperature();
        DebugMsg += "S2: T=" + String(temp2) + "C H=" + String(hum2) + "%\n";
    }
    if ((dhtcnt & 4) > 0)
    {
        hum3 = dht3.readHumidity();
        temp3 = dht3.readTemperature();
        DebugMsg += "S3: T=" + String(temp3) + "C H=" + String(hum3) + "%\n";
    }
    if ((dhtcnt & 8) > 0)
    {
        hum4 = dht4.readHumidity();
        temp4 = dht4.readTemperature();
        DebugMsg += "S4: T=" + String(temp4) + "C H=" + String(hum4) + "%\n";
    }
    unsigned long t2 = millis();
    if (((dhtcnt & 1) > 0) && (!isnan(hum1)) && (!isnan(temp1))) SendData(1, temp1, hum1);
    if (((dhtcnt & 2) > 0) && (!isnan(hum2)) && (!isnan(temp2))) SendData(2, temp2, hum2);
    if (((dhtcnt & 4) > 0) && (!isnan(hum3)) && (!isnan(temp3))) SendData(3, temp3, hum3);
    if (((dhtcnt & 8) > 0) && (!isnan(hum4)) && (!isnan(temp4))) SendData(4, temp4, hum4);
    lasttickcount = tickcnt;	//Increment next trigger time

Before this change I had a requirement that all active sensors should have a non-NAN value for the data to be sent to the database. But due to the problems with sensor #3 many times tghere was no posted data because sensor 3 read bad while the other sensors worked fine. Now all good data will be recorded in the database.

Below is how the plot would have looked like if the sensor was not acting up.
I have run queries in the database to invert the sensor #3 temperatures between the times they should have been negative. Note the close correspondence between the sensor readings in teh attic!

A simple level shifter does not work on a bidirectional bus like the AM2302 uses.

The level shifter I linked works with a bidirectional bus, so it not whatever you imagine to be a "simple level shifter".

Good luck on your project!

The DHT22 represents the temperature in signed-magnitude format. For example,
0000 0000 0110 0101
represents 10.1C
but this
1000 0000 0110 0101
represents -10.1C
Therefore, if there's some way for your code (or wonky electronics) to mangle that one bit, it will change a negative temperature into a positive one.
Offhand, I can't think of a way that this can happen.

Pete

In my start post I included the read function from the DHT library.
Here you see clearly how the sign is used to modify the numeric value.
But this happens once the reading is complete including checking the parity byte, this is what makes me wonder how that piece of data could get through to the wrong answer. Surely the parity check should have caught a bit error (the sign bit)?

    case DHT22:
    case DHT21:
      f = data[2] & 0x7F; //Mask out the sign bit here
      f *= 256;
      f += data[3];
      f *= 0.1;
      if (data[2] & 0x80) { //Check the sign bit here
        f *= -1;
      }

Surely the parity check should have caught a bit error

It's actually only a checksum but it should have caught a single bit error.
Presumably, that code also decodes the negative temperatures from the other sensors and gets those right. But the problem is that it's not just an intermittent error. It always reports negative temperatures as positive which means that the sign bit in every reading is flipped.
Weird.

Pete

Weird is the word....
Right now I have recorded 8 hourly readings since I replaced the sensor #3
"Statistics":

  • missing
    +3.9
  • missing
    +6.0
  • missing
    -7.3
    -7.8
    -8.2
    So the last 3 readings are OK, 5 are either NAN or positive.
    Could it be that when noise hits the transmission there is a 40% chance of it getting passed as a positive value and 60% chance it gets trapped by the checksum? Or is there a higher chance of errors if the value to read is negative?

I have read about an alternate solution with a sensor BME280, which uses I2C and is more reliable.
Can such a sensor be used with the ESP8266 given that I only have 4 wires to each sensing point and a single ESP-07 WiFi device in the electronics box?
And that the cables are 10m in length...

I2C uses addressing so in principle it seems possible with 4 devices on one bus but then I see that the BME280 has only 2 possible addresses and that switching address means cutting board traces, ouch....

I have also read that using I2C means max 50 cm cable length is possible, is this really true? If so I have to ditch this sensor idea.

Maybe I should stay with the AM2302 after all...

Edit:
OOPS! I found this in the data sheet:

4.2 Power supply pins(VDD GND)
AM2302 supply voltage range 3.3V - 5.5V, recommended supply voltage is 5V.

7.1 Special instructions of the single-bus communication:
1.Typical application circuit recommended in the short cable length of 30 meters on the 5.1K
pull-up resistor pullup resistor according to the actual situation of lower than 30 m.
2.With 3.3V supply voltage, cable length shall not be greater than 100cm. Otherwise, the line
voltage drop will lead to the sensor power supply, resulting in measurement error.

So I have rebuilt the electronics today to feed 5V to the sensors while keeping 3.3V for the ESP-07.
Will show a simplified diagram tomorrow if it pans out OK (too dark to do anything today).

I have tested the new design indoors by connecting a sensor using a reel of the remaining 25 m of signal cable I have available. So this is more than twice the cable length I used in the attic and the sensor is one of the ones I tested yesterday and it failed. Now it does not fail anymore but produces good readings all the time.
So I made a quick drawing and scanned it to show here.
What I did was this:

  1. I connected a 5V linear regulator on the incoming 12V to get me the sensor supply.
  2. I connected 1K pull-up resistors from the 4 outputs used to read the sensors to the +5V line
    (1K because the zener would not go higher than about 2.7V with 10K)
  3. I also connected 3.3V zener diodes from the outputs to ground to limit signal swing to 3V
  4. I wired the +5V supply to the 4 sensor's connector power lines (was 3.3V earlier)
    On the sensor side I did not change anything, I kept the higher resistance pull-ups as they were

Here is the schematic of this:


I think this will have solved the problem, test tomorrow morning.

UPDATE:
With the change to using a 5V supply for the sensors (see schematic above) the readings are now all OK!
:slight_smile:

Returning to this issue because I have now found a different DHT sensor problem:
One AM2302 DHT sensor stops transmitting until power cycled!

After changing the supply voltage to 5V for the sensors as shown above it looked like all was well, but now I see that one of the sensors (the one on the far end, with approximately 10 m signal cable) drops out of sight after some time of working fine....
It seems not to respond at all.

I was pretty confused and have been picking at the firmware to find the reason for this behaviour, but did not find anything suspicious.
Restarting the ESP by uploading a new firmware through the network or by sending a restart command (I have implemented this as a precaution) did not help, the sensor #3 was still off-line.

Then I discovered that if the ESP controller was power cycled, then when it came back up the sensors were all working OK again!
First time I did not really understand this, but the second time the sensor disappeared I power cycled the unit (via the fuse for the attic outlet) and it was back on line. Then it worked fine for several days (readings are done once every 60 min) until it failed again today.
So I tested the fuse to cycle power and again sensor #3 is back in business...

QUESTIONS:
Is this a known problem with the AM2302 sensors?
Is there a remedy for it in such a case?

Stupid workaround?
I have been thinking of adding a power switch to the controller board for the 5V feed to the sensors such that the ESP itself can switch on/off the 5V power to the sensors. Seems ridiculous that one should need to do this, but it is one thing I can actually do and then have the firmware actuate the power cycle either every midnight or else whenever a sensor is failing to return a reading...