Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loop #5

Open
Prod69 opened this issue May 2, 2015 · 7 comments
Open

Loop #5

Prod69 opened this issue May 2, 2015 · 7 comments

Comments

@Prod69
Copy link

Prod69 commented May 2, 2015

Hello Jacques,

Firstly, let me thank you for producing this code for the SHT2x sensor.
At first I was getting the same error as some others due to not changing the i2c to bus 1 near the end of your code - but now I have it running on SHT25 sensor on bus 1. I did not have to change anything else so your code works just fine on the newer sensor too and I guess it would also for the SHT7x.
I have some code which returns results from 2 other sensors, a MCP9808 Temp sensor and MS5611 Barometric Pressure sensor. Neither written by me but I did manage to integrate them together into one and they run in a loop indefinitely and return results every 10 seconds.
When I try to integrate your code or loop your code, it goes crazy and returns results very quickly no matter what time.sleep I use.
My question is, if I may, and I hope you will forgive me as I am very new to all this:
If you could shed any light on anything obvious which would cause problem with looping? For my project I need to get results returning from my sensor array 24/7 at regular intervals.
Hope it is ok to contact you here, there is no issue with your code but I thought I would give you a try.

@jaques
Copy link
Owner

jaques commented May 2, 2015

Hello,

Glad to hear that it runs on a SHT25 and that you've been able to get it to work.

I'm not sure what could be going wrong, but if you send it through I could take a look and see if I can see anything.

Thanks for the feedback, most appreciated.
Richard.

@Prod69
Copy link
Author

Prod69 commented May 2, 2015

Hey Jacques,

I tried it two ways, firstly the code I am using for my other two sensors runs within a loop:

while True:

time.sleep(10.0)

when I add your code, the program runs but only returns results for one of the sensors (MCP9808 temp) which happens to be the first sensor the code deals with. Instead of a 10 second delay it also returns results very rapidly.

I tried running your code stand alone within the same loop and get the same result, IE no 10 second delay just a rapid return of results.

Here is the full code, yours and from two other sources which I have only made minor changes to, I have not edited yours in any way except to change to i2c bus 1.

#! /usr/bin/python

Note this script does require Root to run.

Created By: Jonny Fosnight

Date: 2013-03-18

Updated: 2015-04-20

Email: [email protected]

Feel free to use the script however you want.

Usage:

##sensor = MS5611()
##sensor.setElevationFt(354.33)
##sensor.read()
##sensor.printResults()

Alternatively all the values can be passed into the initialize function

sensor = MS5611(0, 0x76, 432.8 )

bus, i2c, elevation

sensor.read()

sensor.printResults()

while True:
import time
import math

## Import Libraries that let python talk to I2C devices
from smbus import SMBus

import Adafruit_MCP9808.MCP9808 as MCP9808

# Define a function to convert celsius to fahrenheit.
def c_to_f(c):
return c * 9.0 / 5.0 + 32.0

Default constructor will use the default I2C address (0x18) and pick a default I2C bus.

For the Raspberry Pi this means you should hook up to the only exposed I2C bus

from the main GPIO header and the library will figure out the bus number based

on the Pi's revision.

For the Beaglebone Black the library will assume bus 1 by default, which is

exposed with SCL = P9_19 and SDA = P9_20.

sensor = MCP9808.MCP9808()

Optionally you can override the address and/or bus number:

#sensor = MCP9808.MCP9808(address=0x20, busnum=2)

Initialize communication with the sensor.

sensor.begin()

temp = sensor.readTempC()
print ""
print "Press CNTRL-C to exit"
print ""
print(time.strftime("Time                      %H:%M:%S"))
print(time.strftime("Date                      %a %d/%m/%Y"))
print ""
print "MCP9808 Temperature:      {0:0.3F} C".format(temp, c_to_f(temp))
print "                          {1:0.3F} F".format(temp, c_to_f(temp))
print ""



