Cleaned up repository

- only moving files around
This commit is contained in:
2026-08-25 17:06:32 +02:00
parent b2c060fcc9
commit bd8925a278
87 changed files with 512097 additions and 74 deletions

View File

@@ -0,0 +1,153 @@
#pragma once
#include "effects/Common.h"
#include "helpers/ColorRGBW.h"
#include "helpers/ColorHSV.h"
#include "helpers/ColorConversions.h"
#include "helpers/BellCurve.h"
#pragma pack(push, 1)
struct EffectAlexaSwipeConfig
{
float primaryColorWidth; // in degrees
float transitionWidth;
float swipeSpeed; // in degrees per second
float bellCurveWidthInLeds;
float startPosition;
bool forward;
ColorRGBW primaryColor;
ColorRGBW secondaryColor;
};
#pragma pack(pop)
template <typename TLedStrip>
class EffectAlexaSwipe
{
public:
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
static constexpr int DELAY_MS = 10;
using ConfigType = EffectAlexaSwipeConfig;
EffectAlexaSwipe(const EffectAlexaSwipeConfig &cfg, TLedStrip &ledStrip)
: ledStrip_(ledStrip),
currentPosition_(0),
transitionWidth_(cfg.transitionWidth / 360.0f * NUM_LEDS),
invTransitionWidth_(1.0f / transitionWidth_),
primaryColorWidth_(cfg.primaryColorWidth / 360.0f * NUM_LEDS + cfg.bellCurveWidthInLeds),
bellCurveWidth_(cfg.bellCurveWidthInLeds),
invBellCurveWidth_(1.0f / cfg.bellCurveWidthInLeds),
speed_(cfg.swipeSpeed / 360 / 1000 * NUM_LEDS * DELAY_MS),
startPosition_(cfg.startPosition / 360.0f * NUM_LEDS),
primaryColor_(rgb2hsv(cfg.primaryColor)),
secondaryColor_(rgb2hsv(cfg.secondaryColor)),
finished_(false)
{
if (cfg.forward)
{
currentPosition_ = 0;
direction_ = 1;
}
else
{
currentPosition_ = float(NUM_LEDS) / 2.0f + bellCurveWidth_ / 2;
direction_ = -1;
}
}
bool finished() const { return finished_; }
int operator()()
{
clear(ledStrip_);
const auto width = std::min(int(currentPosition_ + 1), int(NUM_LEDS / 2));
setLedRGBW(ledStrip_, startPosition_, getColor(currentPosition_));
for (int i = 1; i < width; ++i)
{
const float x = currentPosition_ - float(i);
if (x > 0.0f)
{
const int led1 = startPosition_ + i;
const int led2 = startPosition_ - i;
const ColorRGBW color = getColor(x);
setLedRGBW(ledStrip_, led1, color);
setLedRGBW(ledStrip_, led2, color);
}
}
currentPosition_ += direction_ * speed_;
const auto maxPosition = float(NUM_LEDS) / 2.0f + bellCurveWidth_ / 2;
const auto minPosition = 0.0f;
currentPosition_ = std::min(currentPosition_, maxPosition);
currentPosition_ = std::max(currentPosition_, minPosition);
if (currentPosition_ <= minPosition || currentPosition_ >= maxPosition)
finished_ = true;
return DELAY_MS;
}
private:
void getParams(float x, float &interpFac, float &brightness)
{
brightness = stepFunction(x, bellCurveWidth_, invBellCurveWidth_);
if (x < primaryColorWidth_)
interpFac = 0.0f;
else if (x > primaryColorWidth_ + transitionWidth_)
interpFac = 1.0f;
else
interpFac = (x - primaryColorWidth_) * invTransitionWidth_;
}
// x is positive distance from running front
ColorRGBW getColor(float x)
{
float interpFac;
float brightness;
getParams(x, interpFac, brightness);
ColorHSV result{
interpFac * secondaryColor_.h + (1.0f - interpFac) * primaryColor_.h,
interpFac * secondaryColor_.s + (1.0f - interpFac) * primaryColor_.s,
interpFac * secondaryColor_.v + (1.0f - interpFac) * primaryColor_.v};
result.v *= brightness;
return hsv2rgb(result);
}
TLedStrip &ledStrip_;
// in number of leds
float currentPosition_;
float transitionWidth_;
float invTransitionWidth_;
float primaryColorWidth_;
float bellCurveWidth_;
float invBellCurveWidth_;
float speed_;
int startPosition_;
const ColorHSV primaryColor_;
const ColorHSV secondaryColor_;
float direction_;
bool finished_;
};
// Traits
template <>
struct EffectIdToConfig<EffectId::ALEXA_SWIPE>
{
using type = EffectAlexaSwipeConfig;
};
template <>
struct EffectConfigToId<EffectAlexaSwipeConfig>
{
static constexpr auto id = EffectId::ALEXA_SWIPE;
};
template <typename TLedStrip>
struct EffectIdToClass<EffectId::ALEXA_SWIPE, TLedStrip>
{
using type = EffectAlexaSwipe<TLedStrip>;
};

