/*
Motorcycle Top Box Brake And Turn Signal Lights
Original Code from David Kissick https://www.instructables.com/DIY-Givi-V56-Motorcycle-Topbox-Light-Kit-With-Inte/
Updated for use with a Givi B47 topbox, with 2 strips of 6 LEDs.
Changes:
To reflect the number of LEDs
The B47 has clear lenses instead of red, so colours are updated for brake lights and indicators (turn signals)
Change to the turn signal sequence as the LED strips are positioned vertically rather than horizontally.
*/
// FastLED - Version: Latest
#include <FastLED.h>
#define LED_TYPE WS2811
#define NUM_LEDS 6 // Define the number of LEDs in each strip.
#define NUM_STRIPS 2 // Define the number of LED strips being used.
#define bright 255 // Define the level for bright
#define dim 80 // Define the level for dim
// The following code uses white color as that should be the brightest. It could be changed to other colors as well if needed.
// Define Full brightness, max 255
#define r bright
#define g 0
#define b 0
// Define low brightness
#define r2 dim
#define g2 0
#define b2 0
#define Red_high CRGB(r, g, b) // Define high brightness state
#define Red_dim CRGB(r2, g2, b2) // Define dim brightness state
#define Amber CRGB(255, 90, 0)
enum side {
left,
right,
both
};
CRGB leds[NUM_STRIPS][NUM_LEDS]; // Sets up the array to be used for setting LED colors and outputs. Although
// 16 LEDs are in the strip, the box only has 6 openings, so only 6 LEDs will be
// seen. The two LEDs in between each active LED will be kept dark.
// Constants
const int brakeLight = 4; // Pin to measure the brake light signal
const int leftTurn = 5; // Pin to measure the left turn signal
const int rightTurn = 6; // Pin to measure the right turn signal
const int lightDelay = 6; // Allows adjusting the delay between light flashes for signals in units of 100ms.
// Note that this delay should be longer than the actual delay for the off time between flashes.
// Variables
int scrollDelay = 50; // Timing between lighting lights for turn signals in milliseconds
// variables for color brightness calculations
int rt = 0; // Temp red
int gt = 0; // Temp green
int bt = 0; // Temp blue
bool brakeOnWhenStoppedIndicating = false;
void setup() {
FastLED.addLeds<WS2812B, 2, GRB>(leds[0], NUM_LEDS); // This sets up the left strip to use Pin 4 using the leds aray (defined earlier) +
// with the NUM_LEDS defining the number of LEDs in the strip.
FastLED.addLeds<WS2812B, 3, GRB>(leds[1], NUM_LEDS); // This sets up the right strip in the same manner but using Pin 6
FastLED.clear(); // Make sure all LEDs are turned off for initial setup.
// Setup Input pins
pinMode(brakeLight, INPUT);
pinMode(leftTurn, INPUT);
pinMode(rightTurn, INPUT);
// Startup Sequence - because why not.
delay(200); // Delay to allow power to stabilize.
// This sequence will light up one LED at a time and move down the chain Knight Rider style, but ending when it reaches to other end.
for (int i = 0; i < NUM_LEDS; i++) { // This will change the light for every third LED going from the last to first.
leds[0][i] = Red_dim; // Set strip 0 LED color to the chosen color.
leds[1][i] = Red_dim; // Set strip 1 LED color to the chosen color.
FastLED.show(); // Show the set colors.
leds[0][i] = CRGB::Black; // Turn off set color in prep for next color.
leds[1][i] = CRGB::Black;
delay(150);
}
FastLED.show(); // Output the last LED color to turn off remaining LED.
delay(100);
// This sequence will solidly light up the strip one LED at a time in the opposite direction.
for (int i = NUM_LEDS - 1; i > -1; i--) { // This will change the light for every third LED going from the last to first.
leds[0][i] = Red_dim; // Set strip 0 LED color to the chosen color.
leds[1][i] = Red_dim; // Set strip 1 LED color to the chosen color.
FastLED.show(); // Show the set colors.
delay(150);
}
for (int i = 0; i < dim + 1; i++) { // Gradually fade the light to off.
rt = r - i;
//gt = g - i;
//bt = b - i;
for (int j = -1; j < NUM_LEDS; j++) { // This will change the light for every third LED going from the last to first.
leds[0][j] = CRGB(dim - i, 0, 0); // Set strip 0 LED color to the chosen color.
leds[1][j] = CRGB(dim - i, 0, 0); // Set strip 1 LED color to the chosen color.
}
FastLED.show();
delay(10);
}
delay(300);
for (int i = 0; i < dim; i++) { // Quickly fade lights to running light level.
rt = rt + 1;
//gt = gt + 1;
//bt = bt + 1;
for (int i = 3; i < 6; i++) { // This will light up the last three lights for the position light.
leds[0][i] = CRGB(rt, 0, 0); // Set strip 0 LED color to the chosen color.
leds[1][i] = CRGB(rt, 0, 0); // Set strip 1 LED color to the chosen color.
}
FastLED.show();
delay(10);
}
}
void loop() {
/* The idea behind the code is the following. While there is power to the arduino, the upper three lights will be in running light mode
or the dim output when no signals are active. This allows the bike to be visible at all times. There was no need to use a
signal wire for this since we want it on anytime the bike is on. When the brake light is active, then all lights on both light strips will
go to full brightness. When a turn signal is on, the side not blinking will either be dim or full bright if the brake is on.
The turn signal will light up one at a time in the direction of the turn at full brightness with each blink of the main signal. This will make
the turn signal more noticeable. For hazards, both strips will blink full on and full off again fore more noticeable view.
*/
if (digitalRead(brakeLight) == HIGH) { // If brake light is on, set strips to brake light state and blink
if (!brakeOnWhenStoppedIndicating) {
for (int i = 0; i < NUM_LEDS; i++) { // Turn every LED on
leds[0][i] = Red_high; // Set strip 0
leds[1][i] = Red_high; // Set strip 1
}
FastLED.show(); // Output settings
delay(300); // Delay is used because I want the brake like flash forced instead of using timing.
for (int i = 0; i < NUM_LEDS; i++) { // Turn every every LED off
leds[0][i] = CRGB(0, 0, 0); // Set strip 0
leds[1][i] = CRGB(0, 0, 0); // Set strip 1
}
FastLED.show(); // Output settings
delay(300);
}
brakeOnWhenStoppedIndicating = false;
for (int i = 0; i < NUM_LEDS; i++) { //Turn LEDs back on
leds[0][i] = Red_high;
leds[1][i] = Red_high;
}
FastLED.show();
}
while (digitalRead(brakeLight) == HIGH) { // While the brake light is held on, check for left signal.
if ((digitalRead(leftTurn) == HIGH) && (digitalRead(rightTurn) == HIGH)) { // Check for hazard light while brakes are on.
hazardLight();
}
if (digitalRead(leftTurn) == HIGH) { // If left turn light is on, run left turn light routine.
leftTurnLight();
}
if (digitalRead(rightTurn) == HIGH) { // While the brake light is held on, check for right signal
rightTurnLight(); // If right turn light is on, run right turn light routine.
}
for (int i = 0; i < NUM_LEDS; i++) { // Turn on brake lights
leds[0][i] = Red_high; // Set strip 0
leds[1][i] = Red_high; // Set strip 1
}
FastLED.show();
}
//finished braking
RunningLights(both);
delay(50); // Delay to allow things to stabilize.
if ((digitalRead(leftTurn) == HIGH) && (digitalRead(rightTurn) == HIGH)) { // Check for hazard light activation
hazardLight();
}
if (digitalRead(leftTurn) == HIGH) { // While the brake light is held on, check for left signal
leftTurnLight(); // If left turn light is on, run right turn light routine.
}
if (digitalRead(rightTurn) == HIGH) { // While the brake light is held on, check for right signal
rightTurnLight(); // If right turn light is on, run right turn light routine.
}
// Program will continue to loop till it detects a signal.
}
void leftTurnLight() {
// This sequence will solidly light up the strip two LEDs at a time starting from the middle (as these LED strips are oriented vertically)
delay(50); // Delay to let system settle.
if ((digitalRead(leftTurn) == HIGH) && (digitalRead(rightTurn) == HIGH)) {
hazardLight(); // If both turn lights are on, go to hazard lights.
}
for (int i = 0; i < NUM_LEDS; i++) { // This will change the light for every third LED going from the last to first.
leds[0][i] = CRGB::Black; // Turn off strip in prep for next sweep.
}
FastLED.show();
delay(scrollDelay);
for (int i = 0; i < 3; i++) { // This will change the light for every third LED going from the last to first.
leds[0][2 - i] = Amber;
leds[0][3 + i] = Amber; // Set strip 0 LED color to the chosen color.
FastLED.show(); // Show the set LEDS
leftTurnCheck(); // Run subroutine to check for changes in signals.
delay(scrollDelay); // This delay will change the scroll speed based on the variable setting.
}
while (digitalRead(leftTurn) == HIGH) {
leftTurnCheck();
}
for (int i = 0; i < NUM_LEDS; i++) { //don't want switching between amber and red
leds[0][i] = CRGB::Black;
}
FastLED.show();
while (digitalRead(leftTurn) == LOW) {
for (int i = 0; i < lightDelay; i++) {
leftTurnCheck();
if (digitalRead(leftTurn) == HIGH) {
leftTurnLight();
}
delay(100);
}
if (digitalRead(brakeLight) == LOW) {
RunningLights(left);
} else {
brakeOnWhenStoppedIndicating = true; // Tells loop not to flash brakes when indicator switched off
}
return; // Once turn signal is no longer on, go back to loop.
}
}
void leftTurnCheck() {
if ((digitalRead(leftTurn) == LOW) && (digitalRead(rightTurn) == HIGH)) { // If signal switches to right turn signal, change to right signal.
rightTurnLight();
}
if ((digitalRead(leftTurn) == HIGH) && (digitalRead(rightTurn) == HIGH)) { // If hazard is turned on, run hazard routine.
hazardLight();
}
if (digitalRead(brakeLight) == HIGH) { // If Brakelight is on, turn to high for right strip.
for (int i = 0; i < NUM_LEDS; i++) {
leds[1][i] = Red_high; // Set strip 1 LED color to high brightness
}
FastLED.show(); // Show all brake light LEDs at once (no scroll for right side).
} else {
for (int i = 0; i < NUM_LEDS; i++) { // Cannot call function due to thread issue
leds[1][i] = CRGB::Black;
}
for (int i = 3; i < 6; i++) {
leds[1][i] = Red_dim;
}
FastLED.show();
}
//return;
}
void hazardLight() {
// This runs the hazard lights which will blink both strips on and off.
for (int i = 0; i < NUM_LEDS; i++) { // Set all LEDs to Amber
leds[0][i] = Amber; // Set strip 0
leds[1][i] = Amber; // Set strip 1
}
FastLED.show();
while ((digitalRead(leftTurn) == HIGH) && (digitalRead(rightTurn) == HIGH)) {
// When hazards are on, there are no other light signals we need to watch for, so nothing happens at this time.
// Once the Hazard lights go out, set the strips to off and wait for the next blink or exit if the hazards are turned off.
}
// since the signal is coming from the light wire going to the light, it's not easy to tell when the signal has been stopped or you are between blinks.
// This loop will keep it in the hazard function till either a turn signal is turned on or the lights don't come back on.
// Note that the delay should be longer than the actual delay between flashes so that it can detect the next blink round.
for (int i = 0; i < NUM_LEDS; i++) { // Turn off all LEDs
leds[0][i] = CRGB::Black; // Set strip 0
leds[1][i] = CRGB::Black; // Set strip 1
}
FastLED.show(); // When hazard lights turn off, turn off lights on the strips then wait for the next round.
delay(50); // Delay to allow settling.
for (int i = 0; i < lightDelay; i++) { // This sets up to delay check while the lights are off. If nothing comes on after the delay, exit.
if ((digitalRead(leftTurn) == HIGH) && (digitalRead(rightTurn) == HIGH)) { // If hazard is turned on, run hazard routine.
hazardLight();
}
delay(100);
}
//Hazards lights no longer detected
RunningLights(both);
FastLED.show();
delay(100); // Delay to allow settling.
loop(); // Return to the main program.
}
void rightTurnLight() {
// This sequence will solidly light up the strip two LEDs at a time starting from the middle (as these LED strips are oriented vertically)
delay(50); // Delay to let system settle.
if ((digitalRead(leftTurn) == HIGH) && (digitalRead(rightTurn) == HIGH)) {
hazardLight(); // If both turn lights are on, go to hazard lights.
}
for (int i = 0; i < NUM_LEDS; i++) { // Trun off all LEDs
leds[1][i] = CRGB::Black;
}
FastLED.show();
delay(scrollDelay);
for (int i = 0; i < 3; i++) {
leds[1][2 - i] = Amber;
leds[1][3 + i] = Amber;
FastLED.show(); // Show the set LEDS
rightTurnCheck(); // Run subroutine to check for changes in signals.
delay(scrollDelay); // This delay will change the scroll speed based on the variable setting.
}
while (digitalRead(rightTurn) == HIGH) {
rightTurnCheck(); // Check for signal changes.
}
for (int i = 0; i < NUM_LEDS; i++) {
leds[1][i] = CRGB::Black; // don't want switching between amber and red
}
FastLED.show();
while (digitalRead(rightTurn) == LOW) {
for (int i = 0; i < lightDelay; i++) { // This sets up a delay check for the next signal. If no signal is detected by
// the end of the delay, then the turn signal has been turned off and running lights will resume.
rightTurnCheck(); // Check for signal changes.
if (digitalRead(rightTurn) == HIGH) {
rightTurnLight();
}
delay(100);
}
if (digitalRead(brakeLight) == LOW) {
RunningLights(right);
} else {
brakeOnWhenStoppedIndicating = true; // Tells loop not to flash brakes when indicator switched off
}
//RunningLights(right);
//FastLED.show();
return; // Once turn signal is no longer on, go back to loop.
}
}
void rightTurnCheck() {
if ((digitalRead(rightTurn) == LOW) && (digitalRead(leftTurn) == HIGH)) { // If signal switches to right turn signal, change to right signal.
leftTurnLight();
}
if ((digitalRead(rightTurn) == HIGH) && (digitalRead(leftTurn) == HIGH)) { // If hazard is turned on, run hazard routine.
hazardLight();
}
if (digitalRead(brakeLight) == HIGH) { // If Brakelight is on, turn to high for right strip.
for (int i = 0; i < NUM_LEDS; i++) {
leds[0][i] = Red_high; // Set strip 1
}
FastLED.show(); // Show all brake light LEDs at once (no scroll for right side).
} else {
for (int i = 0; i < 3; i++) { // Running lights. Cannot call function from while loop due to thread issue?
leds[0][i] = CRGB::Black;
}
for (int i = 3; i < 6; i++) {
leds[0][i] = Red_dim;
}
FastLED.show();
}
return;
}
void RunningLights(side x) {
//function to switch on running lights
if (x == left || both) {
for (int i = 0; i < 3; i++) {
leds[0][i] = CRGB(0, 0, 0);
}
for (int i = 3; i < 6; i++) {
leds[0][i] = Red_dim;
}
}
if (x == right || both) {
for (int i = 0; i < 3; i++) {
leds[1][i] = CRGB(0, 0, 0);
}
for (int i = 3; i < 6; i++) {
leds[1][i] = Red_dim;
}
}
FastLED.show();
return;
}