11import time
2+
23import board
34import busio
45from digitalio import DigitalInOut
5- from adafruit_esp32spi import adafruit_esp32spi
6- from adafruit_ntp import NTP
6+
77import adafruit_hashlib as hashlib
8+ import adafruit_touchscreen
9+ import displayio
10+ import neopixel
11+ import terminalio
812from adafruit_binascii import hexlify , unhexlify
13+ from adafruit_bitmap_font import bitmap_font
14+ from adafruit_display_shapes .circle import Circle
15+ from adafruit_display_shapes .roundrect import RoundRect
16+ from adafruit_display_text .label import Label
17+ from adafruit_esp32spi import adafruit_esp32spi
18+ from adafruit_ntp import NTP
19+ from adafruit_pyportal import PyPortal
20+
21+ # Initialize PyPortal Display
22+ display = board .DISPLAY
23+
24+ WIDTH = board .DISPLAY .width
25+ HEIGHT = board .DISPLAY .height
26+
27+ ts = adafruit_touchscreen .Touchscreen (board .TOUCH_XL , board .TOUCH_XR ,
28+ board .TOUCH_YD , board .TOUCH_YU ,
29+ calibration = (
30+ (5200 , 59000 ),
31+ (5800 , 57000 )
32+ ),
33+ size = (WIDTH , HEIGHT ))
34+
35+
936
1037# Get wifi details and more from a secrets.py file
1138try :
1441 print ("WiFi secrets are kept in secrets.py, please add them there!" )
1542 raise
1643
17-
1844TEST = True # if you want to print out the tests the hashers
19- ALWAYS_ON = False # Set to true if you never want to go to sleep!
45+ ALWAYS_ON = True # Set to true if you never want to go to sleep!
2046ON_SECONDS = 60 # how long to stay on if not in always_on mode
2147
22- EPOCH_DELTA = 946684800 # seconds between year 2000 and year 1970
23- SECS_DAY = 86400
24-
2548# Create a SHA1 Object
2649SHA1 = hashlib .sha1
2750
3558esp = adafruit_esp32spi .ESP_SPIcontrol (spi , esp32_cs , esp32_ready , esp32_reset )
3659
3760
38- if TEST :
39- print ("===========================================" )
40- sha1_output = hexlify (SHA1 (b'hello world' ).digest ())
41- assert sha1_output == b"2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"
42-
43-
4461# HMAC implementation, as hashlib/hmac wouldn't fit
4562# From https://en.wikipedia.org/wiki/Hash-based_message_authentication_code
4663def HMAC (k , m ):
@@ -52,14 +69,6 @@ def HMAC(k, m):
5269 outer_message = KEY_OUTER + SHA1 (inner_message ).digest ()
5370 return SHA1 (outer_message )
5471
55-
56- if TEST :
57- KEY = b'abcd'
58- MESSAGE = b'efgh'
59- print ("===========================================" )
60- hmac_out = hexlify (HMAC (KEY , MESSAGE ).digest ())
61- assert hmac_out == b'e5dbcf9263188f9fce90df572afeb39b66b27198'
62-
6372def base32_decode (encoded ):
6473 missing_padding = len (encoded ) % 8
6574 if missing_padding != 0 :
@@ -93,10 +102,6 @@ def base32_decode(encoded):
93102 out .append (byte ) # store what we got
94103 return out
95104
96- if TEST :
97- print ("===========================================" )
98- assert (bytes (base32_decode ("IFSGCZTSOVUXIIJB" )) == b'Adafruit!!' )
99-
100105def int_to_bytestring (i , padding = 8 ):
101106 result = []
102107 while i != 0 :
@@ -109,7 +114,6 @@ def int_to_bytestring(i, padding=8):
109114# HMAC -> OTP generator, pretty much same as
110115# https://github.com/pyotp/pyotp/blob/master/src/pyotp/otp.py
111116
112-
113117def generate_otp (int_input , secret_key , digits = 6 ):
114118 if int_input < 0 :
115119 raise ValueError ('input must be positive integer' )
@@ -128,17 +132,54 @@ def generate_otp(int_input, secret_key, digits=6):
128132
129133 return str_code
130134
135+
131136print ("===========================================" )
132137
138+ # GFX Font
139+ font = terminalio .FONT
140+
141+
142+ # Initialize new PyPortal object
143+ pyportal = PyPortal (esp = esp ,
144+ external_spi = spi )
145+
146+ # Root DisplayIO
147+ root_group = displayio .Group (max_size = 200 )
148+ display .show (root_group )
149+
150+ # TODO: Add press-able icon group
151+
152+ # Text DisplayIO
153+ text_group = displayio .Group (max_size = 100 )
154+
155+ # TOTP Key Label, scaled 5x
156+ key_group = displayio .Group (scale = 5 )
157+ # We'll use a default text placeholder for this label
158+ label_key = Label (font , text = "000 000" )
159+ label_key .x = (display .width // 2 ) // 15
160+ label_key .y = 5
161+ key_group .append (label_key )
162+ text_group .append (key_group )
163+
164+ # Create a label for the status
165+ label_status = Label (font , max_glyphs = 45 )
166+ label_status .x = (display .width // 2 ) - 50
167+ label_status .y = 75
168+ text_group .append (label_status )
169+ display .show (text_group )
133170
134171print ("Connecting to AP..." )
172+ label_status .text = "Connecting to AP..."
135173while not esp .is_connected :
136174 try :
137175 esp .connect_AP (secrets ['ssid' ], secrets ['password' ])
138176 except RuntimeError as e :
139177 print ("could not connect to AP, retrying: " , e )
178+ label_status .text ("Retrying..." )
140179 continue
141180
181+ label_status .text = "Connected! Fetching NTP..."
182+ #label_status.text("Connected to {}, fetching NTP...".format(secrets['ssid']))
142183print ("Connected to SSID: " , secrets ['ssid' ])
143184
144185# Initialize the NTP object
@@ -148,8 +189,11 @@ def generate_otp(int_input, secret_key, digits=6):
148189# keep retrying until a valid time is returned
149190while not ntp .valid_time :
150191 ntp .set_time ()
151- print ("Failed to obtain time, retrying in 15 seconds..." )
152- time .sleep (15 )
192+ label_status .text = "NTP Fetch Failed, retrying.."
193+ print ("Failed to obtain time, retrying in 5 seconds..." )
194+ time .sleep (5 )
195+
196+ label_status .text = "NTP Set!"
153197
154198# Get the current time in seconds since Jan 1, 1970
155199t = time .time ()
@@ -167,7 +211,12 @@ def generate_otp(int_input, secret_key, digits=6):
167211 # print("Unix time: ", unix_time)
168212 for name , secret in secrets ['totp_keys' ]:
169213 otp = generate_otp (unix_time // 30 , secret )
214+ # TODO: This needs to get cleaned up into a one-liner
215+ otp = str (otp )
216+ formatted_otp = "{} {}" .format (otp [0 :3 ],otp [3 :6 ])
217+ label_key .text = formatted_otp
218+ label_status .text = name
170219 print (name + " OTP output: " , otp ) # serial debugging output
171220 # We'll update every 1/4 second, we can hash very fast so its no biggie!
172221 countdown -= 0.25
173- time .sleep (0.25 )
222+ time .sleep (0.25 )
0 commit comments