Using responseTopic in webhook for custom response to get DST offset

OK, so now that we have this new tool, I wanted to provide an example of how to use a single webhook on multiple devices returning location data. I am using my handy webhook that returns sunrise and sunset times for a city and state in the US:

{
	"event": "sun_time",
	"url": "http://api.wunderground.com/api/getYourOwnApiKey/astronomy/q/{{my-state}}/{{my-city}}.json",
	"requestType": "POST",
	"headers": null,
	"query": null,
	"responseTemplate": "{{#sun_phase}}{{sunrise.hour}}~{{sunrise.minute}}~{{sunset.hour}}~{{sunset.minute}}~{{/sun_phase}}",
	"responseTopic": "{{SPARK_CORE_ID}}_sun_time",
	"json": null,
	"auth": null,
	"coreid": null,
	"deviceid": null,
	"mydevices": true
}

notice the "responseTopic": "{{SPARK_CORE_ID}}_sun_time", which inserts the unique device name into a webhook response name that includes a filter for the webhook to identify “hey, I need to respond to this since I called for it!!!”

here is an example that you can enter your city and state:

struct deviceTime{
  int Hour;
  int Minute;
};

const String city = "Weston";  //unique location for my Photon
const String state = "FL";     //unique location for my Photon

deviceTime sunrise = {6,0};
deviceTime sunset = {18,30};

char message[80] = "No Time Values Recieved";
bool startUpFlag = true;
unsigned long myTimer = 0;
void setup()
{
  String responseTopic = System.deviceID() + "_sun_time";        //<< define your custom responseTopic using ID and unique appendage
  Particle.variable("SunriseTimes", &message, STRING);            //<< let's look at the results in the Cloud Variables
  //Particle.publish("pushover", responseTopic, 60, PRIVATE);      //<< I'm texting the data to my phone for debug
  Particle.subscribe(responseTopic, sunTimeHandler, MY_DEVICES); //<< subscribe to the event
}

void loop()
{
  if((millis() - myTimer > 60 * 1000UL) || startUpFlag)
  {
    startUpFlag = false;
    String publishString = "{\"my-city\": \"" + city + "\", \"my-state\": \"" + state + "\" }";  //<< kind of complicated, but passes locations into string
    Particle.publish("sun_time", publishString, 60, PRIVATE);
    myTimer = millis();
  }
}

void sunTimeHandler(const char * event, const char * data)
{
  String sunriseReturn = String(data);
  char sunriseBuffer[25] = "";
  sunriseReturn.toCharArray(sunriseBuffer, 25);
  sunrise.Hour = atoi(strtok(sunriseBuffer, "\"~"));
  sunrise.Minute = atoi(strtok(NULL, "~"));
  sunset.Hour = atoi(strtok(NULL, "~"));
  sunset.Minute = atoi(strtok(NULL, "~"));
  char buffer[80] = "";
  sprintf(buffer, " Sunrise: %02d:%02d, Sunset: %02d:%02d", sunrise.Hour, sunrise.Minute, sunset.Hour, sunset.Minute);
  String pubString = city + ", " + state + buffer;  // why not customize the message, too?
  //Particle.publish("pushover", pubString, 60, PRIVATE);  // calls another webhook!!!
  strcpy (message, pubString);
}

and the response, note the magic happens on the third line:

and in Particle Dev:

Thanks @Dave for the great new tool!!!

6 Likes

So, i was tinkering with this to have the ability to get the Time.zone() offset from the current time (reported from Weather Underground) and this minor revision to the above webhook:

{
	"event": "sun_time",
	"url": "http://api.wunderground.com/api/getYourOwnApiKey/astronomy/q/{{my-state}}/{{my-city}}.json",
	"requestType": "POST",
	"headers": null,
	"query": null,
	"responseTemplate": "{{#sun_phase}}{{sunrise.hour}}~{{sunrise.minute}}~{{sunset.hour}}~{{sunset.minute}}~{{#moon_phase}}{{current_time.hour}}~{{current_time.minute}}{{/moon_phase}}~{{/sun_phase}}",
	"responseTopic": "{{SPARK_CORE_ID}}_sun_time",
	"json": null,
	"auth": null,
	"coreid": null,
	"deviceid": null,
	"mydevices": true
}

