def getDatasourceConfigForAgentAsset(agentAsset):
    simpleError = SimpleError()

    datasourceConfiguration = None
    if agentAsset.typeId != "core.mclib":
        # wenn es kein Lib Agent ist, schaut das Abrufen der vollen Datasource Konfig so aus
        returnValue = wrapApiCall(
            "/api/mindconnectdevicemanagement/v3/devices/" +
            agentAsset.assetId + "/dataConfig",
            "GET",
            assetTypeToDeriveApplicationScope=agentAsset.typeId)
        # Der mindconnctdevicemanagement Endpunkt liefert bei mclib Agenten keine Konfig zurück: "Device configuration does not exist for given assetId xy".
        # Für die MindConnect Lib-Elemente muss man den Agentmanagement-Endpunkt verwenden. Dieser ginge zwar auch für mcnano und mciot2040 aber man erhält dort nicht die volle Info.
        # Deshalb nimmt man für NANO und IoT2040 den mindconnectdevicemanagement-Endpunkt
    else:
        returnValue = wrapApiCall(
            "/api/agentmanagement/v3/agents/" + agentAsset.assetId +
            "/dataSourceConfiguration",
            "GET",
            assetTypeToDeriveApplicationScope=agentAsset.typeId)
    if not returnValue:
        print(
            "Something went wrong with getting datasource Config. Result of API call was empty..."
        )
        exit(-1)

    datasourceConfiguration = returnValue["result"]

    return (simpleError, datasourceConfiguration)
def getAgentsFromMindSphere():
    # Attention: The Agent Management API is not in scope of assetmanager-Application -> Update 2020 -> this seems to be not true anymore
    # This can be reworked with trying to identify agents via the asset's assetType (if the type is core.mcXXX: it is an agent)
    simpleError = SimpleError()

    if fetchFromFile:
        try:
            with open(agentsFilePath) as json_file:
                print(f"... loading Agent-Data from local file now")
                agentsFromMindSphere = json.load(json_file)

            return (simpleError, agentsFromMindSphere)

        except FileNotFoundError:
            print(f"... loading Agent-Data from MindSphere Cloud now")
            pass
        except:
            traceback.print_exc()

    agentsFromMindSphere = []
    totalAgents = 0
    currentPageNumber = 0
    result = wrapApiCall(
        "/api/agentmanagement/v3/agents?page=" + str(currentPageNumber) +
        "&size=100&sort=name,asc", "GET", "{}")["result"]

    if logging in ("INFO"):
        print("Getting page {} for Agents now".format(currentPageNumber + 1))
    if result and "content" in result:
        if result["content"]:
            agentsFromMindSphere.extend(result["content"])

        if result["totalPages"]:
            numberOfReturnPages = int(result["totalPages"])
        if result["totalElements"]:
            totalAgents = int(result["totalElements"])

        if numberOfReturnPages > 1:
            nextResult = result
            for x in range(2, numberOfReturnPages + 1):
                currentPageNumber += 1
                if logging in ("INFO", "VERBOSE"):
                    print("Getting page {} for Agents now".format(x))
                nextLink = "/api/agentmanagement/v3/agents?page=" + str(
                    currentPageNumber) + "&size=100&sort=name,asc"
                nextResult = wrapApiCall(nextLink, "GET", "{}")["result"]
                agentsFromMindSphere.extend(nextResult["content"])
                if nextResult["totalElements"]:
                    totalAgents = int(nextResult["totalElements"])

        if len(agentsFromMindSphere) != totalAgents:
            simpleError.addError(
                "Fetched elements ({}) differ from number of elements according to APIs response PAGE-TOTALELEMENTS ({})"
                .format(len(agentsFromMindSphere), totalAgents))

        if fetchFromFile:
            with open(agentsFilePath, 'w') as outfile:
                json.dump(agentsFromMindSphere, outfile)

    return (simpleError, agentsFromMindSphere)
def getOnboardingKey(agentAsset):

    bodyAsJson = {}

    if agentAsset.typeId == "core.mclib":

        returnValue = wrapApiCall(
            "/api/agentmanagement/v3/agents/" + agentAsset.assetId +
            "/boarding/configuration",
            "GET",
            bodyAsJson,
            assetTypeToDeriveApplicationScope=agentAsset.typeId)

    else:
        returnValue = wrapApiCall(
            "/api/mindconnectdevicemanagement/v3/devices/" +
            agentAsset.assetId + "/onboardingConfig?encrypted=false",
            "GET",
            bodyAsJson,
            assetTypeToDeriveApplicationScope=agentAsset.typeId)

    result = returnValue["result"]
    statusCode = returnValue["responseStatusCode"]
    responseText = returnValue["responseText"]

    returnDict = dict()
    returnDict["response"] = result
    returnDict["statusCode"] = statusCode
    returnDict["responseText"] = responseText

    return returnDict
def createDatapointMapping(dataPointMapping, agentAsset):
    print(
        f" °°°° Creating DatpointMapping for variable '{dataPointMapping.variableName}' between '{agentAsset.name}' and '{dataPointMapping.targetAsset.name}' now ... "
    )
    #The received datapoint mapping ID does probably not matter and does not be saved.
    if not dataPointMapping.agentId:
        dataPointMapping.agentId = dataPointMapping.agentAsset.assetId
    bodyAsJson = {
        "agentId": dataPointMapping.agentId,
        "dataPointId": dataPointMapping.dataPointId,
        "entityId": dataPointMapping.targetAsset.assetId,
        "propertySetName": dataPointMapping.aspectId,
        "propertyName": dataPointMapping.variableName
    }

    if logging == "VERBOSE":
        print("Trying to import Datapoint Mapping with following body")
        print(bodyAsJson)

    if agentAsset.typeId != "core.mclib":
        returnValue = wrapApiCall(
            "/api/mindconnect/v3/dataPointMappings",
            "POST",
            bodyAsJson,
            assetTypeToDeriveApplicationScope=agentAsset.typeId)

    else:
        bodyAsJson["keepMapping"] = True
        returnValue = wrapApiCall(
            "/api/mindconnect/v3/dataPointMappings",
            "POST",
            bodyAsJson,
            assetTypeToDeriveApplicationScope=agentAsset.typeId)

    if not returnValue:
        print(
            "Something went wrong with creating a datapoint mapping. Result of API call was empty..."
        )
        exit(-1)

    result = returnValue["result"]
    statusCode = returnValue["responseStatusCode"]
    responseText = returnValue["responseText"]

    if statusCode >= 200 and statusCode < 300:

        responseAsDict = json.loads(responseText)
        assignReceivedDatapointIds(agentAsset, responseAsDict)

    returnDict = dict()
    returnDict["response"] = result
    returnDict["statusCode"] = statusCode
    returnDict["responseText"] = responseText

    return returnDict
def uploadFile(file):
    # TODO: No idea if this is working ...doubt it
    print(" °°°° Uploading File '{}' now ... ".format(file.name))
    bodyAsJson = {}

    bodyAsJson["name"] = file.name
    bodyAsJson["type"] = file.typeOfFileInMindSphere
    bodyAsJson["parentId"] = file.directoryIdInMindSphere

    if logging == "VERBOSE":
        print("Trying to uploadFile with following body")
        print(bodyAsJson)

    fullFilePath = join(file.localDirectory, file.name)
    uploadFile = {'file': open(fullFilePath, 'rb')}

    payload = {"metadata": json.dumps(bodyAsJson)}

    returnValue = wrapApiCall("/api/dataexchange/v3/files",
                              "POST",
                              data=payload,
                              files=uploadFile,
                              additionalHeaders=None)

    result = returnValue["result"]
    statusCode = returnValue["responseStatusCode"]
    responseText = returnValue["responseText"]

    returnDict = dict()
    returnDict["response"] = result
    returnDict["statusCode"] = statusCode
    returnDict["responseText"] = responseText

    return returnDict
