Notifications
Clear all

Temperature with Pico W

9 Posts
3 Users
1 Reactions
798 Views
(@gomermil)
Member
Joined: 1 year ago
Posts: 15
Topic starter  

Hello I have my Pico W sending information to a web site to log the information. My problem is that after so long the Pico locks up and will not send information any more. If someone could assist me with this it would be greatly appreciated. 

import dht
import machine
import network
import sys
import time
import urequests as requests
import ssd1306
import config

def connect_wifi():
    ap_if=network.WLAN(network.AP_IF)
    ap_if.active(False)
    sta_if=network.WLAN(network.STA_IF)
    if not sta_if.isconnected():
        print('Connecting to WIFI...')
        sta_if.active(True)
        sta_if.connect(config.WIFI_SSID, config.WIFI_PASSWORD)
        while not sta_if.isconnected():
            time.sleep(1)
    print('Network Config:', sta_if.ifconfig())
    
def show_error():
    led=machine.Pin(config.LED_PIN, machine.Pin.OUT)
    for i in range (3):
        led.on()
        time.sleep(0.5)
        led.off()
        time.sleep(0.5)
        
def is_debug():
    debug=machine.Pin(config.DEBUG_PIN, machine.Pin.IN, machine.Pin.PULL_UP)
    return debug.value()==0

def get_temperature_and_humidity():
    dht22=dht.DHT22(machine.Pin(config.DHT22_PIN))
    dht22.measure()
    temperature=dht22.temperature()
    if config.FAHRENHEIT:
        temperature=temperature * 9 / 5 + 32
    return temperature, dht22.humidity()

def log_data(temperature, humidity):
    print('Invoking log webhook')
    url=config.WEBHOOK_URL.format(temperature=temperature, humidity=humidity)
    response=requests.get(url)
    if response.status_code < 400:
        print('Webhook invoked')
    else:
        print('Webhook failed')
        raise RuntimeError('Webhook failed')
    
def display_temperature_and_humidity(temperature, humidity):
    i2c=machine.I2C(config.DISPLAY_I2C_ID, scl=machine.Pin(config.DISPLAY_SCL_PIN), sda=machine.Pin(config.DISPLAY_SDA_PIN))
    if 60 not in i2c.scan():
        raise RuntimeError('Cannot find display.')
    
    display=ssd1306.SSD1306_I2C(128, 64, i2c)
    display.fill(0)
    
    display.text('{:^16s}'.format('Temperature:'), 0, 0)
    display.text('{:^16s}'.format(str(temperature) + \
        ('F' if config.FAHRENHEIT else 'C')), 0, 16)

    display.text('{:^16s}'.format('Humidity:'), 0, 32)
    display.text('{:^16s}'.format(str(humidity) + '%'), 0, 48)

    display.show()
    time.sleep(40)
    display.poweroff()
    
def run():
    debug = is_debug()
    try:
        temperature, humidity=get_temperature_and_humidity()
        print('Temperature: {}{}, Humidity: {}%' .format(temperature, 'F' if config.FAHRENHEIT else 'C', humidity))
        display_temperature_and_humidity(temperature, humidity)
        if not debug:
            connect_wifi()
            log_data(temperature, humidity)
        else:
            print('Debug mode detected. Skipping network calls and sleep.')
            
    except Exception as exc:
        sys.print_exception(exc)
        show_error()
        
    machine.reset()  
run()
    

   
Quote
byron
(@byron)
No Title
Joined: 5 years ago
Posts: 1136
 

@gomermil

I had a quick look at your code.  Its worthy of some amendment, but to  give the proper attention to it will take more time than I have right now, so I give some quick comments in the hope that the pointers help.

1. get rid of the debug stuff, its a short program I doubt if you are using a debugger to step through your code, and its just seem to be there so the program can be asked to ignore some function calls for testing.  For testing just comment out the unwanted function calls.  The sorter the code the easier to read.

2. After the import statement put in all the hardware assignments like your pin assignment so as not to continually redefine the assignments when you repeatedly call the functions.  Remove them from the function definitions.

