/ PyPortal_ISS_Tracker / code.py
code.py
1 # SPDX-FileCopyrightText: 2019 Carter Nelson for Adafruit Industries 2 # 3 # SPDX-License-Identifier: MIT 4 5 import time 6 import math 7 import board 8 import displayio 9 from terminalio import FONT 10 from adafruit_pyportal import PyPortal 11 from adafruit_display_shapes.circle import Circle 12 from adafruit_display_text.label import Label 13 14 #--| USER CONFIG |-------------------------- 15 MARK_SIZE = 10 # marker radius 16 MARK_COLOR = 0xFF3030 # marker color 17 MARK_THICKNESS = 5 # marker thickness 18 TRAIL_LENGTH = 200 # trail length 19 TRAIL_COLOR = 0xFFFF00 # trail color 20 DATE_COLOR = 0x111111 # date color 21 TIME_COLOR = 0x111111 # time color 22 LAT_MAX = 80 # latitude (deg) of map top/bottom edge 23 UPDATE_RATE = 10 # update rate in seconds 24 #------------------------------------------- 25 26 DATA_SOURCE = "http://api.open-notify.org/iss-now.json" 27 DATA_LOCATION = ["iss_position"] 28 29 WIDTH = board.DISPLAY.width 30 HEIGHT = board.DISPLAY.height 31 32 # determine the current working directory needed so we know where to find files 33 cwd = ("/"+__file__).rsplit('/', 1)[0] 34 pyportal = PyPortal(url=DATA_SOURCE, 35 json_path=DATA_LOCATION, 36 status_neopixel=board.NEOPIXEL, 37 text_font=None, 38 default_bg=cwd+"/map.bmp") 39 40 # Connect to the internet and get local time 41 pyportal.get_local_time() 42 43 # Date and time label 44 date_label = Label(FONT, text="0000-00-00", color=DATE_COLOR, x=165, y=223) 45 time_label = Label(FONT, text="00:00:00", color=TIME_COLOR, x=240, y=223) 46 pyportal.splash.append(date_label) 47 pyportal.splash.append(time_label) 48 49 # ISS trail 50 trail_bitmap = displayio.Bitmap(3, 3, 1) 51 trail_palette = displayio.Palette(1) 52 trail_palette[0] = TRAIL_COLOR 53 trail = displayio.Group() 54 pyportal.splash.append(trail) 55 56 # ISS location marker 57 marker = displayio.Group() 58 for r in range(MARK_SIZE - MARK_THICKNESS, MARK_SIZE): 59 marker.append(Circle(0, 0, r, outline=MARK_COLOR)) 60 pyportal.splash.append(marker) 61 62 def get_location(width=WIDTH, height=HEIGHT): 63 """Fetch current lat/lon, convert to (x, y) tuple scaled to width/height.""" 64 65 # Get location 66 try: 67 location = pyportal.fetch() 68 except RuntimeError: 69 return None, None 70 71 # Compute (x, y) coordinates 72 lat = float(location["latitude"]) # degrees, -90 to 90 73 lon = float(location["longitude"]) # degrees, -180 to 180 74 75 # Scale latitude for cropped map 76 lat *= 90 / LAT_MAX 77 78 # Mercator projection math 79 # https://stackoverflow.com/a/14457180 80 # https://en.wikipedia.org/wiki/Mercator_projection#Alternative_expressions 81 x = lon + 180 82 x = width * x / 360 83 84 y = math.radians(lat) 85 y = math.tan(math.pi / 4 + y / 2) 86 y = math.log(y) 87 y = (width * y) / (2 * math.pi) 88 y = height / 2 - y 89 90 return int(x), int(y) 91 92 def update_display(current_time, update_iss=False): 93 """Update the display with current info.""" 94 95 # ISS location 96 if update_iss: 97 x, y = get_location() 98 if x and y: 99 marker.x = x 100 marker.y = y 101 if len(trail) >= TRAIL_LENGTH: 102 trail.pop(0) 103 trail.append(displayio.TileGrid(trail_bitmap, 104 pixel_shader=trail_palette, 105 x = x - 1, 106 y = y - 1) ) 107 108 109 # Date and time 110 date_label.text = "{:04}-{:02}-{:02}".format(current_time.tm_year, 111 current_time.tm_mon, 112 current_time.tm_mday) 113 time_label.text = "{:02}:{:02}:{:02}".format(current_time.tm_hour, 114 current_time.tm_min, 115 current_time.tm_sec) 116 117 try: 118 board.DISPLAY.refresh(target_frames_per_second=60) 119 except AttributeError: 120 board.DISPLAY.refresh_soon() 121 122 123 # Initial refresh 124 update_display(time.localtime(), True) 125 last_update = time.monotonic() 126 127 # Run forever 128 while True: 129 now = time.monotonic() 130 new_position = False 131 if now - last_update > UPDATE_RATE: 132 new_position = True 133 last_update = now 134 update_display(time.localtime(), new_position) 135 time.sleep(0.5)