2013-06-20 91 views
1

編輯#2:所以猜猜看,我快到了!我正面臨着似乎是我的最後一個問題,好吧,只要編程方面。 這其實很有趣,我以前從來沒有遇到過這樣的事情。 問題出在下面的代碼中,我的javascript函數。我通常不會發布看起來很容易解決的問題,但我真的不知道這裏發生了什麼。Cherrypy和JSON Arduino網絡界面

這個問題似乎是在更新函數的第一個條件。看到說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閃爍,如配置),然後發送一條消息,Python腳本檢索數據,但它不能正確顯示。該字符串遺漏了一些字符,並且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') 

回答

1

首先,我did'nt想在你前面的問題告訴你有關,但前陣子我寫了一個軟件叫pyaler那不正是你想要(除了它不支持長輪詢請求,因爲它是(是?)一個wsgi限制)。

爲了回答你的問題,爲什麼不讓你的表單成爲一個發送動作的javascript查詢,並以JSON的形式獲得結果,你可以用結果解析和更新當前頁面?這是更優雅,簡單和2013年...

可悲的是我不能告訴,給你的代碼,爲什麼你沒有得到結果。如果它真的做到了你想要做的事情,那太複雜了...... KISS!

避免在模塊範圍內做任何事情,除非你把它放在if __name__ == "__main__"中,或者你希望通過導入它來擴展你的模塊的那一天,你會順便執行一些代碼,並且它會強制做出更好的設計爲你的代碼。

您可以將InterruptableThread()類從超時函數中取出,並將其作爲參數defaultInterruptableThread(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,並且方法會讀取輸出。

由於網絡服務器可能會對串行對象上的讀取/寫入方法創建並行調用,並且您無法並行讀取同一個對象,因此您可能希望創建一個獨立的線程,方法是創建一個新的類別 從threading.Thread繼承,您實現讀取串行輸出 的無限循環(通過將串行對象作爲參數提供給該類'__init__函數)。 然後,如果您希望保留所有以前的數據的日誌,或者如果您只希望返回最後一次讀數,則可以將每個新的content數據推送到list或 a 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

+0

嘿我編輯了我原來的帖子,你能不能請讀,它很短。非常感謝你的幫助。 – user2501169

+0

我的回答已更新 – zmo

+0

嘿最後一個(我希望)更新,這個魅力很強,只是看你自己。 – user2501169