Re: TSL2561 and Raspberry Pi

by Static on Sun Mar 03, 2013 4:09 am

The "readLux" function of the code is supposed to execute the function as part of the TSL2561 class. (Be real careful reading too much in to what I'm saying here, I'm just barely putting this stuff in to practice. You can already see the screw-up and learning experience I've already provided).
Inside of a Class, the first variable passed to a function (the first item inside the parentheses) is traditionally (Pythonically) "self". In reality it doesn't matter what the first thing is actually called (I think it needs to be consistent throughout the class). By Python convention it is "self".
If I understand it correctly, "self" allows the function to refer to the class variables that house the class functions.
There are some pretty good books out there (I know, I know, more reading). I pulled Mark Pilgrim's book down "Dive into Python 3", and it looks pretty good. The only issue is that Classes are chapter 7. He does a great job of building on his previous examples. The book is good, but you kinda have to start from chapter 1.
http://getpython3.com/diveintopython3/

However, it appears to be free, online (Mr. Pilgrim, I'll buy you a beer if I ever meet you. At least one).

There are other books that will let you just jump into Classes and Objects, but I haven't seen one that just "conveys it". This is one of the areas where Python is incredibly powerful. You need to work at it, but once you get it, it mostly clicks (says the pure amateur, me).

I've run in to the "out of stock notice" from Adafruit. I also got my shipment on time, somehow, in the aftermath of Sandy. That impressed me (I'm an emergency response guy, by trade).
The big thing that does it for me is this board and the technical support. Yeah, I pay a little bit more for things from here. I'll be the first to admit that sometimes I have to buy elsewhere, or find alternate means of procurement (I kit bash and hack things together, that's part of what we do). But these folks do an incredible job. I tried playing with this stuff for decades, and just wasn't getting it. A little willingness to fail (Blowing $30 worth of parts hurts, but isn't damaging), a lot of willingness to read and learn, and some quiet encouragement from the staff here has worked miracles.
Then coming on to the board here and writing things out has really impressed me. You folks are building really cool....stuff (ok, I'm not allowed to use certain words? Words I say to my students or in front of someone else's mother?). Some of those things are utterly inane (why do you do it? Because it's there). Others are building gadgets that would cost hundreds to thousands of dollars (I'm looked for exotic monitoring equipment when I was writing my undergraduate thesis). You're critically thinking, getting a little uncomfortable, and doing really cool things. Some of these things are probably out of your realm, and that's just so freakin' awesome.

I'm kinda jealous of these projects, but really glad you're writing about them.
Static
 
Posts: 178
Joined: Thu Dec 23, 2010 5:21 pm

Re: TSL2561 and Raspberry Pi

by lenos on Mon Mar 04, 2013 3:09 am

Static wrote:
mstone@yawp.com wrote:I didn't know anyone was reading this, except csalty and scortier.

i just wanted you guys to know that i follow the thread since it started. my english and python coding skills arent that good as yours, but hey - im still learning.

atm, we use the python code provided here to monitor various fluorescent lamps (which we use to grow algae). so our idea was:
fluorescent tubes lose light intensity with time to time. the monitored output over a couple of month shown on a nice graph could eventually say us the best moment to replace the lamps.

thank you all for sharing your work here, without you guys our project would still be in our minds. now it does an actual job/task - i hope so. :)

[EDIT]
ive run into problems with smbus using python 3.2 (installed from = wheezy main contrib non-free rpi). under 2.7 smbus works like a charm.
all i know is that the package 'python-smbus' is only usable with python 2.x, after googleing around i found this thread here, im still compiling atm, so i cant say if this will work then.
did i miss something? how did you get smbus work with python 3.2?
lenos
 
Posts: 2
Joined: Mon Mar 04, 2013 2:31 am

Re: TSL2561 and Raspberry Pi

by Static on Mon Mar 04, 2013 8:49 am

Your english is just fine, and I'm going to bet your Python skills are on par with mine.

I think smbus just worked, but I'm using the Adafruit Occidentalis build. It's built off of Rasberry Wheezy, but it's not the same. I seem to remember that I had issues getting smbus to work on Wheezy, but not Occidentalis.
I switched to Occidentalis almost immediately after playing with the Raspberry Pi. I've never had an issue with it, and it let me play with the GPIO pins without much effort. I know Adafruit is calling it "Beta", or a "work in progress", but it really seems to flat-out work.
The link for Occidentalis is on this page. If you have an extra SD card, it's worth throwing on there and checking it out:

http://learn.adafruit.com/adafruit-raspberry-pi-lesson-1-preparing-and-sd-card-for-your-raspberry-pi/downloading-an-image

The sun's coming up over here, and as I'm writing this, I'm looking at my terminal window. I'm getting weird vacillations from 1171.0755 to 28.9980600000000024 on my external sensor. The interior sensor seems to be reading consistently (1 erroneous value out of 100, where it drops to an integer 0). The exterior sensor is using the same code as the interior one. I can't figure out why it's performing like that, unless it has to do with the cold or the increase in sunlight. I'm getting several readings at one level, then it will switch to the other for several readings, and then back. It looks like it started when the light level approached 1171 (the levels look like they raised normally, without issue).

This is an issue that wouldn't be fixed by averaging. I can't get the inside sensor up to that high a light level. I'm not sure I have an intense enough portable light.
Static
 
Posts: 178
Joined: Thu Dec 23, 2010 5:21 pm

Re: TSL2561 and Raspberry Pi

by lenos on Mon Mar 04, 2013 9:00 am

thank you static!

[EDIT]
I seem to remember that I had issues getting smbus to work on Wheezy, but not Occidentalis.

i got the same errors with smbus and python3 on Occidentalis v0.2 - are you using v0.1?

btw. learnpythonthehardway.org is also i nice tutorial for starters, although the title dosen't suggest that. :)
lenos
 
Posts: 2
Joined: Mon Mar 04, 2013 2:31 am

Re: TSL2561 and Raspberry Pi

by Static on Tue Mar 05, 2013 9:10 am

I'm pretty sure that I'm using 0.2. I reinstalled everything within the last two months.

I'm not competent to diagnose the smbus issue (yet). I'm hoping someone else will be able to offer some help. I had really good feedback from the folks over at RaspberryPi.org, if no one here has ideas.

Can someone check the code regarding the auto-ranging (where the gain is automatically adjusted for high light conditions)? I don't have any notes on how that code was arrived at, and looking at it and the spec sheet for the TSL2561, I'm not sure the values and orders of operation are correct.
Static
 
Posts: 178
Joined: Thu Dec 23, 2010 5:21 pm

Re: TSL2561 and Raspberry Pi

by csalty on Tue Mar 05, 2013 8:15 pm

Hello Static. Thanks for the explanation regarding the use of "self". I totally understand now. After doing some additional reading on the subject of classes, it is all starting to make much more sense. I should really get a python book.
The sun's coming up over here, and as I'm writing this, I'm looking at my terminal window. I'm getting weird vacillations from 1171.0755 to 28.9980600000000024 on my external sensor.

Interesting you are getting spikes from outside but not from your inside sensor. Maybe you are detecting solar flare activity :D I was getting some strange results with my Arduino version of the sensor, directly pointing at the sun. With inside use of the Pi and Arduino sensors, I get pretty consistent readings. Not sure what's going on with full sun light. After reading the datasheet in more detail, I think that the sensors are really meant to detect ambient light conditions and control the dimming of LCDs and displays in response to changing light conditions
The TSL256x is intended for use in ambient light detection applications such as display backlight control, where adjustments are made to display brightness or contrast based on the brightness of the ambient light, as perceived by the human eye. pg 22 of the datasheet

Check this out too regarding how the lux calculation was calibrated:
The formulas shown above were obtained by optical testing with fluorescent and incandescent light sources, and apply only to open-air applications. Optical apertures (e.g. light pipes) will affect the incident light on the device. pg 22

Looks calculations are not going to be that accurate using sunlight. I bet one could recalibrate the sensor using measurements from a TSL and a good lux meter done over different times of the day in full sunlight. Maybe I'll give that a try.

-csalty
csalty
 
Posts: 27
Joined: Sat Feb 23, 2013 7:32 pm

Re: TSL2561 and Raspberry Pi

by csalty on Tue Mar 05, 2013 8:21 pm

Lenos: I'm using the TSL2561 for similar purposes, growing purple sulfur bacteria on 850 nm IR LEDs, in the dark. The TSL2561 sensor works perfectly for our application. We can adjust the intensities of our LED arrays to match the IR given off by incandescent light sources. The growth of the microbes are amazingly similar with infrared compared to standard light bulbs.

Good luck with your project and if you have any code modifications please post them.

-csalty
csalty
 
Posts: 27
Joined: Sat Feb 23, 2013 7:32 pm

Re: TSL2561 and Raspberry Pi

by Static on Thu Mar 07, 2013 11:36 am

I've got to finish a writing contract today, then I'm going to take a look at the code again. I feel like this is a ratio issue, and I'm implementing the auto-ranging incorrectly. Whenever a ton of light falls on the sensor, it bounces between those two, very specific, values.
Static
 
Posts: 178
Joined: Thu Dec 23, 2010 5:21 pm

Re: TSL2561 and Raspberry Pi

by csalty on Fri Mar 08, 2013 3:55 am

Waiting to see what you come up with.

I had to modify my code because COSM changed how they acuqire data from the eeml module. So I switched to petervizi's eeml python library but there is an issue with it and COSM: you have to use an integer as your ID's for the datafeed. Bummer. While messing around with the new eeml update, I came up with a newer version of my code. I think it is a bit faster than the one I posted earlier.

Code: Select all
#!/usr/bin/python

import sys
import smbus
import time
import eeml   # uses pertervizi's python-eeml
import eeml.datastream
import eeml.unit
from Adafruit_I2C import Adafruit_I2C
from array import *
from eeml.datastream import CosmError

# info about the cosm.com feed
API_KEY = 'key goes here'  # replace with your private KEY
FEED=105257  # replace with your feednumber
API_URL = '/v2/feeds/{feednum}.xml' .format(feednum = FEED)

### Written for Python 3
### Big thanks to bryand, who wrote the code that I borrowed heavily from/was inspired by
### More thanks pandring who kind of kickstarted my work on the TSL2561 sensor
### A great big huge thanks to driverblock and the Adafruit team (Congrats on your many succeses
### Ladyada).  Without you folks I would just be a guy sitting somewhere thinking about cool stuff
### Now I'm a guy building cool stuff.
### If any of this code proves useful, drop me a line at medicforlife.blogspot.com

class Luxmeter:
    i2c = None

    def __init__(self, address=0x39, debug=0, pause=0.41):
        self.i2c = Adafruit_I2C(address)
        self.address = address
        self.pause = pause
        self.debug = debug

        self.i2c.write8(0x80, 0x03)     # enable the device
        self.i2c.write8(0x81, 0x11)     # set gain = 16X and timing = 101 mSec
        time.sleep(self.pause)          # pause for a warm-up

    def readfull(self, reg=0x8C):
        """Reads visible + IR diode from the I2C device"""
        try:
            fullval = self.i2c.readU16(reg)
            newval = self.i2c.reverseByteOrder(fullval)
            if (self.debug):
                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, fullval & 0xFFFF, reg))
            return newval
        except IOError:
            print("Error accessing 0x%02X: Check your I2C address" % self.address)
            return -1

    def readIR(self, reg=0x8E):
        """Reads IR only diode from the I2C device"""
        try:
            IRval = self.i2c.readU16(reg)
            newIR = self.i2c.reverseByteOrder(IRval)
            if (self.debug):
                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, IRval & 0xFFFF, reg))
            return newIR
        except IOError:
            print("Error accessing 0x%02X: Check your I2C address" % self.address)
            return -1

    def readfullauto(self, reg=0x8c):
        """Reads visible + IR diode from the I2C device with auto ranging"""
        try:
            fullval = self.i2c.readU16(reg)
            newval = self.i2c.reverseByteOrder(fullval)
            if newval >= 37177:
                self.i2c.write8(0x81, 0x01)
                time.sleep(self.pause)
                fullval = self.i2c.readU16(reg)
                newval = self.i2c.reverseByteOrder(fullval)
            if (self.debug):
                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, fullval & 0xFFFF, reg))
            return newval
        except IOError:
            print("Error accessing 0x%02X: Check your I2C address" % self.address)
            return -1

    def readIRauto(self, reg=0x8e):
        """Reads IR diode from the I2C device with auto ranging"""
        try:
            IRval = self.i2c.readU16(reg)
            newIR = self.i2c.reverseByteOrder(IRval)
            if newIR >= 37177:
                self.i2c.write8(0x81, 0x01)     #   remove 16x gain
                time.sleep(self.pause)
                IRval = self.i2c.readU16(reg)
                newIR = self.i2c.reverseByteOrder(IRval)
            if (self.debug):
                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, IRval & 0xFFFF, reg))
            return newIR
        except IOError:
            print("Error accessing 0x%02X: Check your I2C address" % self.address)
            return -1

def luxread(type, address = 0x39, debug = False, autorange = True):
    """Grabs a lux reading either with autoranging or without"""
    LuxSensor = Luxmeter(0x39, False)
    if autorange == True:
        ambient = LuxSensor.readfullauto()
        IR = LuxSensor.readIRauto()
    else:
        ambient = LuxSensor.readfull()
        IR = LuxSensor.readIR()

    if ambient == 0:  # in the dark you cant divide by 0 in the next calculation
        ambient = 0.0001  # so I set it to a small number

    ratio = (float) (IR / ambient)

    if ((ratio >= 0) & (ratio <= 0.52)):
        lux = (0.0315 * ambient) - (0.0593 * ambient * (ratio**1.4))
    elif (ratio <= 0.65):
        lux = (0.0229 * ambient) - (0.0291 * IR)
    elif (ratio <= 0.80):
        lux = (0.0157 * ambient) - (0.018 * IR)
    elif (ratio <= 1.3):
        lux = (0.00338 * ambient) - (0.0026 * IR)
    elif (ratio > 1.3):
        lux = 0

    #  I want to know the values for IR, ambient, and lux

    if (type==1):
        return ambient
    elif (type==2):
        return IR
    elif (type==3):
        return lux

def getIRbuffer(size):
    """read IR sensor and print the data"""
    buffer=[]      # place to store multiple IR readings type==1

    # number of reads to save in the bufer
    for x in range(0,size):
        buffer.append(luxread(1))

    # calculate the average value within the buffer
    a = (sum(buffer) / len(buffer))

    # in case you want to get the data to the terminal
#   return("Lux: %.2f" % (a))
    return a

def getAmbientbuffer(size):
    """read ambient sensor value and print the data"""
    buffer=[] # place to store multiple Ambient readings type==2
    for x in range(0,size):
        buffer.append(luxread(2))

    a = (sum(buffer) / len(buffer))

    # in case you want to get the data to the terminal
#   return("Lux: %.2f" % (a))
    return a

def getLuxbuffer(size):
    """read Lux sensor make a buffer and print the data"""
    buffer=[]     # place to store multiple Lux readings type==3
    for x in range(0,size):
        buffer.append(luxread(3))

    a = int((sum(buffer) / len(buffer))) # convert to integer

    # in case you want to get the data to the terminal
#   return("Lux: %.2f" % (a))
    return a

print("Program started, logging to COSM, ctrl-C to end")  # a startup service message


while(True):  # specify the number of readings in the buffer
    amval= getAmbientbuffer(10)
    irval= getIRbuffer(10)
    luxval= getLuxbuffer(10)
       
#    print (amval, irval, luxval)  # uncomment if you want to see the data in the terminal

    # Open up data stream to cosm with your URL and key
    pac = eeml.datastream.Cosm(API_URL, API_KEY)
    pac.update(eeml.Data(0, amval, tags=('Ambient',)))  # ID's has to be an integer
    pac.update(eeml.Data(1, irval, tags=('Infrared',))) # waiting for update
    pac.update(eeml.Data(2, luxval, tags=('Lux',)))     # to fix this

    # send data to cosm
    pac.put()


I also made a version for using gspread and google docs. I learned about the Google Widget and how you can make a widget like one of those sliding stock windows/quotes. It's much easier to implement relative to COSM. Here's my code so far for the gspread:
Code: Select all
#!/usr/bin/python

import sys
import smbus
import time
import datetime
import gspread
from Adafruit_I2C import Adafruit_I2C
from array import *


