Execute function once a day OR after reset/reboot

I have been looking into the Alarms lib and a few other posts but still struggling with how to handle this conceptually. I want to run @peekay123 getWeather function to trigger my WebHook once a day (I’m only after the forecasted max, min and windspeed for the day) or shortly after a reboot/reset. I am still learning C and microcontrollers in general so please forgive the request for help with something I am sure is basic.
Then after that I have to try and figure out how to parse out the hook response since I am after different data than peekay123… If anyone is willing to help here is my webhook.json.

{
"event": "weather_hook",
"url": "http://api.openweathermap.org/data/2.5/forecast/daily",
"requestType": "POST",
"headers": null,
"query": {
	"q": "Allen,TX",
	"mode": "json",
	"units": "imperial",
	"cnt": 7
	},
"responseTemplate": "{{#list}}{{temp.max}}{{temp.min}}{{speed}}{{/list}}",
"json": null,
"auth": null,
"mydevices": true
}
1 Like

@LukeUSMC, why just once a day! I run mine on bootup and every hour since the forecast changes regularly! As for the webhook, I’ll post something for you later :smile:

1 Like

Hourly would be cool actually, just don’t want a flood of API calls out there. 24 a day is just fine by me. Good point and Thank YOU!

And you might want to verify my responseTemplate edits…I don’t know how to test what that would spit back.

1 Like

well there is a tool for that!!!

The Particle Dashboard!

1: build your webhook (you did that but this is my example:

{
"event": "fl_sun_time",
"url": "http://api.wunderground.com/api/myAPI/astronomy/q/FL/Weston.json",
"requestType": "POST",
"headers": null,
"query": null,
"responseTemplate": "{{#sun_phase}}{{sunrise.hour}}~{{sunrise.minute}}~{{sunset.hour}}~{{sunset.minute}}~{{/sun_phase}}",
"json": null,
"auth": null,
"mydevices": true
}

2: fire it with the CLI tool:

3: observe the response in the Dashboard under "DATA":

This shows sunrise at 6:55 and sunset at 19:54!!

1 Like

Yeah my webhook is bad…came back with some giant number and that’s it.

Notice the tilde in between the fields in my webhook:

{{#sun_phase}}{{sunrise.hour}}~{{sunrise.minute}}~{{sunset.hour}}~{{sunset.minute}}~{{/sun_phase}}

notice the response:

6~55~19~54~

it delimits your response and will allow you to tokenize it in your code sort of like this:

void sunTimeHandler(const char * event, const char * data)
{
  String sunriseReturn = String(data);
  char sunriseBuffer[125] = "";
  sunriseReturn.toCharArray(sunriseBuffer, 125); // example: \"5~37~20~30~\"
  sunrise.Hour = atoi(strtok(sunriseBuffer, "\"~"));
  sunrise.Minute = atoi(strtok(NULL, "~"));
  sunset.Hour = atoi(strtok(NULL, "~"));
  sunset.Minute = atoi(strtok(NULL, "~"));
  char buffer[30] = "";
  sprintf(buffer, "Sunrise: %02d:%02d, Sunset: %02d:%02d", sunrise.Hour, sunrise.Minute, sunset.Hour, sunset.Minute);
  strcpy (message, buffer);
}
3 Likes

@BulldogLowell FWIW, this short thread is one of THE MOST USEFUL that I have found dealing with JSON, String Parsing, webhook, etc. Straight example, with how to test and use it in real code.
Thank you!

2 Likes

@BulldogLowell Your explanation was fantastic, but after 2 hours I am still stuck, so time to ask for help.

I am trying to parse the response from here:
http://api.thingspeak.com/channels/18535/feed/last

Whatever I do, I get an “undefined” or “~~~~” response from the Particle Dashboard. I can create the webhook, and it triggers, but it just don’t wanna work.

What OBVIOUS thing am I missing in this webhook definition???

{
"event": "weather_hook",
"url": "api.thingspeak.com/channels/18535/feed/last",
"requestType": "POST",
"headers": null,
"query": null,
"responseTemplate": "{{test.created_at}}~{{test.entry_id}}~{{test.field1}}~{{test.field2}}~{{test.field3}}",
"json": null,
"auth": null,
"mydevices": true
}

@Awake

hmmm…

https://thingspeak.com/channels/18535/feed/last

returns this JSON object with your data in an array:

{"created_at":"2015-08-20T16:44:13Z","entry_id":4250,"field1":"72.1","field2":"60","field3":"72.1"}

so try to pluck out your elements with a mustache pattern like this:

{{created_at}}~{{entry_id}}~{{field1}}~{{field2}}~{{field3}}~

It worked here producing:

2015-08-20T16:44:13Z~4250~72.1~60~72.1~

but i didn’t test the webhook…

@Awake ,

getting back to this, interesting that your url seems to require a GET instead of a POST to get the response correct!!

This works for me:

{
	"event": "weather_hook",
	"url": "http://api.thingspeak.com/channels/18535/feed/last",
	"requestType": "GET",
	"headers": null,
	"query": null,
	"responseTemplate": "{{created_at}}~{{entry_id}}~{{field1}}~{{field2}}~{{field3}}~",
	"json": null,
	"auth": null,
	"mydevices": true
}

and it returns this:

sweet, yeah?

@BulldogLowell Yeah… I have to RTFM more carefully, think, and actually start to understand what I’m doing.
The examples on the webhooks docs are so limited that for a newbie like me it is like trying to drive a stickshift for the first time.
I’ll keep poking away at it.
Thanks for the help!

1 Like

@Awake,

I found that trymustache.com website after I learned from @peekay123, so I know what you mean!!

If that website link was in the docs, maybe it would be easier…

well maybe @christine will let me take a whack of updating the examples to include an example with more rigor

I couldn’t find an ironic emoticon with a mustache so I’ll give you this instead:

it is very ironical :{

1 Like

I got my webhook to return the data I need! Thank you @peekay123 and @BulldogLowell. Now onto the parsing! I noticed this am that the response contained the previous day so I have to convert from epoch UTC and make sure I pull the current day’s metrics so I can take action based on that. Any suggestions on where to start the parsing and epoch thing would be awesome. I looked at the examples from both of you and it is still a bit beyond me but I will get up to speed soon enough, I am pretty determined!

@LukeUSMC
Thanks to this thread, I got JSON parsing working via Webhooks

I am getting this formatted data:
“2015-08-21T00:29:32Z~4279~76.8~70~76.8~”

This code parses it and serial print it:

// called once on startup
void setup() {
    Serial.begin(115200);

    // Lets listen for the hook response
    Spark.subscribe("hook-response/get_feed", gotFeedData, MY_DEVICES);
}


// called forever really fast
void loop() {

    // Let's request the weather, but no more than once every 60 seconds.
    Serial.println("Requesting feed!");

    // publish the event that will trigger our Webhook
    Spark.publish("get_feed");

    // and wait at least 60 seconds before doing it again
    delay(60000);
}


void gotFeedData(const char *name, const char *data) {
    String str = String(data);
    char strBuffer[125] = "";
    str.toCharArray(strBuffer, 125); // example: \"5~37~20~30~\"
    String created_at = strtok(strBuffer, "\"~");
    int entryID = atoi(strtok(NULL, "~"));
    float field1 = atof(strtok(NULL, "~"));
    float field2 = atof(strtok(NULL, "~"));
    float field3 = atof(strtok(NULL, "~"));
    Serial.println(created_at);
    Serial.println(entryID);
    Serial.println(field1); Serial.println(field2); Serial.println (field3);
}

credit where it is due: @BulldogLowell help me more than I helped myself in this case.

1 Like

@LukeUSMC

Should be not too hard…

Parse the number into an Unsigned Long call it unixTimeStamp:

then compare the day of the month of the timestamp to today’s day of the month:

if(Time.day(unixTimeStamp) == Time.day())  // match today's day of the month to the day of the month of the Unix Timestamp
{
  //do something
}

you just have to verify that your url returns your own local time zone… and that you are adjusting your timezone to your local timezone. OR subtract the timezone offset to UTC (but that varies by one hour if you observe daylight savings!!)

you can use this if you live in North America and you observe Daylight Savings to adjust your internal Time Zone offset:

void setup()
{

}

void loop()
{
  bool daylightSavings = IsDST(Time.day(), Time.month(), Time.weekday());
  Time.zone(daylightSavings? -4 : -5);  // eastern time zone offsets
}

bool IsDST(int dayOfMonth, int month, int dayOfWeek)  // This is for North America!!!
{
  if (month < 3 || month > 11)
  {
    return false;
  }
  if (month > 3 && month < 11)
  {
    return true;
  }
  int previousSunday = dayOfMonth - (dayOfWeek - 1);
  if (month == 3)
  {
    return previousSunday >= 8;
  }
  return previousSunday <= 0;
}

(not perfect on the days that DST changes… fyi)

of course, you can always find a website that provides your offset and make a webhook!!!

1 Like

Thank you so much! Can you show me your webhook response please? I think I get what is going on but the created_at with “”~" means your response starts with a leading \ correct? I know what atoi is what is strtok?

close, the return is like this, literally:

```"2015-08-21T00:44:33Z~4280~76.6~70~76.6~"````

which includes the leading double-quotes

when we TOKENIZE the string with strtok(), we are using the double-quote (") and the tilde (~) to break up the string. The double quote needs to be "escaped" with the reverse-leaning slash (\), so you have an odd looking command like this when you put the tokens between double-quotes:

String created_at = strtok(strBuffer, "\"~");

which tokenizes where it finds either the double quote or the tilde.

cool, right?

This is the full data that I’m getting:

{“data”:"“2015-08-21T00:44:33Z~4280~76.6~70~76.6~”",“ttl”:“60”,“published_at”:“2015-08-21T00:51:57.715Z”,“coreid”:“undefined”,“name”:“hook-response/get_feed/0”}

The leading ‘’ 'is part of the stuff that the webhook adds.

This is the response I am getting now. Switched to weather underground to avoid the whole UTC issue.

Then I am trying to parse it with this code but coming up with all 0’s after it is cast to int currentFcastmax and so on. Could be zeros before I cast to be honest…not sure what to try.

void gotweatherData(const char *name, const char *data) {
    String str = String(data);
    char strBuffer[125] = "";
    str.toCharArray(strBuffer, 125); // example: \"5~37~20~30~\"
    int forecastday1 = atoi(strtok(strBuffer, "\"~"));
    int maxtempday1 = atoi(strtok(NULL, "~"));
    int mintempday1 = atoi(strtok(NULL, "~"));
    int maxwindday1 = atoi(strtok(NULL, "~"));
    int forecastday2 = atoi(strtok(NULL, "~"));
    int maxtempday2 = atoi(strtok(NULL, "~"));
    int mintempday2 = atoi(strtok(NULL, "~"));
    int maxwindday2 = atoi(strtok(NULL, "~"));
    int forecastday3 = atoi(strtok(NULL, "~"));
    int maxtempday3 = atoi(strtok(NULL, "~"));
    int mintempday3 = atoi(strtok(NULL, "~"));
    int maxwindday3 = atoi(strtok(NULL, "~"));
    if (forecastday1 == Time.day()) {
      forecastday1 = currentFcastday;
      maxtempday1 = currentFcastmax;
      mintempday1 = currentFcastmin;
      maxwindday1 = currentFcastwind;
    }
      else
        forecastday2 = currentFcastday;
        maxtempday2 = currentFcastmax;
        mintempday2 = currentFcastmin;
        maxwindday2 = currentFcastwind;
    Serial.print(currentFcastday);
    Serial.println(currentFcastmax); Serial.println(currentFcastmin); Serial.println(currentFcastwind);
    updateweatherhour = Time.hour();
}

great, that works!

I recommend that you set up a very simple sketch, which simply calls the webhook and prints the data you are looking for. Post that with the entire webhook response and it will be easier to debug. You can add Serial.print()s after you parse each number to make sure it matches your response you witnes in the dashboard.

You are getting close, yeah?