Code example for 4-relay board, keyfob, and photon

Hello,

I'm working on a home project using a 5-button keyfob to control a 4-relay board through a particle photon (the keyfob kit + photon).  I've found a few examples for a single-button keyfob with a buzzer output, but nothing for a multi-button keyfob and a relay board.   I can control the relays through the photon, but I'm not sure how to do it through the keyfob.

Is it possible to get an example?

Thanks!

T

Hi,

Yes, this is possible.  I will try to put an example together for you this week.

P

Thank you!

T

Hi,

So unfortunately I do not currently have a KeyFob overlay at my desk so I cannot completely test this code, but it should work.

Create a new application on build.particle.io and name it whatever you like.

Now click on the libraries icon over on the left side of the screen, search community libraries for NCD4Relay and select it.  Once selected click the Include in App button over on the left, then select the application you just created.

Your app should now be open for editing.  Click the Plus button in the upper right corner to add a new file.  Call it KeyFob.  This will create KeyFob.h and KeyFob.cpp.  It will also create an include statement on your main application.  In the KeyFob.h file paste in this code:

 

/*
 * KeyFob.h
 *
 *  Created on: Aug 17, 2015
 *      Author: Travis Elliott
 */
#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;
};

In the KeyFob.cpp file paste in this code:

 

/*
 * KeyFob.cpp
 *
 *  Created on: Aug 17, 2015
 *      Author: Travis Elliott
 */
#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;
}

Now go back to your application ino file and paste in this after the include statements at the top added automatically by build:

 

NCD4Relay relayController;

SYSTEM_MODE(AUTOMATIC);

int triggerRelay(String command);

bool tripped[4];

int debugTrips[4];

int minTrips = 5;

//KeyFob
KeyFob fob;
bool checkFob = false;

/* This function is called once at start up ----------------------------------*/
void setup()
{
    //Setup communication to KeyFob interface module
    attachInterrupt(A3, evalFob, CHANGE);
    
    Particle.function("controlRelay", triggerRelay);
    Serial.begin(115200);
    relayController.setAddress(0,0,0);
}

/* This function loops forever --------------------------------------------*/
void loop()
{
    int status = relayController.readAllInputs();
    int a = 0;
    for(int i = 1; i < 9; i*=2){
        if(status & i){
            debugTrips[a]++;
            if(debugTrips[a] >= minTrips){
                if(!tripped[a]){
                    tripped[a] = true;
                    //set input trip event to true
                    String eventName = "Input_";
                    eventName+=(a+1);
                    Particle.publish(eventName, "ON");
                    Serial.print("eventName: ");
                    Serial.println(eventName);
                    Serial.print("eventContents: ");
                    Serial.println("ON");
                }
            }
        }else{
            debugTrips[a] = 0;
            if(tripped[a]){
                tripped[a] = false;
                //set input trip event to false
                String eventName = "Input_";
                eventName+=(a+1);
                Particle.publish(eventName, "OFF");
                Serial.print("eventName: ");
                Serial.println(eventName);
                Serial.print("eventContents: ");
                Serial.println("OFF");
            }
        }
        a++;
    }
    
    //If an interrupt has fired on A3 which is connected to the fob module then a button has been pressed or released so we need to determine what button was pressed or released.
    if(checkFob){
        checkFob = false;
        delay(10);
        fob.evalFob();
        String action;
        switch(fob.recentAction){
        case(fob.button1press):
            Serial.println("Button 1 pressed");
            action = "Button1Press";
            relayController.turnOnRelay(1);
        break;
        case(fob.button2press):
            Serial.println("Button 2 pressed");
            action = "Button2Press";
            relayController.turnOnRelay(2);
        break;
        case(fob.button3press):
            Serial.println("Button 3 pressed");
            action = "Button3Press";
            relayController.turnOnRelay(3);
        break;
        case(fob.button4press):
            Serial.println("Button 4 pressed");
            action = "Button4Press";
            relayController.turnOnRelay(4);
        break;
        case(fob.button5press):
            Serial.println("Button 5 pressed");
            action = "Button5Press";
        break;
        case(fob.button6press):
            Serial.println("Button 6 pressed");
            action = "Button6Press";
        break;
        case(fob.button7press):
            Serial.println("Button 7 pressed");
            action = "Button7Press";
        break;
        case(fob.button8press):
            Serial.println("Button 8 pressed");
            action = "Button8Press";
        break;
        case(fob.button1release):
            Serial.println("Button 1 released");
            action = "Button1Release";
            relayController.turnOffRelay(1);
        break;
        case(fob.button2release):
            Serial.println("Button 2 released");
            action = "Button2Release";
            relayController.turnOffRelay(2);
        break;
        case(fob.button3release):
            Serial.println("Button 3 released");
            action = "Button3Release";
            relayController.turnOffRelay(3);
        break;
        case(fob.button4release):
            Serial.println("Button 4 released");
            action = "Button4Release";
            relayController.turnOffRelay(4);
        break;
        case(fob.button5release):
            Serial.println("Button 5 released");
            action = "Button5Release";
        break;
        case(fob.button6release):
            Serial.println("Button 6 released");
            action = "Button6Release";
        break;
        case(fob.button7release):
            Serial.println("Button 7 released");
        action = "Button7Release";
        break;
        case(fob.button8release):
            Serial.println("Button 8 released");
            action = "Button8Release";
        break;
        }
    }
}

int triggerRelay(String command){
    if(command.equalsIgnoreCase("turnonallrelays")){
        relayController.turnOnAllRelays();
        return 1;
    }
    if(command.equalsIgnoreCase("turnoffallrelays")){
        relayController.turnOffAllRelays();
        return 1;
    }
    if(command.startsWith("setBankStatus:")){
        int status = command.substring(14).toInt();
        if(status < 0 || status > 255){
            return 0;
        }
        Serial.print("Setting bank status to: ");
        Serial.println(status);
        relayController.setBankStatus(status);
        Serial.println("done");
        return 1;
    }
    //Relay Specific Command
    int relayNumber = command.substring(0,1).toInt();
    Serial.print("relayNumber: ");
    Serial.println(relayNumber);
    String relayCommand = command.substring(1);
    Serial.print("relayCommand:");
    Serial.print(relayCommand);
    Serial.println(".");
    if(relayCommand.equalsIgnoreCase("on")){
        Serial.println("Turning on relay");
        relayController.turnOnRelay(relayNumber);
        Serial.println("returning");
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("off")){
        relayController.turnOffRelay(relayNumber);
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("toggle")){
        relayController.toggleRelay(relayNumber);
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("momentary")){
        relayController.turnOnRelay(relayNumber);
        delay(300);
        relayController.turnOffRelay(relayNumber);
        return 1;
    }
    return 0;
}

void evalFob(){
    Serial.println("Fob button pressed");
    checkFob = true;
}

 

If you have any trouble please let me know.

Thank you,

Travis Elliott

 

 

P

Hi Travis,

Thank you very much for the quick reply.

I uploaded the code, and  it sort of works.  

  • Pressing button one turns on relay one.  Releasing button one has no effect, relay 1 stays on.  Pressing the other buttons have no effect.
  • I cycled power.  After the photon was running, I pressed button two.  Relay one turned on.  Releasing button two had no effect.

I tried cycling power and pressing the other buttons, and each time relay one turned on.

Could there be something wrong with the keyfob?  The battery voltage measured 2.97V, I'll replace it with a new one and see what happens.

Best Regards,

photon_user

T

Hi,

No, honestly there is more than likely something wrong with the code.  I did not have hardware here at my desk to test/troubleshoot.  I will try to have hardware brought to me soon so I can take a look.  In the mean time you can try troubleshooting the code a bit.

Thank you,

Travis Elliott

T

Hi,

I just tested the code listed above with the same hardware setup you have here.  Everything seems to be working properly.

When you press the buttons on the key fob remote do you see the Valid LED on the PKFR board turn on?  If not press the learn button on the PKFR, Valid LED will start flashing, now press all buttons on remote, then press Learn button again.

Let me know what you find.

Thank you,

Travis Elliott

P

Hi Travis,

The valid LED lights up for each button pressed.  A new battery didn't change anything.  Relay one still turns on for any of the pressed buttons.

Thanks,

photon_user

T

Hi,

Are you able to monitor the serial prints from the Photon module?  You can do this using Particle's CLI running the particle serial monitor command.  Documentation on that from Particle here:

Install/Setup:

https://docs.particle.io/guide/tools-and-features/cli/photon/

Use:

https://docs.particle.io/reference/cli/

You will need to be able to monitor the Photon module's output in order to troubleshoot this problem.  Let me know what you see in the serial output when pressing the key fob buttons.

P

Hi Travis,

I realized that I was pairing the keyfob incorrectly.  When pairing, I was holding down all five buttons at the same time, instead of pressing one at a time.  

Everything works fine now.

Thank you very much for your help!

Best Regards,

photon_user

 

T

Great!  Let us know if you have any other questions.

J

wont compile for me errors below

 

fob.cpp:3:1: error: 'NCD4Relay' does not name a type
 void setup();
 ^
fob.cpp: In function 'void setup()':
fob.cpp:27:5: error: 'relayController' was not declared in this scope
 {
     ^
fob.cpp: In function 'void loop()':
fob.cpp:33:18: error: 'relayController' was not declared in this scope
     relayController.setAddress(0,0,0);
                  ^
fob.cpp: In function 'int triggerRelay(String)':
fob.cpp:153:9: error: 'relayController' was not declared in this scope
         }
         ^

 
fob.cpp:157:9: error: 'relayController' was not declared in this scope
 int triggerRelay(String command){
         ^

 
fob.cpp:167:9: error: 'relayController' was not declared in this scope
         int status = command.substring(14).toInt();
         ^

 
fob.cpp:181:9: error: 'relayController' was not declared in this scope
     String relayCommand = command.substring(1);
         ^

 
fob.cpp:186:9: error: 'relayController' was not declared in this scope
         Serial.println("Turning on relay");
         ^

 
fob.cpp:190:9: error: 'relayController' was not declared in this scope
     }
         ^

 
fob.cpp:194:9: error: 'relayController' was not declared in this scope
     }
         ^
