/ CircuitPython_Star_Gazer / code.py
code.py
1 # SPDX-FileCopyrightText: 2019 Limor Fried for Adafruit Industries 2 # 3 # SPDX-License-Identifier: MIT 4 5 """ 6 This example will access an API, grab a number like hackaday skulls, github 7 stars, price of bitcoin, twitter followers... if you can find something that 8 spits out JSON data, we can display it! 9 """ 10 import gc 11 import time 12 import board 13 import busio 14 from digitalio import DigitalInOut, Direction 15 from Adafruit_CircuitPython_ESP_ATcontrol import adafruit_espatcontrol 16 from adafruit_ht16k33 import segments 17 import neopixel 18 import ujson 19 20 # Get wifi details and more from a settings.py file 21 try: 22 from settings import settings 23 except ImportError: 24 print("WiFi settings are kept in settings.py, please add them there!") 25 raise 26 27 # CONFIGURATION 28 PLAY_SOUND_ON_CHANGE = True 29 NEOPIXELS_ON_CHANGE = False 30 TIME_BETWEEN_QUERY = 0 # in seconds 31 32 # Some data sources and JSON locations to try out 33 34 # Github stars! You can query 1ce a minute without an API key token 35 DATA_SOURCE = "https://api.github.com/repos/adafruit/circuitpython" 36 if 'github_token' in settings: 37 DATA_SOURCE += "?access_token="+settings['github_token'] 38 DATA_LOCATION = ["stargazers_count"] 39 40 41 42 uart = busio.UART(board.TX, board.RX, timeout=0.1) 43 resetpin = DigitalInOut(board.D5) 44 rtspin = DigitalInOut(board.D9) 45 46 # Create the connection to the co-processor and reset 47 esp = adafruit_espatcontrol.ESP_ATcontrol(uart, 115200, run_baudrate=115200, 48 reset_pin=resetpin, 49 rts_pin=rtspin, debug=True) 50 esp.hard_reset() 51 52 # Create the I2C interface. 53 i2c = busio.I2C(board.SCL, board.SDA) 54 # Attach a 7 segment display and display -'s so we know its not live yet 55 display = segments.Seg7x4(i2c) 56 display.print('----') 57 58 powerpin = DigitalInOut(board.D10) 59 powerpin.direction = Direction.OUTPUT 60 powerpin.value = True 61 starpin = DigitalInOut(board.D11) 62 starpin.direction = Direction.OUTPUT 63 starpin.value = False 64 65 status = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) 66 67 # neopixels 68 if NEOPIXELS_ON_CHANGE: 69 pixels = neopixel.NeoPixel(board.A1, 16, brightness=0.4, pixel_order=(1, 0, 2, 3)) 70 pixels.fill(0) 71 72 # music! 73 if PLAY_SOUND_ON_CHANGE: 74 import audioio 75 import audiocore 76 wave_file = open("coin.wav", "rb") 77 wave = audiocore.WaveFile(wave_file) 78 79 # we'll save the value in question 80 last_value = value = 0 81 the_time = None 82 times = 0 83 84 def chime_light(): 85 """Light up LEDs and play a tune""" 86 if NEOPIXELS_ON_CHANGE: 87 for i in range(0, 100, 10): 88 pixels.fill((i, i, i)) 89 starpin.value = True 90 91 if PLAY_SOUND_ON_CHANGE: 92 with audioio.AudioOut(board.A0) as audio: 93 audio.play(wave) 94 while audio.playing: 95 pass 96 starpin.value = False 97 98 if NEOPIXELS_ON_CHANGE: 99 for i in range(100, 0, -10): 100 pixels.fill((i, i, i)) 101 pixels.fill(0) 102 103 def get_value(response, location): 104 """Extract a value from a json object, based on the path in 'location'""" 105 try: 106 print("Parsing JSON response...", end='') 107 json = ujson.loads(response) 108 print("parsed OK!") 109 for x in location: 110 json = json[x] 111 return json 112 except ValueError: 113 print("Failed to parse json, retrying") 114 return None 115 116 while True: 117 try: 118 status[0] = (0,0,100) 119 while not esp.is_connected: 120 # settings dictionary must contain 'ssid' and 'password' at a minimum 121 status[0] = (100, 0, 0) # red = not connected 122 esp.connect(settings) 123 # great, lets get the data 124 # get the time 125 #the_time = esp.sntp_time 126 127 print("Retrieving data source...", end='') 128 status[0] = (100, 100, 0) # yellow = fetching data 129 header, body = esp.request_url(DATA_SOURCE) 130 status[0] = (0, 0, 100) # green = got data 131 print("Reply is OK!") 132 except (RuntimeError, adafruit_espatcontrol.OKError) as e: 133 print("Failed to get data, retrying\n", e) 134 continue 135 #print('-'*40, "Size: ", len(body)) 136 #print(str(body, 'utf-8')) 137 #print('-'*40) 138 value = get_value(body, DATA_LOCATION) 139 if not value: 140 continue 141 print(times, the_time, "value:", value) 142 display.print(int(value)) 143 status[0] = (0, 0, 0) # off = ready for next 144 if last_value < value: 145 chime_light() # animate the neopixels 146 last_value = value 147 times += 1 148 # normally we wouldn't have to do this, but we get bad fragments 149 header = body = None 150 gc.collect() 151 print(gc.mem_free()) # pylint: disable=no-member 152 time.sleep(TIME_BETWEEN_QUERY)