예제 #1
0
def device_attribute_data(deviceID):
    """
    Allows for removal of devices from the database given a specified deviceID

    POST: was supposed to allow for editing and addition of attributes to a device. However no relevant database
    functions have been implemented

    DELETE: allows for removal of a device from the system
    :param
        deviceID: a string containing deviceID

    :return:
        'device does not exist. no device to remove from system.' will be returned if there is no database entry
        for requested deviceID
        'device removed successfully' will be returned if device is removed successfully.
    """
    dbAccess = DatabaseAccess()
    if request.method == "POST":
        return ''

    elif request.method == "DELETE":
        if not dbAccess.device_exists(deviceID):
            return 'device does not exist. no device to remove from system.'
        dbAccess.device_remove(deviceID)
        return 'device removed successfully'
예제 #2
0
def group_data():
    """
    Retrieves group data, and allows for addition of new groups.

    GET: should retrieve all groupID's a user is in and their names but due to constraints with timing this was not possible.
    POST: adds a new group ot the database. By calling the group add function of the DatabaseAccess() class.

    Form:
        groupName: a string containing the name of the group to be added.

    :return:
        'group added successfully.' message if a groupName was present in the form data.

        'no group name, no group created.' message if no groupName present in form data.
        This allows the code to fail silently rather than returning an error message to disrupt the server/front-end.

    """
    dbAccess = DatabaseAccess()
    if request.method == "GET":
        # this cannot be implemented with current DB code
        # TODO: add a default val for limit that ensures there can be a missing limit param

        return ''

    elif request.method == "POST":
        # TODO: add a format check for groupIDs, otherwise reject
        groupName = request.form.get('groupName')
        if request.form.get("groupName"):
            dbAccess.group_add(groupName)
            return 'group added successfully, '
        else:
            return 'no group name, no group created.'
예제 #3
0
def user_attribute(userID):
    if request.method == "GET":
        dbAccess = DatabaseAccess()
        # TODO: ONLY RETURN SPECIFIED ATTRIBUTE IF GIVEN (else all attributes?)
        attribute = request.args.get("attribute")
        return dbAccess.user_get_info()

    elif request.method == 'DELETE':
        # no way of doing this with current database functions
        # TODO: Seemingly no way of achieving this with the current databaseAccess.py
        return ''
예제 #4
0
def nested_groups(groupID):
    """
    Allows for a retrieval and addition of parents of a group.
    Ideally there would be a check to verify that the groups exist.

    GET: returns all parent groupIDs of a specified group.
    POST: adds a parent group to a specified group.

    :param
        groupID: an integer value containing an ID of a group

    :form
        parentID: an integer value containing an ID of a group to be added as a parent.

    :return:
        retrievedData will be returned if the GET function is called with a valid groupID.
        'group added successfully' will be returned if the POST function is called with a valid groupID and parentID.
    """
    groupID = int(groupID)
    if request.method == "GET":
        dbAccess = DatabaseAccess()
        retrievedData = dbAccess.group_get_parent(groupID)
        retrievedData = {
            i: retrievedData[i]
            for i in range(0, len(retrievedData))
        }
        print("\n", retrievedData, "\n")
        return retrievedData

    if request.method == "POST":
        parentGroup = int(request.form.get("parentID"))
        dbAccess = DatabaseAccess()
        dbAccess.group_set_parent(groupID, parentGroup)
        return 'group added successfully'
예제 #5
0
def get_device_telemetry(deviceID):
    dbAccess = DatabaseAccess()
    period = int(request.form.get("dataPeriod"))

    func = request.form.get("function")
    key = request.form.get("key")
    count = int(request.form.get("count"))

    if (not period) or (not func) or (not key) or (not count):
        return 'an item of data is missing'

    if not dbAccess.device_exists(deviceID):
        return 'device does not exist. no data to return.'

    flooredPeriod = period // 5
    returnedFromDB = dbAccess.telemetry_get(deviceID, flooredPeriod)
    getData = analytics.get(func, returnedFromDB, key, count)
    print(getData)
    return str(getData)
