Strcmp in subscribe handler not working

I’m kind of pulling my hair out on this. It’s probably a simple problem, but can anyone tell me why this isn’t working? In C# var1 == var2 would return a boolean value and work fine!

void setup() {
    myRelays.begin();
    Particle.subscribe("source", heatSourceHandler);
    Particle.subscribe("BroilerTemperature", broilerTemperatureHandler);
    Serial.begin(9600);
}

void loop() {
}

void heatSourceHandler(const char *event, const char *data){
    
    Particle.publish("The value of data is \"" + String(data) + "\"");
    Particle.publish("strcmp(data,\"outside\") is " + String(strcmp(data,"outside")));
    Particle.publish("strcmp(data,\"inside\") is " + String(strcmp(data,"inside")));
    delay(500);

    if (strcmp(source,"outside") == 0)
    {
        myRelays.on(OutsideWoodBoilerRelay);    //route radiant fluid through outside wood broiler
        myRelays.off(ElectricWaterHeaterRelay);
        Particle.publish("route radiant fluid through outside wood broiler");
    }
    else
    {
        myRelays.on(ElectricWaterHeaterRelay); //default to inline electric heater
        myRelays.off(OutsideWoodBoilerRelay);
        Particle.publish("route radiant fluid through inline electric heater");
    }
}

void broilerTemperatureHandler(const char *event, const char *data){
    //Particle.publish("Received temp - " + String(data));
}

As a test, also log strlen(data). A wild guess would be non-printable characters. We should expect strlen(data) to be 6 if data is “inside”.

It looks like the length is what's expected

Particle.publish("Data", data);
Particle.publish("strlen(data)", String(strlen(data)));
Particle.publish("strcmp(data,\"outside\")", String(strcmp(data,"outside")));
Particle.publish("strcmp(data,\"inside\")", String(strcmp(data,"inside")));

I'm not seeing that the source in this statement has ever been defined:
if (strcmp(source ....

@groker, Particle publish and subscribe share a common buffer for data, so you should copy data before doing those publish statements,

void heatSourceHandler(const char *event, const char *data){
	int len = strlen(data) + 1;
	char copy[len];
	snprintf(copy,len, "%s", data);
	Particle.publish("The value of data is \"" + String(copy) + "\"");
	Particle.publish("strcmp(data,\"outside\") is " + String(strcmp(copy,"outside")));
	Particle.publish("strcmp(data,\"inside\") is " + String(strcmp(copy,"inside")));
	delay(500);

	if (strcmp(copy,"outside") == 0) {
    	Serial.println("outside");
	}else{
		Serial.println("inside");
	}

}

I get correct results when doing it this way.

2 Likes

Ric, you are one awesome dude!

I’ve learned from the best on this forum. You can thank @ScruffR for that piece of wisdom about the publish and subscribe buffers.

1 Like

Sorry about that, I was in the middle of changes and getting fed up. I posted the first post between compiles instead of after. As soon as I compiled it the IDE found that mistake.

@groker, you also need to obey the publishing rate limit of 1 even per second (with a burst of 4 with 4sec cool-down) - otherwise your device will get muted.

Thank you @ScruffR !

1 Like

Since I’m dealing with radiant heat, it doesn’t need to be real time. Thanks for the info.

Is there any plan to change the arrangement whereby Publish and Subscribe share the same buffer? The fix posted above (i.e. copy the event data to a fresh buffer before using it) works fine for preserving the event data. However, it seems not to enable you to use a publish in your event handler IF the message in your event handler is longer than the event data i.e. if it overruns the length of it.

I experimented a bit with event data of a known length and a publish message which is less, the same, or greater in length. In the first two cases, my program continues after handling the event. In the last case, my test program crashed - I think maybe cos the variables area is trashed by the over run?

So, although the answers here explain the problem, the workaround seems not to be good for every use case. The problem is well flagged up and noted in the documentation, so this is not a huge big deal, but I can’t really think of any reason why a shared buffer has any value in this context? Thus, I was wondering if providing separate buffers appears anywhere on the roadmap?

Can you provide a sample implementation?
I wouldn't see why that would be when copying the incoming data correctly.

One reason might be that the 622 byte statically reserved buffer doesn't need to be doubled and hence preserves a rare resource on these devices.

1 Like