Pico W Webserver disconnects when no incoming connections. [UN Solved}

I have a campervan that runs a one Pi control screen for switching on the lights etc via a web interface. This works fine. I also had a Pi Zero running an a similar system which allowed control of the Vent fans from the front of the van mounted in the dash. Then I started to play with Picos. Learnt that they can run webservers and though, the system could do with an upgrade and really a Pico is ideal for the job where the Pi’s are a little overboard for some of the smaller systems. So rewrote one of the smaller systems for Pico and it works fine, UNTIL, you aren’t connected to the page anymore then it disconnects from the wifi after a short period and won’t reconnect when you go to access the page agian. The only way to make it active again is to restart the Pico.

As my van control system has multiple pages to use from various controllers, (for general switching, ventilation fans, tank level monitors that can be accessed from the one screen via fixed ip addresses), the pico is the only one that wont remain active while not being accessed.

I have a test network at home that only has the controller and programming computer on it so connected the Pico to it and the same thing happens. I grabbed another Pico, created a basic webserver code from an instructable site and, yes, when you stop accessing the site, the pico disconnects.

Has anyone else had the same problem. I have looked around google and apparently it is a common problem>

If this issue is common with Pico, I may switch over to an ESP32 for these simpler “none thinking” tasks

Thanks

john

import network
import socket
from time import sleep
from machine import Pin

import stag


import time
import ubinascii
led = machine. Pin('LED', machine. Pin. OUT)
wlan = network.WLAN(network.STA_IF)
wlan.active(True)

wlan.connect(stag.SSID, stag.PASSWORD)
ssid, password = (stag.SSID, stag.PASSWORD)
wlan.ifconfig(('192.168.1.221', '255.255.255.0', '192.168.1.1', '8.8.8.8'))

led_one = Pin(13, Pin.OUT)     #led
led_two = Pin(11, Pin.OUT)     #reverse
led_three = Pin(9, Pin.OUT)    #slow
led_four = Pin(8, Pin.OUT)    #fast
led_five = Pin(28, Pin.OUT)    #close
led_six = Pin(27, Pin.OUT)     #open
led_seven = Pin(26, Pin.OUT)  #on/off


led.value(0)

def Website():
    value_one = led_one.value()
    value_two = led_two.value()
    value_three = led_three.value()
    value_four = led_four.value()
    value_five = led_five.value()
    value_six = led_six.value()
    value_seven = led_seven.value()
    website = """<!DOCTYPE html>
    <html>
     <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <head> <title>Fan Control</title> </head>
          
          <style>
*{background-color: black;
  color:yellow;
  font-family: Arial, Helvetica, sans-serif;
  }
 

.button {
  border: 2px;
  border-style: solid;
  border-color: yellow;
  color: Yellow;
  padding: 0px 20px;
  text-align: center;
  text-decoration: bold;
  display: inline-block;
  font-size: 28px;
  margin-top:10;
  margin: 14px 35px;
  cursor: pointer;
  border-radius: 6px;
  width: 170px;
  height: 90px;
background-color: blue;
}
.button:active {
  color:red;
  background-color: yellow;
  transform: translateY(4px);
}

</style>
       
       
       <body>
             <table style="width:750px" class="center">
               <tr>
               <td></td>
               <td><center> <h1><center>Fan Control    </center></h1></center></td>
               </tr>                 
                  <td><center><button class = "button" value='toggle' input type='button' onpointerdown='toggleLed("seven")' onpointerup='toggleLed("seven")' />ON/OFF</center></td>
                   <td><center><button class = "button" input type='hidden' onpointerdown='toggleLed("six")' onpointerup='toggleLed("six")' />OPEN</center></td>
                 <td><center><button class = "button" input type='hidden' onpointerdown='toggleLed("five")' onpointerup='toggleLed("five")' />CLOSE</center></td>
                 </tr>
                  
                  <tr>
                  <td><center><button class = "button" input type='hidden' onpointerdown='toggleLed("four")' onpointerup='toggleLed("four")' />FASTER</center></td>
                  <td><center><button class = "button" input type='hidden' onpointerdown='toggleLed("three")' onpointerup='toggleLed("three")' />SLOWER</center></td>
                 <td><center><button class = "button" input type='hidden' onpointerdown='toggleLed("two")' onpointerup='toggleLed("two")' />REVERSE</center></td>
 </tr>
 <tr>
                 <td><center><button class = "button" input type='hidden' onpointerdown='toggleLed("one")' onpointerup='toggleLed("one")' />LED</center></td>
                  <td><center><button class = "button" input type='hidden' onpointerdown="window.location.href='http://10.10.10.10';" />MAIN SCREEN</center></td>
          <td</td>   
              
 
<tr>
 </table>
            
            
                        
            <script>
                function toggleLed(led){
                    var xhttp = new XMLHttpRequest();
                    xhttp.open('GET', '/led/'+led, true);
                    xhttp.send();
                }
                function update(){
                    location.reload(true);
                }
                    
            </script>
        </body>
    </html>
    """
    return website

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(stag.SSID, stag.PASSWORD)
    
max_wait = 10
print('Waiting for connection')
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        break
    max_wait -= 1    
    sleep(1)
status = None
if wlan.status() != 3:
    raise RuntimeError('Connections failed')
else:
    status = wlan.ifconfig()
    print('connection to', ssid,'succesfull established!', sep=' ')
    print('IP-adress: ' + status[0])
    led.value(1)
ipAddress = status[0]
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(1)

while True:
    try:
        cl, addr = s.accept()

        print('Connection from ', addr, "accepted!")
        request = cl.recv(1024)
        request = str(request)      
       
      
        if request.find('/led/one') == 6:
            led_one.toggle()
            
        if request.find('/led/two') == 6:
            led_two.toggle()
        if request.find('/led/three') == 6:
            led_three.toggle()
        if request.find('/led/four') == 6:
            led_four.toggle()
        if request.find('/led/five') == 6:
            led_five.toggle()
        if request.find('/led/six') == 6:
            led_six.toggle()
        if request.find('/led/seven') == 6:
            led_seven.toggle()
           
            
            
             
        cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
     
        cl.send(Website())
        cl.close()
               
    except OSError as e:
        cl.close()
        led.value(0)        
        print('connection closed')
        led.value(0)
        
    except KeyboardInterrupt:
         machine.reset()
         
         

2 Likes

I removed these two lines and the webserver remains active

    except KeyboardInterrupt:
         machine.reset()
4 Likes

Glad to hear it’s all working now

2 Likes

While removing the lines did make some difference, once the file was made MAIN.PY and moved from the computer to a power supply, it once again disconnected from the WIFI if the webpage wasn’t being connected too.

Still at a loss how to keep the website running on the network without disconnecting apart from having the page active the whole time

2 Likes

Hi John,

Sounds like you have quite the system running!

I havent run into this issue myself but to capture the actual error thats causing the server to timeout you can do the following when catching the errors:

        cl.send(Website())
        cl.close()
               
    except Exception as e:  # This will catch all other exceptions
        with open('error_log.txt', 'a') as f:
            f.write(str(e))  # Convert exception to string and write to file
        print('Unexpected error occurred, check error_log.txt for more info')
        machine.reset()

I however had had a couple issues with MQTT keeping stable and a similar error handler saved most instances.

I’ve found flask to be much more reliable then sending MQTT commands to Picos/other microcontrollers.

Keen to see how you go!
Liam

Full code
import network
import socket
from time import sleep
from machine import Pin

import stag


import time
import ubinascii
led = machine. Pin('LED', machine. Pin. OUT)
wlan = network.WLAN(network.STA_IF)
wlan.active(True)

wlan.connect(stag.SSID, stag.PASSWORD)
ssid, password = (stag.SSID, stag.PASSWORD)
wlan.ifconfig(('192.168.1.221', '255.255.255.0', '192.168.1.1', '8.8.8.8'))

led_one = Pin(13, Pin.OUT)     #led
led_two = Pin(11, Pin.OUT)     #reverse
led_three = Pin(9, Pin.OUT)    #slow
led_four = Pin(8, Pin.OUT)    #fast
led_five = Pin(28, Pin.OUT)    #close
led_six = Pin(27, Pin.OUT)     #open
led_seven = Pin(26, Pin.OUT)  #on/off


led.value(0)

def Website():
    value_one = led_one.value()
    value_two = led_two.value()
    value_three = led_three.value()
    value_four = led_four.value()
    value_five = led_five.value()
    value_six = led_six.value()
    value_seven = led_seven.value()
    website = """<!DOCTYPE html>
    <html>
     <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <head> <title>Fan Control</title> </head>
          
          <style>
*{background-color: black;
  color:yellow;
  font-family: Arial, Helvetica, sans-serif;
  }
 

.button {
  border: 2px;
  border-style: solid;
  border-color: yellow;
  color: Yellow;
  padding: 0px 20px;
  text-align: center;
  text-decoration: bold;
  display: inline-block;
  font-size: 28px;
  margin-top:10;
  margin: 14px 35px;
  cursor: pointer;
  border-radius: 6px;
  width: 170px;
  height: 90px;
background-color: blue;
}
.button:active {
  color:red;
  background-color: yellow;
  transform: translateY(4px);
}

</style>
       
       
       <body>
             <table style="width:750px" class="center">
               <tr>
               <td></td>
               <td><center> <h1><center>Fan Control    </center></h1></center></td>
               </tr>                 
                  <td><center><button class = "button" value='toggle' input type='button' onpointerdown='toggleLed("seven")' onpointerup='toggleLed("seven")' />ON/OFF</center></td>
                   <td><center><button class = "button" input type='hidden' onpointerdown='toggleLed("six")' onpointerup='toggleLed("six")' />OPEN</center></td>
                 <td><center><button class = "button" input type='hidden' onpointerdown='toggleLed("five")' onpointerup='toggleLed("five")' />CLOSE</center></td>
                 </tr>
                  
                  <tr>
                  <td><center><button class = "button" input type='hidden' onpointerdown='toggleLed("four")' onpointerup='toggleLed("four")' />FASTER</center></td>
                  <td><center><button class = "button" input type='hidden' onpointerdown='toggleLed("three")' onpointerup='toggleLed("three")' />SLOWER</center></td>
                 <td><center><button class = "button" input type='hidden' onpointerdown='toggleLed("two")' onpointerup='toggleLed("two")' />REVERSE</center></td>
 </tr>
 <tr>
                 <td><center><button class = "button" input type='hidden' onpointerdown='toggleLed("one")' onpointerup='toggleLed("one")' />LED</center></td>
                  <td><center><button class = "button" input type='hidden' onpointerdown="window.location.href='http://10.10.10.10';" />MAIN SCREEN</center></td>
          <td</td>   
              
 
<tr>
 </table>
            
            
                        
            <script>
                function toggleLed(led){
                    var xhttp = new XMLHttpRequest();
                    xhttp.open('GET', '/led/'+led, true);
                    xhttp.send();
                }
                function update(){
                    location.reload(true);
                }
                    
            </script>
        </body>
    </html>
    """
    return website

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(stag.SSID, stag.PASSWORD)
    
max_wait = 10
print('Waiting for connection')
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        break
    max_wait -= 1    
    sleep(1)
status = None
if wlan.status() != 3:
    raise RuntimeError('Connections failed')
else:
    status = wlan.ifconfig()
    print('connection to', ssid,'succesfull established!', sep=' ')
    print('IP-adress: ' + status[0])
    led.value(1)
ipAddress = status[0]
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(1)

while True:
    try:
        cl, addr = s.accept()

        print('Connection from ', addr, "accepted!")
        request = cl.recv(1024)
        request = str(request)      
       
      
        if request.find('/led/one') == 6:
            led_one.toggle()
            
        if request.find('/led/two') == 6:
            led_two.toggle()
        if request.find('/led/three') == 6:
            led_three.toggle()
        if request.find('/led/four') == 6:
            led_four.toggle()
        if request.find('/led/five') == 6:
            led_five.toggle()
        if request.find('/led/six') == 6:
            led_six.toggle()
        if request.find('/led/seven') == 6:
            led_seven.toggle()
           
            
            
             
        cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
     
        cl.send(Website())
        cl.close()
               
    except Exception as e:  # This will catch all other exceptions
        with open('error_log.txt', 'a') as f:
            f.write(str(e))  # Convert exception to string and write to file
        print('Unexpected error occurred, check error_log.txt for more info')
        machine.reset()

Thank you

I have added to the code and will see what comes up

1 Like

Unfortunately that hasn’t shown anything as its not picking up an error, It just simply stops responding to page requests or pings, so it stops communicating with the wifi but keeps running.

This image is after a few tries and it hasn’t created an error log

1 Like

Hi John,

Thanks for implementing and testing that.

I haven’t had a Pico-based webserver run over multiple refresh cycles like this one. This Reddit post goes through a few possible fixes that would definitely be worth taking a look at:
https://www.reddit.com/r/raspberrypipico/comments/yj46d2/pico_w_stops_running_randomly_after_a_while/
And a couple similar ones from ESP32: esp32: sockets become unresponsive after several larger transactions · Issue #12819 · micropython/micropython · GitHub

Networking isnt one of my strong suits but hopefully one of the links above can assist!
Liam

2 Likes

This is another post on the Raspberry Pi forum that discusses issues with the Pico W and WiFi.
Haven’t read through it in full.
https://forums.raspberrypi.com/viewtopic.php?t=344058

I think we forget the Pico is a microcontroller not a microcomputer. It performs controller tasks very well.
I suggest using a Raspberry Pi-Zero as a basic low cost low power web server; in all the projects I have used it as a web server, the Zero works very well. The Pi 4 would be an overkill.

The Pico WiFi at best is a compromise. I built a project where it wakes up, collects data, connects to WiFi, sends the data then goes back to sleep (read power off). Makerverse Nano Timer wakes it up.

Sometimes a lateral shift is needed in thinking.
Regards
Jim

1 Like

Thanks James

I have read quite a few about this issue. I have narrowed it down to the HTML requests I have another pico running a webserver that only displays coloured boxes when certain pins are active based on how full my tanks are. That one doesn’t have any website input and has no problem with connection. SO Im thinking its in the html request part as that as apart from that, the scripts for connection etc are the same.

1 Like

I was using a Zero for it previously but wanted to just use pico as it would be fine for such a small job rather than the zero. (I have the zero running in the van at the moment).

I really do like to push the picos though. I just think they are under utilised (I have also rewriting it for ESP32 which works fine, but I am like a bull to a red flag now hahahah)

1 Like

Hi John,
I have a project running where two pico’s talk to each other via LoRa modules.
One of the pico’s is a wifi unit connecting to my house LAN and runs a web server.
It runs continuously no problems. I’m up to a few weeks continuous runtime now. :cowboy_hat_face:
Here is a link to the project description I did. (Don’t let the old Pi case fool you)
I may not mention the web page in this project description as it was a later addition but it’s in the code on github.

Don’t let the complexity of the code put you off I have tried to keep it fairly modular.
So it should be fairly readable. No one ever comments on my coding style so I don’t know how readable it actually is. :cowboy_hat_face:

For example mainHouse.py includes a module named webserver.py and module named subprocess.py.

I recall I decided to run the main functionally of the device in a subprocess and run the web server in the main process. (Pico’s have two cores). I think this decision was a bit arbitrary but I do remember swapping them around while trying to solve problems.
This way one process is always listening for web requests while the other process is off doing what ever you are monitoring.
I always include lots of debugging code as I go and set a debug level so I can turn it off when it all works and don’t have to go back and delete anything. Debug output goes to the console (thonny) and to a file so you can solve problems when running with no console. You do need to be a little careful as the debug log can fill up the little file system so I only run debugging on the bit of code I’m testing at the time and some top level stuff so I can tell where things fail
Hope this helps figure out your problem.
David

2 Likes

Thanks David, I will check it out,

As I said, this project is an upgrade in my Campervan to just change the Zeros to Picos so I don’t have to keep buying Zeros for Pico jobs :slight_smile:

