Skip to content

_compute_lux can fail with an unset variable error #10

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

Closed
dhalbert opened this issue Dec 22, 2017 · 7 comments
Closed

_compute_lux can fail with an unset variable error #10

dhalbert opened this issue Dec 22, 2017 · 7 comments

Comments

@dhalbert
Copy link
Contributor

See this forum post: https://forums.adafruit.com/viewtopic.php?f=60&t=128396

The chain of if statements in _compute_lux() can fail to set lux if ratio <= 0 or possibly if somehow a value slips between the comparisons (might depend on floating point issues).

    def _compute_lux(self):
        """Based on datasheet for FN package."""
        ch0, ch1 = self.luminosity
        if ch0 == 0:
            return None
        if ch0 > _CLIP_THRESHOLD[self.integration_time]:
            return None
        if ch1 > _CLIP_THRESHOLD[self.integration_time]:
            return None
        ratio = ch1 / ch0
        if ratio > 0 and ratio <= 0.50:
            lux = 0.0304 * ch0 - 0.062 * ch0 * ratio**1.4
        elif ratio > 0.50 and ratio <= 0.61:
            lux = 0.0224 * ch0 - 0.031 * ch1
        elif ratio > 0.61 and ratio <= 0.80:
            lux = 0.0128 * ch0 - 0.0153 * ch1
        elif ratio > 0.80 and ratio <= 1.30:
            lux = 0.00146 * ch0 - 0.00112 * ch1
        elif ratio > 1.30:
            lux = 0
        # Pretty sure the floating point math formula on pg. 23 of datasheet
        # is based on 16x gain and 402ms integration time. Need to scale
        # result for other settings.
        # Scale for gain.
        lux *= _GAIN_SCALE[self.gain]
        # Scale for integration time.
        lux *= _TIME_SCALE[self.integration_time]
        return lux

The extra comparisons are redundant and could be rewritten as:

        if ratio > 0 and ratio <= 0.50:
            lux = 0.0304 * ch0 - 0.062 * ch0 * ratio**1.4
        elif ratio <= 0.61:
            lux = 0.0224 * ch0 - 0.031 * ch1
        elif ratio <= 0.80:
            lux = 0.0128 * ch0 - 0.0153 * ch1
        elif ratio <= 1.30:
            lux = 0.00146 * ch0 - 0.00112 * ch1
        else:
            lux = 0

I don't know if ratio can end up <= 0, but that case should be checked for as well, and either None returned or maybe an error thrown. (I don't know about this sensor or have one to test.)

@jerryneedell
Copy link
Contributor

jerryneedell commented Dec 22, 2017

I did some testing with this sensor and I found that if I mishandle it, (touch the pins), it goes into it's "disabled" state. I can bring it back by entering
tsl.enabled=True

when disabled, it returns (0,0) for the tsl.luminosity reading but in one case, I got it to return ( 1, 0) which would result in the error message reported since ch0 !=0 but ch1=0 so ch1/ch0 = 0 and fails all the tests.

Perhaps the driver needs to check for tsl.enabled == False and if so, re-enable it or throw an error.

 >>> tsl.broadband
97
>>> ch0,ch1=tsl.luminosity
>>> ch0
97
>>> ch1
25
>>> ch1/ch0
0.2577319
>>> tsl.broadband
93
>>> tsl.broadband
93
>>> tsl.broadband
93

picked up sensor here - likely touched pins

>>> tsl.broadband
1
>>> tsl.luminosity
(1, 0)
>>> tsl.luminosity
(0, 0)
>>> tsl.enabled
False
>>> tsl.enabled=True
>>> tsl.enabled
True
>>> tsl.luminosity
(107, 26)
>>> tsl.luminosity
(25, 8)
>>> tsl.luminosity
(9, 4)

touched pins again

>>> tsl.luminosity
(0, 0)
>>> tsl.enabled

@jerryneedell
Copy link
Contributor

I am finding the sensor to be very sensitive to handling - it will go disabled sometimes just by handling the jumper wires. I may not have great connections but it is interesting that it goes into this "disabled" state. As before, it recovers if re-enabled. Time to look at the data sheet!

@jerryneedell
Copy link
Contributor

Most likely, I just have a loose VCC connection so it power cycles the sensor and it comes up "disabled". but this does suggest that some checks would be helpful and that it is possible to get a reading with CH1=0 but CH0 non-zero thus triggering the reported error.

@jerryneedell
Copy link
Contributor

according to the data sheet, it powers up with the "power" bits in the control register set to 0 (i.e. disabled) enabling it just turns on the power bits and it starts operating with default settings. If a user has reconfigured the settings, a power cycle will lose the settings, so I think the driver should just throw an error or return None if it detects the sensor disabled rather than automatically re-enabling it.

@jerryneedell
Copy link
Contributor

jerryneedell commented Dec 22, 2017

aha! I just got it to return (1,0) whithout actually disabling so I think the disable question is another matter.
I just put it in a black box and got (1,0) which would trigger the error - but it recovered when I removed the box;

>>> tsl.luminosity
(45, 10)
>>> tsl.luminosity
(3, 1)
>>> tsl.luminosity
(1, 0)
>>> tsl.luminosity
(1, 0)
>>> tsl.luminosity
(1, 0)
>>> tsl.luminosity
(105, 20)
>>> tsl.luminosity
(7, 2)
>>> tsl.luminosity
(5, 2)
>>> tsl.luminosity
(6, 2)

@jerryneedell
Copy link
Contributor

jerryneedell commented Dec 22, 2017

triggered the error by covering the sensor with a box after the first reading. Removed the box for the third reading.

>>> tsl.lux
54.35902
>>> tsl.lux
Traceback (most recent call last):
  File "<stdin>", in <module>
  File "/lib/adafruit_tsl2561.py", in lux
  File "/lib/adafruit_tsl2561.py", in _compute_lux
NameError: local variable referenced before assignment
>>> tsl.lux
54.35902
>>> 

@caternuson
Copy link
Collaborator

Nice work. This PR fixes it:
#11

ratio < 0 is not possible, values are unsigned.

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

3 participants