示例#1
0
async def asset_counts(request):
    """ Browse all the assets for which we have recorded readings and
    return a readings count.

    Returns:
           json result on basis of SELECT asset_code, count(*) FROM readings GROUP BY asset_code;

    :Example:
            curl -sX GET http://localhost:8081/fledge/asset
    """
    payload = PayloadBuilder().AGGREGATE(["count", "*"]).ALIAS("aggregate", ("*", "count", "count")) \
        .GROUP_BY("asset_code").payload()

    results = {}
    try:
        _readings = connect.get_readings_async()
        results = await _readings.query(payload)
        response = results['rows']
        asset_json = [{
            "count": r['count'],
            "assetCode": r['asset_code']
        } for r in response]
    except KeyError:
        raise web.HTTPBadRequest(reason=results['message'])
    else:
        return web.json_response(asset_json)
示例#2
0
async def asset_datapoints_with_bucket_size(
        request: web.Request) -> web.Response:
    """ Retrieve datapoints for an asset.

        If bucket_size is not given then the bucket size is 1
        If start is not given then the start point is now - 60 seconds.
        If length is not given then length is 60 seconds. And length is calculated with length / bucket_size
        For multiple assets use comma separated values in request and this will allow data from one or more asset to be returned.

       :Example:
               curl -sX GET http://localhost:8081/fledge/asset/{asset_code}/bucket/{bucket_size}
               curl -sX GET http://localhost:8081/fledge/asset/{asset_code_1},{asset_code_2}/bucket/{bucket_size}
       """
    try:
        asset_code = request.match_info.get('asset_code', '')
        bucket_size = request.match_info.get('bucket_size', 1)
        length = 60
        ts = datetime.datetime.now().timestamp()
        start = ts - 60
        asset_code_list = asset_code.split(',')
        _readings = connect.get_readings_async()
        for code in asset_code_list:
            verify_asset_payload = PayloadBuilder().WHERE(["asset_code", "in", [code]]).LIMIT(1).\
                ORDER_BY(["user_ts", "desc"]).payload()
            res = await _readings.query(verify_asset_payload)
            if not res['rows']:
                raise KeyError("{} asset code not found".format(code))
        if 'start' in request.query and request.query['start'] != '':
            start = float(request.query['start'])
            if start < 0:
                raise ValueError('start must be a positive integer')

        _aggregate = PayloadBuilder().AGGREGATE(["all"]).chain_payload()
        _and_where = PayloadBuilder(_aggregate).WHERE(
            ["asset_code", "in",
             asset_code_list]).AND_WHERE(["user_ts", ">=",
                                          str(start)]).chain_payload()
        _bucket = PayloadBuilder(_and_where).TIMEBUCKET(
            'user_ts', bucket_size, 'YYYY-MM-DD HH24:MI:SS',
            'timestamp').chain_payload()
        if 'length' in request.query and request.query['length'] != '':
            length = int(request.query['length'])
            if length < 0:
                raise ValueError('length must be a positive integer')
        payload = PayloadBuilder(_bucket).LIMIT(int(
            length / int(bucket_size))).payload()
        # Sort & timebucket modifiers can not be used in same payload
        # payload = PayloadBuilder(limit).ORDER_BY(["user_ts", "desc"]).payload()
        results = await _readings.query(payload)
        response = results['rows']
    except (KeyError, IndexError) as e:
        raise web.HTTPNotFound(reason=e)
    except (TypeError, ValueError) as e:
        raise web.HTTPBadRequest(reason=e)
    except Exception as e:
        raise web.HTTPInternalServerError(reason=str(e))
    else:
        return web.json_response(response)
