forked from maxlklaxl/python-tsl2591
-
Notifications
You must be signed in to change notification settings - Fork 3
/
tsl2591.py
183 lines (158 loc) · 4.8 KB
/
tsl2591.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# tsl2591 lux sensor interface
import time
VISIBLE = 2
INFRARED = 1
FULLSPECTRUM = 0
ADDR = 0x29
READBIT = 0x01
COMMAND_BIT = 0xA0
CLEAR_BIT = 0x40
WORD_BIT = 0x20
BLOCK_BIT = 0x10
ENABLE_POWERON = 0x01
ENABLE_POWEROFF = 0x00
ENABLE_AEN = 0x02
ENABLE_AIEN = 0x10
CONTROL_RESET = 0x80
LUX_DF = 408.0
LUX_COEFB = 1.64
LUX_COEFC = 0.59
LUX_COEFD = 0.86
REGISTER_ENABLE = 0x00
REGISTER_CONTROL = 0x01
REGISTER_THRESHHOLDL_LOW = 0x02
REGISTER_THRESHHOLDL_HIGH = 0x03
REGISTER_THRESHHOLDH_LOW = 0x04
REGISTER_THRESHHOLDH_HIGH = 0x05
REGISTER_INTERRUPT = 0x06
REGISTER_CRC = 0x08
REGISTER_ID = 0x0A
REGISTER_CHAN0_LOW = 0x14
REGISTER_CHAN0_HIGH = 0x15
REGISTER_CHAN1_LOW = 0x16
REGISTER_CHAN1_HIGH = 0x17
INTEGRATIONTIME_100MS = 0x00
INTEGRATIONTIME_200MS = 0x01
INTEGRATIONTIME_300MS = 0x02
INTEGRATIONTIME_400MS = 0x03
INTEGRATIONTIME_500MS = 0x04
INTEGRATIONTIME_600MS = 0x05
GAIN_LOW = 0x00
GAIN_MED = 0x10
GAIN_HIGH = 0x20
GAIN_MAX = 0x30
def _bytes_to_int(data):
return data[0] + (data[1]<<8)
from machine import I2C, Pin
class SMBusEmulator:
__slots__ = ('i2c',)
def __init__(self, scl_pinno=5, sda_pinno=4):
self.i2c = I2C(scl=Pin(scl_pinno, Pin.IN),
sda=Pin(sda_pinno, Pin.IN))
def write_byte_data(self, addr, cmd, val):
buf = bytes([cmd, val])
self.i2c.writeto(addr, buf)
def read_word_data(self, addr, cmd):
assert cmd < 256
buf = bytes([cmd])
self.i2c.writeto(addr, buf)
data = self.i2c.readfrom(addr, 4)
return _bytes_to_int(data)
SENSOR_ADDRESS=0x29
class Tsl2591:
def __init__(
self,
sensor_id,
integration=INTEGRATIONTIME_100MS,
gain=GAIN_LOW
):
self.sensor_id = sensor_id
self.bus = SMBusEmulator()
self.integration_time = integration
self.gain = gain
self.set_timing(self.integration_time)
self.set_gain(self.gain)
self.disable()
def set_timing(self, integration):
self.enable()
self.integration_time = integration
self.bus.write_byte_data(
SENSOR_ADDRESS,
COMMAND_BIT | REGISTER_CONTROL,
self.integration_time | self.gain
)
self.disable()
def set_gain(self, gain):
self.enable()
self.gain = gain
self.bus.write_byte_data(
SENSOR_ADDRESS,
COMMAND_BIT | REGISTER_CONTROL,
self.integration_time | self.gain
)
self.disable()
def calculate_lux(self, full, ir):
if (full == 0xFFFF) | (ir == 0xFFFF):
return 0
case_integ = {
INTEGRATIONTIME_100MS: 100.,
INTEGRATIONTIME_200MS: 200.,
INTEGRATIONTIME_300MS: 300.,
INTEGRATIONTIME_400MS: 400.,
INTEGRATIONTIME_500MS: 500.,
INTEGRATIONTIME_600MS: 600.,
}
if self.integration_time in case_integ.keys():
atime = case_integ[self.integration_time]
else:
atime = 100.
case_gain = {
GAIN_LOW: 1.,
GAIN_MED: 25.,
GAIN_HIGH: 428.,
GAIN_MAX: 9876.,
}
if self.gain in case_gain.keys():
again = case_gain[self.gain]
else:
again = 1.
cpl = (atime * again) / LUX_DF
lux1 = (full - (LUX_COEFB * ir)) / cpl
lux2 = ((LUX_COEFC * full) - (LUX_COEFD * ir)) / cpl
return max([lux1, lux2])
def enable(self):
self.bus.write_byte_data(
SENSOR_ADDRESS,
COMMAND_BIT | REGISTER_ENABLE,
ENABLE_POWERON | ENABLE_AEN | ENABLE_AIEN
)
def disable(self):
self.bus.write_byte_data(
SENSOR_ADDRESS,
COMMAND_BIT | REGISTER_ENABLE,
ENABLE_POWEROFF
)
def get_full_luminosity(self):
self.enable()
time.sleep(0.120*self.integration_time+1)
full = self.bus.read_word_data(
SENSOR_ADDRESS, COMMAND_BIT | REGISTER_CHAN0_LOW
)
ir = self.bus.read_word_data(
SENSOR_ADDRESS, COMMAND_BIT | REGISTER_CHAN1_LOW
)
self.disable()
return full, ir
def get_luminosity(self, channel):
full, ir = self.get_full_luminosity()
if channel == FULLSPECTRUM:
return full
elif channel == INFRARED:
return ir
elif channel == VISIBLE:
return full - ir
else:
return 0
def sample(self):
full, ir = self.get_full_luminosity()
return self.calculate_lux(full, ir)