class MS5611:
    """Driver for reading temperature/pressure MS5611 Pressure Sensor."""

    def __init__(self, bus = 1, i2c = 0x77, elevation = 103):
        """Initialize the Driver.

        Default bus is 1.  If you have a Rev 1 RPi then you will need to use bus 0.
        A bus object can also be passed in if you are sharing it among other modules

        Arguments (All optional):
        bus -- 0, 1, or a bus object
        i2c -- I2C address
        elevation -- Elevation in meters"""

        if(bus == 0 or bus == 1):
            self.bus = SMBus(bus)
        else:
            self.bus = bus
        self.i2c = i2c
        self.elevation = elevation


    def setElevation(self, elevation):
        self.elevation = elevation


    def setElevationFt(self, elevation):
        self.elevation = elevation / 3.2808


    def setI2c(self, i2c):
        self.i2c = i2c


    def read(self):
        ## Get raw pressure
        self.bus.write_byte(0x77, 0x48)
        time.sleep(0.05)

        D1 = self.bus.read_i2c_block_data(0x77, 0x00)
        D1 = D1[0] * 65536 + D1[1] * 256.0 + D1[2]
        time.sleep(0.05)

        ## Get raw temperature
        self.bus.write_byte(0x77, 0x58)
        time.sleep(0.05)
        D2 = self.bus.read_i2c_block_data(0x77, 0x00)
        D2 = D2[0] * 65536 + D2[1] * 256.0 + D2[2]
        time.sleep(0.05)


        ## Read Constants from Sensor
        if hasattr(self, 'C1'):
            C1 = self.C1
        else:
            C1 = self.bus.read_i2c_block_data(0x77, 0xA2) #Pressure Sensitivity
            C1 = C1[0] * 256.0 + C1[1]
            self.C1 = C1
            time.sleep(0.05)

        if hasattr(self, 'C2'):
            C2 = self.C2
        else:
            C2 = self.bus.read_i2c_block_data(0x77, 0xA4) #Pressure Offset
            C2 = C2[0] * 256.0 + C2[1]
            self.C2 = C2
            time.sleep(0.05)

        if hasattr(self, 'C3'):
            C3 = self.C3
        else:
            C3 = self.bus.read_i2c_block_data(0x77, 0xA6) #Temperature coefficient of pressure sensitivity
            C3 = C3[0] * 256.0 + C3[1]
            self.C3 = C3
            time.sleep(0.05)

        if hasattr(self, 'C4'):
            C4 = self.C4
        else:
            C4 = self.bus.read_i2c_block_data(0x77, 0xA8) #Temperature coefficient of pressure offset
            C4 = C4[0] * 256.0 + C4[1]
            self.C4 = C4
            time.sleep(0.05)

        if hasattr(self, 'C5'):
            C5 = self.C5
        else:
            C5 = self.bus.read_i2c_block_data(0x77, 0xAA) #Reference temperature
            C5 = C5[0] * 256.0 + C5[1]
            self.C5 = C5
            time.sleep(0.05)

        if hasattr(self, 'C6'):
            C6 = self.C6
        else:
            C6 = self.bus.read_i2c_block_data(0x77, 0xAC) #Temperature coefficient of the temperature
            C6 = C6[0] * 256.0 + C6[1]
            self.C6 = C6
            time.sleep(0.05)


        ## These are the calculations provided in the datasheet for the sensor.
        dT = D2 - C5 * 2**8
        TEMP = 2000 + dT * C6 / 2**23

        ## Set Values to class to be used elsewhere
        self.tempC = TEMP/100.0
        self.tempF = TEMP/100.0 * 9.0/5 + 32
        self.tempK = TEMP/100.0 + 273.15

        ## These calculations are all used to produce the final pressure value
        OFF = C2 * 2**16 + (C4 * dT) / 2**7
        SENS = C1 * 2**15 + (C3 * dT) / 2**8
        P = (D1 * SENS / 2**21 - OFF) / 2**15
        self.pressure = P/100.0

        ## Calculate an offset for the pressure.  This is required so that the readings are correct.
        ##   Equation can be found here: http://en.wikipedia.org/wiki/Barometric_formula
        altOffset = math.exp( (-9.80665 * 0.0289644 * self.elevation) / (8.31432 * self.tempK) )
        self.pressureAdj = ( P/altOffset ) / 100.0 

    def getTempC(self):
        return self.tempC

    def getTempF(self):
        return self.tempF

    def getPressure(self):
        return self.pressure

    def getPressureAdj(self):
        return self.pressureAdj

    def getBus(self):
        return self.bus

    def printResults(self):
        print ""
        print "MS5611  Temperature:     ", round(self.tempC, 2), "C"
        print "                         ", round(self.tempF, 2), "F"
        print ""
        print "Pressure Absolute:       ", round(self.pressure, 2), " hPa"
        print "         Adjusted:       ", round(self.pressureAdj, 2), "hPa"
        print "         Adjusted:       ", round(self.convert2In(self.pressureAdj), 2), "  inHg"
        print "----------------------------------------------------------------------------------------"

    def convert2In(self, pressure):
        return pressure * 0.0295301

    class SHT21:

#control constants
        _SOFTRESET = 0xFE
        _I2C_ADDRESS = 0x40
        _TRIGGER_TEMPERATURE_NO_HOLD = 0xF3
        _TRIGGER_HUMIDITY_NO_HOLD = 0xF5

        #From: /linux/i2c-dev.h
        I2C_SLAVE = 0x0703
        I2C_SLAVE_FORCE = 0x0706

def __init__(self, device_number=1):

    self.i2c = open('/dev/i2c-%s'%(device_number),'r+',0)
    fcntl.ioctl(self.i2c, self.I2C_SLAVE,0x40)
    self.i2c.write(chr(self._SOFTRESET))
    time.sleep(0.050)


def read_temperature(self):    

    self.i2c.write(chr(self._TRIGGER_TEMPERATURE_NO_HOLD))
    time.sleep(0.250)
    data = self.i2c.read(3)
    if self._calculate_checksum(data,2) == ord(data[2]):
        return self._get_temperature_from_buffer(data)


def read_humidity(self):    

    self.i2c.write(chr(self._TRIGGER_HUMIDITY_NO_HOLD))
    time.sleep(0.250)
    data = self.i2c.read(3)
    if self._calculate_checksum(data,2) == ord(data[2]):
        return self._get_humidity_from_buffer(data)    


def close(self):
    """Closes the i2c connection"""
    self.i2c.close()


def __enter__(self):
    """used to enable python's with statement support"""
    return self


def __exit__(self, type, value, traceback):
    """with support"""
    self.close()


def _calculate_checksum(self, data, nbrOfBytes):
    """5.7 CRC Checksum using teh polynomial given in the datasheet"""
    # CRC
    POLYNOMIAL = 0x131 # //P(x)=x^8+x^5+x^4+1 = 100110001
    crc = 0
    #calculates 8-Bit checksum with given polynomial
    for byteCtr in range(nbrOfBytes):
        crc ^= (ord(data[byteCtr]))
        for bit in range(8,0,-1):
            if (crc & 0x80):
                crc = (crc << 1) ^ POLYNOMIAL
            else:
                crc = (crc << 1)
    return crc


def _get_temperature_from_buffer(self, data):
    """This function reads the first two bytes of data and returns the temperature
    in C by using the following function:
    T = =46.82 + (172.72 * (ST/2^16))
    where ST is the value from the sensor
    """
    unadjusted = (ord(data[0]) << 8) + ord(data[1])
    unadjusted *= 175.72
    unadjusted /= 1 << 16 # divide by 2^16
    unadjusted -= 46.85
    return unadjusted


