adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
Other
4.11k stars 1.22k forks source link

PYSTACK Exhausted Error #8594

Closed b-blake closed 1 year ago

b-blake commented 1 year ago

CircuitPython version

I got a PYSTACK Exhausted Error.
Added to settings.toml **CIRCUITPY_HEAP_START_SIZE =**  and adjusted it from 8192 up to 32768 with x2 in each step: Not fixed.
Removed  CIRCUITPY_HEAP_START_SIZE.
Added CIRCUITPY_PYSTACK_SIZE = 8192: Fixed.

Code/REPL

# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT

import os
import time
import wifi
import busio
import board
import ipaddress
import socketpool
import microcontroller
from   digitalio import DigitalInOut, Direction
##import displayio
##import terminalio
##from   adafruit_display_text import label
##import adafruit_displayio_ssd1306
##import adafruit_imageload

from   adafruit_httpserver import Server, Request, Response, POST
from   adafruit_onewire.bus import OneWireBus
from   adafruit_ds18x20 import DS18X20
import adafruit_ntp
import cedargrove_dst_adjuster as dst_adj

print(board.board_id)

UTC   = not True
AM_PM = not True
DST   = not True
DoW   = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday', 'Beerday')

#  onboard LED setup
led = DigitalInOut(board.LED)
led.direction = Direction.OUTPUT
led.value = True
print('Sleep 10 Seconds.')
time.sleep(10)
led.value = False
time.sleep(0.25)

# one-wire bus for DS18B20
ow_bus = OneWireBus(board.GP6)

# scan for temp sensor
##ds18 = DS18X20(ow_bus, ow_bus.scan()[0])

#  function to convert celcius to fahrenheit
def c_to_f(temp):
    temp_f = (temp * 1.8) + 32
    return temp_f

#  connect to network
print('~~~~~~~~~~~~')
print("Connecting to WiFi")

#  set static IP address
SSID_ = os.getenv('CIRCUITPY_WIFI_SSID')
PASS_ = os.getenv('CIRCUITPY_WIFI_PASSWORD')
print(SSID_, PASS_)
flag = False
while not flag:
    ipv4 =  ipaddress.IPv4Address("192.168.1.89")
    netmask =  ipaddress.IPv4Address("255.255.255.0")
    gateway =  ipaddress.IPv4Address("192.168.1.1")
    try:
        wifi.radio.set_ipv4_address(ipv4=ipv4,netmask=netmask,gateway=gateway)
        #  connect to your SSID
        led.value = not led.value
        wifi.radio.connect(SSID_, PASS_)
        flag = True
    except Exception as ex:
        print('70 Exception:', ex)
        pass
led.value = flag
PASS_ = 'Null'
print("Connected to WiFi")
pool = socketpool.SocketPool(wifi.radio)
server = Server(pool, "/static", debug=True)

#  variables for HTML
#  comment/uncomment desired temp unit
#######################################
def wifi_scan():
    flag = False
    while not flag:
        #SSID_ = os.getenv('CIRCUITPY_WIFI_SSID')
        print("\t\bAvailable WiFi networks:  RSSI:  Channel:")
        c = 0
        for network in wifi.radio.start_scanning_networks():
            if SSID_ in str(network.ssid, "utf-8"): flag = True
            s = "."*(25-len(str(network.ssid, "utf-8")))
            if (len(s) == 0): s = "...Hidden.SSID...."
            c += 1
            print("%3d\t%s%s %d\t   %2d" % (c, str(network.ssid, "utf-8"), s, network.rssi, network.channel))
            #print(flag)
            #flag = False
        wifi.radio.stop_scanning_networks()
        print('\t\b', SSID_, 'found:', flag)
    return(flag)
wifi_scan()
#######################################
def adjust_DST(ntp):
    global datetime
    dt = datetime = time.localtime(time.time())
    _ = (dst_adj.adjust_dst(datetime))
    #print ('\t'+ str(dt[0])+'/'+ str(dt[1])+'/'+ str(dt[2])+' ~ '+ str(dt[3])+':'+ str(dt[4])+':'+ str(dt[5])+' '+ str(dt[6])+'  '+ str(dt[7])+'  '+ str(dt[8]))
    #print(ntp.datetime)
    return(ntp)