示例#3
0
async def asset_summary(request):
    """ Browse all the assets for which we have recorded readings and
    return a summary for a particular sensor. The values that are
    returned are the min, max and average values of the sensor.

    The readings summarised can also be time limited by use of the query
    parameter seconds=sss. This defines a number of seconds that the reading
    must have been processed in. Older readings than this will not be summarised.

    The readings summarised can also be time limited by use of the query
    parameter minutes=mmm. This defines a number of minutes that the reading
    must have been processed in. Older readings than this will not be summarised.

    The readings summarised can also be time limited by use of the query
    parameter hours=hh. This defines a number of hours that the reading
    must have been processed in. Older readings than this will not be summarised.

    Only one of hour, minutes or seconds should be supplied

    Returns:
           json result on basis of SELECT MIN(reading->>'reading'), MAX(reading->>'reading'), AVG((reading->>'reading')::float) FROM readings WHERE asset_code = 'asset_code';

    :Example:
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity/temperature/summary
    """
    asset_code = request.match_info.get('asset_code', '')
    reading = request.match_info.get('reading', '')
    try:
        payload = PayloadBuilder().SELECT("reading").WHERE(
            ["asset_code", "=",
             asset_code]).LIMIT(1).ORDER_BY(["user_ts", "desc"]).payload()
        _readings = connect.get_readings_async()
        results = await _readings.query(payload)
        if not results['rows']:
            raise web.HTTPNotFound(
                reason="{} asset_code not found".format(asset_code))

        # TODO: FOGL-1768 when support available from storage layer then avoid multiple calls
        reading_keys = list(results['rows'][-1]['reading'].keys())
        if reading not in reading_keys:
            raise web.HTTPNotFound(
                reason="{} reading key is not found".format(reading))

        _aggregate = PayloadBuilder().AGGREGATE(["min", ["reading", reading]], ["max", ["reading", reading]],
                                                ["avg", ["reading", reading]]) \
            .ALIAS('aggregate', ('reading', 'min', 'min'), ('reading', 'max', 'max'),
                   ('reading', 'avg', 'average')).chain_payload()
        _where = PayloadBuilder(_aggregate).WHERE(
            ["asset_code", "=", asset_code]).chain_payload()
        _and_where = where_clause(request, _where)
        payload = PayloadBuilder(_and_where).payload()
        results = await _readings.query(payload)
        # for aggregates, so there can only ever be one row
        response = results['rows'][0]
    except KeyError:
        raise web.HTTPBadRequest(reason=results['message'])
    else:
        return web.json_response({reading: response})
示例#4
0
async def asset_all_readings_summary(request):
    """ Browse all the assets for which we have recorded readings and
    return a summary for all sensors values for an asset code. The values that are
    returned are the min, max and average values of the sensor.

    Only one of hour, minutes or seconds should be supplied, if more than one time unit
    then the smallest unit will be picked

    The number of records return is default to a small number (20), this may be changed by supplying
    the query parameter ?limit=xx&skip=xx and it will not respect when datetime units is supplied

    :Example:
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity/summary
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity/summary?seconds=60
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity/summary?limit=10
    """
    try:
        # Get readings from asset_code
        asset_code = request.match_info.get('asset_code', '')
        # TODO: Use only the latest asset read to determine the data points to use. This
        # avoids reading every single reading into memory and creating a very big result set See FOGL-2635
        payload = PayloadBuilder().SELECT("reading").WHERE(
            ["asset_code", "=",
             asset_code]).LIMIT(1).ORDER_BY(["user_ts", "desc"]).payload()
        _readings = connect.get_readings_async()
        results = await _readings.query(payload)
        if not results['rows']:
            raise web.HTTPNotFound(
                reason="{} asset_code not found".format(asset_code))

        # TODO: FOGL-1768 when support available from storage layer then avoid multiple calls
        # Find keys in readings
        reading_keys = list(results['rows'][-1]['reading'].keys())
        response = []
        _where = PayloadBuilder().WHERE(["asset_code", "=",
                                         asset_code]).chain_payload()
        if 'seconds' in request.query or 'minutes' in request.query or 'hours' in request.query:
            _and_where = where_clause(request, _where)
        else:
            # Add limit, offset clause
            _and_where = prepare_limit_skip_payload(request, _where)

        for reading in reading_keys:
            _aggregate = PayloadBuilder(_and_where).AGGREGATE(["min", ["reading", reading]],
                                                              ["max", ["reading", reading]],
                                                              ["avg", ["reading", reading]]) \
                .ALIAS('aggregate', ('reading', 'min', 'min'),
                       ('reading', 'max', 'max'),
                       ('reading', 'avg', 'average')).chain_payload()
            payload = PayloadBuilder(_aggregate).payload()
            results = await _readings.query(payload)
            response.append({reading: results['rows'][0]})
    except (KeyError, IndexError) as ex:
        raise web.HTTPNotFound(reason=ex)
    except (TypeError, ValueError) as ex:
        raise web.HTTPBadRequest(reason=ex)
    else:
        return web.json_response(response)
示例#5
0
async def asset_reading(request):
    """ Browse a particular sensor value of a particular asset for which we have recorded readings and
    return the timestamp and reading value for that sensor. The number of rows returned
    is limited to a small number, this number may be altered by use of
    the query parameter limit=xxx&skip=xxx and it will not respect when datetime units is supplied

    The readings returned can also be time limited by use of the query
    parameter seconds=sss. This defines a number of seconds that the reading
    must have been processed in. Older readings than this will not be returned.

    The readings returned can also be time limited by use of the query
    parameter minutes=mmm. This defines a number of minutes that the reading
    must have been processed in. Older readings than this will not be returned.

    The readings returned can also be time limited by use of the query
    parameter hours=hh. This defines a number of hours that the reading
    must have been processed in. Older readings than this will not be returned.

    Only one of hour, minutes or seconds should be supplied

    Returns:
           json result on basis of SELECT user_ts as "timestamp", reading->>'reading' FROM readings WHERE asset_code = 'asset_code' ORDER BY user_ts DESC LIMIT 20 OFFSET 0;

    :Example:
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity/temperature
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity/temperature?limit=1
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity/temperature?skip=10
            curl -sX GET "http://localhost:8081/fledge/asset/fogbench_humidity/temperature?limit=1&skip=10"
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity/temperature?minutes=60
    """
    asset_code = request.match_info.get('asset_code', '')
    reading = request.match_info.get('reading', '')

    _select = PayloadBuilder().SELECT(("user_ts", ["reading", reading])) \
        .ALIAS("return", ("user_ts", "timestamp"), ("reading", reading)).chain_payload()
    _where = PayloadBuilder(_select).WHERE(["asset_code", "=",
                                            asset_code]).chain_payload()
    if 'seconds' in request.query or 'minutes' in request.query or 'hours' in request.query:
        _and_where = where_clause(request, _where)
    else:
        # Add the order by and limit, offset clause
        _and_where = prepare_limit_skip_payload(request, _where)

    payload = PayloadBuilder(_and_where).ORDER_BY(["user_ts",
                                                   "desc"]).payload()

    results = {}
    try:
        _readings = connect.get_readings_async()
        results = await _readings.query(payload)
        response = results['rows']
    except KeyError:
        raise web.HTTPBadRequest(reason=results['message'])
    else:
        return web.json_response(response)
示例#6
0
async def asset(request):
    """ Browse a particular asset for which we have recorded readings and
    return a readings with timestamps for the asset. The number of readings
    return is defaulted to a small number (20), this may be changed by supplying
    the query parameter ?limit=xx&skip=xx and it will not respect when datetime units is supplied

    Returns:
          json result on basis of SELECT user_ts as "timestamp", (reading)::jsonFROM readings WHERE asset_code = 'asset_code' ORDER BY user_ts DESC LIMIT 20 OFFSET 0;

    :Example:
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity?limit=1
            curl -sX GET "http://localhost:8081/fledge/asset/fogbench_humidity?limit=1&skip=1"
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity?seconds=60
    """
    asset_code = request.match_info.get('asset_code', '')
    _select = PayloadBuilder().SELECT(
        ("reading",
         "user_ts")).ALIAS("return", ("user_ts", "timestamp")).chain_payload()

    _where = PayloadBuilder(_select).WHERE(["asset_code", "=",
                                            asset_code]).chain_payload()
    if 'seconds' in request.query or 'minutes' in request.query or 'hours' in request.query:
        _and_where = where_clause(request, _where)
    else:
        # Add the order by and limit, offset clause
        _and_where = prepare_limit_skip_payload(request, _where)

    payload = PayloadBuilder(_and_where).ORDER_BY(["user_ts",
                                                   "desc"]).payload()
    results = {}
    try:
        _readings = connect.get_readings_async()
        results = await _readings.query(payload)
        response = results['rows']
    except KeyError:
        raise web.HTTPBadRequest(reason=results['message'])
    else:
        return web.json_response(response)