예제 #6
0
def aggregate_device_telemetry(deviceID):
    """
    returns an aggregate of a specified number of datapoints from a specified deviceID

    Form:
        dataPeriod: an integer containing the period (in seconds) that the aggregation is to carry out on

    :param
        deviceID: a string containing the ID of a device

    :return:
        'no dataPeriod present, no functions will be carried out.' will be returned if dataPeriod is missing from the form.
        'device does not exist. no data to return.' will be returned if the device does not exist in the DB.
        aggregatedDict: a dictionary of aggregated data.
    """

    dbAccess = DatabaseAccess()

    if not request.form.get('dataPeriod'):
        return 'no dataPeriod present, no functions will be carried out.'

    period = int(request.form.get("dataPeriod"))
    # floored division allows us to work out how many data points to retrieve
    flooredPeriod = period // 5

    if not dbAccess.device_exists(deviceID):
        return 'device does not exist. no data to return.'

    returnedFromDB = dbAccess.telemetry_get(deviceID, flooredPeriod)
    # Data is descending from db, not ascending. needs fixing.
    #print(returnedFromDB,"\n\n")
    aggregatedData = analytics.aggregate(returnedFromDB)
    for dict in aggregatedData:
        dict["_id"] = deviceID
    #print(aggregatedData)
    # cannot be returned in a list
    aggregatedDict = {
        i: aggregatedData[i]
        for i in range(0, len(aggregatedData))
    }
    print(aggregatedDict)
    # this data is slightly incorrect
    return aggregatedDict
예제 #7
0
def latest_device_telemetry(deviceID):
    """
    Retrieves latest telemetry data for specified device.

    GET: will query the PyMongo container of the relevant deviceID and return the latest datapoints.

    :param
        deviceID: a string containing deviceID.

    :return
        'device does not exist. no data to return.' is displayed if the device with the requested ID does not exist.
        returnedFromDB is a dict containing the latest datapoint.
    """
    dbAccess = DatabaseAccess()
    if not dbAccess.device_exists(deviceID):
        return 'device does not exist. no data to return.'
    returnedFromDB = dbAccess.telemetry_get_latest(deviceID)
    returnedFromDB['_id'] = deviceID
    print("\n", returnedFromDB, "\n")
    return returnedFromDB
예제 #8
0
def device_telemetry(deviceID):
    """
    Retrieves telemetry data up to a specified limit.

    GET: will query the PyMongo container of the relevant deviceID and return the specified number of datapoints.

    Form:
        limit: an integer value specifying how many datapoints to return.

    :param
        deviceID: a string containing deviceID.

    :return
        'no limit present, no functions will be carried out.' is displayed if limit is missing from form data.
        'device does not exist. no data to return.' is displayed if the device with the requested ID does not exist.
        telemetryDict is a dictionary of dictionaries containing requested data.
    """
    if not request.form.get('limit'):
        return 'no limit present, no functions will be carried out.'

    limit = int(request.form.get("limit"))
    dbAccess = DatabaseAccess()
    if not dbAccess.device_exists(deviceID):
        return 'device does not exist. no data to return.'

    returnedFromDB = dbAccess.telemetry_get(deviceID, limit)

    for telemetryReadings in returnedFromDB:
        telemetryReadings.update((key, deviceID)
                                 for key, value in telemetryReadings.items()
                                 if key == "_id")

    telemetryDict = {
        i: returnedFromDB[i]
        for i in range(0, len(returnedFromDB))
    }

    print(telemetryDict)
    return telemetryDict
예제 #9
0
def edit_user():
    if request.method == "POST":
        userID = request.form.get("userID")
        username = request.form.get("username")
        credentials = request.form.get("credentials")

        dbAccess = DatabaseAccess()
        dbAccess.user_add(userID, username, credentials)
        return 'user added'

    if request.method == "DELETE":
        userID = request.form.get("userID")
        dbAccess = DatabaseAccess()
        dbAccess.user_remove(userID)
        return 'user removed successfully'
예제 #10
0
def groups_devices(groupID):
    """
    Returns all deviceID's stored in a specified group.

    GET: returns all deviceIDs within a specified group. DOES NOT return device data as the supporting database function does not exist.

    :param
        groupID: an integer containing the ID of a requested group

    :return:
        'no groupID present, no function will be carried out' will be returned if the groupID is missing
        retrievedData will be returned if the group_get_devices function worked. This data is a dict of DeviceID's
    """
    groupID = int(groupID)
    if request.method == "GET":
        dbAccess = DatabaseAccess()
        retrievedData = dbAccess.group_get_devices(groupID)
        print("\n", retrievedData, "\n")
        retrievedData = {
            i: retrievedData[i]
            for i in range(0, len(retrievedData))
        }
        return retrievedData
