Last active
December 3, 2020 14:04
-
-
Save jameseleach/d2b48b37166ba2d1196875a46a252ef2 to your computer and use it in GitHub Desktop.
MatrixPortal Clock and Weather
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from time import localtime, monotonic | |
from json import loads | |
from board import SCL, SDA, NEOPIXEL, A0 | |
from busio import I2C | |
from neopixel import NeoPixel | |
from displayio import Group, Bitmap, Palette, TileGrid | |
from adafruit_vcnl4040 import VCNL4040 | |
from adafruit_imageload import load | |
from adafruit_display_text.label import Label | |
from adafruit_bitmap_font.bitmap_font import load_font | |
from adafruit_matrixportal.network import Network | |
from adafruit_matrixportal.matrix import Matrix | |
from reshader import Reshader | |
from secrets import secrets | |
# Probably don't modify these values | |
CB = 0.5 | |
LTU = None | |
LWU = None | |
LDS = None | |
class Weather: | |
def __init__(self, i, t, d, h, l): | |
self.icon = i | |
self.temp = t | |
self.description = d | |
self.high_temp = h | |
self.low_temp = l | |
def capitalize(s): | |
return " ".join([word[0].upper() + word[1:] for word in s.split()]) | |
def get_formatted_time(): # Format the current time as HH:MM | |
now = localtime() | |
hours = now.tm_hour | |
if hours > 12: | |
hours -= 12 | |
if hours == 0: | |
hours = 12 | |
minutes = now.tm_min | |
return "{hours}:{minutes:02d}".format(hours=hours, minutes=minutes) | |
def update_time_display(): | |
text = get_formatted_time() | |
previous_text = clock_label.text | |
if text != previous_text: | |
clock_label.text = text | |
clock_label.x = round(display.width / 2 - clock_label.bounding_box[2] / 2) - 1 | |
def query_weather(): # Query weather from API | |
ws =('https://api.openweathermap.org/data/2.5/weather?id=' + secrets['location_id'] + '&appid=' + secrets['openweather_token'] + '&units=imperial') | |
fs = ('https://api.openweathermap.org/data/2.5/forecast?lat=' + secrets['latitude'] + '&lon=' + secrets['longitude'] + '&appid=' + secrets['openweather_token'] + '&units=imperial&cnt=4') | |
wir = {"01d": 0,"01n": 1,"02d": 2,"02n": 3,"03d": 4,"03n": 5,"04d": 6,"04n": 7,"09d": 8,"09n": 9,"10d": 10,"10n": 11,"11d": 12,"11n": 13,"13d": 14,"13n": 15,"50d": 16,"50n": 17} | |
c = loads(network.fetch_data(ws)) | |
f = loads(network.fetch_data(fs)) | |
temps = [i['main']['temp'] for i in f['list']] | |
temps.append(c["main"]["temp"]) | |
return Weather(wir[c["weather"][0]["icon"]], '{:.0f}'.format(c["main"]["temp"]), capitalize(c["weather"][0]["description"]), '{:.0f}'.format(max(temps)), '{:.0f}'.format(min(temps))) | |
def update_weather_display(): | |
if results.icon != weather_icon[0]: | |
weather_icon[0] = results.icon | |
if results.temp != temp_label.text: | |
temp_label.text = results.temp | |
temp_label.x = (round(32 / 2 - temp_label.bounding_box[2] / 2) - 1) + 16 | |
if results.description != desc_label.text: | |
desc_label.text = results.description | |
desc_label.x = round(display.width / 2 - desc_label.bounding_box[2] / 2) - 1 | |
if results.high_temp != hi_temp_label.text: | |
hi_temp_label.text = results.high_temp | |
hi_temp_label.x = display.width - hi_temp_label.bounding_box[2] | |
if results.low_temp != lo_temp_label.text: | |
lo_temp_label.text = results.low_temp | |
lo_temp_label.x = display.width - lo_temp_label.bounding_box[2] | |
def update_display(): | |
if clock_group.hidden: | |
update_weather_display() | |
else: | |
update_time_display() | |
def switch_display(): | |
if clock_group.hidden: | |
weather_group.hidden = True | |
clock_group.hidden = False | |
else: | |
clock_group.hidden = True | |
weather_group.hidden = False | |
def adjust_brightness(l, cb): | |
if l < 20: | |
v = 0.1 | |
elif l > 70: | |
v = 1.0 | |
else: | |
v = 0.5 | |
if v != cb: | |
icon_shader.reshade(v) | |
clock_label_shader.reshade(v) | |
temp_label_shader.reshade(v) | |
desc_label_shader.reshade(v) | |
hi_temp_label_shader.reshade(v) | |
lo_temp_label_shader.reshade(v) | |
return v | |
# Setup VCNL4040 sensor | |
i2c = I2C(SCL, SDA) | |
sensor = VCNL4040(i2c) | |
# --- Turn off on-board Neopixel | |
pixel = NeoPixel(NEOPIXEL, 1) | |
pixel.fill((0,0,0)) | |
# Display setup | |
matrix = Matrix(width=64, height=32, bit_depth=6) | |
display = matrix.display | |
network = Network() | |
# Main screen setup | |
main_group = Group(max_size=2) # The Main Display Group | |
display.show(main_group) | |
# Setup Clock Group | |
clock_group = Group(max_size=1) | |
clock_font = load_font("fonts/Noto-18.bdf") | |
# clock_font.load_glyphs(b'0123456780:') | |
clock_label = Label(clock_font, color=0xFF0000, max_glyphs=5, y=display.height // 2) | |
clock_label.text = "wait" | |
clock_label.x = round(display.width / 2 - clock_label.bounding_box[2] / 2) - 1 | |
clock_label_shader = Reshader(clock_label.palette) | |
clock_group.append(clock_label) | |
# Add the clock group to the main group | |
main_group.append(clock_group) | |
# Setup Weather Group | |
weather_group = Group(max_size=6, scale=1) | |
icon, icon_palette = load("gfx/w-icons.bmp", bitmap=Bitmap, palette=Palette) | |
weather_icon = TileGrid(icon,pixel_shader=icon_palette,width=1,height=1,tile_width=16,tile_height=16,default_tile=5,x=0,y=0) | |
icon_shader = Reshader(icon_palette) | |
a12_font = load_font("fonts/Arial-12.bdf") | |
#a12_font.load_glyphs(b'1234567890 °FC') | |
temp_label = Label(a12_font, color=0xFF00FF, x=18, y=8, max_glyphs=8) | |
temp_label.text = "999" | |
temp_label.x = (round(32 / 2 - temp_label.bounding_box[2] / 2) - 1) + 16 | |
temp_label_shader = Reshader(temp_label.palette) | |
f58_font = load_font("fonts/5x8.bdf") | |
#f58_font.load_glyphs(b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ') | |
desc_label = Label(f58_font, color=0x00FFFF, x=0, y=16+8, max_glyphs=16) | |
desc_label.text = "Unknown" | |
desc_label.x = round(display.width / 2 - desc_label.bounding_box[2] / 2) - 1 | |
desc_label_shader = Reshader(desc_label.palette) | |
hi_temp_label = Label(f58_font, color=0xFF0000, x=48, y=2, max_glyphs=6) | |
hi_temp_label.text = "999" | |
hi_temp_label.x = display.width - hi_temp_label.bounding_box[2] | |
hi_temp_label_shader = Reshader(hi_temp_label.palette) | |
lo_temp_label = Label(f58_font, color=0x00FFFF, x=48, y=10, max_glyphs=6) | |
lo_temp_label.text = "-99" | |
lo_temp_label.x = display.width - lo_temp_label.bounding_box[2] | |
lo_temp_label_shader = Reshader(lo_temp_label.palette) | |
weather_group.append(weather_icon) | |
weather_group.append(temp_label) | |
weather_group.append(desc_label) | |
weather_group.append(hi_temp_label) | |
weather_group.append(lo_temp_label) | |
# Add weather group to main group and hide. | |
main_group.append(weather_group) | |
weather_group.hidden = True | |
while True: | |
if LTU is None or monotonic() > LTU + 3600: | |
try: | |
network.get_local_time() | |
LTU = monotonic() | |
#update_time_display() | |
except RuntimeError as e: | |
print("Error when querying -", e) | |
if LWU is None or monotonic() > LWU + 3600: | |
try: | |
results = query_weather() | |
LWU = monotonic() | |
#update_weather_display() | |
except RuntimeError as e: | |
print("Error when querying weather. -", e) | |
CB = adjust_brightness(sensor.lux, CB) | |
if sensor.proximity > 20 and (LDS is None or monotonic() > LDS + 5): | |
print("You're close!") | |
switch_display() | |
LDS = monotonic() | |
if clock_group.hidden and monotonic() > LDS + 10: | |
print("Weather screen timeout.") | |
switch_display() | |
LDS = monotonic() | |
update_display() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment