Skip to content

PYSTACK Exhausted Error #8594

@b-blake

Description

@b-blake

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions