Skip to content

Commit 75189bd

Browse files
author
brentru
committed
add code for pyportal display, preliminary but working UI
1 parent 9d0fd1f commit 75189bd

2 files changed

Lines changed: 78 additions & 29 deletions

File tree

PyPortal_TOTP_Friend/code.py

Lines changed: 78 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,38 @@
11
import time
2+
23
import board
34
import busio
45
from digitalio import DigitalInOut
5-
from adafruit_esp32spi import adafruit_esp32spi
6-
from adafruit_ntp import NTP
6+
77
import adafruit_hashlib as hashlib
8+
import adafruit_touchscreen
9+
import displayio
10+
import neopixel
11+
import terminalio
812
from 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
1138
try:
@@ -14,14 +41,10 @@
1441
print("WiFi secrets are kept in secrets.py, please add them there!")
1542
raise
1643

17-
1844
TEST = 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!
2046
ON_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
2649
SHA1 = hashlib.sha1
2750

@@ -35,12 +58,6 @@
3558
esp = 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
4663
def 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-
6372
def 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-
100105
def 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-
113117
def 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+
131136
print("===========================================")
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

134171
print("Connecting to AP...")
172+
label_status.text = "Connecting to AP..."
135173
while 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']))
142183
print("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
149190
while 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
155199
t = 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

Comments
 (0)