4

I`m trying to run an Microdot app.run() that is asyncio with other functions that are also asyncio and I keep getting that the Microdot.start_server() was never awaited

in this case the other function is run_thermostat() that is an asyncio function that is running fine if I do not start at all the Microdot app.run()

I need some help on how to use Microdot app.run() to run along with other functions in a forever loop

I`m a beginner in python, but a learning enthusiast. This is my first post on stackoverflow that helped me alot until this point so please be kind :)

from microdot_asyncio import Microdot
import asyncio
from asyncio import gather

class Thermostat:
    def __init__(self):
        self.current_temp = 0
        self.target_temp = 0
        ###
        
        self.loop = asyncio.get_event_loop()
    
    def call__async_main(self):
        self.loop.run_until_complete(self.__async_main())
        print(self.loop)
    
    async def __async_main(self):
    ####does not work | sys:1: RuntimeWarning: coroutine 'Microdot.start_server' was never awaited
        await gather(
            self.start_web_server(),
            self.run_thermostat(),
            )

    ##### does not work | sys:1: RuntimeWarning: coroutine 'Microdot.start_server' was never awaited
        # task1 = asyncio.create_task(self.run_thermostat())
        # task2 = asyncio.create_task(self.start_web_server())
        # # Iterate over the tasks and wait for them to complete one by one
        # for task in asyncio.as_completed([task1, task2]):
        #     await task
        
    ####### does not work | sys:1: RuntimeWarning: coroutine 'Microdot.start_server' was never awaited
        # task1 = asyncio.create_task(self.run_thermostat())
        # task2 = asyncio.create_task(self.start_web_server())
        # await task1
        # await task2
        # self.loop.create_task(task1)
        # self.loop.create_task(task2)

    #####other method | does not work | sys:1: RuntimeWarning: coroutine 'Microdot.start_server' was never awaited
        # await self.start_web_server()
        # await self.run_thermostat()

    #Function for starting Microdot web-server API
    def start_web_server(self):
        app.run()

    # Function to read the current temperature from a temperature sensor
    async def read_temperature(self):
        # read temperature from sensor 
        self.current_temp = 15  # ex: set the current temperature to 15 //simulate

    # Function to set the target temperature
    def set_target_temp(self, temp):
        self.target_temp = temp

    # Function to start or stop the heating system based on the current and target temperatures
    def control_heating(self):
        if self.current_temp < self.target_temp:
            
            # Turn on the heating system 
            print("Starting heating system")
        else:
            # Stop the heating system
            
            print("Stopping heating system")

# Function to run the thermostat control loop
    async def run_thermostat(self):
        while True:
            # Read the current temperature from the sensor
            await thermostat.read_temperature()

            # Control the heating system based on the current and target temperatures
            thermostat.control_heating()

            # Wait for a short time before checking the temperature again
            await asyncio.sleep(1)

#Instantiating Microdot app
app = Microdot()
# Set up a route to allow users to set the target temperature
@app.route('/set_target_temp')
def set_target_temp(request):
    # Get the target temperature from the request
    target_temp = int(request.args['temp'])

    # Set the target temperature on the thermostat
    thermostat.set_target_temp(target_temp)

    # Return a response to confirm the target temperature has been set
    return "Target temperature set to {}".format(target_temp)

# Create an instance of the Thermostat class
thermostat = Thermostat()

#===###
# Start the system
thermostat.call__async_main()

#===###

# Start the Microdot app
# asyncio.create_task(app.run())
# app.run()

# Start the thermostat control loop
# asyncio.create_task(run_thermostat())
################################################



1 Answers1

3

Never mind, I have found the solution, here it is:

    async def __async_main(self):
    ##### does work OK
        task1 = self.loop.create_task(self.run_thermostat())
        task2 = self.loop.create_task(self.start_web_server())
        # Iterate over the tasks and wait for them to complete one by one
        for task in asyncio.as_completed([task1, task2]):
            await task

and the Microdot should be started with app.server_start() and not by app.run() like this:

    #Function for starting Microdot web-server API
    async def start_web_server(self):
      await app.start_server(port=5000, debug=True)

Now, the Microdot web api runs along with other async tasks

In conclusion the main problem was starting the Microdot with app.run() , and also I had to add the task in the loop event like this:

task2 = self.loop.create_task(self.start_web_server())

before was:

task2 = asyncio.create_task(self.start_web_server())

and in this way it does not append into the loop, this loop:

self.loop = asyncio.get_event_loop()

Here is the complete working code:

from microdot_asyncio import Microdot
import asyncio

class Thermostat:
    def __init__(self):
        self.current_temp = 0
        self.target_temp = 0        
        self.loop = asyncio.get_event_loop()
    
    def call__async_main(self):
        self.loop.run_until_complete(self.__async_main())
        # print(self.loop)
    
    async def __async_main(self):
    ##### does work OK
        task1 = self.loop.create_task(self.run_thermostat())
        task2 = self.loop.create_task(self.start_web_server())
        # Iterate over the tasks and wait for them to complete one by one
        for task in asyncio.as_completed([task1, task2]):
            await task
        
    ####### does work OK
        # task1 = self.loop.create_task(self.run_thermostat())
        # task2 = self.loop.create_task(self.start_web_server())
        # await task1
        # await task2

    #Function for starting Microdot web-server API
    async def start_web_server(self):
      await app.start_server(port=5000, debug=True)

    # Function to read the current temperature from a temperature sensor
    async def read_temperature(self):
        # read temperature from sensor 
        self.current_temp = 15  # ex: set the current temperature to 15 //simulate

    # Function to set the target temperature
    def set_target_temp(self, temp):
        self.target_temp = temp

    # Function to start or stop the heating system based on the current and target temperatures
    def control_heating(self):
        if self.current_temp < self.target_temp:
            
            # Turn on the heating system 
            print("Starting heating system")
        else:
            # Stop the heating system
            
            print("Stopping heating system")

# Function to run the thermostat control loop
    async def run_thermostat(self):
        while True:
            # Read the current temperature from the sensor
            await thermostat.read_temperature()

            # Control the heating system based on the current and target temperatures
            thermostat.control_heating()

            # Wait for a short time before checking the temperature again
            await asyncio.sleep(1)

#Instantiating Microdot app
app = Microdot()
# Set up a route to allow users to set the target temperature
@app.route('/set_target_temp')
def set_target_temp(request):
    # Get the target temperature from the request
    target_temp = int(request.args['temp'])

    # Set the target temperature on the thermostat
    thermostat.set_target_temp(target_temp)

    # Return a response to confirm the target temperature has been set
    return "Target temperature set to {}".format(target_temp)

# Create an instance of the Thermostat class
thermostat = Thermostat()

#===###
# Start the system
thermostat.call__async_main()

#===###

you can navigate to your ESP32 IP or localhost and enter this link to change the target_temp variabile:

http://localhost:5000/set_target_temp?temp=21

... you should then see in the VScode console : Starting heating system .... if you enter another int query parameter for the temp like this:

http://localhost:5000/set_target_temp?temp=12

...you shoud see in the VScode console : Stopping heating system

CONCLUSION:

  • the code works
  • the run_thermostat() function runs along (asyncio) with app = Microdot() and does what is supposed to do
  • the Microdot decorator @app.route('/set_target_temp') works OK