3. Do not perform a reboot (machine.reset) to perform a loop to restart your program.  The only time a machine.reset maybe warranted is if its stuck on things like connecting to wifi.  Use a while loop.

4. In your wifi connect function if it cannot make a connection your in an endless loop of isconnected() and time.sleep.  Just try to connect in a loop for a max of 10 times, and if no success consider a small sleep and then a machine.reset() to restart the program.

5. Only connect to your wifi once.  The program flow should be:

imports / pin definitions / i2c assignments / function definitions / connect to wifi / program loop START to read DHT sensor - send readings to screen - send readings to http - have a nap - back to loop START again.

6. If I remember the DHT sensors don't like being read too often.  I suggest a wait of at least 2 minuets between reads.  But, depending of course on what temperatures you are reading, temperatures don't vary much in just 2 minutes so a longer wait of something like 15 minutes is probably more appropriate

7. Consider if raising a runtime error in your send data over internet function on some failure is the appropriate action.  Maybe a pause to try again later would be the better action ?

8. Don't scan for i2c address in your program. Once you know the address of the peripheral, just use the correct address in your program.   You could put your communications with your i2c device in a try/except to catch comms errors.

Thats all for now, hope its some small help.

 

This post was modified 1 year ago by byron

   
DaveE reacted
ReplyQuote
(@gomermil)
Member
Joined: 1 year ago
Posts: 15
Topic starter  

@byron Thank you for the assistance. I will let you know what happens, because I will most likely have to post the code again.


   
ReplyQuote
(@gomermil)
Member
Joined: 1 year ago
Posts: 15
Topic starter  

I worked on the code and it works, for a short time. If anyone can assist me again it would be greatly appreciated.

import dht
import machine
import network
import sys
import time
import urequests as requests
import ssd1306
import config

def connect_wifi():
    ap_if=network.WLAN(network.AP_IF)
    ap_if.active(False)
    sta_if=network.WLAN(network.STA_IF)
    if not sta_if.isconnected():
        print('Connecting to WIFI...')
        sta_if.active(True)
        sta_if.connect(config.WIFI_SSID, config.WIFI_PASSWORD)
        while not sta_if.isconnected():
            time.sleep(1)
    print('Network Config:', sta_if.ifconfig())
connect_wifi()    
def show_error():
    led=machine.Pin(config.LED_PIN, machine.Pin.OUT)
    for i in range (3):
        led.on()
        time.sleep(0.5)
        led.off()
        time.sleep(0.5)
        
def get_temperature_and_humidity():
    dht22=dht.DHT22(machine.Pin(config.DHT22_PIN))
    dht22.measure()
    temperature=dht22.temperature()
    if config.FAHRENHEIT:
        temperature=temperature * 9 / 5 + 32
    return temperature, dht22.humidity()

def log_data(temperature, humidity):
    print('Invoking log webhook')
    url=config.WEBHOOK_URL.format(temperature=temperature, humidity=humidity)
    response=requests.get(url)
    if response.status_code < 400:
        print('Webhook invoked')
    else:
        print('Webhook failed')
        raise RuntimeError('Webhook failed')
    
def display_temperature_and_humidity(temperature, humidity):
    i2c=machine.I2C(config.DISPLAY_I2C_ID, scl=machine.Pin(config.DISPLAY_SCL_PIN), sda=machine.Pin(config.DISPLAY_SDA_PIN))
    if 60 not in i2c.scan():
        raise RuntimeError('Cannot find display.')
    
    display=ssd1306.SSD1306_I2C(128, 64, i2c)
    display.fill(0)
    
    display.text('{:^16s}'.format('Temperature:'), 0, 0)
    display.text('{:^16s}'.format(str(temperature) + \
        ('F' if config.FAHRENHEIT else 'C')), 0, 16)

    display.text('{:^16s}'.format('Humidity:'), 0, 32)
    display.text('{:^16s}'.format(str(humidity) + '%'), 0, 48)

    display.show()
    
    
