diff --git a/src/service/requirements.in b/src/service/requirements.in
index a10f7da7aba3027a89bdd8e9b62bc4ab90fb5e02..ea4d41cc4bf5fcf18ca1365a209e44dbe2c00488 100644
--- a/src/service/requirements.in
+++ b/src/service/requirements.in
@@ -19,3 +19,4 @@ netaddr==0.9.0
 networkx==2.6.3
 pydot==1.4.2
 redis==4.1.2
+requests==2.31.0
diff --git a/src/service/service/ServiceServiceServicerImpl.py b/src/service/service/ServiceServiceServicerImpl.py
index d7a983dc97cefd9a796ab97629ba2dbe58a71b22..f11a60ade2bfd0a9fcd9bc9ea98229def4602725 100644
--- a/src/service/service/ServiceServiceServicerImpl.py
+++ b/src/service/service/ServiceServiceServicerImpl.py
@@ -34,6 +34,13 @@ from .service_handler_api.ServiceHandlerFactory import ServiceHandlerFactory
 from .task_scheduler.TaskScheduler import TasksScheduler
 from .tools.GeodesicDistance import gps_distance
 
+from common.tools.object_factory.Context import json_context_id
+from common.tools.object_factory.Topology import json_topology_id
+from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME
+from common.proto.context_pb2 import Empty, TopologyId
+from service.service.tools.OpticalTools import add_lightpath, delete_lightpath, adapt_reply, get_device_name_from_uuid, get_optical_band
+
+
 LOGGER = logging.getLogger(__name__)
 
 METRICS_POOL = MetricsPool('Service', 'RPC')
@@ -241,7 +248,65 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
         if len(service_with_uuids.service_endpoint_ids) >= num_expected_endpoints:
             pathcomp_request = PathCompRequest()
             pathcomp_request.services.append(service_with_uuids)    # pylint: disable=no-member
-
+        if service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
+                context_id_x = json_context_id(DEFAULT_CONTEXT_NAME)
+                topology_id_x = json_topology_id(
+                    DEFAULT_TOPOLOGY_NAME, context_id_x)
+                topology_details = context_client.GetTopologyDetails(
+                    TopologyId(**topology_id_x))
+                # devices = get_devices_in_topology(context_client, TopologyId(**topology_id_x), ContextId(**context_id_x))
+                devices = topology_details.devices
+                context_uuid_x = topology_details.topology_id.context_id.context_uuid.uuid
+                topology_uuid_x = topology_details.topology_id.topology_uuid.uuid
+                devs = []
+                ports = []
+                for endpoint_id in service.service_endpoint_ids:
+                    devs.append(endpoint_id.device_id.device_uuid.uuid)
+                    ports.append(endpoint_id.endpoint_uuid.uuid)
+                src = devs[0]
+                dst = devs[1]
+                bidir = None
+                ob_band = None
+                bitrate = 100
+                for constraint in service.service_constraints:
+                    if "bandwidth" in constraint.custom.constraint_type:
+                        bitrate = int(float(constraint.custom.constraint_value))
+                    elif "bidirectionality" in constraint.custom.constraint_type:
+                        bidir = int(constraint.custom.constraint_value)
+                    elif "optical-band-width" in constraint.custom.constraint_type:
+                        ob_band = int(constraint.custom.constraint_value)
+                        
+                
+                # to get the reply form the optical module
+                reply_txt = add_lightpath(src, dst, bitrate, bidir, ob_band)
+                
+                # reply with 2 transponders and 2 roadms
+                reply_json = json.loads(reply_txt)
+                optical_band_txt = ""
+                if "new_optical_band" in reply_json.keys():
+                    if reply_json["new_optical_band"] == 1:
+                        if reply_json["parent_opt_band"]:
+                            if "parent_opt_band" in reply_json.keys():
+                                parent_ob = reply_json["parent_opt_band"]
+                                LOGGER.debug('Parent optical-band={}'.format(parent_ob))
+                                optical_band_txt = get_optical_band(parent_ob)
+                                LOGGER.debug('optical-band details={}'.format(optical_band_txt))
+                            else:
+                                LOGGER.debug('expected optical band not found')
+                        else:
+                            LOGGER.debug('expected optical band not found')
+                    else:
+                        LOGGER.debug('Using existing optical band')
+                else:
+                    LOGGER.debug('Using existing optical band')
+                if reply_txt is not None:
+                    optical_reply = adapt_reply(devices, _service, reply_json, context_uuid_x, topology_uuid_x, optical_band_txt)
+                    LOGGER.debug('optical_reply={:s}'.format(
+                        grpc_message_to_json_string(optical_reply)))
+
+                    tasks_scheduler.compose_from_pathcompreply(
+                        optical_reply, is_delete=False)
+             
             if num_disjoint_paths is None or num_disjoint_paths in {0, 1}:
                 pathcomp_request.shortest_path.Clear()              # pylint: disable=no-member
             else:
@@ -280,6 +345,30 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
             context_client.RemoveService(request)
             return Empty()
 
+        if service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
+            devs = []
+           
+            context_id_x = json_context_id(DEFAULT_CONTEXT_NAME)
+            topology_id_x = json_topology_id(
+                DEFAULT_TOPOLOGY_NAME, context_id_x)
+            topology_details = context_client.GetTopologyDetails(
+                TopologyId(**topology_id_x))
+            devices = topology_details.devices
+            for endpoint_id in service.service_endpoint_ids:
+                devs.append(endpoint_id.device_id.device_uuid.uuid)
+            src = get_device_name_from_uuid(devices, devs[0])
+            dst = get_device_name_from_uuid(devices, devs[1])
+           
+            bitrate = int(
+                float(service.service_constraints[0].custom.constraint_value))
+            if len(service.service_config.config_rules) > 0:
+                c_rules_dict = json.loads(
+                service.service_config.config_rules[0].custom.resource_value)
+                flow_id = c_rules_dict["flow_id"]
+              
+                reply = delete_lightpath(flow_id, src, dst, bitrate)
+               
+
         # Normal service
         # Feed TaskScheduler with this service and the sub-services and sub-connections related to this service.
         # TaskScheduler identifies inter-dependencies among them and produces a schedule of tasks (an ordered list of
diff --git a/src/service/service/service_handlers/__init__.py b/src/service/service/service_handlers/__init__.py
index eaf8f715aeff435b67bce77928e726daeb4729e2..f0628110fbd5f2b15308f05c9061c699a09dbcff 100644
--- a/src/service/service/service_handlers/__init__.py
+++ b/src/service/service/service_handlers/__init__.py
@@ -26,6 +26,7 @@ from .p4.p4_service_handler import P4ServiceHandler
 from .tapi_tapi.TapiServiceHandler import TapiServiceHandler
 from .tapi_xr.TapiXrServiceHandler import TapiXrServiceHandler
 from .e2e_orch.E2EOrchestratorServiceHandler import E2EOrchestratorServiceHandler
+from .oc.OCServiceHandler import OCServiceHandler
 
 SERVICE_HANDLERS = [
     (L2NMEmulatedServiceHandler, [
@@ -100,4 +101,10 @@ SERVICE_HANDLERS = [
             FilterFieldEnum.DEVICE_DRIVER : [DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE],
         }
     ]),
+    (OCServiceHandler, [
+        {
+            FilterFieldEnum.SERVICE_TYPE  : ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY,
+            FilterFieldEnum.DEVICE_DRIVER : DeviceDriverEnum.DEVICEDRIVER_OC,
+        }
+    ])
 ]
