initial commit
This commit is contained in:
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# LED CONTROLLER OTA
|
||||||
|
|
||||||
|
This is the repository for the led controller that is in my office
|
||||||
348
src/led-controller-ota.ino
Executable file
348
src/led-controller-ota.ino
Executable file
@@ -0,0 +1,348 @@
|
|||||||
|
#include <WiFi.h>
|
||||||
|
#include <ESPmDNS.h>
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
#include <ArduinoOTA.h>
|
||||||
|
#include <FastLED.h>
|
||||||
|
#include <secrets.h> // Requires a secrets.h file with WIFI_SSID, WIFI_PASSWORD, DEVICE_SECRET
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory> // For std::unique_ptr
|
||||||
|
#include <map> // For std::map
|
||||||
|
|
||||||
|
#define STARTUP_DELAY 2000
|
||||||
|
#define SERIAL_BAUD_RATE 115200
|
||||||
|
#define LED_DATA_PIN_A 2
|
||||||
|
#define LED_DATA_PIN_B 4
|
||||||
|
#define LED_DATA_PIN_C 16
|
||||||
|
#define LED_COUNT_A 32
|
||||||
|
#define LED_COUNT_B 300
|
||||||
|
#define LED_COUNT_C 150
|
||||||
|
#define LED_BRIGHTNESS 125
|
||||||
|
#define LED_PATTERN_DURATION 90 // seconds
|
||||||
|
#define FRAMES_PER_SECOND 80
|
||||||
|
|
||||||
|
const char* wifiSsid = WIFI_SSID;
|
||||||
|
const char* wifiPassword = WIFI_PASSWORD;
|
||||||
|
const char* hostname = "side-desk";
|
||||||
|
const char* deviceSecret = DEVICE_SECRET;
|
||||||
|
|
||||||
|
uint8_t gHue = 0;
|
||||||
|
uint32_t lastHueUpdate = 0;
|
||||||
|
|
||||||
|
class IPattern {
|
||||||
|
public:
|
||||||
|
virtual ~IPattern() = default;
|
||||||
|
virtual void apply(CRGB* leds, uint16_t ledCount) = 0;
|
||||||
|
virtual void update() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class RainbowPattern : public IPattern {
|
||||||
|
public:
|
||||||
|
void apply(CRGB* leds, uint16_t ledCount) override {
|
||||||
|
fill_rainbow(leds, ledCount, gHue, 52);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConfettiPattern : public IPattern {
|
||||||
|
public:
|
||||||
|
void apply(CRGB* leds, uint16_t ledCount) override {
|
||||||
|
fadeToBlackBy(leds, ledCount, 20);
|
||||||
|
int pos = random16(ledCount);
|
||||||
|
leds[pos] += CHSV(gHue + random8(64), 200, 255);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinelonPattern : public IPattern {
|
||||||
|
public:
|
||||||
|
void apply(CRGB* leds, uint16_t ledCount) override {
|
||||||
|
fadeToBlackBy(leds, ledCount, 20);
|
||||||
|
int pos = beatsin16(13, 0, ledCount - 1);
|
||||||
|
leds[pos] += CHSV(gHue, 255, 192);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BpmPattern : public IPattern {
|
||||||
|
public:
|
||||||
|
void apply(CRGB* leds, uint16_t ledCount) override {
|
||||||
|
uint8_t BeatsPerMinute = 136;
|
||||||
|
CRGBPalette16 palette = PartyColors_p;
|
||||||
|
uint8_t beat = beatsin8(BeatsPerMinute, 64, 255);
|
||||||
|
for (int i = 0; i < ledCount; i++) {
|
||||||
|
leds[i] = ColorFromPalette(palette, gHue + (i * 2), beat - gHue + (i * 10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class JugglePattern : public IPattern {
|
||||||
|
public:
|
||||||
|
void apply(CRGB* leds, uint16_t ledCount) override {
|
||||||
|
fadeToBlackBy(leds, ledCount, 20);
|
||||||
|
uint8_t dothue = 0;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
leds[beatsin16(i + 7, 0, ledCount - 1)] |= CHSV(dothue, 200, 255);
|
||||||
|
dothue += 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TracerDotPattern : public IPattern {
|
||||||
|
private:
|
||||||
|
std::map<CRGB*, int> stripPositions;
|
||||||
|
public:
|
||||||
|
void apply(CRGB* leds, uint16_t ledCount) override {
|
||||||
|
fadeToBlackBy(leds, ledCount, 30);
|
||||||
|
|
||||||
|
int& currentPos = stripPositions[leds];
|
||||||
|
if (currentPos >= ledCount) currentPos = 0;
|
||||||
|
|
||||||
|
leds[currentPos] = CRGB::Blue;
|
||||||
|
currentPos++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Glow : public IPattern {
|
||||||
|
private:
|
||||||
|
uint32_t lastFadedAt;
|
||||||
|
static uint8_t hue;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void apply(CRGB* leds, uint16_t ledCount) override {
|
||||||
|
uint32_t now = millis();
|
||||||
|
hue = now % 255;
|
||||||
|
|
||||||
|
if (!lastFadedAt) {
|
||||||
|
|
||||||
|
fadeToBlackBy(leds, ledCount, 100);
|
||||||
|
|
||||||
|
lastFadedAt = now;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (now - lastFadedAt > 2000) {
|
||||||
|
for (int i = 0; i < ledCount; i++) {
|
||||||
|
// fade everything out
|
||||||
|
leds->fadeToBlackBy(40);
|
||||||
|
|
||||||
|
// let's set an led value
|
||||||
|
leds[i] = CHSV(hue++, 255, 255);
|
||||||
|
|
||||||
|
FastLED.delay(33);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t Glow::hue = 0;
|
||||||
|
|
||||||
|
// Generic LED Strip class that can work with any FastLED-supported LED type
|
||||||
|
template<template<uint8_t DATA_PIN, EOrder RGB_ORDER> class LED_TYPE, uint8_t DATA_PIN, EOrder RGB_ORDER = GRB>
|
||||||
|
class LEDStrip {
|
||||||
|
private:
|
||||||
|
CRGB* leds_;
|
||||||
|
uint16_t ledCount_;
|
||||||
|
bool initialized_ = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LEDStrip(uint16_t ledCount)
|
||||||
|
: ledCount_(ledCount) {
|
||||||
|
leds_ = new CRGB[ledCount_];
|
||||||
|
}
|
||||||
|
|
||||||
|
~LEDStrip() {
|
||||||
|
delete[] leds_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initialize() {
|
||||||
|
if (!initialized_) {
|
||||||
|
FastLED.addLeds<LED_TYPE, DATA_PIN, RGB_ORDER>(leds_, ledCount_).setCorrection(TypicalLEDStrip);
|
||||||
|
FastLED.setBrightness(LED_BRIGHTNESS);
|
||||||
|
clear();
|
||||||
|
show();
|
||||||
|
initialized_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
fill_solid(leds_, ledCount_, CRGB::Black);
|
||||||
|
}
|
||||||
|
|
||||||
|
void show() {
|
||||||
|
if (initialized_) {
|
||||||
|
FastLED.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CRGB* getLeds() {
|
||||||
|
return leds_;
|
||||||
|
}
|
||||||
|
uint16_t getLedCount() {
|
||||||
|
return ledCount_;
|
||||||
|
}
|
||||||
|
bool isInitialized() {
|
||||||
|
return initialized_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convenience typedefs for common LED types
|
||||||
|
template<uint8_t DATA_PIN, EOrder RGB_ORDER = GRB>
|
||||||
|
using WS2811Strip = LEDStrip<WS2811, DATA_PIN, RGB_ORDER>;
|
||||||
|
|
||||||
|
template<uint8_t DATA_PIN, EOrder RGB_ORDER = GRB>
|
||||||
|
using WS2812BStrip = LEDStrip<WS2812B, DATA_PIN, RGB_ORDER>;
|
||||||
|
|
||||||
|
template<uint8_t DATA_PIN, EOrder RGB_ORDER = GRB>
|
||||||
|
using WS2813Strip = LEDStrip<WS2813, DATA_PIN, RGB_ORDER>;
|
||||||
|
|
||||||
|
template<uint8_t DATA_PIN, EOrder RGB_ORDER = GRB>
|
||||||
|
using APA104Strip = LEDStrip<APA104, DATA_PIN, RGB_ORDER>;
|
||||||
|
|
||||||
|
// Class for managing patterns (Single Responsibility, depends on IPattern abstraction)
|
||||||
|
class PatternManager {
|
||||||
|
private:
|
||||||
|
std::vector<std::unique_ptr<IPattern>> patterns_;
|
||||||
|
size_t currentPatternIndex_ = 0;
|
||||||
|
uint32_t lastSwitchTime_ = 0;
|
||||||
|
public:
|
||||||
|
void addPattern(std::unique_ptr<IPattern> pattern) {
|
||||||
|
patterns_.push_back(std::move(pattern));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename LED_STRIP_TYPE>
|
||||||
|
void applyCurrent(LED_STRIP_TYPE& strip) {
|
||||||
|
if (!patterns_.empty()) {
|
||||||
|
patterns_[currentPatternIndex_]->apply(strip.getLeds(), strip.getLedCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update() {
|
||||||
|
if (!patterns_.empty()) {
|
||||||
|
patterns_[currentPatternIndex_]->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nextPattern() {
|
||||||
|
if (!patterns_.empty()) {
|
||||||
|
currentPatternIndex_ = (currentPatternIndex_ + 1) % patterns_.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shouldSwitchPattern() {
|
||||||
|
uint32_t now = millis();
|
||||||
|
if (now - lastSwitchTime_ >= LED_PATTERN_DURATION * 1000) {
|
||||||
|
lastSwitchTime_ = now;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Class for OTA and WiFi management (Single Responsibility; renamed to avoid library conflict)
|
||||||
|
class OTAManager {
|
||||||
|
public:
|
||||||
|
void initialize() {
|
||||||
|
connectWiFi();
|
||||||
|
setupOTA();
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle() {
|
||||||
|
ArduinoOTA.handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void connectWiFi() {
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(wifiSsid, wifiPassword);
|
||||||
|
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
||||||
|
Serial.println("WiFi Connection failed. Rebooting...");
|
||||||
|
delay(5000);
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
Serial.println("WiFi Connected");
|
||||||
|
Serial.print("IP address: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupOTA() {
|
||||||
|
ArduinoOTA.setHostname(hostname);
|
||||||
|
ArduinoOTA.setPassword(deviceSecret);
|
||||||
|
ArduinoOTA.onStart([]() {
|
||||||
|
String type = (ArduinoOTA.getCommand() == U_FLASH) ? "sketch" : "filesystem";
|
||||||
|
Serial.println("Starting update [" + type + "]");
|
||||||
|
});
|
||||||
|
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
|
||||||
|
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
|
||||||
|
});
|
||||||
|
ArduinoOTA.onEnd([]() {
|
||||||
|
Serial.println("\nEnd");
|
||||||
|
});
|
||||||
|
ArduinoOTA.onError([](ota_error_t error) {
|
||||||
|
Serial.printf("Error [%u]: ", error);
|
||||||
|
switch (error) {
|
||||||
|
case OTA_AUTH_ERROR: Serial.println("Auth Failed"); break;
|
||||||
|
case OTA_BEGIN_ERROR: Serial.println("Begin failed"); break;
|
||||||
|
case OTA_CONNECT_ERROR: Serial.println("Connect failed"); break;
|
||||||
|
case OTA_RECEIVE_ERROR: Serial.println("Receive failed"); break;
|
||||||
|
case OTA_END_ERROR: Serial.println("End failed"); break;
|
||||||
|
default: Serial.println("Unknown failure");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ArduinoOTA.begin();
|
||||||
|
Serial.println("OTA Ready");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Instances
|
||||||
|
LEDStrip<WS2811, LED_DATA_PIN_A, RGB> ledStripA(LED_COUNT_A);
|
||||||
|
LEDStrip<WS2812B, LED_DATA_PIN_B, GRB> ledStripB(LED_COUNT_B);
|
||||||
|
LEDStrip<WS2812B, LED_DATA_PIN_C, GRB> ledStripC(LED_COUNT_C);
|
||||||
|
PatternManager patternManager;
|
||||||
|
OTAManager otaManager;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
delay(STARTUP_DELAY);
|
||||||
|
Serial.begin(SERIAL_BAUD_RATE);
|
||||||
|
delay(STARTUP_DELAY);
|
||||||
|
|
||||||
|
// Serial.println("Initializing ota...");
|
||||||
|
otaManager.initialize();
|
||||||
|
|
||||||
|
Serial.println("Initializing led strip...");
|
||||||
|
ledStripA.initialize();
|
||||||
|
ledStripB.initialize();
|
||||||
|
ledStripC.initialize();
|
||||||
|
|
||||||
|
// Add patterns (extensible)
|
||||||
|
patternManager.addPattern(std::make_unique<JugglePattern>());
|
||||||
|
patternManager.addPattern(std::make_unique<TracerDotPattern>());
|
||||||
|
patternManager.addPattern(std::make_unique<SinelonPattern>());
|
||||||
|
patternManager.addPattern(std::make_unique<BpmPattern>());
|
||||||
|
patternManager.addPattern(std::make_unique<ConfettiPattern>());
|
||||||
|
patternManager.addPattern(std::make_unique<Glow>());
|
||||||
|
patternManager.addPattern(std::make_unique<RainbowPattern>());
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
otaManager.handle();
|
||||||
|
|
||||||
|
// Apply current pattern
|
||||||
|
patternManager.applyCurrent(ledStripA);
|
||||||
|
patternManager.applyCurrent(ledStripB);
|
||||||
|
patternManager.applyCurrent(ledStripC);
|
||||||
|
ledStripA.show();
|
||||||
|
ledStripB.show();
|
||||||
|
ledStripC.show();
|
||||||
|
FastLED.delay(1000 / FRAMES_PER_SECOND);
|
||||||
|
|
||||||
|
// Periodic updates
|
||||||
|
if (millis() - lastHueUpdate >= 1000) {
|
||||||
|
gHue++;
|
||||||
|
lastHueUpdate = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
patternManager.update();
|
||||||
|
|
||||||
|
if (patternManager.shouldSwitchPattern()) {
|
||||||
|
patternManager.nextPattern();
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/secrets.h
Executable file
3
src/secrets.h
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#define WIFI_SSID "technotic"
|
||||||
|
#define WIFI_PASSWORD "timewarp2022"
|
||||||
|
#define DEVICE_SECRET "al3110e"
|
||||||
Reference in New Issue
Block a user