【问题标题】:Cherrypy and JSON Arduino web interfaceCherrypy 和 JSON Arduino 网络界面
【发布时间】:2013-06-20 16:30:10
【问题描述】:

编辑#2:猜猜看,我快到了!我正面临着似乎是我最后一个问题,好吧,只要涉及到编程。 这实际上很有趣,我以前从未遇到过这样的事情。 问题出在下面的代码中,我的 javascript 函数。我通常从不发布看起来很容易解决的问题,但我真的不知道这里发生了什么。

问题似乎出在更新功能的第一个条件中。请参阅 alert('hey'); ?好吧,如果我删除那条线,由于某种未知的原因,没有任何东西被发送到动作函数。也不是 Arduino,也不是控制台……什么都没有发生。正如我喜欢这样称呼它,这绝对是迷人的。我不知道。我想也许 alert() 造成了读取 arduino 输出所必需的某种延迟,但是当我使用 setTimeout 创建延迟时,也没有任何反应。太不可思议了。

再一次:没有警报,操作函数不会被调用,我通过让函数打印一些东西来检查它是否被调用。什么都没有打印,什么都没有。它只是没有被调用。但是有了警报,函数就会被调用,并且 arduino 会打开 LED。

你有什么解释吗?这是我的代码:

function update(command=0) {
// if command send it
if (command!=0) {
    $.getJSON('/action?command='+command);
    alert('hey');
}

// read no matter what
$.getJSON('/read', {}, function(data) {
    if (data.state != 'failure' && data.content != '') {
        $('.notice').text(data.content);
        $('.notice').hide().fadeIn('slow');
        setTimeout(function () { $('.notice').fadeOut(1000); }, 1500);
    }
    setTimeout(update, 5000);
});
}

update();

我正在尝试创建一个可从任何计算机访问的 Web 界面来控制我的 Arduino。 我越来越近了。我的一个问题是,使用以下代码,当我按下按钮向 Arduino 发送命令时,Arduino 确实得到了它(LED 按照配置闪烁),然后发送消息,@987654322 @ 脚本确实检索数据,但它没有正确显示它。字符串遗漏了一些字符,index.html 未按预期返回。

基本上,按下按钮时会调用一个函数,我需要在与生成结果的函数不同的函数中返回函数的结果。

代码如下:

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

import cherrypy, functools, json, uuid, serial, threading, webbrowser, time

try:
    ser = serial.Serial('COM4', 9600)
    time.sleep(2)
    ser.write('1')
except:
    print('Arduino not detected. Moving on')

INDEX_HTML = open('index.html', 'r').read()

def timeout(func, args = (), kwargs = {}, timeout_duration = 10, default = None):
    class InterruptableThread(threading.Thread):
        def __init__(self):
            threading.Thread.__init__(self)
            self.result = default
        def run(self):
            self.result = func(*args, **kwargs)

    it = InterruptableThread()
    it.start()
    it.join(timeout_duration)
    if it.isAlive():
        return it.result
    else:
        return it.result

def get_byte(useless):
    return ser.read().encode('Utf-8')

def json_yield(command):
    @functools.wraps(command)
    def _(self, command):
        if (command == 'Turn the LED on'):
            ser.write('2')
            time.sleep(2)
            print('wrote to port')
        print('ok, ok')
        try:
            m = ''
            while 1:
                print('reading...')
                byte = timeout(get_byte, ('none',), timeout_duration = 5)
                if byte == '*' or byte == None: break
                m = m + byte
            content = m
            time.sleep(1)
            return json.dumps({'state': 'ready', 'content':content})
        except StopIteration:
            return json.dumps({'state': 'done', 'content': None})
    return _

class DemoServer(object):
    @cherrypy.expose
    def index(self):
        return INDEX_HTML

    @cherrypy.expose
    @json_yield
    def yell(self):
        yield 'nothing'

    @cherrypy.expose
    @json_yield
    def command(self):
        yield 'nothing'

if __name__ == '__main__':
    t = threading.Timer(0.5, webbrowser.open, args=('http://localhost:8080',))
    t.daemon = True
    t.start()
    cherrypy.quickstart(DemoServer(), config='config.conf')

