Making the rest of the Arduino code aware of Outputs turned on by Cayenne

Hello Cayenne Community! This is the first post from a dual-beginner (new to both Arduino and Cayenne) – oh boy.

I have the basics pretty much down. Software is installed. Everything is talking. Cayenne is firing my outputs just fine (very interesting!) and everything I need to have physically wired up is wired and working. All good so far.

BUT I’m confused by one thing: I can’t seem to find any examples showing how to get the rest of the code in my Arduino sketch to be aware when Cayenne turns on (or off) one of the Arduino outputs.

What I’m trying to do is a remote 3-valve control solution for a friend’s ranch. I have my Arduino successfully connected to Cayenne and a set of relays are wired up and firing just great. What I’m trying to do is add some conditions that are pretty simple:

  • Whenever Valve A or Valve B is commanded ON from Cayenne, Valve C must shut OFF.
  • Whenever Valve C is commanded ON from Cayenne, valves A and B must both shut OFF.

And that’s it. [Outputs: Valve A = pin 5; B = pin 6; and C = pin 7]

There does not seem to be any easy way to do it with triggers without them stepping on each other (but I know I’m a huge rookie and that actually may be the easiest way.)

If I could understand how to make the rest of the code in the Arduino sketch detect and respond to the rising trigger (event) from Cayenne to turn on (or turn off) an output, then all would be good. I’m reasonably sure I could write that code, but I just haven’t been able to find an example to follow showing how to detect and act on a change of output sent via Cayenne.

Any help offered to solve this would be greatly appreciated!

Thanks,
i1Patrick

@i1patrick welcome to cayenne community.
which connection are you using MQTT or regular to connect to cayenne?

Regular, I would guess. I followed the basic instructions. My code has these lines:

#define CAYENNE_PRINT Serial
#include <CayenneEthernet.h>

…and within void loop, I have:
Cayenne.run();

Is MQTT a better solution? I will read up on it.

Thanks!

Is this the actual situation or is it Valve A AND Valve B, any of the valves are ON or when both are in ON state.

At this point, all control of the valves (relays, actually, until I wire it up) is coming from the Cayenne App. Any of the three valves can be turned on or off by clicking the icons in the App (all of which is working great), but the App does not appear to have any way to connect those actions with if/then logic.

My logic for Valves A, B, and C is pretty simple:
First logic is: If (Valve A is turned on OR Valve B is turned ON from Cayenne) then turn OFF Valve C.
Second logic is: If (Valve C is turned ON from Cayenne) then turn OFF both Valve A and Valve B.
Note: All three valves can be OFF. It should never be possible for all three valves to be ON.

The issue I have is that I can’t seem to find any examples of code showing how to detect those remote ON/OFF commands coming in from Cayenne. The outputs switch just fine, but I can’t add any if/then logic yet.

I’m looking into Virtual pins as a possibility, but still haven’t seen the path I need to follow to get there.

@i1patrick as you said virtual pins are the correct path.
first make 3 button widget with virtual pins V1 V2 V3
next in your code change variable according to virtual pin state.

 CAYENNE_IN(V1)
{
 int currentValue = getValue.asInt(); 
if (currentValue == 1) 
{
x=1;
}
 else
 { 
x = 0;
 }
}

simillarly add code for virtual pin V2 V3 with variables y and z.
then compare the variables x y and z as you want.

Thank you for your assistance!

