zoukankan      html  css  js  c++  java
  • [记录]python使用serial模块实现实时WebConsole

    ###tornado+websocket+多进程实现:

    1.index.html

    <!DOCTYPE HTML>
    <html>
      <head>
        <style>
          body { margin: 0px; padding: 20px; }
          #received {  500px; height: 400px; border: 1px solid #dedede; overflow-y:scroll;}
          #sent {  500px; } 
        </style>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script type="text/javascript" src="static/main.js"></script>
      </head>
      <body>
      <h1>Websockets serial console</h1>
    
      <p>Data received from serial port</p>
      <div id="received">
      </div>
      <button id="clear">Clear</button>
      
      <p>Send data to serial port</p>
      <form id="sent">
      	<input type="text" id="cmd_value">
      	<button id="cmd_send">Send</button>
      </form>
      </body>
    </html>

    2.main.js

    $(document).ready(function(){
    
    var received = $('#received');
    
    
    var socket = new WebSocket("ws://localhost:8080/ws");
     
    socket.onopen = function(){  
      console.log("connected"); 
    }; 
    
    socket.onmessage = function (message) {
      console.log("receiving: " + message.data);
      received.append(message.data);
      received.append($('<br/>'));
    };
    
    socket.onclose = function(){
      console.log("disconnected"); 
    };
    
    var sendMessage = function(message) {
      console.log("sending:" + message.data);
      socket.send(message.data);
    };
    
    
    // GUI Stuff
    
    
    // send a command to the serial port
    $("#cmd_send").click(function(ev){
      ev.preventDefault();
      var cmd = $('#cmd_value').val();
      sendMessage({ 'data' : cmd});
      $('#cmd_value').val("");
    });
    
    $('#clear').click(function(){
      received.empty();
    });
    
    
    });

    3.serialworker.py

    import serial
    import time
    import multiprocessing
    
    ## Change this to match your local settings
    SERIAL_PORT = '/dev/ttyACM0'
    SERIAL_BAUDRATE = 115200
    
    class SerialProcess(multiprocessing.Process):
     
        def __init__(self, input_queue, output_queue):
            multiprocessing.Process.__init__(self)
            self.input_queue = input_queue
            self.output_queue = output_queue
            self.sp = serial.Serial(SERIAL_PORT, SERIAL_BAUDRATE, timeout=1)
     
        def close(self):
            self.sp.close()
     
        def writeSerial(self, data):
            self.sp.write(data)
            # time.sleep(1)
            
        def readSerial(self):
            return self.sp.readline().replace("
    ", "")
     
        def run(self):
     
        	self.sp.flushInput()
     
            while True:
                # look for incoming tornado request
                if not self.input_queue.empty():
                    data = self.input_queue.get()
     
                    # send it to the serial device
                    self.writeSerial(data)
                    print "writing to serial: " + data
     
                # look for incoming serial data
                if (self.sp.inWaiting() > 0):
                	data = self.readSerial()
                    print "reading from serial: " + data
                    # send it back to tornado
                	self.output_queue.put(data)

    4.server.py

    import tornado.httpserver
    import tornado.ioloop
    import tornado.web
    import tornado.websocket
    import tornado.gen
    from tornado.options import define, options
    import os
    import time
    import multiprocessing
    import serialworker
    import json
     
    define("port", default=8080, help="run on the given port", type=int)
     
    clients = [] 
    
    input_queue = multiprocessing.Queue()
    output_queue = multiprocessing.Queue()
    
    
    
    class IndexHandler(tornado.web.RequestHandler):
        def get(self):
            self.render('index.html')
    
    class StaticFileHandler(tornado.web.RequestHandler):
    	def get(self):
    		self.render('main.js')
     
    class WebSocketHandler(tornado.websocket.WebSocketHandler):
        def open(self):
            print 'new connection'
            clients.append(self)
            self.write_message("connected")
     
        def on_message(self, message):
            print 'tornado received from client: %s' % json.dumps(message)
            #self.write_message('ack')
            input_queue.put(message)
     
        def on_close(self):
            print 'connection closed'
            clients.remove(self)
    
    
    ## check the queue for pending messages, and rely that to all connected clients
    def checkQueue():
    	if not output_queue.empty():
    		message = output_queue.get()
    		for c in clients:
    			c.write_message(message)
    
    
    if __name__ == '__main__':
    	## start the serial worker in background (as a deamon)
    	sp = serialworker.SerialProcess(input_queue, output_queue)
    	sp.daemon = True
    	sp.start()
    	tornado.options.parse_command_line()
    	app = tornado.web.Application(
    	    handlers=[
    	        (r"/", IndexHandler),
    	        (r"/static/(.*)", tornado.web.StaticFileHandler, {'path':  './'}),
    	        (r"/ws", WebSocketHandler)
    	    ]
    	)
    	httpServer = tornado.httpserver.HTTPServer(app)
    	httpServer.listen(options.port)
    	print "Listening on port:", options.port
    
    	mainLoop = tornado.ioloop.IOLoop.instance()
    	## adjust the scheduler_interval according to the frames sent by the serial port
    	scheduler_interval = 100
    	scheduler = tornado.ioloop.PeriodicCallback(checkQueue, scheduler_interval, io_loop = mainLoop)
    	scheduler.start()
    	mainLoop.start()

    5.扩展:每个页面用户登录时生成一个唯一的key,用户绑定该用户该会话的操作,在进行操作时,把这个key也传给server端的input队列,然后在serialworker的run循环中对data数据进行处理,在self.output_queue.put(data)操作是又带上这个key,然后返回,server中checkQueue方法执行是只发给这个key的会话,然后前端显示结果。这样来实现每个会话信息互不干扰。如果不用key做标记,那么所有会话操作的信息,所有会话之间都能看到。同时,serial是否可以和os.openpty()结合,实现serial操作新建的伪终端来实现shell终端操作模式。linux的pty创建是成对出现的,一个主,一个从,执行命令的时一个写,另一个读。一般是配合subprocess来指定STDOUT=slave,这样执行命令之后把结果写到slave,然后从master读取后再前端显示。pty创建简单代码如下:

     

    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
     
    import os,sys,time
    import serial
     
    # 主 pty, 从 tty
    master, slave = os.openpty()
     
    print master
    print slave
     
    # 显示终端名
    slave_name = os.ttyname(slave)
    print master
    print slave_name
     
    ser = serial.Serial(slave_name, rtscts=True, dsrdtr=True)
    print "Open port successful! the port information:"
    print ser
    print "
    "
     
    while ser.isOpen(): #the return is True or Faulse
        print "please write the msg(exit to break)"
        msg = raw_input(">") #add a break reason:::kill the child thread
        if msg == 'exit':
            print "
    "
            print "Please waiting to close the connection......"
            time.sleep(1)
            break;
        msg = msg + '
    ' + '
    ' #AT form define #data=ser.write(msg)
        os.write(master, msg)
        sys.stdout.flush() #flush the buffer
        print "
    "
        print ("waiting to recv the data...")
        time.sleep(2)
        msg_recv = os.read(slave, 128)
        print ("
    ")
        print ("	OK! The recv msg is %s"%(msg_recv))

      

      

    创建伪终端通信简图:

  • 相关阅读:
    批量转外部样式为行内样式
    AngularJS 笔记2
    windows特殊文件或文件夹
    zepto 入门
    js闭包
    AngularJS 笔记1
    sublime配置 sublimecondeintel 分号后不要提示
    sublime插件开发手记
    用flvplayer.swf在网页中播放视频(网页中flash视频播放的实现)
    无插件启动谷歌浏览器
  • 原文地址:https://www.cnblogs.com/wsjhk/p/9083104.html
Copyright © 2011-2022 走看看