The code I have used for the wifi connection is the same as all the picos I have with wifi connection (And they run fine without a problem). The only difference is the HTML code and the request made from the page. As this is the only page that has human intervention by pressing the buttons to perform tasks, I believe this is where I have screwed up the code. This page, unlike all the other pages I have seen to control pins that use individual pages for the OFF press and the ON press, this is a single page that utilizes momentary html push buttons.

The other thing I need to keep in mind, is if I ever sell the camper van, it needs to be simple and bullet proof, something I i have achieved so far using simple wifi network and a single switch that will restart the main Pi4 and the ancillary Picos/Zeros should the power is disconnected. (Plus i’m a tinkerer that won’t give up, just need some guidance occasionally.

So rather than re-invent the wheel with various ways, to make it work, I will persist with learning the html side of it. I have 5 picos between the campervan, and my shed at home that run 24/7 with webpages that display information (no buttons to press though), so it must be in the request code where its failing… I hope hahaha

1 Like

In that case just check out my webpage.py file. It was based on an example I found somewhere.
It has a few buttons on it.
Perhaps you will spot what is different in your code.
Add debug code that writes to a file so you can see where it fails when not connected to a pc.

Make a really simple demo program and add one piece at a time.
David

2 Likes

Alternatively here is what looks like a fairly good example with a decent description

David

1 Like

Just for fun I copied your code onto my pico and connected it to my wifi access point. It seems to run for a while but then I get a time out message in my browser.
“The server at 10.10.10.10 is taking too long to respond.”
My pico has an IP address of 192.168.1.221 which is from my DHCP server. I’m not sure what the 10.10.10.10 address is.

I see a line in the bottom of your HTML
“window.location.href=‘http://10.10.10.10’;” />MAIN SCREEN

Not sure why you would hard code an IP address here.

Maybe you are looking for a complex solution when the cause is something more elementary.

Yes David, This is part of a 3 page control system in the van. Main screen is 10.10.10.10 and is only accessed via the button. The system runs fine WHILE the page is open in a browser, bus as soon as you close the page, thats when it starts to disconnect if you dont reconnect. If you replace the webpage section etc with a static page without buttons, the pico will be happy to stay connected regardless of where the page is open or not. I have had it running for days between connection to the static page and bam straight in no waiting.

As mentioned before, I do have a zero running this similar code at the moment, but I just wanted to downgrade the processor and use the zero for other projects that require an operating system. The third page is another pico with the same python code , Except the webpage is purely a like a digital LED panel which shows the level of the water tanks. This one runs continuously without cutting out, hence why I was saying it must be within the html request code somewhere.

I have a full running system in the van, so if I cant find a solution its no real issue,

Thanks for your input though.

1 Like

Yes, I have seen these but like the others it requires two buttons and two webpages, one for one and one for off. As I have many pages, I wanted to stay away from this style and uses more resources. As my buttons are momentary, that becomes an issue with this type of switch.

My switches are only required to make a .5 second connection through opto couplers to control the fans functions which I have done by hooking into the fans mainboard and duplicating the on the fan control. This way I can access on my phone in the front and operate the fans movements from the front while the fan is at the very back of the van. I can also access the main swithc page for lights etc and see the tank monitor page, all on the phone.

I know, its a geeky van hahahaha

1 Like

John,
I don’t think you are loosing your connection as such. There are no connections, just requests and responses. I think you web server stops listening for requests. Anyway good luck and let us know as things progress. I bet it’s something simple.

1 Like

Hi All

Have a “similar system” but use a pico to mqqt to a zero.
The Zero is in charge of battery management and sends ncat messages to the Ute’s cab and controls charging & load relays.
The pico (mounted on the battery) measures two channels of current to do Coulomb counting and sends updates to the Zero (every minute) for it to display or ncat to the cab.

Although I am using MMBasic as the core system, there are similar challenges
with powering up the pico to recognise the Zero’s Hotspot.
The Zero gets turned off every night whilst camping, but the Pico stays on forever.

I get TCP Disconnected errors. IP address returns 0.0.0.0 every second boot.
So had to write an extensive error checking routine to know when to do a cpu restart.

If you can use a ping every ? seconds/minutes it should keep the connection alive.
Don’t know if that command is available to you, it isn’t in MMBasic.

Regards