Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

Table of Contents

Overview

The following are APIs implemented within the Fluxtream server.  The code implementing the back end support for these calls are in BodyTrackController.java.  Changes in that code may be more recent than this document.  When in doubt, please contact us at info@fluxtream.org.

Authentication and guest ID

You can either use basic auth or session-based management for authentication using the user's username and password.  The examples here are for using basic auth.  Managing cookies is outside the scope of this document.

Note that the web site piece of Fluxtream has recently been modified to accept email addresses in lieu of usernames in deference to cultural changes in what people expect.  However, these APIs have not been modified or tested to support use of email addresses.  

If you only know your email address and not your username, you can log in and check the account settings dialog for your username.

Get the ID for the guest

/api/guest

Returns json reflecting the account info for the logged in user.  The most important field to be aware of is the id field.  This is the numeric user ID corresponding with the authentication credentials provided.  You'll need to be able to get this ID to use with other API calls.


Example, good credentials:

  curl -u test:testtest http://fluxtream.org/api/guest
    {"username":"test","firstname":"test","lastname":"test","email":"foo@bar.com","roles":"[ROLE_USER]","id":1}

If user is not logged in, returns status code 401

Data access

Data sources, devices and channels

A data source can either represent a physical device, like a cell phone or a chest strap, or any other source of data, such as from an observation capture app.  Each data source in the system for a given user has a unique device name and may contain one or more channels.  For historical reasons, the name of the data source to upload to is generally referred to as dev_nickname.  

A data channel within a device also has a name, but that name must only be unique within the device.  

Source and channel names must include only alphanumeric characters (A-Z, a-z, 0-9) plus underscores.  If the names contain other characters they will be converted by the server to underscores.  

Formatting of time

All time fields is represented as double-precision floating point time in seconds since Jan 1, 1970 in UTC, not counting leap second (standard UNIX-style time).  Decimal seconds are allowed.  Times before 1/1/70 are representable by negative numbers.

Fetch tile

/api/bodytrack/tiles/UID/DeviceNickname.ChannelName/Level.Offset.json
Level determines time duration and approximate aggregation of data
Data aggregation bin size:  2level
Time duration of data tile:  512(2level)
E.g:
Tiles at level 0 are 512 seconds long and aggregate data in bins of 1 second
Tiles at level 1 are 1024 seconds long and aggregate data in bins of 2 seconds
Tiles at level -1 are 256 seconds long and aggregate data in bins of 0.5 seconds
Note that negative levels are valid;  the system is designed to work with double-precision floating point timestamps, with effective resolution of 1 ns for contemporary times

Offset is the index of the requested tile if you start with offset=0 at the epoch (midnight UTC on Jan 1, 1970) and number the tiles at this level sequentially since then.
start time = offset(512(2level))
E.g.:
level=0 offset=0 starts at Jan 1, 1970 00:00:00 UTC
level=0 offset=1 starts at Jan 1, 1970 00:08:20 UTC
level=0 offset=-1 starts at Dec 31, 1969 23:51:40 UTC
Notes:
- Negative offsets are valid and represent times before Jan 1, 1970
- A 64-bit signed integer is sufficient for storing offset, while a 32-bit integer is not.
To calculate what offset to use to include a given unixtime timestamp t, first determine the tile duration at the desired level – duration = (512(2level)) – then divide t by that duration and round down to the nearest integer.

For example, at level 5 each bin is 2^5 or 32 seconds.  There are 512 bins per tile, so duration = 32*512=16384 seconds.  The offset of the tile containing the t1384776000 is offset1384776000/16384, rounded down to the nearest integer, which is 84520

 
Values in the "mean" field of -1E+308 indicate a longer than usual break in the data.  We use it in the grapher to know whether to connect points on either side of it with lines or not.  You probably want to ignore those.
 
Returns format:
{
  "fields":["time","mean","stddev","count"],
  "data":[
              [time1, mean1, stddev1, count1],
              [time2, mean2, stddev2, count2],
                ...
              [timeN, meanN, stddevN, countN]
            ]
  "level": level,
  "offset": offset
}
Example:
  curl -u
test:testtest http://flxtest.bodytrack.org/api/bodytrack/tiles/1/PolarStrap.BeatSpacing/5.82564.json
Returns
{
   "fields":["time","mean","stddev","count"],
   "data":[
               [1352729398.800067,0.966,1.485415458679199,15],
               [1352729423.768154,0.6116538461538461,0.04332740977406502,52],
                ...
               [1352743298.36375,0.51925,0.1960801780223846,8],
               [1352744129.181875,-1E+308,0,0]
             ],
   "level":5,
   "offset":82564,
   "sample_width":32,
   "type":"value"
}

...

    {"tags":[energy","fruit","garden","headache"]}

 

Data upload

Storing data

/api/bodytrack/upload?dev_nickname=<name>&channel_names=<channel_names>&data=<data>

POSTs data for a given source to a given user's account.  Uses basic auth for both authentication to determine which user the data is being uploaded to.  Required parameters are:

  • dev_nickname Name of the data source to upload the data to (alphanumeric + underscores, unique to a given user)
  • channel_names  JSON encoded array of channel names.   
    Example: ["temperature", "humidity"]
  • data JSON encoded array of arrays of time samples, in the same order as channel names.  Time is always the first column (and not mentioned in the channel names above).  
    Example: [[1234152345.2, 45.9, 95.02], [1234152355.3, 45.8, 95.10]]


Example

  curl -i -u test:testtest http://fluxtream.org/api/bodytrack/upload -d dev_nickname=test -d channel_names='["a","b"]' -d data='[[1332754616,1,10], [1332754617,-1,20]]'

Returns:

{"max_datetime":null,"min_time":1332754616,"failed_records":0,"channel_specs":{"a":{"max_value":1,"min_value":-1,"min_time":1332754616,"channel_bounds":{"max_value":1,"min_value":-1,"min_time":1332754616,"max_time":1332754617},"imported_bounds":{"max_value":1,"min_value":-1,"min_time":1332754616,"max_time":1332754617},"max_time":1332754617},"b":{"max_value":20,"min_value":10,"min_time":1332754616,"channel_bounds":{"max_value":20,"min_value":10,"min_time":1332754616,"max_time":1332754617},"imported_bounds":{"max_value":20,"min_value":10,"min_time":1332754616,"max_time":1332754617},"max_time":1332754617}},"logrec_id":85284,"successful_records":1,"min_datetime":null,"max_time":1332754617}

Storing photos

/api/bodytrack/photoUpload?connector_name=CONNECTOR_NAME

Accepts a photo uploaded via multipart/form-data to the authenticated user's account for the specified connector.  Currently only supports the Fluxtream Capture connector (specified as "fluxtream_capture" in the query string). The multipart form body must contain two parts:

  • photo: the photo's bytes
  • metadata: JSON containing required photo metadata.  Currently the only required field is "capture_time_secs_utc" which is a double that specifies the time the photo was taken in UTC seconds.  Optional fields are "tags" (a string containing a comma-delimited list of tags) and "comment" (a string). Note that comments and tags are only honored when a photo is uploaded for the first time (a create).  Photos uploaded again are considered an update and the tags and comments are ignored.  Clients needing to modify a Fluxtream Capture photo's tags/comments should use the metadata set API method instead.  Examples:

{"capture_time_secs_utc":1355314332.000}

       {"capture_time_secs_utc":1355314332.000, "tags":"snack,fruit,strawberries", "comment":"Snacked on strawberries from my garden."}

The user need not explicitly add the Fluxtream Capture connector to his/her account prior to upload (and there's actually no way to do so).  Instead, the connector is added automatically upon first upload.  Valid photo formats are JPEG, PNG, and GIF.

See the Fluxtream Capture Photo Architecture docs for more info.

Example: curl -v -u username:password --form 'metadata={"capture_time_secs_utc":1355314332.000}' --form photo=@orientation_4.jpg http://fluxtream.org/api/bodytrack/photoUpload?connector_name=fluxtream_capture;

Returns: JSON describing whether the upload was successful.  The HTTP status code will be 200 upon success, and non-200 upon failure.  Here are several examples:

HTTP 200 OK
{"result":"OK","message":"photo created sucessfully!","payload":{"operation":"created","id":42, "key":"1.FluxtreamCapture.photo.2012348.1355414332000_9c2303170b4601917c59449cdecaecaa0ccbd40b6cf26406f07316261da7fe53"}}

HTTP 200 OK
{"result":"OK","message":"photo updated sucessfully!","payload":{"operation":"updated","id":42,"key":"1.FluxtreamCapture.photo.2012347.1355311332000_0dae72b9ee44a61c1a6efe24814cb713026d58fb5af92f91e88cd2a2bf24d41c"}}

HTTP 400 Bad Request
{"result":"KO","message":"Upload failed because the connector [bogus_connector] is unknown"}

HTTP 400 Bad Request
{"result":"KO","message":"Upload failed because photo uploads are currently only allowed for the Fluxtream Capture connector"}

HTTP 400 Bad Request
{"result":"KO","message":"Upload failed because both the \u0027photo\u0027 and \u0027metadata\u0027 parts are required and must be non-null"}

HTTP 400 Bad Request
{"result":"KO","message":"Upload failed because the Multipart was null"}

HTTP 400 Bad Request
{"result":"KO","message":"InvalidDataException while trying to save the photo"}

HTTP 415 Unsupported Media Type
{"result":"KO","message":"UnsupportedImageFormatException while trying to save the photo"}

HTTP 500 Internal Server Error
{"result":"KO","message":"StorageException while trying to save the photo"}

HTTP 500 Internal Server Error
{"result":"KO","message":"Upload failed due to an unexpected exception"}