View File

@@ -0,0 +1,90 @@
#pragma once
#include "effects/Common.h"
#include "helpers/ColorRGBW.h"
#include "helpers/BellCurve.h"
#pragma pack(push, 1)
struct EffectCircularConfig
{
float speed; // in degrees per second
float width; // width in degrees
ColorRGBW color;
};
#pragma pack(pop)
template <typename TLedStrip>
class EffectCircular
{
public:
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
static constexpr int DELAY_MS = 10;
using ConfigType = EffectCircularConfig;
EffectCircular(const EffectCircularConfig &cfg, TLedStrip &ledStrip)
: config_(cfg),
ledStrip_(ledStrip),
currentPosition_(0),
widthInLeds_((numLeds(ledStrip) * cfg.width / 360)),
invWidth_(1.0f / widthInLeds_)
{
}
int operator()()
{
int startLed = int(currentPosition_);
float distDown = currentPosition_ - float(startLed);
float distUp = 1.f - distDown;
clear(ledStrip_);
// center
setLedRGBW(ledStrip_, startLed,
config_.color * bellCurveApproximation(distDown, invWidth_));
// down
for (int i = 1; i < widthInLeds_ / 2 + 1; ++i)
{
setLedRGBW(ledStrip_, startLed - i,
config_.color * bellCurveApproximation(distDown + i, invWidth_));
}
// up
for (int i = 1; i < widthInLeds_ / 2 + 1; ++i)
{
setLedRGBW(ledStrip_, startLed + i,
config_.color * bellCurveApproximation(distUp + i - 1, invWidth_));
}
currentPosition_ += config_.speed / 1000 / 360 * NUM_LEDS * DELAY_MS;
if (currentPosition_ > NUM_LEDS)
currentPosition_ -= NUM_LEDS;
return DELAY_MS;
}
private:
EffectCircularConfig config_;
TLedStrip &ledStrip_;
float currentPosition_; // between 0 and num leds
int widthInLeds_;
float invWidth_;
};
// Traits
template <>
struct EffectIdToConfig<EffectId::CIRCULAR>
{
using type = EffectCircularConfig;
};
template <>
struct EffectConfigToId<EffectCircularConfig>
{
static constexpr auto id = EffectId::CIRCULAR;
};
template <typename TLedStrip>
struct EffectIdToClass<EffectId::CIRCULAR, TLedStrip>
{
using type = EffectCircular<TLedStrip>;
};

View File

@@ -0,0 +1,27 @@
#pragma once
enum class EffectId
{
STATIC,
CIRCULAR,
ALEXA_SWIPE,
RANDOM_TWO_COLOR_INTERPOLATION,
SWIPE_AND_CHANGE, // combination of ALEXA_SWIPE and RANDOM_TWO_COLOR_INTERPOLATION
REVERSE_SWIPE,
STATIC_DETAILED,
};
template <EffectId id>
struct EffectIdToConfig
{
};
template <typename EffectConfig>
struct EffectConfigToId
{
};
template <EffectId id, typename TLedStrip>
struct EffectIdToClass
{
};

View File

