Upgraded firmware for Simone Giertz's Every Day Calendar that links an ATProto-powered ESP32, for sync with goals.garden 🌱
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

Burst anim on light

+156 -24
+5 -1
README.md
··· 1 1 # foolmoron's Fork 2 - - Playing around with an animation on touch 2 + Changes: 3 + - VSCode setup - all you need is the Arduino extension, and do `Arduino: Upload`. The libraries will be copied automatically. 4 + - Simplified brightness button - pressing darken/brigthen will fully turn off/on the lights with one tap. 5 + - Light wave effect when turning on a light - animates a wave of brightness across the columns. 6 + - Starburst effect when turning on a light - animates lights around the one you touched, like fireworks. 3 7 4 8 # The Every Day Calendar 5 9
+40 -21
firmware/libraries/EverydayCalendar/EverydayCalendar_lights.cpp
··· 40 40 41 41 static const int BRIGHT_SHIFT_TICKS = 1; 42 42 43 + static uint32_t overrideOnValues[12] = {0}; // override light to on 44 + 43 45 void EverydayCalendar_lights::configure(){ 44 46 // LED configurations 45 47 SPI.begin(); ··· 64 66 65 67 void EverydayCalendar_lights::clearAllLEDs(){ 66 68 memset(ledValues, 0, sizeof(ledValues)); 69 + memset(overrideOnValues, 0, sizeof(overrideOnValues)); 67 70 } 68 71 69 72 // Month is in range [0,11] 70 73 // Day is in range [0,30] 71 - void EverydayCalendar_lights::setLED(uint8_t month, uint8_t day, bool enable){ 74 + void setLEDInternal(uint32_t* values, uint8_t month, uint8_t day, bool enable){ 72 75 if (month > 11 || day > 30){ 73 76 return; 74 77 } 75 78 76 79 if (enable){ 77 - ledValues[month] = ledValues[month] | ((uint32_t)1 << day); 80 + values[month] = values[month] | ((uint32_t)1 << day); 81 + }else{ 82 + values[month] = values[month] & ~((uint32_t)1 << day); 83 + } 84 + } 78 85 79 - if (loaded) { 80 - // Run animation for this month 81 - animMonth = month; 82 - for (size_t i = 0; i < 12; i++) 83 - { 84 - int dist = abs((int)month - (int)i); 85 - brights[i].brightnessX10 = dist == 0 ? BRIGHTNESS_LIGHTEST_X10 : BRIGHTNESS_INITIAL_X10; 86 - brights[i].delayTicks = dist * BRIGHTNESS_DELAY_DIST_TICKS; 87 - brights[i].state = dist == 0 ? Brightening : Delayed; 88 - } 86 + void EverydayCalendar_lights::setLED(uint8_t month, uint8_t day, bool enable){ 87 + setLEDInternal(ledValues, month, day, enable); 88 + } 89 + 90 + bool EverydayCalendar_lights::toggleLED(uint8_t month, uint8_t day){ 91 + bool ledState = (*(ledValues+month) & ((uint32_t)1 << (day))); 92 + bool newState = !ledState; 93 + setLED(month, day, newState); 94 + 95 + // Run animation for this month 96 + if (loaded && newState) { 97 + animMonth = month; 98 + for (size_t i = 0; i < 12; i++) 99 + { 100 + int dist = abs((int)month - (int)i); 101 + brights[i].brightnessX10 = dist == 0 ? BRIGHTNESS_LIGHTEST_X10 : BRIGHTNESS_INITIAL_X10; 102 + brights[i].delayTicks = dist * BRIGHTNESS_DELAY_DIST_TICKS; 103 + brights[i].state = dist == 0 ? Brightening : Delayed; 89 104 } 90 - }else{ 91 - ledValues[month] = ledValues[month] & ~((uint32_t)1 << day); 92 105 } 106 + 107 + return newState; 93 108 } 94 109 95 - void EverydayCalendar_lights::toggleLED(uint8_t month, uint8_t day){ 96 - bool ledState = (*(ledValues+month) & ((uint32_t)1 << (day))); 97 - setLED(month, day, !ledState); 110 + void EverydayCalendar_lights::setOverrideLED(uint8_t month, uint8_t day, bool enable){ 111 + setLEDInternal(overrideOnValues, month, day, enable); 112 + } 113 + 114 + void EverydayCalendar_lights::clearOverrideLEDs(){ 115 + memset(overrideOnValues, 0, sizeof(overrideOnValues)); 98 116 } 99 117 100 118 void EverydayCalendar_lights::saveLedStatesToMemory(){ ··· 209 227 // update the next column 210 228 uint16_t month = (1 << activeColumn); 211 229 uint8_t * pDays = (uint8_t*) (ledValues + activeColumn); 230 + uint8_t * overrideOnDays = (uint8_t*) (overrideOnValues + activeColumn); 212 231 213 232 // Send the LED control values into the shift registers 214 233 digitalWrite (csPin, LOW); 215 234 SPI.beginTransaction(spiSettings); 216 235 memcpy(spiBuf, &month, 2); 217 - spiBuf[2] = pDays[3]; 218 - spiBuf[3] = pDays[2]; 219 - spiBuf[4] = pDays[1]; 220 - spiBuf[5] = pDays[0]; 236 + spiBuf[2] = pDays[3] | overrideOnDays[3]; 237 + spiBuf[3] = pDays[2] | overrideOnDays[2]; 238 + spiBuf[4] = pDays[1] | overrideOnDays[1]; 239 + spiBuf[5] = pDays[0] | overrideOnDays[0]; 221 240 SPI.transfer(spiBuf, sizeof(spiBuf)); 222 241 SPI.endTransaction(); 223 242 digitalWrite (csPin, HIGH);
+3 -1
firmware/libraries/EverydayCalendar/EverydayCalendar_lights.h
··· 12 12 void saveLedStatesToMemory(); 13 13 14 14 void setLED(uint8_t month, uint8_t day, bool enable); 15 - void toggleLED(uint8_t month, uint8_t day); 15 + bool toggleLED(uint8_t month, uint8_t day); 16 16 void clearAllLEDs(); 17 17 void setBrightness(uint8_t brightness); 18 18 19 + void setOverrideLED(uint8_t month, uint8_t day, bool enable); 20 + void EverydayCalendar_lights::clearOverrideLEDs(); 19 21 }; 20 22 21 23 #endif
+108 -1
firmware/sketches/EverydayCalendar/EverydayCalendar.ino
··· 10 10 EverydayCalendar_lights cal_lights; 11 11 int16_t brightness = 128; 12 12 13 + 14 + typedef struct { 15 + Point p; 16 + // Max means this burst is deactivated and the struct 17 + // can be reused. Set it to 0 to activate the burst. 18 + uint16_t tick = UINT16_MAX; 19 + } Burst; 20 + const size_t BURST_COUNT = 8; 21 + Burst bursts[BURST_COUNT]; 22 + 23 + typedef struct { 24 + Point offset; 25 + uint16_t tickStart; 26 + uint16_t tickEnd; 27 + } AnimPattern; 28 + const AnimPattern ANIM[] = { 29 + // 1st ring 30 + {{ -1, 0}, 0, 3}, 31 + {{ 1, 0}, 0, 3}, 32 + {{ 0, -1}, 1, 3}, 33 + {{ 0, 1}, 1, 3}, 34 + 35 + // 2nd ring 36 + {{ 1, -1}, 2, 6}, 37 + {{ 1, 1}, 2, 6}, 38 + {{ -1, -1}, 2, 6}, 39 + {{ -1, 1}, 2, 6}, 40 + {{ 0, -2}, 2, 5}, 41 + {{ 0, 2}, 2, 5}, 42 + {{ -2, 0}, 5, 36 }, // these lingering are #s between 24-46, spaced 2 apart, shuffled randomly 43 + {{ 2, 0}, 5, 32 }, 44 + 45 + // 3rd ring 46 + {{ -2, -1}, 7, 34 }, 47 + {{ -2, 1}, 7, 24 }, 48 + {{ 2, -1}, 7, 44 }, 49 + {{ 2, 1}, 7, 42 }, 50 + {{ -1, -2}, 6, 26 }, 51 + {{ -1, 2}, 6, 46 }, 52 + {{ 1, -2}, 6, 28 }, 53 + {{ 1, 2}, 6, 38 }, 54 + {{ 0, -3}, 4, 40 }, 55 + {{ 0, 3}, 4, 30 }, 56 + }; 57 + const size_t ANIM_COUNT = sizeof(ANIM)/sizeof(ANIM[0]); 58 + 59 + uint16_t ANIM_MAX_TICK = 0; 60 + 61 + 62 + void doBurst(Point p) { 63 + for (size_t i = 0; i < BURST_COUNT; i++) 64 + { 65 + Burst* burst = &bursts[i]; 66 + if (burst->tick == UINT16_MAX) { 67 + burst->p = p; 68 + burst->tick = 0; 69 + return; 70 + } 71 + } 72 + } 73 + 13 74 void setup() { 14 75 Serial.begin(9600); 15 76 Serial.println("Sketch setup started"); 77 + 78 + // Init data 79 + for (size_t a = 0; a < ANIM_COUNT; a++) 80 + { 81 + if (ANIM[a].tickEnd > ANIM_MAX_TICK) { 82 + ANIM_MAX_TICK = ANIM[a].tickEnd; 83 + } 84 + } 16 85 17 86 // Initialize LED functionality 18 87 cal_lights.configure(); ··· 78 147 // This is called debouncing 79 148 if (touchCount == debounceCount){ 80 149 // Button is activated 81 - cal_lights.toggleLED((uint8_t)cal_touch.x, (uint8_t)cal_touch.y); 150 + bool on = cal_lights.toggleLED((uint8_t)cal_touch.x, (uint8_t)cal_touch.y); 82 151 cal_lights.saveLedStatesToMemory(); 83 152 Serial.print("x: "); 84 153 Serial.print(cal_touch.x); 85 154 Serial.print("\ty: "); 86 155 Serial.println(cal_touch.y); 156 + 157 + // Burst if toggled on 158 + if (on) { 159 + doBurst({cal_touch.x, cal_touch.y}); 160 + } 87 161 } 88 162 89 163 // Check if the special "Reset" January 1 button is being held ··· 101 175 102 176 previouslyHeldButton.x = cal_touch.x; 103 177 previouslyHeldButton.y = cal_touch.y; 178 + 179 + // Bursts 180 + bool needsClearing = true; 181 + for (size_t i = 0; i < BURST_COUNT; i++) 182 + { 183 + // increment tick for active bursts 184 + Burst* burst = &bursts[i]; 185 + if (burst->tick == UINT16_MAX) { 186 + continue; 187 + } 188 + burst->tick++; 189 + 190 + // clear previous overrides if necessary 191 + if (needsClearing) { 192 + cal_lights.clearOverrideLEDs(); 193 + needsClearing = false; 194 + } 195 + 196 + // end burst when at max tick 197 + if (burst->tick >= ANIM_MAX_TICK) { 198 + burst->tick = UINT16_MAX; 199 + continue; 200 + } 201 + 202 + // enable the overrides for this tick 203 + for (size_t a = 0; a < ANIM_COUNT; a++) { 204 + const AnimPattern* anim = &ANIM[a]; 205 + if (burst->tick < anim->tickStart || burst->tick >= anim->tickEnd) { 206 + continue; 207 + } 208 + cal_lights.setOverrideLED(burst->p.x + anim->offset.x, burst->p.y + anim->offset.y, true); 209 + } 210 + } 104 211 } 105 212 106 213 void honeyDrip(){