def _get_humidity_from_buffer(self, data):
    """This function reads the first two bytes of data and returns the relative humidity
    in C by using the following function:
    RH = -6 + (125 * (SRH / 2 ^16))
    where SRH is the value read from the sensor
    """
    unadjusted = (ord(data[0]) << 8) + ord(data[1])
    unadjusted *= 125
    unadjusted /= 1 << 16 # divide by 2^16
    unadjusted -= 6
    return unadjusted

if name == "main":
try:
with SHT21(1) as sht21:
print "SHT25 Temperature: %s"%sht21.read_temperature(), "C"
print "SHT25 Humidity: %s"%sht21.read_humidity(), "%"
print ""
except IOError, e:
print e
print 'Error creating connection to i2c. This must be run as root'

sensor = MS5611()
sensor.read()
sensor.printResults()
time.sleep(10.0)

@Prod69
Copy link
Author

Prod69 commented May 2, 2015

I am sorry that ended up getting formatted and looking a complete mess, I wasn't expecting that.
At the moment the program is simply printing results to the screen.
Ultimately I wish to take several readings a minute for each sensor, take an average for each and have them added to some kind of database and upload the readouts to a webpage, so a minute average for each sensor.

@jaques
Copy link
Owner

jaques commented May 2, 2015

Ok, no worries. In Markdown (the formatting engine that github uses for comments) if you add an indent of say 4 spaces everything will format like code.

It looks to me like the whole file isn't in the loop. In python whitespace is important, and if the if __name__ == "__main__": line isn't in the main loop as it's not indented. This is why the final sleep isn't working.

I would recommend not doing quite so much in the main loop of the program. I suggest splitting it out into separate files. Here I've got sht21.py untouched in the same folder. If you move the code for the MS5611 code as well you might find it easier to deal with.

I'm not able to run any of this code I include below, as I don't have a pi to hand, but hopefully you get the idea. If this proves to work, try moving the MS5611 code out as well and uncommenting the 3 lines to create the class, read the temperature and print the value.

Let me know if you get stuck.

Richard.

    #! /usr/bin/python
    import time
    import math
    from smbus import SMBus
    import Adafruit_MCP9808.MCP9808 as MCP9808

    #this line needs sht21.py to be in the same folder
    #I don't think you'll need to change anything in it.
    import sht21

    #setup all three sensors
    sht25 = sht21.SHT21(1)  #open on /dev/i2c-1

    mcp9808 = MCP9808.MCP9808()
    mcp9808.begin()

    # if you move the code for the MS5611 class into a file called ms5611.py in the same folder
    # python will understand that as a module, and you'll be able to create an instance of that 
    # class like this, I'll leave it commented out for now, just to keep things simple.
    #ms5611 = ms5611.MS5611()

    print 'Press Ctrl-C to quit.'
    while True:
            mcp_temp = mcp9808.readTempC()
            sht_temp = sht25.read_temperature()
            #ms5611.read()

            print 'MCP9808 Temperature: {0:0.3F}*C'.format(mcp_temp)
            print 'SHT25   Temperature: {0:0.3F}*C'.format(sht_temp)
            #print 'MS5611  Temperature: {0:0.3F}*C'.format(ms5611.tempC)

            time.sleep(1.0)

@nadanks7
Copy link

In case you were curious I've just recently made a similar module for the new SHT31 sensor, and tested it on raspberry pi 2 model b.
I'm posting here in part to give credit here; since I used your SHT21.py code as a base and modified from there (based on sensirions sht31 datasheet) to make it work for the SHT31
The code isn't particularly clean yet and I'm definitely an elementary programmer, but it works. If you wanted to see the code I can post it here.

@poohsen
Copy link

poohsen commented Sep 22, 2015

I am one of the unfortunate ones for which sht21.py does not work. I'm trying to find the reason. @nadanks7 and @Prod69 can I ask what your Revision numbers are in the output of cat /proc/cpuinfo ? Mine is 000e and, like I said, it doesn't work for me.

@poohsen
Copy link

poohsen commented Sep 23, 2015

i2cdetect -y 1 gives me UU instead of b30 so I guess that's my issue. It's not sht21.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants