Pico W Micro Python for SHT30 Temp/Humidity HELP!

RP2040 based microcontroller boards running MicroPython.
Target audience: MicroPython users with an RP2040 boards.
This does not include conventional Linux-based Raspberry Pi boards.
Rissy
Posts: 116
Joined: Sun Aug 14, 2022 8:15 am

Re: Pico W Micro Python for SHT30 Temp/Humidity HELP!

Post by Rissy » Mon Nov 21, 2022 6:19 pm

Well, now that it's been raining quite heavily during the past 16hrs or so, it was inevitable that my SHT30 device would eventually fail because of it. It seems actually that it's failed on quite a few occassions, and it seems that my program is not as hardy against this as I'd thought. I now have a string of errors in my errorlog.txt file i'd like to share with you all.

Errorlog.txt file contents since last post:

Code: Select all

MQTT Error: [Errno 113] EHOSTUNREACH
MQTT Error: [Errno 113] EHOSTUNREACH
MQTT Error: [Errno 107] ENOTCONN
SHT Error: Bus error
SHT Error: Bus error
SHT Error: CRC error
SHT Error: CRC error
SHT Error: Bus error
SHT Error: CRC error
SHT Error: CRC error
SHT Error: CRC error
SHT Error: CRC error
SHT Error: CRC error
SHT Error: CRC error
SHT Error: CRC error
SHT Error: CRC error
SHT Error: CRC error
SHT Error: CRC error
SHT Error: Bus error
This was my program at the time of these errors:

Code: Select all

#Necessary library imports for this code to function
from secrets import SSID
from secrets import PASSWORD
from secrets import IP
from secrets import IP_mask
from secrets import IP_gateway
from secrets import IP_DNS
from secrets import MQTTSERVE
from umqtt.simple import MQTTClient
import time
import network
import ubinascii
import socket
from machine import I2C, Pin, #wdt
import sht30
from sht30 import SHT30
from sht30 import SHT30Error

led = machine.Pin("LED", machine.Pin.OUT)

#initialise LED to OFF
led.off()

# def appendfile(message, error):
#     file=open("errorlog.txt","a")
#     errorstring=str(error)
#     file.write(message)
#     file.write(errorstring)
#     file.write("\n")
#     file.close()
    #file.flush()
    
def appendfile(message, error):
   with open('errorlog.txt', 'a') as file:
       file.write(message)
       errorstring=str(error)
       file.write(errorstring)
       file.write('\n')
       file.close()

def sht_error(ex):
    print("something went wrong reading the SHT-30!")
    print('Error:', ex)
    message = 'SHT Error: '
    appendfile(message, ex) #message, error
    
#Define the interface of the SHT30 Temp/Humidity sensor with the Pico W
i2c=I2C(0, sda=Pin(4), scl=Pin(5), freq=5000)
sht=sht30.SHT30(i2c=i2c, i2c_address=68)

def readsensor():
    global temperature
    global humidity
    try:
        sensor = sht.measure()
    except SHT30Error as ex:
        #print(ex)
        sht_error(ex)
        try:
            print("resetting SHT30")
            restartsensor = SHT30(i2c)
            time.sleep(1)
            restartsensor.reset()
            time.sleep(2)
            print("SHT30 reset")
            sensor = sht.measure()
        except:# SHT30Error as ex:
            #sht_error(ex)
            print("rebooting Pico W")
            time.sleep(10)
            machine.reset()
    temperature, humidity = sensor

#wdt = wdt(timeout= 8000)
readsensor()
#wdt.feed()
#print("woof!...good boy!")
print('SHT Temperature: {:3.1f}ºC'.format(temperature))
print('SHT Humidity: {:3.1f}%'.format(humidity))

#Define the onboard Pico Temperature sensor and necessary conversion factor
sensor_temp = machine.ADC(4)
conversion_factor = 3.3 / (65535)

#Configure this Pico W for a static IP address on router using the following
UseStaticIP = True
IP = IP
IP_mask = IP_mask
IP_gateway = IP_gateway
IP_DNS = IP_DNS
 
#Active the onboard Pico W Wi-Fi and connect to home network defined through "secrets.py"
wlan = network.WLAN(network.STA_IF)
#Read the MAC address from the Pico W itself
mac = ubinascii.hexlify(network.WLAN().config('mac'),':').decode()
print()
print("MAC address for this Pico W:", mac)
print()
#Configure a high power wi-fi connection
wlan.config(pm = 0xa11140)
wlan.active(True)
print("Scanning Available Wifi Connections...")
time.sleep(5)
#wdt.feed()
#print("woof!...good boy!")
print(wlan.scan())
time.sleep(2)
#wdt.feed()
#print("woof!...good boy!")
led.on()
#wdt.feed()
#print("woof!...good boy!")
time.sleep(2)
#wdt.feed()
#print("woof!...good boy!")
try:
    wlan.connect(SSID, PASSWORD)
except:
    try:
        print("first attempt to connect to router failed!")
        print("cycling wifi for retry")
        wlan.active(False)
        led.toggle()
        time.sleep(2)
        #wdt.feed()
        #print("woof!...good boy!")
        led.toggle()
        time.sleep(2)
        #wdt.feed()
        #print("woof!...good boy!")
        wlan.active(True)
        time.sleep(2)
        print(wlan.scan())
        time.sleep(2)
        #wdt.feed()
        #print("woof!...good boy!")
        wlan.connect(SSID, PASSWORD)
    except:
        print("wifi connecting failed.  Rebooting...")
        time.sleep(10)
        machine.reset()

