Skip to content

A convenience layer for thing and client development for The Thing System on iOS devices.

License

Notifications You must be signed in to change notification settings

TheThingSystem/steward-ios-library

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

The Thing System iOS Library

The latest binary release is version 0.2.0 and includes authentication support.

This library is a draft release of The Thing System iOS Library. It serves as a convenience layer and is intended to simplify common tasks when developing both things and clients on iOS devices which talk to The Thing System steward software.

The iOS library has been divided into two seperate static libraries, a libClient.a and alibThing.a. This is intended to minimise the addition of redundant code to your application. However there is no reason why both libraries cannot be used inside a single application.

Pull requests for enhancements, refactoring and bug fixes are welcome.

Note: This library should be considered a draft release. It's likely that the API will evolve considerably over time. Right now for instance JSON is passed back to your code by the library in many places. Future releases may pre-parse the JSON messages and pass them as NSDictionary objects instead.

##Installation

You can either copy all the files for the relevant library into your project, or include the appropriate static library as a subproject with either libThing.a or libClient.a as targets.

However the easiest method is to use the binary release and drop the pre-built binaries along with the asociated header files for the static libraries into your project.

Note: If you add the libraries to your project as a static library lib*.a and associated headers, you must also add -ObjC to the "Other Linker Flags" option in your project settings (see the example code).

###Dependencies

Your application must be linked against the following additional frameworks to use the Thing library,

  • SystemConfiguration.framework

and the following additional frameworks and dynamic libraries for the Client library,

  • SystemConfiguration.framework
  • Security.framework
  • CFNetwork.framework
  • libicucore.dylib

##Building Things

This library is synactic sugar over the top of the Cocoa Async Socket library and is intended to simplify common tasks when building things for the steward under iOS.

###Building a TSRP things

If a thing needs to report sensor readings, or an event happening, to the steward it can implement the Thing Sensor Reporting Protocol (TSRP). This is a simple multicast UDP based protocol. For things that need to both report back to the steward and received requests to perform actions, or make measurements at certain times, you should look at the Simple Thing Protocol instead.

To build a TSRP thing you should

#import "Thing.h"

and then grab a shared instance of the Client class, declare yourself a delgate

Thing *thing = [Thing sharedThing];
thing.delegate = self;

and then declare your class as a <ThingDelegate>.

You should then create a device instance, e.g.

Device *device = [[Device alloc] initWithDevice:@"/device/sensor/phone/iphone"];
device.name = @"iPhone";
device.maker = @"Apple";
device.serial = [Util uniqueID];
device.udn = [NSString stringWithFormat:@"%@-iphone", device.serial];

device.properties = @{ @"roll":@"radians",
                       @"pitch":@"radians",
                       @"yaw":@"radians",
                       @"x acceleration":@"g",
                       @"y acceleration":@"g",
                       @"z acceleration":@"g",
                       @"x gravity":@"g",
                       @"y gravity":@"g",
                       @"z gravity":@"g",
                       @"x rotation":@"radians/s",
                       @"y rotation":@"radians/s",
                       @"z rotation":@"radians/s"
                     };

and then add the device to the thing,

 thing.device = device;

you can then dispatch a sensor report to the steward using the dispatchWithInformation: method,

 CMDeviceMotion *motionData = self.motionManager.deviceMotion;
 
 CMAttitude *attitude = motionData.attitude;
 CMAcceleration gravity = motionData.gravity;
 CMAcceleration userAcceleration = motionData.userAcceleration;
 CMRotationRate rotate = motionData.rotationRate;
 
[[Thing sharedThing] dispatchWithInformation:@{ @"roll":[NSNumber numberWithDouble:attitude.roll],
                                                @"pitch":[NSNumber numberWithDouble:attitude.pitch],
                                                @"yaw":[NSNumber numberWithDouble:attitude.yaw],
                                                @"x acceleration":[NSNumber numberWithDouble:userAcceleration.x],
                                                @"y acceleration":[NSNumber numberWithDouble:userAcceleration.y],
                                                @"z acceleration":[NSNumber numberWithDouble:userAcceleration.z],
                                                @"x gravity":[NSNumber numberWithDouble:gravity.x],
                                                @"y gravity":[NSNumber numberWithDouble:gravity.y],
                                                @"z gravity":[NSNumber numberWithDouble:gravity.z],
                                                @"x rotation":[NSNumber numberWithDouble:rotate.x],
                                                @"y rotation":[NSNumber numberWithDouble:rotate.y],
                                                @"z rotation":[NSNumber numberWithDouble:rotate.z]
                                               } ];

##Building Clients

This library is synactic sugar over the top of the Socket Rocket web socket library and is intended to simplify common tasks when building clients for the steward under iOS.

###Monitoring the event stream

If you want to monitor the event stream from the steward you should

#import "Client.h"

and then grab a shared instance of the Client class, declare yourself a delgate

Client *client = [Client sharedClient];
client.delegate = self;

and then declare your class as a <ClientDelegate>. Then go ahead and find the steward,

[client findSteward];	

which will start the process of looking for an active steward via mDNS (also known as Bonjour). When the steward is found you will recieve a delegate callback of the form stewardFoundWithAddress: at which point you can start monitoring for events,

- (void)stewardFoundWithAddress:(NSString *)ipAddress {
	Client *client = [Client sharedClient];
    [client startMonitoringEvents];
}

Incoming messages from the steward will trigger the receivedEventMessage callback,

- (void)receivedEventMessage:(NSString *)message {
    NSLog(@"json = %@", message);
}

Messages will be in JSON format. This is a firehose of all messages broadcast by the steward, e.g.

{ ".updates":[{
      "updated":1390766348015,
      "level":"alert",
      "message":"please push pairing button on Hue bridge",
      "whoami":"device/2",
      "name":"Phillips hue (192.168.1.100)",
      "info":{
        "whatami":"/device/gateway/hue/bridge",
        "whoami":"device/2",
        "name":"Phillips hue (192.168.1.100)",
        "status":"reset",
        "info":{}
   }}]
}

would be an alert message to indicate that while the steward can see a Philips Hue hub on the network, it is not yet authorised to connect to it to manage the lights.

If the steward is not found you will recieve a stewardNotFoundWithError: callback,

- (void)stewardNotFoundWithError:(NSError *)error {

}

Once you start monitoring for events you can stop monitoring at any time by calling,

[client stopMonitoringEvents];

###Getting a list of devices

If you want to control a single device rather than a class of devices then you'll need the deviceID of the device you want to control. You can obtain a list of devices known to the steward. To do so you should

#import "Client.h"

and then grab a shared instance of the Client class, declare yourself a delgate

Client *client = [Client sharedClient];
client.delegate = self;

and declare your class as a <ClientDelegate>, and then find the steward,

[client findSteward];	

which will start the process of looking for an active steward via mDNS (also known as Bonjour). When the steward is found you will recieve a callback of the form stewardFoundWithAddress: at which point you can ask the steward for a list of associated devices,

- (void)stewardFoundWithAddress:(NSString *)ipAddress {
	Client *client = [Client sharedClient];
    [client availableDevices];
}

The response from the steward will trigger the receivedDeviceList callback,

    - (void)receivedDeviceList:(NSString *)message {
        NSLog(@"json = %@", message);
    }

the message will be in JSON format.

###Calling 'Perform' on a device or devices

If you want to control a device—ask it to perform an action—you can do so by,

#import "Client.h"

and then grab a shared instance of the Client class, declare yourself a delgate

Client *client = [Client sharedClient];
client.delegate = self;

and declare your class as a <ClientDelegate>, and then find the steward,

[client findSteward];	

which will start the process of looking for an active steward via mDNS (also known as Bonjour). When the steward is found you will recieve a callback of the form stewardFoundWithAddress: at which point you can make a request to the steward.

Here for instance we ask the steward to talk to device/lighting, short hand for "all lightbulbs", and turn them "on" with a brightness of 100% and a colour of white, i.e. RGB values of 255.

- (void)stewardFoundWithAddress:(NSString *)ipAddress {
	Client *client = [Client sharedClient];
    NSString *device = @"device/lighting";
    NSString *request = @"on";
    NSString *parameters = @"{ \\\"brightness\\\": 100, \\\"color\\\": { \\\"model\\\": \\\"rgb\\\", \\\"rgb\\\": { \\\"r\\\": 255, \\\"g\\\": 255, \\\"b\\\": 255 }}}";
    [client performWithDevice:device andRequest:request andParameters:parameters];
}	

if at a future point we want to turn all the lightbulbs back off then we would call,

NSString *device = @"device/lighting";
NSString *request = @"off";
[client performWithDevice:device andRequest:request andParameters:nil];	

The response message from the steward, including any error messages, will be dispatched to the receivedPerformResponse: callback

-(void)receivedPerformResponse:(NSString *)message {
    NSLog(@"json = %@", message);
}

in JSON format.

If you wish to make an authenticated request, then you should instead,

client.authenticate = YES;
client.clientID = clientIdentity;
client.secret = ClientAuthenticationSecret;
[client performWithDevice:device andRequest:request andParameters:nil];	

where the client ID and the authentication secret can be obtained from the steward's own Client Bootstrapping web service. See the next section for more details.

Note: To make an un-authenticated call to the steward you will need to go to your steward settings and turn "Security Services" to the "No" setting. This step turns secure connections on your local LAN off for clients and authentication for read/write is no longer required on the LAN.

##Bootstrapping Authentication

If you want to provide authentication capabilities to your Thing System client the easiest way to do this is to create a client ID and the associated authentication secret using the steward's own Client Bootstrapping web service.

steward console

Here you can generate a Client ID and the authentication secret you can use to generate a time-based one-time password (TOTP) you will need to authenticate to the steward. The easiest way to pass this secret to your application—and the Client library which can take it and generate the needed TOTP—is via a QR code.

We provide a simple ScanController class which you can present modally inside your application and uses the ZXingObjC library to scan the QR code generated by the steward bootstrap service, and will return the authentication secret via a delegate callback.

You should

#import "ScanController.h"

and declare your class as a <ScanControllerDelegate>, and then present the view controller,

ScanController *scanner = [[ScanController alloc] initWithNibName:@"ScanController" bundle:nil];
scanner.delegate = self;
[self presentViewController:scanner animated:YES completion:NULL];

This will present a (back) camera view. The user simply has to point the phone at the QR code—possibly tapping the screen to focus the camera depening on lighting and distance—and the controller will detect the QR code and return the OTP authentication URL via the

- (void)closedWithURL:(NSURL *)url {
    
}

delegate callback. You can then pass the authentication URL back to the main Client class by,

Client *client = [Client sharedClient];
client.authURL = url;

This will populate both the clientID and secret properties in the client allowing you to make an authenticated call directly afterwards,

client.authenticate = YES;
[client performWithDevice:device andRequest:request andParameters:nil];	

If the user hits the cancel button in the view controller without a QR code being scanned then you will recieve a

- (void)closedWithoutSecret {

}

delegate callback.

###Installation

We've deliberately left the ScanController out of the main Client library bundle to minimise the size of library for other use cases. If you want to make use of it in your project just drag-and-drop all the files in the Bootstrap/ directory into your project. This includes theScanController code as well as a copy of the ZXingObjC library itself.

You may want to grab the latest version of the ZXingObjC library directly their GitHub project, although it currently needs a small fix to work correctly.

In either case you will need to add the following frameworks to your project

  • AVFoundation.framework
  • CoreGraphics.framework
  • CoreMedia.framework
  • CoreVideo.framework
  • ImageIO.framework
  • QuartzCore.framework

if they are not already present.

##Example Code

The library ships with example code illustrating use of both the Thing and Client portions of the library.

##License

This library is released under the MIT license.

Copyright (c) 2014 The Thing System, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

###Socket Rocket

This library makes use of the Socket Rocket library from Square which is released under the Apache License 2.0.

Copyright (c) 2012 Square Inc.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

###Cocoa Async Socket

This library makes use of the Cocoa Async Socket library, an asynchronous socket networking library for OS X and iOS.

These classes have been placed into the public domain by their author, Robbie Hanson of Deusty LLC. They are updated and maintained by Deusty LLC and the Apple development community.

###ZXingObjC

This library makes use of the ZXingObjC port from LevelUp of the ZXing ("Zebra Crossing") library which is released under the Apache License 2.0.

Copyright (c) 2013 LevelUp.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

###Google Toolbox for Mac

This library makes use of code from the Google Toolbox for Mac and the Google Authenticator example application. Both of these projects have been released under the Apache License 2.0.

Copyright (c) 2008 Google, Inc.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Analytics