How to asynchronously read data via modbus/TCP and send them to web

做~自己de王妃 提交于 2019-12-08 09:46:22

问题


I need to receive data from device connected via Ethernet (modbus/TCP) and send it to webpage (maybe using web sockets).

I can't find good examples. Now I can connect with driver and print values using ModbusClientProtocol.read_input_registers() but I had to create own factory and protocol class. I am using autobahn, twisted, pymodbus.


回答1:


I've no familiarity with modbus or pymodbus, so I'm guessing and leaving a lot of blanks for you to fill in.

This is hacked out of something I recently put together to receive snmptraps and redistribute the information to connected websockets.

Hopefully this is enough to get you going:

#!/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()

On the browser side of things. A little module for interacting with websockets is handy:

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 )
    }
  }
};

Then in your browser console:

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


来源:https://stackoverflow.com/questions/12053599/how-to-asynchronously-read-data-via-modbus-tcp-and-send-them-to-web

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!