#wdt.feed()
#print("woof!...good boy!")

led.off()

# Wait for connect or fail (3mins)
max_wait = 90
attempt = 1
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        #print(wlan.status)
        #break
        led.on()
        max_wait -= 1
        #print(wlan.status)
        print()
        print("Connection status attempt: ", attempt)
        print()
        print('connection is good...continuing')
        print()
        attempt += 1
        time.sleep(1)
        led.off()
        time.sleep(1)
        break
        #wdt.feed()
        #print("woof!...good boy!")
# Handle connection error
    if wlan.status() != 3:
        print("Connection status attempt: ", attempt)
        max_wait -= 1
        attempt += 1
        print()
        print("Network connection attempt failed!")
        print()
        #raise RuntimeError('network connection attempt failed')
        time.sleep(5)
        #machine.reset()

while max_wait == 0:
     print()
     print("cannot connect to the wifi!")
     print("rebooting...")
     led.on()
     time.sleep(10)
     machine.reset()

else:
    time.sleep(1)
    print("Pico W Wi-Fi is connected to: ",SSID)
    status = wlan.ifconfig()
    print( "ip address for this Pico W: " + status[0] )
    print()
    print("Channel: ", wlan.config('channel'))
    print("SSID: ", wlan.config('essid'))
    print("TXPOWER: ", wlan.config('txpower'))

stringstatus = str(status[0])
if stringstatus == IP:
    print()
    print("IP is good for MQTT connection! -> ", stringstatus)
    print("Moving on to next stage")
else:
    print()
    print("IP is bad for MQTT connection!  Rebooting...")
    time.sleep(10)
    machine.reset()

#wdt.feed()
#print("woof!...good boy!")
print()
print("Flashing LEDs for success display")
print()
#wdt.feed()
#print("woof!...good boy!")
#Show some onboard LED flashing to show that attempting to connect to the Wi-Fi has been completed
time.sleep(2)
led.off()
time.sleep(2)
led.toggle()
print("3")
time.sleep(0.2)
led.toggle()
time.sleep(1)
#wdt.feed()
#print("woof!...good boy!")
led.toggle()
print("2")
time.sleep(0.2)
led.toggle()
time.sleep(1)
#wdt.feed()
#print("woof!...good boy!")
led.toggle()
print("1")
time.sleep(0.2)
led.toggle()
time.sleep(1)
led.toggle()
print("blast off!")
print()
#wdt.feed()
#print("woof!...good boy!")
time.sleep(2)

#Setup MQTT server, local client ID (not really required),
#and published data transmissions hierarchy
mqtt_server = MQTTSERVE
client_id = b'PICOW'
#topic_pub1 = b'PicoW/OS_Temp'
#topic_pub2 = b'PicoW/OS_Hum'
#topic_pub3 = b'PicoW/Pico_Temp'
topic_pub1 = b'PicoW/OS_Temp'
topic_pub2 = b'PicoW/OS_Hum'
topic_pub3 = b'PicoW/Pico_Temp'

#For the above topics, use "PicoW/+"
#at the subscriber side to receive all
#three messages at once or use the full
#titles individually i.e PicoW/OS_Temp for
#just the outside temperature variable

def mqtt_connect():
    attempt2 = 5
    while attempt2 > 0:
        try:
            client = MQTTClient(client_id, mqtt_server, keepalive=3600)
            client.connect()
            print('Connected to %s MQTT Broker'%(mqtt_server))
            return client
        except:
            client.disconnect()
            print('Failed to connect to the MQTT Broker. Giving it some time!')
            print(attempt2)
            attempt2 -= 1
            time.sleep(5)
            #client.connect()
            #break
            
    while attempt2 == 0:
        reconnect()

def reconnect():
    print('Failed to connect to the MQTT Broker. Rebooting...')
    time.sleep(5)
    machine.reset()

print("Attempting to connect to MQTT Broker...")
print()
#wdt.feed()
#print("woof!...good boy!")

try:
    client = mqtt_connect()
except OSError as mqtterror:
    print(mqtterror)
    message2 = 'MQTT Error: '
    mqtterror2 = str(mqtterror)
    appendfile(message2, mqtterror2)
    reconnect()

#wdt.feed()
#print("woof!...good boy!")
    
#The main script of repeativeness for reading in from the connected sensor
#and taking in onboard temperature readings
while True:                                  #do stuff here
    led.on()
    time.sleep(0.5)

#Collect readings from the SHT-30
    readsensor()
    
    #wdt.feed()
    #print("woof!...good boy!")

