Esempio n. 1
0
    def testModbusSingleRequestHandlerSend(self):
        handler = socketserver.BaseRequestHandler(None, None, None)
        handler.__class__ = ModbusSingleRequestHandler
        handler.framer = Mock()
        handler.framer.buildPacket.return_value = b"message"
        handler.request = Mock()
        request = ReadCoilsResponse([1])
        handler.send(request)
        self.assertEqual(handler.request.send.call_count, 1)

        request.should_respond = False
        handler.send(request)
        self.assertEqual(handler.request.send.call_count, 1)
Esempio n. 2
0
    def testModbusSingleRequestHandlerSend(self):
        handler = socketserver.BaseRequestHandler(None, None, None)
        handler.__class__ = ModbusSingleRequestHandler
        handler.framer  = Mock()
        handler.framer.buildPacket.return_value = "message"
        handler.request = Mock()
        request = ReadCoilsResponse([1])
        handler.send(request)
        self.assertEqual(handler.request.send.call_count, 1)

        request.should_respond = False
        handler.send(request)
        self.assertEqual(handler.request.send.call_count, 1)
Esempio n. 3
0
 async def _request(self, method, *args, **kwargs):
     if method == 'read_coils':
         address, count = args
         return ReadCoilsResponse(
             [self._coils[address + i] for i in range(count)])
     if method == 'read_discrete_inputs':
         address, count = args
         return ReadDiscreteInputsResponse(
             [self._discrete_inputs[address + i] for i in range(count)])
     elif method == 'read_holding_registers':
         address, count = args
         return ReadHoldingRegistersResponse([
             int.from_bytes(self._registers[address + i], byteorder='big')
             for i in range(count)
         ])
     elif method == 'write_coil':
         address, data = args
         self._coils[address] = data
         return WriteSingleCoilResponse(address, data)
     elif method == 'write_coils':
         address, data = args
         for i, d in enumerate(data):
             self._coils[address + i] = d
         return WriteMultipleCoilsResponse(address, len(data))
     elif method == 'write_register':
         address, data = args
         self._registers[address] = data
         return WriteSingleRegisterResponse(address, data)
     elif method == 'write_registers':
         address, data = args
         for i, d in enumerate(data):
             self._registers[address + i] = d
         return WriteMultipleRegistersResponse(address, len(data))
     return NotImplementedError(f'Unrecognised method: {method}')
Esempio n. 4
0
class LibmodbusClient(ModbusClientMixin):
    ''' A facade around the raw level 1 libmodbus client
    that implements the pymodbus protocol on top of the lower level
    client.
    '''

    #-----------------------------------------------------------------------#
    # these are used to convert from the pymodbus request types to the
    # libmodbus operations (overloaded operator).
    #-----------------------------------------------------------------------#

    __methods = {
        'ReadCoilsRequest':
        lambda c, r: c.read_bits(r.address, r.count),
        'ReadDiscreteInputsRequest':
        lambda c, r: c.read_input_bits(r.address, r.count),
        'WriteSingleCoilRequest':
        lambda c, r: c.write_bit(r.address, r.value),
        'WriteMultipleCoilsRequest':
        lambda c, r: c.write_bits(r.address, r.values),
        'WriteSingleRegisterRequest':
        lambda c, r: c.write_register(r.address, r.value),
        'WriteMultipleRegistersRequest':
        lambda c, r: c.write_registers(r.address, r.values),
        'ReadHoldingRegistersRequest':
        lambda c, r: c.read_registers(r.address, r.count),
        'ReadInputRegistersRequest':
        lambda c, r: c.read_input_registers(r.address, r.count),
        'ReadWriteMultipleRegistersRequest':
        lambda c, r: c.read_and_write_registers(
            r.read_address, r.read_count, r.write_address, r.write_registers),
    }

    #-----------------------------------------------------------------------#
    # these are used to convert from the libmodbus result to the
    # pymodbus response type
    #-----------------------------------------------------------------------#

    __adapters = {
        'ReadCoilsRequest':
        lambda tx, rx: ReadCoilsResponse(list(rx)),
        'ReadDiscreteInputsRequest':
        lambda tx, rx: ReadDiscreteInputsResponse(list(rx)),
        'WriteSingleCoilRequest':
        lambda tx, rx: WriteSingleCoilResponse(tx.address, rx),
        'WriteMultipleCoilsRequest':
        lambda tx, rx: WriteMultipleCoilsResponse(tx.address, rx),
        'WriteSingleRegisterRequest':
        lambda tx, rx: WriteSingleRegisterResponse(tx.address, rx),
        'WriteMultipleRegistersRequest':
        lambda tx, rx: WriteMultipleRegistersResponse(tx.address, rx),
        'ReadHoldingRegistersRequest':
        lambda tx, rx: ReadHoldingRegistersResponse(list(rx)),
        'ReadInputRegistersRequest':
        lambda tx, rx: ReadInputRegistersResponse(list(rx)),
        'ReadWriteMultipleRegistersRequest':
        lambda tx, rx: ReadWriteMultipleRegistersResponse(list(rx)),
    }

    def __init__(self, client):
        ''' Initalize a new instance of the LibmodbusClient. This should
        be initialized with one of the LibmodbusLevel1Client instances:

        * LibmodbusLevel1Client.create_rtu_client(...)
        * LibmodbusLevel1Client.create_tcp_client(...)

        :param client: The underlying client instance to operate with.
        '''
        self.client = client

    #-----------------------------------------------------------------------#
    # We use the client mixin to implement the api methods which are all
    # forwarded to this method. It is implemented using the previously
    # defined lookup tables. Any method not defined simply throws.
    #-----------------------------------------------------------------------#

    def execute(self, request):
        ''' Execute the supplied request against the server.

        :param request: The request to process
        :returns: The result of the request execution
        '''
        if self.client.slave != request.unit_id:
            self.client.set_slave(request.unit_id)

        method = request.__class__.__name__
        operation = self.__methods.get(method, None)
        adapter = self.__adapters.get(method, None)

        if not operation or not adapter:
            raise NotImplementedException("Method not implemented: " + name)

        response = operation(self.client, request)
        return adapter(request, response)

    #-----------------------------------------------------------------------#
    # Other methods can simply be forwarded using the decorator pattern
    #-----------------------------------------------------------------------#

    def connect(self):
        return self.client.connect()

    def close(self):
        return self.client.close()

    #-----------------------------------------------------------------------#
    # magic methods
    #-----------------------------------------------------------------------#

    def __enter__(self):
        ''' Implement the client with enter block

        :returns: The current instance of the client
        '''
        self.client.connect()
        return self

    def __exit__(self, klass, value, traceback):
        ''' Implement the client with exit block '''
        self.client.close()