diff --git a/preload/apps/adventure_timer/__init__.py b/preload/apps/adventure_timer/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b1bb6a8eac195278fa000cb58585399c0e1c5d85 --- /dev/null +++ b/preload/apps/adventure_timer/__init__.py @@ -0,0 +1,125 @@ +import ujson +import os +import display +import utime +import buttons + +CONFIG_NAME = "at-timestamp.json" + + +def init(): + if CONFIG_NAME not in os.listdir("."): + at_config = {"time_start": "unset"} + f = open(CONFIG_NAME, 'w') + f.write(ujson.dumps(at_config)) + f.close() + + if is_timestamp_set(): + global menu_state + menu_state = 1 + timestamp_read() + + +def is_timestamp_set(): + f = open(CONFIG_NAME, 'r') + c = ujson.loads(f.read()) + f.close() + if c["time_start"] == "unset": + return False + else: + return True + + +def triangle(disp, x, y, left): + yf = 1 if left else -1 + scale = 6 + disp.line(x - scale * yf, int(y + scale / 2), x, y) + disp.line(x, y, x, y + scale) + disp.line(x, y + scale, x - scale * yf, y + int(scale / 2)) + + +def timestamp_reset(): + f = open(CONFIG_NAME, 'r') + c = ujson.loads(f.read()) + c["time_start"] = "unset" + f.close() + f = open(CONFIG_NAME, 'w') + f.write(ujson.dumps(c)) + f.close() + + +def timestamp_read(): + global time_start + f = open(CONFIG_NAME, 'r') + c = ujson.loads(f.read()) + time_start = c["time_start"] + f.close() + + +def timestamp_write(): + f = open(CONFIG_NAME, 'r') + c = ujson.loads(f.read()) + c["time_start"] = utime.time() + f.close() + f = open(CONFIG_NAME, 'w') + f.write(ujson.dumps(c)) + f.close() + + +def headline(): + disp.print("Adventure \n Time", posy=0, fg=[0, 255, 255]) + + +def menu(): + if menu_state == 0: + disp.print("start?", posy=40, fg=[255, 255, 255]) + triangle(disp, 10, 66, True) + disp.print("start.", posx=15, posy=60, fg=[0, 255, 0]) + elif menu_state == 1: + seconds = utime.time() - time_start + m, s = divmod(seconds, 60) + h, m = divmod(m, 60) + disp.print("%02d:%02d:%02d" % (h, m, s), posy=40, fg=[255, 255, 255]) + triangle(disp, 10, 66, True) + disp.print("reset", posx=15, posy=60, fg=[255, 0, 0]) + elif menu_state == 2: + disp.print("reset?", posy=40, fg=[255, 255, 255]) + triangle(disp, 10, 66, True) + triangle(disp, 150, 66, False) + disp.print("no", posx=15, posy=60, fg=[255, 0, 0]) + disp.print("yes", posx=105, posy=60, fg=[0, 255, 0]) + + +menu_state = 0 +time_start = 0 +disp = display.open() +button_pressed = False +init() + +while True: + disp.clear() + headline() + v = buttons.read(buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT) + if v == 0: + button_pressed = False + if menu_state == 0: + if not button_pressed and v & buttons.BOTTOM_LEFT != 0: + button_pressed = True + timestamp_write() + timestamp_read() + menu_state = 1 + elif menu_state == 1: + if not button_pressed and v & buttons.BOTTOM_LEFT != 0: + button_pressed = True + menu_state = 2 + elif menu_state == 2: + if not button_pressed and v & buttons.BOTTOM_LEFT != 0: + button_pressed = True + menu_state = 1 + if not button_pressed and v & buttons.BOTTOM_RIGHT != 0: + button_pressed = True + timestamp_reset() + menu_state = 0 + menu() + disp.update() + utime.sleep(0.1) diff --git a/preload/apps/adventure_timer/metadata.json b/preload/apps/adventure_timer/metadata.json new file mode 100644 index 0000000000000000000000000000000000000000..43aef764485a613a284fd081df21cdbe24c1402a --- /dev/null +++ b/preload/apps/adventure_timer/metadata.json @@ -0,0 +1 @@ +{"name":"adventure timer","description":"Simple stopwatch to time your current adventure.","category":"utility","author":"torben","revision":7} \ No newline at end of file diff --git a/preload/apps/card10_nickname/__init__.py b/preload/apps/card10_nickname/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..301b0906d8d92770f949dbbabb989b6156e7b2b0 --- /dev/null +++ b/preload/apps/card10_nickname/__init__.py @@ -0,0 +1,143 @@ +""" +Improvement ideas +- animations + - dvd + - rainbow + - led control + - fade effekt +- led nick writing +""" + +import utime +import display +import leds +import ledfx +import buttons +import light_sensor +import ujson +import os + +FILENAME = 'nickname.txt' +FILENAME_ADV = 'nickname.json' +ANIM_TYPES = ['none', 'led', 'fade'] + + +def render_error(err1, err2): + with display.open() as disp: + disp.clear() + disp.print(err1, posx=80 - round(len(err1) / 2 * 14), posy=18) + disp.print(err2, posx=80 - round(len(err2) / 2 * 14), posy=42) + disp.update() + disp.close() + + +def render_nickname(title, sub, fg, bg, fg_sub, bg_sub, main_bg): + anim = 'led' + posy = 30 + if sub != '': + posy = 18 + r = 255 + g = 0 + b = 0 + while True: + dark = 0 + if light_sensor.get_reading() < 30: + dark = 1 + r_fg_color = fg[dark] + r_bg_color = bg[dark] + r_fg_sub_color = fg_sub[dark] + r_bg_sub_color = bg_sub[dark] + r_bg = main_bg[dark] + if anim == 'fade': + if r > 0 and b == 0: + r = r - 1 + g = g + 1 + if g > 0 and r == 0: + g = g - 1 + b = b + 1 + if b > 0 and g == 0: + r = r + 1 + b = b - 1 + r_bg = [r, g, b] + if anim == 'led': + for i in range(0, 11): + leds.prep(i, r_bg) + leds.update() + leds.dim_top(3) + leds.set_rocket(0, 15) + leds.set_rocket(1, 15) + leds.set_rocket(2, 15) + if anim == 'none': + leds.clear() + leds.set_rocket(0, 0) + leds.set_rocket(1, 0) + leds.set_rocket(2, 0) + with display.open() as disp: + disp.rect(0, 0, 160, 80, col=r_bg, filled=True) + disp.print(title, fg=r_fg_color, bg=r_bg_color, posx=80 - round(len(title) / 2 * 14), posy=posy) + if sub != '': + disp.print(sub, fg=r_fg_sub_color, bg=r_bg_sub_color, posx=80 - round(len(sub) / 2 * 14), posy=42) + disp.update() + disp.close() + pressed = buttons.read( + buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT + ) + if pressed & buttons.BOTTOM_LEFT != 0: + anim = ANIM_TYPES[1] + if pressed & buttons.BOTTOM_RIGHT != 0: + anim = ANIM_TYPES[0] + utime.sleep(0.3) + + +def get_key(json, key, default): + try: + return json[key] + except KeyError: + return default + + +leds.clear() +with display.open() as disp: + disp.clear().update() + disp.close() + +if FILENAME_ADV in os.listdir("."): + f = open(FILENAME_ADV, 'r') + try: + c = ujson.loads(f.read()) + f.close() + # parse config + nick = get_key(c, 'nickname', 'no nick') + sub = get_key(c, 'subtitle', '') + # daytime values + background = get_key(c, 'background', [0, 0, 0]) + fg_color = get_key(c, 'fg_color', [255, 255, 255]) + bg_color = get_key(c, 'bg_color', background) + fg_sub_color = get_key(c, 'fg_sub_color', [255, 255, 255]) + bg_sub_color = get_key(c, 'bg_sub_color', background) + # nighttime values + background_night = get_key(c, 'background_night', [0, 0, 0]) + fg_color_night = get_key(c, 'fg_color_night', [255, 255, 255]) + bg_color_night = get_key(c, 'bg_color_night', background_night) + fg_sub_color_night = get_key(c, 'fg_sub_color_night', [255, 255, 255]) + bg_sub_color_night = get_key(c, 'bg_sub_color_night', background_night) + # render nickname + render_nickname(nick, sub, (fg_color, fg_color_night), (bg_color, bg_color_night), + (fg_sub_color, fg_sub_color_night), (bg_sub_color, bg_sub_color_night), + (background, background_night)) + except ValueError: + render_error('invalid', 'json') +else: + if FILENAME not in os.listdir("."): + render_error('file not', 'found') + else: + f = open(FILENAME, 'r') + nick = f.read() + f.close() + if len(nick) > 11: + render_error('name too', 'long') + if len(nick) < 1: + render_error('nick file', 'empty') + else: + render_nickname(nick, '', ([255, 255, 255], [255, 255, 255]), ([0, 0, 0], [0, 0, 0]), + ([255, 255, 255], [255, 255, 255]), ([0, 0, 0], [0, 0, 0]), ([0, 0, 0], [0, 0, 0])) diff --git a/preload/apps/card10_nickname/metadata.json b/preload/apps/card10_nickname/metadata.json new file mode 100644 index 0000000000000000000000000000000000000000..db70873d61d8a58c53d656f8e9c593c818fe811e --- /dev/null +++ b/preload/apps/card10_nickname/metadata.json @@ -0,0 +1 @@ +{"name":"Card10 Nickname","description":"Nickname app for the card10 badge\r\n\r\nEverything you need can be found here: https:\/\/github.com\/vabene1111\/card10-nickname","category":"graphics","author":"vabene1111","revision":3} \ No newline at end of file diff --git a/preload/apps/text_reader/__init__.py b/preload/apps/text_reader/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..745ecfd489d711b5ca185f83e08c12b7dd0d11ea --- /dev/null +++ b/preload/apps/text_reader/__init__.py @@ -0,0 +1,285 @@ +""" +Text Reader Script +================= +This script will list and display text files +""" +import buttons +import color +import display +import os +import utime + +STATE_LIST = "List" +STATE_SHOW = "Show" +SPECIAL_NO_FILES = "# no txt files" +SPECIAL_EXIT = "[ exit ]" +SPECIAL_EMPTY = "# empty file" +BUTTON_TIMER_POPPED = -1 + +def list_files(): + """Create a list of available text files.""" + files = sorted(os.listdir("/")) + + # Filter for text files + files = [txt for txt in files if txt.endswith(".txt")] + + return files + + +def triangle(disp, x, y, left): + """Draw a triangle to show there's more text in this line""" + yf = 1 if left else -1 + scale = 6 + disp.line(x - scale * yf, int(y + scale / 2), x, y, col=[255,0,0]) + disp.line(x, y, x, y + scale, col=[255,0,0]) + disp.line(x, y + scale, x - scale * yf, y + int(scale / 2), col=[255,0,0]) + + +def button_events(timeout=0): + """Iterate over button presses (event-loop).""" + yield 0 + button_pressed = False + count = 0 + while True: + v = buttons.read(buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT) + if timeout > 0 and count > 0 and count % timeout == 0: + yield BUTTON_TIMER_POPPED + + if timeout > 0: + count += 1 + + if v == 0: + button_pressed = False + + if not button_pressed and v & buttons.BOTTOM_LEFT != 0: + button_pressed = True + yield buttons.BOTTOM_LEFT + + if not button_pressed and v & buttons.BOTTOM_RIGHT != 0: + button_pressed = True + yield buttons.BOTTOM_RIGHT + + if not button_pressed and v & buttons.TOP_RIGHT != 0: + button_pressed = True + yield buttons.TOP_RIGHT + + utime.sleep_ms(10) + + +COLOR1, COLOR2 = (color.CHAOSBLUE_DARK, color.CHAOSBLUE) + +def file_len(filename): + i = -1 + with open(filename) as fh: + for i, l in enumerate(fh): + pass + return i + 1 + + +def draw_filecontent(disp, filename, pos, linecount, lineoffset = 0): + disp.clear() + with open(filename) as fh: + + # stop if file is empty + if linecount <= 0: + disp.print( + SPECIAL_EMPTY, + posy=20, + bg=color.BLACK + ) + return + + # calc start position + start = 0 + if pos > 0: + start = pos-1 + if start + 4 > linecount: + start = linecount - 4 + if start < 0: + start = 0 + + # loop throuhg all lines + for i, line in enumerate(fh): + if i >= start + 4 or i >= linecount: + break + if i >= start: + disp.rect( + 0, (i - start) * 20, 159, (i - start) * 20 + 20, + col=COLOR1 if i == pos else COLOR2 + ) + + off = 0 + linelength = len(line) + if i == pos and linelength > 11 and lineoffset > 0: + off = lineoffset if lineoffset + 11 < linelength else linelength - 11 + if lineoffset > linelength: + off = 0 + + disp.print( + line[off:(off+11)], + posy=(i - start) * 20, + bg=COLOR1 if i == pos else COLOR2 + ) + if linelength > 11 and off < linelength - 11: + triangle(disp, 153, (i - start) * 20 + 6, False) + if off > 0: + triangle(disp, 6, (i - start) * 20 + 6, True) + + disp.update() + + +def draw_filelist(disp, filelist, pos, filecount, lineoffset): + disp.clear() + + start = 0 + if pos > 0: + start = pos-1 + if start + 4 > filecount: + start = filecount - 4 + if start < 0: + start = 0 + + for i, line in enumerate(filelist): + if i >= start + 4 or i >= filecount: + break + if i >= start: + disp.rect( + 0, (i - start) * 20, 159, (i - start) * 20 + 20, + col=COLOR1 if i == pos else COLOR2 + ) + + off = 0 + linelength = len(line) + if i == pos and linelength > 10 and lineoffset > 0: + off = lineoffset if lineoffset + 10 < linelength else linelength - 10 + if lineoffset > linelength: + off = 0 + + disp.print( + " " + line[off:(off+10)], + posy=(i - start) * 20, + bg=COLOR1 if i == pos else COLOR2 + ) + if i == pos: + disp.print(">", posy=(i - start) * 20, fg=color.COMMYELLOW, bg=COLOR1) + + if linelength > 10 and off < linelength - 10: + triangle(disp, 153, (i - start) * 20 + 6, False) + if off > 0: + triangle(disp, 24, (i - start) * 20 + 6, True) + + disp.update() + + +def main(): + disp = display.open() + current_state = STATE_LIST + + # list files variables + + filelist = list_files() + if len(filelist) == 0: + filelist.append(SPECIAL_NO_FILES) + filelist.append(SPECIAL_EXIT) + numfiles = len(filelist) + current_file = 0 + + # show files variables + + filename = "" + linecount = 0 + linepos = 0 + lineoffset = 0 + lineoffdir = 0 + timerscrollspeed = 1 + timerstartscroll = 5 + timercountpopped = 0 + + for ev in button_events(10): + + # list files + + if current_state == STATE_LIST: + if ev == buttons.BOTTOM_RIGHT: + # Scroll down + current_file = (current_file + 1) % numfiles + lineoffset = 0 + timercountpopped = 0 + + elif ev == buttons.BOTTOM_LEFT: + # Scroll up + current_file = (current_file + numfiles - 1) % numfiles + lineoffset = 0 + timercountpopped = 0 + + elif ev == BUTTON_TIMER_POPPED: + timercountpopped += 1 + if timercountpopped >= timerstartscroll and (timercountpopped - timerstartscroll) % timerscrollspeed == 0: + lineoffset += 1 + + elif ev == buttons.TOP_RIGHT: + filename = filelist [ current_file % numfiles ] + + # exit or ignore + if filename == SPECIAL_EXIT: + os.exit() + elif filename == SPECIAL_NO_FILES: + continue + + # show file, switch state and draw + current_state = STATE_SHOW + disp.clear().update() + + # reset variables + linepos = 0 + lineoffset = 0 + timercountpopped = 0 + linecount = file_len(filename) + + # draw + draw_filecontent(disp, filename, linepos, linecount, lineoffset) + continue + + draw_filelist(disp, filelist, current_file, numfiles, lineoffset) + + # show files + + elif current_state == STATE_SHOW: + if ev == buttons.BOTTOM_RIGHT: + if linepos < (linecount - 1): + # Scroll down + linepos += 1 + else: + # goto first line + linepos = 0 + lineoffset = 0 + timercountpopped = 0 + + elif ev == buttons.BOTTOM_LEFT: + if linepos > 0: + # Scroll up + linepos -= 1 + else: + # got to last line + linepos = linecount - 1 + lineoffset = 0 + timercountpopped = 0 + + elif ev == BUTTON_TIMER_POPPED: + timercountpopped += 1 + if timercountpopped >= timerstartscroll and (timercountpopped - timerstartscroll) % timerscrollspeed == 0: + lineoffset += 1 + + elif ev == buttons.TOP_RIGHT: + # go back to file menu + current_state = STATE_LIST + lineoffset = 0 + timercountpopped = 0 + draw_filelist(disp, filelist, current_file, numfiles, 0) + continue + + draw_filecontent(disp, filename, linepos, linecount, lineoffset) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/preload/apps/text_reader/metadata.json b/preload/apps/text_reader/metadata.json new file mode 100644 index 0000000000000000000000000000000000000000..a4132eab0ba9ae0aa70114d84bd69ca93a040ddb --- /dev/null +++ b/preload/apps/text_reader/metadata.json @@ -0,0 +1 @@ +{"name":"Text Reader","description":"Provides a list of *.txt files and displays them (and let you scroll through)","category":"utility","author":"griffon","revision":2} \ No newline at end of file