Not sure why, but it won’t compile. I’m getting the message “a function-definition is not allowed here before ‘{’ token” and it highlights the curly bracket after the “CAYENNE_IN(V1)”.

Here’s my code:

/*
Cayenne valves
*/

//#define CAYENNE_DEBUG // Uncomment to show debug messages
#define CAYENNE_PRINT Serial // Comment this out to disable prints and save space
#include <CayenneEthernet.h>

int x = 0;
int y = 0;
int z = 0;

// Cayenne authentication token. This should be obtained from the Cayenne Dashboard.
char token = “xxxxxxxxxx”;

void setup()
{
Serial.begin(9600);
Cayenne.begin(token);
}

// VOID LOOP
void loop() {

CAYENNE_IN(V1)
{
int currentValue = getValue.asInt();
if (currentValue == 1)
{
x=1;
Serial.print(“x=”);
Serial.print(x);
Serial.print(" “);
}
else
{
x = 0;
Serial.print(“x=”);
Serial.print(x);
Serial.print(” ");
}
}

CAYENNE_IN(V2)
{
int currentValue = getValue.asInt();
if (currentValue == 1)
{
y=1;
}
else
{
y = 0;
}
}

CAYENNE_IN(V3)
{
int currentValue = getValue.asInt();
if (currentValue == 1)
{
z=1;
}
else
{
z = 0;
}
}
Cayenne.run();
}

try this

/*
Cayenne valves
*/

//#define CAYENNE_DEBUG // Uncomment to show debug messages
#define CAYENNE_PRINT Serial // Comment this out to disable prints and save space
#include <CayenneEthernet.h>

int x = 0;
int y = 0;
int z = 0;

// Cayenne authentication token. This should be obtained from the Cayenne Dashboard.
char token[] = “xxxxxx”;

void setup()
{
Serial.begin(9600);
Cayenne.begin(token);
}

// VOID LOOP
void loop() {
  Cayenne.run();
}
CAYENNE_IN(V1)
{
int currentValue = getValue.asInt();
if (currentValue == 1)
{
x=1;
Serial.print(“x=”);
Serial.print(x);
Serial.print(" “);
}
else
{
x = 0;
Serial.print(“x=”);
Serial.print(x);
Serial.print(” ");
}
}

CAYENNE_IN(V2)
{
int currentValue = getValue.asInt();
if (currentValue == 1)
{
y=1;
}
else
{
y = 0;
}
}

CAYENNE_IN(V3)
{
int currentValue = getValue.asInt();
if (currentValue == 1)
{
z=1;
}
else
{
z = 0;
}
}

Still no luck compiling, but a different error code:
stray ‘\342’ in program

Sorry to be such a rookie, but I don’t know what that means. And, again, thank you for all your guidance.

Here’s the full report from the “Copy error messages” button:

Arduino: 1.8.4 (Windows 10), Board: “Arduino/Genuino Uno”
asw_cayenne_d:14: error: stray ‘\342’ in program
char token = “tnn79lv0i0�;
^
asw_cayenne_d:14: error: stray ‘\200’ in program
asw_cayenne_d:14: error: stray ‘\234’ in program
asw_cayenne_d:14: error: stray ‘\342’ in program
asw_cayenne_d:14: error: stray ‘\200’ in program
asw_cayenne_d:14: error: stray ‘\235’ in program
asw_cayenne_d:32: error: stray ‘\342’ in program
Serial.print(“x=�);
^
asw_cayenne_d:32: error: stray ‘\200’ in program
asw_cayenne_d:32: error: stray ‘\234’ in program
asw_cayenne_d:32: error: stray ‘\342’ in program
asw_cayenne_d:32: error: stray ‘\200’ in program
asw_cayenne_d:32: error: stray ‘\235’ in program

C:\Users\Patrick\Documents\Arduino\asw_cayenne_d\asw_cayenne_d.ino:34:14: warning: missing terminating " character

Serial.print(" “);
^
asw_cayenne_d:34: error: missing terminating " character
Serial.print(" “);
^
asw_cayenne_d:39: error: stray ‘\342’ in program
Serial.print(“x=�);
^
asw_cayenne_d:39: error: stray ‘\200’ in program
asw_cayenne_d:39: error: stray ‘\234’ in program
asw_cayenne_d:39: error: stray ‘\342’ in program
asw_cayenne_d:39: error: stray ‘\200’ in program
asw_cayenne_d:39: error: stray ‘\235’ in program
asw_cayenne_d:41: error: stray ‘\342’ in program
Serial.print(� ");
^
asw_cayenne_d:41: error: stray ‘\200’ in program
asw_cayenne_d:41: error: stray ‘\235’ in program

C:\Users\Patrick\Documents\Arduino\asw_cayenne_d\asw_cayenne_d.ino:41:18: warning: missing terminating " character
Serial.print(� ");
^
asw_cayenne_d:41: error: missing terminating " character
Serial.print(� ");
^
asw_cayenne_d:14: error: ‘tnn79lv0i0’ was not declared in this scope

char token = “tnn79lv0i0�;
^
C:\Users\Patrick\Documents\Arduino\asw_cayenne_d\asw_cayenne_d.ino: In function ‘void BlynkWidgetWrite1(BlynkReq&, const BlynkParam&)’:
asw_cayenne_d:32: error: expected primary-expression before ‘)’ token
Serial.print(“x=�);
^
asw_cayenne_d:35: error: expected primary-expression before ‘}’ token
}
^
asw_cayenne_d:39: error: expected primary-expression before ‘)’ token
Serial.print(“x=�);
^
asw_cayenne_d:42: error: expected primary-expression before ‘}’ token
}
^
exit status 1
stray ‘\342’ in program

This report would have more information with
“Show verbose output during compilation”
option enabled in File → Preferences.

OK, I believe I fixed the compile issue. Evidently the error had something to do with copying/pasting from a webpage so that Unicode ASCII text characters invaded the code.

I’ll keep working with it. Thanks!

give this a try. change " " in your code

#define CAYENNE_PRINT Serial // Comment this out to disable prints and save space
#include <CayenneEthernet.h>

int x = 0;
int y = 0;
int z = 0;

// Cayenne authentication token. This should be obtained from the Cayenne Dashboard.
char token[] = "tnn79lv0i0";

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
Cayenne.begin(token);
}

void loop() {
  // put your main code here, to run repeatedly:
  Cayenne.run();
}
CAYENNE_IN(V1)
{
int currentValue = getValue.asInt();
if (currentValue == 1)
{
x=1;
Serial.print("x=");
Serial.print(x);
Serial.print(" ");
}
else
{
x = 0;
Serial.print("x=");
Serial.print(x);
Serial.print(" ");
}
}

CAYENNE_IN(V2)
{
int currentValue = getValue.asInt();
if (currentValue == 1)
{
y=1;
}
else
{
y = 0;
}
}

CAYENNE_IN(V3)
{
int currentValue = getValue.asInt();
if (currentValue == 1)
{
z=1;
}
else
{
z = 0;
}
}

Well, progress has been made, but I’m still stuck.

In general, I can now use the V1, V2, and V3 buttons in Cayenne. I created new variables that change state predictably when the Vn virtual pins change and the serial text prints to the monitor just fine so I can verify it works.

However, I can’t seem to find a way to code it so I can use my Vn variables to:
a.) fire my valve control outputs (relays, really).
b.) turn off any of the virtual pins. [if one of the others turns on (can’t have all three running)] and have that change reflect back on the Vn button in Cayenne.

Here’s my code currently. I commented out some failed attempts:

/*
Cayenne valves
*/

//#define CAYENNE_DEBUG // Uncomment to show debug messages
#define CAYENNE_PRINT Serial // Comment this out to disable prints and save space
#include <CayenneEthernet.h>

int IRR = 0;
int RO = 0;
int LAKE = 0;
int i=0;
int IRR_LED1=2;
int RO_LED2=3;
int LAKE_LED3=4;
int IRR_RELAY1=6;
int RO_RELAY2=7;
int LAKE_RELAY3=8;

// Cayenne authentication token. This should be obtained from the Cayenne Dashboard.
char token = “xxxxxxxxxx”;

void setup()
{
Serial.begin(9600);
Cayenne.begin(token);

pinMode(IRR_LED1, OUTPUT);
pinMode(RO_LED2, OUTPUT);
pinMode(LAKE_LED3, OUTPUT);
pinMode(IRR_RELAY1, OUTPUT);
pinMode(RO_RELAY2, OUTPUT);
pinMode(LAKE_RELAY3, OUTPUT);

}

// VOID LOOP
void loop() {

Cayenne.run();

/*if(IRR==1){
digitalWrite(IRR_LED1,HIGH)}
else
{digitalWrite(IRR_LED1,LOW)}
if(RO==1){
digitalWrite(RO_LED2,HIGH)}
else
{digitalWrite(RO_LED2,LOW)}
if(LAKE==1){
digitalWrite(LAKE_LED3,HIGH)}
else
{digitalWrite(LAKE_LED3,LOW)}

*/

}

CAYENNE_IN(V1)
{
int currentValue = getValue.asInt();
if (currentValue == 1)
{
IRR=1;
LAKE = 0;
//
Serial.print(“IRR=ON, LAKE=OFF”);
Serial.print(" “);
}
else
{
IRR = 0;
Serial.print(“IRR=”);
Serial.print(IRR);
Serial.print(” ");
}
}

CAYENNE_IN(V2)
{
int currentValue = getValue.asInt();
if (currentValue == 1)
{
RO=1;
LAKE = 0;
//CAYENNE_OUT(V3){Cayenne.virtualWrite(V3, 0);}
Serial.print(“RO=ON, LAKE=OFF”);
Serial.print(" “);
}
else
{
RO = 0;
Serial.print(“RO=”);
Serial.print(RO);
Serial.print(” ");
}
}

CAYENNE_IN(V3)
{
int currentValue = getValue.asInt();
if (currentValue == 1){
LAKE=1;
IRR = 0;
RO = 0;
Serial.print(“LAKE=ON, IRR=OFF, RO=OFF”);
Serial.print(" “);
}
else
{
LAKE = 0;
Serial.print(“LAKE=”);
Serial.print(LAKE);
Serial.print(” ");
}
}

Follow up question: is it generally recommended that nothing other than Cayenne.run(); should be in the Void Loop??

I’ve found that nearly anything else I put there (while loop, if/then, etc) has a chance to cause me to lose the Cayenne communications.

You got most of the answers in previous posts regarding valves.
Its ok to put other code in loop as long as you give it a proper delays 30-50ms to avoid resets by watchdog.
Beside working on your code, device also does other network related processes in the background so you need to give him some “time off” for that tasks.

Give this a try, replace the values in the cayenne.virtualwrite section:

/*
Cayenne valves
*/

//#define CAYENNE_DEBUG // Uncomment to show debug messages
#define CAYENNE_PRINT Serial // Comment this out to disable prints and save space
#include <CayenneEthernet.h>

int IRR = 0;
int RO = 0;
int LAKE = 0;
int i=0;
int IRR_LED1=2;
int RO_LED2=3;
int LAKE_LED3=4;
int IRR_RELAY1=6;
int RO_RELAY2=7;
int LAKE_RELAY3=8;

// Cayenne authentication token. This should be obtained from the Cayenne Dashboard.
char token[] = "xxxxxxxxxx";

void setup(){
	Serial.begin(9600);
	Cayenne.begin(token);

	pinMode(IRR_LED1, OUTPUT);
	pinMode(RO_LED2, OUTPUT);
	pinMode(LAKE_LED3, OUTPUT);
	pinMode(IRR_RELAY1, OUTPUT);
	pinMode(RO_RELAY2, OUTPUT);
	pinMode(LAKE_RELAY3, OUTPUT);

}

// VOID LOOP
void loop() {

	Cayenne.run();

	/*if(IRR==1){
		digitalWrite(IRR_LED1,HIGH)
	}
	else{
		digitalWrite(IRR_LED1,LOW)
	}
	if(RO==1){
		digitalWrite(RO_LED2,HIGH)
	}
	else{
		digitalWrite(RO_LED2,LOW)
	}
	if(LAKE==1){
		digitalWrite(LAKE_LED3,HIGH)
	}
	else{
		digitalWrite(LAKE_LED3,LOW)
	}

*/

}

CAYENNE_IN(V1){
	int currentValue = getValue.asInt();
	if (currentValue == 1){
		IRR=1;
		LAKE = 0;
		//
		Cayenne.virtualWrite(virtualpin, value) //replace virtualpin (ex V1) and value (1 or 0)
		Cayenne.virtualWrite(virtualpin, value) //replace virtualpin (ex V1) and value (1 or 0)
		Serial.print("IRR=ON, LAKE=OFF");
		Serial.print(" ");
	}
	else{
		IRR = 0;
		Serial.print("IRR=");
		Serial.print(IRR);
		Serial.print(" ");
	}
}

CAYENNE_IN(V2){
	int currentValue = getValue.asInt();
	if (currentValue == 1){
		RO=1;
		LAKE = 0;
		//CAYENNE_OUT(V3){Cayenne.virtualWrite(V3, 0);}
		Cayenne.virtualWrite(virtualpin, value) //replace virtualpin (ex V1) and value (1 or 0)
		Cayenne.virtualWrite(virtualpin, value) //replace virtualpin (ex V1) and value (1 or 0)
		Serial.print("RO=ON, LAKE=OFF");
		Serial.print(" ");
	}
	else{
		RO = 0;
		Serial.print("RO=");
		Serial.print(RO);
		Serial.print(" ");
	}
}

CAYENNE_IN(V3){
	int currentValue = getValue.asInt();
	if (currentValue == 1){
		LAKE=1;
		IRR = 0;
		RO = 0;
		Cayenne.virtualWrite(virtualpin, value) //replace virtualpin (ex V1) and value (1 or 0)
		Cayenne.virtualWrite(virtualpin, value) //replace virtualpin (ex V1) and value (1 or 0)
		Cayenne.virtualWrite(virtualpin, value) //replace virtualpin (ex V1) and value (1 or 0)
		Serial.print("LAKE=ON, IRR=OFF, RO=OFF");
		Serial.print(" ");
	}
	else{
		LAKE = 0;
		Serial.print("LAKE=");
		Serial.print(LAKE);
		Serial.print(" ");
	}
}

Looks like the answer is over here Can a Cayenne Button attached to a Virtual Pin be turned ON/OFF using code within the sketch? - #4 by i1patrick