pimoroni-pico/micropython/examples/stellar_unicorn/weather/weather.py

198 wiersze
6.6 KiB
Python

import time
from stellar import StellarUnicorn
from picographics import PicoGraphics, DISPLAY_STELLAR_UNICORN as DISPLAY
import WIFI_CONFIG
from network_manager import NetworkManager
import asyncio
import urequests
import jpegdec
from random import choice
"""
This example connects to Open Meteo to access the current weather conditions.
It then displays an appropriate weather icon on Stellar Unicorn.
Find out more about the Open Meteo API at https://open-meteo.com
Buttons:
A - show / hide temperature
B - swap between Celsius and Fahrenheit
C - randomly select a weather icon
D - add rainbows
LUX + and - adjust brightness
"""
# Set your latitude/longitude here (find yours by right clicking in Google Maps!)
LAT = 53.38609085276884
LNG = -1.4239983439328177
TIMEZONE = "auto" # determines time zone from lat/long
URL = "http://api.open-meteo.com/v1/forecast?latitude=" + str(LAT) + "&longitude=" + str(LNG) + "&current_weather=true&timezone=" + TIMEZONE
# how often to poll the API, in minutes
UPDATE_INTERVAL = 5
def get_data():
global temperature, weathercode
print(f"Requesting URL: {URL}")
r = urequests.get(URL)
# open the json data
j = r.json()
print("Data obtained!")
# parse relevant data from JSON
current = j["current_weather"]
temperature = current["temperature"]
windspeed = current["windspeed"]
winddirection = calculate_bearing(current["winddirection"])
weathercode = current["weathercode"]
date, now = current["time"].split("T")
print(f"Temp: {temperature}°C Wind Speed: {windspeed}kmph Wind Direction: {winddirection} As of: {date}, {now}")
r.close()
def calculate_bearing(d):
# calculates a compass direction from the wind direction in degrees
dirs = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW']
ix = round(d / (360. / len(dirs)))
return dirs[ix % len(dirs)]
def status_handler(mode, status, ip):
# reports wifi connection status
print(mode, status, ip)
print('Connecting to wifi...')
if status is not None:
if status:
print('Wifi connection successful!')
else:
print('Wifi connection failed!')
# create objects and picographics surface for drawing
su = StellarUnicorn()
display = PicoGraphics(DISPLAY)
jpeg = jpegdec.JPEG(display)
# some useful constants
WIDTH = StellarUnicorn.WIDTH
HEIGHT = StellarUnicorn.HEIGHT
BLACK = display.create_pen(0, 0, 0)
RED = display.create_pen(255, 0, 0)
ORANGE = display.create_pen(246, 138, 30)
YELLOW = display.create_pen(255, 216, 0)
GREEN = display.create_pen(0, 121, 64)
BLUE = display.create_pen(0, 0, 255)
INDIGO = display.create_pen(36, 64, 142)
VIOLET = display.create_pen(115, 41, 130)
WHITE = display.create_pen(255, 255, 255)
show_temperature = True
show_fahrenheit = False
show_rainbow = False
# timer variable to keep track of how often to poll the api
timer = UPDATE_INTERVAL * 60.0
su.set_brightness(0.8)
# set up wifi
try:
network_manager = NetworkManager(WIFI_CONFIG.COUNTRY, status_handler=status_handler)
asyncio.get_event_loop().run_until_complete(network_manager.client(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK))
except Exception as e:
print(f'Wifi connection failed! {e}')
while True:
# adjust brightness with LUX + and -
if su.is_pressed(StellarUnicorn.SWITCH_BRIGHTNESS_UP):
su.adjust_brightness(+0.05)
print(f"Brightness set to {su.get_brightness()}")
if su.is_pressed(StellarUnicorn.SWITCH_BRIGHTNESS_DOWN):
su.adjust_brightness(-0.05)
print(f"Brightness set to {su.get_brightness()}")
if su.is_pressed(StellarUnicorn.SWITCH_A):
show_temperature = not show_temperature
print(f"Show temperature = {show_temperature}")
# debounce
time.sleep(0.1)
if su.is_pressed(StellarUnicorn.SWITCH_B):
show_fahrenheit = not show_fahrenheit
print(f"Show fahrenheit = {show_fahrenheit}")
# debounce
time.sleep(0.1)
# I hate this weather, give me another
if su.is_pressed(StellarUnicorn.SWITCH_C):
weathercode = choice([71, 51, 1, 0, 95])
print("Weather icon randomised!")
# debounce
time.sleep(0.1)
# brighten up boring weather with a rainbow
if su.is_pressed(StellarUnicorn.SWITCH_D):
show_rainbow = not show_rainbow
print(f"Show rainbow = {show_rainbow}")
# debounce
time.sleep(0.1)
# we only need to ping the api for data every UPDATE_INTERVAL
if timer >= UPDATE_INTERVAL * 60:
get_data()
timer = 0.0
if weathercode is not None:
# Choose an appropriate icon based on the weather code
# Weather codes from https://open-meteo.com/en/docs
if weathercode in [71, 73, 75, 77, 85, 86]: # codes for snow
jpeg.open_file("icons/snow.jpg")
elif weathercode in [51, 53, 55, 56, 57, 61, 63, 65, 66, 67, 80, 81, 82]: # codes for rain
jpeg.open_file("icons/rain.jpg")
elif weathercode in [1, 2, 3, 45, 48]: # codes for cloud
jpeg.open_file("icons/cloud.jpg")
elif weathercode in [0]: # codes for sun
jpeg.open_file("icons/sun.jpg")
elif weathercode in [95, 96, 99]: # codes for storm
jpeg.open_file("icons/storm.jpg")
jpeg.decode(0, 0, jpegdec.JPEG_SCALE_FULL)
if show_rainbow is True:
display.set_pen(VIOLET)
display.circle(WIDTH - 1, HEIGHT - 1, 6)
display.set_pen(BLUE)
display.circle(WIDTH - 1, HEIGHT - 1, 5)
display.set_pen(GREEN)
display.circle(WIDTH - 1, HEIGHT - 1, 4)
display.set_pen(YELLOW)
display.circle(WIDTH - 1, HEIGHT - 1, 3)
display.set_pen(ORANGE)
display.circle(WIDTH - 1, HEIGHT - 1, 2)
display.set_pen(RED)
display.circle(WIDTH - 1, HEIGHT - 1, 1)
# draw the temperature text
if show_temperature is True:
display.set_pen(RED)
if show_fahrenheit is True:
fahrenheit = (temperature * 9 / 5) + 32
# measure the text so we can right align it
text_width = display.measure_text(f"{fahrenheit:.0f}°", scale=1)
display.text(f"{fahrenheit:.0f}°", WIDTH - text_width, 4, WIDTH, scale=1)
else:
# measure the text so we can right align it
text_width = display.measure_text(f"{temperature:.0f}°", scale=1)
display.text(f"{temperature:.0f}°", WIDTH - text_width, 4, WIDTH, scale=1)
else:
display.set_pen(RED)
display.text("ERR", 0, 0, WIDTH, 1)
su.update(display)
timer += 0.1
time.sleep(0.1)