|
#include "SoftPWM.h"
|
|
|
|
int pulseMin = 1; // Minimum number of pulses in each set
|
|
int pulseMax = 5; // Maximum number of pulses in each set
|
|
int brightMin = 128; // Baseline LED brightness. Cannot exceed 128.
|
|
int minDelay = 3000; // Minimum delay between pulse sets (ms)
|
|
int maxDelay = 8000; // Maximum delay between pulse sets (ms)
|
|
int minPulseSpeed = 3; // Minimum dimming speed for pulses (lower is faster)
|
|
int maxPulseSpeed = 5; // Maximum dimming speed for pulses (lower is faster)
|
|
int minPulseGap = 10; // Minimum delay between two pulses (ms)
|
|
int maxPulseGap = 15; // Maximum delay between two pulses (ms)
|
|
|
|
const int numberOfCandles = 14;
|
|
|
|
//#define DEBUG
|
|
|
|
class Candle {
|
|
private:
|
|
int pin;
|
|
|
|
unsigned long nextActionTimestamp;
|
|
|
|
int pulsesLeftInCurrentFlicker;
|
|
|
|
int brightnessOfCurrentPulse;
|
|
int currentBrightness;
|
|
|
|
int currentPulseSpeed;
|
|
int currentPulseDuration;
|
|
|
|
Candle* adjacentCandles[numberOfCandles];
|
|
bool triggerAdjacentFlicker = false;
|
|
|
|
public:
|
|
Candle() : Candle(0){};
|
|
Candle(int pin) : pin(pin) {
|
|
for(int i=0; i<numberOfCandles; i++) {
|
|
adjacentCandles[i] = NULL;
|
|
}
|
|
scheduleNextFlicker();
|
|
}
|
|
|
|
void addAdjacentCandle(Candle* otherCandle){
|
|
for(int i=0; i<numberOfCandles; i++) {
|
|
if(adjacentCandles[i] == NULL){
|
|
adjacentCandles[i] = otherCandle;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void adjacentFlicker() {
|
|
scheduleNextFlicker();
|
|
nextActionTimestamp = millis();
|
|
triggerAdjacentFlicker = false;
|
|
}
|
|
|
|
void execute() {
|
|
if(nextActionTimestamp > millis()){
|
|
return;
|
|
}
|
|
|
|
if(triggerAdjacentFlicker) {
|
|
for(int i=0; i<numberOfCandles; i++) {
|
|
if(adjacentCandles[i] != NULL){
|
|
adjacentCandles[i]->adjacentFlicker();
|
|
}
|
|
}
|
|
triggerAdjacentFlicker = false;
|
|
}
|
|
|
|
if(pulsesLeftInCurrentFlicker == 0) {
|
|
scheduleNextFlicker();
|
|
return;
|
|
}
|
|
|
|
if(currentBrightness != brightnessOfCurrentPulse) {
|
|
brightnessStep();
|
|
waitFor(currentPulseSpeed);
|
|
return;
|
|
}
|
|
|
|
if(currentBrightness == brightMin){
|
|
pulsesLeftInCurrentFlicker--;
|
|
waitFor(currentPulseDuration);
|
|
determineSettingsOfNextPulse();
|
|
} else {
|
|
brightnessOfCurrentPulse = brightMin;
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
void scheduleNextFlicker() {
|
|
pulsesLeftInCurrentFlicker = random(pulseMin, pulseMax);
|
|
determineSettingsOfNextPulse();
|
|
triggerAdjacentFlicker = true;
|
|
waitFor(random(minDelay, maxDelay));
|
|
}
|
|
|
|
void determineSettingsOfNextPulse() {
|
|
currentPulseSpeed = random(minPulseSpeed, maxPulseSpeed);
|
|
currentPulseDuration = random(minPulseGap, maxPulseGap);
|
|
brightnessOfCurrentPulse = 224 - random(96);
|
|
}
|
|
|
|
void waitFor(int milliseconds){
|
|
nextActionTimestamp = millis() + milliseconds;
|
|
}
|
|
|
|
void brightnessStep() {
|
|
if(currentBrightness < brightnessOfCurrentPulse) {
|
|
currentBrightness++;
|
|
} else {
|
|
currentBrightness--;
|
|
}
|
|
|
|
SoftPWMSet(pin, currentBrightness);
|
|
}
|
|
|
|
};
|
|
|
|
Candle candles[numberOfCandles];
|
|
|
|
void setup()
|
|
{
|
|
#ifdef DEBUG
|
|
Serial.begin(115200);
|
|
Serial.println("started");
|
|
#endif
|
|
randomSeed(analogRead(A0));
|
|
SoftPWMBegin();
|
|
for (byte i = 0; i < numberOfCandles; i++) {
|
|
candles[i] = Candle(i);
|
|
}
|
|
|
|
Candle *buerger = candles + 6;
|
|
Candle *bild = candles + 3;
|
|
Candle *erker = candles + 4;
|
|
Candle *schmied = candles + 7;
|
|
Candle *bauern = candles + 5;
|
|
Candle *spitzgiebel = candles + 9;
|
|
Candle *gasthaus = candles + 12;
|
|
Candle *kapelle = candles + 11;
|
|
Candle *rathaus = candles + 10;
|
|
|
|
buerger->addAdjacentCandle(bild);
|
|
buerger->addAdjacentCandle(bauern);
|
|
buerger->addAdjacentCandle(erker);
|
|
|
|
bild->addAdjacentCandle(buerger);
|
|
bild->addAdjacentCandle(erker);
|
|
|
|
erker->addAdjacentCandle(bild);
|
|
erker->addAdjacentCandle(buerger);
|
|
erker->addAdjacentCandle(schmied);
|
|
|
|
spitzgiebel->addAdjacentCandle(gasthaus);
|
|
|
|
gasthaus->addAdjacentCandle(spitzgiebel);
|
|
gasthaus->addAdjacentCandle(kapelle);
|
|
gasthaus->addAdjacentCandle(rathaus);
|
|
|
|
kapelle->addAdjacentCandle(gasthaus);
|
|
kapelle->addAdjacentCandle(rathaus);
|
|
|
|
rathaus->addAdjacentCandle(kapelle);
|
|
rathaus->addAdjacentCandle(gasthaus);
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
for (byte i = 0; i < numberOfCandles; i++) {
|
|
candles[i].execute();
|
|
}
|
|
}
|