first commit
This commit is contained in:
parent
29a7b2aa7b
commit
b8e3518d8a
7 changed files with 41293 additions and 0 deletions
6068
Weather_Display_Matrix/fonts/Arial-12.bdf
Executable file
6068
Weather_Display_Matrix/fonts/Arial-12.bdf
Executable file
File diff suppressed because it is too large
Load diff
27566
Weather_Display_Matrix/fonts/Arial-14.bdf
Executable file
27566
Weather_Display_Matrix/fonts/Arial-14.bdf
Executable file
File diff suppressed because it is too large
Load diff
7366
Weather_Display_Matrix/fonts/Arial-16.bdf
Executable file
7366
Weather_Display_Matrix/fonts/Arial-16.bdf
Executable file
File diff suppressed because it is too large
Load diff
BIN
Weather_Display_Matrix/loading.bmp
Normal file
BIN
Weather_Display_Matrix/loading.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
205
Weather_Display_Matrix/openweather_graphics.py
Normal file
205
Weather_Display_Matrix/openweather_graphics.py
Normal file
|
|
@ -0,0 +1,205 @@
|
||||||
|
import time
|
||||||
|
import displayio
|
||||||
|
from adafruit_display_text.label import Label
|
||||||
|
from adafruit_bitmap_font import bitmap_font
|
||||||
|
|
||||||
|
TEMP_COLOR = 0xFFA800
|
||||||
|
MAIN_COLOR = 0x9000FF # weather condition
|
||||||
|
DESCRIPTION_COLOR = 0x00D3FF
|
||||||
|
CITY_COLOR = 0x9000FF
|
||||||
|
HUMIDITY_COLOR = 0x0000AA
|
||||||
|
WIND_COLOR = 0xCCCCCC
|
||||||
|
|
||||||
|
cwd = ("/" + __file__).rsplit("/", 1)[
|
||||||
|
0
|
||||||
|
] # the current working directory (where this file is)
|
||||||
|
|
||||||
|
small_font = cwd + "/fonts/Arial-12.bdf"
|
||||||
|
medium_font = cwd + "/fonts/Arial-14.bdf"
|
||||||
|
|
||||||
|
icon_spritesheet = cwd + "/weather-icons.bmp"
|
||||||
|
icon_width = 16
|
||||||
|
icon_height = 16
|
||||||
|
scrolling_text_height = 24
|
||||||
|
scroll_delay = 0.03
|
||||||
|
|
||||||
|
|
||||||
|
class OpenWeather_Graphics(displayio.Group):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
display,
|
||||||
|
*,
|
||||||
|
am_pm=True,
|
||||||
|
units="imperial"
|
||||||
|
):
|
||||||
|
super().__init__(max_size=3)
|
||||||
|
self.am_pm = am_pm
|
||||||
|
if units == "metric":
|
||||||
|
self.celsius = True
|
||||||
|
self.meters_speed = True
|
||||||
|
else:
|
||||||
|
self.celsius = False
|
||||||
|
self.meters_speed = False
|
||||||
|
self.display = display
|
||||||
|
|
||||||
|
splash = displayio.Group(max_size=1)
|
||||||
|
background = displayio.OnDiskBitmap(open("loading.bmp", "rb"))
|
||||||
|
bg_sprite = displayio.TileGrid(
|
||||||
|
background,
|
||||||
|
pixel_shader=displayio.ColorConverter(),
|
||||||
|
)
|
||||||
|
splash.append(bg_sprite)
|
||||||
|
display.show(splash)
|
||||||
|
|
||||||
|
self.root_group = displayio.Group(max_size=15)
|
||||||
|
self.root_group.append(self)
|
||||||
|
self._icon_group = displayio.Group(max_size=1)
|
||||||
|
self.append(self._icon_group)
|
||||||
|
self._text_group = displayio.Group(max_size=5)
|
||||||
|
self.append(self._text_group)
|
||||||
|
self._scrolling_group = displayio.Group(max_size=1)
|
||||||
|
self.append(self._scrolling_group)
|
||||||
|
|
||||||
|
# The label index we're currently scrolling
|
||||||
|
self._current_label = None
|
||||||
|
|
||||||
|
# Load the icon sprite sheet
|
||||||
|
icons = displayio.OnDiskBitmap(open(icon_spritesheet, "rb"))
|
||||||
|
self._icon_sprite = displayio.TileGrid(
|
||||||
|
icons,
|
||||||
|
pixel_shader=displayio.ColorConverter(),
|
||||||
|
width=1,
|
||||||
|
height=1,
|
||||||
|
tile_width=icon_width,
|
||||||
|
tile_height=icon_height,
|
||||||
|
default_tile=0,
|
||||||
|
x=0,
|
||||||
|
y=0,
|
||||||
|
)
|
||||||
|
self.set_icon(None)
|
||||||
|
self._scrolling_texts = []
|
||||||
|
|
||||||
|
self.small_font = bitmap_font.load_font(small_font)
|
||||||
|
self.medium_font = bitmap_font.load_font(medium_font)
|
||||||
|
glyphs = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-,.: "
|
||||||
|
self.small_font.load_glyphs(glyphs)
|
||||||
|
self.medium_font.load_glyphs(glyphs)
|
||||||
|
self.medium_font.load_glyphs(("°",)) # a non-ascii character we need for sure
|
||||||
|
|
||||||
|
self.city_text = None
|
||||||
|
|
||||||
|
self.temp_text = Label(self.medium_font, max_glyphs=6)
|
||||||
|
self.temp_text.x = 20
|
||||||
|
self.temp_text.y = 7
|
||||||
|
self.temp_text.color = TEMP_COLOR
|
||||||
|
self._text_group.append(self.temp_text)
|
||||||
|
|
||||||
|
self.description_text = Label(self.small_font, max_glyphs=60)
|
||||||
|
self.description_text.color = DESCRIPTION_COLOR
|
||||||
|
self._scrolling_texts.append(self.description_text)
|
||||||
|
|
||||||
|
self.humidity_text = Label(self.small_font, max_glyphs=14)
|
||||||
|
self.humidity_text.color = HUMIDITY_COLOR #
|
||||||
|
self._scrolling_texts.append(self.humidity_text)
|
||||||
|
|
||||||
|
self.wind_text = Label(self.small_font, max_glyphs=10)
|
||||||
|
self.wind_text.color = WIND_COLOR
|
||||||
|
self._scrolling_texts.append(self.wind_text)
|
||||||
|
|
||||||
|
def display_weather(self, weather):
|
||||||
|
# set the icon
|
||||||
|
self.set_icon(weather["weather"][0]["icon"])
|
||||||
|
|
||||||
|
city_name = weather["name"] + ", " + weather["sys"]["country"]
|
||||||
|
print(city_name)
|
||||||
|
if not self.city_text:
|
||||||
|
self.city_text = Label(self.small_font, text=city_name)
|
||||||
|
self.city_text.color = CITY_COLOR
|
||||||
|
self._scrolling_texts.append(self.city_text)
|
||||||
|
|
||||||
|
temperature = weather["main"]["temp"]
|
||||||
|
print(temperature)
|
||||||
|
if self.celsius:
|
||||||
|
self.temp_text.text = "%d°C" % temperature
|
||||||
|
else:
|
||||||
|
self.temp_text.text = "%d°F" % temperature
|
||||||
|
|
||||||
|
description = weather["weather"][0]["description"]
|
||||||
|
description = description[0].upper() + description[1:]
|
||||||
|
print(description)
|
||||||
|
self.description_text.text = description
|
||||||
|
# "thunderstorm with heavy drizzle"
|
||||||
|
|
||||||
|
humidity = weather["main"]["humidity"]
|
||||||
|
print(humidity)
|
||||||
|
self.humidity_text.text = "%d%% humidity" % humidity
|
||||||
|
|
||||||
|
wind = weather["wind"]["speed"]
|
||||||
|
print(wind)
|
||||||
|
if self.meters_speed:
|
||||||
|
self.wind_text.text = "%d m/s" % wind
|
||||||
|
else:
|
||||||
|
self.wind_text.text = "%d mph" % wind
|
||||||
|
|
||||||
|
self.display.show(self.root_group)
|
||||||
|
|
||||||
|
def set_icon(self, icon_name):
|
||||||
|
"""Use icon_name to get the position of the sprite and update
|
||||||
|
the current icon.
|
||||||
|
|
||||||
|
:param icon_name: The icon name returned by openweathermap
|
||||||
|
|
||||||
|
Format is always 2 numbers followed by 'd' or 'n' as the 3rd character
|
||||||
|
"""
|
||||||
|
|
||||||
|
icon_map = ("01", "02", "03", "04", "09", "10", "11", "13", "50")
|
||||||
|
|
||||||
|
print("Set icon to", icon_name)
|
||||||
|
if self._icon_group:
|
||||||
|
self._icon_group.pop()
|
||||||
|
if icon_name is not None:
|
||||||
|
row = None
|
||||||
|
for index, icon in enumerate(icon_map):
|
||||||
|
if icon == icon_name[0:2]:
|
||||||
|
row = index
|
||||||
|
break
|
||||||
|
column = 0
|
||||||
|
if icon_name[2] == "n":
|
||||||
|
column = 1
|
||||||
|
if row is not None:
|
||||||
|
print(column, row)
|
||||||
|
self._icon_sprite[0] = (row * 2) + column
|
||||||
|
self._icon_group.append(self._icon_sprite)
|
||||||
|
|
||||||
|
def scroll_next_label(self):
|
||||||
|
# Start by scrolling current label off if not set to None
|
||||||
|
if self._current_label is not None and self._scrolling_group:
|
||||||
|
current_text = self._scrolling_texts[self._current_label]
|
||||||
|
text_width = current_text.bounding_box[2]
|
||||||
|
for _ in range(text_width + 1):
|
||||||
|
self._scrolling_group.x = self._scrolling_group.x - 1
|
||||||
|
time.sleep(scroll_delay)
|
||||||
|
|
||||||
|
if self._current_label is not None:
|
||||||
|
self._current_label += 1
|
||||||
|
if self._current_label is None or self._current_label >= len(
|
||||||
|
self._scrolling_texts
|
||||||
|
):
|
||||||
|
self._current_label = 0
|
||||||
|
|
||||||
|
# Setup the scrolling group by removing any existing
|
||||||
|
if self._scrolling_group:
|
||||||
|
self._scrolling_group.pop()
|
||||||
|
# Then add the current label
|
||||||
|
current_text = self._scrolling_texts[self._current_label]
|
||||||
|
self._scrolling_group.append(current_text)
|
||||||
|
|
||||||
|
# Set the position of the group to just off screen and centered vertically for lower half
|
||||||
|
self._scrolling_group.x = self.display.width
|
||||||
|
self._scrolling_group.y = 23
|
||||||
|
|
||||||
|
# Run a loop until the label is offscreen again and leave function
|
||||||
|
for _ in range(self.display.width):
|
||||||
|
self._scrolling_group.x = self._scrolling_group.x - 1
|
||||||
|
time.sleep(scroll_delay)
|
||||||
|
# By blocking other code we will never leave the label half way scrolled
|
||||||
BIN
Weather_Display_Matrix/weather-icons.bmp
Normal file
BIN
Weather_Display_Matrix/weather-icons.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
88
Weather_Display_Matrix/weather_display_matrix.py
Normal file
88
Weather_Display_Matrix/weather_display_matrix.py
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
# Matrix Weather display
|
||||||
|
# For Metro M4 Airlift with RGB Matrix shield, 64 x 32 RGB LED Matrix display
|
||||||
|
|
||||||
|
"""
|
||||||
|
This example queries the Open Weather Maps site API to find out the current
|
||||||
|
weather for your location... and display it on a screen!
|
||||||
|
if you can find something that spits out JSON data, we can display it
|
||||||
|
"""
|
||||||
|
import time
|
||||||
|
import board
|
||||||
|
from digitalio import DigitalInOut, Direction, Pull
|
||||||
|
from adafruit_matrixportal.network import Network
|
||||||
|
from adafruit_matrixportal.matrix import Matrix
|
||||||
|
import openweather_graphics # pylint: disable=wrong-import-position
|
||||||
|
|
||||||
|
# Get wifi details and more from a secrets.py file
|
||||||
|
try:
|
||||||
|
from secrets import secrets
|
||||||
|
except ImportError:
|
||||||
|
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||||
|
raise
|
||||||
|
|
||||||
|
jumper = DigitalInOut(board.D12)
|
||||||
|
jumper.direction = Direction.INPUT
|
||||||
|
jumper.pull = Pull.UP
|
||||||
|
|
||||||
|
if jumper.value:
|
||||||
|
UNITS = "metric" # can pick 'imperial' or 'metric' as part of URL query
|
||||||
|
print("Jumper set to metric")
|
||||||
|
else:
|
||||||
|
UNITS = "imperial"
|
||||||
|
print("Jumper set to imperial")
|
||||||
|
|
||||||
|
# Use cityname, country code where countrycode is ISO3166 format.
|
||||||
|
# E.g. "New York, US" or "London, GB"
|
||||||
|
LOCATION = "Los Angeles, US"
|
||||||
|
print("Getting weather for {}".format(LOCATION))
|
||||||
|
# Set up from where we'll be fetching data
|
||||||
|
DATA_SOURCE = (
|
||||||
|
"http://api.openweathermap.org/data/2.5/weather?q=" + LOCATION + "&units=" + UNITS
|
||||||
|
)
|
||||||
|
DATA_SOURCE += "&appid=" + secrets["openweather_token"]
|
||||||
|
# You'll need to get a token from openweather.org, looks like 'b6907d289e10d714a6e88b30761fae22'
|
||||||
|
# it goes in your secrets.py file on a line such as:
|
||||||
|
# 'openweather_token' : 'your_big_humongous_gigantor_token',
|
||||||
|
DATA_LOCATION = []
|
||||||
|
SCROLL_HOLD_TIME = 0 # set this to hold each line before finishing scroll
|
||||||
|
|
||||||
|
# --- Display setup ---
|
||||||
|
matrix = Matrix()
|
||||||
|
network = Network(status_neopixel=board.NEOPIXEL, debug=True)
|
||||||
|
if UNITS == "imperial":
|
||||||
|
gfx = openweather_graphics.OpenWeather_Graphics(
|
||||||
|
matrix.display, am_pm=True, units="imperial"
|
||||||
|
)
|
||||||
|
elif UNITS == "metric":
|
||||||
|
gfx = openweather_graphics.OpenWeather_Graphics(
|
||||||
|
matrix.display, am_pm=True, units="metric"
|
||||||
|
)
|
||||||
|
|
||||||
|
print("gfx loaded")
|
||||||
|
localtime_refresh = None
|
||||||
|
weather_refresh = None
|
||||||
|
while True:
|
||||||
|
# only query the online time once per hour (and on first run)
|
||||||
|
if (not localtime_refresh) or (time.monotonic() - localtime_refresh) > 3600:
|
||||||
|
try:
|
||||||
|
print("Getting time from internet!")
|
||||||
|
network.get_local_time()
|
||||||
|
localtime_refresh = time.monotonic()
|
||||||
|
except RuntimeError as e:
|
||||||
|
print("Some error occured, retrying! -", e)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# only query the weather every 10 minutes (and on first run)
|
||||||
|
if (not weather_refresh) or (time.monotonic() - weather_refresh) > 600:
|
||||||
|
try:
|
||||||
|
value = network.fetch_data(DATA_SOURCE, json_path=(DATA_LOCATION,))
|
||||||
|
print("Response is", value)
|
||||||
|
gfx.display_weather(value)
|
||||||
|
weather_refresh = time.monotonic()
|
||||||
|
except RuntimeError as e:
|
||||||
|
print("Some error occured, retrying! -", e)
|
||||||
|
continue
|
||||||
|
|
||||||
|
gfx.scroll_next_label()
|
||||||
|
# Pause between labels
|
||||||
|
time.sleep(SCROLL_HOLD_TIME)
|
||||||
Loading…
Reference in a new issue