Two way lighting circuit - anything I need to be aware of?

wolframore:
Looks like Proteus :smiley:

EasyEda :slight_smile:

oh that's the one i sneak at work... i thought it looked familiar. It's not bad and has good library.

It's awesome for huge online library, but at the same time sucks for being online :slight_smile:

Also it becomes a bit slow, I think I'm close to the limit with this design:

We are clustering this mans thread, sorry about that :smiley:

3Dgeo:
We are clustering this mans thread, sorry about that :smiley:

I think it could be forgiven, he did ask what you were using so he's looking for an EDA solution.

I wish I could get the library from this into Proteus.

Hm, forum act strange, deleted my reply, anyway – I totally missed that red text :smiley:

I'm using EasyEDA www.easyeda.com – it's online software, simple, easy to use, huge library. There might be better options, but it do everything I need it to do, I'm only a hobbyist, so I don't miss advance features other softwares might have.

@3Dgeo many thanks for the updated information, it's a little overwhelming starting the code but I will have a go over the next few days and post back if that's ok?

:slight_smile: :slight_smile:

877:
@3Dgeo many thanks for the updated information, it's a little overwhelming starting the code but I will have a go over the next few days and post back if that's ok?

:slight_smile: :slight_smile:

It's totally fine, you don't own me anything :smiley:

Apart of a WIFI stuff the code is simple:

const byte RELAY_Pin = D5; // define your relay pins here
const byte SWITCH_Pin = D6; // define your buttons pins here
 
void setup() 
{
 
  pinMode(RELAY_Pin , OUTPUT);
  digitalWrite(RELAY_Pin, LOW);
  pinMode(SWITCH_Pin, INPUT);
  attachInterrupt(digitalPinToInterrupt(SWITCH_Pin), flipRelayOutput, CHANGE); // making I/O pin as interrupt pin and looking for pin to change from high to low or low to high
 
}
 
void flipRelayOutput() 
{
  digitalWrite(RELAY_Pin, !digitalRead(RELAY_Pin));
  delay(50); // this delay is for debouncing, if it acts strange – increase delay
}
 


void loop() 

{
 
// here is empty cos everything is handled by interrupt
 
}

The fun part of implementing WIFI stuff I'm leaving to you :smiley:

To whom that is a code nazi – yes, I know delays are not recommended on interrupts, sue me :stuck_out_tongue:
If code doesn't work you have to trouble shoot it and make it work with D1 mini.

I should also mention my concerns on ESD or inductance of a long wire, now I'm not an expert on this subject, but it would be helpful if someone that is share his opinion – is it a potential problem? How to solve it if it is – low voltage zener diode, low value low current resistor as a fuse, both?

3Dgeo:
The fun part of implementing WIFI stuff I'm leaving to you :smiley:

To whom that is a code nazi – yes, I know delays are not recommended on interrupts, sue me :stuck_out_tongue:
If code doesn't work you have to trouble shoot it and make it work with D1 mini.

I should also mention my concerns on ESD or inductance of a long wire, now I'm not an expert on this subject, but it would be helpful if someone that is share his opinion – is it a potential problem? How to solve it if it is – low voltage zener diode, low value low current resistor as a fuse, both?

Thanks so much for the code! I just spent around 2hrs reading and putting together some code, yours is so elegant and simple I am truly embarrassed :slight_smile:

You are also correct, the delay is quite unpredictable, I am guessing I need to use the switch debounce code and integrate it. I'll do some reading tomorrow as it's family time for now..

Re: inductance, it could be a problem as I can only run the 3.3V cables alongside mains 230V due to the limited space, I would perhaps use screened alarm cable. If there is a solution such as diode etc. i would be most interested!

Again many thanks 3Dgeo :slight_smile: :slight_smile:

877:
Thanks so much for the code! I just spent around 2hrs reading and putting together some code, yours is so elegant and simple I am truly embarrassed :slight_smile:

You are also correct, the delay is quite unpredictable, I am guessing I need to use the switch debounce code and integrate it. I'll do some reading tomorrow as it's family time for now..

Re: inductance, it could be a problem as I can only run the 3.3V cables alongside mains 230V due to the limited space, I would perhaps use screened alarm cable. If there is a solution such as diode etc. i would be most interested!

Again many thanks 3Dgeo :slight_smile: :slight_smile:

No problem, I was noob as well, people helped me in this same forum with my noob problems, it's nice to pass knowledge I gain to someone that needs them. Tho I might harm you cos now you don't have chance to research, experiment and learn from your mistakes :slight_smile:

Delay might be too long, try to reduce it to 5 or less or remove entirely (share what behavior you are getting), I don't know how D1 mini understands or executes delay function, there's a chance to learn for you :slight_smile: I think delay should be enough for your project, at least until you get more experience and can understand "BlinkWhitouDelayt" default Arduino IDE example, it will probably not work on D1 out of the box, but it's a way to avoid delay but still do software debounce. You can always do hardware debounce Google it... :wink:

Correct Zener diode connected between ground and switches input should protect input pin from voltage above zener voltage (don't know if it's correct therm and too lazy to google it :D) , but it will not protect from false triggering input pin, right low value ceramic capacitor should, it also should act as a switch debauncer, but I can't tell you anything more cos as I said my knowledge on this topic is limited.

P.S. "family time", pfff, I haven't heard this Pokemon :smiley:

wolframore:
I’ve always hated the way light switches that both point up when off. It would be nice to make them one latching button with a status light.

The newer type of press button switch from Clipsal will allow that.

CAT3 and CAT5 are shielded telecom cable. The stuff is too thin for me to solder, the thing to use there is telecom wire splices such as 3M Skotchlok that are also good for thin car harness wiring. Those are what the pros use, fast and sure. Just make sure the size you get will let you splice a 22 ga jumper-thick wire to that 24 ga or smaller CAT wire.

I look at what you have in place and try to figure how to have lights control lay over that with the fewest changes. What I can figure is to run other power than what comes through the 2 switches then isolate the switch wiring (each switch pole is wired to the opposite pole of the other switch in series, AND logic, then both paths are connected in parallel, OR logic, so that if either path is complete the light goes on... right? So you cut that wiring from AC and use it for the Arduino to sense the composite state of the switches and you power the lights through the relay and manual switch OR-wired to it.

I was in school mostly in the ancient times BC, Before Calculators though saw them in the last 2 years. We learned to wire logic not just AND-series and OR-parallel but flip flops and up to octal buffers. It ran at human hand speed but it was logic without transistors and it does work, those light switches that are ON whenever the switches are opposite (XOR logic) are an example.

As an electrician, can you get into having the controls run on signal level instead of carrying the power as the signal? I'm thinking that the power runs to outlets and lights could be shorter in many cases.

3Dgeo:
No problem, I was noob as well, people helped me in this same forum with my noob problems, it's nice to pass knowledge I gain to someone that needs them. Tho I might harm you cos now you don't have chance to research, experiment and learn from your mistakes :slight_smile:

Delay might be too long, try to reduce it to 5 or less or remove entirely (share what behavior you are getting), I don't know how D1 mini understands or executes delay function, there's a chance to learn for you :slight_smile: I think delay should be enough for your project, at least until you get more experience and can understand "BlinkWhitouDelayt" default Arduino IDE example, it will probably not work on D1 out of the box, but it's a way to avoid delay but still do software debounce. You can always do hardware debounce Google it... :wink:

Correct Zener diode connected between ground and switches input should protect input pin from voltage above zener voltage (don't know if it's correct therm and too lazy to google it :D) , but it will not protect from false triggering input pin, right low value ceramic capacitor should, it also should act as a switch debauncer, but I can't tell you anything more cos as I said my knowledge on this topic is limited.

P.S. "family time", pfff, I haven't heard this Pokemon :smiley:

Thanks 3Dgeo! I really appreciate the help.

Don't worry I am making plenty of mistakes, I'm always sure to understand as much code as possible rather than copy/paste. Sometimes it is good to have a hint of where to start, sometime a large hint is required :slight_smile:

I've tried various delay values from 10 to 1000, it seems to have no effect. When I press the button it turns the relay on, but it does not latch in it's new state most times (maybe it will flip states every ten presses). Most times when I press button relay turns on, I let go of button and relay goes off (like a normal push button).

No worries though, I did some reading on interrupt pins and debouncing, and found some code which I added to your above code, it seems to work fine:

const byte RELAY_Pin = D6; // define your relay pins here
const byte SWITCH_Pin = D5; // define your buttons pins here
 
void setup() 
{
 
  pinMode(RELAY_Pin , OUTPUT);
  digitalWrite(RELAY_Pin, LOW);
  pinMode(SWITCH_Pin, INPUT);
  attachInterrupt(digitalPinToInterrupt(SWITCH_Pin), flipRelayOutput, CHANGE); // making I/O pin as interrupt pin
 
}
 

void flipRelayOutput()
{
  
 static unsigned long last_interrupt_time = 0;
 unsigned long interrupt_time = millis();
 
 if (interrupt_time - last_interrupt_time > 500) // If interrupts come faster than time in ms, assume it's a bounce and ignore
 {
   digitalWrite(RELAY_Pin, !digitalRead(RELAY_Pin));
 }
 last_interrupt_time = interrupt_time;
 
}

 
void loop() 

{
 
// here is empty cos everything is handled with interrupt
 
}

Next, to add Blynk support. I am going to look at hardware debounce for sure as well!

Yes families :slight_smile: A rare and sometime troublesome Pokemon indeed :slight_smile: :slight_smile:

GoForSmoke:
CAT3 and CAT5 are shielded telecom cable. The stuff is too thin for me to solder, the thing to use there is telecom wire splices such as 3M Skotchlok that are also good for thin car harness wiring. Those are what the pros use, fast and sure. Just make sure the size you get will let you splice a 22 ga jumper-thick wire to that 24 ga or smaller CAT wire.

I look at what you have in place and try to figure how to have lights control lay over that with the fewest changes. What I can figure is to run other power than what comes through the 2 switches then isolate the switch wiring (each switch pole is wired to the opposite pole of the other switch in series, AND logic, then both paths are connected in parallel, OR logic, so that if either path is complete the light goes on... right? So you cut that wiring from AC and use it for the Arduino to sense the composite state of the switches and you power the lights through the relay and manual switch OR-wired to it.

I was in school mostly in the ancient times BC, Before Calculators though saw them in the last 2 years. We learned to wire logic not just AND-series and OR-parallel but flip flops and up to octal buffers. It ran at human hand speed but it was logic without transistors and it does work, those light switches that are ON whenever the switches are opposite (XOR logic) are an example.

As an electrician, can you get into having the controls run on signal level instead of carrying the power as the signal? I'm thinking that the power runs to outlets and lights could be shorter in many cases.

Hey GoForSmoke,

Yes that's what I though would be easier, just utilise the existing 2way switch wiring for the arduino control, then have the 230V live and switched live going to the relay output. In parallel with the relay wire a backup switch in case the relay/arduino fails.

I've still got some CAT5 cable left over from when I rewired my house, I could easily replace the existing wiring/switches with buttons, or maybe buy some shielded twisted pair alarm cable.

I am still a little unsure if interference from adjacent 230V wiring will be an issue, 3Dgeo suggested capacitors which looks like a good fix. Possibly diode?

Thanks :slight_smile:

You have other 230V wiring adjacent to the light wiring? And it's in place....

Maybe the best thing right off is to find out how much effect there is, make a mini-project to measure signals on the circuit.

Shielding does not have to be solid, a grounded conductive mesh can make a Faraday Cage. If you could shield the power wiring it's effects would not spread.

The strength of EMF falls off with the cube of distance. Wire twice as far from source will get 1/8th the effect.

Once the switches are sensed by the controller that also switches power you can have lots of switches, all kinds.

I'm guessing that the extra copper of power wires to the light switches isn't worth replacing on a better used elsewhere basis?

GoForSmoke:
You have other 230V wiring adjacent to the light wiring? And it's in place....

Yes it's already in place, I'll give a try first I think and see if there's any issues.

I've been working on the code, still learning a lot but I got the Blynk app virtual led to follow the state of the relay with this code:

#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

char auth[] = ""; //Enter the Auth code which was send by Blink

char ssid[] = "";  //Enter your WIFI Name
char pass[] = "";  //Enter your WIFI Password


const byte RELAY_Pin = D6; // define your relay pins here
const byte SWITCH_Pin = D5; // define your buttons pins here
WidgetLED LED(V6);  // define virtual pin used for LED on Blynk app



void flipRelayOutput()
{
    static unsigned long last_interrupt_time = 0;
    unsigned long interrupt_time = millis();
 
 if (interrupt_time - last_interrupt_time > 250) // If interrupts come faster than time in ms, assume it's a bounce and ignore
 {
    digitalWrite(RELAY_Pin, !digitalRead(RELAY_Pin));
     }
 last_interrupt_time = interrupt_time;
 }



void setup() 
{
 
  pinMode(RELAY_Pin , OUTPUT);
  digitalWrite(RELAY_Pin, LOW);
  pinMode(SWITCH_Pin, INPUT);

  attachInterrupt(digitalPinToInterrupt(SWITCH_Pin), flipRelayOutput, CHANGE); // making I/O pin as interrupt pin

  Blynk.begin(auth, ssid, pass);
   
}



 
void loop()
{
  Blynk.run();


  byte output = digitalRead(RELAY_Pin);   //set "output" to the same state of relay output pin D6
   
  if (output == HIGH)
  {
   LED.on();
  }
   else
   LED.off();
   
 }

Next I want to add control of the relay via a virtual button V5 in the Blynk ap (so that either the physical button or the virtual button flip the relay state).
Below is my work in progress code. V5 should trigger the flipRelayOutput function, but it's doing nothing when I press the button on the app.
BLYNK_WRITE does not work in void loop due to spamming their servers (according to their website).

Update, got it working after noticing my mistake, if anyone could have a look and see what they think of the code?

Any suggestions to tidy it up/make more efficient?
Should LED on/off code in void loop be in it's own function?

Thanks :slight_smile:

#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space


#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>


char auth[] = ""; //Enter the Auth code which was send by Blink

char ssid[] = "";  //Enter your WIFI Name
char pass[] = "";  //Enter your WIFI Password

const byte RELAY_Pin = D6; // define your relay pins here
const byte SWITCH_Pin = D5; // define your buttons pins here
WidgetLED LED(V6);  // define virtual pin used for LED on Blynk app


void flipRelayOutput()
{
    static unsigned long last_interrupt_time = 0;
    unsigned long interrupt_time = millis();
 
 if (interrupt_time - last_interrupt_time > 250) // If interrupts come faster than time in ms, assume it's a bounce and ignore
 {
    digitalWrite(RELAY_Pin, !digitalRead(RELAY_Pin));
     }
 last_interrupt_time = interrupt_time;
 }


BLYNK_WRITE(V5)
{
  int pinValue = param.asInt(); // assigning incoming value from pin V1 to a variable

  Serial.println(pinValue);

  if (pinValue = 1)
  {
    flipRelayOutput();
  }

}

 
void setup() 
{
  Serial.begin(115200); // See the connection status in Serial Monitor
  Blynk.begin(auth, ssid, pass);
  
  pinMode(RELAY_Pin , OUTPUT);
  digitalWrite(RELAY_Pin, LOW);
  pinMode(SWITCH_Pin, INPUT);

  attachInterrupt(digitalPinToInterrupt(SWITCH_Pin), flipRelayOutput, CHANGE); // making I/O pin as interrupt pin
     
}


void loop()
{
  Blynk.run();

  byte output = digitalRead(RELAY_Pin);   //set "output" to the same state of relay output pin D6
   
  if (output == HIGH)
  {
   LED.on();
  }
   else
   LED.off();
   
 }

877:
No worries though, I did some reading on interrupt pins and debouncing, and found some code which I added to your above code, it seems to work fine: ...

Hey,

good work, you implemented "blink without delay" method (from what you wrote I think delay() didn't work on D1 mini). My head does not work today, but I think code should look like this:

const byte RELAY_Pin = D6; // define your relay pins here
const byte SWITCH_Pin = D5; // define your buttons pins here

static unsigned long last_interrupt_time = 0;

void setup()
{

  pinMode(RELAY_Pin , OUTPUT);
  digitalWrite(RELAY_Pin, LOW);
  pinMode(SWITCH_Pin, INPUT);
  attachInterrupt(digitalPinToInterrupt(SWITCH_Pin), flipRelayOutput, CHANGE); // making I/O pin as interrupt pin

}


void flipRelayOutput()
{

  unsigned long interrupt_time = millis();

  if (interrupt_time - last_interrupt_time > 500) // If interrupts come faster than time in ms, assume it's a bounce and ignore
  {
    last_interrupt_time = interrupt_time;

    digitalWrite(RELAY_Pin, !digitalRead(RELAY_Pin));
  }
}


void loop()

{

  // here is empty cos everything is handled with interrupt

}

I can't comment on Wifi stuff, cos I never used iOS, but my suggestion would be to remove relay code and hardware for now and focus only on wifi code, try to blink on board D1 mini LED with wifi. I can help you with data processing code if you can get any data to Arduino from your virtual button. Can you link it how it works? What data is being sent?

For a start you need to let Arduino know that virtual button was pressed, you don't have to worry if it on or off state at this point.

3Dgeo:
Hey,

good work, you implemented "blink without delay" method (from what you wrote I think delay() didn't work on D1 mini). My head does not work today, but I think code should look like this:

I can't comment on Wifi stuff, cos I never used iOS, but my suggestion would be to remove relay code and hardware for now and focus only on wifi code, try to blink on board D1 mini LED with wifi. I can help you with data processing code if you can get any data to Arduino from your virtual button. Can you link it how it works? What data is being sent?

For a start you need to let Arduino know that virtual button was pressed, you don't have to worry if it on or off state at this point.

Thanks 3Dgeo, I did have to do some reading and tried a few solutions.

Re: the wifi, I actually got it working fine, with both Blynk app and button :slight_smile:
This is the code, what do you think?
Any improvements?

#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>


char auth[] = ""; //Enter the Auth code which was send by Blink

char ssid[] = "";  //Enter your WIFI Name
char pass[] = "";  //Enter your WIFI Password

const byte RELAY_Pin = D6; // define your relay pins here
const byte SWITCH_Pin = D5; // define your buttons pins here
WidgetLED LED(V6);  // define virtual pin used for LED on Blynk app


void flipRelayOutput()
{
    static unsigned long last_interrupt_time = 0;
    unsigned long interrupt_time = millis();
 
 if (interrupt_time - last_interrupt_time > 250) // If interrupts come faster than time in ms, assume it's a bounce and ignore
 {
    digitalWrite(RELAY_Pin, !digitalRead(RELAY_Pin));
     }
 last_interrupt_time = interrupt_time;
 }


BLYNK_WRITE(V5)
{
  int pinValue = param.asInt(); // assigning incoming value from pin V1 to a variable

  // Serial.println(pinValue); //optional print V5 pin value to terminal

  if (pinValue = 1)
  {
    flipRelayOutput();
  }

}

 
void setup() 
{
  Serial.begin(115200); // See the connection status in Serial Monitor
  Blynk.begin(auth, ssid, pass);
  
  pinMode(RELAY_Pin , OUTPUT);
  digitalWrite(RELAY_Pin, LOW);
  pinMode(SWITCH_Pin, INPUT);

  attachInterrupt(digitalPinToInterrupt(SWITCH_Pin), flipRelayOutput, CHANGE); // making I/O pin as interrupt pin
     
}


void loop()
{
  Blynk.run();

  byte output = digitalRead(RELAY_Pin);   //set "output" to the same state of relay output pin D6
   
  if (output == HIGH)
  {
   LED.on();
  }
   else
   LED.off();
   
 }

Well, first thing – you didn't change code as I recommended, it's important, cos now your debouncing doesn't work as it should.

What comes to wifi code, I don't know what LED.on() and LED.off() do under the hood, but you shouldn't have to use any "IF" conditions in your code cos all you need to do is to invert current light state or send current state back to device, there's no need for "IFs" to do that.
But if it works as you want it to work, I guess it will do :slight_smile:

3Dgeo:
Well, first thing – you didn't change code as I recommended, it's important, cos now your debouncing doesn't work as it should.

What comes to wifi code, I don't know what LED.on() and LED.off() do under the hood, but you shouldn't have to use any "IF" conditions in your code cos all you need to do is to invert current light state or send current state back to device, there's no need for "IFs" to do that.
But if it works as you want it to work, I guess it will do :slight_smile:

Hey, sorry I didn't change code as you recommended, I misunderstood I think what you mean. :confused:

I am able to get data sent from the virtual button to the Arduino with this part of the code:

BLYNK_WRITE(V5)                   //write data from virtual pin V5 to the Arduino
{
  int pinValue = param.asInt(); // assigning incoming value from pin V5 to a variable called pinValue

  // Serial.println(pinValue);     //optional print V5 pin value to terminal - (shows 1 or 0 output)

  if (pinValue = 1)                   // if virtual button is pressed, pinValue becomes logic 1 
  {
    flipRelayOutput();              // if value is logic 1, run the flipRelayOutput function
  }

}

Is this what you mean? I'm not sure why this would affect debouncing?

The LED.on() is part of the Blynk library and is quickly described HERE.

I can see that it's better to invert the output, but I am struggling to understand how. I will think more about it.

Many thanks for your help 3Dgeo :slight_smile: :slight_smile:

Hopefully I am on the right path?

Doing some more research, I have the following code which gets rid of the "if" "else" in the void loop. But..the virtual LED required a value from 0 (OFF) to 255(FULLY ON).

But my code send a 0 or 1.

I wonder if there is a way to convert a logic one to a 255?
More reading required :slight_smile:

void flipRelayOutput()
{
    static unsigned long last_interrupt_time = 0;
    unsigned long interrupt_time = millis();
 
 if (interrupt_time - last_interrupt_time > 250) // If interrupts come faster than time in ms, assume it's a bounce and ignore
 {
    digitalWrite(RELAY_Pin, !digitalRead(RELAY_Pin));   //writes the inverse value to the relay pin
    byte ledoutput = digitalRead(RELAY_Pin);            //
    Blynk.virtualWrite(V6, ledoutput);                  //
    Serial.println(ledoutput);                          //optional print V6 pin value to terminal
      
     }
 last_interrupt_time = interrupt_time;
 }