def setup_msbclient(verification_token):

    logging.debug("Setup MSB Client")

    # Init msb client
    global myMsbClient
    myMsbClient = MsbClient(
        "SmartObject", SO_UUID, SO_NAME, SO_DESCRIPTION, verification_token
    )
    myMsbClient.enableDebug(True)
    myMsbClient.enableTrace(False)
    myMsbClient.enableDataFormatValidation(True)
    myMsbClient.disableEventCache(False)
    myMsbClient.setEventCacheSize(1000)
    myMsbClient.disableAutoReconnect(False)
    myMsbClient.setReconnectInterval(10000)
    myMsbClient.disableHostnameVerification(True)
    myMsbClient.enableThreadAsDaemon(True)

    # add a configuration parameter to the self description
    config_param_name_1 = "testParam1"
    config_param_value_1 = True
    config_param_datatype_1 = bool

    config_param_name_2 = "testParam2"
    config_param_value_2 = "StringValue"
    config_param_datatype_2 = str

    config_param_name_3 = "testParam3"
    config_param_value_3 = 1000
    config_param_datatype_3 = "int32"

    config_param_name_4 = "testParam3_2"
    config_param_value_4 = 2000
    config_param_datatype_4 = int

    config_param_name_5 = "testParam5"
    config_param_value_5 = 3.3
    config_param_datatype_5 = float

    config_param_name_6 = "testParam6"
    config_param_value_6 = 3.3
    config_param_datatype_6 = "float"

    config_param_name_7 = "testParam7"
    config_param_value_7 = datetime.datetime.now()
    config_param_datatype_7 = "date-time"

    myMsbClient.addConfigParameter(config_param_name_1, config_param_value_1, config_param_datatype_1)
    myMsbClient.addConfigParameter(config_param_name_2, config_param_value_2, config_param_datatype_2)
    myMsbClient.addConfigParameter(config_param_name_3, config_param_value_3, config_param_datatype_3)
    myMsbClient.addConfigParameter(config_param_name_4, config_param_value_4, config_param_datatype_4)
    myMsbClient.addConfigParameter(config_param_name_5, config_param_value_5, config_param_datatype_5)
    myMsbClient.addConfigParameter(config_param_name_6, config_param_value_6, config_param_datatype_6)
    myMsbClient.addConfigParameter(config_param_name_7, config_param_value_7, config_param_datatype_7)

    logging.debug("Self Description - added config params")
    # add events to the client: as single param
    myMsbClient.addEvent(
        "SIMPLE_EVENT1_STRING",
        "Simple event 1",
        "Simple event with string",
        DataType.STRING,
        "LOW",
        False,
    )
    myMsbClient.addEvent(
        "SIMPLE_EVENT2_INTEGER_ARRAY",
        "Simple event 2",
        "Simple event with integer array",
        DataType.INT32,
        0,
        True
    )
    myMsbClient.addEvent(
        "SIMPLE_EVENT3_JSONDATAFORMAT",
        "Simple event 3",
        "Simple event with JSON stringified dataformat",
        '{ "type": "number",  "format": "float" }',
        2,
        False
    )
    myMsbClient.addEvent(
        "SIMPLE_EVENT4_NOPAYLOAD",
        "Simple event 4",
        "Simple event with no payload",
        None,
        0,
        False
    )
    myMsbClient.addEvent(
        "DATE_EVENT",
        "Date Event",
        "Simple event with datetime",
        DataType.DATETIME,
        0,
        False
    )
    myMsbClient.addEvent(
        "arrayev",
        "Array Event",
        "Array Event for testing",
        DataType.STRING,
        "LOW",
        True
    )

    # add events to the client: as event object
    event1 = Event(
        "EVENT1",
        "Event 1",
        "Event with string",
        DataType.STRING,
        "LOW",
        False
    )
    myMsbClient.addEvent(event1)
    event1 = Event(
        "EVENT2",
        "Event 2",
        "Event with number",
        DataType.FLOAT,
        "LOW",
        False
    )
    myMsbClient.addEvent(event1)

    logging.debug("Self Description - added simple events")

    # define properties for complex data format to be used in an event
    complexObject_name_1 = "ComplexObject1"
    complexObject_property_name_1 = "megaprop"
    complexObject_isArray_1 = False
    complexObject_name_2 = "ComplexObject2"
    complexObject_property_name_2 = "superprop"
    complexObject_isArray_2 = True
    complexObject_name_3 = "ComplexObject3"
    complexObject_property_name_3 = "mediumprop"
    complexObject_isArray_3 = True
    complexObject_name_4 = "ComplexObject4"
    complexObject_property_name_4 = "prop"
    complexObject_datatype_4 = "int32"
    complexObject_isArray_4 = True
    # initialize the complex data format
    complexObject_1 = ComplexDataFormat(complexObject_name_1)
    complexObject_2 = ComplexDataFormat(complexObject_name_2)
    complexObject_3 = ComplexDataFormat(complexObject_name_3)
    complexObject_4 = ComplexDataFormat(complexObject_name_4)
    # add properties to the nested complex data formats
    complexObject_4.addProperty(
        complexObject_property_name_4,
        complexObject_datatype_4,
        complexObject_isArray_4
    )
    complexObject_3.addProperty(
        complexObject_property_name_3,
        complexObject_4,
        complexObject_isArray_3
    )
    complexObject_2.addProperty(
        complexObject_property_name_2,
        complexObject_3,
        complexObject_isArray_2
    )
    complexObject_1.addProperty(
        complexObject_property_name_1,
        complexObject_2,
        complexObject_isArray_1
    )
    # add the event with the complex data format
    myMsbClient.addEvent(
        "EVENT3_COMPLEX",
        "Event 3 Complex Data Format",
        "Event wit a 4-level complex data format",
        complexObject_1,
        0,
        True,
    )

    # the final data format can be provided as a valid JSON object
    myMsbClient.addEvent(
        "COMPLEX_JSON_EVENT",
        "JSON based event",
        "JSON based event description",
        {
            "Member" : {
                "type" : "object",
                "properties" : {
                    "name" : {
                        "type" : "string"
                    },
                    "status" : {
                        "enum" : [ "present", "absent" ],
                        "type" : "string"
                    }
                }
            },
            "Team" : {
                "type" : "object",
                "properties" : {
                    "staff" : {
                        "type" : "array",
                        "items" : {
                            "$ref" : "#/definitions/Member"
                        }
                    }
                }
            },
            "dataObject" : {
                "$ref" : "#/definitions/Team"
            }
        },
        0,
        False,
    )

    logging.debug("Self Description - added complex events")

    # define the function which will be passed to the function description
    def printMsg(msg):
        print(str(msg["dataObject"]))

    # add functions to the client: as single param
    myMsbClient.addFunction(
        "FUNCTION1",
        "Function 1",
        "Description function 1",
        "int32",
        printMsg,
        False,
        ["EVENT1", "EVENT2"],
    )

    # add functions to the client: as function object
    function2 = Function(
        "FUNCTION2",
        "Function 2",
        "Description function 2",
        str,
        printMsg,
        False,
        ["EVENT1", "EVENT2"],
    )
    myMsbClient.addFunction(function2)

    # the final data format can be provided as a valid JSON object
    myMsbClient.addFunction(
        "COMPLEX_JSON_FUNCTION",
        "Function JSON based",
        "Description function JSON based",
        {
            "Member" : {
                "type" : "object",
                "properties" : {
                    "name" : {
                        "type" : "string"
                    },
                    "status" : {
                        "enum" : [ "present", "absent" ],
                        "type" : "string"
                    }
                }
            },
            "Team" : {
                "type" : "object",
                "properties" : {
                    "staff" : {
                        "type" : "array",
                        "items" : {
                            "$ref" : "#/definitions/Member"
                        }
                    }
                }
            },
            "dataObject" : {
                "$ref" : "#/definitions/Team"
            }
        },
        printMsg,
        False,
        ["EVENT1", "EVENT2"],
    )

    # define the function which will be passed to the function description
    def arrayfun_implementation(msg):
        logging.debug("Array Function has been called, message: " + str(msg["a"]))
        global receivedArrayEvIndexCheck
        receivedArrayEvIndexCheck = True
        receivedArrayEvIndexCheck = str(msg["a"][0]) == "Hello"
        receivedArrayEvIndexCheck = str(msg["a"][1]) == "World"
        receivedArrayEvIndexCheck = str(msg["a"][2]) == "!"
        logging.debug(
            "Array Function has been called, correlationId: " + msg["correlationId"]
        )
        global receivedArrayEvWithCorrectCorrelationId
        receivedArrayEvWithCorrectCorrelationId = (
            str(msg["correlationId"]) == CORRELATIOON_ID_FOR_TEST
        )
        global receivedArrayEv
        receivedArrayEv = True

    # add the function to be tested in integration flow
    function_arrayfun = Function(
        "/arrayfun",
        "Array Function",
        "Array Function for testing",
        str,
        arrayfun_implementation,
        True,
        None,
    )
    myMsbClient.addFunction(function_arrayfun)

    logging.debug("Self Description - added functions")
    myMsbClient.setReconnectInterval(10000)

    # enable or disable the message buffer, 
    # which will buffer sent event messages when no active connection is available (default = enabled).
    myMsbClient.disableEventCache(False)

    # set event cache size (default = 1000 message events).
    myMsbClient.setEventCacheSize(1000)

    # disable SSL hostname check and certificate validation for self signed certificates (default = enabled).
    myMsbClient.disableHostnameVerification(True)  

    # add a configuration parameter to the self description.
    # configuration parameters are published to the MSB and can be changed from the MSB GUI in real time
    # (key, value, datatype)
    myMsbClient.addConfigParameter("testParam1", 17, DataType.INT32)
    myMsbClient.addConfigParameter("testParam2", "Hello World!", DataType.STRING)
    myMsbClient.addConfigParameter("testParam3", 3.3, DataType.FLOAT)
    myMsbClient.addConfigParameter("testParam4", True, DataType.BOOLEAN)

    # to retrieve a configuration parameter, you can retrieve it as follows:
    # myMsbClient.getConfigParameter('testParam1')
    # e.g.
    def printParameter():
        print(str(myMsbClient.getConfigParameter("testParam1")))

    # change a configuration parameter locally:
    # myMsbClient.changeConfigParameter('testParam1', 17)

    # create new event object
    # parameter 1 (str:‘EVENT1’): internal event name reference (inside program code)