Created
December 17, 2015 07:32
-
-
Save manchan/106f4b6108c737df15dc to your computer and use it in GitHub Desktop.
PhilipsHueSwift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// AppDelegate.swift | |
// PhilipsHueSwift | |
// | |
// Created by matz on 2015/11/27. | |
// Copyright © 2015年 matz. All rights reserved. | |
// | |
import UIKit | |
@objc(AppDelegate) | |
@UIApplicationMain | |
class AppDelegate: UIResponder, UIApplicationDelegate, UIAlertViewDelegate, | |
PHBridgeSelectionViewControllerDelegate, PHBridgePushLinkViewControllerDelegate{ | |
var window: UIWindow? | |
// The Hue SDK is created as a property | |
var phHueSDK:PHHueSDK? | |
var loadingView:PHLoadingViewController? | |
var bridgeSearch:PHBridgeSearching? | |
var noConnectionAlert:UIAlertView? | |
var noBridgeFoundAlert:UIAlertView? | |
var authenticationFailedAlert:UIAlertView? | |
var pushLinkViewController:PHBridgePushLinkViewController? | |
var bridgeSelectionViewController:PHBridgeSelectionViewController? | |
var controlLightsViewController:ViewController? | |
var navigationController:UINavigationController? | |
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { | |
// Override point for customization after application launch. | |
self.window = UIWindow(frame: UIScreen.mainScreen().bounds) | |
// Create sdk instance | |
self.phHueSDK = PHHueSDK() | |
// next, the startUpSDK call will initialize the SDK and kick off its regular heartbeat timer: | |
self.phHueSDK?.startUpSDK() | |
self.phHueSDK?.enableLogging(true) | |
// Create the main view controller in a navigation controller and make the navigation controller the rootviewcontroller of the app | |
self.navigationController = UIStoryboard(name: "Main", bundle:nil).instantiateViewControllerWithIdentifier("firstNav") as? UINavigationController | |
self.window?.rootViewController = navigationController | |
self.window?.makeKeyAndVisible() | |
let notificationManager:PHNotificationManager = PHNotificationManager.defaultManager() | |
/*************************************************** | |
The SDK will send the following notifications in response to events: | |
- LOCAL_CONNECTION_NOTIFICATION | |
This notification will notify that the bridge heartbeat occurred and the bridge resources cache data has been updated | |
- NO_LOCAL_CONNECTION_NOTIFICATION | |
This notification will notify that there is no connection with the bridge | |
- NO_LOCAL_AUTHENTICATION_NOTIFICATION | |
This notification will notify that there is no authentication against the bridge | |
*****************************************************/ | |
notificationManager.registerObject(self, withSelector: Selector("localConnection"), forNotification: LOCAL_CONNECTION_NOTIFICATION) | |
notificationManager.registerObject(self, withSelector: Selector("noLocalConnection"), forNotification: NO_LOCAL_CONNECTION_NOTIFICATION) | |
notificationManager.registerObject(self, withSelector: Selector("notAuthenticated"), forNotification: NO_LOCAL_AUTHENTICATION_NOTIFICATION) | |
/*************************************************** | |
The local heartbeat is a regular timer event in the SDK. Once enabled the SDK regular collects the current state of resources managed | |
by the bridge into the Bridge Resources Cache | |
*****************************************************/ | |
self.enableLocalHeartbeat() | |
// JINS MEME | |
MEMELib.setAppClientId("********", clientSecret: "********") | |
NSLog("Please set AppClientId / ClientScecret at developer site"); | |
NSLog("More info at https://developers.jins.com/ja/apps/create/"); | |
return true | |
} | |
func applicationWillResignActive(application: UIApplication) { | |
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. | |
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. | |
} | |
func applicationDidEnterBackground(application: UIApplication) { | |
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. | |
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. | |
} | |
func applicationWillEnterForeground(application: UIApplication) { | |
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. | |
// Start heartbeat | |
self.enableLocalHeartbeat() | |
} | |
func applicationDidBecomeActive(application: UIApplication) { | |
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. | |
} | |
func applicationWillTerminate(application: UIApplication) { | |
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. | |
} | |
/** | |
Notification receiver for successful local connection | |
*/ | |
func localConnection(){ | |
self.checkConnectionState() | |
} | |
/** | |
Notification receiver for failed local connection | |
*/ | |
func noLocalConnection(){ | |
self.checkConnectionState() | |
} | |
/** | |
Notification receiver for failed local authentication | |
*/ | |
func notAuthenticated() { | |
/*************************************************** | |
We are not authenticated so we start the authentication process | |
*****************************************************/ | |
self.navigationController?.popToRootViewControllerAnimated(true) | |
// Dismiss modal views when connection is lost | |
if (self.navigationController?.presentedViewController != nil) { | |
self.navigationController?.dismissViewControllerAnimated(true, completion: nil) | |
} | |
// Remove no connection alert | |
if self.noConnectionAlert != nil { | |
self.noConnectionAlert?.dismissWithClickedButtonIndex((self.noConnectionAlert?.cancelButtonIndex)!, animated: true) | |
self.noConnectionAlert = nil | |
} | |
/*************************************************** | |
doAuthentication will start the push linking | |
*****************************************************/ | |
self.performSelector("doAuthentication", withObject: nil, afterDelay: 0.5) | |
} | |
/** | |
Checks if we are currently connected to the bridge locally and if not, it will show an error when the error is not already shown. | |
*/ | |
func checkConnectionState(){ | |
if self.phHueSDK?.localConnected() == false { | |
// Dismiss modal views when connection is lost | |
if (self.navigationController?.presentedViewController != nil) { | |
self.navigationController?.dismissViewControllerAnimated(true, completion: nil) | |
} | |
// No Connection at all, show connection popup | |
if self.noConnectionAlert == nil { | |
self.navigationController?.popToRootViewControllerAnimated(true) | |
// showing popup, so remove this view | |
self.removeLoadingView() | |
self.showNoConnectionDialog() | |
} | |
} | |
else { | |
// One of the connections is made, remove popups and loading views | |
if (self.noConnectionAlert != nil) { | |
self.noConnectionAlert?.dismissWithClickedButtonIndex((self.noConnectionAlert?.cancelButtonIndex)!, animated: true) | |
self.noConnectionAlert = nil | |
} | |
self.removeLoadingView() | |
} | |
} | |
/** | |
Shows the first no connection alert with more connection options | |
*/ | |
func showNoConnectionDialog() { | |
self.noConnectionAlert = UIAlertView(title: "No connection", message: "Connection to bridge is lost", delegate: self, cancelButtonTitle: nil, otherButtonTitles: "Reconnect", "Find new bridge", "Cancel") | |
self.noConnectionAlert?.tag = 1 | |
self.noConnectionAlert?.show() | |
} | |
/** | |
Starts the local heartbeat with a 10 second interval | |
*/ | |
func enableLocalHeartbeat(){ | |
/*************************************************** | |
The heartbeat processing collects data from the bridge | |
so now try to see if we have a bridge already connected | |
*****************************************************/ | |
let cache:PHBridgeResourcesCache = PHBridgeResourcesReader.readBridgeResourcesCache() | |
if (cache != false && cache.bridgeConfiguration != nil && cache.bridgeConfiguration.ipaddress != nil) { | |
self.showLoadingViewWithText("Connecting...") | |
// Enable heartbeat with interval of 10 seconds | |
self.phHueSDK?.enableLocalConnection() | |
} | |
else{ | |
// Automaticaly start searching for bridges | |
self.searchForBridgeLocal() | |
} | |
} | |
/** | |
Stops the local heartbeat | |
*/ | |
func disableLocalHeartbeat() { | |
self.phHueSDK?.disableLocalConnection() | |
} | |
/** | |
Search for bridges using UPnP and portal discovery, shows results to user or gives error when none found. | |
*/ | |
func searchForBridgeLocal(){ | |
// Stop heartbeats | |
self.disableLocalHeartbeat() | |
// Show search screen | |
self.showLoadingViewWithText("Searching...") | |
/*************************************************** | |
A bridge search is started using UPnP to find local bridges | |
*****************************************************/ | |
// Start search | |
self.bridgeSearch = PHBridgeSearching(upnpSearch: true, andPortalSearch: true, andIpAdressSearch: true) | |
self.bridgeSearch?.startSearchWithCompletionHandler({ (bridgesFound: [NSObject: AnyObject]!) -> Void in | |
// Done with search, remove loading view | |
self.removeLoadingView() | |
/*************************************************** | |
The search is complete, check whether we found a bridge | |
*****************************************************/ | |
// Check for results | |
if (bridgesFound.count > 0) { | |
// Results were found, show options to user (from a user point of view, you should select automatically when there is only one bridge found) | |
print("bridgesFound:: \(bridgesFound)") | |
// (UIApplication.sharedApplication().delegate as! AppDelegate).phHueSDK?.setBridgeToUseWithIpAddress("192.168.24.63", macAddress: "00:17:88:11:0d:bf") | |
self.bridgeSelectionViewController = PHBridgeSelectionViewController(nibName: "PHBridgeSelectionViewController", bundle: NSBundle.mainBundle(), bridges: bridgesFound, delegate: self) | |
/*************************************************** | |
Use the list of bridges, present them to the user, so one can be selected. | |
*****************************************************/ | |
let navController:UINavigationController = UINavigationController(rootViewController: self.bridgeSelectionViewController!) | |
navController.modalPresentationStyle = UIModalPresentationStyle.FormSheet | |
self.navigationController?.presentViewController(navController, animated: true, completion: nil) | |
} | |
else{ | |
/*************************************************** | |
No bridge was found was found. Tell the user and offer to retry.. | |
*****************************************************/ | |
// No bridges were found, show this to the user | |
self.noBridgeFoundAlert = UIAlertView(title: "No bridges", message: "No bridge found alert title", delegate: self, cancelButtonTitle: nil, otherButtonTitles: "Retry", "Cancel", "No bridge found alert cancel button") | |
self.noBridgeFoundAlert?.tag = 1 | |
self.noBridgeFoundAlert?.show() | |
} | |
}) | |
} | |
/** | |
Delegate method for PHbridgeSelectionViewController which is invoked when a bridge is selected | |
*/ | |
func bridgeSelectedWithIpAddress(ipAddress: String!, andBridgeId bridgeId: String!) { | |
/*************************************************** | |
Removing the selection view controller takes us to | |
the 'normal' UI view | |
*****************************************************/ | |
// Remove the selection view controller | |
self.bridgeSelectionViewController = nil | |
self.navigationController?.dismissViewControllerAnimated(true, completion: nil) | |
// Show a connecting view while we try to connect to the bridge | |
self.showLoadingViewWithText("Connecting...") | |
// Set SDK to use bridge and our default username (which should be the same across all apps, so pushlinking is only required once) | |
//NSString *username = [PHUtilities whitelistIdentifier]; | |
/*************************************************** | |
Set the ipaddress and bridge id, | |
as the bridge properties that the SDK framework will use | |
*****************************************************/ | |
print("bridgeId です: \(bridgeId)") | |
print("ipAddress です: \(ipAddress)") | |
self.phHueSDK?.setBridgeToUseWithId(bridgeId, ipAddress:ipAddress) | |
// self.phHueSDK?.setBridgeToUseWithIpAddress(bridgeId, macAddress: ipAddress) | |
/*************************************************** | |
Setting the hearbeat running will cause the SDK | |
to regularly update the cache with the status of the | |
bridge resources | |
*****************************************************/ | |
// Start local heartbeat again | |
self.performSelector(Selector("enableLocalHeartbeat"), withObject: nil, afterDelay: 1) | |
} | |
/** | |
Start the local authentication process | |
*/ | |
func doAuthentication(){ | |
// Disable heartbeats | |
self.disableLocalHeartbeat() | |
/*************************************************** | |
To be certain that we own this bridge we must manually | |
push link it. Here we display the view to do this. | |
*****************************************************/ | |
// Create an interface for the pushlinking | |
self.pushLinkViewController = PHBridgePushLinkViewController(nibName: "PHBridgePushLinkViewController", bundle: NSBundle.mainBundle(), hueSDK: (UIApplication.sharedApplication().delegate as! AppDelegate).phHueSDK, delegate: self) | |
self.navigationController?.presentViewController(self.pushLinkViewController!, animated: true, completion: { () -> Void in | |
/*************************************************** | |
Start the push linking process. | |
*****************************************************/ | |
// Start pushlinking when the interface is shown | |
self.pushLinkViewController?.startPushLinking() | |
}) | |
} | |
/** | |
Delegate method for PHBridgePushLinkViewController which is invoked if the pushlinking was successfull | |
*/ | |
func pushlinkSuccess() { | |
/*************************************************** | |
Push linking succeeded we are authenticated against | |
the chosen bridge. | |
*****************************************************/ | |
// Remove pushlink view controller | |
self.navigationController?.dismissViewControllerAnimated(true, completion: nil) | |
self.pushLinkViewController = nil | |
// Start local heartbeat | |
self.performSelector("enableLocalHeartbeat", withObject: self, afterDelay: 1) | |
} | |
/** | |
Delegate method for PHBridgePushLinkViewController which is invoked if the pushlinking was not successfull | |
*/ | |
func pushlinkFailed(error: PHError!) { | |
// Remove pushlink view controller | |
self.navigationController?.dismissViewControllerAnimated(true, completion: nil) | |
self.pushLinkViewController = nil | |
// Check which error occured | |
if (error.code ) == PUSHLINK_NO_CONNECTION as! Int{ | |
// No local connection to bridge | |
self.noLocalConnection() | |
// Start local heartbeat (to see when connection comes back) | |
self.performSelector(Selector("enableLocalHeartbeat"), withObject: nil, afterDelay: 1) | |
} | |
else { | |
// Bridge button not pressed in time | |
self.authenticationFailedAlert = UIAlertView(title: "Authenticationfailed", message: "Make sure you press the button within 30 seconds", delegate: self, cancelButtonTitle: nil, otherButtonTitles: "Retry", "Cancel") | |
self.authenticationFailedAlert?.show() | |
} | |
} | |
func alertView(alertView: UIAlertView, clickedButtonAtIndex buttonIndex: Int) { | |
if alertView == self.noConnectionAlert && alertView.tag == 1 { | |
// this is no conection alert with option to reconnect or more options | |
self.noConnectionAlert = nil | |
if buttonIndex == 0 { | |
// Retry, just wait for the hearbeat to finish | |
self.showLoadingViewWithText("Connecting...") | |
} | |
else if buttonIndex == 1 { | |
// Find new bridge button | |
self.searchForBridgeLocal() | |
} | |
else if buttonIndex == 2 { | |
// Cancel and disable local heartbeat unit started manually again | |
self.disableLocalHeartbeat() | |
} | |
} | |
else if alertView == self.noBridgeFoundAlert && alertView.tag == 1 { | |
// This is the alert which is shown when no bridges are found locally | |
self.noBridgeFoundAlert = nil | |
if buttonIndex == 0 { | |
// Retry | |
self.searchForBridgeLocal() | |
} | |
else if buttonIndex == 1 { | |
// Cancel and disable local hearbeat unit started manually again | |
self.disableLocalHeartbeat() | |
} | |
} | |
else if alertView == self.authenticationFailedAlert { | |
// This is the alert which is shown when local pushlinking authentication has failed | |
self.authenticationFailedAlert = nil | |
if (buttonIndex == 0) { | |
// Retry authentication | |
self.doAuthentication() | |
} else if (buttonIndex == 1) { | |
// Remove connecting loading message | |
self.removeLoadingView() | |
// Cancel authentication and disable local heartbeat unit started manually again | |
self.disableLocalHeartbeat() | |
} | |
} | |
} | |
/** | |
Shows an overlay over the whole screen with a black box with spinner and loading text in the middle | |
@param text The text to display under the spinner | |
*/ | |
func showLoadingViewWithText(text:NSString) { | |
// First Remove | |
self.removeLoadingView() | |
// Then add new | |
self.loadingView = PHLoadingViewController(nibName: "PHLoadingViewController", bundle: NSBundle.mainBundle()) | |
self.loadingView!.view.frame = (self.navigationController?.view.bounds)! | |
self.navigationController?.view.addSubview((self.loadingView?.view)!) | |
self.loadingView?.loadingLabel?.text = text as String | |
} | |
/** | |
Removes the full screen loading overlay. | |
*/ | |
func removeLoadingView() { | |
if self.loadingView != nil { | |
self.loadingView?.view.removeFromSuperview() | |
self.loadingView = nil | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment