Array Relay Button Actuator
-
Hello everyone,
Has anyone done an Array Relay Button Actuator?
-
I'm having the same issue too using Multi Button Actuator sketch. I can't figure out how to switch from Lo to Hi or Lo to Hi to drive my relays because nothing happens when I change #define. and the sketch can't seem to communicate with my Vera UI7. But when I use a single actuator sketch from My sensor library, it communicates well with Vera. So its obvious that something is not right in the sketch for it to react that way.
Anyway, this is what I have done with the help of the community. Perhaps you or someone can make it better.
#include <MySensor.h> #include <SPI.h> #include <Bounce2.h> #define RELAY_ON 0 //switch around for realy HIGH/LOW state #define RELAY_OFF 1 // MySensor gw; #define RADIO_ID 11 #define noRelays 4 const int relayPin[] = {3,7}; const int buttonPin[] = {4,5}; class Relay // relay class, store all relevant data (equivalent to struct) { public: int buttonPin; // physical pin number of button int relayPin; // physical pin number of relay byte oldValue; // last Values for key (debounce) boolean relayState; // relay status (also stored in EEPROM) }; Relay Relays[noRelays]; Bounce debouncer[noRelays]; MyMessage msg[noRelays]; void setup(){ gw.begin(NULL, RADIO_ID, true); delay(250); gw.sendSketchInfo("MultiRelayButton", "0.9b"); delay(250); // initialize Relays with corresponding buttons for (int i = 0; i < noRelays; i++){ Relays[i].buttonPin = buttonPin[i]; // assign physical pins Relays[i].relayPin = relayPin[i]; msg[i].sensor = i; // initialize messages msg[i].type = V_LIGHT; debouncer[i] = Bounce(); // initialize debouncer debouncer[i].attach(buttonPin[i]); debouncer[i].interval(5); pinMode(Relays[i].buttonPin, INPUT_PULLUP); pinMode(Relays[i].relayPin, OUTPUT); Relays[i].relayState = gw.loadState(i); // retrieve last values from EEPROM digitalWrite(Relays[i].relayPin, Relays[i].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly gw.send(msg[i].set(Relays[i].relayState? true : false) ); // make controller aware of last status gw.present(i, S_LIGHT); // present sensor to gateway delay(250); } } void loop() { gw.process(); for (byte i = 0; i < noRelays; i++) { debouncer[i].update(); byte value = debouncer[i].read(); if (value != Relays[i].oldValue && value == 0) { Relays[i].relayState = !Relays[i].relayState; digitalWrite(Relays[i].relayPin, Relays[i].relayState); delay(250); gw.send(msg[i].set(Relays[i].relayState? true : false) ); gw.saveState( i, Relays[i].relayState ); // save sensor state in EEPROM (location == sensor number) } Relays[i].oldValue = value; } } // process incoming message void incomingMessage(const MyMessage &message){ delay(250); if (message.type == V_LIGHT){ delay(250); if (message.sensor <= noRelays){ // check if message is valid for relays delay(250); Relays[message.sensor].relayState = message.getBool(); delay(250); digitalWrite(Relays[message.sensor].relayPin, Relays[message.sensor].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly delay(250); gw.saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number) } } }
-
@jeylites A few things to consider:
- You have hardwired the radio id to 11 - make sure you aren't using 11 on any other sensors or actuators.
- #define noRelays is set to 4 but you only have two relayPin and buttonPin values set. So noRelays needs to be set to 2 otherwise the setup method is going to run off the end of the arrays in the for loop that could crash the sketch/Arduino or at a minimum overwrite other memory causing unpredictable behavior.
I would check those two things first and report back.
-
I dedicated Radio ID 11 for this sketch. I don't have any sensor or actuators on this channel. Initially, I had #define noRelays set as 4 but I changed it to 2 for testing purpose and forgot to update the sketch when I posted here. Anyway, this is the problem I'm facing.
-
I'm unable to control the Relays from the Vera App and Web interface, but I'm able to toggle the light switch button ON / OFF on Vera App and Web from the Arduino button inputs. Basically the Button pin works, but not Relay Pin.
-
I'm unable to switch around for realy HIGH/LOW state.
Serial Report: Upon start up
repeater started, id 11
send: 11-11-0-0 s=255,c=0,t=18,pt=0,l=5,st=ok:1.4.1
send: 11-11-0-0 s=255,c=3,t=6,pt=1,l=1,st=ok:0
read: 0-0-11 s=255,c=3,t=6,pt=0,l=1:M
send: 11-11-0-0 s=255,c=3,t=11,pt=0,l=16,st=ok:MultiRelayButton
send: 11-11-0-0 s=255,c=3,t=12,pt=0,l=4,st=ok:0.9b
send: 11-11-0-0 s=0,c=1,t=2,pt=2,l=2,st=ok:0
send: 11-11-0-0 s=0,c=0,t=3,pt=0,l=5,st=ok:1.4.1
send: 11-11-0-0 s=1,c=1,t=2,pt=2,l=2,st=ok:1
send: 11-11-0-0 s=1,c=0,t=3,pt=0,l=5,st=ok:1.4.1Serial Report: When button is pressed
send: 11-11-0-0 s=0,c=1,t=2,pt=2,l=2,st=ok:1
send: 11-11-0-0 s=0,c=1,t=2,pt=2,l=2,st=ok:0#include <MySensor.h> #include <SPI.h> #include <Bounce2.h> #define RELAY_ON 0 //switch around for realy HIGH/LOW state #define RELAY_OFF 1 // MySensor gw; #define RADIO_ID 11 #define noRelays 2 const int relayPin[] = {3,7}; const int buttonPin[] = {4,5}; class Relay // relay class, store all relevant data (equivalent to struct) { public: int buttonPin; // physical pin number of button int relayPin; // physical pin number of relay byte oldValue; // last Values for key (debounce) boolean relayState; // relay status (also stored in EEPROM) }; Relay Relays[noRelays]; Bounce debouncer[noRelays]; MyMessage msg[noRelays]; void setup(){ gw.begin(NULL, RADIO_ID, true); delay(250); gw.sendSketchInfo("MultiRelayButton", "0.9b"); delay(250); // initialize Relays with corresponding buttons for (int i = 0; i < noRelays; i++){ Relays[i].buttonPin = buttonPin[i]; // assign physical pins Relays[i].relayPin = relayPin[i]; msg[i].sensor = i; // initialize messages msg[i].type = V_LIGHT; debouncer[i] = Bounce(); // initialize debouncer debouncer[i].attach(buttonPin[i]); debouncer[i].interval(5); pinMode(Relays[i].buttonPin, INPUT_PULLUP); pinMode(Relays[i].relayPin, OUTPUT); Relays[i].relayState = gw.loadState(i); // retrieve last values from EEPROM digitalWrite(Relays[i].relayPin, Relays[i].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly gw.send(msg[i].set(Relays[i].relayState? true : false) ); // make controller aware of last status gw.present(i, S_LIGHT); // present sensor to gateway delay(250); } } void loop() { gw.process(); for (byte i = 0; i < noRelays; i++) { debouncer[i].update(); byte value = debouncer[i].read(); if (value != Relays[i].oldValue && value == 0) { Relays[i].relayState = !Relays[i].relayState; digitalWrite(Relays[i].relayPin, Relays[i].relayState); delay(250); gw.send(msg[i].set(Relays[i].relayState? true : false) ); gw.saveState( i, Relays[i].relayState ); // save sensor state in EEPROM (location == sensor number) } Relays[i].oldValue = value; } } // process incoming message void incomingMessage(const MyMessage &message){ delay(250); if (message.type == V_LIGHT){ delay(250); if (message.sensor <= noRelays){ // check if message is valid for relays delay(250); Relays[message.sensor].relayState = message.getBool(); delay(250); digitalWrite(Relays[message.sensor].relayPin, Relays[message.sensor].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly delay(250); gw.saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number) } } }
-
-
Do you have messages coming in from the controller when executing commands from Vera? You should see this as 'read' in the debug output.?
-
@AWI How do I go about doing this?
This is the messages i get from the gateway when actuator is pressed on the sensor node.
0;0;3;0;9;read: 11-11-0 s=0,c=1,t=2,pt=2,l=2:0
11;0;1;0;2;0
0;0;3;0;9;read: 11-11-0 s=0,c=1,t=2,pt=2,l=2:1
11;0;1;0;2;1
-
@jeylites I was meaning to say.: on the node serial output. Do you see messages coming in. You can also add a print statement in the received message code.
-
@jeylites I think I found the problem. You won't receive any messages from the controller as messages are not initialized. Replace NULL in the gw. begin by the name of the incoming message routine.. Wonders will start to happen
-
@AWI . OK let me try again.
-
... This is insane and it works How do you change between HIGH/LOW state. I changed the #define settings but it's not taking effect.
-
This is the awkward part. On the Vera App & Web, I'm able to toggle ON / OFF to the respective state of the Relay. Eg: "ON" on Vera energize the Relay and "OFF" de-energine the relay. But, when I use the actuator buttons on Arduino input , its reversed. "OFF" turns ON the Relay ...vice versa.
-
@jeylites I understand your Relays are active low. You have to be consequent in terminology like: on/off; true/false; RELAY_ON/RELAY_OFF. From a first glance I think you should be fine if you change the line:
digitalWrite(Relays[i].relayPin, Relays[i].relayState);
to
digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF);
as things get mixed up here. i.e RELAY_ON is in fact "false" or "0"
-
I revised the sketch based on your advice and seem to be working as we speak. I tried to make the final sketch as organized as possible, It has be copied below. Thank you everyone for making this work!!!
#include <MySensor.h> #include <SPI.h> #include <Bounce2.h> #define RELAY_ON 0 // switch around for realy HIGH/LOW state #define RELAY_OFF 1 // MySensor gw; #define RADIO_ID 11 // radio Id, whatever channel you assigned to #define noRelays 2 const int relayPin[] = {3,7}; // switch around pins to your desire const int buttonPin[] = {4,5}; // switch around pins to your desire class Relay // relay class, store all relevant data (equivalent to struct) { public: int buttonPin; // physical pin number of button int relayPin; // physical pin number of relay byte oldValue; // last Values for key (debounce) boolean relayState; // relay status (also stored in EEPROM) }; Relay Relays[noRelays]; Bounce debouncer[noRelays]; MyMessage msg[noRelays]; void setup(){ gw.begin(incomingMessage, RADIO_ID, true); delay(250); gw.sendSketchInfo("MultiRelayButton", "0.9b"); delay(250); // Initialize Relays with corresponding buttons for (int i = 0; i < noRelays; i++){ Relays[i].buttonPin = buttonPin[i]; // assign physical pins Relays[i].relayPin = relayPin[i]; msg[i].sensor = i; // initialize messages msg[i].type = V_LIGHT; debouncer[i] = Bounce(); // initialize debouncer debouncer[i].attach(buttonPin[i]); debouncer[i].interval(5); pinMode(Relays[i].buttonPin, INPUT_PULLUP); pinMode(Relays[i].relayPin, OUTPUT); Relays[i].relayState = gw.loadState(i); // retrieve last values from EEPROM digitalWrite(Relays[i].relayPin, Relays[i].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly gw.send(msg[i].set(Relays[i].relayState? true : false)); // make controller aware of last status gw.present(i, S_LIGHT); // present sensor to gateway delay(250); } } void loop() { gw.process(); for (byte i = 0; i < noRelays; i++){ debouncer[i].update(); byte value = debouncer[i].read(); if (value != Relays[i].oldValue && value == 0){ Relays[i].relayState = !Relays[i].relayState; digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF); gw.send(msg[i].set(Relays[i].relayState? true : false)); gw.saveState( i, Relays[i].relayState );} // save sensor state in EEPROM (location == sensor number) Relays[i].oldValue = value; } } // process incoming message void incomingMessage(const MyMessage &message){ if (message.type == V_LIGHT){ if (message.sensor <noRelays){ // check if message is valid for relays..... previous line [[[ if (message.sensor <=noRelays){ ]]] Relays[message.sensor].relayState = message.getBool(); digitalWrite(Relays[message.sensor].relayPin, Relays[message.sensor].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly gw.saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number) } } }
-
Just tested this sketch and it works. Thank for the effort.
-
Could someone tell what i should to modify to use toggle button not flash button?
-
@maglo18 what do you mean?
-
In yours sketch state button should high next low then relay change state. I want to have possibility after button HIGH relay state change button LOW state relay change again
-
yes , I have same problem.
how can we use simple wall switch with relay to ON and OFF the lights.
-
For learning purposes: Instead of coding it for you, try the line of thought:
Now it changes with the toggle, so if "value" (switch) becomes high is changes the state of the relays, send the message to controller and stores it in EEPROM.
If you use a normal switch, you should change the state if when the "value" changes. So remember the last state of the switch and make it happen
btw :you need a variable to store the last button state and the physical position of the switch does not change if you update the relay switch from the controller..
-
Just wondering any of you guys made progress in normal switch?
-
Hello this is my first post, but i follow my sensors for about 2 months.
Excuse my bad english.For those how want use a normal in wall switch
just change the line:
if (value != Relays[i].oldValue && value == 0){
to
if (value != Relays[i].oldValue){
to
hope this was a bit helpfully
-
@rainair, I tested it and it works! Thanks!!!
-
@jeylites said:
Relays[i].relayState = gw.loadState(i); // retrieve last values from EEPROM
digitalWrite(Relays[i].relayPin, Relays[i].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly
gw.send(msg[i].set(Relays[i].relayState? true : false)); // make controller aware of last status
gw.present(i, S_LIGHT); // present sensor to gateway
delay(250);It's my idea, or shouldn't the sensor be presented to the gateway before sending it status?
Thanks! regards.
-
I don't think it matters. You could try flip "gw.send & gw.present" and see how it respond to the change.
-
Wow ! this is what i was looking for ... Could anyone please share with us some Openhab settings for this wonderful Arduino sketch?
How can we assign in OH buttons to correspond to the physical buttons on the breadboard ?Looking for any answer.
Thanks all!
-
How would I update this to work with 1.6?
-
@Cliff-Karlsson I recently started using 1.6 version, below is converted sketch. It works with momentary (pushbuttons) switches only.
Does anyone have sketch for toggle switches?
#define MY_RADIO_NRF24 #define MY_REPEATER_FEATURE #include <MySensor.h> #include <SPI.h> #include <Bounce2.h> #define RELAY_ON 0 // switch around for relay HIGH/LOW state #define RELAY_OFF 1 // #define noRelays 2 //2-4 const int relayPin[] = {14,15}; // switch around pins to your desire const int buttonPin[] = {3,4}; // switch around pins to your desire class Relay // relay class, store all relevant data (equivalent to struct) { public: int buttonPin; // physical pin number of button int relayPin; // physical pin number of relay byte oldValue; // last Values for key (debounce) boolean relayState; // relay status (also stored in EEPROM) }; Relay Relays[noRelays]; Bounce debouncer[noRelays]; MyMessage msg[noRelays]; void setup(){ sendHeartbeat(); wait(250); // Initialize Relays with corresponding buttons for (int i = 0; i < noRelays; i++){ Relays[i].buttonPin = buttonPin[i]; // assign physical pins Relays[i].relayPin = relayPin[i]; msg[i].sensor = i; // initialize messages msg[i].type = V_LIGHT; debouncer[i] = Bounce(); // initialize debouncer debouncer[i].attach(buttonPin[i]); debouncer[i].interval(5); pinMode(Relays[i].buttonPin, INPUT_PULLUP); //digitalWrite(Relays[i].relayPin, RELAY_OFF); wait(250); pinMode(Relays[i].relayPin, OUTPUT); Relays[i].relayState = loadState(i); // retrieve last values from EEPROM digitalWrite(Relays[i].relayPin, Relays[i].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly send(msg[i].set(Relays[i].relayState? true : false)); // make controller aware of last status wait(250); } } void presentation() { sendSketchInfo("MultiRelayButton", "0.9f"); wait(250); for (int i = 0; i < noRelays; i++) present(i, S_LIGHT); // present sensor to gateway } void loop() { for (byte i = 0; i < noRelays; i++){ debouncer[i].update(); byte value = debouncer[i].read(); if (value != Relays[i].oldValue && value==0){ Relays[i].relayState = !Relays[i].relayState; digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF); send(msg[i].set(Relays[i].relayState? true : false)); saveState( i, Relays[i].relayState );} // save sensor state in EEPROM (location == sensor number) Relays[i].oldValue = value; } } // process incoming message void receive(const MyMessage &message){ if (message.type == V_LIGHT){ if (message.sensor <noRelays){ // check if message is valid for relays..... previous line [[[ if (message.sensor <=noRelays){ ]]] Relays[message.sensor].relayState = message.getBool(); digitalWrite(Relays[message.sensor].relayPin, Relays[message.sensor].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number) } } }
-
The following sketch has got what you're looking for. Hope that helps.
Relay With Actuator Switch Toggle
#include <MySensor.h> #include <SPI.h> #include <Bounce2.h> #define RELAY_ON 0 // switch around for realy HIGH/LOW state #define RELAY_OFF 1 MySensor gw; #define RADIO_ID 11 // Radio ID, whatever channel you assigned to #define noRelays 6 const int relayPin[] = {A0, A1, A2, A3, A4, A5}; const int buttonPin[] = {3, 4, 5, 6, 7, 8}; class Relay // relay class, store all relevant data (equivalent to struct) { public: int buttonPin; // physical pin number of button int relayPin; // physical pin number of relay byte oldValue; // last Values for key (debounce) boolean relayState; // relay status (also stored in EEPROM) }; Relay Relays[noRelays]; Bounce debouncer[noRelays]; MyMessage msg[noRelays]; void setup(){ gw.begin(incomingMessage, RADIO_ID, true); delay(250); gw.sendSketchInfo("MultiRelayButton", "0.9b"); delay(250); // Initialize Relays with corresponding buttons for (int i = 0; i < noRelays; i++){ Relays[i].buttonPin = buttonPin[i]; // assign physical pins Relays[i].relayPin = relayPin[i]; msg[i].sensor = i; // initialize messages msg[i].type = V_LIGHT; debouncer[i] = Bounce(); // initialize debouncer debouncer[i].attach(buttonPin[i]); debouncer[i].interval(5); pinMode(Relays[i].buttonPin, INPUT_PULLUP); pinMode(Relays[i].relayPin, OUTPUT); Relays[i].relayState = gw.loadState(i); // retrieve last values from EEPROM digitalWrite(Relays[i].relayPin, Relays[i].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly gw.send(msg[i].set(Relays[i].relayState? true : false)); // make controller aware of last status gw.present(i, S_LIGHT); // present sensor to gateway delay(250); } } void loop() { gw.process(); for (byte i = 0; i < noRelays; i++){ debouncer[i].update(); byte value = debouncer[i].read(); // if (value != Relays[i].oldValue && value == 0){ if (value != Relays[i].oldValue){ Relays[i].relayState = !Relays[i].relayState; digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF); gw.send(msg[i].set(Relays[i].relayState? true : false)); gw.saveState( i, Relays[i].relayState );} // save sensor state in EEPROM (location == sensor number) Relays[i].oldValue = value; } } // process incoming message void incomingMessage(const MyMessage &message){ if (message.type == V_LIGHT){ if (message.sensor <noRelays){ // check if message is valid for relays..... previous line if [[[ (message.sensor <=noRelays){ ]]] Relays[message.sensor].relayState = message.getBool(); digitalWrite(Relays[message.sensor].relayPin, Relays[message.sensor].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly gw.saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number) } } }
-
@jeylites Thanks, toggle switch works but there is issue when node boots / restarts. On 1st restart relays stay OFF, on 2nd come ON, on 3rd again OFF and so on. It seems that whatever happens during Setup is reversed in Loop. Hopefully someone can point out what should be changed in modified sketch.
#define MY_RADIO_NRF24 #define MY_REPEATER_FEATURE #include <MySensor.h> #include <SPI.h> #include <Bounce2.h> #define RELAY_ON 0 // switch around for realy HIGH/LOW state #define RELAY_OFF 1 // #define noRelays 2 //2-4 const int relayPin[] = {14,15}; // switch around pins to your desire const int buttonPin[] = {3,4}; // switch around pins to your desire class Relay // relay class, store all relevant data (equivalent to struct) { public: int buttonPin; // physical pin number of button int relayPin; // physical pin number of relay byte oldValue; // last Values for key (debounce) boolean relayState; // relay status (also stored in EEPROM) }; Relay Relays[noRelays]; Bounce debouncer[noRelays]; MyMessage msg[noRelays]; void setup(){ sendHeartbeat(); wait(250); // Initialize Relays with corresponding buttons for (int i = 0; i < noRelays; i++){ Relays[i].buttonPin = buttonPin[i]; // assign physical pins Relays[i].relayPin = relayPin[i]; msg[i].sensor = i; // initialize messages msg[i].type = V_LIGHT; debouncer[i] = Bounce(); // initialize debouncer debouncer[i].attach(buttonPin[i]); debouncer[i].interval(5); pinMode(Relays[i].buttonPin, INPUT_PULLUP); //digitalWrite(Relays[i].relayPin, RELAY_OFF); wait(250); pinMode(Relays[i].relayPin, OUTPUT); Relays[i].relayState = loadState(i); // retrieve last values from EEPROM digitalWrite(Relays[i].relayPin, Relays[i].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly send(msg[i].set(Relays[i].relayState? true : false)); // make controller aware of last status wait(250); } } void presentation() { sendSketchInfo("MultiRelayButton", "0.9g"); wait(250); for (int i = 0; i < noRelays; i++) present(i, S_LIGHT); // present sensor to gateway } void loop() { for (byte i = 0; i < noRelays; i++){ debouncer[i].update(); byte value = debouncer[i].read(); if (value != Relays[i].oldValue){ Relays[i].relayState = !Relays[i].relayState; digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF); send(msg[i].set(Relays[i].relayState? true : false)); saveState( i, Relays[i].relayState );} // save sensor state in EEPROM (location == sensor number) Relays[i].oldValue = value; } } // process incoming message void receive(const MyMessage &message){ if (message.type == V_LIGHT){ if (message.sensor <noRelays){ // check if message is valid for relays..... previous line [[[ if (message.sensor <=noRelays){ ]]] Relays[message.sensor].relayState = message.getBool(); digitalWrite(Relays[message.sensor].relayPin, Relays[message.sensor].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number) } } }
these are screenshots from restarts
-
Hi!
I think the problem is you're not initializing oldValue to anything. It will then always be different than value in the loop, and state will change.
You should set oldValue to the same "state" as the loaded relayState in setup. Even better, only use relayState, and make it an int. You can do the same boolean evaluations anyway. 1 is true and 0 is false.
Edit:
Sorry, I forgot that this is a pushbutton, right? Then you should just make sure that oldValue and value are the same after setup is complete, ie HIGH.
-
thanks, I understand what you mean but I don't know how to write it in sketch.
I tried inserting
Relays[i].oldValue = Relays[i].relayState;
at the end of Void Setup section but then sketch wouldn't compile. I get "name lookup of 'i' changed 'for' ISO for scoping [-fpermissive]" error. I get same error if I substitute Relays[i].relayState with loadstate.
-
Put this on a line after pinMode() in setup function.
Relays[i].oldValue = digitalRead(Relays[i].buttonPin);
-
Ok, there is an improvement. Relays now turn to same state as they were before reboot most of the time but not always. Sometimes they inverse - the one which was OFF turns ON and vice-versa. Sometimes (1 in 3) they switch ON and OFF (only for split second) in the loop function. See below screenshots:
This sketch is used with toggle button, same as on this photo.
-
Could be the toggle is still bouncing at read time. Try increasing the debouncer interval. For example, double it until no more issues. Then decrease it in halves of what the last increase was until you see the issue again. This way you can try to find the smallest debounce time needed.
-
@niccodemi You can forget using the oldValue, because the debounce takes track of it's last status. When update() is called and a debounced pin-change is detect this function will return true otherwise it will send false.
Having a short delay each loop will stabilize the debouncers so your loop() can look like this:void loop() { for (byte i = 0; i < noRelays; i++) { if (debouncer[i].update()) { Relays[i].relayState = !Relays[i].relayState; digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF); send(msg[i].set(Relays[i].relayState? true : false)); // save sensor state in EEPROM (location == sensor number) saveState( i, Relays[i].relayState ); } } wait(10); }
-
Why do you think it's better to add the wait than to increase debounce interval? Didn't know update returns a boolean, cool.
-
@martinhjelmare there is no reason to have that many button checks per millisecond, if you "wait" each while loop the MySensors core has more time to process messages i.s.o. of reading I/O pins especially when your node acts as a repeater. (During a wait the process function is called)
A person will not notices a button to take 50 i.s.o 10 milliseconds to respond.
-
Yes, very good point.
-
@martinhjelmare @BartE thank you both for trying to solve this issue but the problem is still there. On reboot relay (usually just 1 never both) gets set randomly in loop function (setup function always restores correct state). I also tried increasing debouncer up to 500 without success. And I am also sure this is not hardware related because if I load sketch which is meant for momentary switch relays work as expected (tested with 10 consecutive reboots). Just to be on the same page this is latest sketch:
//MultiRelayButton Sketch, MySensors 1.6 #define MY_RADIO_NRF24 #define MY_REPEATER_FEATURE #include <MySensor.h> #include <SPI.h> #include <Bounce2.h> #define RELAY_ON 0 // switch around for realy HIGH/LOW state #define RELAY_OFF 1 // #define noRelays 2 //2-4 const int relayPin[] = {14,15}; // switch around pins to your desire const int buttonPin[] = {3,4}; // switch around pins to your desire class Relay // relay class, store all relevant data (equivalent to struct) { public: int buttonPin; // physical pin number of button int relayPin; // physical pin number of relay //byte oldValue; // last Values for key (debounce) boolean relayState; // relay status (also stored in EEPROM) }; Relay Relays[noRelays]; Bounce debouncer[noRelays]; MyMessage msg[noRelays]; void setup(){ sendHeartbeat(); wait(250); // Initialize Relays with corresponding buttons for (int i = 0; i < noRelays; i++){ Relays[i].buttonPin = buttonPin[i]; // assign physical pins Relays[i].relayPin = relayPin[i]; msg[i].sensor = i; // initialize messages msg[i].type = V_LIGHT; debouncer[i] = Bounce(); // initialize debouncer debouncer[i].attach(buttonPin[i]); debouncer[i].interval(100); pinMode(Relays[i].buttonPin, INPUT_PULLUP); wait(250); pinMode(Relays[i].relayPin, OUTPUT); //Relays[i].oldValue = digitalRead(Relays[i].buttonPin); Relays[i].relayState = loadState(i); // retrieve last values from EEPROM digitalWrite(Relays[i].relayPin, Relays[i].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly send(msg[i].set(Relays[i].relayState? true : false)); // make controller aware of last status wait(250); } } void presentation() { sendSketchInfo("MultiRelayButton", "0.9k"); wait(250); for (int i = 0; i < noRelays; i++) present(i, S_LIGHT); // present sensor to gateway wait(250); } void loop() { for (byte i = 0; i < noRelays; i++) { if (debouncer[i].update()) { Relays[i].relayState = !Relays[i].relayState; digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF); send(msg[i].set(Relays[i].relayState? true : false)); // save sensor state in EEPROM (location == sensor number) saveState( i, Relays[i].relayState ); } } wait(50); } // process incoming message void receive(const MyMessage &message){ if (message.type == V_LIGHT){ if (message.sensor <noRelays){ // check if message is valid for relays..... previous line [[[ if (message.sensor <=noRelays){ ]]] Relays[message.sensor].relayState = message.getBool(); digitalWrite(Relays[message.sensor].relayPin, Relays[message.sensor].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number) } } wait(50); }
-
I think you should setup the button first, pinMode etc, and then setup the debouncer and attach it to the button.
https://github.com/thomasfredericks/Bounce2/wiki
If you attach the debouncer while the pin is floating, the debouncer will probably have a hard time figuring out correct new state.
-
That was it. After I amended sketch according to your advise all the random state changes disappeared. I rebooted node over 20 times in various button / relay states and it always started with relays in correct position. For anyone else interested below is amended sketch.
//MultiRelayButton Sketch, MySensors 1.6, toggle switch #define MY_RADIO_NRF24 #define MY_REPEATER_FEATURE #include <MySensor.h> #include <SPI.h> #include <Bounce2.h> #define RELAY_ON 0 // switch around for ACTIVE LOW / ACTIVE HIGH relay #define RELAY_OFF 1 // #define noRelays 2 //2-4 const int relayPin[] = {14,15}; // switch around pins to your desire const int buttonPin[] = {3,4}; // switch around pins to your desire class Relay // relay class, store all relevant data (equivalent to struct) { public: int buttonPin; // physical pin number of button int relayPin; // physical pin number of relay boolean relayState; // relay status (also stored in EEPROM) }; Relay Relays[noRelays]; Bounce debouncer[noRelays]; MyMessage msg[noRelays]; void setup(){ sendHeartbeat(); wait(100); // Initialize Relays with corresponding buttons for (int i = 0; i < noRelays; i++){ Relays[i].buttonPin = buttonPin[i]; // assign physical pins Relays[i].relayPin = relayPin[i]; msg[i].sensor = i; // initialize messages msg[i].type = V_LIGHT; pinMode(Relays[i].buttonPin, INPUT_PULLUP); wait(100); pinMode(Relays[i].relayPin, OUTPUT); Relays[i].relayState = loadState(i); // retrieve last values from EEPROM digitalWrite(Relays[i].relayPin, Relays[i].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly send(msg[i].set(Relays[i].relayState? true : false)); // make controller aware of last status wait(50); debouncer[i] = Bounce(); // initialize debouncer debouncer[i].attach(buttonPin[i]); debouncer[i].interval(20); wait(50); } } void presentation() { sendSketchInfo("MultiRelayButton", "0.9t"); wait(100); for (int i = 0; i < noRelays; i++) present(i, S_LIGHT); // present sensor to gateway wait(100); } void loop() { for (byte i = 0; i < noRelays; i++) { if (debouncer[i].update()) { Relays[i].relayState = !Relays[i].relayState; digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF); send(msg[i].set(Relays[i].relayState? true : false)); // save sensor state in EEPROM (location == sensor number) saveState( i, Relays[i].relayState ); } } wait(20); } // process incoming message void receive(const MyMessage &message){ if (message.type == V_LIGHT){ if (message.sensor <noRelays){ // check if message is valid for relays..... previous line [[[ if (message.sensor <=noRelays){ ]]] Relays[message.sensor].relayState = message.getBool(); digitalWrite(Relays[message.sensor].relayPin, Relays[message.sensor].relayState? RELAY_ON:RELAY_OFF); // and set relays accordingly saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number) } } wait(20); }
-
What is the simplest method to add two extra butons to this sketch not tied to the relay?
I have a four button device. Two will work with relays and two extra utilised in openhab rules
-
Just in case someone else finds this thread and decides to use the sketch and runs in to the same issue I did.
I was using push buttons and the sketch above, when I pushed the button the relay turned on but as soon as I let go of the button the relay turned back off. I changed the sketch like this:
void loop() { for (byte i = 0; i < noRelays; i++) { if (debouncer[i].update()) { int value = debouncer[i].read(); if ( value == LOW) { Relays[i].relayState = !Relays[i].relayState; digitalWrite(Relays[i].relayPin, Relays[i].relayState ? RELAY_ON : RELAY_OFF); send(msg[i].set(Relays[i].relayState ? true : false)); // save sensor state in EEPROM (location == sensor number) saveState( i, Relays[i].relayState ); } } } //wait(20); }
Now the relay changes state as soon as I push the button and keeps the state until I push the button again.
Because my inputs for the push buttons are ground when pushed I used
if ( value == LOW)
This way the relay would turn on immediately when I push the button and not wait until I let go of the button.
-
@korttoma I used this sketch but my vera founds only 1 device and i have no idea why.
-
@ะกัะพัะฝ-ะะตะพัะณะธะตะฒ please post the complete sketch along with info about MySensors library version you are using.