#Collect temperature reading for the Pico W CPU
    def cpumeasure():
        global picotemp
        try:
            reading = sensor_temp.read_u16() * conversion_factor 
            picotemp = 27 - (reading - 0.706)/0.001721
        except OSError as cpu:
            print("something went wrong reading the onboard CPU Temperature!")
            print(cpu)
            print("rebooting...")
            message3 = 'CPU Temp Error: '
            cpu2 = str(cpu)
            appendfile(message3, cpu2)
            time.sleep(5)
            machine.reset()

    cpumeasure()
    #make readings 1 decimal place
    tpm1 = round(temperature,1)
    tpm2 = round(humidity,1)
    tpm3 = round(picotemp,1)
    
    #convert float reading values into bytes ready for MQTT transmission
    tpm4 = f"{tpm1}".encode()
    tpm5 = f"{tpm2}".encode()
    tpm6 = f"{tpm3}".encode()
    
    topic_msg1 = tpm4
    topic_msg2 = tpm5
    topic_msg3 = tpm6
    
    #Message displayed to the screen
    print()
    print("Publishing...")
    print()
    print('SHT Temperature: {:3.1f}ºC'.format(tpm1))
    print('SHT Humidity: {:3.1f}%'.format(tpm2))
    print('Pico W Temperature: {:3.1f}ºC'.format(tpm3))
    print()
    
    #Equivalent transmission of displayed readings above
    #(reverse order to match above order on subscriber receipt)
    try:
        client.publish(topic_pub3, topic_msg3)
        client.publish(topic_pub2, topic_msg2)
        client.publish(topic_pub1, topic_msg1)
        print("Publishing complete")
    except:
        print("Disconnected from MQTT Broker! Attempting Reconnection...")
        print()
        try:
            client = mqtt_connect()
        except OSError as mqtterror:
            print(mqtterror)
            message4 = 'MQTT2 Error: '
            mqtterror3 = str(mqtterror)
            appendfile(message4, mqtterror3)
            reconnect()
    led.off()
    #wdt.feed()
    #print("woof!...good boy!")
    time.sleep(5)
    #wdt.feed()
    #print("woof!...good boy!")
    time.sleep(5)
I've now enhanced it further with even more appendfile messages for even better transparency of where my code is not resilient enough to recover from a fault. Clearly it has recovered on quite a few occassions, but the final failure was obviously the nail in the coffin it seems. I'm unsure of why it has not recovered this time, even if this needed to be a complete automatic Pico W reboot...? (If anyone fancied a challenge at helping me identify?)
You'll notice i'm still resisting using the watchdog.

Code: Select all

#Necessary library imports for this code to function
from secrets import SSID
from secrets import PASSWORD
from secrets import IP
from secrets import IP_mask
from secrets import IP_gateway
from secrets import IP_DNS
from secrets import MQTTSERVE
from umqtt.simple import MQTTClient
import time
import network
import ubinascii
import socket
from machine import I2C, Pin, #wdt
import sht30
from sht30 import SHT30
from sht30 import SHT30Error

led = machine.Pin("LED", machine.Pin.OUT)

#initialise LED to OFF
led.off()

# def appendfile(message, error):
#     file=open("errorlog.txt","a")
#     errorstring=str(error)
#     file.write(message)
#     file.write(errorstring)
#     file.write("\n")
#     file.close()
    #file.flush()
    
def appendfile(message, error):
   with open('errorlog.txt', 'a') as file:
       file.write(message)
       errorstring=str(error)
       file.write(errorstring)
       file.write('\n')
       file.close()

def sht_error(ex):
    print("something went wrong reading the SHT-30!")
    print('Error:', ex)
    message = 'SHT Error: '
    appendfile(message, ex) #message, error
    
#Define the interface of the SHT30 Temp/Humidity sensor with the Pico W
i2c=I2C(0, sda=Pin(4), scl=Pin(5), freq=5000)
sht=sht30.SHT30(i2c=i2c, i2c_address=68)

def readsensor():
    global temperature
    global humidity
    try:
        sensor = sht.measure()
    except SHT30Error as ex:
        #print(ex)
        sht_error(ex)
        try:
            print("resetting SHT30")
            restartsensor = SHT30(i2c)
            time.sleep(1)
            restartsensor.reset()
            appendfile("SHT30 reset", "command")
            time.sleep(2)
            print("SHT30 reset")
            sensor = sht.measure()
        except:# SHT30Error as ex:
            #sht_error(ex)
            print("cannot read from SHT30, rebooting Pico W")
            appendfile("cannot read from SHT30, rebooting Pico W", "command")
            time.sleep(10)
            machine.reset()
    temperature, humidity = sensor

#wdt = wdt(timeout= 8000)
readsensor()
#wdt.feed()
#print("woof!...good boy!")
print('SHT Temperature: {:3.1f}ºC'.format(temperature))
print('SHT Humidity: {:3.1f}%'.format(humidity))

#Define the onboard Pico Temperature sensor and necessary conversion factor
sensor_temp = machine.ADC(4)
conversion_factor = 3.3 / (65535)

#Configure this Pico W for a static IP address on router using the following
UseStaticIP = True
IP = IP
IP_mask = IP_mask
IP_gateway = IP_gateway
IP_DNS = IP_DNS
 
#Active the onboard Pico W Wi-Fi and connect to home network defined through "secrets.py"
wlan = network.WLAN(network.STA_IF)
#Read the MAC address from the Pico W itself
mac = ubinascii.hexlify(network.WLAN().config('mac'),':').decode()
print()
print("MAC address for this Pico W:", mac)
print()
#Configure a high power wi-fi connection
wlan.config(pm = 0xa11140)
wlan.active(True)
print("Scanning Available Wifi Connections...")
time.sleep(5)
#wdt.feed()
#print("woof!...good boy!")
print(wlan.scan())
time.sleep(2)
#wdt.feed()
#print("woof!...good boy!")
led.on()
#wdt.feed()
#print("woof!...good boy!")
time.sleep(2)
#wdt.feed()
#print("woof!...good boy!")
try:
    wlan.connect(SSID, PASSWORD)
except:
    try:
        print("first attempt to connect to router failed!")
        print("cycling wifi for retry")
        wlan.active(False)
        led.toggle()
        time.sleep(2)
        #wdt.feed()
        #print("woof!...good boy!")
        led.toggle()
        time.sleep(2)
        #wdt.feed()
        #print("woof!...good boy!")
        wlan.active(True)
        time.sleep(2)
        print(wlan.scan())
        time.sleep(2)
        #wdt.feed()
        #print("woof!...good boy!")
        wlan.connect(SSID, PASSWORD)
    except:
        print("wifi connecting failed.  Rebooting...")
        appendfile("wifi connecting failed.  Rebooting...", "command")
        time.sleep(10)
        machine.reset()

