multithreaded animation updates
Haldean Brown
3 years ago
14 | 14 | import requests |
15 | 15 | import screen |
16 | 16 | from screen import Screen |
17 | import threading | |
17 | 18 | import time |
19 | import traceback | |
18 | 20 | |
19 | 21 | |
20 | 22 | class SerialError(Exception): |
34 | 36 | def __init__(self): |
35 | 37 | self._sid = None |
36 | 38 | print("starting bitpic with screen ID {}".format(self.sid)) |
39 | self.new_screen = None | |
37 | 40 | self.current_screen = None |
38 | 41 | self.current_anim = None |
39 | 42 | self.last_anim_check = None |
153 | 156 | print("failed to load screen: {}".format(e)) |
154 | 157 | return None |
155 | 158 | |
156 | def loop(self): | |
157 | time_check = (self.last_anim_check is None or | |
158 | datetime.now() - self.last_anim_check > timedelta(seconds=30)) | |
159 | if time_check or self.current_anim is None: | |
160 | new_screen = self.load() | |
161 | if new_screen is not None: | |
162 | self.current_anim = None | |
163 | if new_screen != self.current_screen: | |
164 | self.fade_between(self.current_screen, new_screen) | |
165 | self.current_screen = new_screen | |
166 | else: | |
167 | # we write even if the screen hasn't changed so we can | |
168 | # detect disconnected displays for reconnection | |
169 | self.write_screen(self.current_screen) | |
170 | time.sleep(5) | |
171 | return | |
172 | if self.current_anim is not None: | |
159 | def load_loop(self): | |
160 | self.new_screen = self.load() | |
161 | if self.new_screen is not None: | |
162 | self.current_anim is None | |
163 | ||
164 | def anim_loop(self): | |
165 | current_anim = self.current_anim | |
166 | current_screen = self.current_screen | |
167 | new_screen = self.new_screen | |
168 | ||
169 | if current_anim is not None: | |
173 | 170 | # if we get here, we either didn't check for new data and are in an |
174 | 171 | # animation, or we did check for new data and found out we're in an |
175 | 172 | # animation. |
176 | anim_screen = self.current_anim.get_screen() | |
173 | anim_screen = current_anim.get_screen() | |
177 | 174 | self.write_screen(anim_screen) |
178 | time.sleep(self.current_anim.desired_frame_time) | |
175 | time.sleep(current_anim.desired_frame_time) | |
176 | elif new_screen is not None: | |
177 | if new_screen != current_screen: | |
178 | self.fade_between(current_screen, new_screen) | |
179 | self.current_screen = new_screen | |
180 | else: | |
181 | # we write even if the screen hasn't changed so we can | |
182 | # detect disconnected displays for reconnection | |
183 | self.write_screen(current_screen) | |
184 | time.sleep(0.1) | |
185 | else: | |
186 | time.sleep(0.1) | |
179 | 187 | |
180 | 188 | def main(self): |
189 | def run_load_loop(): | |
190 | while True: | |
191 | try: | |
192 | self.load_loop() | |
193 | except Exception: | |
194 | traceback.print_exc() | |
195 | time.sleep(5) | |
196 | ||
197 | load_thread = threading.Thread(target=run_load_loop, daemon=True) | |
198 | load_thread.start() | |
181 | 199 | try: |
182 | 200 | while True: |
183 | 201 | try: |
184 | self.loop() | |
202 | self.anim_loop() | |
185 | 203 | except SerialError: |
186 | 204 | self.create_driver() |
187 | 205 | except KeyboardInterrupt: |
188 | 206 | self.led.all_off() |
189 | 207 | self.led.push_to_driver() |
190 | 208 | |
209 | ||
191 | 210 | if __name__ == "__main__": |
192 | 211 | bp = Bitpic() |
193 | 212 | bp.main() |