Skip to content

Commit

Permalink
Merge pull request #4 from ladyada/master
Browse files Browse the repository at this point in the history
startup sound, AP settings notification text, allow background solid fill
  • Loading branch information
ladyada authored Feb 26, 2019
2 parents 34d9bb6 + 6f73a61 commit 7df38a4
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 33 deletions.
96 changes: 63 additions & 33 deletions adafruit_pyportal.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PyPortal.git"

# pylint: disable=line-too-long
IMAGE_CONVERTER_SERVICE = "http://res.cloudinary.com/schmarty/image/fetch/w_320,h_240,c_fill,f_bmp/"
IMAGE_CONVERTER_SERVICE = "https://res.cloudinary.com/schmarty/image/fetch/w_320,h_240,c_fill,f_bmp/"
#IMAGE_CONVERTER_SERVICE = "http://ec2-107-23-37-170.compute-1.amazonaws.com/rx/ofmt_bmp,rz_320x240/"
TIME_SERVICE_IPADDR = "http://worldtimeapi.org/api/ip"
TIME_SERVICE_LOCATION = "http://worldtimeapi.org/api/timezone/"
Expand Down Expand Up @@ -107,7 +107,8 @@ class PyPortal:
:param regexp_path: The list of regexp strings to get data out (use a single regexp group). Can
be list of regexps for multiple data points. Defaults to ``None`` to not
use regexp.
:param default_bg: The path to your default background image file. Defaults to ``None``.
:param default_bg: The path to your default background image file or a hex color.
Defaults to 0x000000.
:param status_neopixel: The pin for the status NeoPixel. Use ``board.NEOPIXEL`` for the on-board
NeoPixel. Defaults to ``None``, no status LED
:param str text_font: The path to your font file for your data text display.
Expand Down Expand Up @@ -137,7 +138,7 @@ class PyPortal:
"""
# pylint: disable=too-many-instance-attributes, too-many-locals, too-many-branches, too-many-statements
def __init__(self, *, url=None, json_path=None, regexp_path=None,
default_bg=None, status_neopixel=None,
default_bg=0x000000, status_neopixel=None,
text_font=None, text_position=None, text_color=0x808080,
text_wrap=False, text_maxlen=0,
image_json_path=None, image_resize=None, image_position=None,
Expand Down Expand Up @@ -208,6 +209,7 @@ def __init__(self, *, url=None, json_path=None, regexp_path=None,
raise RuntimeError("Was not able to find ESP32")

requests.set_interface(self._esp)
self._connect_esp()

if self._debug:
print("Init SD Card")
Expand All @@ -220,6 +222,11 @@ def __init__(self, *, url=None, json_path=None, regexp_path=None,
except OSError as error:
print("No SD card found:", error)

try:
self.play_file("pyportal_startup.wav")
except OSError:
pass # they deleted the file, no biggie!

if self._debug:
print("Init display")
self.splash = displayio.Group(max_size=5)
Expand Down Expand Up @@ -303,34 +310,39 @@ def __init__(self, *, url=None, json_path=None, regexp_path=None,
# pylint: enable=no-member

self.set_backlight(1.0) # turn on backlight

gc.collect()

def set_background(self, filename):
def set_background(self, file_or_color):
"""The background image to a bitmap file.
:param filename: The name of the chosen background image file.
:param file_or_color: The filename of the chosen background image, or a hex color.
"""
print("Set background to ", filename)
try:
print("Set background to ", file_or_color)
while self._bg_group:
self._bg_group.pop()
except IndexError:
pass # s'ok, we'll fix to test once we can

if not filename:
if not file_or_color:
return # we're done, no background desired
if self._bg_file:
self._bg_file.close()
self._bg_file = open(filename, "rb")
background = displayio.OnDiskBitmap(self._bg_file)
try:
if isinstance(file_or_color, str): # its a filenme:
self._bg_file = open(file_or_color, "rb")
background = displayio.OnDiskBitmap(self._bg_file)
self._bg_sprite = displayio.TileGrid(background,
pixel_shader=displayio.ColorConverter(),
position=(0, 0))
except AttributeError:
self._bg_sprite = displayio.Sprite(background, pixel_shader=displayio.ColorConverter(),
position=(0, 0))

elif isinstance(file_or_color, int):
# Make a background color fill
color_bitmap = displayio.Bitmap(320, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = file_or_color
self._bg_sprite = displayio.TileGrid(color_bitmap,
pixel_shader=color_palette,
position=(0, 0))
else:
raise RuntimeError("Unknown type of background")
self._bg_group.append(self._bg_sprite)
board.DISPLAY.refresh_soon()
gc.collect()
Expand Down Expand Up @@ -449,8 +461,8 @@ def play_file(file_name):
"""
#self._speaker_enable.value = True
with audioio.AudioOut(board.AUDIO_OUT) as audio:
with open(file_name, "rb") as file:
with open(file_name, "rb") as file:
with audioio.AudioOut(board.AUDIO_OUT) as audio:
with audioio.WaveFile(file) as wavefile:
audio.play(wavefile)
while audio.playing:
Expand All @@ -475,17 +487,24 @@ def get_local_time(self, location=None):
# pylint: enable=line-too-long
self._connect_esp()
api_url = None
if not location:
api_url = TIME_SERVICE_IPADDR
else:
if secrets['timezone']:
location = secrets['timezone']
if location:
print("Getting time for timezone", location)
api_url = TIME_SERVICE_LOCATION + location
response = requests.get(api_url)
time_json = response.json()
current_time = time_json['datetime']
year_day = time_json['day_of_year']
week_day = time_json['day_of_week']
is_dst = time_json['dst']
else: # we'll try to figure it out from the IP address
print("Getting time from IP address")
api_url = TIME_SERVICE_IPADDR