#wdt.feed()
#print("woof!...good boy!")

led.off()

# Wait for connect or fail (3mins)
max_wait = 90
attempt = 1
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        #print(wlan.status)
        #break
        led.on()
        max_wait -= 1
        #print(wlan.status)
        print()
        print("Connection status attempt: ", attempt)
        print()
        print('connection is good...continuing')
        print()
        attempt += 1
        time.sleep(1)
        led.off()
        time.sleep(1)
        break
        #wdt.feed()
        #print("woof!...good boy!")
# Handle connection error
    if wlan.status() != 3:
        print("Connection status attempt: ", attempt)
        max_wait -= 1
        attempt += 1
        print()
        print("Network connection attempt failed!")
        print()
        #raise RuntimeError('network connection attempt failed')
        time.sleep(5)
        #machine.reset()

while max_wait == 0:
     print()
     print("cannot connect to the wifi!")
     print("rebooting...")
     led.on()
     appendfile("cannot connect to the wifi!", "reboot command")
     time.sleep(10)
     machine.reset()

else:
    time.sleep(1)
    print("Pico W Wi-Fi is connected to: ",SSID)
    status = wlan.ifconfig()
    print( "ip address for this Pico W: " + status[0] )
    print()
    print("Channel: ", wlan.config('channel'))
    print("SSID: ", wlan.config('essid'))
    print("TXPOWER: ", wlan.config('txpower'))

stringstatus = str(status[0])
if stringstatus == IP:
    print()
    print("IP is good for MQTT connection! -> ", stringstatus)
    print("Moving on to next stage")
else:
    print()
    print("IP is bad for MQTT connection!  Rebooting...")
    appendfile("IP is bad for MQTT connection!  Rebooting...", "command")
    time.sleep(10)
    machine.reset()

#wdt.feed()
#print("woof!...good boy!")
print()
print("Flashing LEDs for success display")
print()
#wdt.feed()
#print("woof!...good boy!")
#Show some onboard LED flashing to show that attempting to connect to the Wi-Fi has been completed
time.sleep(2)
led.off()
time.sleep(2)
led.toggle()
print("3")
time.sleep(0.2)
led.toggle()
time.sleep(1)
#wdt.feed()
#print("woof!...good boy!")
led.toggle()
print("2")
time.sleep(0.2)
led.toggle()
time.sleep(1)
#wdt.feed()
#print("woof!...good boy!")
led.toggle()
print("1")
time.sleep(0.2)
led.toggle()
time.sleep(1)
led.toggle()
print("blast off!")
print()
#wdt.feed()
#print("woof!...good boy!")
time.sleep(2)

#Setup MQTT server, local client ID (not really required),
#and published data transmissions hierarchy
mqtt_server = MQTTSERVE
client_id = b'PICOW'
#topic_pub1 = b'PicoW/OS_Temp'
#topic_pub2 = b'PicoW/OS_Hum'
#topic_pub3 = b'PicoW/Pico_Temp'
topic_pub1 = b'PicoW/OS_Temp'
topic_pub2 = b'PicoW/OS_Hum'
topic_pub3 = b'PicoW/Pico_Temp'

#For the above topics, use "PicoW/+"
#at the subscriber side to receive all
#three messages at once or use the full
#titles individually i.e PicoW/OS_Temp for
#just the outside temperature variable

def mqtt_connect():
    attempt2 = 5
    while attempt2 > 0:
        try:
            client = MQTTClient(client_id, mqtt_server, keepalive=3600)
            client.connect()
            print('Connected to %s MQTT Broker'%(mqtt_server))
            return client
        except:
            client.disconnect()
            print('Failed to connect to the MQTT Broker. Giving it some time!')
            appendfile('Failed to connect to the MQTT Broker. Giving it some time!', "command")
            print(attempt2)
            attempt2 -= 1
            time.sleep(5)
            #client.connect()
            #break
            
    while attempt2 == 0:
        reconnect()

def reconnect():
    print('Failed to connect to the MQTT Broker. Rebooting...')
    appendfile('Failed to connect to the MQTT Broker. Rebooting...',"command")
    time.sleep(5)
    machine.reset()

print("Attempting to connect to MQTT Broker...")
print()
#wdt.feed()
#print("woof!...good boy!")

try:
    client = mqtt_connect()
except OSError as mqtterror:
    print(mqtterror)
    message2 = 'MQTT Error 2: '
    mqtterror2 = str(mqtterror)
    appendfile(message2, mqtterror2)
    reconnect()

#wdt.feed()
#print("woof!...good boy!")
    
#The main script of repeativeness for reading in from the connected sensor
#and taking in onboard temperature readings
while True:                                  #do stuff here
    led.on()
    time.sleep(0.5)

#Collect readings from the SHT-30
    readsensor()
    
    #wdt.feed()
    #print("woof!...good boy!")