def getDeviceConfigurationForAgentAsset(agentAsset):
    # This queries something like /api/mindconnectdevicemanagement/v3/devices/<agentAssetID>
    # If Agent is Nano or Iot2040 it will return information about Boarding-Status, IP-Configuration, DHCP, Proxy, SerialNumber:
    # For MC Lib Elements there won't be a Device-Config
    # If you ask for it in case of a MC Lib Asset, you will get a reply "Insufficient scope for this resource" when using session cookies
    # When using app credential token for it, you will receive this 'Device configuration does not exist for given assetId'
    # Über /api/mindconnectdevicemanagement/v3/devices/<agentAssetID>/firmware/info könnte man auch noch die Firmware abrufen
    simpleError = SimpleError()
    deviceInformation = None

    if agentAsset.typeId != "core.mclib":
        result = wrapApiCall(
            "/api/mindconnectdevicemanagement/v3/devices/" +
            agentAsset.assetId,
            "GET",
            assetTypeToDeriveApplicationScope=agentAsset.typeId)["result"]

        if not result:
            print(
                "Something went wrong with getting datasource Config. Result of API call was empty..."
            )
            exit(-1)

        deviceInformation = result

    return (simpleError, deviceInformation)
def getAllDatapointMappingsForAgentAsset(agentAsset):
    simpleError = SimpleError()
    #TODO: IMPORTANT: This will currently return maximum 500 (or less, no idea how much are allowed) mapping entries, due to the laziness of the coder.
    #In case you have more mappings, this needs some work
    datapointMappingConfigurations = None
    result = wrapApiCall(
        '/api/mindconnect/v3/dataPointMappings?filter={"agentId":"' +
        agentAsset.assetId + '"}&page=0&size=500',
        "GET",
        assetTypeToDeriveApplicationScope=agentAsset.typeId)["result"]
    if not result:
        print(
            "Something went wrong with getting datasource mapping config. Result of API call was empty...maybe this is even okay, if no mappings exist"
        )
        exit(-1)
    datapointMappingConfigurations = result["content"]

    return (simpleError, datapointMappingConfigurations)
def deleteAsset(asset):

    relatedFileName = assetsFilePath
    print(" °°°° Deleting asset '{}' now ... ".format(asset.name))
    bodyAsJson = {}

    ifMatchHeader = {"if-match": str(asset.etag)}

    returnValue = wrapApiCall("/api/assetmanagement/v3/assets/" +
                              asset.assetId,
                              "DELETE",
                              bodyAsJson,
                              additionalHeaders=ifMatchHeader)

    result = returnValue["result"]
    statusCode = returnValue["responseStatusCode"]
    responseText = returnValue["responseText"]

    if statusCode >= 200 and statusCode < 300:

        if fetchFromFile:

            try:
                with open(relatedFileName) as json_file:
                    oldFileContent = json.load(json_file)

                currentFileContent = [
                    d for d in oldFileContent
                    if d.get('assetId') != asset.assetId
                ]

                with open(relatedFileName, 'w') as outfile:
                    json.dump(currentFileContent, outfile)

            except Exception:
                traceback.print_exc()

    returnDict = dict()
    returnDict["response"] = result
    returnDict["statusCode"] = statusCode
    returnDict["responseText"] = responseText

    return returnDict
def offBoardAgent(asset):

    print(" °°°° Offboarding agent '{}' now ... ".format(asset.name))
    bodyAsJson = {}

    returnValue = wrapApiCall("/api/agentmanagement/v3/agents/" +
                              asset.agentData.agentId + "/boarding/offboard",
                              "POST",
                              bodyAsJson,
                              assetTypeToDeriveApplicationScope=asset.typeId)
    result = returnValue["result"]
    statusCode = returnValue["responseStatusCode"]
    responseText = returnValue["responseText"]

    returnDict = dict()
    returnDict["response"] = result
    returnDict["statusCode"] = statusCode
    returnDict["responseText"] = responseText

    return returnDict
