Add Remote and LEDs to 2-Channel High-Power Relay Controller Shield

Hi all,

I am new to this whole IoT world, but I purchased a 2-Channel High-Power Relay Controller Shield + 6 GPIO with IoT Interface plus a Photon so I can remotely turn on and off my compressor and dust collector in my wood shop. I have it all working with custom code I wrote for the particle. I control it from IFTT and my Echo calling the custom functions I wrote. This is works great. BUT, I really want to add a Key Fob or remote, because turning OFF the dust collector is difficult, because I am usually far from the Echo, and it gets loud in the shop.

I am coming up a bit clueless on how to setup a remote. What do I need to purchase, and what are the basic steps to get started ?

Also, I want to put the Relay in an enclosure, but would love to add 2 LEDs to the outside that come in with the relays. I assume I would add code to control two of the GPIO pins, but I can’t seem to get that to work. They all seem to always be +5V.

// This #include statement was automatically added by the Particle IDE.
#include <NCD2Relay.h>
NCD2Relay relayController;

int led1 = D0;
int led2 = D7;
int onValue=1;
int offValue=0;

void setup() {
Serial.begin(115200);
relayController.setAddress(0,0,0);

Particle.publish("Controller","Started",60,PUBLIC);

Particle.variable("compressorOn", &offValue, INT);
Particle.variable("dustOn", &offValue, INT);

Particle.function("turnOnComp",turnOnComp);
Particle.function("turnOffComp",turnOffComp);
Particle.function("turnOnDust",turnOnDust);
Particle.function("turnOffDust",turnOffDust);
Particle.function("turnOffAll",turnOffAll);

turnOffComp("off");
turnOffDust("off");

pinMode(D0, OUTPUT);
pinMode(D5, OUTPUT);

}

void loop() {
}

int turnOnComp(String command) {
relayController.turnOnRelay(1);
Particle.publish(“Compressor”,“ON”,60,PUBLIC);
Particle.variable(“compressorOn”, &onValue);
digitalWrite(D0, HIGH);

return 1;

}

int turnOffComp(String command) {
relayController.turnOffRelay(1);
Particle.publish(“Compressor”,“OFF”,0,PUBLIC);
Particle.variable(“compressorOn”, &offValue);
digitalWrite(D0, LOW);
return 0;
}
int turnOnDust(String command) {
Particle.publish(“Dust Collector”,“ON”,60,PUBLIC);
relayController.turnOnRelay(2);
digitalWrite(D5, HIGH);
Particle.variable(“dustOn”, &onValue);
return 1;
}

int turnOffDust(String command) {
Particle.publish(“Dust Collector”,“OFF”,60,PUBLIC);
relayController.turnOffRelay(2);
Particle.variable(“dustOn”, &offValue);
digitalWrite(D5, LOW);
return 0;
}

int turnOffAll(String command) {
turnOffComp(“off”);
turnOffDust(“off”);
return 0;
}
}

Thanks,
Mark

Here is a quick video I did

Hi Mark,

You had me at wood shop. Total nerd bait for me :slight_smile:

Ok. First I’ll address your Key Fob question. This is the hardware you need for that. I assume you just want a one button remote which when you push and release turns the relay/dust collector on and when you push and release the button again the dust collector turns off. You’ll need the following:


Now as for the external LEDs. The problem with using D0 or D1 is that both of those are used for I2C communication with the relay controller, so it’s not possible to use either one of those for your external LEDs. This Key Fob overlay will occupy D2-D7 as well as A0, A1 and the Serial1(labeled Tx and Rx on the Photon). So if you want to use the Photon’s IO lines to drive your external LEDs I would recommend A2 and A3. Just change led1 to A2 and led2 to A3. Alternatively you could use the 6 GPIO lines on the relay controller, that would of course require altering the NCD2Relay library.

I went ahead and updated your code here with a couple corrections and added capability to it to monitor the key fob button and turn the dust collector on and off when you press the button. This code will run even if you don’t have the key fob remote yet. I am controlling lines A2 and A3 for the external LEDs so you should see those go high and low when you turn the compressor and dust collector on and off.
https://go.particle.io/shared_apps/5b1843428b26007c06001598

Be sure to tell your friends we are extra friendly to woodworkers here :wink:

1 Like

Wow! Thank you. That is above and beyond! actually writing the code for me. I am gonna order the stuff today. I think i’ll get a 4 button remote in case I want to do other things in the future (thinking about adding a lift for my attic storage, and could program up/down buttons). btw - https://www.facebook.com/MarksWoodworkingCO/