【问题讨论】:

    标签: python arduino cherrypy


    【解决方案1】:

    首先,我没想过在你之前的问题中告诉你,但不久前我写了一个名为 pyaler 的软件,它完全符合你的要求(除了它不支持长轮询请求,因为它(曾经?)是 wsgi 限制)。

    要回答您的问题,为什么不让您的表单成为发送操作的 javascript 查询,并以 JSON 格式获取结果,您可以解析并使用结果更新当前页面?这样更优雅、更简单,而且 2013...

    很遗憾,鉴于您的代码,我无法真正说出为什么您没有得到结果。理解它是否真的按照您的意愿做的事情太过复杂了......亲!

    避免在模块范围内做任何事情,除非你把它放在if __name__ == "__main__",或者你想通过导入来扩展你的模块的那一天,你会偶然执行一些代码,它会迫使你做出更好的为您的代码设计。

    您可以将InterruptableThread() 类从超时函数中取出,并将default 作为参数提供给它。 InterruptableThread(default)def __init__(self, default): self.result = default。但是说到这部分,为什么你做这么复杂的事情,而你有一个timeout argument 你可以在创建串行连接时使用?

    下面是我要对您的代码进行的轻微修改:

    # -*- coding: utf-8 -*-
    
    import cherrypy, functools, json, uuid, serial, threading, webbrowser, time
    
    def arduino_connect(timeout=0):
        try:
            ser=serial.Serial('COM4', 9600, timeout=timeout)
            time.sleep(2)
            ser.write('1')
            return ser
        except:
            raise Exception('Arduino not detected. Moving on')
    
    class ArduinoActions(object):
        def __init__(self, ser):
            self.ser = ser
    
        def get_data(self):
            content = ""
            while True:
                print('reading...')
                data = self.ser.read().encode('utf-8')
                if not data or data == '*':
                    return content
                content += data
    
        def turn_led_on(self):
            ser.write('2')
            time.sleep(2)
            print('wrote led on to port')
    
        def turn_led_off(self):
            ser.write('2') # Replace with the value to tur the led off
            time.sleep(2) 
            print('wrote to led off port')
    
    class DemoServer(ArduinoActions):
        def __init__(self, ser):
            ArduinoActions.__init__(self, ser)
            with open('index.html', 'r') as f:
                self.index_template = f.read()
    
        @cherrypy.expose
        def index(self):
            return self.index_template
    
        @cherrypy.expose
        def action(self, command):
            state = 'ready'
            if command == "on":
                content = self.turn_led_on()
            elif command == "off":
                content = self.turn_led_off()
            else:
                content = 'unknown action'
                state = 'failure'
            return {'state': state, 'content': content}
    
        @cherrypy.expose
        def read(self):
            content = self.get_data()
            time.sleep(1)
            # set content-type to 'application/javascript'
            return content
    
    if __name__ == '__main__':
        ser = arduino_connect(5)
        # t = threading.Timer(0.5, webbrowser.open, args=('http://localhost:8080',))
        # t.daemon = True
        # t.start()
        cherrypy.quickstart(DemoServer(), config='config.conf')
    

    在您的 javascript 代码中,您正在调用 yell 资源,但实际上没有返回任何内容。 你最好创建一个action 方法(因为我修改了给定的python 代码)和一个单独的read() 方法。 所以你 action 方法将通过写入字节来作用于 arduino,从而向 arduino 发出命令,并且 read 方法将读取输出。

    由于网络服务器可能会创建对串行对象的读/写方法的并行调用,并且 你不能并行读取同一个对象,你可能想通过创建一个独立的线程 一个继承自threading.Thread 的新类,您实现了一个读取输出的无限循环 串行(通过将串行对象作为参数提供给该类的__init__ 函数)。 然后将每个新的content 数据推送到list,如果您想保留所有以前数据的日志,或者 Queue.Queue 如果您只想返回最后一个读数。然后从ArduinoActions,在read() 方法你只需要返回list,它会随着来自arduino的任何新读数而增长,并且 因此记录所有数据(如果有队列,则获取最后一个数据)。

    $(function() {
        function update(command) {
            // if you give a command argument to the function, it will send a command
            if (command) {
                $.getJSON('/action?command='+command);
            }
            // then it reads the output
            $.getJSON('/read, {}, function(data) {
            if (data.state !== 'failure' && data.content !== '') {
                $('.notice').text(data.content);
                $('.notice').hide().fadeIn('fast');
                setTimeout(function () { $('.notice').fadeOut('fast'); }, 1500);
            }
            // and rearms the current function so it refreshes the value
            setTimeout(update(), 2); // you can make the updates less often, you don't need to flood your webserver and anyway the arduino reading are blocking
        });
    }
    update();
    });
    

    始终在 javascript 中使用 ===!==,因此不要强制输入。您可以不那么频繁地再次调用该函数 如果您不评估 javascript 参数,则默认情况下将其设置为未定义。

    这只是对你所写内容的一点更新,现在已经很晚了,所以我希望你能从中有所收获!

    HTH

    【讨论】:

    • 嘿,我编辑了我原来的帖子,你能看一下吗,很短。非常感谢您的帮助。
    • 嘿,最后一个(希望)更新,这个魅力很强,自己看吧。
    • 你知道,你应该对最后一个针对 javascript 受众的问题提出另一个问题。 SO 的目标是制作可以帮助您的问答,同时也可以帮助任何通过 google 到达这里的人。而且你更新的问题越多,它就越具体和不清楚,它对面临类似问题的用户的帮助就越少。
    • 首先,您没有阅读我的评论,command=0 参数没有用 argument 单独有效,如果您不提供,将设置为 undefined。您的 if 条件应该是 if (!command),而不是 if (command!=0)。我建议您在函数中添加console.log() 打印输出,以更好地了解发生了什么。我不认为alert() 与您的功能无法正常工作直接相关,但除此之外还有另一个错误。您应该将其作为另一个针对 JS 受众的问题。 (并将问题恢复到之前的状态,这已经非常具体了)
    猜你喜欢
    • 1970-01-01
    • 2021-04-20
    • 2010-10-08
    • 2016-06-02
    • 2013-12-14
    • 1970-01-01
    • 2021-03-04
    • 1970-01-01
    • 2010-10-19
    相关资源
    最近更新 更多