如何通过modbus / TCP异步读取数据并将其发送到Web

时间:2012-08-21 11:12:00

标签: python web-services twisted autobahn

我需要从通过以太网连接的设备(modbus / TCP)接收数据并将其发送到网页(可能使用网络套接字)。

我找不到好的例子。现在我可以使用ModbusClientProtocol.read_input_registers()连接驱动程序和打印值,但我必须创建自己的工厂和协议类。我正在使用高速公路,扭曲,pymodbus。

1 个答案:

答案 0 :(得分:2)

我不熟悉modbus或pymodbus,所以我猜测并留下很多空白让你填写。

这是我最近收集的一些内容,用于接收snmptraps并将信息重新分发到连接的websockets。

希望这足以让你前进:

#!/usr/bin/python
from twisted.internet import protocol, reactor, utils, defer
from twisted.web.server import Site
from twisted.web.static import File

from autobahn.websocket import WebSocketServerFactory, WebSocketServerProtocol
from autobahn.util import newid
from autobahn.resource import WebSocketResource

class ModbusThing(object):
  def __init__(self,clientAddress):
    self.clientAddress = clientAddress
    self.client = None
  def start(self):
    pass
    ## Create client connection to modbus server
    ## Start Looping Call of pollForData with suitable interval
  def pollForData(self):
    pass
    ## Call read methods on ModbusClient object, add call backs to process the results
    ## Add errorBacks to notify of errors
  def resultCallback(self,result):
    pass
    ## Process the data from a read request
    ## Assumes that your websocket clients expect json like {"event":"update","data":[0,1,2]}
    message = dict(event="update",data=processedResults)
    self.broadcast(json.dumps(message))
  def broadcast(self,msg):
    """Override me"""
    pass

class TrackingWebSocketProtocol(WebSocketServerProtocol):
  def onOpen(self):
    self.session_id = newid()
    self.factory._addSession(self,self.session_id)
    print "Socket Open %s" % (self.peerstr,)

  def onMessage(self,payload,isBinary):
    print "Message received from %s\n\t: %r" % (self.peerstr,payload)

  def onClose(self,wasClean,code,reason):
    self.factory._removeSession(self)
    print "Socket Closed %s" % (self.peerstr,)

class TrackingWebSocketFactory(WebSocketServerFactory):
  def __init__(self,*args,**kwargs):
    WebSocketServerFactory.__init__(self,*args,**kwargs)
    self.proto2session = {}
    self.session2proto = {}
  def _addSession(self,proto,session_id):
    if not self.proto2session.has_key(proto):
       self.proto2session[proto] = session_id
    else:
       raise Exception("logic error - dublicate _addSession for protoToSessions")
    if not self.session2proto.has_key(session_id):
       self.session2proto[session_id] = proto
    else:
       raise Exception("logic error - dublicate _addSession for sessionsToProto")
  def _removeSession(self,proto):
    if proto in self.proto2session:
      session_id = self.proto2session[proto]
      del self.proto2session[proto]
      if session_id in self.session2proto:
        del self.session2proto[session_id]
  def sendToAll(self,message,binary=False):
    prepped = self.prepareMessage(message,binary)
    for proto in self.proto2session.keys():
      proto.sendPreparedMessage(prepped)


def run():
  ## WebSocket Factory
  wsfactory = TrackingWebSocketFactory('ws://yourhostname:80')
  wsfactory.protocol = TrackingWebSocketProtocol
  wsresource = WebSocketResource(wsfactory)
  ## Modbus handler
  modbus_thing = ModbusThing((addressofserver,portofserver))
  modbus_thing.broadcast = wsfactory.sendToAll
  modbus_thing.start()
  ## WebServer Site
  # "static" subdirectory, containing http served resources, e.g. index.html, javascript and css
  root = File("static")
  # Your websocket service as 'ws://yourhostname/ws'
  root.putChild("ws", wsresource)
  site = Site(root)
  reactor.listenTCP(80,site)

def main():
  reactor.callWhenRunning(run)
  reactor.run()

if __name__=='__main__':
  main()

在浏览器方面。用于与websockets交互的小模块非常方便:

var FancyWebSocket = function(url){
  var conn = null;
  var fws = this;
  if ("WebSocket" in window) {
    conn = new WebSocket(url);
  } else if ("MozWebSocket" in window) {
    conn = new MozWebSocket(url);
  } else {
    console.log("Error Websockets not supported in browser");
    return;
  }
  var callbacks = {};
  var debug = true;
  this.bind = function(event_name, callback){
    callbacks[event_name] = callbacks[event_name] || [];
    callbacks[event_name].push(callback);
    return this;// chainable
  };
  this.send = function(event_name, event_data){
    var payload = JSON.stringify({event:event_name, data: event_data});
    conn.send( payload ); // <= send JSON data to socket server
    return this;
  };
  this.close = function(){ conn.close(); return this;}
  // dispatch to the right handlers
  conn.onmessage = function(evt){
    if (debug) console.log("Websocket(" + conn.URL + ") Message: " + evt.data)
    var json = JSON.parse(evt.data)
    dispatch(json.event, json.data)
  };
  conn.onclose = function(){
    if (debug) console.log("Websocket(" + conn.URL + ") Closed");
    dispatch('close',fws);
  }
  conn.onopen = function(){
    if (debug) console.log("Websocket(" + conn.URL + ") Open");
    dispatch('open',fws);
  }
  conn.onerror = function(e){
    if (debug) console.log("Websocket(" + conn.URL + ") Error: " + error);
    dispatch('error',fws,e);
  }
  this.setdebug = function(v) { debug=v; return this; }
  var dispatch = function(event_name, message){
    var chain = callbacks[event_name];
    if(typeof chain == 'undefined') return; // no callbacks for this event
    for(var i = 0; i < chain.length; i++){
      chain[i]( message )
    }
  }
};

然后在浏览器控制台中:

conn = new FancyWebSocket("ws://yourhostname/ws");