Hi.
Context: I’m newbie level. With Photon. Triggering events and trying to trigger sending an SMS based on the event detected by Photon. I am in Australia, where our major telco has setup free developer access to being able send free SMSs (limited # per month, no commercial use etc) based on a web API.
Their approach is to have a registered user (with issued keys for User ID) request via API call an OAuth 2.0 Authentication token which expires after 1 hour. Then with that Authorisation token (during the hour) make a subsequent API call (with the token as POST data) to send an SMS.
I have setup a Particle webhook and can successfully request an OAuth 2.0 Authentication token. I was pretty pleased to get that far. It gets returned as data from the remote server as a string that looks like:
My question is how do I get that longtokenstring back to my Photon, so it can Particle.publish it so I can trigger the “Send SMS” webhook to the remote server.
{Before I get a reply telling me to read the reference docs, forums, tutorials…Yes I have looked at all of those…but I cant see through the maze of advice. I need a quick pointer on the approach I should follow}.
If you saw that in the dashboard/console, you’ll also see the respective event name to which your Photon can Particle.subscribe() and in the handler you’ll get the *data parameter which should contain that “longtokenstring” which you could extract with substr(), strtok() or via a JSON parser.
was copied from the Particle Console, under my webhook as the response from the remote server.
With your advice I have a Photon program (pasted below) now that has a Particle.subscribe() statement in the program setup section and a handler function (sits below the loop{} ) and I have in the handler successfully “extracted” the token string by some string handling code. This code works OK and publishes the retrieved token back in an event visible in the Particle console. I have pasted the code below.
What I dont know is how I get the token string back inside the loop{} part of the program so I can send it with another event to the remote server via a separate webhook to send the SMS. I have tried various things but none work so far.
NB: This part of the code is not written/not included below, but is what I need to do next to make the program useful (ie send an SMS via the remote server).
I realise this is probably a very basic C++ variable/program structuring issue, but any help appreciated.
Regards
GM
void setup() {
Serial.begin (9600);
Particle.subscribe("hook-response/GDM", TokenHandler, MY_DEVICES);
}
void loop() {
Particle.publish("GDM");
//GDM is the event related to the webhook that calls the remote server to request an authorisation token
delay(120000);
}
void TokenHandler(const char *name, const char *data) {
String TokenString = String(data);
//Example returned text from Telstra server {"access_token": "Lp4a5ZsZ3JB0CEryxkmcc3Dq07ge", "expires_in": "3599"}
String Token = tryExtractString(TokenString, "\"access_token\": \"","\", \"expires_in");
Particle.publish(Token);
}
// Function from Particle Tutorial (at https://docs.particle.io/tutorials/topics/webhooks/#the-firmware-1)
String tryExtractString(String str, const char* start, const char* end)
{
if (str == NULL) {
return NULL;
}
int idx = str.indexOf(start);
if (idx < 0) {
return NULL;
}
int endIdx = str.indexOf(end);
if (endIdx < 0) {
return NULL;
}
return str.substring(idx + strlen(start), endIdx);
}
You just need to make token a global variable instead of a local one, and test to see if it’s not an empty string in loop.
String token;
void loop() {
if (token.length() > 0) {
//do what you want here with token
}
Particle.publish("GDM");
//GDM is the event related to the webhook that calls the remote server to request an authorisation token
delay(120000);
}
void TokenHandler(const char *name, const char *data) {
String TokenString = String(data);
//Example returned text from Telstra server {"access_token": "Lp4a5ZsZ3JB0CEryxkmcc3Dq07ge", "expires_in": "3599"}
token = tryExtractString(TokenString, "\"access_token\": \"","\", \"expires_in");
}
You declare global variables outside of any function, usually at the top of the file. It should not be inside setup; that makes it local to that function.
Hi @Ric
Just a follow up question:
Is "string".length() an Arduino function, rather than a C++ function?
Are there a mixture of Arduino language elements and C++ elements in our Particle coding?
or is it better to consider it “Arduino” code - that embeds C++ syntax and conventions?
(I appreciate I have veered the original thread in asking this question).
Regards
GM
I’m not sure exactly to answer that question. String is a class, written in C++ I presume, and it is similar (identical?) to the Arduino String class. Particle programs are written in C/C++, and the firmware includes a C/C++ library called Wiring that provides a lot of the functions that are common to Particle and Arduino. Functions like, setup(), loop(), pinMode, digitalWrite, etc. At least, this is my understanding.
OK, thanks.
I couldnt see the function of "stringvariable".length() in any C++ references thats all.
or in the particle language reference.
I did find it in the Arduino language reference.
(So I assume it is something created by the Arduino folks)
As a newcomer (to programming) I keep trying to refer to some bedrock in the documentation…its a challenge sometimes understanding just where to look and what is the authoritative language reference.
Appreciate your help…
I know that it has been a while since anyone posted in this thread - but I came across it and just wanted to point out an error and the quick fix for it.
In @GreyMonkey post from a while ago, where he shared his full code - in the method for tryExtractString(...) you return NULL. When I tried this I came up with an error
converting to 'String' from initializer list would use explicit constructor 'String::String(int, unsigned char)'
The quick fix was just to change the return NULL to return "". Just wanted to put it out there if anyone else was having similar trouble .