Skip to content

Commit b40d421

Browse files
committed
🥅 Ensure full coverage of runner for errors, so nothing fails silently
1 parent 0102e0f commit b40d421

File tree

1 file changed

+90
-82
lines changed

1 file changed

+90
-82
lines changed

octoprint_ws281x_led_status/runner/__init__.py

Lines changed: 90 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -56,98 +56,106 @@ def __init__(
5656
self.setup_custom_logger(log_path, debug)
5757
self._logger.debug("Starting WS281x LED Status Effect runner")
5858

59-
self.segment_manager = None # type Optional[segments.SegmentManager]
60-
61-
# Save settings to class
62-
self.strip_settings = strip_settings
63-
self.effect_settings = effect_settings
64-
self.features_settings = features_settings
65-
self.active_times_settings = features_settings["active_times"]
66-
self.transition_settings = features_settings["transitions"]
67-
self.max_brightness = int(
68-
round((float(strip_settings["brightness"]) / 100) * 255)
69-
)
70-
self.color_correction = {
71-
"red": self.strip_settings["adjustment"]["R"],
72-
"green": self.strip_settings["adjustment"]["G"],
73-
"blue": self.strip_settings["adjustment"]["B"],
74-
"white_override": self.strip_settings["white_override"],
75-
"white_brightness": self.strip_settings["white_brightness"],
76-
}
77-
78-
# Create segment settings
79-
# Segments are EXPERIMENTAL and only enabled for certain conditions
80-
self.segment_settings = []
81-
82-
# Sacrificial pixel offsets by one
83-
default_segment = {"start": 0, "end": int(self.strip_settings["count"])}
84-
if self.features_settings["sacrifice_pixel"]:
85-
default_segment["start"] = 1
86-
87-
self.segment_settings.append(default_segment)
88-
89-
if int(self.strip_settings["count"]) < 6:
90-
self._logger.info("Applying < 6 LED flickering bug workaround")
91-
# rpi_ws281x will think we want 6 LEDs, but we will only use those configured
92-
# this works around issues where LEDs would show the wrong colour, flicker and more
93-
# when used with less than 6 LEDs.
94-
# See #132 for details
95-
self.strip_settings["count"] = 6
96-
97-
# State holders
98-
self.lights_on = saved_lights_on
99-
self.previous_state = previous_state
100-
self.previous_m150 = {} # type: dict
101-
self.active_times_state = True
102-
self.turn_off_timer = None
103-
104-
self.queue = queue # type: multiprocessing.Queue
10559
try:
106-
self.strip = self.start_strip() # type: PixelStrip
107-
except (StripFailedError, segments.InvalidSegmentError):
108-
self._logger.error("Exiting the effect process")
109-
return
110-
except Exception as e:
111-
self._logger.exception(e)
112-
self._logger.error("Exiting the effect process")
113-
return
114-
115-
self.effect_queue = Queue()
116-
self.effect_thread = None # type: Optional[threading.Thread]
117-
118-
self.brightness_manager = BrightnessManager(
119-
self.strip, self.max_brightness, self.transition_settings
120-
)
121-
122-
# Create 'Active Times' background timers
123-
self.active_times_timer = active_times.ActiveTimer(
124-
self.active_times_settings, self.switch_lights
125-
)
126-
self.active_times_timer.start_timer()
60+
# This entire thing is wrapped in a try: except block because otherwise errors here would
61+
# cause the process to crash but nobody would know about it, it died silently.
62+
63+
self.segment_manager = None # type Optional[segments.SegmentManager]
64+
65+
# Save settings to class
66+
self.strip_settings = strip_settings
67+
self.effect_settings = effect_settings
68+
self.features_settings = features_settings
69+
self.active_times_settings = features_settings["active_times"]
70+
self.transition_settings = features_settings["transitions"]
71+
self.max_brightness = int(
72+
round((float(strip_settings["brightness"]) / 100) * 255)
73+
)
74+
self.color_correction = {
75+
"red": self.strip_settings["adjustment"]["R"],
76+
"green": self.strip_settings["adjustment"]["G"],
77+
"blue": self.strip_settings["adjustment"]["B"],
78+
"white_override": self.strip_settings["white_override"],
79+
"white_brightness": self.strip_settings["white_brightness"],
80+
}
12781

128-
if debug:
129-
self.log_settings()
130-
else:
131-
self._logger.info(
132-
"Debug logging not enabled, if you are reporting issues please enable it "
133-
"under 'Features' in the settings page."
82+
# Create segment settings
83+
# Segments are EXPERIMENTAL and only enabled for certain conditions
84+
self.segment_settings = []
85+
86+
# Sacrificial pixel offsets by one
87+
default_segment = {"start": 0, "end": int(self.strip_settings["count"])}
88+
if self.features_settings["sacrifice_pixel"]:
89+
default_segment["start"] = 1
90+
91+
self.segment_settings.append(default_segment)
92+
93+
if int(self.strip_settings["count"]) < 6:
94+
self._logger.info("Applying < 6 LED flickering bug workaround")
95+
# rpi_ws281x will think we want 6 LEDs, but we will only use those configured
96+
# this works around issues where LEDs would show the wrong colour, flicker and more
97+
# when used with less than 6 LEDs.
98+
# See #132 for details
99+
self.strip_settings["count"] = 6
100+
101+
# State holders
102+
self.lights_on = saved_lights_on
103+
self.previous_state = previous_state
104+
self.previous_m150 = {} # type: dict
105+
self.active_times_state = True
106+
self.turn_off_timer = None
107+
108+
self.queue = queue # type: multiprocessing.Queue
109+
try:
110+
self.strip = self.start_strip() # type: PixelStrip
111+
except (StripFailedError, segments.InvalidSegmentError):
112+
self._logger.error("Exiting the effect process")
113+
return
114+
except Exception as e:
115+
self._logger.exception(e)
116+
self._logger.error("Exiting the effect process")
117+
return
118+
119+
self.effect_queue = Queue()
120+
self.effect_thread = None # type: Optional[threading.Thread]
121+
122+
self.brightness_manager = BrightnessManager(
123+
self.strip, self.max_brightness, self.transition_settings
134124
)
135125

136-
# Set back previous state, unless it is `blank`, then start main loop
137-
if not (
138-
self.previous_state["type"] == "standard"
139-
and self.previous_state["effect"] == "blank"
140-
):
141-
self._logger.debug(
142-
"Returning to previous state: {}".format(self.previous_state)
126+
# Create 'Active Times' background timers
127+
self.active_times_timer = active_times.ActiveTimer(
128+
self.active_times_settings, self.switch_lights
143129
)
144-
self.parse_q_msg(self.previous_state)
130+
self.active_times_timer.start_timer()
131+
132+
if debug:
133+
self.log_settings()
134+
else:
135+
self._logger.info(
136+
"Debug logging not enabled, if you are reporting issues please enable it "
137+
"under 'Features' in the settings page."
138+
)
139+
except Exception as e:
140+
self._logger.error("Unhandled error starting the effect runner")
141+
self._logger.exception(e)
142+
return
145143

146-
self._logger.info("Startup Complete!")
147144
self.main_loop()
148145

149146
def main_loop(self):
150147
try:
148+
# Set back previous state, unless it is `blank`, then start main loop
149+
if not (
150+
self.previous_state["type"] == "standard"
151+
and self.previous_state["effect"] == "blank"
152+
):
153+
self._logger.debug(
154+
"Returning to previous state: {}".format(self.previous_state)
155+
)
156+
self.parse_q_msg(self.previous_state)
157+
158+
self._logger.info("Starting main loop")
151159
while True:
152160
msg = self.queue.get()
153161
self._logger.debug("New message: {}".format(msg))

0 commit comments

Comments
 (0)