make[1]: *** [../build/target/user/platform-6fob.o] Error 1
make: *** [user] Error 2

Error: Could not compile. Please review your code.

T

Hi,

On Particle's Build IDE click on the Community Libraries icon on the left(looks like a ribbon).  Under community libraries search for NCD4Relay.  Once you find and select it click on the Include in App button on the left.  Now select the app you are developing and then click the include in this app button.  Now try verifying the code again.  It looks like that Library was not included on your build.

Thank you,

Travis Elliott

J

I started from scratch and still wont compile errors below

 

/src/keyfob.cpp: In function 'void setup()':
/src/keyfob.cpp:210:6: error: redefinition of 'void setup()'
     return 0;
      ^

 
/src/keyfob.cpp:23:6: error: 'void setup()' previously defined here
 
      ^
/src/keyfob.cpp: In function 'void loop()':
/src/keyfob.cpp:214:6: error: redefinition of 'void loop()'
     Serial.println("Fob button pressed");
      ^

 
/src/keyfob.cpp:34:6: error: 'void loop()' previously defined here
     attachInterrupt(A3, evalFob, CHANGE);
      ^
make[1]: *** [../build/target/user/platform-6src/keyfob.o] Error 1
make: *** [user] Error 2

Error: Could not compile. Please review your code.

T

Hi,

Looking at the errors you are getting it looks like both:

void setup()

and

void loop()

are listed twice in your code.  This is not allowed.

J

yep that worked can this code be tweaked so the relays latch ?

for example push button and relay is on untill you press same button again ?

T

Yes, that is possible.  When a button is pressed the action string is set to a particular value and that value is evaluated.  At that time you can decide what to do with the recent action.  

If you would like help with this please post your current code here.

Thank you,

Travis Elliott

J

i am using the same code you posted in the beginning of this thread

it would be great to have some help

T

Just paste this code into your application: 

 

NCD4Relay relayController;

SYSTEM_MODE(AUTOMATIC);

int triggerRelay(String command);

bool tripped[4];

int debugTrips[4];

int minTrips = 5;

//KeyFob
KeyFob fob;
bool checkFob = false;

/* This function is called once at start up ----------------------------------*/
void setup()
{
    //Setup communication to KeyFob interface module
    attachInterrupt(A3, evalFob, CHANGE);
    
    Particle.function("controlRelay", triggerRelay);
    Serial.begin(115200);
    relayController.setAddress(0,0,0);
}

/* This function loops forever --------------------------------------------*/
void loop()
{
    int status = relayController.readAllInputs();
    int a = 0;
    for(int i = 1; i < 9; i*=2){
        if(status & i){
            debugTrips[a]++;
            if(debugTrips[a] >= minTrips){
                if(!tripped[a]){
                    tripped[a] = true;
                    //set input trip event to true
                    String eventName = "Input_";
                    eventName+=(a+1);
                    Particle.publish(eventName, "ON");
                    Serial.print("eventName: ");
                    Serial.println(eventName);
                    Serial.print("eventContents: ");
                    Serial.println("ON");
                }
            }
        }else{
            debugTrips[a] = 0;
            if(tripped[a]){
                tripped[a] = false;
                //set input trip event to false
                String eventName = "Input_";
                eventName+=(a+1);
                Particle.publish(eventName, "OFF");
                Serial.print("eventName: ");
                Serial.println(eventName);
                Serial.print("eventContents: ");
                Serial.println("OFF");
            }
        }
        a++;
    }
    
    //If an interrupt has fired on A3 which is connected to the fob module then a button has been pressed or released so we need to determine what button was pressed or released.
    if(checkFob){
        checkFob = false;
        delay(10);
        fob.evalFob();
        String action;
        switch(fob.recentAction){
        case(fob.button1press):
            Serial.println("Button 1 pressed");
            action = "Button1Press";
            relayController.toggleRelay(1);
        break;
        case(fob.button2press):
            Serial.println("Button 2 pressed");
            action = "Button2Press";
            relayController.toggleRelay(2);
        break;
        case(fob.button3press):
            Serial.println("Button 3 pressed");
            action = "Button3Press";
            relayController.toggleRelay(3);
        break;
        case(fob.button4press):
            Serial.println("Button 4 pressed");
            action = "Button4Press";
            relayController.toggleRelay(4);
        break;
        case(fob.button5press):
            Serial.println("Button 5 pressed");
            action = "Button5Press";
        break;
        case(fob.button6press):
            Serial.println("Button 6 pressed");
            action = "Button6Press";
        break;
        case(fob.button7press):
            Serial.println("Button 7 pressed");
            action = "Button7Press";
        break;
        case(fob.button8press):
            Serial.println("Button 8 pressed");
            action = "Button8Press";
        break;
        case(fob.button1release):
            Serial.println("Button 1 released");
            action = "Button1Release";
            // relayController.turnOffRelay(1);
        break;
        case(fob.button2release):
            Serial.println("Button 2 released");
            action = "Button2Release";
            // relayController.turnOffRelay(2);
        break;
        case(fob.button3release):
            Serial.println("Button 3 released");
            action = "Button3Release";
            // relayController.turnOffRelay(3);
        break;
        case(fob.button4release):
            Serial.println("Button 4 released");
            action = "Button4Release";
            // relayController.turnOffRelay(4);
        break;
        case(fob.button5release):
            Serial.println("Button 5 released");
            action = "Button5Release";
        break;
        case(fob.button6release):
            Serial.println("Button 6 released");
            action = "Button6Release";
        break;
        case(fob.button7release):
            Serial.println("Button 7 released");
        action = "Button7Release";
        break;
        case(fob.button8release):
            Serial.println("Button 8 released");
            action = "Button8Release";
        break;
        }
    }
}

int triggerRelay(String command){
    if(command.equalsIgnoreCase("turnonallrelays")){
        relayController.turnOnAllRelays();
        return 1;
    }
    if(command.equalsIgnoreCase("turnoffallrelays")){
        relayController.turnOffAllRelays();
        return 1;
    }
    if(command.startsWith("setBankStatus:")){
        int status = command.substring(14).toInt();
        if(status < 0 || status > 255){
            return 0;
        }
        Serial.print("Setting bank status to: ");
        Serial.println(status);
        relayController.setBankStatus(status);
        Serial.println("done");
        return 1;
    }
    //Relay Specific Command
    int relayNumber = command.substring(0,1).toInt();
    Serial.print("relayNumber: ");
    Serial.println(relayNumber);
    String relayCommand = command.substring(1);
    Serial.print("relayCommand:");
    Serial.print(relayCommand);
    Serial.println(".");
    if(relayCommand.equalsIgnoreCase("on")){
        Serial.println("Turning on relay");
        relayController.turnOnRelay(relayNumber);
        Serial.println("returning");
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("off")){
        relayController.turnOffRelay(relayNumber);
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("toggle")){
        relayController.toggleRelay(relayNumber);
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("momentary")){
        relayController.turnOnRelay(relayNumber);
        delay(300);
        relayController.turnOffRelay(relayNumber);
        return 1;
    }
    return 0;
}

void evalFob(){
    Serial.println("Fob button pressed");
    checkFob = true;
}

 

J

that worked great is ther away to check if a relay is on ?

i have to have a way on 2 of the relays say relay 1 is on and i try to turn on relay 2 it will not come on untill relay 1 is off and the button is pressed again for 2 .

same if 2 is on and i try to turn on 1 it will not come on untill relay 2 is off and there is another button press for relay 1 ?

relay 3 and 4 can come on any time as they are now

thank you very much for your assist

T

Look for this section in the code:

case(fob.button1press):
            Serial.println("Button 1 pressed");
            action = "Button1Press";
            relayController.toggleRelay(1);
        break;

This is where the controller toggles relay 1 if button 1 is pressed.  Here before you execute the toggle command you can check the status of relay 2 with:

if(relayController.readRelayStatus(2) != 1){

     relayController.toggleRelay(1);

}

relayController.readRelayStatus(2) will return the current status of relay 2.  It will return 1 if the relay is on and 0 if the relay is off.  That should get you going.

Chris Saenz's picture

Thank you Travis, I have been looking for this information. I know very little about coding but was able to get yours to work and updated it to do what I want. 
I change #3 and 4 relays to toggles for light controll and added Blynk so now I can open the garage and, or turn on the secondary light with the key fob or my phone.
Here is a link if anybody wants to check it out.
https://build.particle.io/shared_apps/58f6d5ff9f25ccb412000b8c

T

Very cool Chris.  Thank you so much for sharing!  Blynk is allot of fun eh?  I wrote an article on Particle+CE+Blynk last week on Hackster here although looks like you already have a handle on it:

https://www.hackster.io/ControlEverything/blynk-particle-controleverything-7e0990

Have fun Chris!

Chris Saenz's picture

I still can't get the inputs to work.  I have magnetic reed switches at full open and closed positions to close pin 4 or 5 to ground.  But even with a momentary switch, the LED in Blynk won't come on.

I tried to go back to your article "https://www.hackster.io/ControlEverything/blynk-particle-controleverything-7e0990"  but I don't have the temp. sensor and a 4 relay board so I have to edit your code..... but like I said I don't know enough code to figure out what I have done wrong. I will add my code if someone wants to see it and give them Ideas on how to add/edit for what they need (hopefuly) ☺
 

 

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

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

// This #include statement was automatically added by the Particle IDE.
#include "KeyFob.h"

// Thank you Travis Elliott ☺

NCD4Relay relayController;

SYSTEM_MODE(AUTOMATIC);

int triggerRelay(String command);

bool tripped[4];

int debugTrips[4];

int minTrips = 5;

//Authentication code for Blynk app running on phone.  Enter the Auth code for the project on your Blynk app here.
char blynkAuth[] = "";

//KeyFob
KeyFob fob;
bool checkFob = false;

//LED widget objects on Blynk app user interface.
//Used for indicating status of inputs on relay board(Closed/Open)
WidgetLED led[4] = {V4, V5, V6, V7};