### Written for Python 3
### Big thanks to bryand, who wrote the code that I borrowed heavily from/was inspired by
### More thanks pandring who kind of kickstarted my work on the TSL2561 sensor
### A great big huge thanks to driverblock and the Adafruit team (Congrats on your many succeses
### Ladyada).  Without you folks I would just be a guy sitting somewhere thinking about cool stuff
### Now I'm a guy building cool stuff.
### If any of this code proves useful, drop me a line at medicforlife.blogspot.com

class Luxmeter:
    i2c = None

    def __init__(self, address=0x39, debug=0, pause=0.41):
        self.i2c = Adafruit_I2C(address)
        self.address = address
        self.pause = pause
        self.debug = debug

        self.i2c.write8(0x80, 0x03)     # enable the device
        self.i2c.write8(0x81, 0x11)     # set gain = 16X and timing = 101 mSec
        time.sleep(self.pause)          # pause for a warm-up

    def readfull(self, reg=0x8C):
        """Reads visible + IR diode from the I2C device"""
        try:
            fullval = self.i2c.readU16(reg)
            newval = self.i2c.reverseByteOrder(fullval)
            if (self.debug):
                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, fullval & 0xFFFF, reg))
            return newval
        except IOError:
            print("Error accessing 0x%02X: Check your I2C address" % self.address)
            return -1

    def readIR(self, reg=0x8E):
        """Reads IR only diode from the I2C device"""
        try:
            IRval = self.i2c.readU16(reg)
            newIR = self.i2c.reverseByteOrder(IRval)
            if (self.debug):
                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, IRval & 0xFFFF, reg))
            return newIR
        except IOError:
            print("Error accessing 0x%02X: Check your I2C address" % self.address)
            return -1

    def readfullauto(self, reg=0x8c):
        """Reads visible + IR diode from the I2C device with auto ranging"""
        try:
            fullval = self.i2c.readU16(reg)
            newval = self.i2c.reverseByteOrder(fullval)
            if newval >= 37177:
                self.i2c.write8(0x81, 0x01)
                time.sleep(self.pause)
                fullval = self.i2c.readU16(reg)
                newval = self.i2c.reverseByteOrder(fullval)
            if (self.debug):
                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, fullval & 0xFFFF, reg))
            return newval
        except IOError:
            print("Error accessing 0x%02X: Check your I2C address" % self.address)
            return -1

    def readIRauto(self, reg=0x8e):
        """Reads IR diode from the I2C device with auto ranging"""
        try:
            IRval = self.i2c.readU16(reg)
            newIR = self.i2c.reverseByteOrder(IRval)
            if newIR >= 37177:
                self.i2c.write8(0x81, 0x01)     #   remove 16x gain
                time.sleep(self.pause)
                IRval = self.i2c.readU16(reg)
                newIR = self.i2c.reverseByteOrder(IRval)
            if (self.debug):
                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, IRval & 0xFFFF, reg))
            return newIR
        except IOError:
            print("Error accessing 0x%02X: Check your I2C address" % self.address)
            return -1


def luxread(type, address = 0x39, debug = False, autorange = True):
    """Grabs a lux reading either with autoranging or without"""
    LuxSensor = Luxmeter(0x39, False)
    if autorange == True:
        ambient = LuxSensor.readfullauto()
        IR = LuxSensor.readIRauto()
    else:
        ambient = LuxSensor.readfull()
        IR = LuxSensor.readIR()

    if ambient == 0:  # in the dark you cant divide by 0 in the next calculation
        ambient = 0.0001  # so I set it to a small number

    ratio = (float) (IR / ambient)

    if ((ratio >= 0) & (ratio <= 0.52)):
        lux = (0.0315 * ambient) - (0.0593 * ambient * (ratio**1.4))
    elif (ratio <= 0.65):
        lux = (0.0229 * ambient) - (0.0291 * IR)
    elif (ratio <= 0.80):
        lux = (0.0157 * ambient) - (0.018 * IR)
    elif (ratio <= 1.3):
        lux = (0.00338 * ambient) - (0.0026 * IR)
    elif (ratio > 1.3):
        lux = 0

    #  I want to know the values for IR, ambient, and lux

    if (type==1):
        return ambient
    elif (type==2):
        return IR
    elif (type==3):
        return lux