示例#7
0
async def asset_readings_with_bucket_size(
        request: web.Request) -> web.Response:
    """ Retrieve readings for a single asset between two points in time.
        These points are defined as a relative value in seconds back in time from the current time and a number of seconds worth of data.
        For example: For asset XYZ from (now - 60) for 60 seconds to get a minutes worth of data from a minute in the passed.
        The samples returned are averages grouped over a period of time, know as a bucket size.
        If 60 seconds worth of data is requested and a bucket size of 10 seconds is given then 6 values will be returned.
        Each of those 6 readings is an average over a 10 seconds period.

        If bucket_size is not given then the bucket size is 1
        If start is not given then the start point is now - 60 seconds.
        If length is not given then length is 60 seconds. And length is calculated with length / bucket_size

       :Example:
               curl -sX GET http://localhost:8081/fledge/asset/{asset_code}/{reading}/bucket/{bucket_size}
               curl -sX GET http://localhost:8081/fledge/asset/{asset_code}/{reading}/bucket/{bucket_size}?start=<start point>
               curl -sX GET http://localhost:8081/fledge/asset/{asset_code}/{reading}/bucket/{bucket_size}?length=<length>
               curl -sX GET "http://localhost:8081/fledge/asset/{asset_code}/{reading}/bucket/{bucket_size}?start=<start point>&length=<length>"
       """
    try:
        asset_code = request.match_info.get('asset_code', '')
        reading = request.match_info.get('reading', '')
        bucket_size = request.match_info.get('bucket_size', 1)
        length = 60
        ts = datetime.datetime.now().timestamp()
        start = ts - 60
        _aggregate = PayloadBuilder().AGGREGATE(["min", ["reading", reading]], ["max", ["reading", reading]],
                                                ["avg", ["reading", reading]]) \
            .ALIAS('aggregate', ('reading', 'min', 'min'), ('reading', 'max', 'max'),
                   ('reading', 'avg', 'average')).chain_payload()
        _readings = connect.get_readings_async()

        verify_asset_reading_payload = PayloadBuilder().SELECT("reading").WHERE(["asset_code", "=", asset_code]).LIMIT(1).\
            ORDER_BY(["user_ts", "desc"]).payload()
        res = await _readings.query(verify_asset_reading_payload)
        if not res['rows']:
            raise KeyError("{} asset code not found".format(asset_code))
        # TODO: FOGL-1768 when support available from storage layer then avoid multiple calls
        reading_keys = list(res['rows'][-1]['reading'].keys())
        if reading not in reading_keys:
            raise KeyError(
                "{} reading key is not found for {} asset code".format(
                    reading, asset_code))
        if 'start' in request.query and request.query['start'] != '':
            start = float(request.query['start'])
            if start < 0:
                raise ValueError('start must be a positive integer')

        _where = PayloadBuilder(_aggregate).WHERE(
            ["asset_code", "=",
             asset_code]).AND_WHERE(["user_ts", ">=",
                                     str(start)]).chain_payload()
        _bucket = PayloadBuilder(_where).TIMEBUCKET(
            'user_ts', bucket_size, 'YYYY-MM-DD HH24:MI:SS',
            'timestamp').chain_payload()
        if 'length' in request.query and request.query['length'] != '':
            length = int(request.query['length'])
            if length < 0:
                raise ValueError('length must be a positive integer')
        payload = PayloadBuilder(_bucket).LIMIT(int(
            length / int(bucket_size))).payload()
        # Sort & timebucket modifiers can not be used in same payload
        # payload = PayloadBuilder(limit).ORDER_BY(["user_ts", "desc"]).payload()
        results = await _readings.query(payload)
        response = results['rows']
    except (KeyError, IndexError) as e:
        raise web.HTTPNotFound(reason=e)
    except (TypeError, ValueError) as e:
        raise web.HTTPBadRequest(reason=e)
    except Exception as e:
        raise web.HTTPInternalServerError(reason=str(e))
    else:
        return web.json_response(response)
