Skip to content

Commit fd92dab

Browse files
Macropad hotkeys: Add screensaver mode to prevent OLED burn-in
This commit introduces a screensaver mode to the Adafruit Macropad hotkeys script, addressing issue #2882. Key Changes: - Screensaver Activation: Added a new configurable parameter SCREENSAVER_START_TIME, which specifies the duration of inactivity (in seconds) before the screensaver activates. - Class-Level Variables: Introduced class-level variables in the App class to track the last activity time, screensaver mode status, and breathing effect brightness. - Screensaver Functions: Added helper functions: * enter_screensaver_mode(): Turns off the OLED display and LEDs, entering screensaver mode. * wake_from_screensaver(): Exits screensaver mode and restores the previous state of the display and LEDs. * screensaver_breathing_effect(): Implements a breathing LED effect during screensaver mode. - Main Loop Integration: Modified the main loop to monitor inactivity and trigger the screensaver mode based on the specified timeout. This update ensures the Macropad's OLED display is protected from burn-in during extended periods of inactivity. Fixes issue #2882. Signed-off-by: Flavio Fernandes <[email protected]>
1 parent 24406bf commit fd92dab

File tree

1 file changed

+47
-1
lines changed

1 file changed

+47
-1
lines changed

Diff for: Macropad_Hotkeys/code.py

+47-1
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,29 @@
2323
# CONFIGURABLES ------------------------
2424

2525
MACRO_FOLDER = '/macros'
26-
26+
SCREENSAVER_START_TIME = 10 * 60 # seconds of inactivity will clear oled to avoid burn in
2727

2828
# CLASSES AND FUNCTIONS ----------------
2929

3030
class App:
3131
""" Class representing a host-side application, for which we have a set
3232
of macro sequences. Project code was originally more complex and
3333
this was helpful, but maybe it's excessive now?"""
34+
35+
# Class-level variables (shared among all instances)
36+
last_activity_time = time.monotonic()
37+
in_screensaver_mode = False
38+
breathing_brightness = 0.1 # Initial brightness
39+
breathing_direction = 1 # 1 for increasing brightness, -1 for decreasing
40+
3441
def __init__(self, appdata):
3542
self.name = appdata['name']
3643
self.macros = appdata['macros']
3744

3845
def switch(self):
3946
""" Activate application settings; update OLED labels and LED
4047
colors. """
48+
App.last_activity_time = time.monotonic()
4149
group[13].text = self.name # Application name
4250
if self.name:
4351
rect.fill = 0xFFFFFF
@@ -57,6 +65,29 @@ def switch(self):
5765
macropad.pixels.show()
5866
macropad.display.refresh()
5967

68+
# SCREENSAVER MODE HELPERS -------------
69+
70+
def enter_screensaver_mode():
71+
macropad.display.auto_refresh = False
72+
macropad.display_sleep = True
73+
for i in range(12):
74+
macropad.pixels[i] = 0 # Turn off all key LEDs
75+
macropad.pixels.show()
76+
App.in_screensaver_mode = True
77+
78+
def wake_from_screensaver():
79+
App.in_screensaver_mode = False
80+
macropad.display_sleep = False
81+
macropad.display.auto_refresh = True
82+
apps[app_index].switch() # Redraw the OLED and LEDs
83+
84+
def screensaver_breathing_effect():
85+
App.breathing_brightness += 0.001 * App.breathing_direction
86+
if App.breathing_brightness >= 1.0 or App.breathing_brightness <= 0.1:
87+
App.breathing_direction *= -1 # Reverse direction
88+
pixel_brightness = int(255 * App.breathing_brightness)
89+
macropad.pixels[0] = (0, pixel_brightness, 0) # Green key for breathing effect
90+
macropad.pixels.show()
6091

6192
# INITIALIZATION -----------------------
6293

@@ -111,9 +142,13 @@ def switch(self):
111142
# MAIN LOOP ----------------------------
112143

113144
while True:
145+
current_time = time.monotonic()
146+
114147
# Read encoder position. If it's changed, switch apps.
115148
position = macropad.encoder
116149
if position != last_position:
150+
if App.in_screensaver_mode:
151+
wake_from_screensaver()
117152
app_index = position % len(apps)
118153
apps[app_index].switch()
119154
last_position = position
@@ -132,6 +167,12 @@ def switch(self):
132167
else:
133168
event = macropad.keys.events.get()
134169
if not event or event.key_number >= len(apps[app_index].macros):
170+
if App.in_screensaver_mode:
171+
screensaver_breathing_effect() # Continue breathing effect in screensaver mode
172+
else:
173+
time_since_last_activity = current_time - App.last_activity_time
174+
if time_since_last_activity > SCREENSAVER_START_TIME:
175+
enter_screensaver_mode()
135176
continue # No key events, or no corresponding macro, resume loop
136177
key_number = event.key_number
137178
pressed = event.pressed
@@ -140,8 +181,13 @@ def switch(self):
140181
# and there IS a corresponding macro available for it...other situations
141182
# are avoided by 'continue' statements above which resume the loop.
142183

184+
App.last_activity_time = current_time # Reset inactivity timer
143185
sequence = apps[app_index].macros[key_number][2]
144186
if pressed:
187+
if App.in_screensaver_mode:
188+
wake_from_screensaver()
189+
continue # Skip this event, as it was used for screen wake up
190+
145191
# 'sequence' is an arbitrary-length list, each item is one of:
146192
# Positive integer (e.g. Keycode.KEYPAD_MINUS): key pressed
147193
# Negative integer: (absolute value) key released

0 commit comments

Comments
 (0)