def applyMappingConfigurationToDevice(agentAsset):
    returnDict = dict()
    bodyAsJson = {}
    print(
        f" °°°° Applying changes to hardware device '{agentAsset.name}' now ..."
    )
    if agentAsset.typeId != "core.mclib":  #apply changes is only available for hardware devices
        returnValue = wrapApiCall(
            f"/api/mindconnectdevicemanagement/v3/devices/{agentAsset.assetId}/applyChanges",
            "POST",
            bodyAsJson,
            assetTypeToDeriveApplicationScope=agentAsset.typeId)

        if not returnValue:
            print(
                "Something went wrong with applying mapping Configuration. Result of API call was empty..."
            )
        exit(-1)

        result = returnValue["result"]
        statusCode = returnValue["responseStatusCode"]
        responseText = returnValue["responseText"]

        if statusCode >= 200 and statusCode < 300:

            responseAsDict = json.loads(responseText)
            assignReceivedDatapointIds(agentAsset, responseAsDict)

        returnDict["response"] = result
        returnDict["statusCode"] = statusCode
        returnDict["responseText"] = responseText

        return returnDict
    else:
        returnDict[
            "response"] = "There is no option to apply config for mc.lib elements"
        returnDict["statusCode"] = 123
        returnDict[
            "responseText"] = "There is no option to apply config for mc.lib elements"
def writeTimeSeriesData(assetId, aspectName, dataList):
    """ URL = /timeseries/{entityId}/{propertySetName}
        Body needs to be a list of dictionaries:
        [
    {
        "_time": "2019-02-10T23:01:00Z",
        "exampleproperty0": "examplepropertyValue",
        "exampleproperty0_qc": "exampleproperty0_qc_Value",
        "exampleproperty1": "exampleproperty1Value"
    }
    ]"""
    bodyAsJson = json.dumps(dataList)

    if logging in ("VERBOSE"):
        print("Trying to insert timeseries data with following body now ...")
        print(bodyAsJson)

    # Add some chunking since the TS API only supports 2000 datapoints
    chunkSize = 2000
    listsWithTsData = [
        dataList[i:i + chunkSize] for i in range(0, len(dataList), chunkSize)
    ]

    for listWithTsData in listsWithTsData:
        returnValue = wrapApiCall(f"/api/timeseries/{assetId}/{aspectName}",
                                  "PUT", listWithTsData)
        #Todo: Currently only the last result is being pased on.

    result = returnValue["result"]
    statusCode = returnValue["responseStatusCode"]
    responseText = returnValue["responseText"]

    returnDict = dict()
    returnDict["response"] = result
    returnDict["statusCode"] = statusCode
    returnDict["responseText"] = responseText

    return returnDict
def createNewAssetInMindSphere(asset):
    relatedFileName = assetsFilePath
    print(" °°°° Importing Asset '{}' now ... ".format(asset.name))
    bodyAsJson = {}
    tenantname = config.tenantname

    name = asset.name
    if asset.typeId not in (None, ""):
        assetType = asset.typeId
    else:
        assetType = config.defaultAssetType  #If nothing has been provided: Get Default (shouldnt happen at that point)

    if not assetType.startswith("core.") and not assetType.startswith(
            tenantname + "."):
        assetTypeWithPrefix = tenantname + "." + assetType  #Add TenantPrefix to AssetType

    else:  #prefix is already existing
        assetTypeWithPrefix = assetType

    if asset.assetDescription not in (None, ""):
        assetDescription = asset.assetDescription
    else:
        assetDescription = config.defaultAssetDescription  #If nothing has been provided: Get Default

    if asset.parentId not in (None, ""):
        parentId = asset.parentId
    else:
        parentId = config.defaultParentId  #If nothing has been provided: Get Default

    bodyAsJson["name"] = name
    bodyAsJson["typeId"] = assetTypeWithPrefix
    bodyAsJson["description"] = assetDescription
    bodyAsJson["parentId"] = parentId
    if logging == "VERBOSE":
        print("Trying to import Asset with following body")
        print(bodyAsJson)

    returnValue = wrapApiCall("/api/assetmanagement/v3/assets", "POST",
                              bodyAsJson)
    result = returnValue["result"]
    statusCode = returnValue["responseStatusCode"]
    responseText = returnValue["responseText"]

    if statusCode >= 200 and statusCode < 300:
        if fetchFromFile:

            responseAsDict = json.loads(responseText)

            asset.assetId = responseAsDict[
                "assetId"]  #TODO -> Auch bei anderen Create Prozessen noch die ID und weitere Parameter an die Klasse hängen

            try:
                with open(relatedFileName) as json_file:
                    currentFileContent = json.load(json_file)

                currentFileContent.append(responseAsDict)

                with open(relatedFileName, 'w') as outfile:
                    json.dump(currentFileContent, outfile)

            except Exception:
                traceback.print_exc()

    returnDict = dict()
    returnDict["response"] = result
    returnDict["statusCode"] = statusCode
    returnDict["responseText"] = responseText

    return returnDict