示例#8
0
async def asset_averages(request):
    """ Browse all the assets for which we have recorded readings and
    return a series of averages per second, minute or hour.

    The readings averaged can also be time limited by use of the query
    parameter seconds=sss. This defines a number of seconds that the reading
    must have been processed in. Older readings than this will not be summarised.

    The readings averaged can also be time limited by use of the query
    parameter minutes=mmm. This defines a number of minutes that the reading
    must have been processed in. Older readings than this will not be summarised.

    The readings averaged can also be time limited by use of the query
    parameter hours=hh. This defines a number of hours that the reading
    must have been processed in. Older readings than this will not be summarised.

    Only one of hour, minutes or seconds should be supplied

    The amount of time covered by each returned value is set using the
    query parameter group. This may be set to seconds, minutes or hours

    Returns:
            on the basis of
            SELECT min((reading->>'reading')::float) AS "min",
                   max((reading->>'reading')::float) AS "max",
                   avg((reading->>'reading')::float) AS "average",
                   to_char(user_ts, 'YYYY-MM-DD HH24:MI:SS') AS "timestamp"
            FROM fledge.readings
                   WHERE asset_code = 'asset_code' AND
                     reading ? 'reading'
            GROUP BY to_char(user_ts, 'YYYY-MM-DD HH24:MI:SS')
            ORDER BY timestamp DESC;

    :Example:
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity/temperature/series
            curl -sX GET "http://localhost:8081/fledge/asset/fogbench_humidity/temperature/series?limit=1&skip=1"
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity/temperature/series?hours=1
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity/temperature/series?minutes=60
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity/temperature/series?seconds=3600
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity/temperature/series?group=seconds
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity/temperature/series?group=minutes
            curl -sX GET http://localhost:8081/fledge/asset/fogbench_humidity/temperature/series?group=hours
    """
    asset_code = request.match_info.get('asset_code', '')
    reading = request.match_info.get('reading', '')

    ts_restraint = 'YYYY-MM-DD HH24:MI:SS'
    if 'group' in request.query and request.query['group'] != '':
        _group = request.query['group']
        if _group in ('seconds', 'minutes', 'hours'):
            if _group == 'seconds':
                ts_restraint = 'YYYY-MM-DD HH24:MI:SS'
            elif _group == 'minutes':
                ts_restraint = 'YYYY-MM-DD HH24:MI'
            elif _group == 'hours':
                ts_restraint = 'YYYY-MM-DD HH24'
        else:
            raise web.HTTPBadRequest(
                reason="{} is not a valid group".format(_group))

    _aggregate = PayloadBuilder().AGGREGATE(["min", ["reading", reading]], ["max", ["reading", reading]],
                                            ["avg", ["reading", reading]]) \
        .ALIAS('aggregate', ('reading', 'min', 'min'), ('reading', 'max', 'max'),
               ('reading', 'avg', 'average')).chain_payload()
    _where = PayloadBuilder(_aggregate).WHERE(["asset_code", "=",
                                               asset_code]).chain_payload()

    if 'seconds' in request.query or 'minutes' in request.query or 'hours' in request.query:
        _and_where = where_clause(request, _where)
    else:
        # Add LIMIT, OFFSET
        _and_where = prepare_limit_skip_payload(request, _where)

    # Add the GROUP BY and ORDER BY timestamp DESC
    _group = PayloadBuilder(_and_where).GROUP_BY("user_ts").ALIAS("group", ("user_ts", "timestamp")) \
        .FORMAT("group", ("user_ts", ts_restraint)).chain_payload()
    payload = PayloadBuilder(_group).ORDER_BY(["user_ts", "desc"]).payload()
    results = {}
    try:
        _readings = connect.get_readings_async()
        results = await _readings.query(payload)
        response = results['rows']
    except KeyError:
        raise web.HTTPBadRequest(reason=results['message'])
    else:
        return web.json_response(response)