예제 #11
0
def argget_device_telemetry(deviceID):
    dbAccess = DatabaseAccess()
    period = int(request.form.get("dataPeriod"))

    func = request.form.get("function")
    key = request.form.get("key")
    count = int(request.form.get("count"))

    if (not period) or (not func) or (not key) or (not count):
        return 'an item of data is missing'

    if not dbAccess.device_exists(deviceID):
        return 'device does not exist. no data to return.'

    flooredPeriod = period // 5
    returnedFromDB = dbAccess.telemetry_get(deviceID, flooredPeriod)
    arggetData = analytics.argget(func, returnedFromDB, key, count)
    for dict in arggetData:
        dict["_id"] = deviceID

    arggetDict = {i: arggetData[i] for i in range(0, len(arggetData))}
    print(arggetDict)
    return arggetDict
예제 #12
0
def device_data():
    """
    Retrieves device data, and allows for addition of new devices.

    GET: should retrieve all deviceID's from groups a user is in and their names but due to constraints with timing this was not possible.
    POST: adds a new device to the database. By calling the device add function of the DatabaseAccess() class.

    Form:
        deviceID: a string containing the name of the device to be added.
        groupID: an integer containing the ID of the group the device is to be bound to.
        id: the IP address of the device on the network.
        token: the authToken given to the device to verify it. <- JSON auth wasn't implemented.

    :return:
        'an item of data is missing' message if an item of data is missing from the form.
        'device already present. refused addition.' message if a device of the specified ID already exists.
        This allows the code to fail silently rather than returning an error message to disrupt the server/front-end.
        'device added successfully.' message if all data is present and correct in the form data.
    """
    dbAccess = DatabaseAccess()
    if request.method == "GET":
        # TODO; find out again if return limit possible
        limit = request.args.get("limit")

    elif request.method == "POST":
        deviceID = request.form.get("deviceID")
        groupID = int(request.form.get("groupID"))
        ip = request.form.get("ip")
        token = request.form.get("token")
        if (not deviceID) or (not groupID) or (not ip) or (not token):
            return 'an item of data is missing'
        if dbAccess.device_exists(deviceID):
            return 'device already present. refused addition.'
        else:
            dbAccess.device_add(deviceID, groupID, ip, token)
            return 'device added successfully.'
예제 #13
0
def groups_users(groupID):
    """
    Allows for retrieval and addition of users in a specified group.

    GET: returns all users of a specified group.
    POST: adds a user of a specified userID to a group of a specifiedID

    Form:
        userID: an integer value corresponding to a user account

    :param
        groupID: an integer value corresponding to a group

    :return:
        'no groupID present, no functions will be carried out.' will be returned if no groupID is entered.
        'no userID present, no function will be carried out.' will be returned if no userID is contained in the form data.
         retrievedData will be returned if the GET function is called with a groupID present.
        This is a dict containing users of the specified group
        'permission added' will be returned if the POST function is called with acceptable data.
    """
    groupID = int(groupID)
    if request.method == "GET":
        dbAccess = DatabaseAccess()
        retrievedData = dbAccess.group_get_users(groupID)
        print(retrievedData)
        retrievedData = {
            i: retrievedData[i]
            for i in range(0, len(retrievedData))
        }
        return retrievedData

    elif request.method == "POST":
        if not request.form.get('userID'):
            return 'no userID present, no function will be carried out.'
        userID = int(request.form.get("userID"))
        dbAccess = DatabaseAccess()
        dbAccess.permission_add(userID, groupID)
        return 'permission added'
