// Modern turn lights v3.1.0 – FIXED + Hazard
#include <FastLED.h>
#define NUM_STRIPS 4
#define NUM_LEDS_PART_A 50
#define NUM_LEDS_PART_B 16
CRGB ledsA[NUM_LEDS_PART_A];
CRGB ledsB[NUM_STRIPS][NUM_LEDS_PART_B];
// INPUT PINS
#define buttonPinL 2
#define buttonPinR 3
#define buttonPinEng 4
#define buttonPinKnightRider 5
#define buttonPinBrake 6
#define buttonPinTailLights 7
#define buttonPinHazard 8
// STATES
volatile int stateLT = 0;
volatile int stateRT = 0;
int buttonStateL, buttonStateR;
int engineOn, KnightRiderState, Brake, TailLights, HazardState;
uint8_t gBrtL = 0, gBrtR = 0;
int halfOfLeds = NUM_LEDS_PART_A / 2;
int leftLeds, rightLeds;
int tailLeft = halfOfLeds - 1;
int tailRight = halfOfLeds;
unsigned long turnColor = 0xff6a00;
// SETTINGS
int maxBrt = 254;
int maxBrtBrake = 254;
int maxBrtTailLights = 70;
int delayTurnLedAnim = 8;
int delayTurnLedOff = 250;
int delayLedToDayLight = 500;
int nrAnimAfterOff = 3;
// ---------------- SETUP ----------------
void setup() {
pinMode(buttonPinL, INPUT_PULLUP);
pinMode(buttonPinR, INPUT_PULLUP);
pinMode(buttonPinEng, INPUT_PULLUP);
pinMode(buttonPinKnightRider, INPUT_PULLUP);
pinMode(buttonPinBrake, INPUT_PULLUP);
pinMode(buttonPinTailLights, INPUT_PULLUP);
pinMode(buttonPinHazard, INPUT_PULLUP);
FastLED.addLeds<NEOPIXEL, 13>(ledsA, NUM_LEDS_PART_A);
FastLED.addLeds<NEOPIXEL, 12>(ledsB[0], NUM_LEDS_PART_B);
FastLED.addLeds<NEOPIXEL, 11>(ledsB[1], NUM_LEDS_PART_B);
FastLED.addLeds<NEOPIXEL, 10>(ledsB[2], NUM_LEDS_PART_B);
FastLED.addLeds<NEOPIXEL, 9>(ledsB[3], NUM_LEDS_PART_B);
attachInterrupt(digitalPinToInterrupt(buttonPinL), btnPressL, FALLING);
attachInterrupt(digitalPinToInterrupt(buttonPinR), btnPressR, FALLING);
FastLED.clear();
FastLED.show();
}
// ---------------- LOOP ----------------
void loop() {
buttonStateL = !digitalRead(buttonPinL);
buttonStateR = !digitalRead(buttonPinR);
HazardState = !digitalRead(buttonPinHazard);
Brake = !digitalRead(buttonPinBrake);
// HAZARD OVERRIDE
if (HazardState) {
stateLT = 1;
stateRT = 1;
}
// STOP INDICATORS WHEN SWITCH OFF
if (!buttonStateL && !HazardState && stateLT >= nrAnimAfterOff) {
stateLT = 0;
gBrtL = 0;
}
if (!buttonStateR && !HazardState && stateRT >= nrAnimAfterOff) {
stateRT = 0;
gBrtR = 0;
}
// -------- HAZARD --------
if (stateLT && stateRT) {
blinkBoth();
}
// -------- LEFT --------
else if (stateLT) {
blinkLeft();
}
// -------- RIGHT --------
else if (stateRT) {
blinkRight();
}
// -------- IDLE --------
else {
tailAndBrake();
FastLED.show();
}
}
// ---------------- FUNCTIONS ----------------
void blinkLeft() {
for (int i = 0; i < NUM_LEDS_PART_B; i++) {
ledsB[0][i] = turnColor;
ledsB[2][i] = turnColor;
ledsA[i] = turnColor;
tailAndBrake();
FastLED.show();
delay(delayTurnLedAnim);
}
FastLED.clear();
FastLED.show();
delay(delayTurnLedOff);
stateLT++;
}
void blinkRight() {
for (int i = 0; i < NUM_LEDS_PART_B; i++) {
ledsB[1][i] = turnColor;
ledsB[3][i] = turnColor;
ledsA[NUM_LEDS_PART_A - 1 - i] = turnColor;
tailAndBrake();
FastLED.show();
delay(delayTurnLedAnim);
}
FastLED.clear();
FastLED.show();
delay(delayTurnLedOff);
stateRT++;
}
void blinkBoth() {
for (int i = 0; i < NUM_LEDS_PART_B; i++) {
for (int s = 0; s < 4; s++) ledsB[s][i] = turnColor;
ledsA[i] = turnColor;
ledsA[NUM_LEDS_PART_A - 1 - i] = turnColor;
tailAndBrake();
FastLED.show();
delay(delayTurnLedAnim);
}
FastLED.clear();
FastLED.show();
delay(delayTurnLedOff);
}
void tailAndBrake() {
if (Brake) {
fill_solid(ledsA, NUM_LEDS_PART_A, CHSV(0, 255, maxBrtBrake));
} else {
fill_solid(ledsA, NUM_LEDS_PART_A, CHSV(0, 255, maxBrtTailLights));
}
}
// ---------------- INTERRUPTS ----------------
void btnPressL() {
stateLT = 1;
}
void btnPressR() {
stateRT = 1;
}