def _helper(self, data):
        '''
        This factory is used to generate the correct response object
        from a valid response packet. This decodes from a list of the
        currently implemented request types.

        :param data: The response packet to decode
        :returns: The decoded request or an exception response object
        '''
        function_code = ord(data[0])
        _logger.debug("Factory Response[%d]" % function_code)
        response = self.__lookup.get(function_code, lambda: None)()
        if function_code > 0x80:
            code = function_code & 0x7f  # strip error portion
            response = ExceptionResponse(code, ecode.IllegalFunction)
        if not response:
            raise ModbusException("Unknown response %d" % function_code)
        response.decode(data[1:])

        if hasattr(response, 'sub_function_code'):
            lookup = self.__sub_lookup.get(response.function_code, {})
            subtype = lookup.get(response.sub_function_code, None)
            if subtype: response.__class__ = subtype

        return response
Example #2
0
    def _helper(self, data):
        '''
        This factory is used to generate the correct response object
        from a valid response packet. This decodes from a list of the
        currently implemented request types.

        :param data: The response packet to decode
        :returns: The decoded request or an exception response object
        '''
        function_code = ord(data[0])
        _logger.debug("Factory Response[%d]" % function_code)
        response = self.__lookup.get(function_code, lambda: None)()
        if function_code > 0x80:
            code = function_code & 0x7f  # strip error portion
            response = ExceptionResponse(code, ecode.IllegalFunction)
        if not response:
            raise ModbusException("Unknown response %d" % function_code)
        response.decode(data[1:])

        if hasattr(response, 'sub_function_code'):
            lookup = self.__sub_lookup.get(response.function_code, {})
            subtype = lookup.get(response.sub_function_code, None)
            if subtype: response.__class__ = subtype

        return response
Example #3
0
async def test_pb_service_write(hass, do_write, caplog, mock_modbus):
    """Run test for service write_register."""

    func_name = {
        CALL_TYPE_WRITE_COIL: mock_modbus.write_coil,
        CALL_TYPE_WRITE_COILS: mock_modbus.write_coils,
        CALL_TYPE_WRITE_REGISTER: mock_modbus.write_register,
        CALL_TYPE_WRITE_REGISTERS: mock_modbus.write_registers,
    }

    data = {
        ATTR_HUB: TEST_MODBUS_NAME,
        ATTR_UNIT: 17,
        ATTR_ADDRESS: 16,
        do_write[DATA]: do_write[VALUE],
    }
    await hass.services.async_call(DOMAIN, do_write[SERVICE], data, blocking=True)
    assert func_name[do_write[FUNC]].called
    assert func_name[do_write[FUNC]].call_args[0] == (
        data[ATTR_ADDRESS],
        data[do_write[DATA]],
    )
    mock_modbus.reset_mock()

    for return_value in [
        ExceptionResponse(0x06),
        IllegalFunctionRequest(0x06),
        ModbusException("fail write_"),
    ]:
        caplog.set_level(logging.DEBUG)
        func_name[do_write[FUNC]].return_value = return_value
        await hass.services.async_call(DOMAIN, do_write[SERVICE], data, blocking=True)
        assert func_name[do_write[FUNC]].called
        assert caplog.messages[-1].startswith("Pymodbus:")
        mock_modbus.reset_mock()
Example #4
0
 def manipulate_response(self, response):
     """
     Manipulates the actual response according to the required error state.
     :param response: Modbus response object
     :return: Modbus response
     """
     skip_encoding = False
     if not self._manipulator_config:
         return response
     else:
         clear_after = self._manipulator_config.get("clear_after")
         if clear_after and self._counter > clear_after:
             logger.info("Resetting manipulator"
                         " after {} responses".format(clear_after))
             self.update_manipulator_config(dict(DEFAULT_MANIPULATOR))
             return response
         response_type = self._manipulator_config.get("response_type")
         if response_type == "error":
             error_code = self._manipulator_config.get("error_code")
             logger.warning(
                 "Sending error response for all incoming requests")
             err_response = ExceptionResponse(response.function_code,
                                              error_code)
             err_response.transaction_id = response.transaction_id
             err_response.unit_id = response.unit_id
             response = err_response
             self._counter += 1
         elif response_type == "delayed":
             delay_by = self._manipulator_config.get("delay_by")
             logger.warning("Delaying response by {}s for "
                            "all incoming requests".format(delay_by))
             time.sleep(delay_by)
             self._counter += 1
         elif response_type == "empty":
             logger.warning("Sending empty response")
             self._counter += 1
             response.should_respond = False
         elif response_type == "stray":
             data_len = self._manipulator_config.get("data_len", 10)
             if data_len <= 0:
                 logger.warning(f"Invalid data_len {data_len}. "
                                f"Using default lenght 10")
                 data_len = 10
             response = os.urandom(data_len)
             self._counter += 1
             skip_encoding = True
         return response, skip_encoding
