线程与python,cherrypy和pyserial

时间:2013-06-19 12:54:55

标签: python arduino cherrypy pyserial python-multithreading

所以我编写了一个Web界面来与Arduino Uno交互,使用cherrypy和pyserial。它非常完整,我唯一缺少的,而且我一直试图找出一天,就是不断读取Arduino发送的数据,并自动显示包含html代码中的消息的div。我可以在控制台中显示它,但我无法返回实际的html。事实上,我无法使用return,我必须使用print,这不方便,因为我想要html页面中的数据,而不是控制台。 我已经尝试了很多方法来做到这一点。

这是我的代码,非常简单。常量函数继续读取从Arduino发送的数据,并将其发送到控制台。我希望它将它发送到html代码,就像实时更新一样。我该怎么做?

# -*- coding: Utf-8 -*-

import cherrypy, arduino, time, threading

ser=arduino.Serial('COM4', 9600)

def constant():
    while True:
        m=''
        print('running')
    while True:
        print('sub_running')
        byte=(ser.read().encode('Utf-8'))
        if byte=='*':
            break
        m=m+byte
        time.sleep(1)
    print(m)
    time.sleep(1)

class website(object):
    def index(self):
        return '''
            <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" ></script><script src="annexes/functions.js"></script>
            <link rel=stylesheet type=text/css media=screen href="/annexes/design.css">
            <form action="command" method="POST">
            <input type="submit" name="command" value="Turn the LED on" text="hey"/>
            <input type="submit" name="command" value="Turn the LED off"/>
            </form>
        '''    
    index.exposed=True

    def command(self, command):
        m=''
        if command=='Turn the LED on':
            ser.write('1')
        if command=='Turn the LED off':
            ser.write('0')
        self.index
    command.exposed=True

_thread = threading.Thread(target=constant)
_thread.setDaemon(True)
_thread.start()

cherrypy.quickstart(website(), config='config.conf')

1 个答案:

答案 0 :(得分:0)

让它做你想做的事你有两个选择:

  • 使生成的网页在每次显示时都打印动态数据,并在客户端添加元刷新(或javascript刷新)或
  • 制作一个长轮询路线,每当新数据进入时都会更新(请参阅此example

但我认为您的问题的核心与如何将线程函数中的值发送到您的网站类有关。您需要使用Queue.Queue: 这些示例显示了如何使用cherrypy进行长轮询请求。

在以下示例中,您将错过this site上提供的jsonyield装饰器,这是了解樱桃和长轮询的好方法。

# -*- coding: utf-8 -*-

import cherrypy, arduino, time, threading
import Queue

def serialWatcher(ser, queue):
    while True:
        m=''
        print('running')
    while True:
        print('sub_running')
        byte=(ser.read().encode('Utf-8'))
        if byte=='*':
            break
        m=m+byte
        time.sleep(1)
    queue.put(m)
    time.sleep(1)

class website(object):
    def __init__(self, ser, queue):
        self.serial = ser
        self.queue = queue

    # it's often better to use decorators when you can
    @cherrypy.expose
    def index(self):
        return '''
            <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" ></script><script src="annexes/functions.js"></script>
            <link rel=stylesheet type=text/css media=screen href="/annexes/design.css">
            <form action="command" method="POST">
            <input type="submit" name="command" value="Turn the LED on" text="hey"/>
            <input type="submit" name="command" value="Turn the LED off"/>
            </form>
        '''

    @cherrypy.expose
    def command(self, command):
        m=''
        if command=='Turn the LED on':
            self.serial.write('1')
        if command=='Turn the LED off':
            self.serial.write('0')
        return self.index() # I assume that's what you wanted to write

    @cherrypy.expose
    @json_yield
    def get_arduino_results(self):
        """you can get the result of this long polling request using a JS AJAX query"""
        while True:
            while not self.queue.empty():
                yield self.queue.get()


# always use the following, so you can also use the module you're writing as imports
# in other modules
if __name__ == "__main__":
    q = Queue.Queue()
    # Never use global variables, always pass them as parameters
    ser = arduino.Serial('COM4', 9600) 

    _thread = threading.Thread(target=serialWatcher, args=(ser, q))
    _thread.setDaemon(True)
    _thread.start()

    cherrypy.quickstart(website(ser, q), config='config.conf')

but the same principle would work for a standard page, something like:

    @cherrypy.expose
    get_arduino_results(self):
        out = "<ul>"
        while not self.queue.empty():
            out += "<li>" + self.queue.get() + "</li>"
        return out + "</ul>

使用Queue的整个想法是,在你的arduino观看线程和cherrypy线程之间交换信息时,你不会冒险遇到线程问题。队列是线程安全的,并且同步读/写以使它们按顺序排列,并且一次一个线程。

HTH