def getIRbuffer(size):
    """read IR sensor and print the data"""
    buffer=[]      # place to store multiple IR readings type==1

    # number of reads to save in the bufer
    for x in range(0,size):
        buffer.append(luxread(1))

    # calculate the average value within the buffer
    a = (sum(buffer) / len(buffer))

    return a

def getAmbientbuffer(size):
    """read ambient sensor value and print the data"""
    buffer=[] # place to store multiple Ambient readings type==2
    for x in range(0,size):
        buffer.append(luxread(2))

    a = (sum(buffer) / len(buffer))

    return a

def getLuxbuffer(size):
    """read Lux sensor make a buffer and print the data"""
    buffer=[]     # place to store multiple Lux readings type==3
    for x in range(0,size):
        buffer.append(luxread(3))

    a = int((sum(buffer) / len(buffer))) # convert to integer

    return a


print("Program started, logging to COSM, ctrl-C to end")  # a startup service message

while(True):
    amval= getAmbientbuffer(10)  # number of reads in the buffer
    irval= getIRbuffer(10)
    luxval= getLuxbuffer(10)
       
#    print (amval, irval, luxval)  # uncomment to print to the terminal

    # Login with your Google account
    gc = gspread.login('your google email address', 'your password')  # enter login credentials

    # Open a worksheet from spreadsheet with one shot
    wks = gc.open("spreadsheet name goes here").sheet1  # put your spreadsheet name here

    # print the values to the Google Spreadsheet
    values = [datetime.datetime.now(), amval, irval, luxval]
    wks.append_row(values)

    time.sleep(60) #  reading interval
csalty
 
Posts: 27
Joined: Sat Feb 23, 2013 7:32 pm

Re: TSL2561 and Raspberry Pi

by csalty on Tue Mar 12, 2013 12:51 am

For what it's worth, here is a new version of the TSL2561 code I've been working on. I post my data from a Raspberry Pi to http://cosm.com for realtime data monitoring. I switched to a json-based method of formatting because of some problems with the eeml module (xml-based). I found a great simple python approach from a Cosm.com forum member. What a genius! See post: http://community.cosm.com/node/910

Latest script:

Code: Select all
#!/usr/bin/python

from Adafruit_I2C import Adafruit_I2C
from array import *
from datetime import datetime
import json
import mechanize
import smbus
import sys
import time

# info about the cosm.com feed
key = 'put your long cosm.com key here'  # replace with your private KEY
feed='cosm feed number goes here'  # replace with your feednumber

### Original code by bryand, who wrote the code and static who borrowed heavily from/was
### inspired by.  Visit static's website: medicforlife.blogspot.com
### Thanks to driverblock and the Adafruit team for answering questions on the forum


# ===========================================================================
# Cosm json CLASS  develop by jrheling http://community.cosm.com/node/910
# Also see http://www.netfluvia.org/layer8/?p=175 for code
# ===========================================================================

class PachubeFeedUpdate:

  _url_base = "http://api.pachube.com/v2/feeds/"
  _feed_id = None
  _version = None
  ## the substance of our update - list of dictionaries with keys 'id' and 'current_value'
  _data = None
  ## the actual object we'll JSONify and send to the API endpoint
  _payload = None
  _opener = None

  def __init__(self, feed_id, apikey):
    self._version = "1.0.0"
    self._feed_id = feed_id
    self._opener = mechanize.build_opener()
    self._opener.addheaders = [('X-PachubeApiKey',apikey)]
    self._data = []
    self._payload = {}

  def addDatapoint(self,dp_id,dp_value):
    self._data.append({'id':dp_id, 'current_value':dp_value})

  def buildUpdate(self):
    self._payload['version'] = self._version
    self._payload['id'] = self._feed_id
    self._payload['datastreams'] = self._data

  def sendUpdate(self):
    url = self._url_base + self._feed_id + "?_method=put"
    try:
      self._opener.open(url,json.dumps(self._payload))
    except mechanize.HTTPError as e:
      print "An HTTP error occurred: %s " % e

# ===========================================================================
# Luxmeter CLASS
# ===========================================================================

