Toggle Navigation
Hatchery
Eggs
NLUUG Schedule
nluug_schedule.py
Users
Badges
Login
Register
MCH2022 badge?
go to mch2022.badge.team
nluug_schedule.py
raw
Content
### Event program Egg ### Author: Renze Nicolai ### License: GPLv3 import ugfx, badge, gc, network, wifi, ujson, utime, appglue, version from machine import Timer import urequests as requests from nluug_schedule import event_alarm from nluug_schedule import fahrplan # TODO: integrate this more... # GLOBALS ledTimer = Timer(-1) position = 0 schedule = {} schedule_day = {} schedule_event = {} titles = [] title_guid = {} # DRAW def draw_msg(title, desc): ugfx.clear(ugfx.WHITE) ugfx.string(0, 0, title, "PermanentMarker22", ugfx.BLACK) ugfx.string(0, 25, desc, "Roboto_Regular12", ugfx.BLACK) ugfx.set_lut(ugfx.LUT_FASTER) ugfx.flush() def draw_alarm(desc,room): ugfx.clear(ugfx.WHITE) ugfx.string(0, 0, "Event starts soon!", "PermanentMarker22", ugfx.BLACK) ugfx.string(0, 25, desc, "Roboto_Regular12", ugfx.BLACK) ugfx.string(0, 25+13, room, "Roboto_Regular12", ugfx.BLACK) ugfx.string(0, ugfx.height()-13, "[ B: Close ]", "Roboto_Regular12", ugfx.BLACK) ugfx.set_lut(ugfx.LUT_FASTER) ugfx.flush() # BACK TO HOME def start_home(pushed): global ledTimer if(pushed): ledTimer.deinit() appglue.home() # ALARM def pop_alarm(): event_alarm.alarms_read() current_datetime = utime.time() amount_of_alarms = len(event_alarm.alarms) for i in range(0, amount_of_alarms): alarm = event_alarm.alarms[i] c = int(alarm['timestamp']) - 10*60 if (c < current_datetime): print("Deleted alarm "+str(i)) event_alarm.alarms.pop(i) break event_alarm.alarms_write() def alarm_dismiss(pressed): if (pressed): draw_msg("Please wait...", "") pop_alarm() appglue.start_app("nluug_schedule") def alarm_check_and_notify(): event_alarm.alarms_read() current_datetime = utime.time() amount_of_alarms = len(event_alarm.alarms) for i in range(0, amount_of_alarms): alarm = event_alarm.alarms[i] c = int(alarm['timestamp']) - 10*60 #10 minutes before start if (c < current_datetime): ledTimer.deinit() #Stop the background timer ledTimer.init(period=50, mode=Timer.PERIODIC, callback=alarmTimer_callback) global alarm_check_title print("Alarm! ("+alarm['title']+", "+str(c)+")") draw_alarm("Title: "+alarm['title'],"Location: "+alarm['room']) ugfx.input_attach(ugfx.JOY_UP, nothing) ugfx.input_attach(ugfx.JOY_DOWN, nothing) ugfx.input_attach(ugfx.JOY_LEFT, nothing) ugfx.input_attach(ugfx.JOY_RIGHT, nothing) ugfx.input_attach(ugfx.BTN_SELECT, nothing) ugfx.input_attach(ugfx.BTN_A, nothing) ugfx.input_attach(ugfx.BTN_B, alarm_dismiss ) badge.vibrator_activate(0xFF) diff = c - current_datetime print("[EVSCH] Alarm time reached for "+alarm['title']+" ("+str(diff)+")") return True #Program should stop else: countdown = abs(c - current_datetime) print("[EVSCH] Alarm over "+str(countdown)+"s: "+alarm['title']) return False #Normal operation may continue def alarmTimer_callback(tmr): global position position = position + 1 if (position>255): badge.vibrator_activate(0xF0) position = 0 ledVal = 0 if (position==0) or (position==20) or (position==40) or (position==60) or (position==80): ledVal = 128 badge.leds_send_data(bytes([0,ledVal,0,ledVal,0,ledVal,0,ledVal,0,ledVal,0,ledVal,0,ledVal,0,ledVal,0,ledVal,0,ledVal,0,ledVal,0,ledVal]),24) # EVENT TIMER def ledTimer_callback(tmr): global position position = position + 2 ledVal = 0 if position>10: ledVal = 1 position = 0 badge.leds_send_data(bytes([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,ledVal,0,0,0]),24) gc.collect() print("Memory available: "+str(gc.mem_free())) alarm_check_and_notify() # GENERIC INPUT EVENT def nothing(pressed): ugfx.flush() pass # SCREEN: EVENT def screen_event_submit(pressed): if (pressed): print("> event submit (create alarm)") global schedule_event if (event_alarm.alarm_exists(schedule_event['guid'])): draw_msg("Already added", "Event already in alarm list") else: event_alarm.alarms_add(schedule_event) event_alarm.alarms_write() draw_msg("You will be notified!", "Event added to alarms") utime.sleep(1) screen_event() def screen_event_back(pressed): if (pressed): screen_eventselect() def screen_event_flip_left(pressed): if (pressed): screen_event() def screen_event_flip_right(pressed): if (pressed): screen_event_detail() def split_and_draw(x,y,text,max_lines,skip_lines): words = text.split() line = "" lc = 0 tl = 0 for i in range(0,len(words)): if len(words[i])>=50: print("What the?!?! This word is "+str(len(words[i]))+" characters long: "+words[i]) tl += 2 if skip_lines>0: skip_lines -= 1 elif lc<max_lines: ugfx.string(x, y, line, "Roboto_Regular12", ugfx.BLACK) y += 13 lc += 1 if skip_lines>0: skip_lines -= 1 elif lc<max_lines: ugfx.string(x, y, words[i], "Roboto_Regular12", ugfx.BLACK) y += 13 lc += 1 line = "" elif len(line+' '+words[i])<50: line += ' '+words[i] else: tl += 1 if skip_lines>0: skip_lines -= 1 elif lc<max_lines: ugfx.string(x, y, line, "Roboto_Regular12", ugfx.BLACK) y += 13 lc += 1 line = words[i] tl += 1 if skip_lines>0: skip_lines -= 1 elif lc<max_lines: ugfx.string(x, y, line, "Roboto_Regular12", ugfx.BLACK) return tl def screen_event_scroll(): ugfx.area(0,34,ugfx.width(),ugfx.height()-15-34,ugfx.WHITE) global scrollPos global schedule_event split_and_draw(0,35,schedule_event['abstract'],6,scrollPos) ugfx.flush() def screen_event_scroll_up(pressed): if pressed: global scrollPos if scrollPos>0: scrollPos -= 1 screen_event_scroll() def screen_event_scroll_down(pressed): if pressed: global scrollPos global scrollMax if scrollPos<scrollMax-6: scrollPos += 1 screen_event_scroll() def screen_event(): print("> Screen event") global schedule_event ugfx.clear(ugfx.WHITE) ugfx.string(0, 0, schedule_event['title'], "Roboto_Regular18", ugfx.BLACK) ugfx.string(0, 20, ', '.join(schedule_event['persons']), "Roboto_Regular12", ugfx.BLACK) ugfx.line(0,33,295,33, ugfx.BLACK) global scrollPos scrollPos = 0 global scrollMax scrollMax = split_and_draw(0,35,schedule_event['abstract'],6,0) ugfx.line(0,ugfx.height()-14,295,ugfx.height()-14, ugfx.BLACK) ugfx.string(0, ugfx.height()-12, "A: Add alarm | B: Back | START: Home | >: Details", "Roboto_Regular12", ugfx.BLACK) ugfx.input_attach(ugfx.JOY_UP, screen_event_scroll_up) ugfx.input_attach(ugfx.JOY_DOWN, screen_event_scroll_down) ugfx.input_attach(ugfx.JOY_LEFT, screen_event_flip_left) ugfx.input_attach(ugfx.JOY_RIGHT, screen_event_flip_right) ugfx.input_attach(ugfx.BTN_SELECT, nothing) ugfx.input_attach(ugfx.BTN_A, screen_event_submit) ugfx.input_attach(ugfx.BTN_B, screen_event_back ) ugfx.flush() def screen_event_detail(): print("> Screen event detail") global schedule_event ugfx.clear(ugfx.WHITE) ugfx.string(0, 0, schedule_event['title'], "Roboto_Regular18", ugfx.BLACK) ugfx.string(0, 20, schedule_event['subtitle'], "Roboto_Regular12", ugfx.BLACK) ugfx.line(0,33,295,33, ugfx.BLACK) ugfx.string(0, 35, "Type: "+schedule_event['type'], "Roboto_Regular12", ugfx.BLACK) if (schedule_event['do_not_record']): ugfx.string(0, 35+13, "Recording is not allowed!", "Roboto_Regular12", ugfx.BLACK) else: ugfx.string(0, 35+13, "Recording is allowed ("+schedule_event['recording_license']+").", "Roboto_Regular12", ugfx.BLACK) ugfx.string(0, 35+13*2, "Language: "+schedule_event['language'], "Roboto_Regular12", ugfx.BLACK) ugfx.string(0, 35+13*3, "Room: "+schedule_event['room'], "Roboto_Regular12", ugfx.BLACK) #Timezone correction # XXX fixme localtimestamp = schedule_event['timestamp'] [year, month, day, hour, minute, second, weekday, yearday] = utime.localtime(localtimestamp) when = "%d-%d-%d %d:%d"% (day, month, year, hour, minute) ugfx.string(0, 35+13*4, "When: "+when, "Roboto_Regular12", ugfx.BLACK) ugfx.string(0, 35+13*5, "Duration: "+schedule_event['duration'], "Roboto_Regular12", ugfx.BLACK) ugfx.line(0,ugfx.height()-14,295,ugfx.height()-14, ugfx.BLACK) ugfx.string(0, ugfx.height()-12, "A: Add alarm | B: Back | START: Home | <: Abstract", "Roboto_Regular12", ugfx.BLACK) ugfx.input_attach(ugfx.JOY_UP, nothing) ugfx.input_attach(ugfx.JOY_DOWN, nothing) ugfx.input_attach(ugfx.JOY_LEFT, screen_event_flip_left) ugfx.input_attach(ugfx.JOY_RIGHT, screen_event_flip_right) ugfx.input_attach(ugfx.BTN_SELECT, nothing) ugfx.input_attach(ugfx.BTN_A, screen_event_submit) ugfx.input_attach(ugfx.BTN_B, screen_event_back ) ugfx.flush() def load_event(guid): draw_msg("Loading...", "Downloading JSON...") gc.collect() try: data = requests.get("https://nluug.nl/events/nj17/schedule/event/"+guid+".json") except: draw_msg("Error", "Could not download JSON!") utime.sleep(5) screen_eventselect() return try: global schedule_event schedule_event = data.json() except: data.close() draw_msg("Error", "Could not decode JSON!") utime.sleep(5) screen_eventselect() return data.close() draw_msg("Loading...", "Rendering list...") screen_event() # SCREEN: EVENTSELECT (DAY VIEW) def screen_eventselect_submit(pressed): if (pressed): global options option_id = options.selected_index() options.destroy() global titles global title_guid event = title_guid[titles[option_id]] print("> load event: "+titles[option_id]+" ("+event+")") load_event(event) def screen_eventselect_back(pressed): if (pressed): options.destroy() screen_dayselect() def screen_eventselect(): print("> Screen eventselect") global options global schedule global titles ugfx.clear(ugfx.WHITE) title = "Select an event" ugfx.string(0, 0, title, "Roboto_Regular12", ugfx.BLACK) options = ugfx.List(0,15,ugfx.width(),ugfx.height()) for evtitle in titles: print("Adding event "+evtitle) if (len(evtitle)>50): evtitle = evtitle[0:47]+"..." options.add_item("%s" % evtitle) ugfx.input_attach(ugfx.JOY_UP, nothing) ugfx.input_attach(ugfx.JOY_DOWN, nothing) ugfx.input_attach(ugfx.JOY_LEFT, nothing) ugfx.input_attach(ugfx.JOY_RIGHT, nothing) ugfx.input_attach(ugfx.BTN_SELECT, nothing) ugfx.input_attach(ugfx.BTN_A, screen_eventselect_submit) ugfx.input_attach(ugfx.BTN_B, screen_eventselect_back ) ugfx.flush() def load_day(day): draw_msg("Loading...", "Downloading JSON...") gc.collect() try: data = requests.get("https://nluug.nl/events/nj17/schedule/"+str(day)+".json") except: draw_msg("Error", "Could not download JSON!") utime.sleep(5) screen_dayselect() return try: global schedule_day global titles global title_guid schedule_day = data.json() titles = [e['title'] for r in schedule_day['rooms'].keys() for e in schedule_day['rooms'][r]] # XXX need to sort on time but oh well titles.sort() title_guid=dict([(e['title'], e['guid']) for r in schedule_day['rooms'].keys() for e in schedule_day['rooms'][r]]) except: data.close() draw_msg("Error", "Could not decode JSON!") utime.sleep(5) screen_dayselect() return data.close() screen_eventselect() # SCREEN: DAY SELECT def screen_dayselect_submit(pressed): if (pressed): global options day = options.selected_index() options.destroy() print("> load day: "+str(day)) load_day(day) def fahrplan_callback(action): if (action==0): screen_dayselect() elif (action==1): start_home(True) else: print("Fahrplan error unknown action: "+str(action)) def load_fahrplan(day): draw_msg("Loading...", "Downloading JSON...") gc.collect() try: data = requests.get("https://nluug.nl/events/nj17/schedule/"+str(day)+".json") except: draw_msg("Error", "Could not download JSON!") utime.sleep(5) screen_dayselect() return try: global schedule_day schedule_day = data.json() except: data.close() draw_msg("Error", "Could not decode JSON!") utime.sleep(5) screen_dayselect() return data.close() fahrplan.schedule = schedule_day fahrplan.callback = fahrplan_callback fahrplan.run() def screen_dayselect_fahrplan(pressed): if (pressed): global options day = options.selected_index() options.destroy() print("> load fahrplan: "+str(day)) load_fahrplan(day) def screen_dayselect_back(pressed): if (pressed): options.destroy() screen_home() def screen_dayselect(): print("> Screen dayselect") global options global schedule ugfx.clear(ugfx.WHITE) title = "Select a day [ "+schedule["version"]+" ]" ugfx.string(0, 0, title, "Roboto_Regular12", ugfx.BLACK) ugfx.string(0, ugfx.height()-13, "A: List | SELECT: Overview | B: Back | START: Home", "Roboto_Regular12", ugfx.BLACK) options = ugfx.List(0,15,ugfx.width(),ugfx.height()-29) for day in range(0, len(schedule['days'])): #print("Adding day "+str(day)) options.add_item("Day %d of %d: %s"% (day+1, len(schedule['days']), schedule["days"][str(day)])) ugfx.input_attach(ugfx.JOY_UP, nothing) ugfx.input_attach(ugfx.JOY_DOWN, nothing) ugfx.input_attach(ugfx.JOY_LEFT, nothing) ugfx.input_attach(ugfx.JOY_RIGHT, nothing) ugfx.input_attach(ugfx.BTN_SELECT, screen_dayselect_fahrplan) ugfx.input_attach(ugfx.BTN_A, screen_dayselect_submit) ugfx.input_attach(ugfx.BTN_B, screen_dayselect_back ) ugfx.flush() def load_daylist(): draw_msg("Loading...", "Downloading JSON...") gc.collect() try: data = requests.get("https://nluug.nl/events/nj17/schedule.json") except: draw_msg("Error", "Could not download JSON!") utime.sleep(5) start_home(True) try: global schedule schedule = data.json() except: data.close() draw_msg("Error", "Could not decode JSON!") utime.sleep(5) start_home(True) data.close() draw_msg("Loading...", "Rendering list...") screen_dayselect() # SCREEN: ALARM def screen_alarm_submit(pressed): if (pressed): global options id = options.selected_index() options.destroy() print("> delete alarm: "+str(id)) event_alarm.alarms_remove(id) event_alarm.alarms_write() draw_msg("Alarm removed", "You will no longer be notified") utime.sleep(1) screen_alarms() def screen_alarms(): print("> Screen alarms") global options global schedule ugfx.clear(ugfx.WHITE) title = "Alarms" ugfx.string(0, 0, title, "Roboto_Regular12", ugfx.BLACK) ugfx.string(0, ugfx.height()-13, "A: Delete | B: Back | START: Home", "Roboto_Regular12", ugfx.BLACK) options = ugfx.List(0,15,ugfx.width(),ugfx.height()-29) for alarm in event_alarm.alarms: options.add_item(alarm['title']) ugfx.input_attach(ugfx.JOY_UP, nothing) ugfx.input_attach(ugfx.JOY_DOWN, nothing) ugfx.input_attach(ugfx.JOY_LEFT, nothing) ugfx.input_attach(ugfx.JOY_RIGHT, nothing) ugfx.input_attach(ugfx.BTN_SELECT, nothing) if len(event_alarm.alarms)<1: ugfx.input_attach(ugfx.BTN_A, nothing) else: ugfx.input_attach(ugfx.BTN_A, screen_alarm_submit) ugfx.input_attach(ugfx.BTN_B, screen_dayselect_back ) ugfx.flush() # SCREEN: HOME def screen_home_submit(pressed): if pressed: global options option = options.selected_index() options.destroy() if (option==0): load_daylist() if (option==1): screen_alarms() if (option==2): draw_msg("About","") utime.sleep(2) draw_msg("About","Thank you for using our app!") utime.sleep(2) screen_home() def screen_about_back(pressed): if pressed: screen_home() def try_destroy_options(): try: global options options options.destroy() except: pass def screen_about(pressed): if pressed: try_destroy_options() print("> Screen about") global schedule ugfx.clear(ugfx.WHITE) ugfx.string(0, 0, "NLUUG event schedule", "Roboto_Regular12", ugfx.BLACK) ugfx.string(0, 13, "This app has been brought to you by", "Roboto_Regular12", ugfx.BLACK) ugfx.string(0, 13*2, "SHA version by Renze Nicolai and f0x.", "Roboto_Regular12", ugfx.BLACK) ugfx.string(0, 13*3, "NLUUG version by rvs", "Roboto_Regular12", ugfx.BLACK) ugfx.string(0, 13*5, "(c) 2017 - GPLv3", "Roboto_Regular12", ugfx.BLACK) ugfx.string(0, ugfx.height()-13, "B: Back | START: Home", "Roboto_Regular12", ugfx.BLACK) ugfx.flush() ugfx.input_attach(ugfx.JOY_UP, nothing) ugfx.input_attach(ugfx.JOY_DOWN, nothing) ugfx.input_attach(ugfx.JOY_LEFT, nothing) ugfx.input_attach(ugfx.JOY_RIGHT, nothing) ugfx.input_attach(ugfx.BTN_SELECT, nothing) ugfx.input_attach(ugfx.BTN_A, nothing) ugfx.input_attach(ugfx.BTN_B, screen_about_back) def screen_home(): print("> Screen home") global options global schedule ugfx.clear(ugfx.WHITE) title = "NLUUG event schedule [ 4.0 ]" ugfx.string(0, 0, title, "Roboto_Regular12", ugfx.BLACK) ugfx.string(0, ugfx.height()-13, "A: Select | START: Home | SELECT: About", "Roboto_Regular12", ugfx.BLACK) options = ugfx.List(0,15,ugfx.width(),ugfx.height()-29) options.add_item("Browse schedule") options.add_item("Manage scheduled alarms") #options.add_item("About") #About the app ugfx.input_attach(ugfx.JOY_UP, nothing) ugfx.input_attach(ugfx.JOY_DOWN, nothing) ugfx.input_attach(ugfx.JOY_LEFT, nothing) ugfx.input_attach(ugfx.JOY_RIGHT, nothing) ugfx.input_attach(ugfx.BTN_SELECT, screen_about) ugfx.input_attach(ugfx.BTN_A, screen_home_submit) ugfx.input_attach(ugfx.BTN_B, nothing ) ugfx.flush() # MAIN PROGRAM def program_main(): ugfx.init() ugfx.input_init() draw_msg("Welcome!","Starting app...") if version.build <= 10: draw_msg("Error", "Needs Verdwenen Verteller or better!") utime.sleep(5) start_home(True) if alarm_check_and_notify(): return #Stop running normal app if alarm has triggered ugfx.input_attach(ugfx.BTN_START, start_home) global ledTimer ledTimer.init(period=1000, mode=Timer.PERIODIC, callback=ledTimer_callback) badge.leds_enable() draw_msg("Loading...", "WiFi: starting radio...") wifi.init() ssid = badge.nvs_get_str('badge', 'wifi.ssid', 'SHA2017-insecure') draw_msg("Loading...", "WiFi: connecting to '"+ssid+"'...") timeout = 100 while not wifi.sta_if.isconnected(): utime.sleep(0.1) timeout = timeout - 1 if (timeout<1): draw_msg("Error", "Timeout while connecting!") utime.sleep(5) start_home(True) break else: pass draw_msg("Loading...","Loading alarms...") event_alarm.alarms_read() screen_home() # Start main application program_main()