From 60abf218e65ec3c96bed9cd71fddb6300f1bf3df Mon Sep 17 00:00:00 2001 From: ladyada Date: Mon, 25 Feb 2019 22:56:52 -0500 Subject: [PATCH 1/6] update to pretty board names, dont fail if no timezone --- adafruit_pyportal.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/adafruit_pyportal.py b/adafruit_pyportal.py index a751ed3..e0b1207 100644 --- a/adafruit_pyportal.py +++ b/adafruit_pyportal.py @@ -181,17 +181,11 @@ def __init__(self, *, url=None, json_path=None, regexp_path=None, # Make ESP32 connection if self._debug: print("Init ESP32") - # pylint: disable=no-member - esp32_cs = DigitalInOut(microcontroller.pin.PB14) - esp32_ready = DigitalInOut(microcontroller.pin.PB16) - esp32_gpio0 = DigitalInOut(microcontroller.pin.PB15) - esp32_reset = DigitalInOut(microcontroller.pin.PB17) - #esp32_ready = DigitalInOut(board.ESP_BUSY) - #esp32_gpio0 = DigitalInOut(board.ESP_GPIO0) - #esp32_reset = DigitalInOut(board.ESP_RESET) - #esp32_cs = DigitalInOut(board.ESP_CS) + esp32_ready = DigitalInOut(board.ESP_BUSY) + esp32_gpio0 = DigitalInOut(board.ESP_GPIO0) + esp32_reset = DigitalInOut(board.ESP_RESET) + esp32_cs = DigitalInOut(board.ESP_CS) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) - # pylint: enable=no-member if not self._uselocal: self._esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, From c9b880a7c94b976ffbbd043acf6467b6d82a4956 Mon Sep 17 00:00:00 2001 From: ladyada Date: Mon, 25 Feb 2019 23:00:37 -0500 Subject: [PATCH 2/6] try to get timezone but dont error --- adafruit_pyportal.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/adafruit_pyportal.py b/adafruit_pyportal.py index e0b1207..8db05b1 100644 --- a/adafruit_pyportal.py +++ b/adafruit_pyportal.py @@ -481,8 +481,10 @@ def get_local_time(self, location=None): # pylint: enable=line-too-long self._connect_esp() api_url = None - if secrets['timezone']: + try: location = secrets['timezone'] + except: + pass if location: print("Getting time for timezone", location) api_url = TIME_SERVICE_LOCATION + location From 3e0524e72e48b8b1644bdab4fb6e54c5da19f8d8 Mon Sep 17 00:00:00 2001 From: ladyada Date: Mon, 25 Feb 2019 23:07:24 -0500 Subject: [PATCH 3/6] more simpler get --- adafruit_pyportal.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/adafruit_pyportal.py b/adafruit_pyportal.py index 8db05b1..4ae9ecb 100644 --- a/adafruit_pyportal.py +++ b/adafruit_pyportal.py @@ -481,10 +481,7 @@ def get_local_time(self, location=None): # pylint: enable=line-too-long self._connect_esp() api_url = None - try: - location = secrets['timezone'] - except: - pass + location = secrets.get('timezone', location) if location: print("Getting time for timezone", location) api_url = TIME_SERVICE_LOCATION + location From ce1bd60a1d599c02269795349855430ce43c63df Mon Sep 17 00:00:00 2001 From: ladyada Date: Thu, 28 Feb 2019 17:23:06 -0500 Subject: [PATCH 4/6] add text transformation function and update image service to adafruit.io --- adafruit_pyportal.py | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/adafruit_pyportal.py b/adafruit_pyportal.py index 4ae9ecb..78148ab 100644 --- a/adafruit_pyportal.py +++ b/adafruit_pyportal.py @@ -77,8 +77,9 @@ __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PyPortal.git" # pylint: disable=line-too-long -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/" +# you'll need to pass in an io username, width, height, format (bit depth), io key, and then url! +IMAGE_CONVERTER_SERVICE = "https://io.adafruit.com/api/v2/%s/integrations/image-formatter?x-aio-key=%s&width=%d&height=%d&output=BMP%d&url=%s" + TIME_SERVICE_IPADDR = "http://worldtimeapi.org/api/ip" TIME_SERVICE_LOCATION = "http://worldtimeapi.org/api/timezone/" LOCALFILE = "local.txt" @@ -119,6 +120,7 @@ class PyPortal: :param text_wrap: Whether or not to wrap text (for long text data chunks). Defaults to ``False``, no wrapping. :param text_maxlen: The max length of the text for text wrapping. Defaults to 0. + :param text_transform: A function that will be called on the text before display :param image_json_path: The JSON traversal path for a background image to display. Defaults to ``None``. :param image_resize: What size to resize the image we got from the json_path, make this a tuple @@ -140,7 +142,7 @@ class PyPortal: def __init__(self, *, url=None, json_path=None, regexp_path=None, default_bg=0x000000, status_neopixel=None, text_font=None, text_position=None, text_color=0x808080, - text_wrap=False, text_maxlen=0, + text_wrap=False, text_maxlen=0, text_transform=None, image_json_path=None, image_resize=None, image_position=None, caption_text=None, caption_font=None, caption_position=None, caption_color=0x808080, @@ -256,11 +258,13 @@ def __init__(self, *, url=None, json_path=None, regexp_path=None, text_color = (text_color,) text_wrap = (text_wrap,) text_maxlen = (text_maxlen,) + text_transform = (text_transform,) self._text = [None] * num self._text_color = [None] * num self._text_position = [None] * num self._text_wrap = [None] * num self._text_maxlen = [None] * num + self._text_transform = [None] * num self._text_font = bitmap_font.load_font(text_font) if self._debug: print("Loading font glyphs") @@ -276,6 +280,7 @@ def __init__(self, *, url=None, json_path=None, regexp_path=None, self._text_position[i] = text_position[i] self._text_wrap[i] = text_wrap[i] self._text_maxlen[i] = text_maxlen[i] + self._text_transform[i] = text_transform[i] else: self._text_font = None self._text = None @@ -617,7 +622,11 @@ def fetch(self): # extract desired text/values from json if self._json_path: for path in self._json_path: - values.append(PyPortal._json_traverse(json_out, path)) + try: + values.append(PyPortal._json_traverse(json_out, path)) + except KeyError: + print(json_out) + raise elif self._regexp_path: for regexp in self._regexp_path: values.append(re.search(regexp, r.text).group(1)) @@ -637,9 +646,17 @@ def fetch(self): gc.collect() if image_url: + try: + aio_username = secrets['aio_username'] + aio_key = secrets['aio_key'] + except KeyError: + raise KeyError("\n\nOur image converter service require a login/password to rate-limit. Please register for a freeadafruit.io account and place the user/key in your secrets file under 'aio_username' and 'aio_key'")# pylint: disable=line-too-long try: print("original URL:", image_url) - image_url = IMAGE_CONVERTER_SERVICE+image_url + image_url = IMAGE_CONVERTER_SERVICE % (aio_username, aio_key, + self._image_resize[0], + self._image_resize[1], + 16, image_url) print("convert URL:", image_url) # convert image to bitmap and cache #print("**not actually wgetting**") @@ -669,10 +686,14 @@ def fetch(self): if self._text: for i in range(len(self._text)): string = None - try: - string = "{:,d}".format(int(values[i])) - except (TypeError, ValueError): - string = values[i] # ok its a string + if self._text_transform[i]: + f = self._text_transform[i] + string = f(values[i]) + else: + try: + string = "{:,d}".format(int(values[i])) + except (TypeError, ValueError): + string = values[i] # ok its a string if self._debug: print("Drawing text", string) if self._text_wrap[i]: From f78185b3538154ab824b49b87c189f7ab7ce444d Mon Sep 17 00:00:00 2001 From: ladyada Date: Thu, 28 Feb 2019 17:41:00 -0500 Subject: [PATCH 5/6] lint --- adafruit_pyportal.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/adafruit_pyportal.py b/adafruit_pyportal.py index 78148ab..4cb21c4 100644 --- a/adafruit_pyportal.py +++ b/adafruit_pyportal.py @@ -252,6 +252,8 @@ def __init__(self, *, url=None, json_path=None, regexp_path=None, text_wrap = [0] * num if not text_maxlen: text_maxlen = [0] * num + if not text_transform: + text_transform = [None] * num else: num = 1 text_position = (text_position,) @@ -687,8 +689,8 @@ def fetch(self): for i in range(len(self._text)): string = None if self._text_transform[i]: - f = self._text_transform[i] - string = f(values[i]) + func = self._text_transform[i] + string = func(values[i]) else: try: string = "{:,d}".format(int(values[i])) From 6086ce396d8e1a0e6221bc713e631d3f5bdf45b5 Mon Sep 17 00:00:00 2001 From: ladyada Date: Thu, 28 Feb 2019 20:29:32 -0500 Subject: [PATCH 6/6] allow background playback --- adafruit_pyportal.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/adafruit_pyportal.py b/adafruit_pyportal.py index 4cb21c4..f01313f 100644 --- a/adafruit_pyportal.py +++ b/adafruit_pyportal.py @@ -218,6 +218,10 @@ def __init__(self, *, url=None, json_path=None, regexp_path=None, except OSError as error: print("No SD card found:", error) + self._speaker_enable = DigitalInOut(board.SPEAKER_ENABLE) + self._speaker_enable.switch_to_output(False) + self.audio = audioio.AudioOut(board.AUDIO_OUT) + try: self.play_file("pyportal_startup.wav") except OSError: @@ -454,21 +458,23 @@ def neo_status(self, value): if self.neopix: self.neopix.fill(value) - @staticmethod - def play_file(file_name): + def play_file(self, file_name, wait_to_finish=True): """Play a wav file. :param str file_name: The name of the wav file to play on the speaker. """ - #self._speaker_enable.value = True - 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: - pass - #self._speaker_enable.value = False + board.DISPLAY.wait_for_frame() + wavfile = open(file_name, "rb") + wavedata = audioio.WaveFile(wavfile) + self._speaker_enable.value = True + self.audio.play(wavedata) + if not wait_to_finish: + return + while self.audio.playing: + pass + wavfile.close() + self._speaker_enable.value = False @staticmethod def _json_traverse(json, path):