def createNewAgent(asset):

    if asset.typeId == "core.mclib":
        bodyAsJson = {
            "name": asset.assetId,
            "securityProfile": asset.agentData.securityProfile,
            "entityId": asset.assetId
        }

        if logging in ("VERBOSE"):
            print("Trying to initialize DeviceConfig with following body")
            print(bodyAsJson)

        returnValue = wrapApiCall(
            "/api/agentmanagement/v3/agents",
            "POST",
            bodyAsJson,
            assetTypeToDeriveApplicationScope=asset.typeId)

    else:
        networkList = []
        for network in asset.agentData.deviceConfiguration.networkInterfaces:
            currentNetworkDict = {}
            currentNetworkDict["name"] = network.name

            if network.DHCP:
                currentNetworkDict["DHCP"] = {"enabled": True}
                currentNetworkDict["static"] = {}
            else:
                currentNetworkDict["DHCP"] = {"enabled": False}
                currentNetworkDict["IPv4"] = network.IPv4
                currentNetworkDict["IPv6"] = network.IPv6
                currentNetworkDict["DNS"] = network.DNS
                currentNetworkDict["SubnetMask"] = network.subnetMask
                currentNetworkDict["Gateway"] = network.gateway
            networkList.append(currentNetworkDict)

        deviceDict = {
            "serialNumber": asset.agentData.deviceConfiguration.serialNumber,
            "deviceType":
            "NANO" if asset.typeId == "core.mcnano" else "IOT2040",
            "networkInterfaces": networkList
        }

        bodyAsJson = {
            "assetId": asset.assetId,
            "device": deviceDict,
            "agent": {
                "name": asset.assetId,
                "proxy": {}
            }
        }

        if logging in ("VERBOSE"):
            print("Trying to initialize DeviceConfig with following body")
            print(bodyAsJson)
        returnValue = wrapApiCall(
            "/api/mindconnectdevicemanagement/v3/devices",
            "POST",
            bodyAsJson,
            assetTypeToDeriveApplicationScope=asset.typeId
        )  #Todo: if this should be able to update existing agents device configs, this needs to be a put request

    result = returnValue["result"]
    statusCode = returnValue["responseStatusCode"]
    responseText = returnValue["responseText"]

    returnDict = dict()
    returnDict["response"] = result
    returnDict["statusCode"] = statusCode
    returnDict["responseText"] = responseText

    return returnDict