#######################################
def get_NTP():
    flag = False
    while not flag:
        global DST, AM_PM, UTC, ntp
        tz = -4 if DST else -5
        if UTC:
            tz = 0
            DST = False
            AM_PM = False
        ntp = adafruit_ntp.NTP(pool, tz_offset=(tz), socket_timeout=2)
        while not ntp:
            ntp = adafruit_ntp.NTP(pool, tz_offset=(tz), socket_timeout=2)
        try:
            tm = ntp.datetime
            flag = True
        except Exception as ex:
            print('117 Exception:', ex)
    adjust_DST(tm)
    return(ntp)
#######################################
ntp = get_NTP()
flag = 150
if flag:
    try:
        tm = ntp.datetime
        flag = 0
    except Exception as ex:
        print('127 Exception:', ex)
        time.sleep(0.1)
        tm = (1,2,3,4,5,6,7,8,9)
        flag -= 1
        pass
else:
    print("restarting..")
    time.sleep(5)
    microcontroller.reset()
adjust_DST(ntp)
print ('\t'+str(tm[0])+'/'+str(tm[1])+'/'+str(tm[2])+' ~ '+str(tm[3])+':'+str(tm[4])+':'+str(tm[5])+'  '+DoW[tm[6]]+'  DoY:'+str(tm[7])+'  '+str(tm[8]))
#######################################
def get_temps():
    global temp_test0C, temp_test1C, unitC, temp_test0F, temp_test1F, unitF
    ##temp_testC = str(ds18.temperature)
    temp_test0C = microcontroller.cpus[0].temperature
    temp_test1C = microcontroller.cpus[1].temperature
    unitC = "C"
    ##temp_testF = str(c_to_f(ds18.temperature))
    temp_test0F = c_to_f(temp_test0C)
    temp_test1F = c_to_f(temp_test1C)
    unitF = "F"

get_temps()
#  font for HTML
font_family = "monospace"

#  the HTML script
#  setup as an f string
#  this way, can insert string variables from code.py directly
#  of NOTE, use {{ and }} if something from html *actually* needs to be in brackets
#  i.e. CSS style formatting

#######################################
def webpage():
    html = f"""
    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="Content-type" content="text/html;charset=utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
    html{{font-family: {font_family}; background-color: lightgrey;
    display:inline-block; margin: 0px auto; text-align: center;}}
      h1{{color: deeppink; width: 200; word-wrap: break-word; padding: 2vh; font-size: 35px;}}
      p{{font-size: 1.5rem; width: 200; word-wrap: break-word;}}
      .button{{font-family: {font_family};display: inline-block;
      background-color: black; border: none;
      border-radius: 4px; color: white; padding: 16px 40px;
      text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}}
      p.dotted {{margin: auto;
      width: 75%; font-size: 25px; text-align: center;}}
    </style>
    </head>
    <body>
    <title>Pico W HTTP Server & Status</title>
    <h1>Pico W HTTP Server</h1>
    <br><p class="dotted">This is a Pico W running an HTTP server with CircuitPython.</p>

    <br><p class="dotted">The current temperature of the Pico W CPU is:
    <br><span style="color: deeppink;">{temp_test0C:.2f}°{unitC} ~ {temp_test0F:.2f}°{unitF}</span></p>

    <h1>Control the LED on the Pico W with these buttons:</h1><br>

    <form accept-charset="utf-8" method="POST">
    <button class="button" name="LED ON" value="ON" type="submit">LED ON</button></a></p></form>

    <p><form accept-charset="utf-8" method="POST">
    <button class="button" name="LED OFF" value="OFF" type="submit">LED OFF</button></a></p></form>

    <p><form accept-charset="utf-8" method="POST">
    <button class="button" name="LED TOGGLE" value="TOGGLE" type="submit">LED TOGGLE</button></a></p></form>

    <br><h1><span style="color: blue;">SSID: {os.getenv('CIRCUITPY_WIFI_SSID')}
    <br>IP: {wifi.radio.ipv4_address}
    <br>CPU 0: {temp_test0C:.2f}°{unitC} ~ {temp_test0F:.2f}°{unitF}
    <br>CPU 1: {temp_test1C:.2f}°{unitC} ~ {temp_test1F:.2f}°{unitF}
    <br>Ping 8.8.4.4: {wifi.radio.ping(ping_address)} Sec</h1>

    <h1>Party?</h>
    <p><form accept-charset="utf-8" method="POST">
    <button class="button" name="party" value="PARTY" type="submit">PARTY!</button></a></p></form>

    </body></html>
    """
    return html

#  route default static IP
@server.route("/")
#######################################
def base(request: Request):  # pylint: disable=unused-argument
    #  serve the HTML f string
    #  with content type text/htm
    return Response(request, f"{webpage()}", content_type='text/html')

#  if a button is pressed on the site
@server.route("/", POST)
#######################################
def buttonpress(request: Request):
    #  get the raw text
    raw_text = request.raw_request.decode("utf8")
    print('Raw Text:\n', raw_text)
    print('*'*40)

    #  if the led on button was pressed
    if "LED+ON=ON" in raw_text:
        #  turn on the onboard LED
        led.value = True

    #  if the led off button was pressed
    elif "OFF=OFF" in raw_text:
        #  turn the onboard LED off
        led.value = False

    #  if the led off button was pressed
    elif "TOGGLE" in raw_text:
        #  turn the onboard LED off
        led.value = not led.value

    #  if the party button was pressed
    elif "party" or "PARTY" in raw_text:
        #  toggle the parrot_pin value
        pass # parrot_pin.value = not parrot_pin.value
    #  reload site
    return Response(request, f"{webpage()}", content_type='text/html')

print("starting server..")
# startup the server
try:
    if(wifi.radio.ipv4_address == None):
        print('Resetting in 5 seconds:')
        time.sleep(5)
        microcontroller.reset()
    server.start(str(wifi.radio.ipv4_address))
    print("Listening on http://%s:80" % wifi.radio.ipv4_address)
#  if the server fails to begin, restart the pico w
except Exception as ex:
    print("263 Restarting..", ex)
    time.sleep(5)
    microcontroller.reset()
ping_address = ipaddress.ip_address("8.8.4.4")

monotonicClock = time.monotonic() #  time.monotonic() holder for server ping
#print(time.localtime())
print('~~~~~~~~~~~~')
#######################################
#######################################
pingFailCount = 0
while True:
    get_temps()
    #led.value = not led.value
    try:
        #  every few seconds, ping server & update temp reading
        _ = 30
        if (monotonicClock + _) < time.monotonic():
            if wifi.radio.ping(ping_address) is None:
                pingFailCount +=1
                print("Ping Failed <*>\a", pingFailCount)
                if(pingFailCount > 10):
                    microcontroller.reset()
            else:
                tm = ntp.datetime
                print("Ping Success")
                pingFailCount = 0
                print (str(tm[0])+'/'+ str(tm[1])+'/'+ str(tm[2])+' ~ '+ str(tm[3])+':'+ str(tm[4])+':'+ str(tm[5])+' ~ '+ DoW[tm[6]]+'  DoY:'+ str(tm[7])+'  '+ str(tm[8]))
            if(tm[5] % _ != 0): time.sleep(1); print('+', end='')
            monotonicClock = time.monotonic()
            #  comment/uncomment for desired units
            ##temp_testC = str(ds18.temperature)
            ##temp_testF = str(c_to_f(ds18.temperature))

        server.poll()
        time.sleep(0.01)
    # pylint: disable=broad-except
    except Exception as ex:
        print('301 Exception:', ex)
        print (str(tm[0])+'/'+ str(tm[1])+'/'+ str(tm[2])+' ~ '+ str(tm[3])+':'+ str(tm[4])+':'+ str(tm[5])+' ~ '+ DoW[tm[6]]+'  DoY:'+ str(tm[7])+'  '+ str(tm[8]))
        continue

Behavior

Adjusting CIRCUITPY_HEAP_START_SIZE in settings.toml, as noted in the initial posting of 9.0.0 Alpha 4, does not fix the error on an RP2040.

Description

The code.py above runs on a bare Raspberry Pi Pico W. No additional parts needed.
Your settings.toml will be needed.
I started with the Code the Pico W HTTP Server and only modified code.py.
I removed the ssd1306 code and disabled the DS18X20 pending later use.
The print('nnn Exception :', ex) code shows the approximate line number of where the exception occured.

Additional information

No response

b-blake commented 1 year ago

Adafruit CircuitPython 9.0.0-alpha.4 on 2023-11-12; Raspberry Pi Pico W with rp2040 Board ID:raspberry_pi_pico_w UID:E661410403657439 MAC:28:CD:C1:03:9E:26 boot.py output: Write to SD Card: True Write to Flash : False boot.py Finis

tannewt commented 1 year ago

I'm going to mark this a duplicate of #8574. I think I found the issue. PR soon.

b-blake commented 1 year ago

Thumbs-Up