NEST API AUTH ERROR - authorization code not found/ios - nest-api

Here is the code using obj-c ..i am getting "authorization code not found" error but unable to resolve it. i tried couple of alternatives
Error:{"error":"oauth2_error","error_description":"authorization code not found"}
Case 1:
NSURL *url = [NSURL URLWithString: [NSString stringWithFormat:#"https://api.home.nest.com/oauth2/access_token?code=%#&client_id=xxx&client_secret=xxx&grant_type=authorization_code,code]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSError *error;
NSURLResponse *response;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
Case 2:
NSString *post = [NSString stringWithFormat:#"client_id=xxx&client_secret=xxx&grant_type=authorization_code&code=%#", code];
NSLog(#"Post -%#",post);
NSData * postData = [post dataUsingEncoding:NSUTF8StringEncoding]; //tried ascii too
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSURL *url = [NSURL URLWithString: [NSString stringWithFormat:#"https://api.home.nest.com/oauth2/access_token"]];
NSLog(#"url-%#",url);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSError *error;
NSURLResponse *response;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
My steps:
1. Used LHOAuth2LoginViewController
2. Opens webview
3. user enters email/pwd to login to Nest
4. "Works with Nest" is prompted
5. User "Accepts"
6. Redirected to localhost
7. Intercepted to get "Authorization code"
8. Use NSUrlConnection to pass Auth code to get Auth Token
9. Getting oauth2_error: "authorization code not found"

Have a look at the sample iOS-NestDK project on Nest's developer website. Specifically, take a look at the NestAuthManager file and feel free to use it in your project.
Cheers,
Raymond

Related

Core Data - One to Many relationship with object(one) and UIImages(many), storing and fetching

I aim to build a app with the object of:
- Request(contains an unique id, customer name, phone, email, a brief summary of request info, a list of images(store in NSMutable Array)
My Core data contains:
Request
Image
For my request object, I have:
#import <Foundation/Foundation.h>
#interface BAPRequest : NSObject
#property (nonatomic, retain) NSString *requestID;
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *email;
#property (nonatomic, retain) NSString *phone;
#property (nonatomic, retain) NSString *detail;
#property (nonatomic, retain) NSMutableArray *images;
#property (nonatomic, retain) NSDate *requestDate;
#property (nonatomic) BOOL isSent;
- (void)fetchImages;
#end
And the .m File:
#import "BAPAppDelegate.h"
#import "BAPRequest.h"
#implementation BAPRequest
#synthesize name, email, phone, detail;
#synthesize images;
#synthesize requestDate;
#synthesize isSent;
#synthesize requestID;
- (id)init{
self = [super init];
if(self != nil){
self.isSent = false;
self.requestID = [[NSProcessInfo processInfo] globallyUniqueString];
self.images = [[NSMutableArray alloc] init];
}
return self;
}
- (void)fetchImages{
//get delegation
BAPAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSError *error;
//init request
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
//load the entity description
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Image"
inManagedObjectContext:context];
//set the request query
[fetchRequest setEntity:entityDescription];
//set predicate to request to ask select specific entity with the matching line num
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(requestId == %#)", self.requestID];
[fetchRequest setPredicate:pred];
//exec the command to find the object(table) from core database
NSArray * imageList = [context executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *imageObject in imageList){
[self.images addObject: [UIImage imageWithData:[imageObject valueForKey:#"content"]]];
}
}
#end
To fetch all the requests, I also do:
- (void)removeRequest:(BAPRequest*)request{
//get delegation
BAPAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSError *error;
//init request
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
//load the entity description
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Request"
inManagedObjectContext:context];
//set the request query
[fetchRequest setEntity:entityDescription];
//set predicate to request to ask select specific entity with the matching line num
NSLog(#"request id is %#", request.requestID);
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(requestId LIKE %#)", request.requestID];
[fetchRequest setPredicate:pred];
//exec the command to find the object(table) from core database
NSArray *objects = [context executeFetchRequest:fetchRequest error:&error];
//if this object doesn't exist in the database, it must be something wrong
if (objects == nil) {
NSLog(#"There was an error !");
NSLog(#"Error Info: %#", error);
}
//if object exist in database, take the first search object, and deletes it
if ([objects count] > 0){
NSManagedObject *theRequest = [objects objectAtIndex:0];
[context deleteObject:theRequest];
}
[context save:&error];
/*
//delete existing images relates to this request first
entityDescription = [NSEntityDescription entityForName:#"Image"
inManagedObjectContext:context];
pred = [NSPredicate predicateWithFormat:#"(self.request == %#)", request];
[fetchRequest setPredicate:pred];
NSArray * imageList = [context executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *removeImageObject in imageList){
[context deleteObject:removeImageObject];
}
*/
}
#pragma mark - Convert Core Data Object to Request Object
#pragma mark - Core Data Methods
- (NSMutableArray *)getRequests{
//get app delegate
BAPAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
//get object context that's created for us
NSManagedObjectContext *context = [appDelegate managedObjectContext];
//define the entities we want load to description
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Request"
inManagedObjectContext:context];
//init request and set search query to the request
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entityDescription];
NSError *error;
//get objects(table) though request
NSArray *objects = [context executeFetchRequest:fetchRequest error:&error];
if (objects == nil){
NSLog(#"There was an error !");
//error handling there
NSLog(#"Error Info: %#", error);
}
NSMutableArray *requests = [[NSMutableArray alloc] init];
for (NSManagedObject *requestObj in objects){
BAPRequest *request = [[BAPRequest alloc] init];
request.requestID = [requestObj valueForKey:#"requestId"];
request.name = [requestObj valueForKey:#"name"];
request.email = [requestObj valueForKey:#"email"];
request.phone = [requestObj valueForKey:#"phone"];
request.detail = [requestObj valueForKey:#"detail"];
request.requestDate = [requestObj valueForKey:#"requestDate"];
request.isSent = [[requestObj valueForKey:#"isSent"] boolValue];
[request fetchImages];
[requests addObject: requestObj];
}
return requests; //return the requests
}
- (void)saveRequest:(BAPRequest *)request{
request.requestDate = [NSDate date];
//get delegation
BAPAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSError *error;
BAPRequest *theRequest = [NSEntityDescription insertNewObjectForEntityForName:#"Request"
inManagedObjectContext:context];
//set the request obejct basics
[theRequest setValue:request.requestID forKey:#"requestId"];
[theRequest setValue:request.name forKey:#"name"];
[theRequest setValue:request.email forKey:#"email"];
[theRequest setValue:request.phone forKey:#"phone"];
[theRequest setValue:request.detail forKey:#"detail"];
[theRequest setValue:request.requestDate forKey:#"requestDate"];
[theRequest setValue:[NSNumber numberWithBool:request.isSent ] forKey:#"isSent"];
//also save its requests
for (UIImage *img in request.images) {
//init image object
UIImage *newImage=[NSEntityDescription insertNewObjectForEntityForName:#"Image" inManagedObjectContext:context];
[newImage setValue:request.requestID forKey:#"requestId"];
[newImage setValue:UIImagePNGRepresentation(img) forKey:#"content"];
}
[context save:&error]; //save the object
}
#end
My Issue is:
I guess it just doesn't fetch the images at all. Even they fetched the images in the getRequests method, when I try to pass the request to somewhere else, it still get lots issues:
boolean not loading properly
images are nil(even it was loaded when fetch)
and the reason is(I can be wrong) that when I store these request objects(BAPRequest*) into a NSArray and pass it to a table view, when I load them from array (e.g [myArray objectAtIndex:0]), they are still NSManagedObject. I tried to give a class name in the core data entity option to make the Request(Core Data) Object Class of BAPRequest, but it keeps saying I have to subclass NSManagedObject, where subclassing NSManagedObject is not possible:
I can't do:
BAPRequest: NSManagedObject
XCode doesn't likes it.
Look at mogenerator. Here's a tutorial on how to use it: http://raptureinvenice.com/getting-started-with-mogenerator/ . It will save you a lot of trouble.

A Core-Data Relashionship not working after stopping the app

I have had one issue with Core Data and Relationship. Since this has kept me without a solution for a while and has at the same time been easy to locate I have made a tiny sample application to reproduce the problem.
Under XCode I created a barebone Window-based application, checking "Use Core Data for storage".
I called this application "CDR" for Core-Data-Relationship.
I then added a subclass of UIViewController called CDR_ViewController; as I usually do.
Here is the relevant code that I added :
First in CDR_ViewController.h :
#import <UIKit/UIKit.h>
#import "AppDelegate_Shared.h"
#interface CDR_ViewController : UIViewController {
UILabel *cdrLabel;
NSManagedObject *currentItem;
}
#property (nonatomic, retain) IBOutlet UILabel *cdrLabel;
-(IBAction) handleButtonClick:(id)sender;
#end
Then in CDR_ViewController.m the viewDidLoad method is as follow :
- (void)viewDidLoad {
[super viewDidLoad];
NSFetchRequest *request;
NSError *error;
AppDelegate_Shared *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
request=[[NSFetchRequest alloc] init];
[request setEntity: [NSEntityDescription entityForName:#"CDR_Entity" inManagedObjectContext:context]];
error=nil;
NSUInteger count = [context countForFetchRequest:request error:&error];
[request release];
if (count!=0) {
request=[[NSFetchRequest alloc] init];
[request setEntity: [NSEntityDescription entityForName:#"CDR_Entity" inManagedObjectContext:context]];
error=nil;
NSArray *objects=[context executeFetchRequest:request error:&error];
NSLog(#"Error:%#",error);
[request release];
currentItem=[objects objectAtIndex:0];
return;
}
NSManagedObject *newItemOne,*newItemTwo,*newItemThree;
request=[[NSFetchRequest alloc] init];
[request setEntity: [NSEntityDescription entityForName:#"CDR_Entity" inManagedObjectContext:context]];
newItemOne=[NSEntityDescription insertNewObjectForEntityForName:#"CDR_Entity" inManagedObjectContext:context];
newItemTwo=[NSEntityDescription insertNewObjectForEntityForName:#"CDR_Entity" inManagedObjectContext:context];
newItemThree=[NSEntityDescription insertNewObjectForEntityForName:#"CDR_Entity" inManagedObjectContext:context];
[newItemOne setValue:[NSNumber numberWithInteger:1] forKey:#"Value"];
[newItemTwo setValue:[NSNumber numberWithInteger:2] forKey:#"Value"];
[newItemThree setValue:[NSNumber numberWithInteger:3] forKey:#"Value"];
[newItemOne setValue:newItemThree forKey:#"Previous"];
[newItemOne setValue:newItemTwo forKey:#"Next"];
[newItemTwo setValue:newItemOne forKey:#"Previous"];
[newItemTwo setValue:newItemThree forKey:#"Next"];
[newItemThree setValue:newItemTwo forKey:#"Previous"];
[newItemThree setValue:newItemOne forKey:#"Next"];
error=nil;
[context save:&error];
[request release];
currentItem=newItemOne;
}
And the viewWillAppear method is as follow :
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
cdrLabel.text=[NSString stringWithFormat:#"%#",[currentItem valueForKey:#"Value"]];
}
Finally the handleButtonClick method is as follow :
-(IBAction) handleButtonClick:(id)sender
{
if (((UIButton*)sender).tag==101) {// Previous item.
currentItem=[currentItem valueForKey:#"Previous"];
} else /*(((UIButton*)sender).tag==102)*/ {// Next item.
currentItem=[currentItem valueForKey:#"Next"];
}
cdrLabel.text=[NSString stringWithFormat:#"%#",[currentItem valueForKey:#"Value"]];
}
The CDR_ViewController.xib contains one Label and two buttons.
This code works fine for start, meaning just after I compile the app and reset the contents of the iPhone simulator.
I can then cycle the contents of the label : 1,2,3,1,2,3,1,2,3 ---etc… and backward with the buttons.
As soon as I terminate the application using Command-Q. When I want to start it again, it crashes on :
currentItem=[currentItem valueForKey:#"Previous"];
or:
currentItem=[currentItem valueForKey:#"Next"];
inside the handleButtonClick method.
And it is the same when I put the app on my iPod touch.
Can anyone see in my code anything that could explain this behavior?
If you terminate an app in the simulator by stopping it, a opposed to clicking the home button in the simulator or otherwise, then the program is sent a SIGKILL message which immediately stop it running. Your application delegate methods (will terminate, will enter background etc) will not be called.
In all likelihood this will have meant that your managed object context has not been saved, so when re-running the app the object graph cannot be restored properly. In your sample app, add another button which saves the context. If you click this button, then terminate your app, does that solve the problem?

NSFetchedResultsController with NSPredicate not updating

I fetch data from a Core Data-base and present them in a UITableView. I use a NSFetchedResultController to fetch the data. I want the user to be able to search in the database, and to do that I use a NSPredicate.
The data is presented in the UITableView and everything works well until I set the NSPredicate to the NSFetchedResultController.
I use this in the ViewDidLoad method:
self.fetchedResultsController = nil;
fetchedResultsController_ = nil;
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1);
}
and when the user has entered a text from the UITextField, that text will go to the new NSPredicate.
This is done when the search starts:
NSPredicate *pred = nil;
pred = [NSPredicate predicateWithFormat:#"(Designation BEGINSWITH '22')"];
[fetchedResultsController_.fetchRequest setPredicate:pred];
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1);
}
[tView reloadData];
Right now I use #"(Designation BEGINSWITH '22')" for testing only.
This is my NSFetchedResultsController:
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController_ != nil) {
return fetchedResultsController_;
}
/*
Set up the fetched results controller.
*/
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Product" inManagedObjectContext:importContext];//self.managedObjectContext
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"Designation" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:importContext sectionNameKeyPath:nil cacheName:#"Root"]; //self.managedObjectContext
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
return fetchedResultsController_;
}
The problem is that the fetched data stays the same, no matter how or if I set a predicate. If I would set a predicate in the viewDidLoad it would work, but then I wouldn't be able to get new results if I'd tried that again. I use an "importContext" for a batch-import of my CoreData.
Any ideas?
Thanks in advance!
UPDATE:
Ok, here is what I found out. I have an importContext where I make a batch-import. And for the fetchController I use self.managedObjectContext. That's why it doesn't work, so I have to make self.managedObjectContext have the same stuff as my importContext somehow...
You're using a cache (#"Root")… Try setting it to nil, this could prevent crashes. You should not cache FetchedResultsControllers meant to be Predicated.
Even better than setting the cache to nil is giving it a unique name. After posting this question
iPhone - Cache name for NSFetchedResultsController
I added a function to generate UUIDs as my cache names.

Printing Core Data

I'm working on a program and I have created a fetch request to grab the data that I need to print. I'm able to log information like this:
2010-10-03 16:57:10.362 lzshow7.2[2537:10b] <NSManagedObject: 0x2ca120> (entity: Song; id: 0x2afcb0 <x-coredata://CF5A85CE-BE0F-4ADC-979A-7F4214A8FB19/Song/p9> ; data: {
cueName = Freedom;
cueNo = 014;
cueNotes = nil;
songToInstrument = "<relationship fault: 0x2b1800 'songToInstrument'>";
})
How do I seperate the properties like cueName, cueNo, cueNotes out to be printed?
Here is the fetch request:
//Managed object context???
NSLog(#"setting Managed object stuff");
NSManagedObjectContext *context=[[[NSDocumentController sharedDocumentController] currentDocument] managedObjectContext];
NSLog(#"Second line of Managed object stuff");
//fetch request:
NSLog(#"Starting to fetch:");
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Song" inManagedObjectContext:context];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"cueNo" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
NSError *error;
NSMutableArray *mutableFetchResults = [[context executeFetchRequest:request error:&error] mutableCopy];
for (id obj in mutableFetchResults)
NSLog(#"%#", obj);
NSLog(#"finished looping");
//Error handling
if (mutableFetchResults == nil) {
// Handle the error.
}
//[self setEventsArray:mutableFetchResults];
[mutableFetchResults release];
[request release];
}
Any help would be greatly appreciated.
Thank you,
Loren
You use basically the opposite of how you stored the values in your managedObject
NSString *name = [song valueForKey:#"cueName"];
NSNumber *number = [song valueForKey:#"cueNo"];
NSString *notes = [song valueForKey:#"cueNotes"];
...
NSLog(#"%# %# %#", name, number, notes);
if you've created a custom Class of your entity you could add this method:
- (NSString *)description {
NSString *name = [song valueForKey:#"cueName"];
NSNumber *number = [song valueForKey:#"cueNo"];
NSString *notes = [song valueForKey:#"cueNotes"];
...
NSString *returnString = [NSString stringWithFormat:#"%# %# %#", name, number, notes];
return returnString;
}
With this method you can just use NSLog(#"%#", object); to get a nice formatted output

CoreData "Error validating url for store"

I'm having a problem in my application, CoreData works as it should in he simulator - but not on the device.
I receive an
2010-09-30 12:45:07.500 CoreDataTutorial_iOS[130:307] Unresolved error Error Domain=NSCocoaErrorDomain Code=513 "The operation couldn’t be completed. (Cocoa error 513.)" UserInfo=0x1412a0 {NSUnderlyingException=Error validating url for store}, {
NSUnderlyingException = "Error validating url for store";
I'm calling for the PersistentStoreCoordinator in this function (which throws the error above):
-(NSPersistentStoreCoordinator*)persistentStoreCoordinator
{
if(persistentStoreCoordinator_ != nil)
return persistentStoreCoordinator_;
NSURL *aStoreURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingFormat:#"corebase.sqlite"]];
NSError *anError = nil;
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if(![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:aStoreURL options:nil error:&anError])
{
NSLog(#"Unresolved error %#, %#", anError, [anError userInfo]);
abort();
}
return persistentStoreCoordinator;
}
I'm setting a break point, on "objc_exception_throw", to see what the aStoreURL is, and it is:
file://localhost/var/mobile/Applications/BE9A2982-BDC3-405D-A201-FB78E9E0790B/Documentscorebase.sqlite
I notice it's not itself adding the final "/" after "/Documents".
When I created the URL this way
NSURL *aStoreURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingFormat:#"/corebase.sqlite"]];
It seems to have worked, or at least got passed that part.
Shouldn't this function be appending that part itself?
-(NSString*) applicationDocumentsDirectory
{
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
}
It works fine in the simulator, what is the right practice?
NSURL *aStoreURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory]
stringByAppendingFormat: #"corebase.sqlite"]];
should be
NSURL *aStoreURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory]
stringByAppendingPathComponent: #"corebase.sqlite"]];
stringByAppending*PathComponent* instead of stringByAppending*Format*.
This nice little bug was brought to you by autocomplete :-)
Why it worked in the simulator? I guess because you are allowed to create files everywhere on the harddisk. So the Simulator created Documentscorebase.sqlite in your Apps Directory. You should check if it's there.
On the iphone you are limited to the Documents directory and are not allowed to create files everywhere.

Resources