Picoweb and temperature read in the loop (uasyncio)

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
Post Reply
mvincm
Posts: 9
Joined: Sun Sep 17, 2017 10:59 pm

Picoweb and temperature read in the loop (uasyncio)

Post by mvincm » Sun Sep 17, 2017 11:02 pm

Hello,

I would like to use ESP32 (with micropython) and picoweb to made some thermostat. I will get and set temperature via picoweb "web app". To communicate I will use simple json messages... but I need to check temperature every e.g. 2 minutes, compare it to stored one and turn on or off my heater.

So my idea is:

in file "init.py" I will add second scheduled job:

loop.create_task(asyncio.start_server(self._handle, host, port))
loop.create_task(check_temperature())

then define this function (outside WebApp class) and put some code to read temperature and turn on/off heater

async def check_temperature():
while True:
#check temperature
# some IFs
# turn on/off heater
await asyncio.sleep(120)

And the question is... Is this the right way to do this? Any better solution?

Best regards,
MvincM

User avatar
MostlyHarmless
Posts: 147
Joined: Thu Nov 21, 2019 6:25 pm
Location: Pennsylvania, USA

Re: Picoweb and temperature read in the loop (uasyncio)

Post by MostlyHarmless » Thu Dec 05, 2019 4:07 am

I am aware that this is an old thread, but I have been wondering the same lately and none of the "web server" packages out there seem to have a clear answer to that question, which is

"how do I combine my uasyncio coros with a web server?"

For now I created https://github.com/pfalcon/picoweb/pull/59

It would be one clean way.


Regards, Jan

User avatar
MostlyHarmless
Posts: 147
Joined: Thu Nov 21, 2019 6:25 pm
Location: Pennsylvania, USA

Re: Picoweb and temperature read in the loop (uasyncio)

Post by MostlyHarmless » Thu Dec 05, 2019 2:09 pm

Actually that change is entirely obsolete.

Digging further I realized that the uasyncio event loop is a global thing, not an instance created by get_event_loop(). This means that the right way to do this is:

Code: Select all

loop = asyncio.get_event_loop()
loop.create_task(do_something())

app.run(debug = True, host = "0.0.0.0", port = 80, log = log)
Regards, Jan

User avatar
pythoncoder
Posts: 4234
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

New uasyncio version

Post by pythoncoder » Thu Dec 05, 2019 3:24 pm

Just FYI there is a new version of uasyncio in the pipeline which is based on CPython 3.8 asyncio syntax. In normal programming the event loop is completely ignored. Applications are started with

Code: Select all

import uasyncio as asyncio
asyncio.run(coroutine())
The new version is at quite an advanced stage of development and hopefully will be merged soon. In asyncio V3.8 docs the use of the event loop is deprecated.
Peter Hinch

User avatar
MostlyHarmless
Posts: 147
Joined: Thu Nov 21, 2019 6:25 pm
Location: Pennsylvania, USA

Re: New uasyncio version

Post by MostlyHarmless » Thu Dec 05, 2019 4:43 pm

pythoncoder wrote:
Thu Dec 05, 2019 3:24 pm
Just FYI there is a new version of uasyncio in the pipeline which is based on CPython 3.8 asyncio syntax. In normal programming the event loop is completely ignored. Applications are started with
Thanks for the heads up. I probably should merge that into a local branch and use that.

User avatar
MostlyHarmless
Posts: 147
Joined: Thu Nov 21, 2019 6:25 pm
Location: Pennsylvania, USA

Re: New uasyncio version

Post by MostlyHarmless » Thu Dec 05, 2019 6:26 pm

MostlyHarmless wrote:
Thu Dec 05, 2019 4:43 pm
Thanks for the heads up. I probably should merge that into a local branch and use that.
Looking good. Here is the complete example (slightly modified example_webapp2.py from picoweb):

Code: Select all

#
# This is a picoweb example showing a web page route
# specification using view decorators (Flask style)
#
import logging 
import picoweb
import uasyncio as asyncio

app = picoweb.WebApp(__name__)

@app.route("/")
def index(req, resp):
    yield from picoweb.start_response(resp)
    yield from resp.awrite("I can show you a table of <a href='squares'>squares</a>.\r\n")

@app.route("/squares")
def squares(req, resp):
    yield from picoweb.start_response(resp)
    yield from resp.awrite("Oh well, I lied\r\n")

async def do_something():
    count = 0
    while True:
        await asyncio.sleep(2)
        count += 1
        print("doing something", count)

logging.basicConfig(level=logging.INFO)
applog = logging.getLogger("picoweb")

asyncio.create_task(do_something())
app.run(host = "0.0.0.0", port = 80, log = applog)
I symlinked the uasyncio.py from extmod to ports/esp32/modules. Not sure that is how it was intended, but it was easy and works.

picoweb's run() still uses get_event_loop(), but that's just confirming that the backwards compatibility is working in a mixed usage environment.

Pretty cool stuff!


Regards, Jan

User avatar
pythoncoder
Posts: 4234
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: New uasyncio version

Post by pythoncoder » Fri Dec 06, 2019 10:24 am

MostlyHarmless wrote:
Thu Dec 05, 2019 6:26 pm
...
I symlinked the uasyncio.py from extmod to ports/esp32/modules. Not sure that is how it was intended, but it was easy and works...
A good way to try it out; the final implementation is up for grabs. I suggested a Python package so synchronisation primitives may be loaded independently, saving RAM where they are not required. The doc also proposes other changes.

@Damien also mentioned implementing parts of it in C for performance - although even in Python performance is pretty good ;)

We will see what he decides.
Peter Hinch

Post Reply