#Collect temperature reading for the Pico W CPU
    def cpumeasure():
        global picotemp
        try:
            reading = sensor_temp.read_u16() * conversion_factor 
            picotemp = 27 - (reading - 0.706)/0.001721
        except OSError as cpu:
            print("something went wrong reading the onboard CPU Temperature!")
            print(cpu)
            print("rebooting...")
            message3 = 'CPU Temp Error: '
            cpu2 = str(cpu)
            appendfile(message3, cpu2)
            time.sleep(5)
            machine.reset()

    cpumeasure()
    #make readings 1 decimal place
    tpm1 = round(temperature,1)
    tpm2 = round(humidity,1)
    tpm3 = round(picotemp,1)
    
    #convert float reading values into bytes ready for MQTT transmission
    tpm4 = f"{tpm1}".encode()
    tpm5 = f"{tpm2}".encode()
    tpm6 = f"{tpm3}".encode()
    
    topic_msg1 = tpm4
    topic_msg2 = tpm5
    topic_msg3 = tpm6
    
    #Message displayed to the screen
    print()
    print("Publishing...")
    print()
    print('SHT Temperature: {:3.1f}ºC'.format(tpm1))
    print('SHT Humidity: {:3.1f}%'.format(tpm2))
    print('Pico W Temperature: {:3.1f}ºC'.format(tpm3))
    print()
    
    #Equivalent transmission of displayed readings above
    #(reverse order to match above order on subscriber receipt)
    try:
        client.publish(topic_pub3, topic_msg3)
        client.publish(topic_pub2, topic_msg2)
        client.publish(topic_pub1, topic_msg1)
        print("Publishing complete")
    except:
        print("Disconnected from MQTT Broker! Attempting Reconnection...")
        print()
        try:
            client = mqtt_connect()
        except OSError as mqtterror:
            print(mqtterror)
            message4 = 'MQTT2 Error 4: '
            mqtterror3 = str(mqtterror)
            appendfile(message4, mqtterror3)
            reconnect()
    led.off()
    #wdt.feed()
    #print("woof!...good boy!")
    time.sleep(5)
    #wdt.feed()
    #print("woof!...good boy!")
    time.sleep(5)

Rissy
Posts: 116
Joined: Sun Aug 14, 2022 8:15 am

Re: Pico W Micro Python for SHT30 Temp/Humidity HELP!

Post by Rissy » Tue Nov 22, 2022 6:11 pm

I couldn't help myself this evening. Even though everything was still working as normal when i got home from work, I wanted to check out my errorlog.txt file to see what's been ocurring.

This is what I found:

Code: Select all

IP is bad for MQTT connection!  Rebooting...command
SHT Error: CRC error
SHT30 resetcommand
SHT Error: CRC error
SHT30 resetcommand
SHT Error: CRC error
SHT30 resetcommand
SHT Error: CRC error
SHT30 resetcommand
SHT Error: Bus error
SHT30 resetcommand
SHT Error: CRC error
SHT30 resetcommand
SHT Error: CRC error
SHT30 resetcommand
SHT Error: Bus error
SHT30 resetcommand
SHT Error: CRC error
SHT30 resetcommand
You can pretty much ignore that top error. For some reason when my Pico W attempts to connect to the Virgin router too soon after previously being connected before, then it either fails to connect (for which I have multiple attempts to do so) or it connects successfully, but it doesn't have its IP address assigned properly (I'm assigning it a fixed IP address in my code via my "secrets" file). When this fault happens, it gets 0.0.0.0 assigned to it, which means it wont successfully connect to my MQTT broker, so I've coded it so that if the IP address assigned doesn't match the IP i've designated in my secrets file, then just reboot the Pico W and try again. I wasn't sure of there being any other action I could take at this point besides rebooting....?

After that, you can see that my sensor has multiple errors when trying to be read, but it also seems to be successfully catching these errors and resetting the SHT30 accordingly and then continuing. This is good news for me for sure.

I've now enhanced my code even further with yet more errorlog.txt append commands so that I can get even further transparency, but ultimately I need to wait until I get to one of those rainy days again where I come home from work to find its crashed and no longer contributing its readings to my home monitoring so that I can see the resultant errorlog.txt logs up to the point of crashing.

For those who might still be interested to follow, this is what my code looks like now (still resisting using watchdog):

Code: Select all

#Necessary library imports for this code to function
from secrets import SSID
from secrets import PASSWORD
from secrets import IP
from secrets import IP_mask
from secrets import IP_gateway
from secrets import IP_DNS
from secrets import MQTTSERVE
from umqtt.simple import MQTTClient
import time
import network
import ubinascii
import socket
from machine import I2C, Pin, #wdt
import sht30
from sht30 import SHT30
from sht30 import SHT30Error

led = machine.Pin("LED", machine.Pin.OUT)

#initialise LED to OFF
led.off()

# def appendfile(message, error):
#     file=open("errorlog.txt","a")
#     errorstring=str(error)
#     file.write(message)
#     file.write(errorstring)
#     file.write("\n")
#     file.close()
    #file.flush()
    
def appendfile(message, error):
   with open('errorlog.txt', 'a') as file:
       file.write(message)
       errorstring=str(error)
       file.write(errorstring)
       file.write('\n')
       file.close()

def sht_error(ex):
    print("something went wrong reading the SHT-30!")
    print('Error:', ex)
    message = 'SHT Error: '
    appendfile(message, ex) #message, error
    
#Define the interface of the SHT30 Temp/Humidity sensor with the Pico W
i2c=I2C(0, sda=Pin(4), scl=Pin(5), freq=5000)
sht=sht30.SHT30(i2c=i2c, i2c_address=68)

def readsensor():
    global temperature
    global humidity
    try:
        sensor = sht.measure()
    except SHT30Error as ex:
        #print(ex)
        sht_error(ex)
        try:
            print("resetting SHT30")
            restartsensor = SHT30(i2c)
            time.sleep(1)
            restartsensor.reset()
            appendfile("SHT30 reset", " command")
            time.sleep(2)
            print("SHT30 reset")
            sensor = sht.measure()
        except:# SHT30Error as ex:
            #sht_error(ex)
            print("cannot read from SHT30, rebooting Pico W")
            appendfile("cannot read from SHT30, rebooting Pico W", " command")
            time.sleep(10)
            machine.reset()
    temperature, humidity = sensor

#wdt = wdt(timeout= 8000)
readsensor()
#wdt.feed()
#print("woof!...good boy!")
print('SHT Temperature: {:3.1f}ºC'.format(temperature))
print('SHT Humidity: {:3.1f}%'.format(humidity))

#Define the onboard Pico Temperature sensor and necessary conversion factor
sensor_temp = machine.ADC(4)
conversion_factor = 3.3 / (65535)

#Configure this Pico W for a static IP address on router using the following
UseStaticIP = True
IP = IP
IP_mask = IP_mask
IP_gateway = IP_gateway
IP_DNS = IP_DNS
 
#Active the onboard Pico W Wi-Fi and connect to home network defined through "secrets.py"
wlan = network.WLAN(network.STA_IF)
#Read the MAC address from the Pico W itself
mac = ubinascii.hexlify(network.WLAN().config('mac'),':').decode()
print()
print("MAC address for this Pico W:", mac)
print()
#Configure a high power wi-fi connection
wlan.config(pm = 0xa11140)
wlan.active(True)
print("Scanning Available Wifi Connections...")
time.sleep(5)
#wdt.feed()
#print("woof!...good boy!")
print(wlan.scan())
time.sleep(2)
#wdt.feed()
#print("woof!...good boy!")
led.on()
#wdt.feed()
#print("woof!...good boy!")
time.sleep(2)
#wdt.feed()
#print("woof!...good boy!")
try:
    wlan.connect(SSID, PASSWORD)
except:
    try:
        print("first attempt to connect to router failed!")
        print("cycling wifi for retry")
        appendfile("first router connection failed, cycling wifi", " command")
        wlan.active(False)
        led.toggle()
        time.sleep(2)
        #wdt.feed()
        #print("woof!...good boy!")
        led.toggle()
        time.sleep(2)
        #wdt.feed()
        #print("woof!...good boy!")
        wlan.active(True)
        time.sleep(2)
        print(wlan.scan())
        time.sleep(2)
        #wdt.feed()
        #print("woof!...good boy!")
        wlan.connect(SSID, PASSWORD)
    except:
        print("wifi connecting failed.  Rebooting...")
        appendfile("wifi connecting failed.  Rebooting...", " command")
        time.sleep(10)
        machine.reset()

#wdt.feed()
#print("woof!...good boy!")

led.off()

# Wait for connect or fail (3mins)
max_wait = 90
attempt = 1
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        #print(wlan.status)
        #break
        led.on()
        max_wait -= 1
        #print(wlan.status)
        print()
        print("Connection status attempt: ", attempt)
        print()
        print('connection is good...continuing')
        print()
        attempt += 1
        time.sleep(1)
        led.off()
        time.sleep(1)
        break
        #wdt.feed()
        #print("woof!...good boy!")
# Handle connection error
    if wlan.status() != 3:
        print("Connection status attempt: ", attempt)
        max_wait -= 1
        appendfile("Network connection failed attempt:", attempt)
        attempt += 1
        print()
        print("Network connection attempt failed!")
        print()
        #raise RuntimeError('network connection attempt failed')
        time.sleep(5)
        #machine.reset()

while max_wait == 0:
     print()
     print("cannot connect to the wifi!")
     print("rebooting...")
     led.on()
     appendfile("cannot connect to the wifi!", " reboot command")
     time.sleep(10)
     machine.reset()

else:
    time.sleep(1)
    print("Pico W Wi-Fi is connected to: ",SSID)
    status = wlan.ifconfig()
    print( "ip address for this Pico W: " + status[0] )
    print()
    print("Channel: ", wlan.config('channel'))
    print("SSID: ", wlan.config('essid'))
    print("TXPOWER: ", wlan.config('txpower'))

stringstatus = str(status[0])
if stringstatus == IP:
    print()
    print("IP is good for MQTT connection! -> ", stringstatus)
    print("Moving on to next stage")
else:
    print()
    print("IP is bad for MQTT connection!  Rebooting...")
    appendfile("IP is bad for MQTT connection!  Rebooting...", " command")
    time.sleep(10)
    machine.reset()

#wdt.feed()
#print("woof!...good boy!")
print()
print("Flashing LEDs for success display")
print()
#wdt.feed()
#print("woof!...good boy!")
#Show some onboard LED flashing to show that attempting to connect to the Wi-Fi has been completed
time.sleep(2)
led.off()
time.sleep(2)
led.toggle()
print("3")
time.sleep(0.2)
led.toggle()
time.sleep(1)
#wdt.feed()
#print("woof!...good boy!")
led.toggle()
print("2")
time.sleep(0.2)
led.toggle()
time.sleep(1)
#wdt.feed()
#print("woof!...good boy!")
led.toggle()
print("1")
time.sleep(0.2)
led.toggle()
time.sleep(1)
led.toggle()
print("blast off!")
print()
#wdt.feed()
#print("woof!...good boy!")
time.sleep(2)

