Pico code runs from Thony but will not run on battery or USB power

Mostly as a way to learn Python I have combined a PiicoDev Air Quality Sensor ENS160 with an OLED SSD1306. I cobbled together code from the demo offerings and got it running on a Pico 2 on a PiicoDev LiPo expansion board. I then thought I could do the temp and humidity compensation by adding a DHT22 to the setup and that worked as well.
That is, it all works when running from Thony.
However, when I name the code main.py and try to run from a LiPo battery or USB power without Thony, nothing appears on the OLED so it appears not to be running but there are no errors.

I have narrowed the issue down to one single line in the code.
If this line is commented out it runs from battery. If it is there it will not run from battery.
It is the first line after While True. THsensor.measure()
Can anyone suggest a reason why this line would prevent the code running properly from battery while there is no problem when running from Thony?
I have checked the 3.3V out and it is 3.28V whether powered from usb or battery.
I found a suggestion to reduce the I2C frequency but that did nothing.
I am very new to this and I have run out of ideas.
Thanks
Ian

# Read air quality metrics from the PiicoDev Air Quality Sensor ENS160 compensated for temp and hum from a DHT22
# Shows three metrics: AQI, TVOC and eCO2

from PiicoDev_ENS160 import PiicoDev_ENS160 # import the device driver
from PiicoDev_Unified import sleep_ms       # a cross-platform sleep function
from PiicoDev_SSD1306 import *
from machine import Pin
from time import sleep
import dht


THsensor = dht.DHT22(Pin(22)) # Initialise DHT22 Temp and Hum sensor

sensor = PiicoDev_ENS160()   # Initialise the ENS160 air quality module

display = create_PiicoDev_SSD1306() #initialise the OLED display

while True:
    
    #THsensor.measure()  #This line works from Thony but nothing appears on the OLED when run from battery or USB without Thony

    temp = THsensor.temperature()
    hum = THsensor.humidity()
    
    sensor.temperature = 25    # temporarily set as not being read  # [degC] Apply temp compensation value read from DHT22 to ENS160
    sensor.humidity = 50       # temporarily set as not being read  # [%RH]  Apply hum compensation value read from DHT22 to ENS160
    
    aqi = sensor.aqi         #    
    tvoc = sensor.tvoc       # Read from the air quality sensor
    eco2 = sensor.eco2       #
    
    display.fill(0)          #clear the OLED by filling with blackness
    display.text(('AQI :'+ str(aqi.value) + " "+str(aqi.rating)), 0,0, 1)
    display.text(('TVOC:' + str(tvoc) + ' ppb'), 0,10, 1)
    display.text(('eCO2:' + str(eco2.value) + ' ppm'), 0,20, 1)
    display.text(("    :" + str(eco2.rating)), 0,30, 1)
    display.text(("T= "+ str(temp) + " H= "+ str(hum) +"%"), 0,45, 1)
    display.text((sensor.operation), 0,56, 1)
    display.show()          #write to the OLED display
    
    sleep_ms(2000)
1 Like

Hi Ian,
I have experienced a very similar thing, all works in thonny but when connected by battery nothing, I thought it might have been some sort of corruption to the pico flash but remember now that it was when I started to modify a code myself. I am very intersted in the cause of this!

1 Like

Hi Nick,
The offending line THsensor.measure() is the line that reads the DHT22 temp and humidity sensor. It’s supply voltage range is unfortunately different according to where you look from 3.5 to 5.5 volts to 3 to 6 volts so the 3.3 V out from the Pico might be under the minimum but I’m pretty sure that is not the problem it as it won’t run with the same USB connection as Thonny uses.
This issue is mentioned a bit on the net but none of the suggested solutions did anything for me.
Ian

1 Like

Hi Ian and Nicholas,

The DHT22’s datssheet mentions a requirement of 1s before anything is sent to the device after it powering on, adding a delay between the import and initialising the device should solve the issue.

Hi Liam,
Thanks for the suggestion. I added a 1500 ms sleep after the import and before the initialisation as you suggested but it has made no difference. The code runs from Thonny but not from battery or USB power with Thonny closed down. I believe the DHT22 can only be read every 2 seconds so I had allowed for that in the while loop.
Thanks for trying.
Which data sheet did you see?
I looked at https://cdn.sparkfun.com/assets/f/7/d/9/c/DHT22.pdf
It says the minimum supply is 3.3V but others say 3.5 V
Ian

