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

260 wiersze
8.4 KiB
Python
Czysty Zwykły widok Historia

2022-10-04 18:17:09 +00:00
import WIFI_CONFIG
from network_manager import NetworkManager
import uasyncio
2022-10-05 11:17:00 +00:00
import urequests
2022-10-04 18:17:09 +00:00
import time
import plasma
from plasma import plasma_stick
2022-10-04 18:17:09 +00:00
# Random functions! randrange is for picking integers from a range, and uniform is for floats.
from random import randrange, uniform
2022-10-18 14:17:10 +00:00
from machine import Timer, Pin
2022-10-04 18:17:09 +00:00
"""
Weather in a bottle!
This Plasma Stick example connects to Open Meteo to access the current weather conditions.
It then does some cool weather appropriate stuff with LEDs.
Find out more about the Open Meteo API at https://open-meteo.com
2022-10-18 14:49:59 +00:00
Based on original code by AxWax <3 https://github.com/axwax/Open-Meteo-Inky-Pack
2022-10-04 18:17:09 +00:00
"""
# Set how many LEDs you have
NUM_LEDS = 50
# 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 = "https://api.open-meteo.com/v1/forecast?latitude=" + str(LAT) + "&longitude=" + str(LNG) + "&current_weather=true&timezone=" + TIMEZONE
2022-10-10 14:17:25 +00:00
UPDATE_INTERVAL = 900 # refresh interval in secs. Be nice to free APIs!
2022-10-04 18:17:09 +00:00
# Weather codes from https://open-meteo.com/en/docs#:~:text=WMO%20Weather%20interpretation%20codes%20(WW)
WEATHERCODES = {
0: 'clear sky',
1: 'mostly clear',
2: 'partly cloudy',
3: 'cloudy',
45: 'fog and depositing rime',
48: 'fog',
51: 'light drizzle',
53: 'moderate drizzle',
55: 'dense drizzle',
56: 'light freezing drizzle',
57: 'dense freezing drizzle',
61: 'slight rain',
63: 'moderate rain',
65: 'heavy rain',
66: 'light freezing rain',
67: 'heavy freezing rain',
71: 'slight snow',
73: 'moderate snow',
75: 'heavy snow',
77: 'snow grains',
80: 'slight rain showers',
81: 'moderate rain showers',
82: 'violent rain showers',
85: 'slight snow showers',
86: 'heavy snow showers',
95: 'thunderstorm',
96: 'thunderstorm with slight hail',
99: 'thunderstorm with heavy hail'
}
def status_handler(mode, status, ip):
# reports wifi connection status
print(mode, status, ip)
print('Connecting to wifi...')
# flash while connecting
for i in range(NUM_LEDS):
led_strip.set_rgb(i, 255, 255, 255)
time.sleep(0.02)
for i in range(NUM_LEDS):
led_strip.set_rgb(i, 0, 0, 0)
if status is not None:
if status:
print('Connection successful!')
else:
print('Connection failed!')
# light up red if connection fails
for i in range(NUM_LEDS):
led_strip.set_rgb(i, 255, 0, 0)
2022-10-05 11:17:00 +00:00
2022-10-04 18:17:09 +00:00
def get_data():
global weathercode
print(f"Requesting URL: {URL}")
2022-10-05 11:17:00 +00:00
r = urequests.get(URL)
# open the json data
j = r.json()
2022-10-04 18:17:09 +00:00
print("Data obtained!")
2022-10-05 11:17:00 +00:00
r.close()
2022-10-04 18:17:09 +00:00
# parse relevant data from JSON
2022-10-05 11:17:00 +00:00
current = j["current_weather"]
2022-10-04 18:17:09 +00:00
temperature = current["temperature"]
weathercode = current["weathercode"]
datetime_arr = current["time"].split("T")
2022-10-05 11:17:00 +00:00
2022-10-10 14:17:25 +00:00
print(f"""Temperature = {temperature}°C
Conditions = {WEATHERCODES[weathercode]}
Last Open-Meteo update: {datetime_arr[0]}, {datetime_arr[1]}
2022-10-04 18:17:09 +00:00
""")
2022-10-18 14:53:20 +00:00
2022-10-18 14:17:10 +00:00
# flash the onboard LED after getting data
pico_led.value(True)
time.sleep(0.2)
pico_led.value(False)
2022-10-04 18:17:09 +00:00
# the rest of our functions are for animations!
def display_current():
# paint our current LED colours to the strip
for i in range(NUM_LEDS):
led_strip.set_rgb(i, current_leds[i][0], current_leds[i][1], current_leds[i][2])
2022-10-05 11:17:00 +00:00
2022-10-04 18:17:09 +00:00
def move_to_target():
2022-10-05 11:17:00 +00:00
# nudge our current colours closer to the target colours
2022-10-04 18:17:09 +00:00
for i in range(NUM_LEDS):
2022-10-05 11:17:00 +00:00
for c in range(3): # 3 times, for R, G & B channels
2022-10-04 18:17:09 +00:00
if current_leds[i][c] < target_leds[i][c]:
2022-10-05 11:17:00 +00:00
current_leds[i][c] = min(current_leds[i][c] + ANIMATION_SPEED, target_leds[i][c]) # increase current, up to a maximum of target
2022-10-04 18:17:09 +00:00
elif current_leds[i][c] > target_leds[i][c]:
2022-10-05 11:17:00 +00:00
current_leds[i][c] = max(current_leds[i][c] - ANIMATION_SPEED, target_leds[i][c]) # reduce current, down to a minimum of target
2022-10-04 18:17:09 +00:00
def clear():
2022-10-10 14:17:25 +00:00
if weathercode == 0: # clear
# nice sunny yellow
for i in range(NUM_LEDS):
target_leds[i] = [randrange(220, 260), randrange(220, 260), randrange(60, 100)]
if weathercode == 1: # mostly clear
# sky blues
for i in range(NUM_LEDS):
target_leds[i] = [randrange(0, 40), randrange(150, 190), randrange(180, 220)]
2022-10-05 11:17:00 +00:00
2022-10-04 18:17:09 +00:00
def clouds():
# base colours:
2022-10-05 11:17:00 +00:00
if weathercode == 2:
2022-10-04 18:17:09 +00:00
cloud_colour = [165, 168, 138] # partly cloudy
2022-10-05 11:17:00 +00:00
if weathercode == 3:
2022-10-04 18:17:09 +00:00
cloud_colour = [93, 94, 83] # cloudy
2022-10-05 11:17:00 +00:00
if weathercode in (45, 48):
2022-10-04 18:17:09 +00:00
cloud_colour = [186, 185, 182] # foggy
# add highlights and lowlights
for i in range(NUM_LEDS):
if uniform(0, 1) < 0.001: # highlight
2022-10-05 11:20:20 +00:00
target_leds[i] = [x + 20 for x in cloud_colour]
2022-10-04 18:17:09 +00:00
elif uniform(0, 1) < 0.001: # lowlight
2022-10-05 11:20:20 +00:00
target_leds[i] = [x - 20 for x in cloud_colour]
2022-10-04 18:17:09 +00:00
elif uniform(0, 1) < 0.005: # normal
target_leds[i] = cloud_colour
2022-10-05 11:17:00 +00:00
2022-10-04 18:17:09 +00:00
def storm():
# heavy rain, with lightning!
raindrop_chance = 0.01
2022-10-05 11:17:00 +00:00
2022-10-04 18:17:09 +00:00
for i in range(NUM_LEDS):
if raindrop_chance > uniform(0, 1):
# paint a raindrop (use current rather than target, for an abrupt change to the drop colour)
current_leds[i] = [randrange(0, 50), randrange(20, 100), randrange(50, 255)]
else:
# paint backdrop
target_leds[i] = [0, 15, 60]
2022-10-05 11:17:00 +00:00
2022-10-04 18:17:09 +00:00
lightning_chance = 0.001
if lightning_chance > uniform(0, 1):
for i in range(NUM_LEDS):
current_leds[i] = [255, 255, 255]
2022-10-05 11:17:00 +00:00
2022-10-04 18:17:09 +00:00
def rain():
# splodgy blues
# first, work out how many raindrops:
if weathercode in (51, 56, 61, 66, 80): # light rain
raindrop_chance = 0.001
2022-10-05 11:17:00 +00:00
elif weathercode in (53, 63, 81): # moderate rain
2022-10-04 18:17:09 +00:00
raindrop_chance = 0.005
2022-10-05 11:17:00 +00:00
else:
# heavy rain
2022-10-04 18:17:09 +00:00
raindrop_chance = 0.01
2022-10-05 11:17:00 +00:00
2022-10-04 18:17:09 +00:00
for i in range(NUM_LEDS):
2022-10-05 11:17:00 +00:00
if raindrop_chance > uniform(0, 1):
2022-10-04 18:17:09 +00:00
# paint a raindrop (use current rather than target, for an abrupt change to the drop colour)
current_leds[i] = [randrange(0, 50), randrange(20, 100), randrange(50, 255)]
else:
# paint backdrop
target_leds[i] = [0, 15, 60]
2022-10-05 11:17:00 +00:00
2022-10-04 18:17:09 +00:00
def snow():
# splodgy whites
# first, work out how many snowflakes:
if weathercode in (71, 85): # light snow
snowflake_chance = 0.001
2022-10-05 11:17:00 +00:00
elif weathercode in (73, 77): # moderate snow
snowflake_chance = 0.005
else:
# heavy snow
2022-10-04 18:17:09 +00:00
snowflake_chance = 0.01
2022-10-05 11:17:00 +00:00
2022-10-04 18:17:09 +00:00
for i in range(NUM_LEDS):
if snowflake_chance > uniform(0, 1):
# paint a snowflake (use current rather than target, for an abrupt change to the drop colour)
current_leds[i] = [227, 227, 227]
else:
# paint backdrop
target_leds[i] = [54, 54, 54]
2022-10-05 11:17:00 +00:00
2022-10-04 18:17:09 +00:00
# some variables we'll use for animations
2022-10-10 14:17:25 +00:00
ANIMATION_SPEED = 1 # higher number gets from current to target colour faster
2022-10-04 18:17:09 +00:00
2022-10-05 11:17:00 +00:00
# Create an list of [r, g, b] values that will hold current LED colours, for display
current_leds = [[0] * 3 for i in range(NUM_LEDS)]
# Create an list of [r, g, b] values that will hold target LED colours, to move towards
target_leds = [[0] * 3 for i in range(NUM_LEDS)]
2022-10-04 18:17:09 +00:00
2022-10-18 14:17:10 +00:00
# set up the Pico W's onboard LED
pico_led = Pin('LED', Pin.OUT)
2022-10-04 18:17:09 +00:00
# set up the WS2812 / NeoPixel™ LEDs
2022-10-19 15:31:36 +00:00
led_strip = plasma.WS2812(NUM_LEDS, 0, 0, plasma_stick.DAT, color_order=plasma.COLOR_ORDER_RGB)
2022-10-04 18:17:09 +00:00
# start updating the LED strip
led_strip.start()
# set up wifi
network_manager = NetworkManager(WIFI_CONFIG.COUNTRY, status_handler=status_handler)
uasyncio.get_event_loop().run_until_complete(network_manager.client(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK))
# get the first lot of data
get_data()
# start timer (the timer will update our data every UPDATE_INTERVAL)
timer = Timer(-1)
2022-10-05 11:20:20 +00:00
timer.init(period=UPDATE_INTERVAL * 1000, mode=Timer.PERIODIC, callback=lambda t: get_data())
2022-10-04 18:17:09 +00:00
while True:
# do some fancy stuff with the LEDs based on the weather code
2022-10-05 11:17:00 +00:00
if 0 <= weathercode <= 1:
2022-10-04 18:17:09 +00:00
clear()
2022-10-05 11:17:00 +00:00
elif 2 <= weathercode <= 48:
2022-10-04 18:17:09 +00:00
clouds()
2022-10-05 11:17:00 +00:00
elif 51 <= weathercode <= 67 or 80 <= weathercode <= 82:
2022-10-04 18:17:09 +00:00
rain()
elif 71 <= weathercode <= 77 or 85 <= weathercode <= 86:
snow()
elif 95 <= weathercode <= 99:
storm()
else:
print("Unknown weather code :(")
2022-10-05 11:17:00 +00:00
2022-10-04 18:17:09 +00:00
move_to_target() # nudge our current colours closer to the target colours
display_current() # display current colours to strip