while True:
    try:
        temperature, humidity=get_temperature_and_humidity()
        print('Temperature: {}{}, Humidity: {}%' .format(temperature, 'F' if config.FAHRENHEIT else 'C', humidity))
        display_temperature_and_humidity(temperature, humidity)
        log_data(temperature, humidity)
    
    except Exception as exc:
        sys.print_exception(exc)
        show_error()
    time.sleep(80)        
        

    
Temperature: 71.42F, Humidity: 41.3%
Invoking log webhook
Webhook invoked
Temperature: 71.42F, Humidity: 41.1%
Invoking log webhook
Webhook invoked
Temperature: 71.24001F, Humidity: 41.0%
Invoking log webhook
Webhook invoked
Temperature: 70.88F, Humidity: 41.4%
Invoking log webhook
Webhook invoked
Temperature: 70.88F, Humidity: 41.5%
Invoking log webhook
Traceback (most recent call last):
  File "<stdin>", line 71, in <module>
  File "<stdin>", line 41, in log_data
  File "urequests.py", line 180, in get
  File "urequests.py", line 93, in request
OSError: [Errno 12] ENOMEM
Temperature: 70.7F, Humidity: 41.6%
Invoking log webhook
Traceback (most recent call last):
  File "<stdin>", line 71, in <module>
  File "<stdin>", line 41, in log_data
  File "urequests.py", line 180, in get
  File "urequests.py", line 93, in request
OSError: [Errno 12] ENOMEM
Temperature: 70.52F, Humidity: 41.6%
Invoking log webhook
Traceback (most recent call last):
  File "<stdin>", line 71, in <module>
  File "<stdin>", line 41, in log_data
  File "urequests.py", line 180, in get
  File "urequests.py", line 93, in request
OSError: [Errno 12] ENOMEM
Temperature: 70.52F, Humidity: 41.7%
Invoking log webhook
Traceback (most recent call last):
  File "<stdin>", line 71, in <module>
  File "<stdin>", line 41, in log_data
  File "urequests.py", line 180, in get
  File "urequests.py", line 93, in request
OSError: [Errno 12] ENOMEM

   
ReplyQuote
byron
(@byron)
No Title
Joined: 5 years ago
Posts: 1136
 

@gomermil

its way passed my bedtime, but I will look tomorrow if someone else has not provided you with an answer.  

It all goes wobbly with your request to get something from a web page - response=requests.get(url) - and then appears to complain about running out of memory.  Just what are you expecting to receive?

Anyway, goodnight for now 😀 


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 4 years ago
Posts: 7410
 

@gomermil It looks like you ran out of memory (ENOMEM). I don't speak python but it sounds like you are requesting memory but not giving it back. It helps iof your source listing showed line numbers so you can look at the specific line the error messages are telling you. Lines 93, 180, 41, 71 is the trace.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
ReplyQuote
byron
(@byron)
No Title
Joined: 5 years ago
Posts: 1136
 

@gomermil

2 things spring to mind.  Micropython code for the picow has never had a stable release due to the fact is came out after the last stable pico release in July.  V1.2 stable release is due very soon but in the meanwhile I suggest you download and install the latest micropython nightly release to get the most up to date.  I do remember seeing some reports about ENOMEM errors with some earlier nightly releases. 

But if your code continues to be uncoperative than you need to divide and conquer.   In your log_data function simply put a print statement, e.g. print('Im in log_data and doing nowt') and remove all the other code you have in that function.  Then run your program to check all the rest runs without any problems.

Once that step is fully sorted, then turn your attention to the log_data function.  I don't know anything about the WEBHOOK thingy but to analyse what is going on put that function as you have it now into a separate python script.  Add some extra print statements so you can see whats going on.  Immediately after the response=requests.get(url) statement put a print(response) to have a look at whats being received in full.  You could invoke your function in a loop with dummy data. 

import time
import urequests as requests

