1
+ # The MIT License (MIT)
2
+ #
3
+ # Copyright (c) 2019 Michael McGurrin
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ """
24
+ This is the main program for a multi-function Portal app.
25
+ It includes current weather, day, date, time, S&P 500, Indoor Temp,
26
+ and Shower Thoughts subreddit.
27
+ """
28
+ import sys
29
+ import time
30
+ import board
31
+ from adafruit_pyportal import PyPortal
32
+ from adafruit_bitmap_font import bitmap_font
33
+ cwd = ("/" + __file__ ).rsplit ('/' , 1 )[0 ] # the current working directory (where this file is)
34
+ sys .path .append (cwd )
35
+ import day_graphics # pylint: disable=wrong-import-position
36
+ import openweather_graphics # pylint: disable=wrong-import-position
37
+ import st_graphics # pylint: disable=wrong-import-position
38
+ import market_graphics
39
+
40
+ linger = 7 # number of seconds to stay on each app
41
+ long_linger = 14 # For apps with more text, like shower thoughts
42
+
43
+ # Get wifi details and more from a secrets.py file
44
+ try :
45
+ from secrets import secrets
46
+ except ImportError :
47
+ print ("WiFi secrets are kept in secrets.py, please add them there!" )
48
+ raise
49
+
50
+ # Initiate the pyportal
51
+ DATA_LOCATION = []
52
+ pyportal = PyPortal (json_path = DATA_LOCATION ,
53
+ status_neopixel = board .NEOPIXEL ,
54
+ default_bg = 0x000000 )
55
+
56
+ # Get the fonts for all apps
57
+ small_font = cwd + "/fonts/Arial-12.bdf"
58
+ medium_font = cwd + "/fonts/Arial-16.bdf"
59
+ large_font = cwd + "/fonts/Arial-Bold-24.bdf"
60
+ small_font = bitmap_font .load_font (small_font )
61
+ medium_font = bitmap_font .load_font (medium_font )
62
+ large_font = bitmap_font .load_font (large_font )
63
+ glyphs = b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-,.: '
64
+ small_font .load_glyphs (glyphs )
65
+ medium_font .load_glyphs (glyphs )
66
+ large_font .load_glyphs (glyphs )
67
+ large_font .load_glyphs (('°' ,)) # a non-ascii character we need for sure
68
+
69
+ # Weather info
70
+ # Use cityname, country code where countrycode is ISO3166 format.
71
+ # E.g. "New York, US" or "London, GB" OR use Location Code
72
+ LOCATION = "4791160" #Vienna, VA
73
+ # Set up where we'll be fetching data from
74
+ # You'll need to get a token from openweather.org, looks like 'b6907d289e10d714a6e88b30761fae22'
75
+ WX_DATA_SOURCE = "https://api.openweathermap.org/data/2.5/weather?id=" + LOCATION
76
+ WX_DATA_SOURCE += "&appid=" + secrets ['openweather_token' ]
77
+
78
+ # S&P 500 ("Market Data") info
79
+ MARKET_DATA_SOURCE = "https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=INX"
80
+ MARKET_DATA_SOURCE += "&apikey=" + secrets ['alpha_advantage_key' ]
81
+
82
+ # Shower thoughts info
83
+ ST_DATA_SOURCE = "https://www.reddit.com/r/Showerthoughts/new.json?sort=new&limit=1"
84
+
85
+ # Loop through all the applications
86
+ localtime_refresh = None
87
+ weather_refresh = None
88
+ st_refresh = None
89
+ market_refresh = None
90
+ while True :
91
+ # Day, date, and time
92
+ # only query the online time once per hour (and on first run)
93
+ pyportal .set_background (cwd + "/day_bitmap.bmp" )
94
+ try :
95
+ if (not localtime_refresh ) or (time .monotonic () - localtime_refresh ) > 3600 :
96
+ print ("Getting time from internet!" )
97
+ pyportal .get_local_time ()
98
+ localtime_refresh = time .monotonic ()
99
+ text_group = day_graphics .day_graphics (medium_font = medium_font , large_font = large_font )
100
+ pyportal .splash .append (text_group )
101
+ # Display for seven seconds, then empty the pyportal.splash group so it can be loaded with new display info
102
+ time .sleep (linger )
103
+ except RuntimeError as e :
104
+ print ("Some error occured, skipping this iteration! -" , e )
105
+ continue
106
+ pyportal .splash .pop ()
107
+
108
+ # While there are some differences, could probably refactor the three segments
109
+ # below into one function call
110
+
111
+ # Display weather
112
+ # only query the weather every 10 minutes (and on first run)
113
+ pyportal .set_background (cwd + "/wx_bitmap.bmp" )
114
+ time .sleep (2 )
115
+ try :
116
+ if (not weather_refresh ) or (time .monotonic () - weather_refresh ) > 600 :
117
+ wx = pyportal .fetch (WX_DATA_SOURCE )
118
+ print ("Response is" , wx )
119
+ weather_refresh = time .monotonic ()
120
+ text_group , background_file = openweather_graphics .wx_graphics (medium_font = medium_font ,
121
+ large_font = large_font , small_font = small_font , weather = wx )
122
+ pyportal .set_background (cwd + background_file )
123
+ pyportal .splash .append (text_group )
124
+ # Display for 14 seconds, then empty the pyportal.splash group so it can be loaded with new display info
125
+ time .sleep (long_linger )
126
+ except RuntimeError as e :
127
+ print ("Some error occured, skipping this iteration! -" , e )
128
+ continue
129
+ pyportal .splash .pop ()
130
+
131
+ # Display Reddit Shower Thoughts
132
+ # only query shower thoughts every 5 minutes (and on first run)
133
+ pyportal .set_background (cwd + "/st_bitmap.bmp" )
134
+ time .sleep (2 )
135
+ try :
136
+ if (not st_refresh ) or (time .monotonic () - st_refresh ) > 300 :
137
+ print ("Getting shower thought from internet!" )
138
+ st = pyportal .fetch (ST_DATA_SOURCE )
139
+ print ("Response is" , st )
140
+ st_refresh = time .monotonic ()
141
+ text_group = st_graphics .st_graphics (medium_font = medium_font , large_font = large_font ,
142
+ small_font = small_font , st = st )
143
+ pyportal .splash .append (text_group )
144
+ # Display for 14 seconds, then empty the pyportal.splash group so it can be loaded with new display info
145
+ time .sleep (long_linger )
146
+ except RuntimeError as e :
147
+ print ("Some error occured, skipping this iteration! -" , e )
148
+ continue
149
+ pyportal .splash .pop ()
150
+
151
+ # Display S&P 500
152
+ # only query the S&P every 10 minutes (and on first run)
153
+ pyportal .set_background (cwd + "/market_bitmap.bmp" )
154
+ time .sleep (2 )
155
+ try :
156
+ if (not market_refresh ) or (time .monotonic () - market_refresh ) > 300 :
157
+ print ("Getting S&P 500 from internet!" )
158
+ market = pyportal .fetch (MARKET_DATA_SOURCE )
159
+ print ("Response is" , market )
160
+ market_refresh = time .monotonic ()
161
+ text_group , background_file = market_graphics .market_graphics (medium_font = medium_font , large_font = large_font ,
162
+ market = market )
163
+ pyportal .set_background (cwd + background_file )
164
+ pyportal .splash .append (text_group )
165
+ # Display for 7 seconds, then empty the pyportal.splash group so it can be loaded with new display info
166
+ time .sleep (linger )
167
+ except RuntimeError as e :
168
+ print ("Some error occured, skipping this iteration! -" , e )
169
+ continue
170
+ pyportal .splash .pop ()
0 commit comments