How to create an iOS app for Sens'it tracker in Swift
Sens’it is small tracker developed by Sigfox and given for free during events to let people test the Sigfox low frequency IoT network. Let’s see how to create an iOS app in Swift based on Sens’it api.
There were different versions of this device, usually with a single button but with different sensors included (temperature, humidity, brightness, movements etc). Sens’it is actually working on battery.
This year, I’ve got the opportunity to go to the Mobile World Congress 2016 with Aruco and get one of this tracker. Sigfox becoming bigger and bigger in IoT thanks to its network solution, I was really keen to work on its tracker and see what I can manage to do with Sens’it api.
For this project, I wanted to develop an iOS mobile app to display history data without using their own web interface, which is not that user friendly.
In theory
I wanted to design a very simple app, listing every tracker the user have, then list the sensors in it and display the history.
To prototype it quickly, I created a JSON file with multiples sample results Sens’it offer on their api website. I integrated this file directly into my app to create the design and check if the user flow was alright. I also based my app on Swift language, which I think is really easy to use and fast to implement for these kind of apps.
First point I noticed is the samples in the documentation were not a proper valid JSON format. Maybe they just forgot about it.
I also noticed Sens’it api doesn’t allow to get access to the product name. By listing the products “/devices”, I can’t find any friendly way to list my devices. I had to use the serial number itself, which is not so good for the user experience.
My Sens’it tracker integrate temperature, humidity, light and motion sensors. When I checked the documentation about “/device/{device_id}”, I didn’t find anything about the humidity. I guess the documentation is not updated then.
Good thing, the api allow to create custom notifications based on tracker results. This is great if you want to call a third part api (probably yours) to manage some calculations or any other treatments you can think about. This is a very interesting point for developers.
Once my design and prototype almost ready, I only needed to use the call the api and use the real data instead of my local JSON file.
In practice
Once I enabled my Sens’it on their website, I had to go to “Edit my account” then, at the bottom find a way to enable developer program. Even if it generated a token and let me add an URL callback, I had to follow a second link to “Developer Part” and create a dedicated app on the platform to let my final user sign in. Not very clear.
Sens’it api uses OAUTH2 and HTTPS for all their calls and , which is great when you’re using private user data. I will go back to this point later.
First issue experienced was to keep the user back into the app after authenticating. URL callback field in OAUTH2 in the back office only allow HTTP and HTTPS request. I bypassed this point by using a third part to forward the authenticate credentials into my app with an URL scheme. Probably not the best solution.
if (isset($_GET['code'])) {
header('Location: BPSensit://code='.$_GET['code']);
}
exit;
Back into the iOS app, I used the AFOAuth2Manager to manage OAUTH2 authentication. This package is a top layer for AFNetwork library.
To authenticate an user, there is a code needed via a GET request which has to be sent into a second POST request to get the final access token.
In the website api example,I assumed POST parameters were actually sent as POST. However, I saw that it were passed as GET (as see in the image above). I thought it was a documentation issue but I quickly got more trouble with this part.
AFOAuth2Manager library already wrapped methods to make it quicker and easier to use. As best practice, all of requested parameters are passed as POST. Since I tried to make the authentication work, I’ve noticed the api didn’t recognize the POST parameters. I had to embed them directly into the url path as GET parameters. Not really proud of that…
let sessionManager = AFOAuth2Manager(baseURL: url, clientID: clientId, secret: clientSecret)
sessionManager.requestSerializer = AFJSONRequestSerializer()
sessionManager.responseSerializer = AFJSONResponseSerializer()
sessionManager.requestSerializer.setAuthorizationHeaderFieldWithUsername(clientId, password: clientSecret)
sessionManager.authenticateUsingOAuthWithURLString("/oauth/token?grant_type=authorization_code&code=" + authCode + "&client_id="+clientId+"&redirect_uri="+redirectUrl, code: authCode, redirectURI: redirectUrl, success: { [weak self] (credential) in
print("Token: " + credential.accessToken)
self?.credential = credential
}, failure: { (error) in
print(error)
})
Once authenticated and my credentials saved, I was ready to get my devices. Trying to request /devices
api, I’ve seen Xcode stopped me due to a non HTTPS request, a requirement since iOS9.
However, my endpoint was defined as HTTPS. I assumed that Sens’it api uses HTTP as some point, which iOS9 can track and is not very happy with that.
To work around this new issue, I’ve added Sens’it api domain into my property list file as an exception for HTTPS. But does it mean I’m losing the encryption at some point?
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>api.sensit.io</key>
<dict>
<!--Include to allow subdomains-->
<key>NSIncludesSubdomains</key>
<true/>
<!--Include to allow HTTP requests-->
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<!--Include to specify minimum TLS version-->
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
The app should now be ready, but once the request called, a new error occurred. Trying to figuring out what’s happening, I realized that the request tried to redirect me into the login page. This meant to me I wasn’t authenticate… In the documentation, the api should return the result when success or an error description as JSON format. However, in my case, it literally redirected me to the login page and sent me the html content as response. Really frustrating…
After few days trying to work around this one, I didn’t find any solution. I tried my code with other OAUTH2 common api to be sure, and it worked fine. From my point of view, it seemed their api were not working at some point, by not sending the right success or error result.
I tapped out and give up on this one as I can’t get access to devices, I can’t go further into the app.
My conclusion
Even if Sens’it try to be a device opened to developers, the api behind is really bad right now. I’ve pointed too many issues between the documentation, the given examples and the real result, I won’t say it’s “ developer friendly”.
However, as a mobile developer in IoT, the best thing about Sens’it is to not think about the connection with the final device. This is a big advantage. I used to work with Bluetooth paired devices or WiFi slow connection bridges, I don’t think these issues can apply to SigFox technology at this point. I will try to keep it in mind for my next SigFox developer review I will do.
My project is available on my github.