@@ -0,0 +1,155 @@
#pragma once
#include "effects/Common.h"
#include "helpers/ColorRGBW.h"
#include "helpers/ColorHSV.h"
#include "helpers/ColorConversions.h"
#pragma pack(push, 1)
struct EffectRandomTwoColorInterpolationConfig
{
int32_t cycleDurationMs;
bool startWithExisting;
int32_t numSegments;
bool hue1Random;
bool hue2Random;
ColorHSV color1;
ColorHSV color2;
};
#pragma pack(pop)
template <typename TLedStrip>
class EffectRandomTwoColorInterpolation
{
public:
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
static constexpr int DELAY_MS = 10;
EffectRandomTwoColorInterpolation(const EffectRandomTwoColorInterpolationConfig &cfg, TLedStrip &ledStrip)
: ledStrip_(ledStrip),
config_(cfg),
progress_(0.0f)
{
currentColors_ = arr1;
nextColors_ = arr2;
if (config_.startWithExisting)
for (int i = 0; i < NUM_LEDS; ++i)
currentColors_[i] = rgb2hsv(getLedRGBW(ledStrip_, i));
else
randomizeColors(currentColors_);
randomizeColors(nextColors_);
}
void begin()
{
if (config_.startWithExisting)
for (int i = 0; i < NUM_LEDS; ++i)
currentColors_[i] = rgb2hsv(getLedRGBW(ledStrip_, i));
}
int operator()()
{
for (int i = 0; i < NUM_LEDS; ++i)
setLedRGBW(ledStrip_, i, hsv2rgb(interpolate(currentColors_[i], nextColors_[i], progress_)));
progress_ += (float(DELAY_MS) / config_.cycleDurationMs);
if (progress_ > 1)
{
progress_ = 0;
std::swap(currentColors_, nextColors_);
randomizeColors(nextColors_);
}
return DELAY_MS;
}
private:
float randomFloat()
{
return float(esp_random()) / float(UINT32_MAX);
}
ColorHSV randomColor()
{
ColorHSV color1 = config_.color1;
ColorHSV color2 = config_.color2;
if (config_.hue1Random)
color1.h = randomFloat() * 360;
if (config_.hue2Random)
color2.h = randomFloat() * 360;
float f = randomFloat();
return interpolate(color1, color2, f);
}
void randomizeColors(ColorHSV *arr)
{
int segmentLength = NUM_LEDS / config_.numSegments;
int lastSegmentLength = NUM_LEDS - (segmentLength * (config_.numSegments - 1));
ColorHSV firstColor = randomColor();
ColorHSV currentColor = firstColor;
ColorHSV nextColor = randomColor();
int position = random(0, NUM_LEDS);
const auto incrPosition = [&position]()
{
position = (position == NUM_LEDS - 1) ? 0 : position + 1;
};
for (int segmentIdx = 0; segmentIdx < config_.numSegments - 1; ++segmentIdx)
{
for (int i = 0; i < segmentLength; ++i)
{
float f = float(i) / float(segmentLength);
arr[position] = interpolate(currentColor, nextColor, f);
incrPosition();
}
currentColor = nextColor;
nextColor = randomColor();
}
// last segment
for (int i = 0; i < lastSegmentLength; ++i)
{
float f = float(i) / float(lastSegmentLength);
arr[position] = interpolate(currentColor, firstColor, f);
incrPosition();
}
}
TLedStrip &ledStrip_;
EffectRandomTwoColorInterpolationConfig config_;
ColorHSV arr1[NUM_LEDS];
ColorHSV arr2[NUM_LEDS];
ColorHSV *currentColors_;
ColorHSV *nextColors_;
float progress_;
};
// Traits
template <>
struct EffectIdToConfig<EffectId::RANDOM_TWO_COLOR_INTERPOLATION>
{
using type = EffectRandomTwoColorInterpolationConfig;
};
template <>
struct EffectConfigToId<EffectRandomTwoColorInterpolationConfig>
{
static constexpr auto id = EffectId::RANDOM_TWO_COLOR_INTERPOLATION;
};
template <typename TLedStrip>
struct EffectIdToClass<EffectId::RANDOM_TWO_COLOR_INTERPOLATION, TLedStrip>
{
using type = EffectRandomTwoColorInterpolation<TLedStrip>;
};

View File

@@ -0,0 +1,112 @@
#pragma once
#include "effects/Common.h"
#include "helpers/BellCurve.h"
#pragma pack(push, 1)
struct EffectReverseSwipeConfig
{
float swipeSpeed; // in degrees per second
float bellCurveWidthInLeds;
float startPosition;
};
#pragma pack(pop)
template <typename TLedStrip>
class EffectReverseSwipe
{
public:
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
static constexpr int DELAY_MS = 10;
using ConfigType = EffectReverseSwipeConfig;
EffectReverseSwipe(const EffectReverseSwipeConfig &cfg, TLedStrip &ledStrip)
: ledStrip_(ledStrip),
currentPosition_(float(NUM_LEDS) / 2 + cfg.bellCurveWidthInLeds),
bellCurveWidth_(cfg.bellCurveWidthInLeds),
invBellCurveWidth_(1.0f / cfg.bellCurveWidthInLeds),
speed_(cfg.swipeSpeed / 360 / 1000 * NUM_LEDS * DELAY_MS),
startPosition_(cfg.startPosition / 360.0f * NUM_LEDS),
finished_(false)
{
for (int i = 0; i < NUM_LEDS; ++i)
state_[i] = getLedRGBW(ledStrip_, i);
}
bool finished() const { return finished_; }
int operator()()
{
if (finished_)
return 60000;
const auto width = std::min(int(currentPosition_ + 1), int(NUM_LEDS / 2) + 1);
{
float brightness = stepFunction(currentPosition_, bellCurveWidth_, invBellCurveWidth_);
ColorRGBW &prevC = state_[ledStrip_.normalizeIdx(startPosition_)];
setLedRGBW(ledStrip_, startPosition_, prevC * brightness);
}
for (int i = 1; i < width; ++i)
{
const float x = currentPosition_ - float(i);
if (x > 0.0f)
{
const int led1 = startPosition_ + i;
const int led2 = startPosition_ - i;
float brightness = stepFunction(x, bellCurveWidth_, invBellCurveWidth_);
ColorRGBW &prevC1 = state_[ledStrip_.normalizeIdx(led1)];
ColorRGBW &prevC2 = state_[ledStrip_.normalizeIdx(led2)];
setLedRGBW(ledStrip_, led1, prevC1 * brightness);
setLedRGBW(ledStrip_, led2, prevC2 * brightness);
}
}
currentPosition_ -= speed_;
if (currentPosition_ < 0)
{
finished_ = true;
clear(ledStrip_);
}
return DELAY_MS;
}
private:
TLedStrip &ledStrip_;
float currentPosition_;
float bellCurveWidth_;
float invBellCurveWidth_;
float speed_;
int startPosition_;
bool finished_;
ColorRGBW state_[NUM_LEDS];
};
// Traits
template <>
struct EffectIdToConfig<EffectId::REVERSE_SWIPE>
{
using type = EffectReverseSwipeConfig;
};
template <>
struct EffectConfigToId<EffectReverseSwipeConfig>
{
static constexpr auto id = EffectId::REVERSE_SWIPE;
};
template <typename TLedStrip>
struct EffectIdToClass<EffectId::REVERSE_SWIPE, TLedStrip>
{
using type = EffectReverseSwipe<TLedStrip>;
};

View File

@@ -0,0 +1,63 @@
#pragma once
#include "effects/Common.h"
#include "helpers/ColorRGBW.h"
#pragma pack(push, 1)
struct EffectStaticConfig
{
EffectStaticConfig(const ColorRGBW &c = ColorRGBW{0, 0, 0, 0}, uint16_t beg = 0, uint16_t en = 0)
: color(c), begin(beg), end(en) {}
ColorRGBW color;
uint16_t begin = 0;
uint16_t end = 0;
};
#pragma pack(pop)
template <typename TLedStrip>
class EffectStatic
{
public:
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
using ConfigType = EffectStaticConfig;
EffectStatic(const EffectStaticConfig &cfg, TLedStrip &ledStrip)
: config_(cfg),
ledStrip_(ledStrip)
{
}
int operator()()
{
if (config_.begin == config_.end)
setLedRGBW(ledStrip_, 0, NUM_LEDS, config_.color);
else
setLedRGBW(ledStrip_, config_.begin, config_.end, config_.color);
return 10000; // nothing changing, return some large time to sleep
}
private:
EffectStaticConfig config_;
TLedStrip &ledStrip_;
};
// Traits
template <>
struct EffectIdToConfig<EffectId::STATIC>
{
using type = EffectStaticConfig;
};
template <>
struct EffectConfigToId<EffectStaticConfig>
{
static constexpr auto id = EffectId::STATIC;
};
template <typename TLedStrip>
struct EffectIdToClass<EffectId::STATIC, TLedStrip>
{
using type = EffectStatic<TLedStrip>;
};

View File