Hi Mark,

No problem. Always more than happy to help a fellow woodworker. If you need any help modifying the code for your 4 button key fob remote I’ll be more than happy to assist.

Are you trying to learn how to code or do you just sort of want a solution that works? Trying to determine if you’d prefer I just write the code for you or explain how to do it so you can do it yourself and learn.

I am always up for learning more, and love writing code. I am having trouble finding examples of how to do this stuff. I’m sure it is out there, but I can’t find it.

As far as your code, I am having trouble with it. Is there a specific library I need to include? Fob_Alarm seems to include the KeyFob.h, but when I include it, I get compile errors:

lib/NCD2Relay/I2CBZ.cpp:7:0: multiple definition of “I2CBZ::initialize(int)”

I’m assuming the NCD2Relay and Fob_Alarm both call the initialize??

also, with the code you added, you turn on and off A3 and A4. Where on the relay shield would I hook my LEDs ?

btw, this all started because I often forget to turn off my compressor, and then it stays on for days, wasting power. Then my remote switch for my dust collector died 2 days ago, so I decided to use the relay shield, but need a KeyFob. I did order the parts you recommended

Thanks,
Mark

Hi Mark,

I was hoping Particle’s code sharing would pull in custom libraries but it looks like it doesn’t.

Ok so don’t include Fob alarm because it also has an NCD2Relay object in it which will conflict with the NCD2Relay library.

Instead click the Plus tab button at the top of the code window to create a new class. Name it KeyFob. This will create a KeyFob.cpp and a KeyFob.h. It will also add an include to the top of your application code.

In KeyFob.h paste in this code:

#include "spark_wiring.h"
#include "spark_wiring_interrupts.h"
#include "spark_wiring_usbserial.h"
#include "spark_wiring_usartserial.h"

class KeyFob{
public:
	//Constructor
	KeyFob(void);
	void evalFob();

	int recentFobID = 0;
	int recentButton = 0;
	int recentAction = 0;

	static const int button1press = 0;
	static const int button1release = 1;
	static const int button2press = 2;
	static const int button2release = 3;
	static const int button3press = 4;
	static const int button3release = 5;
	static const int button4press = 6;
	static const int button4release = 7;
	static const int button5press = 8;
	static const int button5release = 9;
	static const int button6press = 10;
	static const int button6release = 11;
	static const int button7press = 12;
	static const int button7release = 13;
	static const int button8press = 14;
	static const int button8release = 15;



private:
	int previousStatus = 0;
};

Now in KeyFob.cpp paste in this code:

#include "KeyFob.h"

//KeyFob Buttons
int kfb1 = A0;
int kfb2 = A1;
int kfb3 = D2;
int kfb4 = D3;
int kfb5 = D4;
int kfb6 = D5;
int kfb7 = D6;
int kfb8 = D7;

//RSSI
int rssiPin = A2;
//KeyFob Interrupt function

KeyFob::KeyFob(){
}

void KeyFob::evalFob(){
	recentFobID = Serial1.read();

	int newStatus = 0;

	if(digitalRead(kfb1) == 1)	{
		newStatus = newStatus | 1;
	}else{
		newStatus = newStatus & ~1;
	}
	if(digitalRead(kfb2) == 1)	{
		newStatus = newStatus | 2;
	}else{
		newStatus = newStatus & ~2;
	}
	if(digitalRead(kfb3) == 1)	{
		newStatus = newStatus | 4;
	}else{
		newStatus = newStatus & ~4;
	}
	if(digitalRead(kfb4) == 1)	{
		newStatus = newStatus | 8;
	}else{
		newStatus = newStatus & ~8;
	}
	if(digitalRead(kfb5) == 1)	{
		newStatus = newStatus | 16;
	}else{
		newStatus = newStatus & ~16;
	}
	if(digitalRead(kfb6) == 1)	{
		newStatus = newStatus | 32;
	}else{
		newStatus = newStatus & ~32;
	}
	if(digitalRead(kfb7) == 1)	{
		newStatus = newStatus | 64;
	}else{
		newStatus = newStatus & ~64;
	}
	if(digitalRead(kfb8) == 1)	{
		newStatus = newStatus | 128;
	}else{
		newStatus = newStatus & ~128;
	}

	//off
	if(newStatus < previousStatus){
		int statusChange = previousStatus - newStatus;
		if((statusChange & 1) == 1){
			recentAction = button1release;
		}
		if((statusChange & 2) == 2){
			recentAction = button2release;
		}
		if((statusChange & 4) == 4){
			recentAction = button3release;
		}
		if((statusChange & 8) == 8){
			recentAction = button4release;
		}
		if((statusChange & 16) == 16){
			recentAction = button5release;
		}
		if((statusChange & 32) == 32){
			recentAction = button6release;
		}
		if((statusChange & 64) == 64){
			recentAction = button7release;
		}
		if((statusChange & 128) == 128){
			recentAction = button8release;
		}

	}
	if(previousStatus < newStatus){
		int statusChange = newStatus - previousStatus;
		if((statusChange & 1) == 1){
			recentAction = button1press;
		}
		if((statusChange & 2) == 2){
			recentAction = button2press;
		}
		if((statusChange & 4) == 4){
			recentAction = button3press;
		}
		if((statusChange & 8) == 8){
			recentAction = button4press;
		}
		if((statusChange & 16) == 16){
			recentAction = button5press;
		}
		if((statusChange & 32) == 32){
			recentAction = button6press;
		}
		if((statusChange & 64) == 64){
			recentAction = button7press;
		}
		if((statusChange & 128) == 128){
			recentAction = button8press;
		}
	}
	previousStatus = newStatus;
}