try:
response = requests.get(api_url)
time_json = response.json()
current_time = time_json['datetime']
year_day = time_json['day_of_year']
week_day = time_json['day_of_week']
is_dst = time_json['dst']
except KeyError:
raise KeyError("Was unable to lookup the time, try setting secrets['timezone'] according to http://worldtimeapi.org/timezones") # pylint: disable=line-too-long
the_date, the_time = current_time.split('T')
year, month, mday = [int(x) for x in the_date.split('-')]
the_time = the_time.split('.')[0]
Expand Down Expand Up @@ -542,12 +561,22 @@ def wget(self, url, filename, *, chunk_size=12000):
def _connect_esp(self):
self.neo_status((0, 0, 100))
while not self._esp.is_connected:
if self._debug:
print("Connecting to AP")
# secrets dictionary must contain 'ssid' and 'password' at a minimum
print("Connecting to AP", secrets['ssid'])
if secrets['ssid'] == 'CHANGE ME' or secrets['ssid'] == 'CHANGE ME':
print("*"*45)
print("Please update the 'secrets.py' file on your")
print("CIRCUITPY drive to include your local access")
print("point SSID name in 'ssid' and SSID password")
print("in 'password'. Then save to reload!")
print("*"*45)
self.neo_status((100, 0, 0)) # red = not connected
self._esp.connect(secrets)

try:
self._esp.connect(secrets)
except RuntimeError as error:
print("Cound not connect to internet", error)
print("Retrying in 3 seconds...")
time.sleep(3)
def fetch(self):
"""Fetch data from the url we initialized with, perfom any parsing,
and display text or graphics. This function does pretty much everything"""
Expand Down Expand Up @@ -719,7 +748,8 @@ def show_QR(self, qr_data, qr_size=128, position=None): # pylint: disable=inval

for b in range(BLOCK_SIZE):
# load this line of data in, as many time as block size
qr_bitmap._load_row(Y_OFFSET + y*BLOCK_SIZE+b, line) # pylint: disable=protected-access
for i, byte in enumerate(line):
qr_bitmap[Y_OFFSET + y*BLOCK_SIZE+b + i] = byte
# pylint: enable=invalid-name

# display the bitmap using our palette
Expand Down
Binary file added examples/pyportal_startup.wav
Binary file not shown.

0 comments on commit 7df38a4

Please sign in to comment.