def log_data(temperature, humidity):
    print('Invoking log webhook')
    url=config.WEBHOOK_URL.format(temperature=temperature, humidity=humidity)
    response=requests.get(url)
    
    print(response)
    
    if response.status_code < 400:
        print('Webhook invoked')
    else:
        print('Webhook failed')
        #raise RuntimeError('Webhook failed')
    
temp = 20
hum = 66

while True:
    log_data(temp, hum)
    time.sleep(30)

 

Hopefully you will then be able to get a handle on whats going on with your WEBHOOK code.

If you did not want dummy data to be used for your WEBHOOK stuff then you could save the real temperature and humidity reading in the other part of your divided coded into a file and read those values from that file into the code above in place of the dummy data.

 

 


   
ReplyQuote
byron
(@byron)
No Title
Joined: 5 years ago
Posts: 1136
 

@gomermil

I forgot to mention that this forum is not the best place to get help on micropython.  Its good for electronics circuits and for coding in arduino c/c++.   Seek help on micropthyon on the following forums. (the raspberry pi forum is just for the rpi pico's and the github micropython forum is for all boards and the authors of micropython participate therein)

https://forums.raspberrypi.com/viewforum.php?f=146

https://github.com/orgs/micropython/discussions


   
ReplyQuote
(@gomermil)
Member
Joined: 1 year ago
Posts: 15
Topic starter  

@byron Thank you for all the assistance that you have given me I greatly appreciate it. I will look into the other forums also. I did figure out what I was doing wrong after some research. I had to close the response in the log data part. I have had the code running all night with no errors. Thank you again for all the assistance you have provided.

import dht
import machine
import network
import sys
import time
import urequests as requests
import ssd1306
import config
        
def get_temperature_and_humidity():
    dht22=dht.DHT22(machine.Pin(config.DHT22_PIN))
    dht22.measure()
    temperature=dht22.temperature()
    if config.FAHRENHEIT:
        temperature=temperature * 9 / 5 + 32
    return temperature, dht22.humidity()

def log_data(temperature, humidity):
    print('Invoking log webhook')
    url=config.WEBHOOK_URL.format(temperature=temperature, humidity=humidity)
    response=requests.get(url)
    if response.status_code < 400:
        print('Webhook invoked')
    else:
        print('Webhook failed')
        raise RuntimeError('Webhook failed')
    response.close()
def display_temperature_and_humidity(temperature, humidity):
    i2c=machine.I2C(config.DISPLAY_I2C_ID, scl=machine.Pin(config.DISPLAY_SCL_PIN), sda=machine.Pin(config.DISPLAY_SDA_PIN))
    
    display=ssd1306.SSD1306_I2C(128, 64, i2c)
    display.fill(0)
    
    display.text('{:^16s}'.format('Temperature:'), 0, 0)
    display.text('{:^16s}'.format(str(temperature) + \
        ('F' if config.FAHRENHEIT else 'C')), 0, 16)

    display.text('{:^16s}'.format('Humidity:'), 0, 32)
    display.text('{:^16s}'.format(str(humidity) + '%'), 0, 48)

    display.show()
    
def connect_wifi():
    ap_if=network.WLAN(network.AP_IF)
    ap_if.active(False)
    sta_if=network.WLAN(network.STA_IF)
    if not sta_if.isconnected():
        print('Connecting to WIFI...')
        sta_if.active(True)
        sta_if.connect(config.WIFI_SSID, config.WIFI_PASSWORD)
        while not sta_if.isconnected():
            time.sleep(1)
    print('Network Config:', sta_if.ifconfig())
connect_wifi()    
 
 
while True:
    try:
        temperature, humidity=get_temperature_and_humidity()
        print('Temperature: {}{}, Humidity: {}%' .format(temperature, 'F' if config.FAHRENHEIT else 'C', humidity))
        display_temperature_and_humidity(temperature, humidity)
        log_data(temperature, humidity)
    
    except Exception as exc:
        sys.print_exception(exc)
        show_error()
    time.sleep(60)        

   
ReplyQuote