Skip to content

Commit 6b3357d

Browse files
committed
Add tsl2591 component
Fix compiler warning
1 parent 8abc06b commit 6b3357d

File tree

4 files changed

+929
-0
lines changed

4 files changed

+929
-0
lines changed

components/tsl2591/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CODEOWNERS = ["@wjcarpenter"]

components/tsl2591/sensor.py

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# Credit where due....
2+
# I put a certain amount of work into this, but a lot of ESPHome integration is
3+
# "look for other examples and see what they do" programming-by-example. Here are
4+
# things that helped me along with this:
5+
#
6+
# - I mined the existing tsl2561 integration for basic structural framing for both
7+
# the code and documentation.
8+
#
9+
# - I looked at the existing bme280 integration as an example of a single device
10+
# with multiple sensors.
11+
#
12+
# - Comments and code in this thread got me going with the Adafruit TSL2591 library
13+
# and prompted my desired to have tsl2591 as a standard component instead of a
14+
# custom/external component.
15+
#
16+
# - And, of course, the handy and available Adafruit TSL2591 library was very
17+
# helpful in understanding what the device is actually talking about.
18+
#
19+
# Here is the project that started me down the TSL2591 device trail in the first
20+
# place: https://hackaday.io/project/176690-the-water-watcher
21+
22+
import esphome.codegen as cg
23+
from esphome.components import i2c, sensor
24+
import esphome.config_validation as cv
25+
from esphome.const import (
26+
CONF_ACTUAL_GAIN,
27+
CONF_CALCULATED_LUX,
28+
CONF_DEVICE_FACTOR,
29+
CONF_FULL_SPECTRUM,
30+
CONF_GAIN,
31+
CONF_GLASS_ATTENUATION_FACTOR,
32+
CONF_ID,
33+
CONF_INFRARED,
34+
CONF_INTEGRATION_TIME,
35+
CONF_NAME,
36+
CONF_POWER_SAVE_MODE,
37+
CONF_VISIBLE,
38+
DEVICE_CLASS_ILLUMINANCE,
39+
ICON_BRIGHTNESS_6,
40+
STATE_CLASS_MEASUREMENT,
41+
UNIT_LUX,
42+
)
43+
44+
DEPENDENCIES = ["i2c"]
45+
46+
tsl2591_ns = cg.esphome_ns.namespace("tsl2591")
47+
48+
TSL2591IntegrationTime = tsl2591_ns.enum("TSL2591IntegrationTime")
49+
INTEGRATION_TIMES = {
50+
100: TSL2591IntegrationTime.TSL2591_INTEGRATION_TIME_100MS,
51+
200: TSL2591IntegrationTime.TSL2591_INTEGRATION_TIME_200MS,
52+
300: TSL2591IntegrationTime.TSL2591_INTEGRATION_TIME_300MS,
53+
400: TSL2591IntegrationTime.TSL2591_INTEGRATION_TIME_400MS,
54+
500: TSL2591IntegrationTime.TSL2591_INTEGRATION_TIME_500MS,
55+
600: TSL2591IntegrationTime.TSL2591_INTEGRATION_TIME_600MS,
56+
}
57+
58+
TSL2591ComponentGain = tsl2591_ns.enum("TSL2591ComponentGain")
59+
GAINS = {
60+
"1X": TSL2591ComponentGain.TSL2591_CGAIN_LOW,
61+
"LOW": TSL2591ComponentGain.TSL2591_CGAIN_LOW,
62+
"25X": TSL2591ComponentGain.TSL2591_CGAIN_MED,
63+
"MED": TSL2591ComponentGain.TSL2591_CGAIN_MED,
64+
"MEDIUM": TSL2591ComponentGain.TSL2591_CGAIN_MED,
65+
"400X": TSL2591ComponentGain.TSL2591_CGAIN_HIGH,
66+
"HIGH": TSL2591ComponentGain.TSL2591_CGAIN_HIGH,
67+
"9500X": TSL2591ComponentGain.TSL2591_CGAIN_MAX,
68+
"MAX": TSL2591ComponentGain.TSL2591_CGAIN_MAX,
69+
"MAXIMUM": TSL2591ComponentGain.TSL2591_CGAIN_MAX,
70+
"AUTO": TSL2591ComponentGain.TSL2591_CGAIN_AUTO,
71+
}
72+
73+
74+
def validate_integration_time(value):
75+
value = cv.positive_time_period_milliseconds(value).total_milliseconds
76+
return cv.enum(INTEGRATION_TIMES, int=True)(value)
77+
78+
79+
TSL2591Component = tsl2591_ns.class_(
80+
"TSL2591Component", cg.PollingComponent, i2c.I2CDevice
81+
)
82+
83+
CONFIG_SCHEMA = (
84+
cv.Schema(
85+
{
86+
cv.GenerateID(): cv.declare_id(TSL2591Component),
87+
cv.Optional(CONF_INFRARED): sensor.sensor_schema(
88+
icon=ICON_BRIGHTNESS_6,
89+
accuracy_decimals=0,
90+
state_class=STATE_CLASS_MEASUREMENT,
91+
),
92+
cv.Optional(CONF_VISIBLE): sensor.sensor_schema(
93+
icon=ICON_BRIGHTNESS_6,
94+
accuracy_decimals=0,
95+
state_class=STATE_CLASS_MEASUREMENT,
96+
),
97+
cv.Optional(CONF_FULL_SPECTRUM): sensor.sensor_schema(
98+
icon=ICON_BRIGHTNESS_6,
99+
accuracy_decimals=0,
100+
state_class=STATE_CLASS_MEASUREMENT,
101+
),
102+
cv.Optional(CONF_CALCULATED_LUX): sensor.sensor_schema(
103+
unit_of_measurement=UNIT_LUX,
104+
icon=ICON_BRIGHTNESS_6,
105+
accuracy_decimals=4,
106+
device_class=DEVICE_CLASS_ILLUMINANCE,
107+
state_class=STATE_CLASS_MEASUREMENT,
108+
),
109+
cv.Optional(CONF_ACTUAL_GAIN): sensor.sensor_schema(
110+
icon=ICON_BRIGHTNESS_6,
111+
accuracy_decimals=0,
112+
device_class=DEVICE_CLASS_ILLUMINANCE,
113+
state_class=STATE_CLASS_MEASUREMENT,
114+
),
115+
cv.Optional(
116+
CONF_INTEGRATION_TIME, default="100ms"
117+
): validate_integration_time,
118+
cv.Optional(CONF_NAME, default="TLS2591"): cv.string,
119+
cv.Optional(CONF_GAIN, default="AUTO"): cv.enum(GAINS, upper=True),
120+
cv.Optional(CONF_POWER_SAVE_MODE, default=True): cv.boolean,
121+
cv.Optional(CONF_DEVICE_FACTOR, default=53.0): cv.float_with_unit(
122+
"device_factor", "", True
123+
),
124+
cv.Optional(CONF_GLASS_ATTENUATION_FACTOR, default=7.7): cv.float_with_unit(
125+
"glass_attenuation_factor", "", True
126+
),
127+
}
128+
)
129+
.extend(cv.polling_component_schema("60s"))
130+
.extend(i2c.i2c_device_schema(0x29))
131+
)
132+
133+
134+
async def to_code(config):
135+
var = cg.new_Pvariable(config[CONF_ID])
136+
await cg.register_component(var, config)
137+
await i2c.register_i2c_device(var, config)
138+
139+
if CONF_FULL_SPECTRUM in config:
140+
conf = config[CONF_FULL_SPECTRUM]
141+
sens = await sensor.new_sensor(conf)
142+
cg.add(var.set_full_spectrum_sensor(sens))
143+
144+
if CONF_INFRARED in config:
145+
conf = config[CONF_INFRARED]
146+
sens = await sensor.new_sensor(conf)
147+
cg.add(var.set_infrared_sensor(sens))
148+
149+
if CONF_VISIBLE in config:
150+
conf = config[CONF_VISIBLE]
151+
sens = await sensor.new_sensor(conf)
152+
cg.add(var.set_visible_sensor(sens))
153+
154+
if CONF_CALCULATED_LUX in config:
155+
conf = config[CONF_CALCULATED_LUX]
156+
sens = await sensor.new_sensor(conf)
157+
cg.add(var.set_calculated_lux_sensor(sens))
158+
159+
if CONF_ACTUAL_GAIN in config:
160+
conf = config[CONF_ACTUAL_GAIN]
161+
sens = await sensor.new_sensor(conf)
162+
cg.add(var.set_actual_gain_sensor(sens))
163+
164+
cg.add(var.set_name(config[CONF_NAME]))
165+
cg.add(var.set_power_save_mode(config[CONF_POWER_SAVE_MODE]))
166+
cg.add(var.set_integration_time(config[CONF_INTEGRATION_TIME]))
167+
cg.add(var.set_gain(config[CONF_GAIN]))
168+
cg.add(
169+
var.set_device_and_glass_attenuation_factors(
170+
config[CONF_DEVICE_FACTOR], config[CONF_GLASS_ATTENUATION_FACTOR]
171+
)
172+
)

0 commit comments

Comments
 (0)