0

I am running a web server on a raspberry pi which is logging temperatures etc. I am using websockets in Tornado to communicate with my client. I want the client to be able to control when the server is sending data over the socket.

My thought was that when client connects and says it's ready, the server will start a loop where it logs temps every second. But I need this loop to run asynchronously. This is where I get in trouble. I tried to follow an example, but I cant get it to run properly.

class TemperatureSocketHandler(tornado.websocket.WebSocketHandler):

    @gen.coroutine
    def async_func(self):
        num = 0
        while(self.sending):
            num = num + 1
            temp = self.sense.get_temperature()
            yield self.write_message(str(temp))
            gen.sleep(1)

    def open(self):
        print("Temperature socket opened")
        self.sense = SenseHat()
        self.sense.clear()
        self.sending = False

    def on_message(self, message):
        if(message == "START"):
            self.sending = True
        if(message == "STOP"):
            self.sending = False

        tornado.ioloop.IOLoop.current().spawn_callback(self.async_func(self))

But I get an error here when I run this:

ERROR:tornado.application:Exception in callback functools.partial(<function wrap.<locals>.null_wrapper at 0x75159858>)
Traceback (most recent call last):
  File "/home/pi/.local/lib/python3.5/site-packages/tornado/ioloop.py", line 605, in _run_callback
    ret = callback()
  File "/home/pi/.local/lib/python3.5/site-packages/tornado/stack_context.py", line 277, in null_wrapper
    return fn(*args, **kwargs)
TypeError: 'Future' object is not callable
2
  • Please fix the indentations. Do you call spawn_callback in on_message? Commented Feb 19, 2018 at 8:05
  • Sorry, fixed now Commented Feb 19, 2018 at 8:08

1 Answer 1

1

You have to use IOLoop.add_future() since async_func() returns a Future (it is decorated as a coroutine!).

Also, you should add the future, when you receive the start message, not on any message:

def on_message(self, message):
        if(message == "START"):
            self.sending = True
            tornado.ioloop.IOLoop.current().add_future(
                self.async_func(self), lambda f: self.close())
        if(message == "STOP"):
            self.sending = False
Sign up to request clarification or add additional context in comments.

2 Comments

The documentation says that I need two arguments to add_future. the second one is a callback. What should this function be? I'm not very experienced with callback functions etc.
You are right, of course. You must specify a callback. It is called when async_func() returns (i.e. the Future of async_func has a result). In the case of your WebSocket handler, it would be useful to close the socket. Alternatively you could send the client a "goodbye" message (and then close the socket).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.