Romain
Romain

Reputation: 39

Problems using threading for a webserver on raspberry pi pico W

I'm trying to make a webserver display some data while the pico is collecting it from some pins. Everything works fine for making the webserver running, i'm able to access it with "static" data, but things get tricky having to loop for periodically collect data AND make the webserver running. I have tried to implement this using the _thread library as i've seen on many tutorials/projects, and made it the following to test if it is working (spoiler it's not) :

def serve(connection):
    while True:
        client = connection.accept()[0]
        try:
            html = webpage()
            client.send(html)
        except Exception as e:
            print(f"Error serving client: {e}")
        client.close()

...followed by all my methods for logic etc...

def GetSensorsValues():
    #Here should be all my data inputs stored locally/updated
    print('Test')

ip = connect()
connection = open_socket(ip)
_thread.start_new_thread(serve, (connection,))

while True:
    GetSensorsValues()
    sleep(5)

What i'm not really understanding is that without the call in the _thread the webserver works well, but threaded it is unreachable. I might be missing something on how this thread library works, i would appreciate some help ... Thanks for having considered my request !

Upvotes: 0

Views: 54

Answers (2)

Romain
Romain

Reputation: 39

Thanks for having taken the time to provide all those informations !

Actually i already went onto that forum were someone said that this library might be buggy, but this post was from 2022, and the microcontroller i'm using was also released that year so i thought that maybe it should me more stable today.

Anyway i just switched to using another library called microdot, and everything works fine.

Here is the github repo in case anyone is interested : https://github.com/spacecreep/Raspberry_pi_pico_w_weather_station

It is simply a basic website displaying realtime retrieved data from the pico using websockets.

Upvotes: 0

J_H
J_H

Reputation: 20540

tl;dr: Strip this to the bones, get the threading working, then build it back up.

Thank you for posting the source. I added some code review at the bottom.

cite your reference

tried to implement ... as I've seen on many tutorials / projects

It would be helpful if there were # comments in the source code mentioning the URL of a tutorial this is based on. As written, it does not appear to me that the OP code should be expected to work, as it does not appear to be playing nice with the OS. Ordinarily I would expect to see a class BackgroundLogging(Thread): which we can start, run, and perhaps join if it ever exits.

Mentioning documentation URLs in the source code can be helpful, too. I can't say that I find this encouraging:

https://docs.micropython.org/en/latest/library/_thread.html

This module implements multithreading support.

This module is highly experimental and its API is not yet fully settled and not yet described in this documentation.

Maybe it's supposed to not work?

I didn't notice any automated tests in there, unlike some of the other modules such as time.

independent tasks

Your code has three looping tasks:

  • wait for HTTP request and send HTML result
  • append a new temperature reading to a file
  • print "test" to show we're still alive

Given that "nothing works" currently, I recommend you scale back your ambitions until you have something very simple which is working. Then you can slowly build it up to something fancier, pausing to debug if some tiny addition managed to break things. So start a red, a green, and a blue thread. Each will simply print color + timestamp, briefly sleep, and then loop to repeat. No special ADC hardware is needed, so you can test it on your laptop, see it work, then test on the Pi, and see it work.

I assume the ADC(4) and sensor.read_u16() calls are "fast" and do not block threads. Replacing them with a constant of 0 and then restoring the original call will let you verify that during testing.

networking

Aren't you supposed to import usocket as socket ?

file format

After your code has been successfully working for a day, each temperature poll will have to write out 8640 lines of temperature data, which seems like 8639 lines too many. I recommend you abandon JSON format and prefer to import csv. Then you can append a single line and flush() it out.

A fancier approach would use the builtin sqlite database. That way you could store a year's worth of readings, and use an indexed table to quickly get just today's temperatures.


Here is some unrelated code review.

You might rename open_socket() to open_web_socket().

pathlib

def file_exists(filepath):
    try:
        os.stat(filepath)  # Check if the file exists
        return True
    except OSError:
        return False

We can tighten this up by preferring the newer pathlib which has been available since 2022.

from pathlib import Path

def file_exists(filepath: str) -> bool:
    return Path(filepath).exists()

Upvotes: 0

Related Questions