Give the sensor and the board a little time to power up before interacting with the DHT22:


sleep(2)  # Let peripherals stabilize for 2 seconds


Put this near the top, before the while True: loop. It can go right after your initializations.

Thanks ahsrab but I have tried putting a 2 second delay just before the loop and it did not help.

I have now pared down the code to just what is necessary to see the problem.

from machine import Pin
import dht 
from PiicoDev_Unified import sleep_ms
from PiicoDev_SSD1306 import *

#i2c = I2C(0, sda=machine.Pin(8), scl=machine.Pin(9), freq=200000) I tried this but it did not help (lowering I2C frequency to 200000)

sensor = dht.DHT22(Pin(22))

display = create_PiicoDev_SSD1306() #initialise the OLED display

display.fill(0)
display.text(("test1"), 0,20, 1) #display on OLED to prove it is initialised and ready before the measurement loop.
display.show()
sleep_ms(2000)  #This was suggested but has not helped
while True:
    sleep_ms(2000)
    display.text(("test2"), 0,30, 1)  
    display.show()
    sleep_ms(2000)      # just so you can see "test2" for 2 seconds. It stops after this line.
    sensor.measure()    # this is the line that causes the problem. If commented out the loop runs. If not it fails here.
    temp = sensor.temperature()
    hum = sensor.humidity()
    display.fill(0)
    display.text(("T= "+ str(temp) + " H= "+ str(hum) +"%"), 0,45, 1)
    display.show()

Test1 and Test2 are displayed whether the sensor.measure() line is in or out so that shows that the display is ready. Adding a sleep_ms(2000) before the while True: loop made no difference.

Ian

Hey @Ian100768,

Since you’ve narrowed down the issue to one line, could you alter that line to the following?

try:
    sensor.measure()    # this is the line that causes the problem. If commented out the loop runs. If not it fails here.
except Exception as e:
    print('measurement failed', str(e))     
    continue

This should print the exception that causes the try to fail.

Hi Zach. I was about to try your suggestion when I realised that to print I have to be connected to Thonny and that is when it works so the exception will not occur.
I wonder if I can get it to display on the OLED screen? I’ll try.
Thanks for the idea.

Zach,
I managed to get the error displayed on the OLED while running on battery.
It says “checksum error”.
Interestingly, when the code continues after the exception data from the DHT22 is displayed.
I’m not sure where to go from here.
Ian

Hi again,
Made a bit more progress. I have discovered that it is only the first attempted reading of the DHT22 that fails with a checksum error. All subsequent readings work.
So the question is do I just ignore the first reading and let the try: except continue handle it or is there actually a reason this error only occurs when Thonny is not present? And is there a way to fix it properly?
I have tried adding delays up to 10 seconds between the sensor initialisation and the first attempted reading but delays do not work.
Thanks again Zach.
Ian

ps. now it is on battery I put it outside. Left for a while and it is showing its minimum readings of 0 ppb VOC and 400 ppm eCO2. Interesting as the Cape Grim C02 readings are sitting about 421 ppm CO2 at the moment. I do live in the foothills of the Snowy Mountains but the air is not that good! However I am blown out at how using the toaster wrecks the indoor air quality according to this device!

I don’t fully understand your problem but when I am dealing with problems like this log to a file instead of print to screen. (Or as well as)
I have an include file with all my logging stuff in it. So when I start a new project the first thing in is debug.py. Then all my debug output statements are surrounded by If debug >=2 or what ever. That way when all your problems are solved you just set the variable debug=0 and all you debug statements can stay in the code and don’t weigh it down.
So then, when you are running headless and things go wrong you can check out the log file and see where it failed. You just have to watch out for running out of space in your file system when the log file grows to large.
David

1 Like

Hi Ian
I have looked at your problem and share your frustration that there seems to be no logical explanation. The dht library is built into MicroPython so when running on battery the import would be from the onboard MicroPython. When running under Thonny I am wondering if the dht library is imported locally and this version works without error. If so the solution could be to upgrade to the latest MicroPython release.

1 Like

Hi Fractal,
Yes, these unsolved mysteries are frustrating. I have searched fairly hard and found no explanation. At the moment I am using the Try: Except Continue method to get around the initial reading that gets a checksum error as suggested by Zach earlier in this thread. All readings after that work properly. The Continue statement only works on the first iteration of the loop so it is perfect here as it continues on as normal after the initial error.
I have recently updated all my Picos to the latest MicroPython release.
Ian

1 Like