#Setup MQTT server, local client ID (not really required),
#and published data transmissions hierarchy
mqtt_server = MQTTSERVE
client_id = b'PICOW'
#topic_pub1 = b'PicoW/OS_Temp'
#topic_pub2 = b'PicoW/OS_Hum'
#topic_pub3 = b'PicoW/Pico_Temp'
topic_pub1 = b'PicoW/OS_Temp'
topic_pub2 = b'PicoW/OS_Hum'
topic_pub3 = b'PicoW/Pico_Temp'

#For the above topics, use "PicoW/+"
#at the subscriber side to receive all
#three messages at once or use the full
#titles individually i.e PicoW/OS_Temp for
#just the outside temperature variable

def mqtt_connect():
    attempt2 = 5
    while attempt2 > 0:
        try:
            client = MQTTClient(client_id, mqtt_server, keepalive=3600)
            client.connect()
            print('Connected to %s MQTT Broker'%(mqtt_server))
            return client
        except:
            client.disconnect()
            print('Failed to connect to the MQTT Broker. Giving it some time!')
            appendfile('Failed to connect to the MQTT Broker. Giving it some time!', " command")
            appendfile('attempt: ', attempt2)
            print(attempt2)
            attempt2 -= 1
            time.sleep(5)
            #client.connect()
            #break
            
    while attempt2 == 0:
        reconnect()

def reconnect():
    print('Failed to connect to the MQTT Broker. Rebooting...')
    appendfile('Failed to connect to the MQTT Broker. Rebooting...'," command")
    time.sleep(5)
    machine.reset()

print("Attempting to connect to MQTT Broker...")
print()
#wdt.feed()
#print("woof!...good boy!")

try:
    client = mqtt_connect()
except OSError as mqtterror:
    print(mqtterror)
    message2 = 'MQTT Error 2: '
    mqtterror2 = str(mqtterror)
    appendfile(message2, mqtterror2)
    reconnect()

#wdt.feed()
#print("woof!...good boy!")
    
#The main script of repeativeness for reading in from the connected sensor
#and taking in onboard temperature readings
while True:                                  #do stuff here
    led.on()
    time.sleep(0.5)

#Collect readings from the SHT-30
    readsensor()
    
    #wdt.feed()
    #print("woof!...good boy!")

#Collect temperature reading for the Pico W CPU
    def cpumeasure():
        global picotemp
        try:
            reading = sensor_temp.read_u16() * conversion_factor 
            picotemp = 27 - (reading - 0.706)/0.001721
        except OSError as cpu:
            print("something went wrong reading the onboard CPU Temperature!")
            print(cpu)
            print("rebooting...")
            message3 = 'CPU Temp Error: '
            cpu2 = str(cpu)
            appendfile(message3, cpu2)
            time.sleep(5)
            machine.reset()

    cpumeasure()
    #make readings 1 decimal place
    tpm1 = round(temperature,1)
    tpm2 = round(humidity,1)
    tpm3 = round(picotemp,1)
    
    #convert float reading values into bytes ready for MQTT transmission
    tpm4 = f"{tpm1}".encode()
    tpm5 = f"{tpm2}".encode()
    tpm6 = f"{tpm3}".encode()
    
    topic_msg1 = tpm4
    topic_msg2 = tpm5
    topic_msg3 = tpm6
    
    #Message displayed to the screen
    print()
    print("Publishing...")
    print()
    print('SHT Temperature: {:3.1f}ºC'.format(tpm1))
    print('SHT Humidity: {:3.1f}%'.format(tpm2))
    print('Pico W Temperature: {:3.1f}ºC'.format(tpm3))
    print()
    
    #Equivalent transmission of displayed readings above
    #(reverse order to match above order on subscriber receipt)
    try:
        client.publish(topic_pub3, topic_msg3)
        client.publish(topic_pub2, topic_msg2)
        client.publish(topic_pub1, topic_msg1)
        print("Publishing complete")
    except:
        print("Disconnected from MQTT Broker! Attempting Reconnection...")
        print()
        try:
            client = mqtt_connect()
        except OSError as mqtterror:
            print(mqtterror)
            message4 = 'MQTT2 Error 4: '
            mqtterror3 = str(mqtterror)
            appendfile(message4, mqtterror3)
            reconnect()
    led.off()
    #wdt.feed()
    #print("woof!...good boy!")
    time.sleep(5)
    #wdt.feed()
    #print("woof!...good boy!")
    time.sleep(5)

Rissy
Posts: 116
Joined: Sun Aug 14, 2022 8:15 am

Re: Pico W Micro Python for SHT30 Temp/Humidity HELP!

Post by Rissy » Tue Dec 06, 2022 8:28 am

Roberthh wrote:
Wed Nov 09, 2022 1:33 pm
You can measure the existing pull-up resistors between a data line and Vcc, if the sensor is not powered. And you can always connect additional resistors fomr SDA to Vcc and SCL to Vcc. They would be simply in parallel to the existing resistor. Let's assume, the existing value is 4700, and you add 390 Ohm. Then the resulting value is 1 / ((1 / 4700) + (1 / 390)) = 360.
So I think i'm going to have to try this now.

My plan is to try and measure the resistances I have as it is, and then add some more resistance in parallel now that I have an assortment of resistors to hand at home.

I'm getting fed up with my sensor always letting me down. So much so that I put the watchdog back on last night, and then four hours later, it still failed even with the watchdog in play. By the time I got out of bed this morning and saw that it had failed (I was NOT happy!), I looked to see what it was doing and it was stuck in a continual cyclic reboot loop of about 10 seconds or so (watchdog set to 8 secs which is the maximum I believe). Pulling the USB and putting it back in again fixed the issue and it booted up perfectly again (still with the watchdog), so I know it's not an issue with where I'm putting my "woof good boy!" watchdog nudges.

