Hey @shmimel!
I so remember struggling initially to wrap my head around how to do things in a world where I didn’t have sleep() or wait() to delay execution. But now I’m so glad I understand this alternate timing paradigm because it’s used in a lot of other places (gaming, task scheduling) and is more flexible and portable.
For your particular use case, which is around responding to an event and doing something for some amount of time right after, I’m going to suggest you use delta
instead of time()
. You’ll see the accelerometer example (scroll to “Example code: Shake to switch modes”) uses delta to do something similar, debouncing the shake motion. Debouncing means not letting it trigger multiple times as part of the same motion.
As a quick reminder:
// Stuff outside of either function - things to execute or declare one time
var hue
// Stuff to do once-per-frame, right before we recalculate all the colors for each pixel
// `delta` is the number of milliseconds that has passed since the last time beforeRender() ran.
export function beforeRender(delta) {
// Excellent spot to work with time,
// compute things that don't vary based on pixel position,
// or read sensors or websocket API data.
}
export function render(index) {
// Calculate things that vary based on the LEDs position in space
}
So with that reminder of where delta is used, here’s an example that will flash all the LEDs white for 1 second (or, 1000 milliseconds) after some motion is triggered.
var isBlinkingNow = 0
var currentBlinkDurationMs = 0
export function beforeRender(delta) {
// Some imaginary accelerometer code here sets "isBlinkingNow" to 1
// if the desired motion is detected.
if (!isBlinkingNow && accelerometerDetectionCode) isBlinkingNow = 1
if (isBlinkingNow) {
currentBlinkDurationMs = currentBlinkDurationMs + delta
if (currentBlinkDurationMs > 1000) {
currentBlinkDurationMs = 0
isBlinkingNow = 0
}
}
}
export function render(index) {
if (isBlinkingNow) {
hsv(0, 0, 1) // all LEDs white
} else {
// Some other normal pattern code
hsv(index / pixelCount, 1, .25)
}
}
Folks sometimes refer to this technique as “accumulating delta”.
It’s possible to do something similar using just time()
, but it’s a little less readable and can start to break down in scenarios where the waiting period is close to or greater than time()'s period or close to delta
, so it’s not recommended. For the sake of completeness:
var isBlinkingNow = 0
var blinkStartRampValue = -1
var timerDuration = 1 // in seconds.
export function beforeRender(delta) {
// time(10 / 65.535) ramps from 0 to 1 every 10 seconds, so .2 is a second after .1.
timeRampNow = time(10 / 65.535)
// Some imaginary accelerometer code here sets "isBlinkingNow" to 1
// if the desired motion is detected.
if (!isBlinkingNow && accelerometerDetectionCode) {
isBlinkingNow = 1
blinkStartRampValue = timeRampNow
}
if (isBlinkingNow) { // We're doing something for timerDuration
if (
timeRampNow > (blinkStartRampValue + timerDuration / 10) ||
( (timeRampNow < blinkStartRampValue)
&& timeRampNow > (blinkStartRampValue + timerDuration / 10) % 1
)
) {
isBlinkingNow = 0
}
}
}
export function render(index) {
if (isBlinkingNow) {
hsv(0, 0, 1) // all LEDs white
} else {
// Some other normal pattern code
hsv(index / pixelCount, 1, .25)
}
}
I don’t find that as easy to read since you need to detect time()'s potential wraparound.