예제 #14
0
def post_device_telemetry(device):
    """API Endpoint to receive, validate and forward POST data received from the hardware.

    The created /devices/<device>/telemetry with <devices> being the 16 Digit device ID
    will be used by the hardware to POST json data.
    The data format that is expected is:
    {
        "ts": 1587479991,
        "data": [
            {
                "name": "temperature",
                "value": 19.3
            }
        ]
    }
    Once received, it would would be validated by checking if a timestamp is included
    if not then assign the server one.
    Data list would also be validated and check if each telemetry reading includes a name
    and a value, also it makes sure that neither of those values are empty, if they are missing
    or are empty then the specific telemetry reading is not included in the final dictionary.
    The final dictionary formatted as follows:
    {
        "data":
        {
            "temperature": 19.3
        },
        "ts": 1587479991
    }
    Print statements are implemented in different parts to output the API's process to the console.

    Args:
        device: The 16 digit device ID received from the hardware when it accesses the endpoint.

    Returns:
        HTTP Status code
        200 if the POST request happened successfully.
        401 if the device_id doesn't exist in the database.
    """

    #Accessing database
    dbAccess = DatabaseAccess()

    #If device not on list return 401
    if not dbAccess.device_exists(device):
        return '401'

    #Receiving request
    tele_data = request.get_json()
    print("Request received.")

    #If no timestamp is present or is empty in the POST request assign epoch server time
    if not "ts" in tele_data or not tele_data["ts"]:

        tele_timestamp = int(datetime.utcnow().timestamp())
        print("No timestamp received, assigning server: " +
              str(tele_timestamp))

    else:
        tele_timestamp = tele_data["ts"]

    #Validating incoming data
    #If no name or reading detected or are empty drop the current reading and move to the next
    #Else store in data_list and data_dict as dictionary
    data_list = []
    data_dict = {}
    unvalid_data_no = 0
    data_length = len(tele_data["data"])

    for i in range(data_length):

        if not "name" in tele_data["data"][i] or not "value" in tele_data[
                "data"][i]:

            if "name" in tele_data["data"][
                    i] or not "value" in tele_data["data"][i]:
                print(
                    str(tele_data["data"][i]["name"]) +
                    " contains no value and will not be included.")

            elif "value" in tele_data["data"][i]:
                print(
                    "Value with no name attached detected and will not be included."
                )

            unvalid_data_no = unvalid_data_no + 1
            continue

        else:

            tele_name = tele_data["data"][i]["name"]
            tele_value = tele_data["data"][i]["value"]

            if not tele_value or not tele_name:

                if not tele_value and tele_name:
                    print(
                        str(tele_name) +
                        " contains empty value and will not be included.")

                elif tele_value and not tele_name:
                    print(
                        "Value with empty name attached detected and will not be included."
                    )

                unvalid_data_no = unvalid_data_no + 1
                continue

            else:
                data_list.append(tele_data["data"][i])
                data_dict[tele_data["data"][i]
                          ["name"]] = tele_data["data"][i]["value"]

    #Formats the data for the database and anomaly detection
    tele_valid_data = {"ts": tele_timestamp, "data": data_dict}

    #Echoes validated data received
    valid_data_length = data_length - unvalid_data_no
    print("Data received from Device: " + str(device))
    print("Time: " + str(tele_timestamp))
    print("Containing Data:")

    for i in range(valid_data_length):
        print("Name: " + str(data_list[i]["name"]) + " with value: " +
              str(data_list[i]["value"]))

    #Database
    print("Sending to database.")
    dbAccess.telemetry_add(device, tele_valid_data)

    return '200'
예제 #15
0
def groups():
    """
    Handles the retrieval, group name changes and deletion of groups.

    GET: returns all relevant data about the group specified in the groupID form data.
    POST: allows for the user to change the name of the group specified in the groupID form data.
    DELETE: allows for the deletion of the group specified in the groupID form data.

    Ideally a check for if group exists would be present to give another fail safe to the functions.

    Form:
        groupID: an integer containing the ID of a requested group

    :return:
        'no groupID present, no functions will be carried out.' will be returned if a groupID is missing.
        'data to be returned' will be returned if the GET function is called an a groupID is present.
        'group name changed' will be returned if the POST function is called an a groupName/groupID is provided.
        'no group name given. no changes made.' will be returned if the POST function is called, a groupID is provided and a groupName is missing.
        'group removed successfully.' will be returned if DELETE function is called with a groupID provided.
    """
    groupID = int(request.form.get('groupID'))
    if not request.form.get('groupID'):
        return 'no groupID present, no functions will be carried out.'
    if request.method == "GET":
        dbAccess = DatabaseAccess()
        groupName = dbAccess.group_get_name(groupID)
        groupUser = dbAccess.group_get_users(groupID)
        groupParent = dbAccess.group_get_parent(groupID)
        # No function actually exists to set children. This function is useless.
        # groupChildren= dbAccess.group_get_children(groupID)
        groupDevices = dbAccess.group_get_devices(groupID)
        groupAttributes = [groupName, groupUser, groupParent, groupDevices]
        print(groupAttributes)
        return 'data to be returned'

    elif request.method == "POST":
        if request.form.get("groupName"):
            dbAccess = DatabaseAccess()
            dbAccess.group_set_name(groupID, request.form.get("groupName"))
            return 'group name changed'
        else:
            return 'no group name given. no changes made.'

    elif request.method == "DELETE":
        dbAccess = DatabaseAccess()
        dbAccess.group_remove(groupID)
        return 'group removed successfully.'