/*
Forum: https://forum.arduino.cc/t/led-runner-chasser-with-hc-05-till-off-button-pressed/1421148
Wokwi: https://wokwi.com/projects/451148665794671617
2025/12/23
ec2021
Effect "blink all" and function blinkAll() added
*/
struct myLights {
byte pin;
char name[20];
};
enum LIGHTS {
light13 = 4,
light14 = 5,
light15 = 6,
streetL1 = 7,
streetL2 = 8,
poolL = 9,
carparkL = 11,
profileL = 12
};
myLights lights[] = {
{light13, "light 13"},
{light14, "light 14"},
{light15, "light 15"},
{streetL1, "street light one"},
{streetL2, "street light two"},
{poolL, "pool light"},
{carparkL, "carpark light"},
{profileL, "profile light"}
};
constexpr int noOfLights = sizeof(lights) / sizeof(lights[0]);
char effects[][20] = {
"light up",
"central light on",
"light down",
"central light off",
"blink all"
};
constexpr int noOfEffects = sizeof(effects) / sizeof(effects[0]);
boolean msgComplete = false;
String command;
int runEffectNo = -1;
void setup() {
Serial.begin(9600);
Serial.println("Start");
Serial.println(noOfLights);
command.reserve(40);
command = "";
for (int i = 0; i < noOfLights; i++) {
pinMode(lights[i].pin, OUTPUT );
}
setAllLightsTo(LOW);
delay (2000);
setAllLightsTo(HIGH);
}
void loop() {
if ( commandReceived()) {
Serial.println (command);
evaluateCommand();
}
runEffects();
}
boolean commandReceived() {
if (Serial.available()) {
char jos = Serial.read();
if (jos >= ' ') {
command += jos;
} else {
command.toLowerCase();
return true;
}
}
return false;
}
void evaluateCommand() {
if (!isDirectCommand()) {
checkEffectCommand();
};
command = "";
}
boolean isDirectCommand() {
boolean cmdFound = false;
int lightNo = 0;
while (!cmdFound && lightNo < noOfLights) {
if (command.startsWith(lights[lightNo].name)) {
cmdFound = true;
} else {
lightNo++;
}
}
if (cmdFound) {
if (command.endsWith("on")) {
digitalWrite(lights[lightNo].pin, LOW);
}
if (command.endsWith("off")) {
digitalWrite(lights[lightNo].pin, HIGH);
}
runEffectNo = -1;
}
return cmdFound;
}
void checkEffectCommand() {
boolean cmdFound = false;
int effectNo = 0;
while (!cmdFound && effectNo < noOfEffects) {
if (command.startsWith(effects[effectNo])) {
cmdFound = true;
} else {
effectNo++;
}
}
if (cmdFound) {
runEffectNo = effectNo;
}
}
void setAllLightsTo(byte aState) {
for (int i = 0; i < noOfLights; i++) {
digitalWrite(lights[i].pin, aState);
}
}
void runEffects() {
if (runEffectNo < 0) {
return;
}
switch (runEffectNo) {
case 0: // light up
lightUp();
break;
case 1: // central light on
centralLightOn();
break;
case 2: // light down
case 3: // central light off
lightDown();
break;
case 4: //blink all
blinkAll();
break;
}
}
void centralLightOn() {
setAllLightsTo(LOW);
runEffectNo = -1;
}
void blinkAll() {
static int count = 0;
if (count > 10) {
count = 0;
runEffectNo = -1;
} else {
count++;
setAllLightsTo(LOW);
delay(300);
setAllLightsTo(HIGH);
delay(300);
if (breakOnSerial()) {
return;
}
}
}
void lightDown() {
setAllLightsTo(HIGH);
runEffectNo = -1;
}
void lightUp() {
if (!FirstDone()) {
return;
}
if (!SecondDone()) {
return;
}
if (!ThirdDone()) {
return;
}
runEffectNo = -1;
}
boolean FirstDone() {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < noOfLights / 2; j++) {
switchPair(j, noOfLights - j - 1, 200);
if (breakOnSerial()) {
return false;
};
}
for (int j = 1; j < noOfLights / 2; j++) {
switchPair(noOfLights - j - 1, j, 200);
if (breakOnSerial()) {
return false;
};
}
delay (10);
}
return true;
}
boolean SecondDone() {
for (int i = 0; i < 2; i++) {
for (int j = 0; j < noOfLights; j++) {
switchSingle(j, 500);
if (breakOnSerial()) {
return false;
};
}
for (int j = 0; j < noOfLights; j++) {
switchSingle(noOfLights - j - 1, 500);
if (breakOnSerial()) {
return false;
};
}
delay(90);
}
return true;
}
boolean ThirdDone() {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < noOfLights; j++) {
switchSingle(j, 300);
if (breakOnSerial()) {
return false;
};
}
delay(300);
for (int j = 0; j < noOfLights; j++) {
switchSingle(noOfLights - j - 1, 300);
if (breakOnSerial()) {
return false;
};
}
delay(10);
}
return true;
}
void switchSingle(byte lOne, uint16_t dly) {
digitalWrite(lights[lOne].pin, LOW);
delay(dly);
digitalWrite(lights[lOne].pin, HIGH);
}
void switchPair(byte lOne, byte lTwo, uint16_t dly) {
digitalWrite(lights[lOne].pin, LOW);
digitalWrite(lights[lTwo].pin, LOW);
delay(dly);
digitalWrite(lights[lOne].pin, HIGH);
digitalWrite(lights[lTwo].pin, HIGH);
}
boolean breakOnSerial() {
if (Serial.available()) {
setAllLightsTo(HIGH);
runEffectNo = -1;
return true;
}
return false;
}