Example #5
0
    def _helper(self, data):
        function_code = byte2int(data[0])
        _logger.debug("Factory Response[%d]" % function_code)
        response = self.__lookup.get(function_code, lambda: None)()
        if function_code > 0x80:
            code = function_code & 0x7f  # strip error portion
            response = ExceptionResponse(code, ecode.IllegalFunction)
        if not response:
            raise ModbusException("Unknown response %d" % function_code)
        response.decode(data[1:])

        if hasattr(response, 'sub_function_code'):
            lookup = self.__sub_lookup.get(response.function_code, {})
            subtype = lookup.get(response.sub_function_code, None)
            if subtype:
                response.__class__ = subtype
        return response
Example #6
0
    def _helper(self, data):
        '''
        This factory is used to generate the correct response object
        from a valid response packet. This decodes from a list of the
        currently implemented request types.

        :param data: The response packet to decode
        :returns: The decoded request or an exception response object
        '''
        function_code = ord(data[0])
        _logger.debug("Factory Response[%d]" % function_code)
        response = self.__lookup.get(function_code, lambda: None)()
        if function_code > 0x80:
            response = ExceptionResponse(function_code & 0x7f, mexcept.IllegalFunction)
        if not response:
            raise ModbusException("Unknown response %d" % function_code)
        response.decode(data[1:])
        return response
Example #7
0
    def __test__ProductionDeviceModMap_get_registers__exception(self):

        device_data = self.sensorDeviceNS()

        item_data = device_data.modmap[0]
        print(item_data)

        devModMap = ProductionDeviceModMap.factory(item_data)

        connection = ProductionProtocol.factory(device_data.protocol)

        result = devModMap.get_registers(connection)

        exception = ExceptionResponse(131, 1, "IllegalAddress")

        self.assertEqual(result, exception)
Example #8
0
    def testRemoteSlaveValidateValues(self):
        ''' Test validating against a remote slave context '''
        client = mock()
        client.read_coils = lambda a, b: ReadCoilsResponse([1] * 10)
        client.read_input_registers = lambda a, b: ReadInputRegistersResponse(
            [10] * 10)
        client.read_holding_registers = lambda a, b: ExceptionResponse(0x15)

        context = RemoteSlaveContext(client)
        result = context.validate(1, 0, 10)
        self.assertTrue(result)

        result = context.validate(4, 0, 10)
        self.assertTrue(result)

        result = context.validate(3, 0, 10)
        self.assertFalse(result)
Example #9
0
    def testRemoteSlaveGetValues(self):
        ''' Test getting values from a remote slave context '''
        client = mock()
        client.read_coils = lambda a, b: ReadCoilsResponse([1] * 10)
        client.read_input_registers = lambda a, b: ReadInputRegistersResponse(
            [10] * 10)
        client.read_holding_registers = lambda a, b: ExceptionResponse(0x15)

        context = RemoteSlaveContext(client)
        result = context.getValues(1, 0, 10)
        self.assertEqual(result, [1] * 10)

        result = context.getValues(4, 0, 10)
        self.assertEqual(result, [10] * 10)

        result = context.getValues(3, 0, 10)
        self.assertNotEqual(result, [10] * 10)
Example #10
0
async def test_pb_service_write_coil(hass, caplog, mock_modbus):
    """Run test for service write_coil."""

    # Pymodbus write single, response OK.
    data = {
        ATTR_HUB: TEST_MODBUS_NAME,
        ATTR_UNIT: 17,
        ATTR_ADDRESS: 16,
        ATTR_STATE: False,
    }
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coil.called
    assert mock_modbus.write_coil.call_args[0] == (
        data[ATTR_ADDRESS],
        data[ATTR_STATE],
    )
    mock_modbus.reset_mock()

    # Pymodbus write single, response error or exception
    caplog.set_level(logging.DEBUG)
    mock_modbus.write_coil.return_value = ExceptionResponse(0x06)
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coil.called
    assert caplog.messages[-1].startswith("Pymodbus:")
    mock_modbus.reset_mock()

    mock_modbus.write_coil.return_value = IllegalFunctionRequest(0x06)
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coil.called
    assert caplog.messages[-1].startswith("Pymodbus:")
    mock_modbus.reset_mock()

    mock_modbus.write_coil.side_effect = ModbusException("fail write_")
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coil.called
    assert caplog.messages[-1].startswith("Pymodbus:")
    mock_modbus.reset_mock()

    # Pymodbus write multiple, response OK.
    data[ATTR_STATE] = [True, False, True]
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coils.called
    assert mock_modbus.write_coils.call_args[0] == (
        data[ATTR_ADDRESS],
        data[ATTR_STATE],
    )
    mock_modbus.reset_mock()

    # Pymodbus write multiple, response error or exception
    mock_modbus.write_coils.return_value = ExceptionResponse(0x06)
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coils.called
    assert caplog.messages[-1].startswith("Pymodbus:")
    mock_modbus.reset_mock()

    mock_modbus.write_coils.return_value = IllegalFunctionRequest(0x06)
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coils.called
    assert caplog.messages[-1].startswith("Pymodbus:")
    mock_modbus.reset_mock()

    mock_modbus.write_coils.side_effect = ModbusException("fail write_")
    await hass.services.async_call(DOMAIN,
                                   SERVICE_WRITE_COIL,
                                   data,
                                   blocking=True)
    assert mock_modbus.write_coils.called
    assert caplog.messages[-1].startswith("Pymodbus:")
    mock_modbus.reset_mock()
