adafruit / Adafruit_CircuitPython_LC709203F

Library for I2C LC709203F battery status and fuel gauge
MIT License
4 stars 10 forks source link

OSError: [Errno 116] ETIMEDOUT #26

Closed DJDevon3 closed 8 months ago

DJDevon3 commented 8 months ago
Adafruit CircuitPython 9.0.0 on 2024-03-19; Adafruit Feather ESP32S3 4MB Flash 2MB PSRAM with ESP32S3
Board ID:adafruit_feather_esp32s3_4mbflash_2mbpsram

Bundle Version: adafruit-circuitpython-bundle-9.x-mpy-20240307

This is on the older version of the feather with the lc709203f chip and not the max chip. I use battery voltage to display a battery charge status icon on a TFT.

i2c = board.I2C()
battery_monitor = LC709203F(board.I2C())  # line 145
Traceback (most recent call last):
  File "code.py", line 145, in <module>
  File "adafruit_lc709203f.py", line 147, in __init__
  File "adafruit_lc709203f.py", line 203, in battery_profile
  File "adafruit_lc709203f.py", line 301, in _write_word
OSError: [Errno 116] ETIMEDOUT

This happens randomly at script startup. I have quite a large script where splash screen loading time can take up to 30 seconds. The randomness that this fails at is still an issue. It's random, or seems random.

dhalbert commented 8 months ago

The LC709203F goes to sleep after a short while if it is not being used. It is possible to wake it up by retrying. See this sample script: https://github.com/adafruit/circuitpython/issues/6311#issuecomment-1295812087.

If this works for you we can add this to the simpletest and write it up in the Guide.

There was a significant problem with I2C in CircuitPython 8.x.x on ESP32-S3, due to bugs in the underlying ESP-IDF SDK we are using. That was fixed in 9.0.0 when we updated to a newer version of the SDK. So that is not this problem.

DJDevon3 commented 8 months ago

I have gotten it to fail again

USB Sense:  True
LC709203F Error: 
 [Errno 116] ETIMEDOUT

However for whatever reason by the time it gets to the part in the script that calls it again it does work.

Here's the Feather Weather MQTT Touch project I'm using it in. The I2C doesn't prevent the first error By the time it loads line 688 everything seems peachy. The cell voltage and battery gauge icon work. 🤷

DJDevon3 commented 8 months ago

Nevermind, just crashed again.

def hack_for_i2c_issue():
    """LC709203F Battery Monitor Workaround"""
    i2c = board.I2C()
    while not i2c.try_lock():
        pass
    running = True
    try:
        while running:
            """
            print(
                "I2C addresses found:",
                [hex(device_address) for device_address in i2c.scan()],
            )
            """
            running = False
        return i2c
    finally:  # unlock the i2c bus when ctrl-c'ing out of the loop
        i2c.unlock()

# LC709203F Battery Monitor
# https://github.com/adafruit/Adafruit_CircuitPython_LC709203F/blob/main/adafruit_lc709203f.py
i2c = hack_for_i2c_issue()
battery_monitor = LC709203F(i2c)  # This is line 163 where it fails
# battery_monitor.pack_size = PackSize.MAH3000
battery_monitor.thermistor_bconstant = 3950
battery_monitor.thermistor_enable = True
Traceback (most recent call last):
  File "code.py", line 163, in <module>
  File "adafruit_lc709203f.py", line 147, in __init__
  File "adafruit_lc709203f.py", line 203, in battery_profile
  File "adafruit_lc709203f.py", line 301, in _write_word
OSError: [Errno 116] ETIMEDOUT

I need to put that thing in a try/except continue loop or something.

DJDevon3 commented 8 months ago

See, what had happened was... user error, again.

def hack_for_i2c_issue():
    """LC709203F Battery Monitor Workaround"""
    i2c2 = board.I2C()
    while not i2c2.try_lock():
        pass
    running = True
    try:
        while running:
            """
            print(
                "I2C addresses found:",
                [hex(device_address) for device_address in i2c.scan()],
            )
            """
            running = False
        return i2c2
    finally:  # unlock the i2c bus when ctrl-c'ing out of the loop
        i2c2.unlock()

# LC709203F Battery Monitor
i2c2 = hack_for_i2c_issue()
try:
    battery_monitor = LC709203F(i2c2)
except OSError as e:
    print("LC709203F: {e}")
# battery_monitor.pack_size = PackSize.MAH3000
battery_monitor.thermistor_bconstant = 3950
battery_monitor.thermistor_enable = True

# Initialize BME280 Sensor
i2c = board.STEMMA_I2C()  # uses board.SCL and board.SDA
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)

I was initializing the i2c bus twice. Just renamed the call to i2c2 and now everything is happy. In my defense my script is literally 1500 lines long... but they are right next to each other. 🤦 Sorry!

DJDevon3 commented 8 months ago

Closed this too soon. It does still happen. Probably because the I2C buses are the same just with different methods. I've started doing this instead.

i2c = board.I2C()
try:
    battery_monitor = LC709203F(i2c)
except OSError:
    supervisor.reload()

If the battery monitor cannot setup the thermistor simply reload until it does.