Issues with multiple instances of Spark.subscribe( ) for Webhooks

Has anyone experienced difficulty subscribing to multiple webhooks?

Searched the forum to no avail…

Spark.subscribe("hook-response/gmail_count", gotGmailAtomFeed, MY_DEVICES);
//delay(2000); // tried delays here...
Spark.subscribe("hook-response/princeton_weather", gotWeather, MY_DEVICES);

EDIT:

From the documentation:

NOTE: A Core can register up to 4 event handlers. This means you can call Spark.subscribe() a maximum of 4 times; after that it will return false.

I cannot seem to get two to work…

@BulldogLowell, I can’t find any reference to it, but with 31 char is your second filter quite long.
Could you just try to make it a bit shorter?

As said, it’s only a “starting with”-filter, so you will still catch the event you’re looking for.

Just a blind guess - and I might burn my hands with it again :wink:

On the other hand, have you checked if you can subsribe to either event when it’s your only subscription?
Can you also check the return value of your Spark.subscribe() calls whether you do get a true result.

1 Like

I shortened it:

Spark.subscribe("hook-response/nj_weather", gotWeather, MY_DEVICES);

but that didn’t work either.

Either works, but not both. I am going to try to write a small sketch with just the two Spark.subscribe() hooks

1 Like

@ScruffR

I confirmed with this small sketch that only the first instance will work… the first one in setup( )

bool pubToggle = true;
int emailCount = -99;
int outdoorDewpoint = -99;
int windSpeed = -99;
String windDirection;
String weatherCondition;
int outsideHumid = -99;
int outsideTemp = -99;
unsigned long pubTime = 0;

//
void setup()
{
  Serial.begin(9600);
  //Spark.subscribe("hook-response/nj_weather", gotWeather, MY_DEVICES);
  Spark.subscribe("hook-response/gmail_count", gotGmailFeed, MY_DEVICES);
  Spark.subscribe("hook-response/nj_weather", gotWeather, MY_DEVICES);
}
//
void loop()
{
  if (millis() - pubTime > 10000UL)
  {
    Serial.print("publishing...");
    if (pubToggle)
    {
      Spark.publish("gmail_count");
      Serial.println("gmail count");
    }
    else
    {
      Spark.publish("nj_weather");
      Serial.println("weather");
    }
    pubToggle = !pubToggle;
    pubTime = millis();
  }
}
void gotGmailFeed(const char *event, const char *data)
{
  String gMailBuffer = String(data);
  String emailReturn = extractString(gMailBuffer, "<fullcount>", "</fullcount>");
  if (emailReturn != NULL)
  {
    emailCount = emailReturn.toInt(); //
    Serial.println("Email Count Retrieved");
    Serial.println(emailCount);
  }
}
void gotWeather(const char *event, const char *data)
{
  Serial.println("getting Weather");
  String weatherBuffer = String(data);//<temp_f>35.6</temp_f>
  String temperatureReturn = extractString(weatherBuffer, "<temp_f>", "</temp_f>");
  String humidityReturn = extractString(weatherBuffer, "<relative_humidity>", "</relative_humidity>");//<relative_humidity>56%</relative_humidity>
  String dewpointReturn = extractString(weatherBuffer, "<dewpoint_f>", "</dewpoint_f>");
  String windDirectionReturn = extractString(weatherBuffer, "<wind_dir>", "</wind_dir>");
  String windSpeedReturn = extractString(weatherBuffer, "<wind_mph>", "</wind_mph>");
  String todayHighReturn = extractString(weatherBuffer, "<high> <fahrenheit>", "</fahrenheit>");
  //String todayLowReturn = extractString(weatherBuffer, "<wind_mph>", "</wind_mph>");

  String weatherReturn = extractString(weatherBuffer, "<weather>", "</weather>");
  if (temperatureReturn != NULL)
  {
    outsideTemp = temperatureReturn.toInt();
    Serial.println(outsideTemp);
  }
  if (humidityReturn != NULL)
    outsideHumid = humidityReturn.toInt();
  if (weatherReturn != NULL)
    weatherCondition = weatherReturn;
  if (windDirectionReturn != NULL)
    windDirection = windDirectionReturn;
  if (windSpeedReturn != NULL)
    windSpeed = windSpeedReturn.toInt();
  if (dewpointReturn != NULL)
    outdoorDewpoint = dewpointReturn.toInt();
  //
}

String extractString(String myString, const char* start, const char* end)
{
  if (myString == NULL)
  {
    return NULL;
  }
  int idx = myString.indexOf(start);
  if (idx < 0) {
    return NULL;
  }
  int endIdx = myString.indexOf(end);
  if (endIdx < 0) {
    return NULL;
  }
  return myString.substring(idx + strlen(start), endIdx);
}

That’s rather odd.
Maybe it’s time to call on @Dave and @BDub for some assistance, but meanwhile could you try two more things?

  1. Check if the second Spark.subscribe() returns true or false
  2. Try one handler for both, which just looks for "hook-response/" and Serial.println(event). You could also use this handler to parse event to then call your respective functions (as workaround for the time being).

I’d also edit your topic title to attract more attention of Webhook pros
e.g. “Issues with more than one instance of Spark.subscribe( ) for Webhooks”

thanks for the help @ScruffR

yup, returns true.

not sure what you mean there

Since one Spark.subscribe("hook-response/", webhookHandler, MY_DEVICES); would catch both webhooks, you will be able to do this

void webhookHandler(const char *event, const char *data)
{
  Serial.println(event);  // just for debugging
                          // to see how the webhook was actually called
  
  if (strpos(event, "gmail_count") >= 0)
    gotGmailFeed(event, data);
  if (strpos(event, "nj_weather") >= 0)
    gotWeather(event, data);
}
2 Likes

that did it…
MUCH appreciated. We will have to see what’s up here.

(using strstr(), FYI):

bool pubToggle = true;
int emailCount = -99;
int outdoorDewpoint = -99;
int windSpeed = -99;
String windDirection;
String weatherCondition;
int outsideHumid = -99;
int outsideTemp = -99;
unsigned long pubTime = 0;

//
void setup()
{
  Serial.begin(9600);
  delay(6000);
  Spark.subscribe("hook-response/", webhookHandler, MY_DEVICES);
  //Spark.subscribe("hook-response/", gotGmailFeed, MY_DEVICES);
  //Spark.subscribe("hook-response/", gotWeather, MY_DEVICES);

}
//
void loop()
{
  if (millis() - pubTime > 10000UL)
  {
    Serial.print("publishing...");
    if (pubToggle)
    {
      Spark.publish("gmail_count");
      Serial.println("gmail count");
    }
    else
    {
      Spark.publish("nj_weather");
      Serial.println("weather");
    }
    pubToggle = !pubToggle;
    pubTime = millis();
  }
}
void gotGmailFeed(const char *event, const char *data)
{
  String gMailBuffer = String(data);
  String emailReturn = extractString(gMailBuffer, "<fullcount>", "</fullcount>");
  if (emailReturn != NULL)
  {
    emailCount = emailReturn.toInt(); //
    Serial.println("Email Count Retrieved");
    Serial.println(emailCount);
  }
}
void gotWeather(const char *event, const char *data)
{
  Serial.println("getting Weather");
  String weatherBuffer = String(data);
  String temperatureReturn = extractString(weatherBuffer, "<temp_f>", "</temp_f>");
  if (temperatureReturn != NULL)
  {
    outsideTemp = temperatureReturn.toInt();
    Serial.print("outsideTemp = ");
    Serial.println(outsideTemp);
  }
  //
}

String extractString(String myString, const char* start, const char* end)
{
  if (myString == NULL)
  {
    return NULL;
  }
  int idx = myString.indexOf(start);
  if (idx < 0) {
    return NULL;
  }
  int endIdx = myString.indexOf(end);
  if (endIdx < 0) {
    return NULL;
  }
  return myString.substring(idx + strlen(start), endIdx);
}
void webhookHandler(const char *event, const char *data)
{
  Serial.println(event);  // just for debugging
                          // to see how the webhook was actually called

  if (strstr(event, "gmail_count"))
    gotGmailFeed(event, data);
  else if(strstr(event, "nj_weather"))
    gotWeather(event, data);
}

outputs:

publishing…gmail count
hook-response/gmail_count/0
Email Count Retrieved
7
hook-response/gmail_count/1
hook-response/gmail_count/2
hook-response/gmail_count/3
hook-response/gmail_count/4
hook-response/gmail_count/5
hook-response/gmail_count/6
hook-response/gmail_count/7
publishing…weather
hook-response/nj_weather/0
getting Weather
hook-response/nj_weather/1
getting Weather
hook-response/nj_weather/2
getting Weather
hook-response/nj_weather/3
getting Weather
outsideTemp = 37
hook-response/nj_weather/4
getting Weather
hook-response/nj_weather/5
getting Weather
hook-response/nj_weather/6
getting Weather
hook-response/nj_weather/7
getting Weather

2 Likes

Do I interpret this wrong or does only one of the eight retriggers of the webhook actually carry some data payload?

Could you try this

 void webhookHandler(const char *event, const char *data)
{
  Serial.print(event);         // debug full event name
  Serial.print(" (");    
  Serial.print(strlen(data));  // debug payload length 
  Serial.println(")");

  ...
}
1 Like

you can see when there is no email that much fewer chunks of data are sent… I am using the Weather Underground API to retrieve the weather. In the test code, I am only extracting a single value from the XML.

publishing…gmail count
hook-response/gmail_count/0
(361)
Email Count Retrieved
0
publishing…weather
hook-response/nj_weather/0
(560)
getting Weather
hook-response/nj_weather/1
(562)
getting Weather
hook-response/nj_weather/2
(547)
getting Weather
hook-response/nj_weather/3
(556)
getting Weather
outsideTemp = 25
hook-response/nj_weather/4
(569)
getting Weather
hook-response/nj_weather/5
(546)
getting Weather
hook-response/nj_weather/6
(573)
getting Weather
hook-response/nj_weather/7
(73)
getting Weather
publishing…gmail count
hook-response/gmail_count/0
(361)
Email Count Retrieved
0

1 Like

Hmm, am I reading this right? you’re getting bad echo’s / responses of the hook firing?

Thanks,
David

No… I cannot get more than one webhook to return (without a custom handler like @ScruffR advised).

check out the first post…

Hmm, that’s weird, I’ll check things on this end.

Thanks!
David

Just wrote up this demo,

void setup() {
    Serial.begin(115200);
    
    Spark.subscribe("one", oneHandler);
    Spark.subscribe("two", twoHandler);
    Spark.subscribe("three", threeHandler);
    Spark.subscribe("four", fourHandler);
    
    Serial.println("subscribed!  waiting...");
}

void oneHandler(const char *topic, const char *data) {
    Serial.println("1.)" + String(topic) + ": " + String(data));
}
void twoHandler(const char *topic, const char *data) {
    Serial.println("2.)" + String(topic) + ": " + String(data));
}
void threeHandler(const char *topic, const char *data) {
    Serial.println("3.)" + String(topic) + ": " + String(data));
}
void fourHandler(const char *topic, const char *data) {
    Serial.println("4.)" + String(topic) + ": " + String(data));
}

void loop() {

}

With the CLI:

spark publish one 123
spark publish two 234
spark publish three 345
spark publish four 456

Serial output:

1.)one: 123
2.)two: 234
3.)three: 345
4.)four: 456

It’s possible you’re using webhooks too fast? You’re limited to 10 hook triggers per minute per core on your account, so if you have two you’re triggering every 10 seconds, you might be running over the limits?

I hope that helps!

Thanks,
David

1 Like

@Dave

my issue was tied to webhooks created like this:

5.) Hook #55171cbc2df05a607a544e1b is watching for "nj_weather"
and posting to: http://api.wunderground.com/api/MyApiKey/conditions/q/NJ/Princeton.xml
created at 2015-03-28T21:27:24.305Z

trying to work with another webhook like this:

3.) Hook #55006fa9a32e23062da048db is watching for "gmail_count"
and posting to: https://myEmail:MyPassword@mail.google.com/mail/feed/atom/
created at 2015-03-11T16:39:05.758Z

Calling (alternating) once per minute…

1 Like

Hi @BulldogLowell,

I think you’re right that there might be an issue here, digging in to see if I can track it down.

Thanks!
David

1 Like

thanks @Dave I appreciate your looking into it.

1 Like

Hi All,

Not wanted to create a new article so i use this one.

I have two webhooks configured. Plus in my code two times “spark.subscribe” defined in setup() which both call their own function. After some fiddling i detected that only the first defined spark.subscribe works.

How can i subscribe to two webhooks at the same time?!

Regards,
Bart

Have you read through the whole thread. There is your answer already :wink:

@ScruffR Humz, i think i have written over it, time for weekend i think :wink: … i’ll read it again, if I do not succeed i’ll let you know!

Update; Works! webhookHandler FTW!

2 Likes