Make sure you remove the include for the FobAlarm both from your code menu on the left, and remote any include statements at the top of your application code.

Let me know if that works.

THANKS! That compiles and flashes. Now I just have to wait for the keyfob in the mail.

my other question, where do I hook up the LED for A3 and A4 on the Relay shield board ?

Hi Mark,

Look on the Photon module and you will see labels next to it’s pins. There you will find A3 and A4 pins. Connect the + leg of your LEDs to those pins. Then connect the ground legs of your LEDs to any of the GND connection pins on the Photon. There are pin sockets all along the length of the Photon module where you can make connections so you do not need to connect directly to the Photon’s pins. Here is a photo of an LED hooked up to A4 and GND:

OHHHHH, I was thinking I was looking at the pins on the Relay shield, NOT on the photon. I assume I can also control the GPIO ports (and they can also be used as inputs to the photon) on the relay board.

Hi Mark,

Yes, you can definitely use the GPIO lines on the relay controller. This will require some modification to the NCD2Relay library however since it sets all those lines to inputs. I just saw that you mentioned earlier wanting to use the IOs on the Photon so I showed you how to do it with the Photon’s IO lines. If you want to use the GPIOs on the relay board let me know and I can help with that as well.

hey Travis,

I am still struggling. The keyfob code you gave me always returns button1press, even though I am using multiple buttons. I even tried just the “key-fob-buzzer-article.ino” example, and it does the same. Seems like the logic in evalFob is just off. I’m happy to spend the time to try and figure it out, but if you can give me any guidance, I’d appreciate it.

Thanks,
Mark

Hi Mark,

The code I gave you earlier really only checks for button 1 on the remote so that is the problem there. Can you share you current code? If you are using Particle’s WEB IDE for writing the code just click the Share Revision button on the left panel.

That will give you a link which you can share with me. I’ll help with those changes.

Hi,

I am still struggling with this. C++ is NOT my language, but I can’t seem to get any valid data from the A0,A1,D2-D7 pins. They always seem to return 0.

I’ve added this code to KeyFob

        char numstr1[21];
        char numstr2[21];
        char numstr3[21];
        char numstr4[21];
        char numstr5[21];
        char numstr6[21];
        char numstr7[21];
        char numstr8[21];
        
        itoa(digitalRead(A0), numstr1, 10);
        itoa(digitalRead(A1), numstr2, 10);
        itoa(digitalRead(D2), numstr3, 10);
        itoa(digitalRead(D3), numstr4, 10);
        itoa(digitalRead(D4), numstr5, 10);
        itoa(digitalRead(D5), numstr6, 10);
        itoa(digitalRead(D6), numstr7, 10);
        itoa(digitalRead(D7), numstr8, 10);
        
        char res[100];   // array to hold the result.

        strcpy(res,"A0="); 
        strcat(res,numstr1); 
        strcat(res,",A1=");
        strcat(res,numstr2); 
        strcat(res,",D2=");
        strcat(res,numstr3); 
        strcat(res,",D3=");
        strcat(res,numstr4); 
        strcat(res,",D4=");
        strcat(res,numstr5); 
        strcat(res,",D5=");
        strcat(res,numstr6); 
        strcat(res,",D6=");
        strcat(res,numstr7); 
        strcat(res,",D7=");
        strcat(res,numstr8); 
        
        Particle.publish("Pins", res, 60, PUBLIC);

