Skip to content

Instantly share code, notes, and snippets.

@aborilov
Created January 9, 2013 15:34
Show Gist options
  • Select an option

  • Save aborilov/4494064 to your computer and use it in GitHub Desktop.

Select an option

Save aborilov/4494064 to your computer and use it in GitHub Desktop.
example
#!/usr/bin/env python
'''
Pymodbus Asynchronous Processor Example
--------------------------------------------------------------------------
The following is a full example of a continuous client processor. Feel
free to use it as a skeleton guide in implementing your own.
'''
#---------------------------------------------------------------------------#
# import the neccessary modules
#---------------------------------------------------------------------------#
from twisted.internet import serialport, reactor
from twisted.internet import defer
from twisted.internet.protocol import ClientFactory
from pymodbus.factory import ClientDecoder
from pymodbus.client.async import ModbusClientProtocol
from serial import PARITY_NONE, PARITY_EVEN, PARITY_ODD
from serial import STOPBITS_ONE, STOPBITS_TWO
from serial import FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS
#---------------------------------------------------------------------------#
# Choose the framer you want to use
#---------------------------------------------------------------------------#
#from pymodbus.transaction import ModbusBinaryFramer as ModbusFramer
from pymodbus.transaction import ModbusAsciiFramer as ModbusFramer
#from pymodbus.transaction import ModbusRtuFramer as ModbusFramer
# from pymodbus.transaction import ModbusSocketFramer as ModbusFramer
#---------------------------------------------------------------------------#
# configure the client logging
#---------------------------------------------------------------------------#
import logging
logging.basicConfig()
log = logging.getLogger("pymodbus")
log.setLevel(logging.DEBUG)
#---------------------------------------------------------------------------#
# state a few constants
#---------------------------------------------------------------------------#
SERIAL_PORT = "/dev/plc"
STATUS_REGS1 = (3595, 1)
STATUS_REGS2 = (3592, 1)
STATUS_COILS = (1298, 10)
CLIENT_DELAY = 0
data_length = SEVENBITS
speed = 9600
parity = PARITY_EVEN
stop_bits = STOPBITS_ONE
station_address = 1
#---------------------------------------------------------------------------#
# an example custom protocol
#---------------------------------------------------------------------------#
# Here you can perform your main procesing loop utilizing defereds and timed
# callbacks.
#---------------------------------------------------------------------------#
class ExampleProtocol(ModbusClientProtocol):
def __init__(self, framer, endpoint):
''' Initializes our custom protocol
:param framer: The decoder to use to process messages
:param endpoint: The endpoint to send results to
'''
ModbusClientProtocol.__init__(self, framer)
self.endpoint = endpoint
log.debug("Beginning the processing loop")
reactor.callLater(1, self.start_next_cycle)
def fetch_holding_registers(self, response):
''' Defer fetching holding registers
'''
log.debug("Starting the next cycle")
d1 = self.read_holding_registers(*STATUS_REGS1)
d2 = self.read_holding_registers(*STATUS_REGS2)
d1.addCallbacks(self.reg_fetched)
d2.addCallbacks(self.reg_fetched)
def reg_fetched(self, response):
log.error("Fetched %d" % response.getRegister(0))
def send_holding_registers(self, response):
''' Write values of holding registers, defer fetching coils
:param response: The response to process
'''
# self.endpoint.write(response.getRegister(0))
# self.endpoint.write(response.getRegister(1))
log.error("Response - %s" % response)
d = self.read_coils(*STATUS_COILS)
d.addCallbacks(self.start_next_cycle, self.error_handler)
def start_next_cycle(self):
''' Write values of coils, trigger next cycle
:param response: The response to process
'''
d = defer.Deferred()
d.addCallbacks(self.fetch_holding_registers)
d.callback('Start new cycle')
def error_handler(self, failure):
''' Handle any twisted errors
:param failure: The error to handle
'''
log.error(failure)
#---------------------------------------------------------------------------#
# a factory for the example protocol
#---------------------------------------------------------------------------#
# This is used to build client protocol's if you tie into twisted's method
# of processing. It basically produces client instances of the underlying
# protocol::
#
# Factory(Protocol) -> ProtocolInstance
#
# It also persists data between client instances (think protocol singelton).
#---------------------------------------------------------------------------#
class ExampleFactory(ClientFactory):
protocol = ExampleProtocol
def __init__(self, framer, endpoint):
''' Remember things necessary for building a protocols '''
self.framer = framer
self.endpoint = endpoint
def buildProtocol(self, _):
''' Create a protocol and start the reading cycle '''
proto = self.protocol(self.framer, self.endpoint)
proto.factory = self
return proto
#---------------------------------------------------------------------------#
# a custom client for our device
#---------------------------------------------------------------------------#
# Twisted provides a number of helper methods for creating and starting
# clients:
# - protocol.ClientCreator
# - reactor.connectTCP
#
# How you start your client is really up to you.
#---------------------------------------------------------------------------#
class SerialModbusClient(serialport.SerialPort):
def __init__(self, factory, *args, **kwargs):
''' Setup the client and start listening on the serial port
:param factory: The factory to build clients with
'''
protocol = factory.buildProtocol(None)
self.decoder = ClientDecoder()
serialport.SerialPort.__init__(self, protocol, *args, **kwargs)
#---------------------------------------------------------------------------#
# a custom endpoint for our results
#---------------------------------------------------------------------------#
# An example line reader, this can replace with:
# - the TCP protocol
# - a context recorder
# - a database or file recorder
#---------------------------------------------------------------------------#
class LoggingLineReader(object):
def write(self, response):
''' Handle the next modbus response
:param response: The response to process
'''
log.info("Read Data: %d" % response)
#---------------------------------------------------------------------------#
# start running the processor
#---------------------------------------------------------------------------#
# This initializes the client, the framer, the factory, and starts the
# twisted event loop (the reactor). It should be noted that a number of
# things could be chanegd as one sees fit:
# - The ModbusRtuFramer could be replaced with a ModbusAsciiFramer
# - The SerialModbusClient could be replaced with reactor.connectTCP
# - The LineReader endpoint could be replaced with a database store
#---------------------------------------------------------------------------#
def main():
log.debug("Initializing the client")
framer = ModbusFramer(ClientDecoder())
reader = LoggingLineReader()
factory = ExampleFactory(framer, reader)
SerialModbusClient(
factory, SERIAL_PORT,
reactor, baudrate=9600,
parity=PARITY_EVEN, bytesize=SEVENBITS,
stopbits=STOPBITS_ONE, timeout=3)
#factory = reactor.connectTCP("localhost", 502, factory)
log.debug("Starting the client")
reactor.run()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment