Adding a simple limit switch

I have recently started my 1st Cayenne project using a 8266. With a little help from my friends(thank you again vapor83 ), I have it up and running. My next step is to add a simple limit switch that is normally closed to monitor if my basement is flooding. I have seen many projects that monitor this with an analog device, I am shooting for digital. My 1st question is do I add this sensor from the web page, through code, or both? I would like to get ride of the simulated sensors that are in the code by default, can I/ should i just delete them from the code? I have seen a similar post about adding a button but I could not figure out to it in play. I also noticed the point that the switch will not trigger an event upon change of state, it must wait till the next 10 second update. Not an issue here but I would like to know more for if/when I do something more time sensitive. I work with PLC’s and use rising edge triggers for this, just not sure how to use it here.

Below is the current code I am using

// This example shows how to connect to Cayenne using an ESP8266 and send/receive sample data.
// Make sure you install the ESP8266 Board Package via the Arduino IDE Board Manager and select the correct ESP8266 board before compiling.

#define CAYENNE_DEBUG
#define CAYENNE_PRINT Serial
#include <CayenneMQTTESP8266.h>

// WiFi network info.
char ssid = “";
char wifiPassword[] = "t
n”;

// Cayenne authentication info. This should be obtained from the Cayenne Dashboard.
char username = “";
char password[] = "
***”;
char clientID = “0*************5”;

unsigned long lastMillis = 0;

void setup() {
Serial.begin(9600);
Cayenne.begin(username, password, clientID, ssid, wifiPassword);
}

void loop() {
Cayenne.loop();

//Publish data every 10 seconds (10000 milliseconds). Change this value to publish at a different interval.
if (millis() - lastMillis > 10000) {
	lastMillis = millis();
	//Write data to Cayenne here. This example just sends the current uptime in milliseconds.
	Cayenne.virtualWrite(0, lastMillis);
	//Some examples of other functions you can use to send data.
	Cayenne.celsiusWrite(1, 22.0);
	Cayenne.luxWrite(2, 700);
	Cayenne.virtualWrite(3, 50, TYPE_PROXIMITY, UNIT_CENTIMETER);
}

}

//Default function for processing actuator commands from the Cayenne Dashboard.
//You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.
CAYENNE_IN_DEFAULT()
{
CAYENNE_LOG(“CAYENNE_IN_DEFAULT(%u) - %s, %s”, request.channel, getValue.getId(), getValue.asString());
//Process message here. If there is an error set an error message using getValue.setError(), e.g getValue.setError(“Error message”);
}

@scamilleri1228 use this code. connect your digital sensor switch to your 8266.

//#define CAYENNE_DEBUG
#define CAYENNE_PRINT Serial
#include <CayenneMQTTESP8266.h>
int inputPin = 2;
int x;
// WiFi network info.
char ssid[] = "ssid";
char wifiPassword[] = "wifiPassword";

// Cayenne authentication info. This should be obtained from the Cayenne Dashboard.
char username[] = "MQTT_USERNAME";
char password[] = "MQTT_PASSWORD";
char clientID[] = "CLIENT_ID";

unsigned long lastMillis = 0;

void setup() {
  Serial.begin(9600);
  Cayenne.begin(username, password, clientID, ssid, wifiPassword);
}

void loop() {
  Cayenne.loop();
  x = digitalRead(inputPin);
  //Publish data every 10 seconds (10000 milliseconds). Change this value to publish at a different interval.
  if (millis() - lastMillis > 10000) {
    lastMillis = millis();
    Cayenne.virtualWrite(1, x, "digital_sensor", "d");

    //Write data to Cayenne here. This example just sends the current uptime in milliseconds.
    //Cayenne.virtualWrite(0, lastMillis);

    //Some examples of other functions you can use to send data.
    //Cayenne.celsiusWrite(1, 22.0);
    //Cayenne.luxWrite(2, 700);
    //Cayenne.virtualWrite(3, 50, TYPE_PROXIMITY, UNIT_CENTIMETER);
  }
}

//Default function for processing actuator commands from the Cayenne Dashboard.
//You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.
CAYENNE_IN_DEFAULT()
{
  CAYENNE_LOG("CAYENNE_IN_DEFAULT(%u) - %s, %s", request.channel, getValue.getId(), getValue.asString());
  //Process message here. If there is an error set an error message using getValue.setError(), e.g getValue.setError("Error message");
}

As far as the sample data statements, I’d delete them from your code first, then the associated widgets from the dashboard. Only because if you do the dashboard first they might be re-created on the next publish of data on that channel.

if you want to add a Button (or any other actuator, as opposed to a sensor) in MQTT, there is no auto-creation process like there is with the virtualWrite statements. Instead, first create the button on your Cayenne dashboard via Add New > Device Widget > Custom Widgets. Assign it an unused MQTT channel.

Next, on the code side, you’ll need a code block to handle the button press from the dashboard. We have a default one in place that will assume the MQTT channel is equal to the physical pin the actuator is on, that could be used. It’s this block from your code above:

//Default function for processing actuator commands from the Cayenne Dashboard.
//You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.
CAYENNE_IN_DEFAULT()
{
CAYENNE_LOG(“CAYENNE_IN_DEFAULT(%u) - %s, %s”, request.channel, getValue.getId(), getValue.asString());
//Process message here. If there is an error set an error message using getValue.setError(), e.g getValue.setError(“Error message”);
}

If, say, you made a button on MQTT channel 4 – this default block would handle changing the HIGH/LOW state of pin 4 on the device – enough to handle a light switch or relay.

In many cases, your wiring won’t match directly with the MQTT channel, or you want to run more complex code on a button press than simply toggling the pin state. In that case, you can make a custom CAYENNE_IN block just for just that channel, and it will have precedence over the default function. For a contrived example:

CAYENNE_IN(4)
{
Serial.println("Button on MQTT channel 4 was pressed.");
}

Would print the above message when the Cayenne button associated with MQTT channel 4 was pressed. That code block can contain any arbitrary code.

So now if I want to add a digital output using gpio3 to say a simple led or
a control relay the code would be?

So I had some trouble using the default function as I described above. Perhaps I misunderstood it’s ability.
Either way though, CAYENNE_IN() blocks will allow you to accomplish this. Just to demonstrate that MQTT channel and pin number don’t need to match up, here is an example that works for me to use a Cayenne button widget set to MQTT channel 6 to toggle an LED on GPIO2 on my device:

CAYENNE_IN(6)
{
  pinMode(2, OUTPUT);
  if (getValue.asInt() == 1)  //check the 0/1 value coming from the Cayenne widget
    {
    digitalWrite(2, HIGH);  
    }
  else
    {
    digitalWrite(2, LOW); 
    }
}

Again sorry if this is a silly question but where do I add this in the code?

No worries, we’re here to help. That can sit anywhere outside the loop() and setup() functions. I generally just stick those blocks at the bottom of my code. They’ll be automatically called when an actuator widget on the matching MQTT channel is pressed on the Cayenne dashboard.

Here is the full code for my simple sketch that just connects a device to Cayenne (in my case, an Arduino) and then uses that block to drive an LED:

//#define CAYENNE_DEBUG
#define CAYENNE_PRINT Serial
#include <CayenneMQTTEthernet.h>

// Cayenne authentication info. This should be obtained from the Cayenne Dashboard.
char username[] = "5a*****e";
char password[] = "2*****9";
char clientID[] = "9****7";

unsigned long lastMillis = 0;

void setup() {
	Serial.begin(9600);
	Cayenne.begin(username, password, clientID);
}

void loop() {
	Cayenne.loop();

	//Publish data every 10 seconds (10000 milliseconds). Change this value to publish at a different interval.
	if(millis() - lastMillis > 10000) {
		lastMillis = millis();
		//Write data to Cayenne here. This example just sends the current uptime in milliseconds.
		Cayenne.virtualWrite(0, lastMillis);
		//Some examples of other functions you can use to send data.
		//Cayenne.celsiusWrite(1, 22.0);
		//Cayenne.luxWrite(2, 700);
		//Cayenne.virtualWrite(3, 50, TYPE_PROXIMITY, UNIT_CENTIMETER);
	}
}

//Default function for processing actuator commands from the Cayenne Dashboard.
//You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.
CAYENNE_IN_DEFAULT()
{
	CAYENNE_LOG("CAYENNE_IN_DEFAULT(%u) - %s, %s", request.channel, getValue.getId(), getValue.asString());
	//Process message here. If there is an error set an error message using getValue.setError(), e.g getValue.setError("Error message");
}

CAYENNE_IN(6)
{
  pinMode(2, OUTPUT);
  if (getValue.asInt() == 1)
    {
    digitalWrite(2, HIGH);
    }
  else
    {
    digitalWrite(2, LOW); 
    }
}
1 Like