@@ -0,0 +1,107 @@
#pragma once
#include "effects/Common.h"
#include "helpers/ColorRGBW.h"
#include "helpers/ColorConversions.h"
#pragma pack(push, 1)
struct EffectStaticDetailedConfig
{
EffectStaticDetailedConfig(const ColorRGBW &c = ColorRGBW{0, 0, 0, 0}, uint16_t beg = 0, uint16_t en = 0)
: color(c), begin(beg), end(en) {}
ColorRGBW color;
uint16_t increment = 1;
float begin = 0.0f;
float end = 0.0f;
float transition_time_in_ms = 0.0f;
};
#pragma pack(pop)
template <typename TLedStrip>
class EffectStaticDetailed
{
public:
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
static constexpr int DELAY_MS = 10;
using ConfigType = EffectStaticDetailedConfig;
EffectStaticDetailed(const EffectStaticDetailedConfig &cfg, TLedStrip &ledStrip)
: config_(cfg),
ledStrip_(ledStrip)
{
for (int i = 0; i < NUM_LEDS; ++i)
state_[i] = getLedRGBW(ledStrip_, i);
beginIdx_ = constrain(static_cast<int>(cfg.begin * NUM_LEDS + 0.5f), 0, NUM_LEDS - 1);
endIdx_ = constrain(static_cast<int>(cfg.end * NUM_LEDS + 0.5f), 0, NUM_LEDS - 1);
while (endIdx_ < beginIdx_)
endIdx_ += NUM_LEDS;
}
bool finished() const { return finished_; }
int operator()()
{
if (finished_)
return 1000000;
const float progress = config_.transition_time_in_ms > 0.0f ? static_cast<float>(DELAY_MS * calls_) / config_.transition_time_in_ms : 1.f;
// Finished case
if (config_.transition_time_in_ms <= 0.0f || progress >= 1.0)
{
finished_ = true;
clear(ledStrip_);
for (int i = beginIdx_; i < endIdx_; i += config_.increment)
setLedRGBW(ledStrip_, i % NUM_LEDS, config_.color);
return 10000000;
}
// In-progress case
clear(ledStrip_);
for (int i = beginIdx_; i < endIdx_; i += config_.increment)
{
const auto idx = i % NUM_LEDS;
ColorRGBW newColor = ColorRGBW::interpolate(state_[idx], config_.color, progress);
setLedRGBW(ledStrip_, idx, newColor);
}
++calls_;
return DELAY_MS;
}
private:
static int int_interpolate(int prev, int next, float progress)
{
return static_cast<float>(prev) * (1 - progress) +
static_cast<float>(next) * progress;
}
EffectStaticDetailedConfig config_;
TLedStrip &ledStrip_;
ColorRGBW state_[NUM_LEDS];
int beginIdx_;
int endIdx_;
int calls_ = 0;
bool finished_ = false;
};
// Traits
template <>
struct EffectIdToConfig<EffectId::STATIC_DETAILED>
{
using type = EffectStaticDetailedConfig;
};
template <>
struct EffectConfigToId<EffectStaticDetailedConfig>
{
static constexpr auto id = EffectId::STATIC_DETAILED;
};
template <typename TLedStrip>
struct EffectIdToClass<EffectId::STATIC_DETAILED, TLedStrip>
{
using type = EffectStaticDetailed<TLedStrip>;
};

View File

@@ -0,0 +1,64 @@
#pragma once
#include "effects/Common.h"
#include "effects/AlexaSwipe.h"
#include "effects/RandomTwoColorInterpolation.h"
#pragma pack(push, 1)
struct EffectSwipeAndChangeConfig
{
EffectAlexaSwipeConfig swipeCfg;
EffectRandomTwoColorInterpolationConfig changeCfg;
};
#pragma pack(pop)
template <typename TLedStrip>
class EffectSwipeAndChange
{
public:
EffectSwipeAndChange(const EffectSwipeAndChangeConfig &cfg, TLedStrip &ledStrip)
: effect1_(cfg.swipeCfg, ledStrip),
effect2_(cfg.changeCfg, ledStrip),
effectRunning_(0)
{
}
int operator()()
{
if (!effect1_.finished())
{
return effect1_();
}
else
{
if (effectRunning_ == 0)
effect2_.begin();
effectRunning_ = 1;
return effect2_();
}
}
private:
EffectAlexaSwipe<TLedStrip> effect1_;
EffectRandomTwoColorInterpolation<TLedStrip> effect2_;
int effectRunning_;
};
// Traits
template <>
struct EffectIdToConfig<EffectId::SWIPE_AND_CHANGE>
{
using type = EffectSwipeAndChangeConfig;
};
template <>
struct EffectConfigToId<EffectSwipeAndChangeConfig>
{
static constexpr auto id = EffectId::SWIPE_AND_CHANGE;
};
template <typename TLedStrip>
struct EffectIdToClass<EffectId::SWIPE_AND_CHANGE, TLedStrip>
{
using type = EffectSwipeAndChange<TLedStrip>;
};

File diff suppressed because one or more lines are too long