class Luxmeter:
    i2c = None

    def __init__(self, address=0x39, debug=0, pause=0.41):
        self.i2c = Adafruit_I2C(address)
        self.address = address
        self.pause = pause
        self.debug = debug

        self.i2c.write8(0x80, 0x03)     # enable the device
        self.i2c.write8(0x81, 0x11)     # set gain = 16X and timing = 101 mSec
        time.sleep(self.pause)          # pause for a warm-up

    def readfull(self, reg=0x8C):
        """Reads visible + IR diode from the I2C device"""
        try:
            fullval = self.i2c.readU16(reg)
            newval = self.i2c.reverseByteOrder(fullval)
            if (self.debug):
                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, fullval & 0xFFFF, reg))
            return newval
        except IOError:
            print("Error accessing 0x%02X: Check your I2C address" % self.address)
            return -1

    def readIR(self, reg=0x8E):
        """Reads IR only diode from the I2C device"""
        try:
            IRval = self.i2c.readU16(reg)
            newIR = self.i2c.reverseByteOrder(IRval)
            if (self.debug):
                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, IRval & 0xFFFF, reg))
            return newIR
        except IOError:
            print("Error accessing 0x%02X: Check your I2C address" % self.address)
            return -1

    def readfullauto(self, reg=0x8c):
        """Reads visible + IR diode from the I2C device with auto ranging"""
        try:
            fullval = self.i2c.readU16(reg)
            newval = self.i2c.reverseByteOrder(fullval)
            if newval >= 37177:
                self.i2c.write8(0x81, 0x01)
                time.sleep(self.pause)
                fullval = self.i2c.readU16(reg)
                newval = self.i2c.reverseByteOrder(fullval)
            if (self.debug):
                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, fullval & 0xFFFF, reg))
            return newval
        except IOError:
            print("Error accessing 0x%02X: Check your I2C address" % self.address)
            return -1

    def readIRauto(self, reg=0x8e):
        """Reads IR diode from the I2C device with auto ranging"""
        try:
            IRval = self.i2c.readU16(reg)
            newIR = self.i2c.reverseByteOrder(IRval)
            if newIR >= 37177:
                self.i2c.write8(0x81, 0x01)     #   remove 16x gain
                time.sleep(self.pause)
                IRval = self.i2c.readU16(reg)
                newIR = self.i2c.reverseByteOrder(IRval)
            if (self.debug):
                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, IRval & 0xFFFF, reg))
            return newIR
        except IOError:
            print("Error accessing 0x%02X: Check your I2C address" % self.address)
            return -1


# ===========================================================================
# READING THE SENSOR
# ===========================================================================

def luxread(type, address = 0x39, debug = False, autorange = True):
    """Grabs a lux reading either with autoranging or without"""
    LuxSensor = Luxmeter(0x39, False)
    if autorange == True:
        ambient = LuxSensor.readfullauto()
        IR = LuxSensor.readIRauto()
    else:
        ambient = LuxSensor.readfull()
        IR = LuxSensor.readIR()

    if ambient == 0:  # in the dark you cant divide by 0 in the next calculation
        ambient = 0.0001  # so I set it to a small number

    ratio = (float) (IR / ambient)

    if ((ratio >= 0) & (ratio <= 0.52)):
        lux = (0.0315 * ambient) - (0.0593 * ambient * (ratio**1.4))
    elif (ratio <= 0.65):
        lux = (0.0229 * ambient) - (0.0291 * IR)
    elif (ratio <= 0.80):
        lux = (0.0157 * ambient) - (0.018 * IR)
    elif (ratio <= 1.3):
        lux = (0.00338 * ambient) - (0.0026 * IR)
    elif (ratio > 1.3):
        lux = 0

    #  I want to know the values for IR, ambient, and lux

    if (type==1):
        return ambient
    elif (type==2):
        return IR
    elif (type==3):
        return lux

# ===========================================================================
# MAKE DATA BUFFERS
# ===========================================================================

def getIRbuffer(size):
    """read IR sensor and print the data"""
    buffer=[]      # place to store multiple IR readings type==1

    # number of reads to save in the bufer
    for x in range(0,size):
        buffer.append(luxread(1))

    # calculate the average value within the buffer
    a = (sum(buffer) / len(buffer))

    # in case you want to get the data to the terminal
#   return("Lux: %.2f" % (a))
    return a

def getAmbientbuffer(size):
    """read ambient sensor value and print the data"""
    buffer=[] # place to store multiple Ambient readings type==2
    for x in range(0,size):
        buffer.append(luxread(2))

    a = (sum(buffer) / len(buffer))

    # in case you want to get the data to the terminal
