IOS SDK subscribe and display event data

Hi Guys,

Any help would be greatly appreciated!

I'm trying to further this app now. I want to take my 3 separate publishes roll them up into a single event, but I don't understand what I need to do to parse the combined data with 3 variables in it.

Below is my publish routine, and I've been using the three publishes at the top successfully, and my app displays them correctly. I've added a 4th, which is the one I want to use in the future. The data arrives in the IOS device fine, in the Xcode manual it look like this:

Publish routine:

void publishBattSpeedAndTime() {
    Particle.publish("SOC", String(charge), PRIVATE);
    delay(1000);
    Particle.publish("Speed", String(speed), PRIVATE);
    delay(1000);
    Particle.publish("Time", String(elapsed), PRIVATE);
    delay(1000);
    
    Particle.publish("Data", "{ \"A\": \"" + String(charge) + "\"," +
        "\"B\": \"" + String(speed) + "\"," +
        "\"C\": \"" + String(elapsed) + "\" }", 60, PRIVATE); 
}

This is what the data from my new publish statement looks like in the Xcode log:

Got Event Data with data: { "A": "8.089844","B": "12","C": "28" }

Now how do I parse this { "A": "8.089844","B": "12","C": "28" } into three different variables that I can update the labels with?

Here is an Xcode handler from the previous publish statements:

ParticleEventHandler handlerSOC = ^(ParticleEvent *event, NSError *error) {
        if (!error)
        {
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"Got Event %@ with data: %@",event.event,event.data);
                self.charge.text = event.data;
            });
        }
        else
        {
            NSLog(@"Time Error occured: %@",error.localizedDescription);
        }
    };

Thanks!
J

I wouldn't send the data to your own app in that format, nor would I parse it into three variables. There's no reason to send your data as JSON when you could just send it as a comma separated string of the three values, and then convert that string into an array in your app. You would populate your labels directly from the array without needing to create three variables (though you could create those variables from your array if you want). I would also avoid using String, and just create a c-string with snprintf,

 char dataString[50];
 snprintf(dataString, 50, "%f,%d,%d", charge, speed, elapsed);
 Particle.publish("Data", dataString, 60, PRIVATE);

This is assuming that charge is a double, and speed and elapsed are ints. This should give you a string that looks like this,

"8.089844,12,28"

You then just need to use the NSString method, componentsSeparatedByString:, to convert that string into an array of strings. If you want to convert them to their numeric values, you can use the intValue and doubleValue methods of NSString.

2 Likes

Thank you, @Ric,
I’ll start working on that tonight.
The particle side is easy enough, I haven’t worked with NSString much, so that should be interesting.
J

Yay, working! Thx @Ric

This next question is really more Xcode than Particle, but I thought I'd put it out there and see if I could get a quick answer before signing onto some Xcode forums. I've been researching the past day, but can't get to the bottom of it...

So I'm using the code at the bottom to populate the labels. Working well, but I can't figure out how to use label names from an array to make the code simpler to expand.

How can I use an Array like this to call out the name of my user labels? Or use names I'd put in the data sent from the Photon??

NSArray *myLabels = [NSArray arrayWithObjects:@"charge", @"lineSpeed", @"totalTime"];

I tried these and a number of other variations...

self.[myLabels objectAtIndex:0].text = [myData objectAtIndex:0];

self."%@".text = [myData objectAtIndex:i], [myLabels objectAtIndex:i];

Working but clunky code:

ParticleEventHandler handlerData = ^(ParticleEvent *event, NSError *error) {
        if (!error)
        {
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"Got Event %@ with data: %@",event.event,event.data);
                NSString *myString = event.data;
                NSArray *myData = [myString componentsSeparatedByString:@","];
                for (int i = 0; i < [myData count]; i++)
                {
                    NSLog(@"Got data: %@", [myData objectAtIndex:i]);
                }
                self.charge.text = [myData objectAtIndex:0];
                self.lineSpeed.text = [myData objectAtIndex:1];
                self.totalTime.text = [myData objectAtIndex:2];
            });
        }
        else
        {
            NSLog(@"Time Error occured: %@",error.localizedDescription);
        }
    };

