How to trigger a notification only on state change?

OK, so I have a custom device connected to Cayenne through MQTT. It has a digital pin, and I’d like to be notified whenever its state changes. Unfortunately, apparently I can’t set a trigger explicitely to only fire on state changes - it will fire on every update from the device whenever the pin value is what I specified in the trigger.

From what I’ve learnt browsing around here on the forums, the suggested solution is to only send updates from the device when the state actually changes. I have two issues with this approach however.

First, if there are only data points on state changes, then the chart on the dashboard will “interpolate” between these points, showing like it would’ve gradually transitioned from the previous state over the whole time span. Makes it reading quite difficult.

The other problem is that from what I’ve observed, these updates are not always entirely reliable. My device might have connectivity issues, or for any other reason, a specific update might fail. If I only attempt to send updates on explicit state changes, then in case there’s a temporary failure at the time of the change, I’ll never get notified.

A solution might be that I chechk the state update operation for failure - but for some (to me incomprehensible) reason the Cayenne.virtualWrite() method returns void, despite the underlying method it uses does return a status code, which is promptly discarded. So I don’t even have the means to check whether the write succeeded.

So, all in all, how am I supposed to get notified of digital pin state changes? The best option would be if we had a trigger type explicitely for that (I guess this scenario must be quite common).

i simple code like this will trigger a notification only on state change:

int previousState = -1;
int currentState = -1;
unsigned long previousMillis = 0;

void checkSensor()
{
	unsigned long currentMillis = millis();
	// Check sensor data every 250 milliseconds
	if (currentMillis - previousMillis >= 250) {
		// Check the sensor state and send data when it changes.
		currentState = digitalRead(SENSOR_PIN);
		if (currentState != previousState) {
			Cayenne.virtualWrite(VIRTUAL_CHANNEL, currentState);
			previousState = currentState;
		}
        previousMillis = currentMillis;
	}
}

whenever you have an internet issue, the code to read the status of the digital pin will never execute. so the state will never change in the code (it might have changed physically). we are working on creating an offline feature where you can handle the sensor reading code when a disconnect occurs.

what do you mean by this? i can’t understand how checking the update state is the solution.

What do you mean by this? How does the lost wifi signal prevent my arduino code from reading the state of a pin (which is even before it would try to send the result over the network, anyway)?

Maybe you’re referring to that this whole code is supposed to be called from within CAYENNE_OUT_*(), which is skipped altogether when offline?

(Part of) my concern is that if I fail to send the updated state to Cayenne, then of course the trigger won’t fire. If I could at least check for such failure, I could retry sending the state update later. But without that, I have no means to even know if I’m supposed to resend it.

Anyhow, I positively prefer sending updates even when unchanged, both for the chart interpolation reason, and also to make it absolutely clear that we have a verified and unchanged pin state, not just missing data. And then on the cloud side the trigger should only execute when a change is observed in the received data point.

Give it a try. Add #define CAYENNE_DEBUG, open your serial monitor and disconnect your wifi. whenever there is an internet connection issue, the first thing the code does is reconnect and it loops until it is reconnected to the internet.

the above should help you understand that no internet = no sensor reading.

Still not an answer to the issue of sending updates to the cloud even if the pin state is unchanged, but in turn getting my notification triggered only when a change occurs.

what about the code i gave above?

That code only sends an update to the Cayenne cloud when the pin state is changed.

Oh, and also it doesn’t take into consideration the condition when the code DOES get to the point of reading the pin state, and THEN connectivity gets lost in the meantime.

So you want to show data even when the state is not changed? Add another widget with a different channel.

CAYENNE_OUT_DEFAULT()
{
  Cayenne.virtualWrite(VIRTUAL_CHANNEL_2, currentState);
}

Then again, WHY is it so impossible to have a change trigger on the cloud side?

How much time do you think will it take between this condition for it to cause a failure?

Interesting approach to the principle of handling race conditions.

we are working on it.

All in all, you think it’s impossible (or at least extremely unlikely) that a packet gets sent through the network which enables the CAYENNE_OUT() body to execute, but then the next packet, which would do the channel update, fails to get sent through? I guess this is by no means implausible.

Glad to hear that. Any time frame estimate for it?

is execute at an time interval of 15 sec to avoid hitting rate limit and it wont be called when there is no internet connection, So the point here is when there is no internet no other code is executed.

not soon, we have some high priority bugs to be fixed.

@mortee As a workaround for now I would suggest using your code as normal for the graph (widget) you want. To handle triggers, create a second widget on the dashboard that only updates when the state changes and trigger off that widget. It’s not ideal but it will work for now and it will allow you to easily change the trigger over to the other widget when the triggers are fixed then delete the secondary widget.

1 Like

Yeah, thanks, that’s what I actually implemented already, according to the suggestion above. Not ideal indeed, still prone to missing certain state updates when there’s specific network issues, but for now, it does the job.

1 Like