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

ltr390 light sensor reports very low UVI values and resolution settings not working #4380

Closed
plee3001 opened this issue Apr 2, 2023 · 10 comments · Fixed by esphome/esphome#6161

Comments

@plee3001
Copy link

plee3001 commented Apr 2, 2023

The problem

Issue 1: When using the ltr390 sensor component, it reports very low UVI values. For example, when under direct midday sun, when UVI of 7 or greater is expected, it would report UVI of less than 1.

Issue 2: When changing the resolution to something other than default, the raw outputs, als or uvs, do not scale with the resolution. Instead the calculated light lux (lx) output would change by factors of 2 even though it should stay more or less the same under the same lighting conditions.

Looking into the source file, I think I have found and fixed the issues. Attached is the modified .cpp file that seems to give reasonable values. I have no light measurement tool to verify.

ltr390.cpp.txt

The cause of issue 1 seems to be the interpretation of the ambiguous datasheet. The UVI Conversion Formula in the datasheet has no terms to compensate for gain and resolution settings. While on Figure 4.6, it implies that the Sensitivity of 2300 counts/UVI is tied to Gain 18x and Resolution 20-bit.

In my experiments, even under direct midday sun, the UV ADC output values are still a number of bits short of the max afforded by the ADC register at Gain 18x. So it is best to use Gain 18x for UV measurement all the time. In the .cpp file attached, it uses the user config gain setting for the ambient light measurement and uses 18x for UV measurement. The calculation of UVI is changed to include a factor ( 4 / INT ) to account for the different resolution settings.

The cause of issue 2 is that the user config resolution setting is never applied to the ltr390 chip. There are a few lines in the original source in setup() with a comment of "Set resolution". But the few lines end up not really changing anything. In the attached .cpp, it has been modified to actually write the user config resolution setting to the ltr390 chip.

Which version of ESPHome has the issue?

2022.12.8 is what I am using

What type of installation are you using?

pip

Which version of Home Assistant has the issue?

n/a, debug using esphome log

What platform are you using?

ESP8266

Board

d1 mini

Component causing the issue

ltr390

Example YAML snippet

i2c:
  scl: 5
  sda: 4

sensor:
  - platform: ltr390
    address: 0x53
    uv_index:
      name: ${esp_name} uv index
    uv:
      name: ${esp_name} uvs
    light:
      name: ${esp_name} alight
    ambient_light:
      name: ${esp_name} als
    resolution: 20
    update_interval: 10s

Anything in the logs that might be useful for us?

No response

Additional information

No response

@AussiSG
Copy link

AussiSG commented Apr 19, 2023

I can confirm aswell that the readings for this sensors are way off comparing the uv being put "on" to it ;)

image

@AussiSG
Copy link

AussiSG commented Apr 27, 2023

@OttoWinter
Any follow up on this issue ? Would be nice to see that the suggested fix be part of a next update

@AussiSG
Copy link

AussiSG commented May 9, 2023

or @jesserockz maybe you can have a little peak ?

@fran6120
Copy link

fran6120 commented Jun 1, 2023

In my case with the default settings, the light reading reaches a maximum of 52428.6 lux while BH1750 under the same conditions exceeds that value.

The UV Index reading shows absurd values, being minimum under direct sunlight and high when sunlight is not direct...

Using the modification mentioned here, adding the component as external does not seem to correct the problem.

For light readings, higher numbers are reached when configuring 20bit, but the lux value obtained is static.

UV Index values are still absurd

@plee3001
Copy link
Author

plee3001 commented Jun 2, 2023

"the light reading reaches a maximum of 52428.6 lux" - the formula is
lux = als x (0.6 x wfac) / (gain x int)
Substitute als = 2^18 (18-bit resolution)= 262144 max;
wfac = 1; x3 gain; 18-bit -> int = 1
You get lux = 262144 x 0.6 / (3 x 1) = 52428.6, so that is as expected.
You can allow for higher lux value (up to 157286.4 lux) by changing the gain config to x1.

"The UV Index reading shows absurd values, being minimum under direct sunlight and high when sunlight is not direct" - I have not seen that. So that is a different issue and stuff I mentioned here is not going to address that issue.

BTW, als and uv are values directly from the sensor, while lux and UVI are calculated in the code of the esphome component.

Until the couple issues are fixed in the esphome repository, here are two possible workarounds:

workaround 1:
Using the existing esphome component, the resolution config does not work, so leave that at 18-bit default.
The UVI calculation has dependency on the resolution config and gain config, so calculate you own (using lambda or template) using this formula:
UVI = ( uv x wfac / 2300 ) x 4 x ( 18 / gain )
The first part is the original formula. The x 4 term is to adjust for being at default 18-bit resolution instead of 20-bit as intended in original formula. The x 18 / gain term is adjust for actual gain configured vs x18 as intended in original formula

workaround 2:
Use the esphome external components method to override the ltr390 component.
https://esphome.io/components/external_components.html
Set up the external component by downloading the ltr390 files from the esphome github, you should get 4 files in the ltr390 directory. Overwrite the ltr390.cpp file with the file I attached here.
ltr390.cpp.txt
(you have to rename the attached file to remove the ".txt" because this site would not let me attach with ".cpp" extension.)

I have been using this file for the last two months and it has been giving me outputs that are reasonable relative to expectation, but I have no other light measurement equipment to verify. This file has additional changes to the one in the opening post. Other than a bunch of superfluous changes relating to code formatting and commenting, the one additional functional change is that the data sensing is only enabled during each refresh interval. The original code has the data sensing enabled all the time, where the chip would do an automatic data sensing after each read. With my limited testing, the data acquired would then sit in the receive register and would be read out on the next esphome refresh interval, resulting in the data always being one refresh interval delayed.

@AussiSG
Copy link

AussiSG commented Aug 11, 2023

Any follow up on this @jesserockz would love to see this working in a normal way.... ?

@plee3001 I tried to get 'workaround 2' working but it seems that i'm not getting the LTR390 files locally in my ESPhome directory and than under the specific module...

@plee3001
Copy link
Author

plee3001 commented Aug 15, 2023

@AussiSG
following the instructions in https://esphome.io/components/external_components.html
specify the source to be "local", with something like this as part of your .yaml file:

external_components:
  # use all components from a local folder
  - source:
      type: local
      path: my_components

Create a directory in your "esphome" directory (where the .yaml files are) with a name that matches the path entry above ("my_components" in this example).
Create another directory under the directory created above with the name "ltr390".
Put 4 files into the "ltr390" directory: the renamed ltr390.cpp file from one post above and also "__init__.py", "ltr390.h", "sensor.py" from:
https://github.com/esphome/esphome/tree/dev/esphome/components/ltr390
(make sure you get those files in raw text form).

@sjtrny
Copy link

sjtrny commented Feb 1, 2024

Hi @plee3001, I submitted the original code for this component. Thank you for digging into this issue - unfortunately I have only had time now to look at it. To be honest when I wrote this component I was referencing the Adafruit implementation without thinking too hard about whether it was correct or not.

I'll put together a PR with the changes soon! See my notes on the issues below.

Issue 2

Absolutely correct, the code doesn't set resolution to the configured value.

Issue 1

I think you're right that the conversion rate of 2300 counts/UVI is only for the specific combination of gain and resolution. However I found that after fixing issue 2, that the formula in the datasheet is correct for that specific combination of gain and resolution. In other words we don't need to multiply by 4.

After some googling I found https://github.com/torvalds/linux/blob/master/drivers/iio/light/ltr390.c, where @ArchUsr64 has provided a formula that assumes linear scaling of sensitivity, which is:

SENSITIVITY = 2300 * (GAIN/18) * (INT_TIME/400)

where GAIN is one of 1, 3, 6, 9, 18 and INT_TIME is one of 25, 50, 100, 200, 400}.

For example the defaults of X3 (3) gain and 18 bit resolution (100ms)
SENSITIVITY = 2300 * 3/18 * 100/400 = 95.83.

I have tested this value to confirm and cross referenced live UVI data from https://www.arpansa.gov.au/our-services/monitoring/ultraviolet-radiation-monitoring/ultraviolet-radiation-index. It's not absolutely perfect since reported UVI values are slightly different between combinations of gain and resolution. But it is probably as good as we are going to get until someone can provide calibration points.

@plee3001
Copy link
Author

plee3001 commented Feb 1, 2024

Thanks for putting up this component in the first place.

I do have a suggestion. Leave the UV detection to x18 gain all the time. From the testing I have done, the UV reading would never max out the input register with a number of bits to spare, so it is nice to just have the max precision regardless of the ambient light gain setting. (The ambient light detection do max out the input register easily under direct sun, so one may want to adjust the gain setting for that to tailor to one's application).

@sjtrny
Copy link

sjtrny commented Feb 2, 2024

I'm not convinced that "it doesn't use up all the bits" is a strong reason to lock the UV sensor to that gain setting. It might be that you can max the sensor counts if using a strong artificial UV source.

I think the better solution is to:

  • Set the default to X18 and 20-bit
  • Add a note to the documentation saying that "We recommend using the defaults when UVI is required since the data sheet only provides accurate conversion formula for this combination. The UVI value is linearly scaled from this reference point when using other combinations of gain and resolution, which may be slightly inaccurate."

I think if there's interest in supporting different gain/resolution for ALS/UV sensors this should be put into a feature request PR.

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

Successfully merging a pull request may close this issue.

4 participants