So here is how it looks now, where i put the code for the input( note i changed the “2” to a 3 since thats the pin I will be using for the input. It loads fine but it does not show up on the cayenne dash board. Does the code look right or do I need to do something else to get the led to show up? Again, I am using an LED for now, I will eventually be controlling a relay instead but I think that shouldn’t matter.
Again thanks for your help with this,

#define CAYENNE_DEBUG
#define CAYENNE_PRINT Serial
#include <CayenneMQTTESP8266.h>
int inputPin = 2;
int x;
// WiFi network info.
char ssid = “xxxxxxxxxxxxe”;
char wifiPassword = “txxxxxxxxxxxx”;

// Cayenne authentication info. This should be obtained from the Cayenne Dashboard.
char username = “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”;
char password = “4xxxxxxxxxxxx”;
char clientID = “cxxxxxxxxxxxx”;

unsigned long lastMillis = 0;

void setup() {
Serial.begin(9600);
Cayenne.begin(username, password, clientID, ssid, wifiPassword);
}

void loop() {
Cayenne.loop();
x = digitalRead(inputPin);
//Publish data every 10 seconds (10000 milliseconds). Change this value to publish at a different interval.
if (millis() - lastMillis > 10000) {
lastMillis = millis();
Cayenne.virtualWrite(1, x, “digital_sensor”, “d”);

//Write data to Cayenne here. This example just sends the current uptime in milliseconds.
//Cayenne.virtualWrite(0, lastMillis);

}
}

//Default function for processing actuator commands from the Cayenne Dashboard.
//You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.
CAYENNE_IN_DEFAULT()
{
CAYENNE_LOG(“CAYENNE_IN_DEFAULT(%u) - %s, %s”, request.channel, getValue.getId(), getValue.asString());
//Process message here. If there is an error set an error message using getValue.setError(), e.g getValue.setError(“Error message”);
}
CAYENNE_IN(6)
{
** pinMode(3, OUTPUT);**
** if (getValue.asInt() == 1)**
** {**
** digitalWrite(3, HIGH);**
** }**
** else**
** {**
** digitalWrite(3, LOW); **
** }**
}.

@scamilleri1228 you need to add a digital actuator on your cayenne dashboard.
go to: add new —> device/widget -->Actuators → generic → digital output → fill in all details with connectivity virtual and pin 6.

So I can add the widget and name it but it will not allow me to select the device.

can you please give more details about this problem.

Rather than using the Digital Output widget from the path @shramik_salgaonkar posted above, you’ll need to use Add New > Custom Widget > Button, and then your MQTT device should show on the list, and you should be able to choose MQTT Channel 6 so that it hits that code block.

We’ll be simplifying the UI here in the next few months as it’s confusing which options are allowed with which connectivities, apologies for the confusion.

1 Like

So if I’m using GPIO3 it should look like this? Then I click step one, then
what? I add this to my existing code, or just take parts? Above is where I
am currently at with my code, I’m just not sure how to tie this in

If you want to use the CAYENNE_IN(6) code block above, you’d want to set that widget to channel 6 in your screenshot.

There are basically two numbers here:

  • The MQTT channel the widget and your code are communicating on
  • The GPIO pin the relay is actually wired to

In the case of the code above, that’s 6 and 3. There is no reason why you can’t use the same number for both though, and I know many people prefer that for code readability (using both MQTT channel 3 and GPIO3, for example). If you wanted to do that, just change CAYENNE_IN(6) to CAYENNE_IN(3).

I feel like I might be the outlier but I actually find it more readable if they are different, as then I don’t get confused between when I’m referencing the MQTT channel (purely a virtual, software construct), and the physical pin.

@scamilleri1228 what you have added 3 is MQTT channel. change it to 6.
then run the above code. fill the unit as digital(0/1).
click add widget.

Done, when I click “Step 1” it produces the code. It says to paste it in my
tool chain/IDE. What does that mean, do I just replace all my existing code
with this new code? If I do will I loose my digital input?

you dont have to click on “Step 1: code”. you have to click on “add widget” to add the widget to the dashboard.

Thanks, I can see the command to turn on channel 6 in the serial monitor
however my next question is what pin should be it be controlling?

when you are done adding the button widget with virtual pin 6 on cayenne dashboard you have to add this code to read the status and do whatever you want to do.

CAYENNE_IN(6)
{
  int currentValue = getValue.asInt();
  if (currentValue == 1)
  {
//do whatever you want when you turn on the button on cayenne dashboard
 }
  else
  {
//do whatever you want when you turn off the button on cayenne dashboard   
  }
}

So does this look right? It seems like the pin with the board label D4
which I believe is also GPIO2 does not seem to be changing

#define CAYENNE_DEBUG
#define CAYENNE_PRINT Serial
#include <CayenneMQTTESP8266.h>
int inputPin = 2;
int x;
// WiFi network info.
char ssid = “XXXXXXXXXXXXXXXXXXXX”;
char wifiPassword = “XXXXXXXXXXXXXXXXXXXXXXXXXX”;

// Cayenne authentication info. This should be obtained from the Cayenne
Dashboard.
char username = “XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX”;
char password = “XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX”;
char clientID = “XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX”;

unsigned long lastMillis = 0;

void setup() {
Serial.begin(9600);
Cayenne.begin(username, password, clientID, ssid, wifiPassword);
}

void loop() {
Cayenne.loop();
x = digitalRead(inputPin);
//Publish data every 10 seconds (10000 milliseconds). Change this value
to publish at a different interval.
if (millis() - lastMillis > 10000) {
lastMillis = millis();
Cayenne.virtualWrite(1, x, “digital_sensor”, “d”);

//Write data to Cayenne here. This example just sends the current

uptime in milliseconds.
//Cayenne.virtualWrite(0, lastMillis);

}
}

//Default function for processing actuator commands from the Cayenne
Dashboard.
//You can also use functions for specific channels, e.g CAYENNE_IN(1) for
channel 1 commands.
CAYENNE_IN(6)
{
int currentValue = getValue.asInt();
if (currentValue == 1)
{
//do whatever you want when you turn on the button on cayenne dashboard
}
else
{
//do whatever you want when you turn off the button on cayenne dashboard
}
}

CAYENNE_IN_DEFAULT()
{
CAYENNE_LOG(“CAYENNE_IN_DEFAULT(%u) - %s, %s”, request.channel,
getValue.getId(), getValue.asString());
//Process message here. If there is an error set an error message using
getValue.setError(), e.g getValue.setError(“Error message”);
}