Revisiting the AM2315 Humidity Sensor

NOTE: This content of this page is no longer relevant. Please go here for the latest AM2315 implementation “How-To.”

——————————————————————————————————————–

I was quite surprised by the number of comments and emails I received about the AM2315 humidity sensor. This confirms two things. First, it appears this sensor is quite popular. Based on my experimentation with the device, it is also quite accurate. Secondly, there are a lot of folks hacking this sensor but struggling with the am2315-python-api code.

It was really great of Joehrg Ehrsam to publish the code and make it available to all of us. Unfortunately, the code is poorly formatted and not commented. Also, the code has some timing issues that can result in bogus data. If you look at the below screenshot you can see the sensor is sending garbage.

image001

The AM2315 datasheet warns about this:

“Send read/write command, the host must wait at least 1.5ms, and then send a read sequence, to read back the data…” (pg15).

Failure to get this timing right means you can get inaccurate data from the sensor. I have written Joehrg twice and did not receive a response. So, I decided to write a new Python class to read the sensor data accurately. You can download the code here:

 

Be sure to read the README.txt file and I suggest you run the test_aosong_am2315.py script to be sure the sensor is wired correctly.

Sopwith

 

16 thoughts on “Revisiting the AM2315 Humidity Sensor

  1. Amazing work! I finally got the chance to go over the code and it was so much easier to understand. I want to personally thank you for taking the time to answer my emails and explain in depth when I had questions.

  2. Hi Sopwith,
    Bang up job on the new class! Great to see code that doesn’t sacrifice readability at the alter of cleverness.

    Just wondering if the negative check should instead be;

    # Check for negative temp
    if temp_H&0x80:
    negative = True
    # Mask the negative flag
    temp_H &=0x7F

    As I suspect (haven’t tested) 0x8 and 0x7 will be interpreted as 0x08 and 0x07?

    Cheers

  3. A byte is represented by 8bits or 2 hex characters
    1 hex character represents 4 bits

    Hex Dec Bin
    0x00 0 0b0000 0000
    0x0F 15 0b0000 1111
    0xF0 240 0b1111 0000
    0xFF 255 0b1111 1111

    0x08 8 0b0000 1000
    0x80 128 0b1000 0000

    0x07 7 0b0000 0111
    0x7F 127 0b0111 1111

    • Ethan,

      You are correct – this is a bug. Not sure what I was thinking here, I guess I was in too much of a hurry. Without the leading zeros, I am not correctly checking or masking the negative temperature flag at all. I am missing the high-order nibble. This means my code will not read the temperature correctly if it is below zero Celsius.

      The correct code should be:
      # Check for negative temp
      if temp_H&0x08:
      negative = True
      # Mask the negative flag
      temp_H &=0x7F

      Thanks for your persistence in pointing this out! I will correct the source and re-post it.
      Much appreciated.

      Sopwith

  4. Hi Sopwith,

    Excellent work here, but there is still an issue with the negative temperatures.

    The two problems are that you need to check for bit 15 in the upper byte to be a 1 (0x80 not 0x08). The other issue is that you need to correct the celsius value prior to converting to Farenheit. It is cold here today (7°F right now), so I was able to test all of this out.

    I changed your main routine to:
    if temp_H & 0x80:
    negative = True
    # Mask the negative flag
    temp_H &=0x7F

    tempC = (temp_H*256.0+temp_L)/10.0
    if negative:
    tempC = -tempC
    tempF = self.CelsiusToFahrenheit(tempC)

    and I changed your conversion routine to:
    if celsius == None:
    return

    return celsius*9.0/5.0 + 32.

    Works perfectly now.

    Thanks for doing all the hard work.

    Keith

    • Wow Keith – thanks so much for fixing my code. It is obvious that I did not test it. Living in Southern CA it is hard to find a cold place! Ol’ Sopwith believes if code has not been tested – then it is broken. This confirms the theory.

      I will fix the code and repost.

      Thanks again for making this right.

      Sopwith

      • Hi Sopwith,

        For the work I am doing with the AM2315 I really wanted to get it running under Python 2. I worked on it all day today and I have been successful. Since your Python3 version works well, it may not matter too much, but in case anyone is in the same boat as I am, I have shared the code on my website at http://www.colorado-barrs.com/RPi/am2315.py.

        The trick is using pigpio.

        I hope you don’t think I am trying to hijack your blog…I am not. :^)

        • Keith,

          I have had several pings from folks who really want AM2315 V2 Python because they want to integrate it with other legacy code. Having working V2 code is highly valuable. Thanks for taking the time to do this.

          Sopwith

  5. Out of 10 times calling `sensor.ReadSensorData()`, 3 of them return `None`.

    The test suite is only successful about once every 10 runs or so.

    Any ideas? I hooked up the sensor on a Raspi 2 on I2C Bus 1 using two 10kO pullups…

    • Strange thing is, this works without any problems:

      while true; do python3 -c ‘from aosong_am2315 import AOSONG_AM2315; sensor = AOSONG_AM2315(); print(sensor.ReadSensorData())’; sleep 1; done

      The test suite still fails in almost all cases. Could this be a timing issue?

      • Hi Danilo,

        I have not tested any of the sensors or code with the new Pi2. I suspect you are correct – this is a timing issue. Trying to ‘bit-bang’ a sensor on a traditional Pi is hard enough. Attempting to do it on a very fast Pi2 is probably not going to work.

        Until I can do some further testing, I suggest you try your exact same setup in an earlier Pi version and see if it works.

        Sopwith

  6. Hello-

    Thanks for cleaning up this code and making it work – I’ve been using it for the past year. But due to changes in use of my sensor (i.e. colder temps), I found today that there still appears to be a bug in the code in dealing with temps below 0C – when requesting them in F. See below:
    >>> sensor.ReadTemperature()
    -8.6
    >>> sensor.ReadTemperature(True)
    -16.520000000000003
    >>> sensor.ReadTemperature()*9/5+32
    16.520000000000003

    Notice that the temp in F is being returned as negative, though it shouldn’t yet be negative.

    I believe the relevant code that may be causing the bug is this:
    if negative:
    tempC = -abs(tempC)
    tempF = -abs(tempF)
    i.e. the code is assuming that if negative, to take the negative ABS of both C and F – but this is a flaw in logic, as C goes negative before F.

    I’m not strong enough with Python to modify the logic myself unfortunately.

    For now I’m modifying my script to request the temp in C and do the conversion to F myself.

    • On second review, that code block I believe is the culprit just needs to be commented out. There is already logic above it to set the C as negative. Haven’t tested with a negative F temp though – and hopefully won’t have any of those any time soon!

      • Thanks for pointing this out. I am currently working on a Pi camera system housed in a heated enclosure. The goal is to make sure it can withstand temperatures down to -20F. I will need this code to work and will fix it as required.

        Sopwith

Leave a Reply

Your email address will not be published. Required fields are marked *