Changing state of a light (Uncle Bob's light switch problem)
Welcome to the world of programming where you never know exactly when you're done because the client doesn't know precisely what they want!

The business solution is to this problem is to first sit down with the client, write down a proposal about some precise interpretation of what should happen. Have the client agree with this interpretation and sign it. Then implement this exactly as proposed.

Then later on when the client tests your code they're either happy (yay, we're done!) or they are not. If they're not you write down what they want to change and make them pay for it again. Happy times! (for you at least, the client doesn't like paying again for something "you should have known" in the first place).

Extra note: sometimes a client asks for something that cannot work. They might only realise the contradiction after you explained what exactly happens and offer them 2 possible ways that achieve 1 of the 2 things they ask for. In such a case you let the client decide which of the 2 is more important.



To write working code we first need to know which exact result we want to get.
Here's the current problem more precisely:

1) If 2 (or more) different switches are flipped within a certain time (half a second) of each other, ignore one of them and change the state of the light.
2) If a switch is flipped twice in rapid succession the second flip should not be ignored.  

Question: If (1) and (2) happen within half a second, should the light change state?

My answer would be: If a switch is flipped once within half a second, the light should change state (compared to half a second earlier) irregardless of other switches.



Solution 1:

One possible solution is to modify the implementation of the switches themselves. If a switch is first in state off, and then flipped on, it will still say it's off for half a second. Only if it has remained on for half a second will it say it's turned on. This solves the problem of flipping the same switch twice in rappid succession ... with the downside that a light state will change at the earliest half a second after a switch is flipped. This is something the client has to agree on.

If the client agrees on that change, the lightLogic can remain exactly the same as in Bob's solution since that correctly handles the remaining requirement of ignoring multiple switches flipping "simultaniously".

This kind of solution is often used to prevent flickering in oversensitive keys. Consider a switch that has a bad contact. If switched halfway, it might rappidly say ON>OFF>ON>OFF even though you only flicked it once. Looking at a change from a small delay before makes sure that it will only fire once in such cases as intended.



Solution 2:

Alternatively if you require that the light switches on immediatly after a single switch is flipped, you'll have to do it differently.

Let's say the light is switched from off to on. For the next 500 milliseconds, under which condition should the light be switched back off? -> If ALL switches are back to what they were when the light was still off.

This looks similar to your idea, but only looking at the penultimate state isn't enough. If switch A is flipped, and then switch B is flipped 4 times, the light should still be ON because of switch A.

An idea would be like this (note not tested):

int currentTime = millis();
if (currentTime - lastChangeTime &lt;= 500) { // might be considered simultanious
    if(currentSwitchState == initialSwitchState) { //all switches back to initial state
        light.state = initialLightState;
        lastChangeTime = 0; //respond to any new flip after this as if it was new.
    } // else light stays as it is now
} else {
    if (currentSwitchState != previousSwitchState) { // start new case
        light.state = !light.state;
        lastChangeTime = currentTime;
        initialSwitchState = previousSwitchState;
    } // else nothing changed
}
previousSwitchState = currentSwitchState; //always update latest known state