/* This function is called once at start up ----------------------------------*/
void setup()
{
    //Configure Blynk
    Blynk.begin(blynkAuth);
    //Initialize relay controller by passing status of the 3 on board address jumpers.  This function must be called prior to interfacing with the controller.
    relayController.setAddress(0,0,0);
    
    //Publish status of inputs to app on boot
    updateInputs(true);
 
    //Setup communication to KeyFob interface module
    attachInterrupt(A3, evalFob, CHANGE);
    
    Particle.function("controlRelay", triggerRelay);
    Serial.begin(115200);
    relayController.setAddress(0,0,0);
}

/* This function loops forever --------------------------------------------*/
void loop()
{
        //Perform Housekeeping of Blynk connection
    Blynk.run();

    int status = relayController.readAllInputs();
    int a = 0;
    for(int i = 1; i < 9; i*=2){
        if(status & i){
            debugTrips[a]++;
            if(debugTrips[a] >= minTrips){
                if(!tripped[a]){
                    tripped[a] = true;
                    //set input trip event to true
                    String eventName = "Input_";
                    eventName+=(a+1);
                    Particle.publish(eventName, "ON");
                    Serial.print("eventName: ");
                    Serial.println(eventName);
                    Serial.print("eventContents: ");
                    Serial.println("ON");
                }
            }
        }else{
            debugTrips[a] = 0;
            if(tripped[a]){
                tripped[a] = false;
                //set input trip event to false
                String eventName = "Input_";
                eventName+=(a+1);
                Particle.publish(eventName, "OFF");
                Serial.print("eventName: ");
                Serial.println(eventName);
                Serial.print("eventContents: ");
                Serial.println("OFF");
            }
        }
        a++;
    }
    
    //If an interrupt has fired on A3 which is connected to the fob module then a button has been pressed or released so we need to determine what button was pressed or released.
    if(checkFob){
        checkFob = false;
        delay(10);
        fob.evalFob();
        String action;
        switch(fob.recentAction){
        case(fob.button1press):
            Serial.println("Button 1 pressed");
            action = "Button1Press";
            relayController.turnOnRelay(1);
        break;
        case(fob.button2press):
            Serial.println("Button 2 pressed");
            action = "Button2Press";
            relayController.turnOnRelay(2);
        break;
        case(fob.button3press):
            Serial.println("Button 3 pressed");
            action = "Button3Press";
            relayController.toggleRelay(3);
        break;
        case(fob.button4press):
            Serial.println("Button 4 pressed");
            action = "Button4Press";
            relayController.toggleRelay(4);
        break;
        case(fob.button5press):
            Serial.println("Button 5 pressed");
            action = "Button5Press";
        break;
        case(fob.button6press):
            Serial.println("Button 6 pressed");
            action = "Button6Press";
        break;
        case(fob.button7press):
            Serial.println("Button 7 pressed");
            action = "Button7Press";
        break;
        case(fob.button8press):
            Serial.println("Button 8 pressed");
            action = "Button8Press";
        break;
        case(fob.button1release):
            Serial.println("Button 1 released");
            action = "Button1Release";
            relayController.turnOffRelay(1);
        break;
        case(fob.button2release):
            Serial.println("Button 2 released");
            action = "Button2Release";
            relayController.turnOffRelay(2);
        break;
        case(fob.button3release):
            Serial.println("Button 3 released");
            action = "Button3Release";
            //relayController.turnOffRelay(3);
        break;
        case(fob.button4release):
            Serial.println("Button 4 released");
            action = "Button4Release";
            //relayController.turnOffRelay(4);
        break;
        case(fob.button5release):
            Serial.println("Button 5 released");
            action = "Button5Release";
            relayController.turnOffAllRelays();
        break;
        case(fob.button6release):
            Serial.println("Button 6 released");
            action = "Button6Release";
        break;
        case(fob.button7release):
            Serial.println("Button 7 released");
        action = "Button7Release";
        break;
        case(fob.button8release):
            Serial.println("Button 8 released");
            action = "Button8Release";
        break;
        }
    }
}

int triggerRelay(String command){
    if(command.equalsIgnoreCase("turnonallrelays")){
        relayController.turnOnAllRelays();
        return 1;
    }
    if(command.equalsIgnoreCase("turnoffallrelays")){
        relayController.turnOffAllRelays();
        return 1;
    }
    if(command.startsWith("setBankStatus:")){
        int status = command.substring(14).toInt();
        if(status < 0 || status > 255){
            return 0;
        }
        Serial.print("Setting bank status to: ");
        Serial.println(status);
        relayController.setBankStatus(status);
        Serial.println("done");
        return 1;
    }
    //Relay Specific Command
    int relayNumber = command.substring(0,1).toInt();
    Serial.print("relayNumber: ");
    Serial.println(relayNumber);
    String relayCommand = command.substring(1);
    Serial.print("relayCommand:");
    Serial.print(relayCommand);
    Serial.println(".");
    if(relayCommand.equalsIgnoreCase("on")){
        Serial.println("Turning on relay");
        relayController.turnOnRelay(relayNumber);
        Serial.println("returning");
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("off")){
        relayController.turnOffRelay(relayNumber);
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("toggle")){
        relayController.toggleRelay(relayNumber);
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("momentary")){
        relayController.turnOnRelay(relayNumber);
        delay(300);
        relayController.turnOffRelay(relayNumber);
        return 1;
    }
    return 0;
}

void evalFob(){
    Serial.println("Fob button pressed");
    checkFob = true;
}

BLYNK_WRITE(V0){
    //Recieved command to control relay 1.
    int value = param.asInt();
    Serial.printf("Blynk virtual write pin %i with param %i \n", V0, value);
    switch(value){
        case 1:
            relayController.turnOnRelay(1);
            break;
        case 0:
            relayController.turnOffRelay(1);
            break;
    }
}
BLYNK_WRITE(V1){
    //Recieved command to control relay 2.
    int value = param.asInt();
    Serial.printf("Blynk virtual write pin %i with param %i \n", V1, value);
    switch(value){
        case 1:
            relayController.turnOnRelay(2);
            break;
        case 0:
            relayController.turnOffRelay(2);
            break;
    }
}

BLYNK_WRITE(V2){
    //Recieved command to control relay 3.
    int value = param.asInt();
    Serial.printf("Blynk virtual write pin %i with param %i \n", V2, value);
    switch(value){
        case 1:
            relayController.turnOnRelay(3);
            break;
        case 0:
            relayController.turnOffRelay(3);
            break;
    }
}
BLYNK_WRITE(V3){
    //Recieved command to control relay 4.
    int value = param.asInt();
    Serial.printf("Blynk virtual write pin %i with param %i \n", V3, value);
    switch(value){
        case 1:
            relayController.turnOnRelay(4);
            break;
        case 0:
            relayController.turnOffRelay(4);
            break;
    }
}

void updateInputs(bool startup){
    //Read and debounce digital inputs on relay board.
    int status = relayController.readAllInputs();
    int a = 0;
    for(int i = 1; i < 33; i*=2){
        if(status & i){
            debugTrips[a]++;
            if(debugTrips[a] >= minTrips || startup){
                if(!tripped[a] || startup){
                    //Input is closed
                    Serial.println("Input Closed");
                    tripped[a] = true;
                    //Publish high status to LED indicator in Blynk app notifying user that input is closed.
                    led[a].on();
                    if(a == 3){
                        //If this is input 4 on the relay board then push notification to user's phone.
                        Blynk.notify("You're really pushing my buttons");
                    }
                }
            }
        }else{
            debugTrips[a] = 0;
            if(tripped[a] || startup){
                Serial.println("Input Open");
                //Input is open
                tripped[a] = false;
                //Publish low status to LED indicator in Blynk app notifying user that input is open.
                led[a].off();
            }
        }
        a++;
    }
}

 

T

Hi Chris,

Is your relay controller a 4 relay controller?  Can you tell me all the hardware you have on this setup(4 relay controller + Key Fob + ...)?

Chris Saenz's picture

Just that. A 4 relay board, with key fob kit ( https://store.particle.io/products/key-fob-kit )

And the Particle Photon.

 

J

did i see you are controlling the relays with the key fob and Blynk ???

Chris Saenz's picture

Yes, I can open the door and turn on the light with the or Blynk.  Both of those work well. But when I ground gp4 (or any 5, 6, or 7), Blynk doesn't show​ the input as being closed.

T

Hi Chris,

I will try to replicate your hardware setup here at my desk this afternoon and see if I can determine what the issue may be.  After a quick glance over your code everything appears to be correct.  Will let you know what I find.

T

Hey Chris,

Try updating your loop function to this.  I believe you just need the updateInputs(false) added there.  Also since the inputs are checked in that function there really is no need to read inputs in the loop.

void loop()
{
        //Perform Housekeeping of Blynk connection
    Blynk.run();
    
    updateInputs(false);
    
    //If an interrupt has fired on A3 which is connected to the fob module then a button has been pressed or released so we need to determine what button was pressed or released.
    if(checkFob){
        checkFob = false;
        delay(10);
        fob.evalFob();
        String action;
        switch(fob.recentAction){
        case(fob.button1press):
            Serial.println("Button 1 pressed");
            action = "Button1Press";
            relayController.turnOnRelay(1);
        break;
        case(fob.button2press):
            Serial.println("Button 2 pressed");
            action = "Button2Press";
            relayController.turnOnRelay(2);
        break;
        case(fob.button3press):
            Serial.println("Button 3 pressed");
            action = "Button3Press";
            relayController.toggleRelay(3);
        break;
        case(fob.button4press):
            Serial.println("Button 4 pressed");
            action = "Button4Press";
            relayController.toggleRelay(4);
        break;
        case(fob.button5press):
            Serial.println("Button 5 pressed");
            action = "Button5Press";
        break;
        case(fob.button6press):
            Serial.println("Button 6 pressed");
            action = "Button6Press";
        break;
        case(fob.button7press):
            Serial.println("Button 7 pressed");
            action = "Button7Press";
        break;
        case(fob.button8press):
            Serial.println("Button 8 pressed");
            action = "Button8Press";
        break;
        case(fob.button1release):
            Serial.println("Button 1 released");
            action = "Button1Release";
            relayController.turnOffRelay(1);
        break;
        case(fob.button2release):
            Serial.println("Button 2 released");
            action = "Button2Release";
            relayController.turnOffRelay(2);
        break;
        case(fob.button3release):
            Serial.println("Button 3 released");
            action = "Button3Release";
            //relayController.turnOffRelay(3);
        break;
        case(fob.button4release):
            Serial.println("Button 4 released");
            action = "Button4Release";
            //relayController.turnOffRelay(4);
        break;
        case(fob.button5release):
            Serial.println("Button 5 released");
            action = "Button5Release";
            relayController.turnOffAllRelays();
        break;
        case(fob.button6release):
            Serial.println("Button 6 released");
            action = "Button6Release";
        break;
        case(fob.button7release):
            Serial.println("Button 7 released");
        action = "Button7Release";
        break;
        case(fob.button8release):
            Serial.println("Button 8 released");
            action = "Button8Release";
        break;
        }
    }
}

T

Oh, also update the updateInputs(bool startup) function to this so it only reads 4 inputs on the board and not 6 which are available on the 2 channel board the code was origionally written for:

void updateInputs(bool startup){
    //Read and debounce digital inputs on relay board.
    int status = relayController.readAllInputs();
    int a = 0;
    for(int i = 1; i < 9; i*=2){
        if(status & i){
            debugTrips[a]++;
            if(debugTrips[a] >= minTrips || startup){
                if(!tripped[a] || startup){
                    //Input is closed
                    Serial.println("Input Closed");
                    tripped[a] = true;
                    //Publish high status to LED indicator in Blynk app notifying user that input is closed.
                    led[a].on();
                    if(a == 3){
                        //If this is input 4 on the relay board then push notification to user's phone.
                        Blynk.notify("You're really pushing my buttons");
                    }
                }
            }
        }else{
            debugTrips[a] = 0;
            if(tripped[a] || startup){
                Serial.println("Input Open");
                //Input is open
                tripped[a] = false;
                //Publish low status to LED indicator in Blynk app notifying user that input is open.
                led[a].off();
            }
        }
        a++;
    }
}

J

i posted that code in to add blynk and now i have fast flashing green light

Chris Saenz's picture

I believe the fast flashing green light is looking for internet.
https://docs.particle.io/guide/getting-started/modes/photon/#listening-mode

 

Chris Saenz's picture

Thank you Travis it all works now. 2 realys for 2 doors, 2 for lights. And Leds for door open and door closed.  
Here is the current updated code.     Next I will look into a timer if the door is left open

 

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

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

// This #include statement was automatically added by the Particle IDE.
#include "KeyFob.h"

// Thank you Travis Elliott ☺

NCD4Relay relayController;

SYSTEM_MODE(AUTOMATIC);

int triggerRelay(String command);

bool tripped[4];

int debugTrips[4];

int minTrips = 5;

//Authentication code for Blynk app running on phone.  Enter the Auth code for the project on your Blynk app here.
char blynkAuth[] = "";

//KeyFob
KeyFob fob;
bool checkFob = false;

//LED widget objects on Blynk app user interface.
//Used for indicating status of inputs on relay board(Closed/Open)
WidgetLED led[4] = {V4, V5, V6, V7};

/* This function is called once at start up ----------------------------------*/
void setup()
{
    //Configure Blynk
    Blynk.begin(blynkAuth);
    //Initialize relay controller by passing status of the 3 on board address jumpers.  This function must be called prior to interfacing with the controller.
    relayController.setAddress(0,0,0);
    
    //Publish status of inputs to app on boot
    updateInputs(true);
 
    //Setup communication to KeyFob interface module
    attachInterrupt(A3, evalFob, CHANGE);
    
    Particle.function("controlRelay", triggerRelay);
    Serial.begin(115200);
    relayController.setAddress(0,0,0);
}

/* This function loops forever --------------------------------------------*/
void loop()
{
        //Perform Housekeeping of Blynk connection
    Blynk.run();
    updateInputs(false);

    //If an interrupt has fired on A3 which is connected to the fob module then a button has been pressed or released so we need to determine what button was pressed or released.
    if(checkFob){
        checkFob = false;
        delay(10);
        fob.evalFob();
        String action;
        switch(fob.recentAction){
        case(fob.button1press):
            Serial.println("Button 1 pressed");
            action = "Button1Press";
            relayController.turnOnRelay(1);
        break;
        case(fob.button2press):
            Serial.println("Button 2 pressed");
            action = "Button2Press";
            relayController.turnOnRelay(2);
        break;
        case(fob.button3press):
            Serial.println("Button 3 pressed");
            action = "Button3Press";
            relayController.toggleRelay(3);
        break;
        case(fob.button4press):
            Serial.println("Button 4 pressed");
            action = "Button4Press";
            relayController.toggleRelay(4);
        break;
        case(fob.button5press):
            Serial.println("Button 5 pressed");
            action = "Button5Press";
        break;
        case(fob.button6press):
            Serial.println("Button 6 pressed");
            action = "Button6Press";
        break;
        case(fob.button7press):
            Serial.println("Button 7 pressed");
            action = "Button7Press";
        break;
        case(fob.button8press):
            Serial.println("Button 8 pressed");
            action = "Button8Press";
        break;
        case(fob.button1release):
            Serial.println("Button 1 released");
            action = "Button1Release";
            relayController.turnOffRelay(1);
        break;
        case(fob.button2release):
            Serial.println("Button 2 released");
            action = "Button2Release";
            relayController.turnOffRelay(2);
        break;
        case(fob.button3release):
            Serial.println("Button 3 released");
            action = "Button3Release";
            //relayController.turnOffRelay(3);
        break;
        case(fob.button4release):
            Serial.println("Button 4 released");
            action = "Button4Release";
            //relayController.turnOffRelay(4);
        break;
        case(fob.button5release):
            Serial.println("Button 5 released");
            action = "Button5Release";
            relayController.turnOffAllRelays();
        break;
        case(fob.button6release):
            Serial.println("Button 6 released");
            action = "Button6Release";
        break;
        case(fob.button7release):
            Serial.println("Button 7 released");
        action = "Button7Release";
        break;
        case(fob.button8release):
            Serial.println("Button 8 released");
            action = "Button8Release";
        break;
        }
    }
}

int triggerRelay(String command){
    if(command.equalsIgnoreCase("turnonallrelays")){
        relayController.turnOnAllRelays();
        return 1;
    }
    if(command.equalsIgnoreCase("turnoffallrelays")){
        relayController.turnOffAllRelays();
        return 1;
    }
    if(command.startsWith("setBankStatus:")){
        int status = command.substring(14).toInt();
        if(status < 0 || status > 255){
            return 0;
        }
        Serial.print("Setting bank status to: ");
        Serial.println(status);
        relayController.setBankStatus(status);
        Serial.println("done");
        return 1;
    }
    //Relay Specific Command
    int relayNumber = command.substring(0,1).toInt();
    Serial.print("relayNumber: ");
    Serial.println(relayNumber);
    String relayCommand = command.substring(1);
    Serial.print("relayCommand:");
    Serial.print(relayCommand);
    Serial.println(".");
    if(relayCommand.equalsIgnoreCase("on")){
        Serial.println("Turning on relay");
        relayController.turnOnRelay(relayNumber);
        Serial.println("returning");
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("off")){
        relayController.turnOffRelay(relayNumber);
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("toggle")){
        relayController.toggleRelay(relayNumber);
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("momentary")){
        relayController.turnOnRelay(relayNumber);
        delay(300);
        relayController.turnOffRelay(relayNumber);
        return 1;
    }
    return 0;
}

void evalFob(){
    Serial.println("Fob button pressed");
    checkFob = true;
}

BLYNK_WRITE(V0){
    //Recieved command to control relay 1.
    int value = param.asInt();
    Serial.printf("Blynk virtual write pin %i with param %i \n", V0, value);
    switch(value){
        case 1:
            relayController.turnOnRelay(1);
            break;
        case 0:
            relayController.turnOffRelay(1);
            break;
    }
}
BLYNK_WRITE(V1){
    //Recieved command to control relay 2.
    int value = param.asInt();
    Serial.printf("Blynk virtual write pin %i with param %i \n", V1, value);
    switch(value){
        case 1:
            relayController.turnOnRelay(2);
            break;
        case 0:
            relayController.turnOffRelay(2);
            break;
    }
}

BLYNK_WRITE(V2){
    //Recieved command to control relay 3.
    int value = param.asInt();
    Serial.printf("Blynk virtual write pin %i with param %i \n", V2, value);
    switch(value){
        case 1:
            relayController.turnOnRelay(3);
            break;
        case 0:
            relayController.turnOffRelay(3);
            break;
    }
}
BLYNK_WRITE(V3){
    //Recieved command to control relay 4.
    int value = param.asInt();
    Serial.printf("Blynk virtual write pin %i with param %i \n", V3, value);
    switch(value){
        case 1:
            relayController.turnOnRelay(4);
            break;
        case 0:
            relayController.turnOffRelay(4);
            break;
    }
}

void updateInputs(bool startup){
    //Read and debounce digital inputs on relay board.
    int status = relayController.readAllInputs();
    int a = 0;
    for(int i = 1; i < 9; i*=2){
        if(status & i){
            debugTrips[a]++;
            if(debugTrips[a] >= minTrips || startup){
                if(!tripped[a] || startup){
                    //Input is closed
                    Serial.println("Input Closed");
                    tripped[a] = true;
                    //Publish high status to LED indicator in Blynk app notifying user that input is closed.
                    led[a].on();
                    if(a == 3){
                        //If this is input 4 on the relay board then push notification to user's phone.
                        Blynk.notify("You're really pushing my buttons");
                    }
                }
            }
        }else{
            debugTrips[a] = 0;
            if(tripped[a] || startup){
                Serial.println("Input Open");
                //Input is open
                tripped[a] = false;
                //Publish low status to LED indicator in Blynk app notifying user that input is open.
                led[a].off();
            }
        }
        a++;
    }
}

 

 

T

Great Chris!

Jpotpo, paste in Chris's latest code, then search community libraries and include Blynk and the appropriate NCD relay library(depends on the number of relays on your board).  You will also need the key fob library files(KeyFob.cpp and KeyFob.h) which are available here:

https://github.com/ControlEverythingCom/Fob_Alarm/tree/master/firmware

Thank you,

Travis Elliott