python读取plc数据上传web_[记录]python使用serial模块实现实时WebConsole

使用Tornado框架和WebSocket技术,结合多进程处理,实现Python通过Web界面实时读取PLC数据。用户交互通过WebSocket发送指令到服务器,服务器将指令放入队列,由子进程读取并发送到串口设备,同时监听串口回传数据,再将结果推送给相应WebSocket连接。扩展讨论了通过用户key确保会话独立性和pty伪终端实现shell终端操作模式。
摘要由CSDN通过智能技术生成

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

1.index.html

body { margin: 0px; padding: 20px; }

#received { width: 500px; height: 400px; border: 1px solid #dedede; overflow-y:scroll;}

#sent { width: 500px; }

Websockets serial console

Data received from serial port

Clear

Send data to serial port

Send

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($('
'));

};

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("\n", "")

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 "\n"

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 "\n"

print "Please waiting to close the connection......"

time.sleep(1)

break;

msg = msg + '\r' + '\n' #AT form define #data=ser.write(msg)

os.write(master, msg)

sys.stdout.flush() #flush the buffer

print "\n"

print ("waiting to recv the data...")

time.sleep(2)

msg_recv = os.read(slave, 128)

print ("\n")

print ("\tOK! The recv msg is %s"%(msg_recv))

创建伪终端通信简图:

7ac1c410bb198994be99f9c2aee194aa.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值