Example #11
0
                    return_value=now):
        assert await async_setup_component(hass, DOMAIN, config) is True
        await hass.async_block_till_done()
    now = now + timedelta(seconds=DEFAULT_SCAN_INTERVAL + 60)
    with mock.patch("homeassistant.helpers.event.dt_util.utcnow",
                    return_value=now):
        async_fire_time_changed(hass, now)
        await hass.async_block_till_done()


@pytest.mark.parametrize(
    "do_return,do_exception,do_expect",
    [
        [ReadResult([7]), None, "7"],
        [IllegalFunctionRequest(0x99), None, STATE_UNAVAILABLE],
        [ExceptionResponse(0x99), None, STATE_UNAVAILABLE],
        [ReadResult([7]),
         ModbusException("fail read_"), STATE_UNAVAILABLE],
    ],
)
@pytest.mark.parametrize(
    "do_type",
    [CALL_TYPE_REGISTER_HOLDING, CALL_TYPE_REGISTER_INPUT],
)
async def test_pb_read_value(hass, caplog, do_type, do_return, do_exception,
                             do_expect, mock_pymodbus):
    """Run test for different read."""

    # the purpose of this test is to test the special
    # return values from pymodbus:
    #     ExceptionResponse, IllegalResponse
Example #12
0
            DATA: ATTR_STATE,
            VALUE: [True, False, True],
            SERVICE: SERVICE_WRITE_COIL,
            FUNC: CALL_TYPE_WRITE_COILS,
        },
    ],
)
@pytest.mark.parametrize(
    "do_return",
    [
        {
            VALUE: ReadResult([0x0001]),
            DATA: ""
        },
        {
            VALUE: ExceptionResponse(0x06),
            DATA: "Pymodbus:"
        },
        {
            VALUE: IllegalFunctionRequest(0x06),
            DATA: "Pymodbus:"
        },
        {
            VALUE: ModbusException("fail write_"),
            DATA: "Pymodbus:"
        },
    ],
)
async def test_pb_service_write(hass, do_write, do_return, caplog,
                                mock_modbus_with_pymodbus):
    """Run test for service write_register."""
Example #13
0
            SERVICE: SERVICE_WRITE_COIL,
            FUNC: CALL_TYPE_WRITE_COIL,
        },
        {
            DATA: ATTR_STATE,
            VALUE: [True, False, True],
            SERVICE: SERVICE_WRITE_COIL,
            FUNC: CALL_TYPE_WRITE_COILS,
        },
    ],
)
@pytest.mark.parametrize(
    "do_return",
    [
        {VALUE: ReadResult([0x0001]), DATA: ""},
        {VALUE: ExceptionResponse(0x06), DATA: "Pymodbus:"},
        {VALUE: IllegalFunctionRequest(0x06), DATA: "Pymodbus:"},
        {VALUE: ModbusException("fail write_"), DATA: "Pymodbus:"},
    ],
)
async def test_pb_service_write(
    hass, do_write, do_return, caplog, mock_modbus_with_pymodbus
):
    """Run test for service write_register."""

    func_name = {
        CALL_TYPE_WRITE_COIL: mock_modbus_with_pymodbus.write_coil,
        CALL_TYPE_WRITE_COILS: mock_modbus_with_pymodbus.write_coils,
        CALL_TYPE_WRITE_REGISTER: mock_modbus_with_pymodbus.write_register,
        CALL_TYPE_WRITE_REGISTERS: mock_modbus_with_pymodbus.write_registers,
    }