Unfortunately, you can't use variable names that way. They are names, not strings. There are several ways around this problem, but whether it's worth doing that or not depends on how many labels you have. With only 3 labels, the way you're doing it now is probably the best. If you had a lot of data you needed to display, I wouldn't use labels at all, I would use a UITableView instead. The other option is to put your labels into a outlet collection, instead of individual outlets. An outlet collection is an array that you could loop through. I don't remember though if the order of that array is defined.

BTW, there's no need to use objectAtIndex the way you are. You can use array subscript syntax instead.

self.charge.text = myData[0];
self.lineSpeed.text = myData[1];
self.totalTime.text = myData[2];

Well, no wonder I can’t figure that out, then!

Thanks, @Ric

J

So I use the code below to run a function that has my photon send data to the app when I press an update button. The reason I’ve coded it this way is simply that it was from an example in the Particle documentation. How can I just specify my particular photon without iterating the info from all my devices? I’ve tried with the id and the name, but can’t make it work.
Thanks,
J

- (IBAction)getData:(id)sender {
    
    // 1
    [[ParticleCloud sharedInstance] getDevices:^(NSArray *ParticleDevices, NSError *error) {
        //NSLog(@"%@",ParticleDevices.description);
        // 2
        if (!error)
        {
            // 3
            for (ParticleDevice *device in ParticleDevices)
            {
                if ([device.name isEqualToString:@"my_Photon_Name"])
                {
                    ParticleDevice *myPhoton = device;
                    NSLog(@"%@",myPhoton);
                    // 4
                    
                    NSURLSessionDataTask *task = [myPhoton callFunction:@"getData"withArguments:@[@"D7",@"1"] completion:^(NSNumber *resultCode, NSError *error) {
                        if (!error)
                        {
                            NSLog(@"Got Data from my_Photon_Name");
                        }
                    }];
                }
            }
        }
    }];
}

Did you see the other example in the docs for getting a single device?

__block SparkDevice *myOtherDevice;
NSString *deviceID = @"53fa73265066544b16208184";
[[SparkCloud sharedInstance] getDevice:deviceID completion:^(SparkDevice *device, NSError *error) {
    if (!error)
        myOtherDevice = device;
}];

You should update that code, replacing all Spark references with Particle.

Got it working, and it sped up a bit. @Ric thanks.

So Is there anything that I should do with deprecations? I have one in this project, it doesn't keep it from building, I'm just not sure if there is a way to get rid of it, and if is helpful to do so.

J

Pods/Particle-SDK/Pod/Classes/SDK/ParticleDevice.m:505:52: 'dataTaskWithRequest:completionHandler:' is deprecated

Pods/Headers/Private/AFNetworking/AFURLSessionManager.h:211:166: 'dataTaskWithRequest:completionHandler:' has been explicitly marked deprecated here

It’s always best to replace depreciated methods if you can. The one you’re seeing is in AFNetworking, which is an outside library that is a dependency of the Particle iOS SDK. I don’t know if that’s current or not. Are you using the latest version of the SDK found here?

@Ric, it looks like I have the latest.

I’ve also just done a cocoapods update, and it did change AFNetworking 3.2.0 to 3.2.1, however it didn’t change the deprecation message when I built the app again.

J

I guess you'll just have to live with it for now then. It most likely won't cause any problems. Stuff like this is why I prefer not to use external dependencies if I can. I usually use my own iOS SDK that I wrote in Swift, that uses Apple's NSURLSession class directly (no AFNetworking) to do all the cloud communication.

It doesn’t seem to be a problem, I was just trying to clean it up as much as I can.
And using your own SDK to solve the problem… I doubt I’ll ever make to that level!
:slight_smile:
J