22""" the all the app runner needs to do is import one variable: 'display' """
33
44""" All Devices Need These """
5+ from bbapp .version import version
56from .config import screen
7+ from .font_runner import sm_font , score_font , date_font
8+ from .ili9341 import color565
69
710""" Break Down of Individual Personalities """
811if 'ili' in screen :
912
1013 from .ili9341_runner import display
11-
14+ white = color565 (255 ,255 ,255 )
15+ drk_grn = color565 (50 ,100 ,30 )
16+ red = color565 (255 , 0 , 0 )
17+ black = color565 (0 , 0 , 0 )
18+ def check_upgrade ():
19+ return False
20+
1221elif screen == "lilygo_watch" :
1322
1423 from .lilygo_watch_1_54_inch import display
24+ def check_upgrade ():
25+ return False
26+
27+ if 'esp32-s3-box' in screen :
28+
29+ from machine import ADC , Pin
30+ adc = ADC (Pin (1 ))
31+
32+ if screen == 'esp32-s3-box-lite' :
33+
34+ from .espboxlite import display
35+
36+ """ BOX-LITE specifics """
37+ #NOTE: S3-ESP32-BOX-LITE - INVERTED w/ili9341
38+ drk_grn = color565 (255 ,222 ,255 )
39+ white = color565 (0 , 0 , 0 )
40+ black = color565 (255 ,255 ,255 )
41+ yellow = color565 (255 , 0 , 0 )
42+ green = color565 (0 ,0 ,255 )
43+ pink = color565 (0 , 255 , 0 )
44+
45+ def check_upgrade ():
46+ """ We only check Button 3 - It's on GPIO01
47+ #Unpushed
48+ >>> adc.read_u16()
49+ 65535
50+
51+ #Pushed
52+ >>> adc.read_u16()
53+ 55261
54+ """
55+ if str (adc .read_u16 ()).startswith ('55' ):
56+ return True
57+
58+ if screen == 'esp32-s3-box' :
59+
60+ from .espbox import display
61+
62+ drk_grn = color565 (58 , 124 , 14 ) # esp full box
63+ black = color565 (0 , 0 , 0 )
64+ white = color565 (255 ,255 ,255 )
65+ yellow = color565 (255 , 0 , 0 )
66+ green = color565 (0 ,0 ,255 )
67+ pink = color565 (0 , 255 , 0 )
68+ red = color565 (255 , 0 , 0 )
69+
70+ def check_upgrade ():
71+ """ We only check the Mute Button on the ESP BOX - It's on GPIO01
72+ #Unpushed:
73+ >>>adc.read_u16()
74+ 65535
75+
76+ #Pushed
77+ >>> adc.read_u16()
78+ 0
79+ """
80+ if adc .read_u16 () == 0 :
81+ return True
82+
83+ """ How many chars per line before you hit the end """
84+ anum = {'r' : '36' , 'Y' : '19' , 'Z' : '22' , 'y' : '27' , 'x' : '27' , 'z' : '27' , 'E' :'21' ,
85+ 'D' : '19' , 'G' : '18' , 'F' : '22' , 'A' : '21' , 'C' : '19' , 'B' : '21' , 'M' :'18' ,
86+ 'L' : '25' , 'O' : '17' , 'N' : '21' , 'I' : '65' , 'H' : '21' , 'K' : '19' , 'J' : '30' ,
87+ 'U' : '21' , 'T' : '22' , 'W' : '14' , 'V' : '21' , 'Q' : '17' , 'P' : '21' , 'S' : '21' ,
88+ 'R' : '19' , 'e' : '25' , 'd' : '25' , 'g' : '25' , 'f' : '41' , 'a' : '25' , 'X' : '21' ,
89+ 'c' : '27' , 'b' : '23' , 'm' : '17' , 'l' : '65' , 'o' : '25' , 'n' : '25' , 'i' : '65' ,
90+ 'h' : '25' , 'k' : '25' , 'j' : '65' , 'u' : '25' , 't' : '41' , 'w' : '18' , 'v' : '27' ,
91+ 'q' : '25' , 'p' : '23' , 's' : '27' }
92+
93+ """ How many pixels/char, rounded up (/320) """
94+ apnt3 = {'.' :10 , 0 :13 , 1 :10 , 2 :13 , 3 :13 , 4 :13 , 5 :13 , 6 :13 , 7 :13 , 8 :13 , 9 :13 , '-' :12 ,
95+ "'" :5 , ' ' : 19 , 'r' : 8 , 'X' : 15 , 'Z' : 14 , 'y' : 11 , 'x' : 11 , 'z' : 11 ,
96+ 'E' : 15 , 'D' : 16 , 'G' : 17 , 'F' : 14 , 'A' : 15 , 'C' : 16 , 'B' : 15 , 'M' : 17 ,
97+ 'L' : 12 , 'O' : 18 , 'N' : 15 , 'I' : 4 , 'H' : 15 , 'K' : 16 , 'J' : 10 , 'U' : 15 ,
98+ 'T' : 14 , 'W' : 22 , 'V' : 15 , 'Q' : 18 , 'P' : 15 , 'S' : 15 , 'R' : 16 , 'e' : 12 ,
99+ 'd' : 12 , 'g' : 12 , 'f' : 7 , 'Y' : 16 , 'a' : 12 , 'c' : 11 , 'b' : 13 , 'm' : 18 ,
100+ 'l' : 4 , 'o' : 12 , 'n' : 12 , 'i' : 4 , 'h' : 12 , 'k' : 12 , 'j' : 4 , 'u' : 12 ,
101+ 't' : 7 , 'w' : 17 , 'v' : 11 , 'q' : 12 , 'p' : 13 , 's' : 11 }
102+
103+ """ How many pixels/char, rounded up (/240) """
104+ apnt2 = {'K' : 18 , 'J' : 11 , 'U' : 15 , 'T' : 15 , 'W' : 22 , 'V' : 16 , 'Q' : 19 , 'P' : 15 ,
105+ 'S' : 15 , 'R' : 16 , 'Z' : 15 , 'Y' : 16 , 'E' : 15 , 'D' : 18 , 'G' : 18 , 'F' : 15 ,
106+ 'A' : 16 , 'X' : 16 , 'C' : 18 , 'B' : 15 , 'M' : 19 , 'L' : 14 , 'O' : 19 , 'N' : 15 ,
107+ 'I' : 6 , 'H' : 15 , 't' : 7 , 'w' : 18 , 'v' : 12 , 'q' : 12 , 'p' : 13 , 's' : 12 ,
108+ 'r' : 9 , 'z' : 11 , 'y' : 12 , 'e' : 13 , 'd' : 12 , 'g' : 12 , 'f' : 8 , 'a' : 13 ,
109+ 'x' : 11 , 'c' : 12 , 'b' : 13 , 'm' : 19 , 'l' : 5 , 'o' : 13 , 'n' : 13 , 'i' : 5 ,
110+ 'h' : 13 , 'k' : 13 , 'j' : 5 , 'u' : 13 , 0 : 14 , 1 : 10 , 2 : 13 , 3 : 14 , 4 : 14 ,
111+ 5 :14 , 6 : 14 , 7 : 14 , 8 : 14 , 9 : 14 , "'" : 4 , '-' : 8 , ' ' : 14 , '.' : 6 }
112+
113+ def draw_outline_box ():
114+ display .draw_vline (0 , 0 , 240 , white )
115+ display .draw_vline (319 , 0 , 240 , white )
116+ display .draw_hline (0 , 0 , 320 , white )
117+ display .draw_hline (0 , 40 , 320 , white )
118+ display .draw_hline (0 , 239 , 320 , white )
119+
120+ def clear_fill ():
121+ display .clear ()
122+ display .fill_rectangle (0 ,0 , 320 , 240 , drk_grn )
123+
124+ def fresh_box ():
125+ display .clear_fill ()
126+ display .draw_outline_box ()
127+
128+ def print_setup (boot_stage ):
129+ clear_fill ()
130+ draw_outline_box ()
131+ display .draw_text (5 , 8 , f"{ boot_stage } " , date_font , white , drk_grn )
132+ display .draw_text (5 , 65 , 'BB Kiosk' , date_font , white , drk_grn )
133+ display .draw_text (5 , 105 , f"Version { version } " , date_font , white , drk_grn )
134+
135+ def crash_burn (err ):
136+ display .fresh_box ()
137+ print (f"=={ err } " )
138+ display .draw_text (5 , 5 , err , date_font , white , drk_grn )
139+ time .sleep (5 )
140+ import machine
141+ machine .reset ()
15142
16- elif screen == 'esp32-s3-box-lite' :
143+ def get_tb_text (err ):
144+ """
145+ Credit https://forums.openmv.io/t/how-can-i-get-the-line-number-of-error/6145
146+ """
147+ import io
148+ import sys
149+ buf = io .StringIO ()
150+ sys .print_exception (err , buf )
151+ #Remove the word Traceback/etc
152+ print (buf .getvalue ()[35 :])
153+ return buf .getvalue ()[35 :]
154+
155+ def scroll_print (text = 'NA' ,x_pos = 5 , y_pos = 5 , scr_len = 30 ,
156+ Error = False , clear = True , font = sm_font ,
157+ bg = drk_grn , fg = white , debug = False ):
158+ """ Given a headline from a text string from mlb.com/news like:
17159
18- from .espboxlite import display
160+ 'Celebrate Aaron's birthday with 13 stats that show his greatness'
161+
162+ We need to break it into grouping like this:
163+
164+ ["Celebrate Aaron's", 'birthday with 13', 'stats that show his', 'greatness']
165+
166+ ...but do so in a way that does not step outside the character/pixel limits """
167+
168+
169+ """ We will pass in a 'text container' which will be either
170+ and instance of an error or a string """
171+ if clear :
172+ display .fresh_box ()
19173
20- elif screen == 'esp32-s3-box' :
174+ """ 5 is already tight, 6 partly off the screen """
175+ max_rows = 6
176+ scr_len = scr_len
177+
178+ def proc_text (text ):
179+ """ Here's where we do the processing of the 'text' """
180+
181+ def get_raw_parts (_text ):
182+ """ Split 'text' to list[] in scr_len increments as a first pass
183+ return a list of 'raw' parts like this:
184+ ["Celebrate Aaron's", "birthday with 13 s","tats that show his greatness"] """
185+ return [ _text [i : i + scr_len ] for i in range (0 , len (_text ), scr_len )]
186+
187+ def mv_parts (text ):
188+ """ Cycle through / Get the 'raw' 'parts' of 'text', convert each to a list.
189+ Then align() each item/push characters to the next part if needed.
190+
191+ Return a list of strings that do no 'run on', but still need to be processed for length.
192+ Ex. ["Celebrate Aaron's ", 'birthday with 13 ', 'stats that show his', ' greatness'] """
193+
194+ print (f"Text: { text } " ) if debug else None
195+ raw_parts = get_raw_parts (text )
196+
197+ if debug :
198+ for _each in raw_parts :
199+ print (f"Raw Part: { _each } - Raw tsum: { get_tsum (_each )} " )
200+
201+ max_num_raw_parts = len (raw_parts )- 2
202+ start = 0
203+ while start <= max_num_raw_parts :
204+ """Convert Text parts to lists to be able to pop easily """
205+ t1 = list (raw_parts [start ])
206+ t2 = list (raw_parts [start + 1 ])
207+ """ Move upstream through raw_parts align()ing to a new list as you go """
208+ raw_parts [start ], raw_parts [start + 1 ] = align (t1 ,t2 )
209+ print (f"Parts after round { start } { raw_parts } " ) if debug else None
210+ start += 1
211+ return raw_parts
212+
213+ def align (_t1 , _t2 ):
214+ """ Given the first 2 portions of the text converted to lists,
215+ see if the end of the 1st list and the start of the 2nd list are
216+ alphanumeric, if so push text to avoid a broken word on the screen
217+
218+ Ex.
219+ ['W', 'h', 'i', 't', 'e', 'S']['o', 'x', ' ', 'a', 'c', 'q', 'u', 'i', 'r', 'e']
220+ to
221+ ['W', 'h', 'i', 't', 'e']['S','o', 'x', ' ', 'a', 'c', 'q', 'u', 'i', 'r', 'e']
222+
223+ then return a tuple of strings:
224+
225+
226+ """
227+ if run_on (_t1 , _t2 ):
228+ _t2 .insert (0 ,_t1 .pop (- 1 ))
229+ _t1 , _t2 = align (_t1 ,_t2 )
230+ return '' .join (_t1 ), '' .join (_t2 )
231+
232+
233+ def run_on (_t1 , _t2 ):
234+ """ check for align() """
235+ if _t1 [- 1 ] != ' ' and _t2 [0 ] != ' ' :
236+ return True
237+ return False
238+
239+
240+ def get_tsum (thing , def_size = 15 ):
241+ """ Given the footprint of each character, return the sum(), "tsum" of it
242+ whether it's a string or a list, to determine how to postion the text """
243+ if isinstance (thing , list ):
244+ return sum ([ apnt2 .get (x ,def_size ) for x in ' ' .join (thing )])
245+ if isinstance (thing , str ):
246+ return sum ([ apnt2 .get (x ,def_size ) for x in thing ])
247+
248+ def rm_space (_parts ):
249+ """ rm final / inital spaces of each part of given list """
250+ [ x .pop () for x in _parts if x [- 1 ] == ' ' ]
251+ [ x .pop (0 ) for x in _parts if x [0 ] == ' ' ]
252+ return _parts
253+
254+ def sw_parts (parts ):
255+ """ Swap parts like
256+ from ['One series to ', "circle on each team's ", "schedule in '23" ]
257+ to
258+ ['One series to ', "circle on each ", " team's schedule in '23"]
259+ if their pixel footprint (tsum) breaks past the screen's max """
260+
261+ def bump (each , tsum ):
262+ """ Insert strategically into a list (push to a non existing 'part'/list to create it)
263+ for the last 'each', or into an (already existing 'each'/list) inside a list """
264+ if tsum > max_x :
265+ print (f"over { max_x } " ) if debug else None
266+ if len (_pparts ) == each + 1 :
267+ _pparts .insert (each + 1 ,[_pparts [each ].pop (- 1 )])
268+ else :
269+ _pparts [each + 1 ].insert (0 ,_pparts [each ].pop (- 1 ))
270+ tsum = get_tsum (_pparts [each ])
271+ print (f"New _pparts each { _pparts [each ]} new tsum { tsum } " ) if debug else None
272+ bump (each , tsum )
273+
274+ """ Given the aligned parts(strings), convert each to list to rm space easily """
275+ _parts = [ list (x ) for x in parts ]
276+ print (f"_parts list comp { _parts } " ) if debug else None
277+
278+ """ There is no need for beg/end spaces at all right now, rm them """
279+ _parts = rm_space (_parts )
280+ print (f"_parts list rm_space { _parts } " ) if debug else None
281+
282+ """ join them all back to get words back """
283+ _parts = [ '' .join (x ) for x in _parts ]
284+ print (f"_parts Current joined { _parts } " ) if debug else None
285+
286+ """ make each part a list in a new candidate list for easy bumping of a full word/string """
287+ _pparts = [ x .split (' ' ) for x in _parts ]
288+ print (f"_pparts Current list cand to bump { _pparts } " ) if debug else None
289+ print (f"lp { len (_parts )} " ) if debug else None
290+
291+ max_x = 230
292+
293+ for each in range (0 , len (_parts )):
294+ if debug :
295+ print (f"---- Each { each } " )
296+ print (f"-- each _parts { each } : { _parts [each ]} { get_tsum (_parts [each ]) } " )
297+ print (f"-- each _pparts { each } : { _pparts [each ]} { get_tsum (_pparts [each ]) } " )
298+ bump (each , get_tsum (_pparts [each ]))
299+
300+ print (f"Final swapped but unjoined _pparts { _pparts } " ) if debug else None
301+ if debug :
302+ for each in _pparts :
303+ print (get_tsum (each ))
304+
305+ _parts = [ ' ' .join (x ) for x in _pparts ]
306+ print (f"Final joined _parts { _parts } " ) if debug else None
307+ if debug :
308+ for each in _parts :
309+ print (get_tsum (each )) if debug else None
310+
311+ return _parts
312+
313+ return sw_parts (mv_parts (text ))
21314
22- from .espbox import display
315+ """ If an error instance, pull out the text other process the beast ... """
316+
317+ if Error :
318+
319+ _text = get_tb_text (text )
320+ print (f"_text: { text } type: { type (_text )} , len: { len (_text )} " ) if debug else None
321+ procd_parts = [ _text [- 150 :- 125 ], _text [- 125 :- 100 ],
322+ _text [- 100 :- 75 ], _text [- 75 :- 50 ],
323+ _text [- 50 :- 25 ], _text [- 25 :- 1 ] ]
324+ else :
325+
326+ procd_parts = proc_text (text )
327+
328+
329+ print (f"Final procd_parts parts { procd_parts } " ) if debug else None
330+
331+ count = 0
332+ for each_text in procd_parts :
333+ """ sm font = 25, date font =30 """
334+ if count > max_rows :
335+ break
336+ else :
337+ display .draw_text (x_pos , y_pos , each_text , font = font , color = fg , background = bg )
338+ print (f"{ each_text } " ) #This will be each story or the error message
339+ count += 1
340+ y_pos += 30
341+
342+
343+
344+
345+ display .draw_outline_box = draw_outline_box
346+ display .clear_fill = clear_fill
347+ display .print_setup = print_setup
348+ display .white = white
349+ display .drk_grn = drk_grn
350+ display .black = black
351+ display .sm_font = sm_font
352+ display .score_font = score_font
353+ display .date_font = date_font
354+ display .get_tb_text = get_tb_text
355+ display .scroll_print = scroll_print
356+ display .check_upgrade = check_upgrade
357+ display .fresh_box = fresh_box
358+ display .crash_burn = crash_burn
0 commit comments