pimoroni-pico/micropython/examples/gfx_pack/sunrise.py

281 lines
7.5 KiB
Python

'''
sunrise.py
This example is for the Pico W with GFX Pack.
This displays information from the Sunrise Sunset API:
Find out more here - https://sunrise-sunset.org/api
Also shows how to use a 16x16 animated sprite.
'''
import WIFI_CONFIG
import time
from math import radians, sin, cos
from random import randint
from gfx_pack import GfxPack
from network_manager import NetworkManager
import ntptime
import urequests
import uasyncio
import machine
# Helper class so that the different formats of time can be converted into one comparable format
# Makes up for the lack of a datetime module in MicroPython
class TimeObj:
def __init__(self):
self.secs = 0
self.mins = 0
self.hours = 0
self.PM = False
# Returns time variables as a tuple (h, m, s)
def get_time(self):
pm_hrs = 0
if self.PM:
pm_hrs = 12
return (self.hours + pm_hrs, self.mins, self.secs)
# Returns time variables as a single string
def get_str(self):
h, m, s = self.get_time()
return "{0:02d}:{1:02d}:{2:02d}".format(h, m, s)
# Set time variables from the sunrise-sunset API
def parse_api(self, apiStr):
strsplit = apiStr.split()
if strsplit[1] == 'PM':
self.PM = True
timesplit = strsplit[0].split(':')
self.hours = int(timesplit[0])
self.mins = int(timesplit[1])
self.secs = int(timesplit[2])
# Set time variables form
def parse_localtime(self, localtpl):
yr, mo, dy, self.hours, self.mins, self.secs, un1, un2 = localtpl
# Returns number of seconds since midnight
def get_total_secs(self):
seconds = 0
if self.PM:
seconds += 43200 # seconds in the first 12 hours
seconds += (self.hours * 3600)
seconds += (self.mins * 60)
seconds += self.secs
return seconds
# Instances of TimeObj helper class defined above
sunrise_obj = TimeObj()
sunset_obj = TimeObj()
currenttime = TimeObj()
# Coordinates for Sheffield-on-Sea, UK
lng = -1.4659
lat = 53.3829
# Coordinates for LA, USA
# lng = -118.2437
# lat = 34.0522
URL = 'https://api.sunrise-sunset.org/json?lat={0}&lng={1}&date=today'.format(lat, lng)
rtc = machine.RTC()
gp = GfxPack()
display = gp.display
sys_status = "Starting"
WIDTH, HEIGHT = display.get_bounds()
display.set_backlight(1) # turn on the white component of the backlight
# Generate hill heights
hills1 = [randint(10, 18), randint(10, 18), randint(10, 18), randint(10, 18), randint(10, 18)]
hills2 = [randint(10, 18), randint(10, 18)]
hills3 = [randint(10, 18), randint(10, 18)]
# Sprite information for sun icon
sun = [
[
0b0000000100000000,
0b0000000000000000,
0b0010011111001000,
0b0000100000100000,
0b0001000000010000,
0b0010000000001000,
0b0010010001001000,
0b0010000100001000,
0b0010000000001000,
0b0010000000001000,
0b0001001110010000,
0b0000100000100000,
0b0010011111001000,
0b0000000000000000,
0b0000000100000000,
0b0000000000000000
],
[
0b0000000000000000,
0b0100000000000100,
0b0000011111000000,
0b0000100000100000,
0b0001000000010000,
0b0010010001001000,
0b0010010001001000,
0b1010000100001010,
0b0010000000001000,
0b0010010001001000,
0b0001001110010000,
0b0000100000100000,
0b0000011111000000,
0b0100000000000100,
0b0000000000000000,
0b0000000000000000
],
[
0b0000000100000000,
0b0100000000000100,
0b0010011111001000,
0b0000100000100000,
0b0001000000010000,
0b0010010001001000,
0b0010010001001000,
0b1010000100001010,
0b0010000000001000,
0b0010010001001000,
0b0001001110010000,
0b0000100000100000,
0b0010011111001000,
0b0100000000000100,
0b0000000100000000,
0b0000000000000000
]
]
def get_data():
# open the json file
print(f'Requesting URL: {URL}')
r = urequests.get(URL)
# open the json data
j = r.json()
print('Data obtained!')
r.close()
return j
def get_sunrise():
sun_json = get_data()
sunrise = sun_json['results']['sunrise']
sunrise_obj.parse_api(sunrise)
sunset = sun_json['results']['sunset']
sunset_obj.parse_api(sunset)
def display_status():
global sys_status
display.set_pen(0)
display.clear()
display.set_pen(15)
display.text(sys_status, 0, 0, WIDTH, 1)
display.update()
def status_handler(mode, status, ip):
# reports wifi connection status
global sys_status
print(mode, status, ip)
sys_status = 'Mode: {0} Connected: {1} IP: {2}'.format(mode, status, ip)
display_status()
display.update()
print('Connecting to wifi...')
if status is not None:
if status:
print('Wifi connection successful!')
else:
print('Wifi connection failed!')
def calc_circle_points(ori_x, ori_y, r, deg):
rads = radians(deg - 180)
x = int(cos(rads) * r) + ori_x
y = int(sin(rads) * r) + ori_y
return x, y
def to_seconds(hour, mins, secs, isPM=False):
seconds = 0
if isPM:
seconds += 43200 # Seconds in the first 12 hours
seconds += (hour * 3600)
seconds += (mins * 60)
seconds += secs
return seconds
def draw_hills():
display.set_pen(12)
for x in range(5):
display.circle(30 * x, 64, hills1[x])
display.set_pen(9)
for x in range(2):
display.circle(60 * x + 15, 64, hills2[x])
display.set_pen(3)
for x in range(2):
display.circle(60 * x + 30 + 15, 64, hills3[x])
def draw_text():
display.set_pen(15)
display.text("Sun Rise-Set API demo", 0, 0, WIDTH, 1)
display.text("Sunrise: {0}".format(sunrise_obj.get_str()), 0, 8, WIDTH, 1)
display.text("Sunset: {0}".format(sunset_obj.get_str()), 0, 16, WIDTH, 1)
display.text("{0}".format(currenttime.get_str()), 0, 24, WIDTH, 1)
def draw_sun(sunrise, sunset, time, cycle):
sunlight_range = sunset - sunrise
angle = int((180 / sunlight_range) * (time - sunrise)) % 360
pos_x, pos_y = calc_circle_points(64 - 16, 54, 50, angle)
display.set_pen(15)
if angle > 180:
gp.set_backlight(0, 0, 255)
elif angle < 90:
r = 255
g = ((angle / 100) * 90)
b = 0
gp.set_backlight(r, g, b)
elif angle > 90:
r = 255
g = 100 - (((angle - 90) / 100) * 90)
b = 0
gp.set_backlight(r, g, b)
for y in range(16):
for x in range(16):
if sun[cycle][y] & (1 << x):
display.pixel(x + pos_x, int((y + pos_y)))
try:
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))
except Exception as e:
print(f'Wifi connection failed! {e}')
get_sunrise()
ntptime.settime()
currenttime.parse_localtime(time.localtime())
count = 0 # Counter for animation
display.set_backlight(0.5) # Dim white backlight to help colours show
while True:
# Update current time class instance from RTC
currenttime.parse_localtime(time.localtime())
count += 1
display.set_pen(0)
display.clear()
# Uncomment for the animation
# draw_sun(0, 180, count % 180, count % 3)
draw_sun(sunrise_obj.get_total_secs(), sunset_obj.get_total_secs(), currenttime.get_total_secs(), count % 3)
draw_hills()
draw_text()
display.update()
time.sleep(0.2)