diff --git a/src/service/service/service_handlers/oc/ConfigRules.py b/src/service/service/service_handlers/oc/ConfigRules.py
new file mode 100644
index 0000000000000000000000000000000000000000..f4a46112e778bd01aa76322384d8adee942aaa5b
--- /dev/null
+++ b/src/service/service/service_handlers/oc/ConfigRules.py
@@ -0,0 +1,255 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from typing import Dict, List
+from common.tools.object_factory.ConfigRule import json_config_rule_delete, json_config_rule_set
+from service.service.service_handler_api.AnyTreeTools import TreeNode
+
+def setup_config_rules(
+    service_uuid : str, connection_uuid : str, device_uuid : str, endpoint_uuid : str, endpoint_name : str,
+    service_settings : TreeNode, endpoint_settings : TreeNode
+) -> List[Dict]:
+
+    if service_settings  is None: return []
+    if endpoint_settings is None: return []
+
+    json_settings          : Dict = service_settings.value
+    json_endpoint_settings : Dict = endpoint_settings.value
+
+    service_short_uuid        = service_uuid.split('-')[-1]
+    network_instance_name     = '{:s}-NetInst'.format(service_short_uuid)
+    network_interface_desc    = '{:s}-NetIf'.format(service_uuid)
+    network_subinterface_desc = '{:s}-NetSubIf'.format(service_uuid)
+
+    mtu                 = json_settings.get('mtu',                 1450 )    # 1512
+    #address_families    = json_settings.get('address_families',    []   )    # ['IPV4']
+    bgp_as              = json_settings.get('bgp_as',              0    )    # 65000
+    bgp_route_target    = json_settings.get('bgp_route_target',    '0:0')    # 65000:333
+
+    #router_id           = json_endpoint_settings.get('router_id',           '0.0.0.0')  # '10.95.0.10'
+    route_distinguisher = json_endpoint_settings.get('route_distinguisher', '0:0'    )  # '60001:801'
+    sub_interface_index = json_endpoint_settings.get('sub_interface_index', 0        )  # 1
+    vlan_id             = json_endpoint_settings.get('vlan_id',             1        )  # 400
+    address_ip          = json_endpoint_settings.get('address_ip',          '0.0.0.0')  # '2.2.2.1'
+    address_prefix      = json_endpoint_settings.get('address_prefix',      24       )  # 30
+    if_subif_name       = '{:s}.{:d}'.format(endpoint_name, vlan_id)
+
+    json_config_rules = [
+        json_config_rule_set(
+            '/network_instance[{:s}]'.format(network_instance_name), {
+                'name': network_instance_name, 'description': network_interface_desc, 'type': 'L3VRF',
+                'route_distinguisher': route_distinguisher,
+                #'router_id': router_id, 'address_families': address_families,
+        }),
+        json_config_rule_set(
+            '/interface[{:s}]'.format(endpoint_name), {
+                'name': endpoint_name, 'description': network_interface_desc, 'mtu': mtu,
+        }),
+        json_config_rule_set(
+            '/interface[{:s}]/subinterface[{:d}]'.format(endpoint_name, sub_interface_index), {
+                'name': endpoint_name, 'index': sub_interface_index,
+                'description': network_subinterface_desc, 'vlan_id': vlan_id,
+                'address_ip': address_ip, 'address_prefix': address_prefix,
+        }),
+        json_config_rule_set(
+            '/network_instance[{:s}]/interface[{:s}]'.format(network_instance_name, if_subif_name), {
+                'name': network_instance_name, 'id': if_subif_name, 'interface': endpoint_name,
+                'subinterface': sub_interface_index,
+        }),
+        json_config_rule_set(
+            '/network_instance[{:s}]/protocols[BGP]'.format(network_instance_name), {
+                'name': network_instance_name, 'identifier': 'BGP', 'protocol_name': 'BGP', 'as': bgp_as,
+        }),
+        json_config_rule_set(
+            '/network_instance[{:s}]/table_connections[STATIC][BGP][IPV4]'.format(network_instance_name), {
+                'name': network_instance_name, 'src_protocol': 'STATIC', 'dst_protocol': 'BGP',
+                'address_family': 'IPV4', #'default_import_policy': 'REJECT_ROUTE',
+        }),
+        json_config_rule_set(
+            '/network_instance[{:s}]/table_connections[DIRECTLY_CONNECTED][BGP][IPV4]'.format(
+                network_instance_name), {
+                'name': network_instance_name, 'src_protocol': 'DIRECTLY_CONNECTED', 'dst_protocol': 'BGP',
+                'address_family': 'IPV4', #'default_import_policy': 'REJECT_ROUTE',
+        }),
+        json_config_rule_set(
+            '/routing_policy/bgp_defined_set[{:s}_rt_import]'.format(network_instance_name), {
+                'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
+        }),
+        json_config_rule_set(
+            '/routing_policy/bgp_defined_set[{:s}_rt_import][route-target:{:s}]'.format(
+                network_instance_name, bgp_route_target), {
+                'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
+                'ext_community_member'  : 'route-target:{:s}'.format(bgp_route_target),
+        }),
+        json_config_rule_set(
+            '/routing_policy/policy_definition[{:s}_import]'.format(network_instance_name), {
+                'policy_name': '{:s}_import'.format(network_instance_name),
+        }),
+        json_config_rule_set(
+            '/routing_policy/policy_definition[{:s}_import]/statement[{:s}]'.format(
+                network_instance_name, '3'), {
+                'policy_name': '{:s}_import'.format(network_instance_name), 'statement_name': '3',
+                'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
+                'match_set_options': 'ANY', 'policy_result': 'ACCEPT_ROUTE',
+        }),
+        json_config_rule_set(
+            # pylint: disable=duplicate-string-formatting-argument
+            '/network_instance[{:s}]/inter_instance_policies[{:s}_import]'.format(
+                network_instance_name, network_instance_name), {
+                'name': network_instance_name, 'import_policy': '{:s}_import'.format(network_instance_name),
+        }),
+        json_config_rule_set(
+            '/routing_policy/bgp_defined_set[{:s}_rt_export]'.format(network_instance_name), {
+                'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
+        }),
+        json_config_rule_set(
+            '/routing_policy/bgp_defined_set[{:s}_rt_export][route-target:{:s}]'.format(
+                network_instance_name, bgp_route_target), {
+                'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
+                'ext_community_member'  : 'route-target:{:s}'.format(bgp_route_target),
+        }),
+        json_config_rule_set(
+            '/routing_policy/policy_definition[{:s}_export]'.format(network_instance_name), {
+                'policy_name': '{:s}_export'.format(network_instance_name),
+        }),
+        json_config_rule_set(
+            '/routing_policy/policy_definition[{:s}_export]/statement[{:s}]'.format(
+                network_instance_name, '3'), {
+                'policy_name': '{:s}_export'.format(network_instance_name), 'statement_name': '3',
+                'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
+                'match_set_options': 'ANY', 'policy_result': 'ACCEPT_ROUTE',
+        }),
+        json_config_rule_set(
+            # pylint: disable=duplicate-string-formatting-argument
+            '/network_instance[{:s}]/inter_instance_policies[{:s}_export]'.format(
+                network_instance_name, network_instance_name), {
+                'name': network_instance_name, 'export_policy': '{:s}_export'.format(network_instance_name),
+        }),
+    ]
+
+    return json_config_rules
+
+def teardown_config_rules(
+    service_uuid : str, connection_uuid : str, device_uuid : str, endpoint_uuid : str, endpoint_name : str,
+    service_settings : TreeNode, endpoint_settings : TreeNode
+) -> List[Dict]:
+
+    if service_settings  is None: return []
+    if endpoint_settings is None: return []
+
+    json_settings          : Dict = service_settings.value
+    json_endpoint_settings : Dict = endpoint_settings.value
+
+    #mtu                 = json_settings.get('mtu',                 1450 )    # 1512
+    #address_families    = json_settings.get('address_families',    []   )    # ['IPV4']
+    #bgp_as              = json_settings.get('bgp_as',              0    )    # 65000
+    bgp_route_target    = json_settings.get('bgp_route_target',    '0:0')    # 65000:333
+
+    #router_id           = json_endpoint_settings.get('router_id',           '0.0.0.0')  # '10.95.0.10'
+    #route_distinguisher = json_endpoint_settings.get('route_distinguisher', '0:0'    )  # '60001:801'
+    sub_interface_index = json_endpoint_settings.get('sub_interface_index', 0        )  # 1
+    vlan_id             = json_endpoint_settings.get('vlan_id',             1        )  # 400
+    #address_ip          = json_endpoint_settings.get('address_ip',          '0.0.0.0')  # '2.2.2.1'
+    #address_prefix      = json_endpoint_settings.get('address_prefix',      24       )  # 30
+
+    if_subif_name             = '{:s}.{:d}'.format(endpoint_name, vlan_id)
+    service_short_uuid        = service_uuid.split('-')[-1]
+    network_instance_name     = '{:s}-NetInst'.format(service_short_uuid)
+    #network_interface_desc    = '{:s}-NetIf'.format(service_uuid)
+    #network_subinterface_desc = '{:s}-NetSubIf'.format(service_uuid)
+
+    json_config_rules = [
+        json_config_rule_delete(
+            '/network_instance[{:s}]/interface[{:s}]'.format(network_instance_name, if_subif_name), {
+                'name': network_instance_name, 'id': if_subif_name,
+        }),
+        json_config_rule_delete(
+            '/interface[{:s}]/subinterface[{:d}]'.format(endpoint_name, sub_interface_index), {
+                'name': endpoint_name, 'index': sub_interface_index,
+        }),
+        json_config_rule_delete(
+            '/interface[{:s}]'.format(endpoint_name), {
+                'name': endpoint_name,
+        }),
+        json_config_rule_delete(
+            '/network_instance[{:s}]/table_connections[DIRECTLY_CONNECTED][BGP][IPV4]'.format(
+                network_instance_name), {
+                'name': network_instance_name, 'src_protocol': 'DIRECTLY_CONNECTED', 'dst_protocol': 'BGP',
+                'address_family': 'IPV4',
+        }),
+        json_config_rule_delete(
+            '/network_instance[{:s}]/table_connections[STATIC][BGP][IPV4]'.format(network_instance_name), {
+                'name': network_instance_name, 'src_protocol': 'STATIC', 'dst_protocol': 'BGP',
+                'address_family': 'IPV4',
+        }),
+        json_config_rule_delete(
+            '/network_instance[{:s}]/protocols[BGP]'.format(network_instance_name), {
+                'name': network_instance_name, 'identifier': 'BGP', 'protocol_name': 'BGP',
+        }),
+        json_config_rule_delete(
+            # pylint: disable=duplicate-string-formatting-argument
+            '/network_instance[{:s}]/inter_instance_policies[{:s}_import]'.format(
+                network_instance_name, network_instance_name), {
+            'name': network_instance_name,
+        }),
+        json_config_rule_delete(
+            '/routing_policy/policy_definition[{:s}_import]/statement[{:s}]'.format(
+                network_instance_name, '3'), {
+                'policy_name': '{:s}_import'.format(network_instance_name), 'statement_name': '3',
+        }),
+        json_config_rule_delete(
+            '/routing_policy/policy_definition[{:s}_import]'.format(network_instance_name), {
+                'policy_name': '{:s}_import'.format(network_instance_name),
+        }),
+        json_config_rule_delete(
+            '/routing_policy/bgp_defined_set[{:s}_rt_import][route-target:{:s}]'.format(
+                network_instance_name, bgp_route_target), {
+                'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
+                'ext_community_member'  : 'route-target:{:s}'.format(bgp_route_target),
+        }),
+        json_config_rule_delete(
+            '/routing_policy/bgp_defined_set[{:s}_rt_import]'.format(network_instance_name), {
+                'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
+        }),
+        json_config_rule_delete(
+            # pylint: disable=duplicate-string-formatting-argument
+            '/network_instance[{:s}]/inter_instance_policies[{:s}_export]'.format(
+                network_instance_name, network_instance_name), {
+                'name': network_instance_name,
+        }),
+        json_config_rule_delete(
+            '/routing_policy/policy_definition[{:s}_export]/statement[{:s}]'.format(
+                network_instance_name, '3'), {
+                'policy_name': '{:s}_export'.format(network_instance_name), 'statement_name': '3',
+        }),
+        json_config_rule_delete(
+            '/routing_policy/policy_definition[{:s}_export]'.format(network_instance_name), {
+                'policy_name': '{:s}_export'.format(network_instance_name),
+        }),
+        json_config_rule_delete(
+            '/routing_policy/bgp_defined_set[{:s}_rt_export][route-target:{:s}]'.format(
+                network_instance_name, bgp_route_target), {
+                'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
+                'ext_community_member'  : 'route-target:{:s}'.format(bgp_route_target),
+        }),
+        json_config_rule_delete(
+            '/routing_policy/bgp_defined_set[{:s}_rt_export]'.format(network_instance_name), {
+                'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
+        }),
+        json_config_rule_delete(
+            '/network_instance[{:s}]'.format(network_instance_name), {
+                'name': network_instance_name
+        }),
+    ]
+    return json_config_rules
diff --git a/src/service/service/service_handlers/oc/OCServiceHandler.py b/src/service/service/service_handlers/oc/OCServiceHandler.py
new file mode 100644
index 0000000000000000000000000000000000000000..89e9d23edfcb4b529f1ee02a7b978994e5a87684
--- /dev/null
+++ b/src/service/service/service_handlers/oc/OCServiceHandler.py
@@ -0,0 +1,274 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import json, logging
+from typing import Any, List, Optional, Tuple, Union
+from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method
+from common.proto.context_pb2 import ConfigRule, DeviceId, Service
+from common.tools.object_factory.Device import json_device_id
+from common.type_checkers.Checkers import chk_type
+from service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching
+from service.service.service_handler_api._ServiceHandler import _ServiceHandler
+from service.service.service_handler_api.SettingsHandler import SettingsHandler
+from service.service.task_scheduler.TaskExecutor import TaskExecutor
+from .ConfigRules import setup_config_rules, teardown_config_rules
+
+from common.proto.context_pb2 import EndPointId
+from .OCTools import convert_endpoints_to_flows, handle_flows_names
+LOGGER = logging.getLogger(__name__)
+
+METRICS_POOL = MetricsPool('Service', 'Handler', labels={'handler': 'l3nm_emulated'})
+
+class OCServiceHandler(_ServiceHandler):
+    def __init__(   # pylint: disable=super-init-not-called
+        self, service : Service, task_executor : TaskExecutor, **settings
+    ) -> None:
+        self.__service = service
+        self.__task_executor = task_executor
+        self.__settings_handler = SettingsHandler(service.service_config, **settings)
+
+
+
+
+    '''
+    @metered_subclass_method(METRICS_POOL)
+    def SetEndpoint(
+        self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None
+    ) -> List[Union[bool, Exception]]:
+   
+        chk_type('endpoints', endpoints, list)
+        if len(endpoints) == 0: return []
+
+        service_uuid = self.__service.service_id.service_uuid.uuid
+        if self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid)):
+            settings = self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid))
+        else:
+            settings = self.__settings_handler.get('/settings')
+        LOGGER.info("AAAAAAAAAAAAAAAAAAAA settings={}".format(settings))
+        
+        settings = self.__settings_handler.get('/settings')
+        #new structure
+        #in, dev, out, topo(opt)
+        entries = List[Tuple[str, str, str Optional[str]]]
+        entry_tuple = device_uuid, endpoint_uuid, topology_uuid
+        entries.append(endpoint_id_tuple)
+        for i in range (1, len(endpoints)):
+            endpoint_x = endpoints[i]
+            dev_x = endpoint_x[0]
+            if_x = endpoint_x[1]
+            
+            
+
+
+
+        results = []
+        for endpoint in endpoints:
+            try:
+                device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint)
+
+                device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid)))
+                endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid)
+                endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj)
+                endpoint_name = endpoint_obj.name
+
+                json_config_rules = setup_config_rules(
+                    service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name,
+                    settings, endpoint_settings)
+                LOGGER.info("Start configuring device %s",settings)
+                if (settings): 
+                    self.__task_executor.configure_optical_device(device_obj,settings)    
+                if len(json_config_rules) > 0:
+                    LOGGER.info("Start configuring device")
+                    del device_obj.device_config.config_rules[:]
+                    for json_config_rule in json_config_rules:
+                        device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule))
+                    self.__task_executor.configure_optical_device(device_obj)    
+                    #self.__task_executor.configure_device(device_obj)
+
+                results.append(True)
+            except Exception as e: # pylint: disable=broad-except
+                LOGGER.exception('Unable to SetEndpoint({:s})'.format(str(endpoint)))
+                results.append(e)
+
+        return results
+    '''
+
+
+    @metered_subclass_method(METRICS_POOL)
+    def SetEndpoint(
+        self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None
+    ) -> List[Union[bool, Exception]]:
+   
+        chk_type('endpoints', endpoints, list)
+        if len(endpoints) == 0: return []
+        is_opticalband =False
+        #service_uuid = self.__service.service_id.service_uuid.uuid
+        settings=None
+        if self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid)):
+            is_opticalband=True
+            settings = self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid))
+        else:
+            settings = self.__settings_handler.get('/settings')
+       
+        LOGGER.debug("Andrea111 settings={}".format(settings))
+       # settings = self.__settings_handler.get('/settings')
+
+        #flow is the new variable that stores input-output relationship
+        
+        flows = convert_endpoints_to_flows(endpoints)
+        #handled_flows=handle_flows_names(flows=flows,task_executor=self.__task_executor)
+        LOGGER.debug("AndreaXXX dict of flows= {}".format(flows))
+        #LOGGER.info("Handled Flows %s",handled_flows)
+        
+        results = []
+        #new cycle for setting optical devices
+        for device_uuid in flows.keys():
+            try:
+                dev_flows = flows[device_uuid]
+                device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid)))
+                LOGGER.debug("Andrea567 device_obj={}".format(device_obj))
+                '''
+                #to be imported in the device handler
+                endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid)
+                endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj)
+                endpoint_name = endpoint_obj.name
+                '''
+                if (settings): 
+                    LOGGER.debug("Andrea234 settings={}".format(settings))
+                    self.__task_executor.configure_optical_device(device_obj, settings, dev_flows, is_opticalband)
+                results.append(True)
+            except Exception as e: # pylint: disable=broad-except
+                LOGGER.exception('Unable to configure Device({:s})'.format(str(device_uuid)))
+                results.append(e) 
+        
+        '''
+        for endpoint in endpoints:
+            try:
+                device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint)
+
+                device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid)))
+                endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid)
+                endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj)
+                endpoint_name = endpoint_obj.name
+
+                # json_config_rules = setup_config_rules(
+                #     service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name,
+                #     settings, endpoint_settings)
+               
+                if (settings): 
+                    LOGGER.debug("Andrea234 settings={}".format(settings))
+                    self.__task_executor.configure_optical_device(device_obj,settings,handled_flows,is_opticalband)
+                #we don't use config_rules    
+                # if len(json_config_rules) > 0:
+                #     LOGGER.debug("VBNMHGStart configuring device")
+                #     del device_obj.device_config.config_rules[:]
+                #     for json_config_rule in json_config_rules:
+                #         device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule))
+                #     self.__task_executor.configure_optical_device(device_obj)    
+                    #self.__task_executor.configure_device(device_obj)
+
+                results.append(True)
+            except Exception as e: # pylint: disable=broad-except
+                LOGGER.exception('Unable to SetEndpoint({:s})'.format(str(endpoint)))
+                results.append(e)
+        '''
+
+        return results
+
+    @metered_subclass_method(METRICS_POOL)
+    def DeleteEndpoint(
+        self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None
+    ) -> List[Union[bool, Exception]]:
+        chk_type('endpoints', endpoints, list)
+        if len(endpoints) == 0: return []
+
+        service_uuid = self.__service.service_id.service_uuid.uuid
+        settings = self.__settings_handler.get('/settings')
+
+        results = []
+        for endpoint in endpoints:
+            try:
+                device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint)
+
+                device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid)))
+                endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid)
+                endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj)
+                endpoint_name = endpoint_obj.name
+
+                json_config_rules = teardown_config_rules(
+                    service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name,
+                    settings, endpoint_settings)
+
+                if len(json_config_rules) > 0:
+                    del device_obj.device_config.config_rules[:]
+                    for json_config_rule in json_config_rules:
+                        device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule))
+                    self.__task_executor.configure_device(device_obj)
+
+                results.append(True)
+            except Exception as e: # pylint: disable=broad-except
+                LOGGER.exception('Unable to DeleteEndpoint({:s})'.format(str(endpoint)))
+                results.append(e)
+
+        return results
+
+    @metered_subclass_method(METRICS_POOL)
+    def SetConstraint(self, constraints : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+        chk_type('constraints', constraints, list)
+        if len(constraints) == 0: return []
+
+        msg = '[SetConstraint] Method not implemented. Constraints({:s}) are being ignored.'
+        LOGGER.warning(msg.format(str(constraints)))
+        return [True for _ in range(len(constraints))]
+
+    @metered_subclass_method(METRICS_POOL)
+    def DeleteConstraint(self, constraints : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+        chk_type('constraints', constraints, list)
+        if len(constraints) == 0: return []
+
+        msg = '[DeleteConstraint] Method not implemented. Constraints({:s}) are being ignored.'
+        LOGGER.warning(msg.format(str(constraints)))
+        return [True for _ in range(len(constraints))]
+
+    @metered_subclass_method(METRICS_POOL)
+    def SetConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+        chk_type('resources', resources, list)
+        if len(resources) == 0: return []
+
+        results = []
+        for resource in resources:
+            try:
+                resource_value = json.loads(resource[1])
+                self.__settings_handler.set(resource[0], resource_value)
+                results.append(True)
+            except Exception as e: # pylint: disable=broad-except
+                LOGGER.exception('Unable to SetConfig({:s})'.format(str(resource)))
+                results.append(e)
+
+        return results
+
+    @metered_subclass_method(METRICS_POOL)
+    def DeleteConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+        chk_type('resources', resources, list)
+        if len(resources) == 0: return []
+
+        results = []
+        for resource in resources:
+            try:
+                self.__settings_handler.delete(resource[0])
+            except Exception as e: # pylint: disable=broad-except
+                LOGGER.exception('Unable to DeleteConfig({:s})'.format(str(resource)))
+                results.append(e)
+
+        return results
diff --git a/src/service/service/service_handlers/oc/OCTools.py b/src/service/service/service_handlers/oc/OCTools.py
new file mode 100644
index 0000000000000000000000000000000000000000..c8bddefb94e352754f0d3bdafd21fa4b12317cdb
--- /dev/null
+++ b/src/service/service/service_handlers/oc/OCTools.py
@@ -0,0 +1,143 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+from service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching
+from typing import Dict, Any, List, Optional, Tuple
+import logging
+from common.proto.context_pb2 import ConfigRule, DeviceId, Service
+from common.tools.object_factory.Device import json_device_id
+log = logging.getLogger(__name__)
+
+#def convert_endpoints_to_flows(endpoints : List[Tuple[str, str, Optional[str]]])->Dict[str: List[Tuple[str, str]]]:
+
+def convert_endpoints_to_flows(endpoints : List[Tuple[str, str, Optional[str]]])->Dict:
+    #entries = List[Tuple[str, str, str, Optional[str]]]
+    #entries = Dict[str: List[Tuple[str, str]]]
+    entries = {}
+    #tuple is in, out
+    end = len(endpoints)
+    i = 0
+    bidir = 0
+    log.debug("end={}".format(end))
+    while(i < end):
+        endpoint = endpoints[i]
+        device_uuid, endpoint_uuid = endpoint[0:2]
+        log.debug("current OCTools step {}, {}, {}".format(i, device_uuid, endpoint_uuid))
+        if device_uuid not in entries.keys():
+            entries[device_uuid] = []
+        if i == 0:
+            entry_tuple = "0", endpoint_uuid
+            entries[device_uuid].append(entry_tuple)
+            next_endpoint = endpoints[i+1]
+            next_device_uuid, next_endpoint_uuid = next_endpoint[0:2]
+            if next_device_uuid == device_uuid:
+                bidir = 1
+                log.debug("connection is bidirectional")
+                entry_tuple = next_endpoint_uuid, "0"
+                entries[device_uuid].append(entry_tuple)
+                i = i + 1
+            else:
+                log.debug("connection is unidirectional")
+        else:
+            if not bidir:
+                if i == end-1:
+                    #is the last node
+                    entry_tuple = endpoint_uuid, "0"
+                    entries[device_uuid].append(entry_tuple)
+                else:
+                    #it is a transit node
+                    next_endpoint = endpoints[i+1]
+                    next_device_uuid, next_endpoint_uuid = next_endpoint[0:2]
+                    if next_device_uuid == device_uuid:
+                        entry_tuple = endpoint_uuid, next_endpoint_uuid
+                        entries[device_uuid].append(entry_tuple)
+                        i = i + 1
+                        log.debug("current OCTools step {}, {}, {}".format(i, next_device_uuid, device_uuid))
+                    else:
+                        log.debug("ERROR in unidirectional connection 4")
+                        return {}
+            if bidir:
+                log.debug("Ocheck i {}, {}, {}".format(i, i+1, end-1))
+                if i + 1 == end-1:
+                    log.debug("current OCTools step {}, {}, {}".format(i, device_uuid, endpoint_uuid))
+                    #is the last node
+                    entry_tuple = endpoint_uuid, "0"
+                    entries[device_uuid].append(entry_tuple)
+                    next_endpoint = endpoints[i+1]
+                    log.debug("OCTools i+1 step {}, {}, {}".format(i+1, next_device_uuid, device_uuid))
+
+                    next_device_uuid, next_endpoint_uuid = next_endpoint[0:2]
+                    if next_device_uuid == device_uuid:
+                        entry_tuple = "0", next_endpoint_uuid
+                        entries[device_uuid].append(entry_tuple)
+                        i = i + 1
+                    else:
+                        log.debug("ERROR in bidirectional connection 2")
+                        return entries
+                else:
+                    log.debug("OCTools i+1+2+3 step {}, {}, {}".format(i+1, next_device_uuid, device_uuid))
+                    #i+1
+                    next_endpoint = endpoints[i+1]
+                    next_device_uuid, next_endpoint_uuid = next_endpoint[0:2]
+                    if next_device_uuid == device_uuid:
+                        entry_tuple = endpoint_uuid, next_endpoint_uuid
+                        entries[device_uuid].append(entry_tuple)
+                    else:
+                        log.debug("ERROR in bidirectional connection 3")
+                        log.debug("{}, {}, {}".format(i, next_device_uuid, device_uuid))
+                        return entries
+                    #i+2
+                    next_2_endpoint = endpoints[i+2]
+                    next_2_device_uuid, next_2_endpoint_uuid = next_2_endpoint[0:2]                    
+                    #i+3
+                    next_3_endpoint = endpoints[i+3]
+                    next_3_device_uuid, next_3_endpoint_uuid = next_3_endpoint[0:2]
+                    if next_2_device_uuid == next_3_device_uuid and next_3_device_uuid == device_uuid:
+                        entry_tuple = next_2_endpoint_uuid, next_3_endpoint_uuid
+                        entries[device_uuid].append(entry_tuple)
+                        i = i + 3
+                    else:
+                        log.debug("ERROR in bidirection connection 4")
+                        return {}
+        i = i + 1
+    return entries
+
+
+def get_device_endpint_name (endpoint_uuid:str,device_uuid:str,task_executor)->Tuple:
+    
+  
+
+    device_obj = task_executor.get_device(DeviceId(**json_device_id(device_uuid)))
+    endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid)
+    endpoint_name = endpoint_obj.name
+    
+    return (device_obj.name,endpoint_name)
+
+def handle_flows_names (task_executor,flows:dict)->Dict :
+    new_flows={}
+    for index,( device_uuid_key , device_endpoints_list) in enumerate(flows.items()):
+        for endpoint_tupple in device_endpoints_list:
+            source_port=None 
+            destination_port=None
+            device_name=""
+            source_endpoint,destination_endpoint =endpoint_tupple
+            if (source_endpoint !='0'):
+                if get_device_endpint_name(source_endpoint,device_uuid_key,task_executor) is not None:
+                   device_name,source_port=get_device_endpint_name(source_endpoint,device_uuid_key,task_executor) 
+            if (destination_endpoint !='0'):
+                if get_device_endpint_name(destination_endpoint,device_uuid_key,task_executor) is not None:   
+                    device_name,destination_port=get_device_endpint_name(destination_endpoint,device_uuid_key,task_executor) 
+            if (device_name  not in new_flows):
+                new_flows[device_name]=[]    
+            new_flows[device_name].append((source_port,destination_port))    
+    return new_flows         
\ No newline at end of file
diff --git a/src/service/service/service_handlers/oc/__init__.py b/src/service/service/service_handlers/oc/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612
--- /dev/null
+++ b/src/service/service/service_handlers/oc/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
diff --git a/src/service/service/task_scheduler/TaskExecutor.py b/src/service/service/task_scheduler/TaskExecutor.py
index ae0f1be7da291a5dc025641cb606f7a7706059ca..3718c01f46b5c440b177c3506520dce6a974c802 100644
--- a/src/service/service/task_scheduler/TaskExecutor.py
+++ b/src/service/service/task_scheduler/TaskExecutor.py
@@ -16,7 +16,7 @@ import logging #, json
 from enum import Enum
 from typing import TYPE_CHECKING, Any, Dict, Optional, Union
 from common.method_wrappers.ServiceExceptions import NotFoundException
-from common.proto.context_pb2 import Connection, ConnectionId, Device, DeviceDriverEnum, DeviceId, Service, ServiceId
+from common.proto.context_pb2 import Connection, ConnectionId, Device, DeviceDriverEnum, DeviceId, Service, ServiceId,MyConfig,MyConfigId
 from common.tools.context_queries.Connection import get_connection_by_id
 from common.tools.context_queries.Device import get_device
 from common.tools.context_queries.Service import get_service_by_id
@@ -108,10 +108,74 @@ class TaskExecutor:
         return device
 
     def configure_device(self, device : Device) -> None:
+        self._context_client.SelectMyConfig()
         device_key = get_device_key(device.device_id)
         self._device_client.ConfigureDevice(device)
         self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device)
-
+    
+    # New function Andrea for Optical Devices 
+    def configure_optical_device(self,device:Device,settings:str,flows:list,is_opticalband:bool):
+        
+        
+        device_key = get_device_key(device.device_id)
+        myid=MyConfigId()
+        myid.myconfig_uuid=device.device_id.device_uuid.uuid
+        myConfig=MyConfig()
+     
+        setting =settings.value if settings else ""
+      
+        new_config={}
+        try:
+          result=self._context_client.SelectMyConfig(myid)
+          new_config=eval(result.config)
+          LOGGER.info("result %s",result)
+          if result is not None :
+              
+              new_config["new_config"]=setting
+              new_config["is_opticalband"]=is_opticalband
+              new_config["flow"]=flows
+              result.config = str(new_config)
+              myConfig.CopyFrom(result)
+                
+              self._device_client.ConfigureOpticalDevice(myConfig)
+             
+          self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device)
+        except Exception as e:
+            LOGGER.debug("error in config my config %s",e)
+    
+    '''
+    # For Optical Devices 
+    def configure_optical_device (self,device:Device,settings:str,flows:dict,is_opticalband:bool)   :
+        
+       
+        device_key = get_device_key(device.device_id)
+        myid=MyConfigId()
+        myid.myconfig_uuid=device.device_id.device_uuid.uuid
+        myConfig=MyConfig()
+     
+        setting =settings.value if settings else ""
+      
+        new_config={}
+        try:
+          result=self._context_client.SelectMyConfig(myid)
+          new_config=eval(result.config)
+          
+          if result is not None :
+              
+              new_config["new_config"]=setting
+              new_config["is_opticalband"]=is_opticalband
+              new_config["flow"]=flows
+              result.config = str(new_config)
+              myConfig.CopyFrom(result)
+                
+              self._device_client.ConfigureOpticalDevice(myConfig)
+             
+          self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device)
+        except Exception as e:
+            LOGGER.debug("error in config my config %s",e)
+    '''        
+    
+            
     def get_device_controller(self, device : Device) -> Optional[Device]:
         #json_controller = None
         #for config_rule in device.device_config.config_rules:
diff --git a/src/service/service/tools/OpticalTools.py b/src/service/service/tools/OpticalTools.py
new file mode 100644
index 0000000000000000000000000000000000000000..227be2765fbd6bbc779e53505b833fc8bf08873f
--- /dev/null
+++ b/src/service/service/tools/OpticalTools.py
@@ -0,0 +1,290 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# 
+
+import json
+import requests
+import uuid
+from common.Constants import *
+from typing import Dict, List
+from common.proto.context_pb2 import(
+    Device, DeviceId, Service, Connection, EndPointId, TopologyId, ContextId, Uuid, ConfigRule, ConfigActionEnum, ConfigRule_Custom)
+from common.proto.pathcomp_pb2 import PathCompReply
+from typing import Dict, List, Optional, Tuple
+
+from context.service.database.uuids.EndPoint import endpoint_get_uuid
+
+
+from service.service.tools.replies import reply_uni_txt, optical_band_uni_txt, reply_bid_txt, optical_band_bid_txt
+
+log = logging.getLogger(__name__)
+
+testing = True
+                
+
+def get_uuids_from_names(devices: List[Device], device_name: str, port_name: str):
+
+    device_uuid = ""
+    port_uuid = ""
+    for device in devices:
+        if device.name == device_name:
+          
+            device_uuid  = device.device_id.device_uuid.uuid
+         
+            for ep in device.device_endpoints:
+                if ep.name == port_name:
+                    port_uuid = ep.endpoint_id.endpoint_uuid.uuid
+                  
+                    return device_uuid, port_uuid
+    return "", ""
+
+
+def get_names_from_uuids(devices: List[Device], device_uuid: str, port_uuid: str):
+    device_name = ""
+    port_name = ""
+    for device in devices:
+        if device.device_id.device_uuid.uuid == device_uuid:
+            device_name  = device.name
+            for ep in device.device_endpoints:
+                if ep.endpoint_id.endpoint_uuid.uuid == port_uuid:
+                    port_name = ep.name
+                    return device_name, port_name
+    return "", ""
+
+def get_device_name_from_uuid(devices: List[Device], device_uuid: str):
+    device_name = ""
+    
+    for device in devices:
+        if device.device_id.device_uuid.uuid == device_uuid:
+            device_name  = device.name
+            return device_name
+    return ""
+
+
+def add_lightpath(src, dst, bitrate, bidir, ob_band) -> str:
+    if not testing:
+        urlx = ""
+        headers = {"Content-Type": "application/json"}
+        if ob_band is None:
+            if bidir is None:
+                bidir = 1
+            urlx = "http://{}:{}/OpticalTFS/AddFlexLightpath/{}/{}/{}/{}".format(OPTICAL_IP, OPTICAL_PORT, src, dst, bitrate, bidir)
+        else:
+            if bidir is None:
+                bidir = 1
+            urlx = "http://{}:{}/OpticalTFS/AddFlexLightpath/{}/{}/{}/{}/{}".format(OPTICAL_IP, OPTICAL_PORT, src, dst, bitrate, bidir, ob_band)
+        r = requests.put(urlx, headers=headers)
+        reply = r.text 
+        return reply
+    else:
+        if bidir is not None:
+            if bidir == 0:        
+                return reply_uni_txt
+        return reply_bid_txt
+                
+
+def get_optical_band(idx) -> str:
+    if not testing:
+        urlx = "http://{}:{}/OpticalTFS/GetOpticalBand/{}".format(OPTICAL_IP, OPTICAL_PORT, idx)
+        headers = {"Content-Type": "application/json"}
+        r = requests.get(urlx, headers=headers)
+        reply = r.text 
+        return reply
+    else:
+        if str(idx) == "1":
+            return optical_band_bid_txt
+        else:
+            return optical_band_uni_txt
+
+    
+def delete_lightpath(flow_id, src, dst, bitrate) -> str:
+    reply = "200"
+    if not testing:
+        urlx = "http://{}:{}/OpticalTFS/DelLightpath/{}/{}/{}/{}".format(OPTICAL_IP, OPTICAL_PORT, flow_id, src, dst, bitrate)
+
+        headers = {"Content-Type": "application/json"}
+        r = requests.delete(urlx, headers=headers)
+        reply = r.text 
+    return reply
+
+
+def get_lightpaths() -> str:
+    urlx = "http://{}:{}/OpticalTFS/GetLightpaths".format(OPTICAL_IP, OPTICAL_PORT)
+
+    headers = {"Content-Type": "application/json"}
+    r = requests.get(urlx, headers=headers)
+    reply = r.text 
+    return reply
+
+        
+def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_band_txt) ->  PathCompReply:
+    opt_reply = PathCompReply()
+    topo = TopologyId(context_id=ContextId(context_uuid=Uuid(uuid=context_id)),topology_uuid=Uuid(uuid=topology_id))
+    #add optical band connection first
+    rules_ob= []
+    ob_id = 0
+    if optical_band_txt != "":
+        ob_json = json.loads(optical_band_txt)
+        ob = ob_json
+        connection_ob = add_connection_to_reply(opt_reply)
+        uuuid_x = str(uuid.uuid4())
+        connection_ob.connection_id.connection_uuid.uuid = uuuid_x
+        connection_ob.service_id.CopyFrom(service.service_id)
+       
+        ob_id = ob["optical_band_id"]        
+        obt = ob["band_type"]
+        if obt == "l_slots":
+          band_type = "L_BAND"
+        elif obt == "s_slots":
+          band_type = "S_BAND"
+        else:
+          band_type = "C_BAND"
+          
+        freq = ob["freq"]
+        bx = ob["band"]
+        lf = int(int(freq)-int(bx/2))
+        uf = int(int(freq)+int(bx/2))
+        val_ob = {"band_type": band_type, "low-freq": lf, "up-freq": uf, "frequency": freq, "band": bx, "ob_id": ob_id}
+        rules_ob.append(ConfigRule_Custom(resource_key="/settings-ob_{}".format(uuuid_x), resource_value=json.dumps(val_ob)))
+        bidir_ob = ob["bidir"]
+        for devxb in ob["flows"].keys():
+            log.debug("optical-band device {}".format(devxb))
+            in_end_point_b = "0"
+            out_end_point_b = "0"
+            in_end_point_f = ob["flows"][devxb]["f"]["in"]
+            out_end_point_f = ob["flows"][devxb]["f"]["out"]
+            log.debug("optical-band ports {}, {}".format(in_end_point_f, out_end_point_f))
+            if bidir_ob:
+                in_end_point_b = ob["flows"][devxb]["b"]["in"]
+                out_end_point_b = ob["flows"][devxb]["b"]["out"]
+                log.debug("optical-band ports {}, {}".format(in_end_point_b, out_end_point_b))
+            #if (in_end_point_f == "0" or out_end_point_f == "0") and (in_end_point_b == "0" or out_end_point_b == "0"):
+            if in_end_point_f != "0":
+                d_ob, p_ob = get_uuids_from_names(devices, devxb, in_end_point_f)
+                if d_ob != "" and p_ob != "":
+                    end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob))
+                    connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_b)
+                else:
+                    log.INFO("no map device port for device {} port {}".format(devxb, in_end_point_f))
+
+            if out_end_point_f != "0":
+                d_ob, p_ob = get_uuids_from_names(devices, devxb, out_end_point_f)
+                if d_ob != "" and p_ob != "":
+                    end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob))
+                    connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_b) 
+                else:
+                    log.INFO("no map device port for device {} port {}".format(devxb, out_end_point_f))
+            if in_end_point_b != "0":
+                d_ob, p_ob = get_uuids_from_names(devices, devxb, in_end_point_b)
+                if d_ob != "" and p_ob != "":
+                    end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob))
+                    connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_b) 
+                else:
+                    log.INFO("no map device port for device {} port {}".format(devxb, in_end_point_b))
+            if out_end_point_b != "0":
+                d_ob, p_ob = get_uuids_from_names(devices, devxb, out_end_point_b)
+                if d_ob != "" and p_ob != "":
+                    end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob))
+                    connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_b)
+                else:
+                    log.INFO("no map device port for device {} port {}".format(devxb, out_end_point_b))
+            log.debug("optical-band connection {}".format(connection_ob))
+    r = reply_json
+    bidir_f = r["bidir"]
+    connection_f = add_connection_to_reply(opt_reply)
+    connection_f.connection_id.connection_uuid.uuid = str(uuid.uuid4())
+    connection_f.service_id.CopyFrom(service.service_id)
+    for devx in r["flows"].keys():
+        log.debug("lightpath device {}".format(devx))
+        in_end_point_b = "0"
+        out_end_point_b = "0"
+        
+        in_end_point_f = r["flows"][devx]["f"]["in"]
+        out_end_point_f = r["flows"][devx]["f"]["out"]
+        log.debug("lightpath ports {}, {}".format(in_end_point_f, out_end_point_f))
+        if bidir_f:
+            in_end_point_b = r["flows"][devx]["b"]["in"]
+            out_end_point_b = r["flows"][devx]["b"]["out"]
+            log.debug("lightpath ports {}, {}".format(in_end_point_b, out_end_point_b))
+        if in_end_point_f != "0":
+            d, p = get_uuids_from_names(devices, devx, in_end_point_f)
+            if d != "" and p != "":
+                end_point = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d)), endpoint_uuid=Uuid(uuid=p))
+                connection_f.path_hops_endpoint_ids.add().CopyFrom(end_point) 
+            else:
+                log.INFO("no map device port for device {} port {}".format(devx, in_end_point_f))
+        if out_end_point_f != "0":
+            d, p = get_uuids_from_names(devices, devx, out_end_point_f)
+            if d != "" and p != "":
+                end_point = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d)), endpoint_uuid=Uuid(uuid=p))
+                connection_f.path_hops_endpoint_ids.add().CopyFrom(end_point)
+            else:
+                log.INFO("no map device port for device {} port {}".format(devx, out_end_point_f))
+        if in_end_point_b != "0":
+            d, p = get_uuids_from_names(devices, devx, in_end_point_b)
+            if d != "" and p != "":
+                end_point = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d)), endpoint_uuid=Uuid(uuid=p))
+                connection_f.path_hops_endpoint_ids.add().CopyFrom(end_point) 
+            else:
+                log.INFO("no map device port for device {} port {}".format(devx, in_end_point_b))
+        if out_end_point_b != "0":
+            d, p = get_uuids_from_names(devices, devx, out_end_point_b)
+            if d != "" and p != "":
+                end_point = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d)), endpoint_uuid=Uuid(uuid=p))
+                connection_f.path_hops_endpoint_ids.add().CopyFrom(end_point) 
+            else:
+                log.INFO("no map device port for device {} port {}".format(devx, out_end_point_b))      
+    #check that list of endpoints is not empty  
+    if len(connection_ob.path_hops_endpoint_ids) == 0:
+        log.debug("deleting empty optical-band connection")
+        opt_reply.connections.remove(connection_ob)
+    
+    #inizialize custom optical parameters
+    band = r["band"]
+    op_mode = r["op-mode"]
+    frequency = r["freq"]
+    flow_id = r["flow_id"]
+    r_type = r["band_type"]
+    if r_type == "l_slots":
+        band_type = "L_BAND"
+    elif r_type == "s_slots":
+        band_type = "S_BAND"
+    else:
+        band_type = "C_BAND"
+        
+    if ob_id is not 0:
+        val = {"frequency": frequency, "operational-mode": op_mode, "band": band, "flow_id": flow_id, "ob_id": ob_id, "band_type": band_type,}
+    else:
+        val = {"frequency": frequency, "operational-mode": op_mode, "band": band, "flow_id": flow_id, "band_type": band_type,}
+    custom_rule = ConfigRule_Custom(resource_key="/settings", resource_value=json.dumps(val))
+    rule = ConfigRule(action=ConfigActionEnum.CONFIGACTION_SET, custom=custom_rule)
+    service.service_config.config_rules.add().CopyFrom(rule)
+    log.debug("optical-band rules {}".format(rules_ob))
+    if len(rules_ob) > 0:
+      for rulex in rules_ob:
+        rule_ob = ConfigRule(action=ConfigActionEnum.CONFIGACTION_SET, custom=rulex)
+        service.service_config.config_rules.add().CopyFrom(rule_ob)
+      
+    opt_reply.services.add().CopyFrom(service)   
+    
+    return opt_reply         
+
+def add_service_to_reply(reply : PathCompReply, service : Service)-> Service:
+    service_x = reply.services.add()
+    service_x.CopyFrom(service)
+    return service_x
+ 
+def add_connection_to_reply(reply : PathCompReply)-> Connection:
+    conn = reply.connections.add()
+    return conn
diff --git a/src/service/service/tools/replies.py b/src/service/service/tools/replies.py
new file mode 100644
index 0000000000000000000000000000000000000000..5fcb393e9d8a5eaaeccc11a8c1dc8e4485b8cbc9
--- /dev/null
+++ b/src/service/service/tools/replies.py
@@ -0,0 +1,321 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# 
+
+reply_bid_txt = """
+{
+  "flow_id": 1,
+  "src": "T1",
+  "dst": "T2",
+  "bitrate": 100,
+  "bidir": 1,
+  "flows": {
+    "T1": {
+      "f": {
+        "in": "0",
+        "out": "1"
+      },
+      "b": {
+        "in": "1",
+        "out": "0"
+      }
+    },
+    "R1": {
+      "f": {
+        "in": "12",
+        "out": "3"
+      },
+      "b": {
+        "in": "13",
+        "out": "2"
+      }
+    },
+    "R2": {
+      "f": {
+        "in": "14",
+        "out": "5"
+      },
+      "b": {
+        "in": "15",
+        "out": "4"
+      }
+    },
+    "T2": {
+      "f": {
+        "in": "6",
+        "out": "0"
+      },
+      "b": {
+        "in": "0",
+        "out": "6"
+      }
+    }
+  },
+  "band_type": "c_slots",
+  "slots": [
+    1,
+    2,
+    3,
+    4
+  ],
+  "fiber_forward": {
+    "T1-R1": "M1",
+    "R2-T2": "S1"
+  },
+  "fiber_backward": {
+    "R1-T1": "S1",
+    "T2-R2": "M1"
+  },
+  "op-mode": 1,
+  "n_slots": 4,
+  "links": [
+    "T1-R1",
+    "R2-T2"
+  ],
+  "path": [
+    "R1",
+    "R2"
+  ],
+  "band": 50000,
+  "freq": 192031250,
+  "is_active": true,
+  "parent_opt_band": 1,
+  "new_optical_band": 1
+}
+  """
+  
+optical_band_bid_txt = """
+{
+  "optical_band_id": 1,
+  "bidir": 1,
+  "src": "R1",
+  "dst": "R2",
+  "flows": {
+    "R1": {
+      "f": {
+        "in": "0", 
+        "out": "3" 
+      },
+      "b": {
+        "in": "13",
+        "out": "0"
+      }
+    },
+    "R2": {
+      "f": {
+        "in": "14",
+        "out": "0"
+      },
+      "b": {
+        "in": "0",
+        "out": "4"
+      }
+    }
+  },
+  "band_type": "c_slots",
+  "fiber_forward": {
+    "R1-R2": "d1-1"
+  },
+  "fiber_backward": {
+    "R2-R1": "d1-1"
+  },
+  "op-mode": 0,
+  "n_slots": 16,
+  "links": [
+    "R1-R2"
+  ],
+  "path": [
+    "R1",
+    "R2"
+  ],
+  "band": 200000,
+  "freq": 192106250,
+  "is_active": true,
+  "src_port": "101",
+  "dst_port": "201",
+  "rev_dst_port": "201",
+  "rev_src_port": "101",
+  "c_slots": [
+    5,
+    6,
+    7,
+    8,
+    9,
+    10,
+    11,
+    12,
+    13,
+    14,
+    15,
+    16
+  ],
+  "served_lightpaths": [
+    1
+  ]
+}
+  """
+
+reply_uni_txt = """
+{
+  "flow_id": 2,
+  "src": "T1",
+  "dst": "T2",
+  "bitrate": 100,
+  "bidir": 0,
+  "flows": {
+    "T1": {
+      "f": {
+        "in": "0",
+        "out": "1"
+      },
+      "b": {
+        "in": "1",
+        "out": "0"
+      }
+    },
+    "R1": {
+      "f": {
+        "in": "12",
+        "out": "3"
+      },
+      "b": {
+        "in": "13",
+        "out": "2"
+      }
+    },
+    "R2": {
+      "f": {
+        "in": "14",
+        "out": "5"
+      },
+      "b": {
+        "in": "15",
+        "out": "4"
+      }
+    },
+    "T2": {
+      "f": {
+        "in": "6",
+        "out": "0"
+      },
+      "b": {
+        "in": "0",
+        "out": "6"
+      }
+    }
+  },
+  "band_type": "c_slots",
+  "slots": [
+    1,
+    2,
+    3,
+    4
+  ],
+  "fiber_forward": {
+    "T1-R1": "M1",
+    "R2-T2": "S1"
+  },
+  "fiber_backward": {
+    "R1-T1": "S1",
+    "T2-R2": "M1"
+  },
+  "op-mode": 1,
+  "n_slots": 4,
+  "links": [
+    "T1-R1",
+    "R2-T2"
+  ],
+  "path": [
+    "R1",
+    "R2"
+  ],
+  "band": 50000,
+  "freq": 192031250,
+  "is_active": true,
+  "parent_opt_band": 2,
+  "new_optical_band": 1
+}
+  """
+  
+optical_band_uni_txt = """
+{
+  "optical_band_id": 2,
+  "bidir": 0,
+  "src": "R1",
+  "dst": "R2",
+  "flows": {
+    "R1": {
+      "f": {
+        "in": "0", 
+        "out": "3" 
+      },
+      "b": {
+        "in": "13",
+        "out": "0"
+      }
+    },
+    "R2": {
+      "f": {
+        "in": "14",
+        "out": "0"
+      },
+      "b": {
+        "in": "0",
+        "out": "4"
+      }
+    }
+  },
+  "band_type": "c_slots",
+  "fiber_forward": {
+    "R1-R2": "d1-1"
+  },
+  "fiber_backward": {
+    "R2-R1": "d1-1"
+  },
+  "op-mode": 0,
+  "n_slots": 16,
+  "links": [
+    "R1-R2"
+  ],
+  "path": [
+    "R1",
+    "R2"
+  ],
+  "band": 200000,
+  "freq": 192106250,
+  "is_active": true,
+  "src_port": "101",
+  "dst_port": "201",
+  "rev_dst_port": "201",
+  "rev_src_port": "101",
+  "c_slots": [
+    5,
+    6,
+    7,
+    8,
+    9,
+    10,
+    11,
+    12,
+    13,
+    14,
+    15,
+    16
+  ],
+  "served_lightpaths": [
+    2
+  ]
+}
+  """
+