and I see this in my logs:

event: Pins
data: {“data”:“A0=0,A1=0,D2=0,D3=0,D4=0,D5=0,D6=0,D7=0”,“ttl”:60,“published_at”:“2018-06-25T21:39:17.014Z”,“coreid”:“280032000251353530373132”}

event: Pins
data: {“data”:“A0=0,A1=0,D2=0,D3=0,D4=0,D5=0,D6=0,D7=0”,“ttl”:60,“published_at”:“2018-06-25T21:39:17.437Z”,“coreid”:“280032000251353530373132”}

event: Pins
data: {“data”:“A0=0,A1=0,D2=0,D3=0,D4=0,D5=0,D6=0,D7=0”,“ttl”:60,“published_at”:“2018-06-25T21:39:20.201Z”,“coreid”:“280032000251353530373132”}

event: Pins
data: {“data”:“A0=0,A1=0,D2=0,D3=0,D4=0,D5=0,D6=0,D7=0”,“ttl”:60,“published_at”:“2018-06-25T21:39:20.577Z”,“coreid”:“280032000251353530373132”}

event: Pins
data: {“data”:“A0=0,A1=0,D2=0,D3=0,D4=0,D5=0,D6=0,D7=0”,“ttl”:60,“published_at”:“2018-06-25T21:39:24.176Z”,“coreid”:“280032000251353530373132”}

event: Pins
data: {“data”:“A0=0,A1=0,D2=0,D3=0,D4=0,D5=0,D6=0,D7=0”,“ttl”:60,“published_at”:“2018-06-25T21:39:25.656Z”,“coreid”:“280032000251353530373132”}

event: Pins
data: {“data”:“A0=0,A1=0,D2=0,D3=0,D4=0,D5=0,D6=0,D7=0”,“ttl”:60,“published_at”:“2018-06-25T21:39:27.476Z”,“coreid”:“280032000251353530373132”}

event: Pins
data: {“data”:“A0=0,A1=0,D2=0,D3=0,D4=0,D5=0,D6=0,D7=0”,“ttl”:60,“published_at”:“2018-06-25T21:39:27.632Z”,“coreid”:“280032000251353530373132”}

event: Pins
data: {“data”:“A0=0,A1=0,D2=0,D3=0,D4=0,D5=0,D6=0,D7=0”,“ttl”:60,“published_at”:“2018-06-25T21:39:30.554Z”,“coreid”:“280032000251353530373132”}

event: Pins
data: {“data”:“A0=0,A1=0,D2=0,D3=0,D4=0,D5=0,D6=0,D7=0”,“ttl”:60,“published_at”:“2018-06-25T21:39:30.686Z”,“coreid”:“280032000251353530373132”}
doesn’t seem to matter which of the buttons I push, I get the same thing.

I have tried the key-fob-buzzer-article source again, and it always returns Button1Press, no matter what I do.

I see from the order page for the KeyFob shield, it should send a HIGH to the pins when the button is pressed and a LOW when the button is released. I just am not seeing that happen.

Thanks,
Mark

Hi Mark,

Did you buy a 4 button key fob remote?

Yes. KeyFob shield, and the 4 button remote. What I don’t get is that I never seem to get values from the call to digitalRead on any of the 8 pins.

Try this Mark,
https://go.particle.io/shared_apps/5b3265aacf5a3b9efc0000c6

You should get serial prints and Particle Event publishes when any of the 4 buttons are pressed. Let me know what you find.

Hi Travis,

I have been busy, and am just getting back to this. I tried the code you sent above, but it still always says Button4. I noticed the switch case statements were missing the break; lines, but when I add that in, it always says button1 press.

It seems as though the logic in KeyFob.cpp is wrong, because it always returns Button1 press, and never anything else.
Is there any documentation that says what values SHOULD be returned in recentFobID = Serial1.read(); and how to interpret which button ?

Thanks,
Mark

Btw, I really want to get this worked out. I am planning to go to my daughter’s high school and teach some kids how to build these kinds of devices. They just got 3 new dust collectors and a compressor, and we’d like to be able to control them with a device like I’ve built, and with Keyfobs.

Hi Mark,

recentFobID is the ID of the key fob that sent the button press. So if you had 2 different key fobs you could perform different actions depending on which key fob the button was pressed on.

I just read back through the code and nothing is jumping out at me as being incorrect. Not sure why it always says Button 1 press. I unfortunately do not have one of the Key Fob Particle overlay modules here at my desk at the moment so I can’t really test anything. I’ll try to get one so I can test the code again.