def _putDatasourceAndDatapointDefinition(agentAsset,
                                         dataSourceDefinition,
                                         latestETag=None):
    ifMatchHeader = {}
    if latestETag:
        ifMatchHeader = {"if-match": str(latestETag)}

    additionalHeaders = ifMatchHeader

    dataSourceDefinition.pop('id', None)
    dataSourceDefinition.pop('eTag', None)
    bodyAsJson = dataSourceDefinition

    if logging == "VERBOSE":
        print("Trying to import DataSource and Datapoints with following body")
        print(bodyAsJson)

    # for mc lib elements and etag needs to be set using a PUT method
    if agentAsset.typeId != "core.mclib":
        # if it is no mc lib agent, the full datasource config will be fetched like this:
        returnValue = wrapApiCall(
            "/api/mindconnectdevicemanagement/v3/devices/" +
            agentAsset.assetId + "/dataConfig",
            "PUT",
            bodyAsJson,
            assetTypeToDeriveApplicationScope=agentAsset.typeId,
            additionalHeaders=additionalHeaders)
        # mindconnctdevicemanagement endpoint does not provide config for mclib agents: "Device configuration does not exist for given assetId xy".
        # Therefore MindConnect Lib-Elements require the Agentmanagement-endpoint. This would also work for mcnano and mciot204, but with less information.
        # As a consequence for NANO and IoT2040 mindconnectdevicemanagement-endpoint will be used
    else:
        returnValue = wrapApiCall(
            "/api/agentmanagement/v3/agents/" + agentAsset.assetId +
            "/dataSourceConfiguration",
            "PUT",
            bodyAsJson,
            assetTypeToDeriveApplicationScope=agentAsset.typeId,
            additionalHeaders=additionalHeaders)
    #The received datapoint IDs need to be saved in the dataPointClass, so that the mappings can applied

    if not returnValue:
        print(
            "Something went wrong with creating the datasource configuration. Result of API call was empty..."
        )
        exit(-1)

    result = returnValue["result"]
    statusCode = returnValue["responseStatusCode"]
    responseText = returnValue["responseText"]

    if statusCode >= 200 and statusCode < 300:

        responseAsDict = json.loads(responseText)
        assignReceivedDatapointIds(agentAsset, responseAsDict)

    returnDict = dict()
    returnDict["response"] = result
    returnDict["statusCode"] = statusCode
    returnDict["responseText"] = responseText

    return returnDict
def getDataModelObjectsFromMindSphere(mindSphereObjectType):
    currentObject = genericMindSphereObjectMapper[mindSphereObjectType]
    currentFilePath = currentObject["filepath"]
    currentApiPath = currentObject["url"]
    currentDisplayName = currentObject["displayName"]

    if fetchFromFile:
        try:
            with open(currentFilePath) as json_file:
                objectsFromMindSphere = json.load(json_file)
                print(
                    f"... loading {currentDisplayName}-Data from local file now"
                )
            return objectsFromMindSphere

        except FileNotFoundError:
            print(
                f"... loading {currentDisplayName}-Data from MindSphere Cloud now"
            )
        except:
            traceback.print_exc()

    objectsFromMindSphere = []
    totalElements = 0
    if logging in ("INFO"):
        print("Getting page 1 for {}s now".format(currentDisplayName))

    response = wrapApiCall(currentApiPath, "GET", "{}")

    if int(response["responseStatusCode"]) > 300:
        print(
            "Something went wrong with getting {}s from Mindsphere. Exiting now..."
            .format(currentDisplayName))
        print(response["responseText"])
        exit(-1)  #Todo: Error Handling einbauen?!

    result = response["result"]

    if result["_embedded"][mindSphereObjectType]:
        objectsFromMindSphere.extend(result["_embedded"][mindSphereObjectType])

    if result["page"]["totalPages"]:
        numberOfReturnPages = int(result["page"]["totalPages"])
    if result["page"]["totalElements"]:
        totalElements = int(result["page"]["totalElements"])

    if numberOfReturnPages > 1:
        nextResult = result
        for x in range(2, numberOfReturnPages + 1):
            if logging in ("INFO", "VERBOSE"):
                print("Getting page {} for {}s now".format(
                    x, currentDisplayName))
            if nextResult["_links"]["next"]["href"]:
                nextLink = nextResult["_links"]["next"]["href"]
                nextResult = wrapApiCall(nextLink, "GET", "{}")["result"]
                objectsFromMindSphere.extend(
                    nextResult["_embedded"][mindSphereObjectType])
                if nextResult["page"]["totalElements"]:
                    totalElements = int(nextResult["page"]["totalElements"])

    if len(objectsFromMindSphere) != totalElements:
        print(
            "Fetched elements ({}) differ from number of elements according to APIs response PAGE-TOTALELEMENTS ({})"
            .format(len(objectsFromMindSphere), totalElements))
        print("This bodes ill and therefore ...exiting now")
        exit(-1)

    if fetchFromFile:
        with open(currentFilePath, 'w') as outfile:
            json.dump(objectsFromMindSphere, outfile)

    return objectsFromMindSphere
def createNewAspectInMindSphere(aspect):
    relatedFileName = aspectsFilePath
    print(" °°°° Importing Aspect '{}' now ... ".format(aspect.name))
    bodyAsJson = {}

    if aspect.description not in (None, ""):
        aspectDescription = aspect.description
    else:
        aspectDescription = config.defaultAspectDescription  #If nothing has been provided: Get Default

    variablesForImport = []
    for variable in aspect.getVariables():
        variableDict = {
            "name": variable.name,
            "dataType": variable.dataType,
            "unit": variable.unit
        }

        if variable.dataType.lower() == "string":
            variableDict["length"] = config.maxLengthForStringVariableCreation

        variablesForImport.append(variableDict)

    bodyAsJson["name"] = aspect.name
    bodyAsJson["description"] = aspectDescription
    bodyAsJson["variables"] = variablesForImport
    bodyAsJson["scope"] = aspect.scope
    bodyAsJson["category"] = aspect.category

    if logging == "VERBOSE":
        print("Trying to import aspect with following body")
        print(bodyAsJson)

    returnValue = wrapApiCall(
        "/api/assetmanagement/v3/aspecttypes/" + aspect.id, "PUT", bodyAsJson)

    result = returnValue["result"]
    statusCode = returnValue["responseStatusCode"]
    responseText = returnValue["responseText"]

    if statusCode >= 200 and statusCode < 300:
        if fetchFromFile:

            responseAsDict = json.loads(responseText)

            try:
                with open(relatedFileName) as json_file:
                    currentFileContent = json.load(json_file)

                currentFileContent.append(responseAsDict)

                with open(relatedFileName, 'w') as outfile:
                    json.dump(currentFileContent, outfile)

            except Exception:
                traceback.print_exc()

    returnDict = dict()
    returnDict["response"] = result
    returnDict["statusCode"] = statusCode
    returnDict["responseText"] = responseText

    return returnDict
def createNewAssetTypeInMindSphere(assetType):

    relatedFileName = assetTypesFilePath

    print(" °°°° Importing AssetType '{}' now ... ".format(assetType.name))
    bodyAsJson = {}

    #handling of core asset-types should not be needed, since it should never happen, that the importer tries to import a core.assetType ...should... ;)
    if assetType.id.startswith("core"):
        print(
            "It should never happen, that the importer tries to import a core.asset ...something is wrong here in the program's logic, please do complain somewhere...exiting now..."
        )
        exit(-1)

    if assetType.description in (None, ""):
        assetType.description = config.defaultAssetDescription  #If nothing has been provided: Get Default

    aspectsForImport = []

    for aspect in assetType.getAspects():

        aspectDict = {
            "name": aspect.aspectNameWithinAssetTypeContext,
            "aspectTypeId": aspect.id
        }
        aspectsForImport.append(aspectDict)

    if assetType.ancestorOfTypeId in (None, ""):
        assetType.ancestorOfTypeId = config.defaultParentAssetTypeId

    bodyAsJson["name"] = assetType.name
    bodyAsJson["id"] = assetType.id
    bodyAsJson["parentTypeId"] = assetType.ancestorOfTypeId
    bodyAsJson["description"] = assetType.description
    bodyAsJson["aspects"] = aspectsForImport
    bodyAsJson["instantiable"] = "true"
    bodyAsJson["scope"] = "private"

    if logging == "VERBOSE":
        print("Trying to import AssetType with following body")

    returnValue = wrapApiCall(
        "/api/assetmanagement/v3/assettypes/" + assetType.id, "PUT",
        bodyAsJson)

    result = returnValue["result"]
    statusCode = returnValue["responseStatusCode"]
    responseText = returnValue["responseText"]

    if statusCode >= 200 and statusCode < 300:
        if fetchFromFile:

            responseAsDict = json.loads(responseText)

            try:
                with open(relatedFileName) as json_file:
                    currentFileContent = json.load(json_file)

                currentFileContent.append(responseAsDict)

                with open(relatedFileName, 'w') as outfile:
                    json.dump(currentFileContent, outfile)

            except Exception:
                traceback.print_exc()

    returnDict = dict()
    returnDict["response"] = result
    returnDict["statusCode"] = statusCode
    returnDict["responseText"] = responseText

    return returnDict