def __init__(self, context, framer=None, identity=None, address=None, handler=None, **kwargs): """ Overloaded initializer for the socket server If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. :param context: The ModbusServerContext datastore :param framer: The framer strategy to use :param identity: An optional identify structure :param address: An optional (interface, port) to bind to. :param handler: A handler for each client session; default is ModbusDisonnectedRequestHandler :param ignore_missing_slaves: True to not send errors on a request to a missing slave :param broadcast_enable: True to treat unit_id 0 as broadcast address, False to treat 0 as any other unit_id """ self.threads = [] self.decoder = ServerDecoder() self.framer = framer or ModbusSocketFramer self.context = context or ModbusServerContext() self.control = ModbusControlBlock() self.address = address or ("", Defaults.Port) self.handler = handler or ModbusDisconnectedRequestHandler self.ignore_missing_slaves = kwargs.get('ignore_missing_slaves', Defaults.IgnoreMissingSlaves) self.broadcast_enable = kwargs.get('broadcast_enable', Defaults.broadcast_enable) if isinstance(identity, ModbusDeviceIdentification): self.control.Identity.update(identity) socketserver.ThreadingUDPServer.__init__(self, self.address, self.handler)
def __init__(self, gateway, connector, store, framer=None, identity=None, **kwargs): self._clients = dict() self._gateway = gateway self._devices = {} # self._connector = connector self._tokens = set() self._usrConfig = None # 定时任务 self._jobs = {} self._schedulerService = TBScheduleService(BackgroundScheduler()) # Modbus self.decoder = ServerDecoder() self.framer = framer(self.decoder) or ModbusSocketFramer(self.decoder) self.store = store or ModbusServerContext() self.control = ModbusControlBlock() self.access = ModbusAccessControl() self.ignore_missing_slaves = kwargs.get('ignore_missing_slaves', Defaults.IgnoreMissingSlaves) if isinstance(identity, ModbusDeviceIdentification): self.control.Identity.update(identity) log.debug('Start Usr Factory:', self)
def __init__(self, context, framer=None, identity=None, **kwargs): ''' Overloaded initializer for the socket server If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. :param context: The ModbusServerContext datastore :param framer: The framer strategy to use :param identity: An optional identify structure :param port: The serial port to attach to :param stopbits: The number of stop bits to use :param bytesize: The bytesize of the serial messages :param parity: Which kind of parity to use :param baudrate: The baud rate to use for the serial device :param timeout: The timeout to use for the serial device ''' self.threads = [] self.decoder = ServerDecoder() self.framer = framer or ModbusAsciiFramer self.context = context or ModbusServerContext() self.control = ModbusControlBlock() if isinstance(identity, ModbusDeviceIdentification): self.control.Identity.update(identity) self.device = kwargs.get('port', 0) self.stopbits = kwargs.get('stopbits', Defaults.Stopbits) self.bytesize = kwargs.get('bytesize', Defaults.Bytesize) self.parity = kwargs.get('parity', Defaults.Parity) self.baudrate = kwargs.get('baudrate', Defaults.Baudrate) self.timeout = kwargs.get('timeout', Defaults.Timeout) self.socket = None self._connect()
def __init__(self, store, framer=None, identity=None): """ Overloaded initializer for the modbus factory If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. :param store: The ModbusServerContext datastore :param framer: The framer strategy to use :param identity: An optional identify structure """ self.decoder = ServerDecoder() if isinstance(framer, IModbusFramer): self.framer = framer else: self.framer = ModbusSocketFramer if isinstance(store, ModbusServerContext): self.store = store else: self.store = ModbusServerContext() self.control = ModbusControlBlock() self.access = ModbusAccessControl() if isinstance(identity, ModbusDeviceIdentification): self.control.Identity.update(identity)
def __init__(self, context, framer=None, identity=None): ''' Overloaded initializer for the socket server If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. :param context: The ModbusServerContext datastore :param framer: The framer strategy to use :param identity: An optional identify structure ''' self.decoder = ServerDecoder() if isinstance(framer, IModbusFramer): self.framer = framer else: self.framer = ModbusSerialFramer if isinstance(store, ModbusServerContext): self.context = context else: self.context = ModbusServerContext() self.control = ModbusControlBlock() if isinstance(identity, ModbusDeviceIdentification): self.control.Identity.update(identity)
def __init__(self, context, framer=None, identity=None, address=None, handler=None, allow_reuse_address=False, allow_reuse_port=False, defer_start=False, backlog=20, loop=None, **kwargs): """ Overloaded initializer for the socket server If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. :param context: The ModbusServerContext datastore :param framer: The framer strategy to use :param identity: An optional identify structure :param address: An optional (interface, port) to bind to. :param handler: A handler for each client session; default is ModbusDisonnectedRequestHandler :param ignore_missing_slaves: True to not send errors on a request to a missing slave :param broadcast_enable: True to treat unit_id 0 as broadcast address, False to treat 0 as any other unit_id :param response_manipulator: Callback method for manipulating the response """ self.loop = loop or asyncio.get_event_loop() self.decoder = ServerDecoder() self.framer = framer or ModbusSocketFramer self.context = context or ModbusServerContext() self.control = ModbusControlBlock() self.address = address or ("", Defaults.Port) self.handler = handler or ModbusDisconnectedRequestHandler self.ignore_missing_slaves = kwargs.get('ignore_missing_slaves', Defaults.IgnoreMissingSlaves) self.broadcast_enable = kwargs.get('broadcast_enable', Defaults.broadcast_enable) self.response_manipulator = kwargs.get("response_manipulator", None) if isinstance(identity, ModbusDeviceIdentification): self.control.Identity.update(identity) self.protocol = None self.endpoint = None self.on_connection_terminated = None self.stop_serving = self.loop.create_future() # asyncio future that will be done once server has started self.serving = self.loop.create_future() self.server_factory = self.loop.create_datagram_endpoint( lambda: self.handler(self), local_addr=self.address, reuse_address=allow_reuse_address, reuse_port=allow_reuse_port, allow_broadcast=True)
def __init__(self, context, framer=None, identity=None, **kwargs): # pragma: no cover """ Overloaded initializer for the socket server If the identity structure is not passed in, the ModbusControlBlock uses its own empty structure. :param context: The ModbusServerContext datastore :param framer: The framer strategy to use :param identity: An optional identify structure :param port: The serial port to attach to :param stopbits: The number of stop bits to use :param bytesize: The bytesize of the serial messages :param parity: Which kind of parity to use :param baudrate: The baud rate to use for the serial device :param timeout: The timeout to use for the serial device :param ignore_missing_slaves: True to not send errors on a request to a missing slave :param broadcast_enable: True to treat unit_id 0 as broadcast address, False to treat 0 as any other unit_id :param autoreonnect: True to enable automatic reconnection, False otherwise :param reconnect_delay: reconnect delay in seconds :param response_manipulator: Callback method for manipulating the response """ self.device = kwargs.get('port', 0) self.stopbits = kwargs.get('stopbits', Defaults.Stopbits) self.bytesize = kwargs.get('bytesize', Defaults.Bytesize) self.parity = kwargs.get('parity', Defaults.Parity) self.baudrate = kwargs.get('baudrate', Defaults.Baudrate) self.timeout = kwargs.get('timeout', Defaults.Timeout) self.ignore_missing_slaves = kwargs.get('ignore_missing_slaves', Defaults.IgnoreMissingSlaves) self.broadcast_enable = kwargs.get('broadcast_enable', Defaults.broadcast_enable) self.auto_reconnect = kwargs.get('auto_reconnect', False) self.reconnect_delay = kwargs.get('reconnect_delay', 2) self.reconnecting_task = None self.handler = kwargs.get("handler") or ModbusSingleRequestHandler self.framer = framer or ModbusRtuFramer self.decoder = ServerDecoder() self.context = context or ModbusServerContext() self.response_manipulator = kwargs.get("response_manipulator", None) self.control = ModbusControlBlock() if isinstance(identity, ModbusDeviceIdentification): self.control.Identity.update(identity) self.protocol = None self.transport = None
def testReadDeviceInformationRequest(self): ''' Test basic bit message encoding/decoding ''' context = None control = ModbusControlBlock() control.Identity.VendorName = "Company" control.Identity.ProductCode = "Product" control.Identity.MajorMinorRevision = "v2.1.12" handle = ReadDeviceInformationRequest() result = handle.execute(context) self.assertTrue(isinstance(result, ReadDeviceInformationResponse)) self.assertTrue(result.information[0x00], "Company") self.assertTrue(result.information[0x01], "Product") self.assertTrue(result.information[0x02], "v2.1.12")
def __init__(self, store, framer=None, identity=None, **kwargs): """ Overloaded initializer for the modbus factory If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. :param store: The ModbusServerContext datastore :param framer: The framer strategy to use :param identity: An optional identify structure :param ignore_missing_slaves: True to not send errors on a request to a missing slave """ self.decoder = CustomServerDecoder() self.framer = framer or ModbusSocketFramer self.store = store or ModbusServerContext() self.control = ModbusControlBlock() self.access = ModbusAccessControl() self.ignore_missing_slaves = kwargs.get('ignore_missing_slaves', Defaults.IgnoreMissingSlaves) if isinstance(identity, ModbusDeviceIdentification): self.control.Identity.update(identity)
def __init__(self, context, framer=None, identity=None, **kwargs): """ Overloaded initializer for the socket server If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. :param context: The ModbusServerContext datastore :param framer: The framer strategy to use :param identity: An optional identify structure :param port: The serial port to attach to :param stopbits: The number of stop bits to use :param bytesize: The bytesize of the serial messages :param parity: Which kind of parity to use :param baudrate: The baud rate to use for the serial device :param timeout: The timeout to use for the serial device :param ignore_missing_slaves: True to not send errors on a request to a missing slave :param broadcast_enable: True to treat unit_id 0 as broadcast address, False to treat 0 as any other unit_id """ self.threads = [] self.decoder = ServerDecoder() self.framer = framer or ModbusAsciiFramer self.context = context or ModbusServerContext() self.control = ModbusControlBlock() if isinstance(identity, ModbusDeviceIdentification): self.control.Identity.update(identity) self.device = kwargs.get('port', 0) self.stopbits = kwargs.get('stopbits', Defaults.Stopbits) self.bytesize = kwargs.get('bytesize', Defaults.Bytesize) self.parity = kwargs.get('parity', Defaults.Parity) self.baudrate = kwargs.get('baudrate', Defaults.Baudrate) self.timeout = kwargs.get('timeout', Defaults.Timeout) self.ignore_missing_slaves = kwargs.get('ignore_missing_slaves', Defaults.IgnoreMissingSlaves) self.broadcast_enable = kwargs.get('broadcast_enable', Defaults.broadcast_enable) self.socket = None if self._connect(): self.is_running = True self._build_handler()
def __init__(self, context, framer=None, identity=None): ''' Overloaded initializer for the socket server If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. :param context: The ModbusServerContext datastore :param framer: The framer strategy to use :param identity: An optional identify structure ''' self.threads = [] self.decoder = ServerDecoder() self.framer = framer or ModbusSocketFramer self.context = context or ModbusServerContext() self.control = ModbusControlBlock() if isinstance(identity, ModbusDeviceIdentification): self.control.Identity.update(identity) SocketServer.ThreadingUDPServer.__init__( self, ("", Defaults.Port), ModbusDisconnectedRequestHandler)
def testReadDeviceInformationRequest(self): ''' Test basic bit message encoding/decoding ''' context = None control = ModbusControlBlock() control.Identity.VendorName = "Company" control.Identity.ProductCode = "Product" control.Identity.MajorMinorRevision = "v2.1.12" control.Identity.update({0x81: ['Test', 'Repeated']}) handle = ReadDeviceInformationRequest() result = handle.execute(context) self.assertTrue(isinstance(result, ReadDeviceInformationResponse)) self.assertEqual(result.information[0x00], "Company") self.assertEqual(result.information[0x01], "Product") self.assertEqual(result.information[0x02], "v2.1.12") with self.assertRaises(KeyError): _ = result.information[0x81] handle = ReadDeviceInformationRequest( read_code=DeviceInformation.Extended, object_id=0x80) result = handle.execute(context) self.assertEqual(result.information[0x81], ['Test', 'Repeated'])
''' Diagnostic record read/write Currently not all implemented ''' import struct from pymodbus.constants import ModbusStatus from pymodbus.pdu import ModbusRequest from pymodbus.pdu import ModbusResponse from pymodbus.device import ModbusControlBlock from pymodbus.compat import byte2int, int2byte _MCB = ModbusControlBlock() #---------------------------------------------------------------------------# # TODO Make these only work on serial #---------------------------------------------------------------------------# class ReadExceptionStatusRequest(ModbusRequest): ''' This function code is used to read the contents of eight Exception Status outputs in a remote device. The function provides a simple method for accessing this information, because the Exception Output references are known (no output reference is needed in the function). ''' function_code = 0x07 _rtu_frame_size = 4 def __init__(self, **kwargs): ''' Initializes a new instance '''
def __init__(self, context, framer=None, identity=None, address=None, sslctx=None, certfile=None, keyfile=None, handler=None, allow_reuse_address=False, allow_reuse_port=False, defer_start=False, backlog=20, loop=None, **kwargs): """ Overloaded initializer for the socket server If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. :param context: The ModbusServerContext datastore :param framer: The framer strategy to use :param identity: An optional identify structure :param address: An optional (interface, port) to bind to. :param sslctx: The SSLContext to use for TLS (default None and auto create) :param certfile: The cert file path for TLS (used if sslctx is None) :param keyfile: The key file path for TLS (used if sslctx is None) :param handler: A handler for each client session; default is ModbusConnectedRequestHandler. The handler class receives connection create/teardown events :param allow_reuse_address: Whether the server will allow the reuse of an address. :param allow_reuse_port: Whether the server will allow the reuse of a port. :param backlog: is the maximum number of queued connections passed to listen(). Defaults to 20, increase if many connections are being made and broken to your Modbus slave :param loop: optional asyncio event loop to run in. Will default to asyncio.get_event_loop() supplied value if None. :param ignore_missing_slaves: True to not send errors on a request to a missing slave :param broadcast_enable: True to treat unit_id 0 as broadcast address, False to treat 0 as any other unit_id """ self.active_connections = {} self.loop = loop or asyncio.get_event_loop() self.allow_reuse_address = allow_reuse_address self.decoder = ServerDecoder() self.framer = framer or ModbusTlsFramer self.context = context or ModbusServerContext() self.control = ModbusControlBlock() self.address = address or ("", Defaults.Port) self.handler = handler or ModbusConnectedRequestHandler self.handler.server = self self.ignore_missing_slaves = kwargs.get('ignore_missing_slaves', Defaults.IgnoreMissingSlaves) self.broadcast_enable = kwargs.get('broadcast_enable', Defaults.broadcast_enable) if isinstance(identity, ModbusDeviceIdentification): self.control.Identity.update(identity) self.sslctx = sslctx if self.sslctx is None: self.sslctx = ssl.create_default_context() self.sslctx.load_cert_chain(certfile=certfile, keyfile=keyfile) # According to MODBUS/TCP Security Protocol Specification, it is # TLSv2 at least self.sslctx.options |= ssl.OP_NO_TLSv1_1 self.sslctx.options |= ssl.OP_NO_TLSv1 self.sslctx.options |= ssl.OP_NO_SSLv3 self.sslctx.options |= ssl.OP_NO_SSLv2 self.sslctx.verify_mode = ssl.CERT_OPTIONAL self.sslctx.check_hostname = False self.serving = self.loop.create_future( ) # asyncio future that will be done once server has started self.server = None # constructors cannot be declared async, so we have to defer the initialization of the server if PYTHON_VERSION >= (3, 7): # start_serving is new in version 3.7 self.server_factory = self.loop.create_server( lambda: self.handler(self), *self.address, ssl=self.sslctx, reuse_address=allow_reuse_address, reuse_port=allow_reuse_port, backlog=backlog, start_serving=not defer_start) else: self.server_factory = self.loop.create_server( lambda: self.handler(self), *self.address, ssl=self.sslctx, reuse_address=allow_reuse_address, reuse_port=allow_reuse_port, backlog=backlog)
def __init__(self, context, framer=None, identity=None, address=None, handler=None, allow_reuse_address=False, allow_reuse_port=False, defer_start=False, backlog=20, loop=None, **kwargs): """ Overloaded initializer for the socket server If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. :param context: The ModbusServerContext datastore :param framer: The framer strategy to use :param identity: An optional identify structure :param address: An optional (interface, port) to bind to. :param handler: A handler for each client session; default is ModbusConnectedRequestHandler. The handler class receives connection create/teardown events :param allow_reuse_address: Whether the server will allow the reuse of an address. :param allow_reuse_port: Whether the server will allow the reuse of a port. :param backlog: is the maximum number of queued connections passed to listen(). Defaults to 20, increase if many connections are being made and broken to your Modbus slave :param loop: optional asyncio event loop to run in. Will default to asyncio.get_event_loop() supplied value if None. :param ignore_missing_slaves: True to not send errors on a request to a missing slave :param broadcast_enable: True to treat unit_id 0 as broadcast address, False to treat 0 as any other unit_id :param response_manipulator: Callback method for manipulating the response """ self.active_connections = {} self.loop = loop or asyncio.get_event_loop() self.allow_reuse_address = allow_reuse_address self.decoder = ServerDecoder() self.framer = framer or ModbusSocketFramer self.context = context or ModbusServerContext() self.control = ModbusControlBlock() self.address = address or ("", Defaults.Port) self.handler = handler or ModbusConnectedRequestHandler self.handler.server = self self.ignore_missing_slaves = kwargs.get('ignore_missing_slaves', Defaults.IgnoreMissingSlaves) self.broadcast_enable = kwargs.get('broadcast_enable', Defaults.broadcast_enable) self.response_manipulator = kwargs.get("response_manipulator", None) if isinstance(identity, ModbusDeviceIdentification): self.control.Identity.update(identity) # asyncio future that will be done once server has started self.serving = self.loop.create_future() # constructors cannot be declared async, so we have to # defer the initialization of the server self.server = None if PYTHON_VERSION >= (3, 7): # start_serving is new in version 3.7 self.server_factory = self.loop.create_server( lambda: self.handler(self), *self.address, reuse_address=allow_reuse_address, reuse_port=allow_reuse_port, backlog=backlog, start_serving=not defer_start) else: self.server_factory = self.loop.create_server( lambda: self.handler(self), *self.address, reuse_address=allow_reuse_address, reuse_port=allow_reuse_port, backlog=backlog)