#include <Arduino.h>
#include <Keypad.h>
#include <FastLED.h>
#define LED_PIN 12 // LED Data Pin
#define LED_TYPE WS2812B // LED TYPE
#define COLOR_ORDER BRG // LED LAYOUT
#define NUM_LEDS 20 // no of LED in sign
CRGB leds[NUM_LEDS]; // do not change
const int ROW_NUM = 4; // number of rows
const int COLUMN_NUM = 4; // number of columns
// Controls how fast to travel down the strip for animated effects
#define FRAME_DELAY 40 // [milliseconds]
int paletteIndex = 0;
int barPosition = 1;
int twoColourLedIndex = 0;
char keys[ROW_NUM][COLUMN_NUM] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}}; // Keypad Layout for Character output
byte pin_rows[ROW_NUM] = {5, 4, 3, 2}; // connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {9, 8, 7, 6}; // connect to the column pinouts of the keypad
Keypad keypad = Keypad(makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM);
typedef void (*Animation)(const CRGB &);
enum class AnimType
{
Invalid = -1,
SolidColour,
LoadupTwoColour,
MulticolourSpin
};
constexpr size_t MaxPaletteSize = 4;
struct Information
{
Information(AnimType newAnimType, const String &newPassword, const CRGB (&newColorPalette)[MaxPaletteSize], const size_t newSize)
: animType(newAnimType)
, password(newPassword)
, colorPalette(newColorPalette)
, paletteSize(newSize)
{
}
String password = "";
const CRGB colorPalette[MaxPaletteSize];
const int paletteSize;
AnimType animType = AnimType::Invalid;
};
String input_password;
#define NUM_PASSWORDS 12
const Information animInformation[NUM_PASSWORDS] =
{
Information{AnimType::SolidColour, "1", {CRGB(148, 0, 211)}, 1},
Information{AnimType::SolidColour, "2", {CRGB(75, 0, 130)}, 1},
Information{AnimType::SolidColour, "3", {CRGB(0, 0, 255)}, 1},
Information{AnimType::SolidColour, "4", {CRGB(0, 255, 0)}, 1},
Information{AnimType::SolidColour, "5", {CRGB(255, 255, 0)}, 1},
Information{AnimType::SolidColour, "6", {CRGB(255, 127, 0)}, 1},
Information{AnimType::SolidColour, "7", {CRGB(255, 0, 0)}, 1},
Information{AnimType::SolidColour, "8", {CRGB(255, 255, 255)}, 1},
Information{AnimType::MulticolourSpin, "9", {CRGB(152, 13, 73),CRGB(18, 133, 102),CRGB(211, 151, 0),CRGB(235, 227, 239)}, 4},
Information{AnimType::MulticolourSpin, "10", {CRGB::Red,CRGB(0, 249, 17),CRGB(0, 255, 208),CRGB(137, 154, 50)}, 4},
Information{AnimType::LoadupTwoColour, "11", {CRGB(0, 200, 255),CRGB(255, 1, 175)}, 2},
Information{AnimType::LoadupTwoColour, "12", {CRGB(255, 215, 0),CRGB(85, 255, 0)}, 2}
};
void setup()
{
Serial.begin(9600);
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setCorrection(TypicalLEDStrip);
FastLED.clear();
FastLED.show();
input_password.reserve(32); // maximum input characters is 33, change if needed
}
void SolidColourAnim(const CRGB colourPalette[])
{
fill_solid(leds, NUM_LEDS, colourPalette[0]);
FastLED.show();
}
void MultiColourAnim(const CRGB colourPalette[], int paletteSize, int delayValue)
{
EVERY_N_MILLISECONDS(delayValue)
{
// move current pixel data over one position
for (uint16_t x = 0; x < NUM_LEDS - 1; ++x)
{
leds[x] = leds[x + 1];
}
// assign new data at end of line
leds[NUM_LEDS - 1] = colourPalette[paletteIndex];
int colorBarLength = NUM_LEDS / paletteSize;
barPosition++;
// check and reset things as needed
if ((barPosition > colorBarLength) && (paletteIndex == paletteSize - 1))
{
barPosition = 1;
paletteIndex = 0;
}
else if (barPosition > colorBarLength)
{
barPosition = 1;
paletteIndex = paletteIndex + 1;
}
} // end_EVERY_N
FastLED.show();
}
void TwoColourAnim(const CRGB colourPalette[], int paletteSze, int delayValue)
{
if (paletteSze != 2)
{
Serial.write("Incorrect amount of colours in palette. For LoadupTwoColour have to use 2 colours.");
return;
}
EVERY_N_MILLISECONDS(delayValue)
{
static bool goingUp = true;
if(twoColourLedIndex >= NUM_LEDS)
{
goingUp = false;
twoColourLedIndex = NUM_LEDS -1;
}
else if(twoColourLedIndex < 0)
{
goingUp = true;
twoColourLedIndex++;
}
const CRGB& colour = goingUp ? colourPalette[0] : colourPalette[1];
leds[twoColourLedIndex] = colour;
FastLED.show();
goingUp ? ++twoColourLedIndex : --twoColourLedIndex;
}
}
Information* currentAnimInfo = nullptr;
bool playAnimation = false;
void ResetAll()
{
input_password = ""; // reset the input password
playAnimation = false;
paletteIndex = 0;
barPosition = 1;
twoColourLedIndex = 0;
FastLED.clear();
FastLED.show();
currentAnimInfo = nullptr;
}
void loop()
{
char key = keypad.getKey();
if (key)
{
Serial.println(key);
if (key == '*')
{
ResetAll();
}
else if (key == '#')
{
for (const Information &info : animInformation)
{
if (info.password == input_password)
{
currentAnimInfo = &info;
playAnimation = true;
}
}
input_password = ""; // reset the input password
}
else
{
input_password += key; // append new character to input password string
}
}
if(playAnimation)
{
switch (currentAnimInfo->animType)
{
case AnimType::SolidColour:
SolidColourAnim(currentAnimInfo->colorPalette);
break;
case AnimType::LoadupTwoColour:
TwoColourAnim(currentAnimInfo->colorPalette, currentAnimInfo->paletteSize, 40);
break;
case AnimType::MulticolourSpin:
MultiColourAnim(currentAnimInfo->colorPalette, currentAnimInfo->paletteSize, 40);
break;
default:
break;
}
}
}