Your app will send commands to, and receive callbacks from, BACtrack devices. In order to do this, you must first
initialize a BacTrackAPI object with the following command call:
mBacTrack = [[BacTrackAPI alloc] initWithDelegate:<BacTrackAPIDelegate> AndAPIKey:@"insertAPIKeyStringHere"];
This initializer method sets the specified delegate and
checks with our server whether the included API Key is valid. In case your app has not been approved
to use our SDK, the callback (void)BacTrackAPIKpiKeyDeclined:(NSString *)errorMessage
will be called and
must be implemented.
Once you've initialized your BacTrackAPI object, you can establish a BTLE connection between your iOS device
and a BACtrack by executing the following command call on the BacTrackAPI object:
connectToNearestBreathalyzer
Tapping on the "Take Test" button calls startCountdown
on the BacTrackAPI object and initiates a series of callbacks on the BacTrackAPIDelegate shown below.
Starting a BAC test walks the user through 5 steps.
The test process consists of a series of five phases. At the start of every phase your <BacTrackAPIDelegate> receives the following callbacks:
(void)BacTrackCountdown:(NSNumber *)seconds executionFailure:(BOOL)failure
This callback may be called many times and the <seconds> parameter is an estimated amount of seconds
left until the next phase (BacTrackStart
) begins.
(void)BacTrackStart
(void)BacTrackBlow:
This callback may be called many times during the time that the user is blowing into the BACtrack.
(void)BacTrackAnalyzing
When this callback is called, the user can stop blowing.
(void)BacTrackResults:(CGFloat)bac
-(id)initWithDelegate:(id<BacTrackAPIDelegate> )delegate AndAPIKey:(NSString*)api_key;
These methods represent the commands you can send to a BACtrack:
Methods | Description |
---|---|
-(void)connectToNearestBreathalyzer
|
NORMAL use case for connecting to a BACtrack. Connects to nearest to BACtrack. |
-(void)startScan
|
Scan for BACtracks within range. To be used with connectBreathalyzer:withTimeout. |
|
ALTERNATE use case for connecting to a BACtrack. See below for explanation. |
-(void)stopScan
|
Stop scanning for BACtracks within range. To be used with startScan. |
-(void)disconnect
|
Disconnect from BACtrack |
-(BOOL)startCountdown
|
Start BACtrack countdown to take a BAC test. |
-(void)getBreathalyzerBatteryLevel
|
Request a callback with the current battery voltage and level. |
These methods represent all the messages you might get from the BACtrack.
Required Methods | Description |
---|---|
-(void)BacTrackAPIKeyDeclined:(NSString *)errorMessage
|
Called if the passed in API Key is not valid. |
Optional Methods | Description |
---|---|
-(void)BacTrackAPIKeyAuthorized
|
Called if the passed in API Key is valid. |
-(void)BacTrackConnected:(BACtrackDeviceType)device
|
Successfully connected to BACTrack and found services and characteristics. |
-(void)BacTrackDisconnected
|
Disconnected from BACTrack. |
-(void)BacTrackConnectTimeout
|
Attempting to connect to BACTrack timed out. |
-(NSTimeInterval)BacTrackGetTimeout
|
Asks for connection timeout when connecting to nearest BACtrack. |
|
Counting down to reading, number (a double) seconds left, error = TRUE if BAC sensor rejects request. |
-(void)BacTrackStart
|
Tell the user to start blowing. |
-(void)BacTrackBlow |
Tell the user to keep blowing. This call is deprecated and will not support newer devices. Use BacTrackBlow:(float) instead. |
-(void)BacTrackBlow:(NSNumber*)breathFractionRemaining
|
Tell the user to keep blowing. The argument blowFractionRemaining ranges from 1.0 to 0 to inform the application of how much blow time or breath volume remains. |
-(void)BacTrackAnalyzing
|
BACtrack is analyzing the result. |
-(void)BacTrackResults:(CGFloat)bac
|
Result of the blow. |
-(void)BacTrackFoundBreathalyzer:(Breathalyzer*)breathalyzer
|
Found a BACtrack. Call comes in for every BACtrack found during scan. |
-(void)BacTrackBatteryLevel:(NSNumber *)number
|
Reports battery level in the XCode console. 0 is low (needs to be charged). 1 is medium, >=2 is high. |
-(void)BacTrackSerial:(NSString *)serial_hex
|
Reports the hardware serial number. |
-(void)BacTrackError:(NSErrror *)error
|
Called when an error occurs. The code of the error. Codes can be looked up in the SDK header file prefixed by "MOBILE__ERROR_*". |
Depracated Methods |
---|
-(void)BacTrackConnected
-(void)BacTrackBreathalyzerError:(UInt8)errortype withTemperature:(UInt8)temperaturestate
Normally, an app will set up a BTLE connection with the nearest BACtrack using the connectToNearestBreathalyzer
command call. However, your app might want to connect with a selected BACtrack. To enable this functionality, you need to scan for nearby BACtracks using the startScan
command call. The scan runs indefinitely until the command stopScan
is called. During the scan, everytime your iOS device finds a BACtrack, the callback (void)BacTrackFoundBreathalyzer:(Breathalyzer*)breathalyzer
is called. Our sample app implements this by adding the breathalyzer to a breathalyzers array, which is then used as the data source for a table view that lists all the nearby breathalyzers.
A list of nearby BACtracks in the Sample App
You can distinguish between BACtracks with the following attributes:
Breathalyzer.perpipheral.name
Breathalyzer.uuid
After isolating the Breathalyzer object that you want, you can connect with it by providing the Breathalyzer
object as an argument to the following command call:
(void)connectBreathalyzer:(Breathalyzer*)breathalyzer withTimeout:(NSTimeInterval)timeout
The BACtrack API consists of a static library (.a file) and a header file (.h file). To use the SDK, your app must link with our static library.
Add the .a library file in build phases.
Lastly, in Build Settings > Linking > Other Linker Flags, add the following flags:
Your app will send commands, and recieve callbacks from your BACtrack device. In order to do this, you must first
create a BacTrackAPI object with the following constructor:
mAPI = new BACtrackAPI(this, mCallbacks, apiKey);
. This constructor creates a BACtrackAPI object with the passed in callbacks and also checks with our server whether the included API Key is valid. In case your app has not been approved
to use our SDK, the callback void BACtrackAPIKeyDeclined(String errorMessage)
will be called and
must be implemented.
Once you've created your BacTrackAPI object, you can establish a BTLE connection between your Android device
and your BACtrack by executing the following command call on the BACtrackAPI object:
public void connectToNearestBreathalyzer()
Tapping on the "Take Test" button calls public boolean startCountdown()
on the BacTrackAPI object and initiates
a series of callbacks on the BacTrackAPIDelegate shown below.
The test process consists of a series of five phases. At the start of every phase your <BacTrackAPIDelegate> receives the following callbacks:
void BACtrackCountdown(int currentCountdownCount)
This callback may be called repeatedly and the <currentCountdownCount> parameter is an estimated amount of seconds
left until the next callback (BacTrackStart) is called.
void BACtrackStart()
void BACtrackBlow(float breathFractionRemaining)
This callback may be called repeatedly during the time that the user is expected to blow into the BACtrack device.
void BACtrackAnalyzing()
When this callback is called, the user can stop blowing.
void BACtrackResults(float measuredBac)
public BACtrackAPI(Context context, final BACtrackAPICallbacks bacTrackAPICallbacks, String apiKey)
These methods represent the commands you can send to the BACtrack.
Methods | Description |
---|---|
public void connectToNearestBreathalyzer()
|
Connect to the nearest BACtrack device. |
public void connectToNearestBreathalyzerWithTimeout()
|
Connect to the nearest BACtrack device. |
public void startScan()
|
Scans for BACtracks within range. Continues until stopScan() is called |
public void connectToDevice(BACtrackAPI.b breathalyzer)
|
ALTERNATE use case for connecting to a BACtrack device. Use arraylist returned in stopScan to get BACtrack device. |
public ArrayList<BACtrackAPI.b> stopScan()
|
Stop scanning and return array of breathalyzers found. |
public void disconnect()
|
Disconnect from the currently-connected BACtrack device. |
public boolean startCountdown()
|
Start BACtrack countdown to take a BAC test. |
public boolean getBreathalyzerBatteryVoltage()
|
Request the device's battery voltage. Will trigger BACtrackBatteryVoltage and BACtrackBatteryLevel on successful read. |
These methods represent all the messages you might get from the BACtrack.
Required Methods | Description |
---|---|
void BACtrackAPIKeyDeclined(String errorMessage)
|
Called if the passed in API Key is not valid. |
Optional Methods | Description |
---|---|
void BACtrackAPIKeyAuthorized()
|
Called if the passed in API Key is valid. |
void BACtrackConnected(BACTrackDeviceType bacTrackDeviceType)
|
Called after the BACtrack is connected and services are discovered. |
void BACtrackDidConnect(String breathalyzerAdvertisedName)
|
Called after the BACtrack is connected but before services are discovered. |
void BACtrackDisconnected()
|
Called when the BACtrack disconnects from the Android device. |
void BACtrackConnectionTimeout()
|
Called if the connection to the BACtrack times out. |
void BACtrackFoundBreathalyzer(BACtrackAPI.b BACtrackDevice)
|
Called whenever a BACtrack device is found while scanning for a device. |
void BACtrackCountdown(int currentCountdownCount)
|
Called when the BACtrack is counting down to the "Blow Now" state. currentCountdownCount is the estimated time until BACtrackStart() is called. |
void BACtrackStart()
|
Called when the device wants the user to start blowing. |
void BACtrackBlow(float blowFractionRemaining)
|
Tell the user to keep blowing. The argument blowFractionRemaining ranges from 1.0 to 0 to inform the application of how much blow time or breath volume remains. |
void BACtrackAnalyzing()
|
Called while the BACtrack is analyzing the blow results. |
void BACtrackResults(float measuredBac)
|
Called when the BACtrack is finished analyzing the blow results. |
void BACtrackFirmwareVersion(String version)
|
Called when the BACtrack responds with its firmware version. |
void BACtrackSerial(String serialHex)
|
Called when the BACtrack responds with its serial number. |
void BACtrackUseCount(int useCount)
|
Called when the BACtrack responds with the use count. |
void BACtrackFoundBreathalyzer(BluetoothDevice breathalyzer)
|
Called whenever a BACtrack device is found while scanning for a device. |
void BACtrackBatteryVoltage(float voltage)
|
Called when the BACtrack responds with its battery voltage. |
void BACtrackBatteryLevel(int level)
|
Called when the BACtrack responds with its battery level. 0 is low (needs to be charged). 1 is medium, >=2 is high. |
void BACtrackError(int errorCode)
|
Called when an error occurs. The code of the error. Codes can be looked up in Constants/ControlBytes * prefixed by "ERROR_". |
BACtrack users have store hundreds of thousands of BAC readings to the cloud. BAC readings contain rich metadata like location, photos, and notes. Many users opt in to allow readings to be viewed anonymously. This unique dataset can be accessed by developers for use in statistcal analysis, data mashups, or use in your app. You can view some examples of the data in action at the BACtrack Consumption Report and BACtrack WorldView. In your own app, you can authentice users to let them view their account data.
The BACtrack data API uses OAuth 1.0a. OAuth is a protocol that allows the user grant your app access to our web service on his behalf without telling you his login credentials. OAuth defines a workflow that allows the user to log in to our site at your request to create an access token that will allow you to request data from the service on his behalf.
These docs don't describe how to sign each request. There is a description of the process at https://oauth.net/core/1.0a/#signing_process. However, most developers do not implement OAuth signing themselves since there are several available libraries. In python, people typically use OAuth2 (In spite of its name, this library is for OAuth 1.0a).
As you read the overview of the OAuth authentication protocol below, it might help to follow along on this diagram from oauth.net: https://oauth.net/core/diagram.png
oauth_token
in the header. The response will consist of a Request Token and a Request Token Secret.oauth_token
and compute the oauth_signature
using the Request Token Secret.For all of these steps and for general API usage, the oauth parameters should be passed via the HTTP Authorization header. If the HTTP Authorization header is not available, we also accept these parameters as url-encoded query string parameters. The parameter names are as follows:
Parameter | Description |
---|---|
oauth_consumer_key |
The public key for your app. This is different than your hardware API Key. Please contact [email protected] to get a Web API Key |
oauth_nonce |
A one time random string that you generate per request. This protects against replay attacks. Nonce stands for "number used once". |
oauth_signature |
Signature for the request. Signed with the appropriate secret key using the technique from https://oauth.net/core/1.0a/#signing_process. It is probably easiest to find a library to do this signing for you. |
oauth_signature_method |
Must be HMAC-SHA1 . We do not support plaintext signing. |
oauth_timestamp |
Must be a recent timestamp in seconds since the epoch. In python this is found with import time; timestamp = time.time() . |
oauth_token |
The appropriate token (depending on which leg of the auth procedure you're performing). |
oauth_version |
Must be 1.0 |
Note: In OAuth jargon, a key is like a username, and a secret is the corresponding password. Important: You must set the content-type to json in the header of every request: Content-Type: application/json
.
Alternatively, you can add ?format=json
to all requests.
Readings are the backbone of the BACtrack data API. They provide insight into user activity and contain a variety of interesting data sets.
User readings are readings that belong to a particular users. These readings may or may not be publicly shared by the user. To access the private readings for a user, you must sign the request with a validated Access Token.
GET https://mobile.bactrack.com/v1/users/id
/readings/
Query String Filter Parameters:
Parameter | Description |
---|---|
lat_center |
The latitudinal center to query for readings from. Expressed in degrees. |
lng_center |
The longitudinal center to query for readings from. Expressed in degrees. |
radius_meters |
The radius in meters from the center latitude / longitude to limit to return of readings to. |
timestamp__gte |
Limit the results to readings timestamped after this value. Expressed in ISO-8601. |
timestamp__lte |
Limit the results to readings timestamped before this value. Expressed in ISO-8601. |
offset |
Offset of the results as an integer. Default is 0 . |
limit |
Limit the number of results as an integer. Default is 100 . |
Content-Type: application/json; charset=utf-8 Authorization: {oauth header goes here} GET https://mobile.bactrack.com/v1/users/1/readings/timestamp__gte=2010-11-16 14:17:00×tamp__lte=2010-11-16 14:22:00
Sample Response:
HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 { count:1, readings: [ { "id": 123, "date": "2010-11-16 14:18:00", "location": [47.123, 128.112], "bac": 0.021, "verified", false, "drinks": [ "martini", "bourbon" ], "notes": [ "Love whiskey" ], "photos": [ ] } ] }
Content-Type: application/json; charset=utf-8 Authorization: {oauth header goes here} GET https://mobile.bactrack.com/v1/users/{id}/readings?lat_center=47.123&lng_center=128.112&radius_meters=100
Sample Response:
HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 { count:1, readings: [ { "id": 123, "date": "2010-11-16 14:18:00", "location": [47.123, 128.112], "bac": 0.021, "verified", false, "drinks": [ "martini", "bourbon" ], "notes": [ "Love whiskey" ], "photos": [ ] } ] }
Note: Since these resources give you readings that users have made public, you don't need to sign these requests with a validated Access Token. You can just sign them with your Consumer Key and Secret (like when you're requesting a request token).
GET https://mobile.bactrack.com/v1/readings
Query String Filter Parameters:
Parameter | Description |
---|---|
lat_center |
The latitudinal center to query for readings from. Expressed in degrees. |
lng_center |
The longitudinal center to query for readings from. Expressed in degrees. |
radius_meters |
The radius in meters from the center latitude / longitude to limit to return of readings to. |
timestamp__gte |
Limit the results to readings timestamped after this value. Expressed in ISO-8601. |
timestamp__lte |
Limit the results to readings timestamped before this value. Expressed in ISO-8601. |
offset |
Offset of the results as an integer. Default is 0 . |
limit |
Limit the number of results as an integer. Default is 100 . |
Content-Type: application/json; charset=utf-8 Authorization: {oauth header goes here} GET https://mobile.bactrack.com/v1/readings?lat_center=47.123&lng_center=128.112&radius_meters=100
Sample Response:
HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 { count:1, readings: [ { "id": 123, "date": "2010-11-16 14:18:00", "location": [47.123, 128.112], "bac": 0.021, "verified", false, "drinks": [ "martini", "bourbon" ], "notes": [ "Love whiskey" ], "photos": [ ] } ] }
GET https://mobile.bactrack.com/v1/readings/id
Content-Type: application/json; charset=utf-8 Authorization: {oauth header goes here} GET https://mobile.bactrack.com/v1/readings/123
Sample Response:
HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 { "id": 123, "date": "2010-11-16 14:18:00", "location": [47.123, 128.112], "bac": 0.021, "verified", false, "drinks": [ "martini", "bourbon" ], "notes": [ "Love whiskey" ], "photos": [ ] }
Photos are requested via a normal GET request that does not need to be signed with OAuth. The URLs for the photos are available in "photos" section of any Reading resource.