adafruit / Adafruit_CircuitPython_SCD4X

CircuitPython/Python driver for Sensirion SCD40 & SCD41
MIT License
20 stars 10 forks source link

Data_Ready is rarely ready (True) #17

Open tyeth opened 1 year ago

tyeth commented 1 year ago

I'm running this code on an adafruit esp32s2 reverse tft feather, with the scd4x connected (plus an SEN5x but it will gracefully accept not having one (hopefully). Code needs an adafruit io username + key and wifi, plus the SCD40/SCD41/SCD42. https://github.com/good-enough-technology/Good-Enough_Air-Quality-Device_CO2-SCD4x_PM-SEN5x_CircuitPython

The symptom is that when I was calling if scd4x_device.data_ready: after sleeping for 30seconds it was false, but very often false, so my code wouldn't read the metrics that iteration. I never get this issue with the sen5x on same bus. When bug detecting I set it to check in a loop, with time.sleep 0.1, and it took between under a second to over 3seconds to become scd4x_device.data_ready == True. That's not expected behaviour according to my experience with other libraries for this sensor (arduino etc). I have the i2c bus initialised manually (instead of board.I2C) so I can set the frequency, to avoid the esp32s2 100kHz timing bug, but no noticable diference. Using Circuitpython 8.1.0-beta 2 (maybe, but the one with gifio), and now 8.2.0 beta 1.

My understanding from arduino land was data_ready meant new readings available for the read_measurements type function. This library doesn't have such a beastie so the meaning is unclear👹 Is it the same, should I wait until data_ready to read scd4x_device.co2? If so, then the sensor is meant to be comfortably pollable at 1Hz so it shouldnt take longer than that for data ready to become truthy. I'll try to get some more exact bug report / reproduction steps / a video.

KeithTheEE commented 1 year ago

When you sleep for 30 seconds, do you power down the i2c bus, or do you keep it powered? Going of the good enough air quality device code, I'm guessing the i2c line gets powered down?

If that's the case there's a few things--Unless you're using single shot measurement, the co2 sensor will be inaccurate for a period of time.

The above question was answered via discord chat: No power is not removed from the sensor during any sleep period and a second start_periodic_measurement is not sent, so the sensor should be sampling and we don't have to worry about the weird edge conditions of startup co2 measurement or single shot co2 measurement.

Ok so roughly speaking you have two sections in the linked code where you call if scd4x_device.data_ready:.

In the first one is right after initialization and you only wait 1 second: I think you need to wait 5 seconds before the CO2 measurement is ready to go.

The second one is in the main loop, and the max time it could rest between the last attempted measurement in start up and that call is ~1.1 seconds + code execution time. When looping through that loop it looks like it normally has even less time to rest so it would be not ready most of the time.

Adjusting the demo code for this sensor to look like this:


scd4x.start_periodic_measurement()
print("Waiting for first measurement....")

old_time = time.monotonic_ns()

while True:
    if scd4x.data_ready:
        print((time.monotonic_ns()-old_time)/10**9)
        old_time = time.monotonic_ns()
        print("CO2: %d ppm" % scd4x.CO2)
        print("Temperature: %0.1f *C" % scd4x.temperature)
        print("Humidity: %0.1f %%" % scd4x.relative_humidity)
        print()
    time.sleep(.1)

in my setup, it shows a time between loops of, 4.71487 seconds which is pretty much within reason for a 5 second refresh rate

Adjusting the time.sleep() time to times greater than 5 seconds yields that sleep time + some change for code execution (time.sleep(6) yields a consistent 6.017 delay, however I have not yet run this for more than a couple of minutes.)

So at sampling periods shorter than 5 seconds you're going to run into a lot of data not yet ready issues.

The part that's throwing me is this,

The symptom is that when I was calling if scd4x_device.data_ready: after sleeping for 30seconds it was false,

Was the sensor initialized and set to start_periodic_measurement before those 30 seconds began? Does your sensor work with the example code under the Readme for this sensor?