示例#9
0
文件: browser.py 项目: lclfans/fledge
async def asset_readings_with_bucket_size(
        request: web.Request) -> web.Response:
    """ Retrieve readings for a single asset between two points in time.
        These points are defined as a relative value in seconds back in time from the current time and a number of seconds worth of data.
        For example: For asset XYZ from (now - 60) for 60 seconds to get a minutes worth of data from a minute in the passed.
        The samples returned are averages grouped over a period of time, know as a bucket size.
        If 60 seconds worth of data is requested and a bucket size of 10 seconds is given then 6 values will be returned.
        Each of those 6 readings is an average over a 10 seconds period.

        If bucket_size is not given then the bucket size is 1
        If start is not given then the start point is now - 60 seconds.
        If length is not given then length is 60 seconds. And length is calculated with length / bucket_size

       :Example:
               curl -sX GET http://localhost:8081/fledge/asset/{asset_code}/{reading}/bucket/{bucket_size}
               curl -sX GET http://localhost:8081/fledge/asset/{asset_code}/{reading}/bucket/{bucket_size}?start=<start point>
               curl -sX GET http://localhost:8081/fledge/asset/{asset_code}/{reading}/bucket/{bucket_size}?length=<length>
               curl -sX GET "http://localhost:8081/fledge/asset/{asset_code}/{reading}/bucket/{bucket_size}?start=<start point>&length=<length>"
       """
    try:
        start_found = False
        asset_code = request.match_info.get('asset_code', '')
        reading = request.match_info.get('reading', '')
        bucket_size = request.match_info.get('bucket_size', 1)
        length = 60
        ts = datetime.datetime.now().timestamp()
        start = ts - 60
        _aggregate = PayloadBuilder().AGGREGATE(["min", ["reading", reading]], ["max", ["reading", reading]],
                                                ["avg", ["reading", reading]]) \
            .ALIAS('aggregate', ('reading', 'min', 'min'), ('reading', 'max', 'max'),
                   ('reading', 'avg', 'average')).chain_payload()
        _readings = connect.get_readings_async()

        if 'start' in request.query and request.query['start'] != '':
            try:
                start = float(request.query['start'])
                datetime.datetime.fromtimestamp(start)
                start_found = True
            except Exception as e:
                raise ValueError('Invalid value for start. Error: {}'.format(
                    str(e)))

        if 'length' in request.query and request.query['length'] != '':
            length = int(request.query['length'])
            if length < 0:
                raise ValueError('length must be a positive integer')
            # No user start parameter: decrease default start by the user provided length
            if start_found == False:
                start = ts - length

        # Build datetime from timestamp
        start_time = time.gmtime(start)
        start_date = time.strftime("%Y-%m-%d %H:%M:%S", start_time)
        stop_time = time.gmtime(start + length)
        stop_date = time.strftime("%Y-%m-%d %H:%M:%S", stop_time)

        # Prepare payload
        _where = PayloadBuilder(_aggregate).WHERE([
            "asset_code", "=", asset_code
        ]).AND_WHERE(["user_ts", ">=", str(start_date)],
                     ["user_ts", "<=", str(stop_date)],
                     ["user_ts", "<=", str(stop_date)]).chain_payload()
        _bucket = PayloadBuilder(_where).TIMEBUCKET(
            'user_ts', bucket_size, 'YYYY-MM-DD HH24:MI:SS',
            'timestamp').chain_payload()

        payload = PayloadBuilder(_bucket).LIMIT(int(
            length / int(bucket_size))).payload()

        # Sort & timebucket modifiers can not be used in same payload
        # payload = PayloadBuilder(limit).ORDER_BY(["user_ts", "desc"]).payload()
        results = await _readings.query(payload)
        response = results['rows']
    except (KeyError, IndexError) as e:
        raise web.HTTPNotFound(reason=e)
    except (TypeError, ValueError) as e:
        raise web.HTTPBadRequest(reason=e)
    except Exception as e:
        raise web.HTTPInternalServerError(reason=str(e))
    else:
        return web.json_response(response)
示例#10
0
文件: browser.py 项目: lclfans/fledge
async def asset_datapoints_with_bucket_size(
        request: web.Request) -> web.Response:
    """ Retrieve datapoints for an asset.

        If bucket_size is not given then the bucket size is 1
        If start is not given then the start point is now - 60 seconds.
        If length is not given then length is 60 seconds. And length is calculated with length / bucket_size
        For multiple assets use comma separated values in request and this will allow data from one or more asset to be returned.

       :Example:
               curl -sX GET http://localhost:8081/fledge/asset/{asset_code}/bucket/{bucket_size}
               curl -sX GET http://localhost:8081/fledge/asset/{asset_code_1},{asset_code_2}/bucket/{bucket_size}
       """
    try:
        start_found = False
        length_found = False
        asset_code = request.match_info.get('asset_code', '')
        bucket_size = request.match_info.get('bucket_size', 1)
        length = 60

        ts = datetime.datetime.timestamp(datetime.datetime.now())
        start = ts - length
        asset_code_list = asset_code.split(',')
        _readings = connect.get_readings_async()

        if 'start' in request.query and request.query['start'] != '':
            try:
                start = float(request.query['start'])
                start_found = True
            except Exception as e:
                raise ValueError('Invalid value for start. Error: {}'.format(
                    str(e)))

        if 'length' in request.query and request.query['length'] != '':
            length = float(request.query['length'])
            if length < 0:
                raise ValueError('length must be a positive integer')
            length_found = True
            # No user start parameter: decrease default start by the user provided length
            if start_found == False:
                start = ts - length

        use_microseconds = False
        # Check subsecond request in start
        start_micros = "{:.6f}".format(start).split('.')[1]
        if start_found == True and start_micros != '000000':
            use_microseconds = True
        else:
            # No decimal part, check subsecond request in length
            start_micros = "{:.6f}".format(length).split('.')[1]
            if length_found == True and start_micros != '000000':
                use_microseconds = True

        # Build UTC datetime start/stop from start timestamp with/without microseconds
        if use_microseconds == False:
            start_date = datetime.datetime.fromtimestamp(
                start, datetime.timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
            stop_date = datetime.datetime.fromtimestamp(
                start + length,
                datetime.timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
        else:
            start_date = datetime.datetime.fromtimestamp(
                start, datetime.timezone.utc).strftime("%Y-%m-%d %H:%M:%S.%f")
            stop_date = datetime.datetime.fromtimestamp(
                start + length,
                datetime.timezone.utc).strftime("%Y-%m-%d %H:%M:%S.%f")

        # Prepare payload
        _aggregate = PayloadBuilder().AGGREGATE(["all"]).chain_payload()
        _and_where = PayloadBuilder(_aggregate).WHERE([
            "asset_code", "in", asset_code_list
        ]).AND_WHERE(["user_ts", ">=", str(start_date)],
                     ["user_ts", "<=", str(stop_date)]).chain_payload()

        _bucket = PayloadBuilder(_and_where).TIMEBUCKET(
            'user_ts', bucket_size, 'YYYY-MM-DD HH24:MI:SS',
            'timestamp').chain_payload()

        payload = PayloadBuilder(_bucket).LIMIT(
            int(float(length / float(bucket_size)))).payload()

        # Sort & timebucket modifiers can not be used in same payload
        # payload = PayloadBuilder(limit).ORDER_BY(["user_ts", "desc"]).payload()
        results = await _readings.query(payload)
        response = results['rows']
    except (KeyError, IndexError) as e:
        raise web.HTTPNotFound(reason=e)
    except (TypeError, ValueError) as e:
        raise web.HTTPBadRequest(reason=e)
    except Exception as e:
        raise web.HTTPInternalServerError(reason=str(e))
    else:
        return web.json_response(response)