note the new ResponseTemplate:

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

and using this revised program, I can use the local time and compare it to UTC to return Time.zone() offset:

const String city = "Paris";  //City for my Photon
const String state = "France";     // State for my Photon

struct deviceTime
{
  int Hour;
  int Minute;
};

deviceTime sunrise = {6,0};
deviceTime sunset = {18,30};

char message[120] = "No Time Values Recieved";
String localTime = "not yest reported";
bool startUpFlag = true;
unsigned long myTimer = 0;

void setup()
{
  Serial.begin(115200);
  String responseTopic = System.deviceID() + "_sun_time";        //<< define your custom responseTopic using ID and unique appendage
  Particle.variable("SunriseTimes", &message, STRING);           //<< let's look at the results in the Cloud Variables
  Particle.publish("pushover", responseTopic, 60, PRIVATE);      //<< I'm texting the data to my phone for debug
  Particle.subscribe(responseTopic, sunTimeHandler, MY_DEVICES); //<< subscribe to the event
}

void loop()
{
  if((millis() - myTimer > 60 * 1000UL) || startUpFlag)
  {
    startUpFlag = false;
    String publishString = "{\"my-city\": \"" + city + "\", \"my-state\": \"" + state + "\" }";  //<< kind of complicated, but passes locations into string
    Particle.publish("sun_time", publishString, 60, PRIVATE);
    myTimer = millis();
  }
}

void sunTimeHandler(const char * event, const char * data)
{
  deviceTime currentTime;
  String sunriseReturn = String(data);
  char sunriseBuffer[25] = "";
  sunriseReturn.toCharArray(sunriseBuffer, 25);
  sunrise.Hour = atoi(strtok(sunriseBuffer, "\"~"));
  sunrise.Minute = atoi(strtok(NULL, "~"));
  sunset.Hour = atoi(strtok(NULL, "~"));
  sunset.Minute = atoi(strtok(NULL, "~"));
  currentTime.Hour = atoi(strtok(NULL, "~"));
  currentTime.Minute = atoi(strtok(NULL, "~"));
  //Particle.syncTime();
  Time.zone(0);
  Time.zone(utcOffset(Time.hour(), currentTime.Hour));
  Serial.println(Time.timeStr());
  Particle.publish("pushover", Time.timeStr(), 60, PRIVATE);
  char buffer[120] = "";
  sprintf(buffer, " Current Time: %02d:%02d Sunrise: %02d:%02d, Sunset: %02d:%02d", currentTime.Hour, currentTime.Minute, sunrise.Hour, sunrise.Minute, sunset.Hour, sunset.Minute);
  String pubString = city + ", " + state + buffer;  // why not customize the message, too?
  Particle.publish("pushover", pubString, 60, PRIVATE);  // calls another webhook!!!
  strcpy (message, pubString);
}
int utcOffset(int utcHour, int localHour)  // sorry Baker Island, this won't work for you (UTC-12)
{
  if (utcHour == localHour)
  {
    return 0;
  }
  else if (utcHour > localHour)
  {
    if (utcHour - localHour >= 12)
    {
      return 24 - utcHour + localHour;
    }
    else
    {
      return localHour - utcHour;
    }
  }
  else
  {
    if (localHour - utcHour > 12)
    {
      return  localHour - 24 - utcHour;
    }
    else
    {
      return localHour - utcHour;
    }
  }
}

you can see my local time and Paris time:

just another way of getting your DST offset, but with a webhook…

2 Likes

@BulldogLowell, I copied and pasted both versions of code into the IDE (along with the Webhook) and the IDE can't compile (with no errors).

Any suggestions?

Yes, show what exactly the error message says.

BTW, this thread is three years old, so things might have changed since.

It doesn’t give any specific errors, just:

“Error: Could not compile. Please review your code.”

I saw similar (almost exact code) in the SparkDailyTimer.h library example as well and was unable to get that functioning either.

Are you using Web IDE?
If so, does the SHOW RAW button give you some more info?

One possible cause for such a non-descript error could be a Particle.variable() name that's too long. The have to be max 12 characters.
Also since this thread is so old, the syntax used for Particle.variable() is outdated and especially this one is wrong to start with (even in respect of the old syntax).

The ampersand (&) has to go (and while at it also remove , STRING as this is old syntax).