#   return("Lux: %.2f" % (a))
    return a

def getLuxbuffer(size):
    """read Lux sensor make a buffer and print the data"""
    buffer=[]     # place to store multiple Lux readings type==3
    for x in range(0,size):
        buffer.append(luxread(3))

    a = int((sum(buffer) / len(buffer))) # convert to integer

    # in case you want to get the data to the terminal
#   return("Lux: %.2f" % (a))
    return a

# ===========================================================================
# UPLOAD THE DATA TO COSM
# ===========================================================================

# a startup service message
now = datetime.now()
print("Program started %s, logging to COSM, ctrl-C to end" % now)

# In the code below the buffer is the number of
# reads that will be averaged together

while True:
  try:
    # process the ambient sensor value
    amval= getAmbientbuffer(10)
    pfu = PachubeFeedUpdate(feed,key)
    pfu.addDatapoint('Ambient', amval)
    # finish up and submit the data
    pfu.buildUpdate()
    pfu.sendUpdate()

    # process the infrared sensor value
    irval= getIRbuffer(10)
    pfu = PachubeFeedUpdate(feed,key)
    pfu.addDatapoint('Infrared', irval)
    # finish up and submit the data
    pfu.buildUpdate()
    pfu.sendUpdate()

    # process the the lux sensor value
    luxval= getLuxbuffer(10)
    pfu = PachubeFeedUpdate(feed,key)
    pfu.addDatapoint('Lux', luxval)
    # finish up and submit the data
    pfu.buildUpdate()
    pfu.sendUpdate()

    # pause, remove for full speed!
    time.sleep(10)
  except (KeyboardInterrupt, SystemExit):
    raise
  except StandardError:
    print ('ERROR: StandardError')
csalty
 
Posts: 27
Joined: Sat Feb 23, 2013 7:32 pm

Re: TSL2561 and Raspberry Pi

by Static on Fri Mar 15, 2013 9:39 pm

Sorry I haven't posted in a bit.

I just updated my Adafruit_I2C to the most recent version.

Now, everything is broken.

I'm tracing things through the code, but it looks like it should be handling everything the same (There were a couple of small changes that I needed to make). The values I'm getting are just wrong, across the board. Temperature (two different sensors), pressure, light, all of 'em.
Static
 
Posts: 178
Joined: Thu Dec 23, 2010 5:21 pm

Re: TSL2561 and Raspberry Pi

by csalty on Mon Mar 18, 2013 3:32 pm

That stinks. Hope you can work everything out. Do you know what's different about their newer module?
csalty
 
Posts: 27
Joined: Sat Feb 23, 2013 7:32 pm

Re: TSL2561 and Raspberry Pi

by Static on Thu Mar 21, 2013 6:37 am

It doesn't look like there is anything there that would change things.
This morning (after the coffee) i'm going to pull the sensor pod back inside.
I'm in the process (Right now) of pulling my other Raspberry Pi.

I'll try swapping out components, and seeing if I can troubleshoot the issue.

From the coding side of things, it doesn't look like there should be a problem.
Static
 
Posts: 178
Joined: Thu Dec 23, 2010 5:21 pm

Re: TSL2561 and Raspberry Pi

by Static on Sat Mar 30, 2013 9:22 pm

Boy, was I wrong.

The new Adafruit_I2C.py seemed to be the culprit. It took me this long to try trading out functions, and getting the functionality back that I wanted. I'm not using the stock Adafruit_I2C.py. If other folks are having problems, I can post it up here.

An interesting side effect: Right now, it looks like the light levels are steady. I didn't pop the sensor outside until after noon, but things looked good this afternoon.
Static
 
Posts: 178
Joined: Thu Dec 23, 2010 5:21 pm

Re: TSL2561 and Raspberry Pi

by Static on Sun Mar 31, 2013 3:55 pm

I'm still getting the weird "vampire fang" pattern during peak light cycles. The value pegs, then rapidly (over minutes) drops down. Later in the day, the value rapidly climbs (again, over minutes) and then drops down.
Static
 
Posts: 178
Joined: Thu Dec 23, 2010 5:21 pm