Rissy
Posts: 116
Joined: Sun Aug 14, 2022 8:15 am

Re: Pico W Micro Python for SHT30 Temp/Humidity HELP!

Post by Rissy » Tue Dec 06, 2022 6:22 pm

So i'm home, and I've just been investigating my inbuilt pull up resistance values from my SHT-30 outdoor sensor (built in, so can't get at them locally). I measured between Vcc (3v3) and SDA, followed by Vcc (3v3) and SCL at the Pico W end of my cabling (indoors).

Between Vcc (3v3) and SDA I measured 2208 Ohms (basically 2.2kohms)
Between Vcc (3v3) and SCL I measured 2198 Ohms (basically 2.2kohms)

I decided to run between the Vcc and each of the serial lines above with another 2.2kohms resistor each (meaning in parallel with the inbuilt existing 2.2kohms resistances I can't get at).

Doing the maths, this gives:

1/2200 (or 2200^-1) + 1/2200 (or 2200^-1) = 1/1100 (or 1100^-1) = 1100 Ohms (Basically half the resistance that it was before).

I also reduced the frequency from 5000Hz on my serial line down to 2000Hz. I've deactivated the watchdog once more and set my program to go. It's working, so electrically speaking, my resistor modifications are ok.

Incidentally, whether it makes a difference or not (i thought not because the resistance should be equal all the way along the cable lines no matter where I put them), I put the resistors in parallel at the PicoW end where I measured, not the sensor end (because it's really cold and dark outside, instead of being nice and warm and well lit indoors where my PicoW lives).

Now I play the waiting game again and see what happens. It's supposed to be really cold this week, starting Wednesday, so hopefully that will be a good test. It failed last night even thought it wasn't raining, but it *was* cold, so maybe the cold affects it too...!?

Rissy
Posts: 116
Joined: Sun Aug 14, 2022 8:15 am

Re: Pico W Micro Python for SHT30 Temp/Humidity HELP!

Post by Rissy » Wed Dec 07, 2022 5:42 pm

I couldn't resist it. Although everything was still working this evening as I left it this morning before work (still running from last nights mods etc), I wanted to see what had been happening behind the scenes as it were, by referring to my errorlog.txt file.

Not a single error in 24hrs! I've NEVER had that with this device, ever! I think I may have cracked it finally (Hoping not to have spoken too soon of course).

I've already started looking at ntptime.py into my Pico W, and got a working solution for that on another test Pico W. I did try to put the same functions into my SHT-30 Pico W but quickly realised that it would be more difficult to timestamp errors where there is no internet connection for the ntp (if that was one of the errors). I'm wondering if I only need to read in the time in the first instance of booting up my program to set the Pico W internal clock once after first power up (and have an internet connection of course), or if I need to always refer to the internet time every time i want the Pico W to know the time. I will look at it again, but for now, I think i'll live with just my errorlogging without a timestamp.

EDIT: I decided to look into my idea of setting the local Pico W time once via the internet ntptime.py and then just relying on the local Pico W time exclusively after that. This is what I've come up with, fully tested to work even after switching off the wifi within the Pico W code. Not too hard to do after all. I'm retrofitting this into my SHT30 code now so that I can timestamp any errors which may still come out at any time.

Code: Select all

def gettime():
    clocktime = ntptime.settime()
    time.sleep(0.1)
    #ntptime tuple (year, month, day, hour, minute, second, weekday, yeardaynumber)
    year = clocktime[0]
    month = clocktime[1]
    day = clocktime[2]
    hour = clocktime[3]
    minute = clocktime[4]
    second = clocktime[5]
    weekday = clocktime[6]
    yeardaynumber = clocktime[7]
    timestamp = f'{day} {month} {year} {hour}:{minute}:{second}'
    #rtc.datetime tuple(year, month, day, weekday, hours, minutes, seconds, subseconds)
    rtc.datetime((year, month, day, weekday, hour, minute, second, 0))
    time.sleep(0.1)
    
def getlocaltime():
    localclocktime = rtc.datetime()
    time.sleep(0.1)
    localyear = localclocktime[0]
    localmonth = localclocktime[1]
    localday = localclocktime[2]
    localweekday = localclocktime[3]
    localhour = localclocktime[4]
    localminute = localclocktime[5]
    localsecond = localclocktime[6]
    localsubsecond = localclocktime[7]
    if localmonth == 1:
        localmonthstring = 'Jan'
    if localmonth == 2:
        localmonthstring = 'Feb'
    if localmonth == 3:
        localmonthstring = 'Mar'
    if localmonth == 4:
        localmonthstring = 'Apr'
    if localmonth == 5:
        localmonthstring = 'May'
    if localmonth == 6:
        localmonthstring = 'Jun'
    if localmonth == 7:
        localmonthstring = 'Jul'
    if localmonth == 8:
        localmonthstring = 'Aug'
    if localmonth == 9:
        localmonthstring = 'Sep'
    if localmonth == 10:
        localmonthstring = 'Oct'
    if localmonth == 11:
        localmonthstring = 'Nov'
    if localmonth == 12:
        localmonthstring = "Dec"
    localtimestamp = f'{localday} {localmonthstring} {localyear} {localhour}:{localminute}:{localsecond}'
    return localtimestamp
    
gettime() # run this function once to collect the time via the internet
localtimestamp = getlocaltime() # run this function within the "while True" loop to get an update of the time at the point desired
print(localtimestamp)

Post Reply