/ CircuitPython_WeatherCloud / code.py
code.py
1 # SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries 2 # 3 # SPDX-License-Identifier: MIT 4 5 import time 6 import random 7 import audioio 8 import audiocore 9 import board 10 import busio 11 from digitalio import DigitalInOut 12 import digitalio 13 import neopixel 14 from adafruit_esp32spi import adafruit_esp32spi 15 from adafruit_esp32spi import adafruit_esp32spi_wifimanager 16 import adafruit_fancyled.adafruit_fancyled as fancy 17 18 print("ESP32 Open Weather API demo") 19 20 button = digitalio.DigitalInOut(board.A1) 21 button.switch_to_input(pull=digitalio.Pull.UP) 22 23 wave_file = open("sound/Rain.wav", "rb") 24 wave = audiocore.WaveFile(wave_file) 25 audio = audioio.AudioOut(board.A0) 26 27 28 # Get wifi details and more from a secrets.py file 29 try: 30 from secrets import secrets 31 except ImportError: 32 print("WiFi secrets are kept in secrets.py, please add them there!") 33 raise 34 35 # Use cityname, country code where countrycode is ISO3166 format. 36 # E.g. "New York, US" or "London, GB" 37 LOCATION = secrets['timezone'] 38 39 # Set up where we'll be fetching data from 40 DATA_SOURCE = "http://api.openweathermap.org/data/2.5/weather?q="+secrets['timezone'] 41 DATA_SOURCE += "&appid="+secrets['openweather_token'] 42 43 # If you are using a board with pre-defined ESP32 Pins: 44 esp32_cs = DigitalInOut(board.ESP_CS) 45 esp32_ready = DigitalInOut(board.ESP_BUSY) 46 esp32_reset = DigitalInOut(board.ESP_RESET) 47 48 spi = busio.SPI(board.SCK, board.MOSI, board.MISO) 49 esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) 50 status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) # Uncomment for Most Boards 51 wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) 52 pixels = neopixel.NeoPixel(board.D2, 150, brightness=1.0, auto_write=False) 53 pixels.fill(0x050505) 54 pixels.show() 55 56 # clouds palette 57 cloudy_palette = [fancy.CRGB(1.0, 1.0, 1.0), # White 58 fancy.CRGB(0.5, 0.5, 0.5), # gray 59 fancy.CRGB(0.5, 0.5, 1.0)] # blue-gray 60 # sunny palette 61 sunny_palette = [fancy.CRGB(1.0, 1.0, 1.0), # White 62 fancy.CRGB(1.0, 1.0, 0.0), # Yellow 63 fancy.CRGB(1.0, 0.5, 0.0), ] # Orange 64 # thunderstorm palette 65 thunder_palette = [fancy.CRGB(0.0, 0.0, 1.0), # blue 66 fancy.CRGB(0.5, 0.5, 0.5), # gray 67 fancy.CRGB(0.5, 0.5, 1.0)] # blue-gray 68 last_thunder_bolt = None 69 70 palette = None # current palette 71 pal_offset = 0 # Positional offset into color palette to get it to 'spin' 72 levels = (0.25, 0.3, 0.15) # Color balance / brightness for gamma function 73 raining = False 74 snowing = False 75 thundering = False 76 has_sound = False 77 78 weather_refresh = None 79 weather_type = None 80 button_mode = 4 81 button_select = False 82 83 cloud_on = True 84 85 while True: 86 if not button.value: 87 button_mode = button_mode + 1 88 print("Button Pressed") 89 if button_mode > 4: 90 button_mode = 0 91 print("Mode is:", button_mode) 92 pressed_time = time.monotonic() 93 button_select = True 94 weather_refresh = None 95 while not button.value: # Debounce 96 audio.stop() 97 if (time.monotonic() - pressed_time) > 4: 98 print("Turning OFF") 99 cloud_on = False 100 pixels.fill(0x000000) # bright white! 101 pixels.show() 102 while not cloud_on: 103 while not button.value: # Debounce 104 pass 105 if not button.value: 106 pressed_time = time.monotonic() 107 print("Button Pressed") 108 cloud_on = True 109 button_select = False 110 weather_refresh = None 111 112 if button_mode == 0: 113 weather_type = 'Sunny' 114 if button_mode == 1: 115 weather_type = 'Clouds' 116 if button_mode == 2: 117 weather_type = 'Rain' 118 if button_mode == 3: 119 weather_type = 'Thunderstorm' 120 if button_mode == 4: 121 weather_type = 'Snow' 122 123 # only query the weather every 10 minutes (and on first run) 124 if (not weather_refresh) or (time.monotonic() - weather_refresh) > 600: 125 try: 126 if not button_select: 127 response = wifi.get(DATA_SOURCE).json() 128 print("Response is", response) 129 weather_type = response['weather'][0]['main'] 130 if weather_type == 'Clear': 131 weather_type = 'Sunny' 132 print(weather_type) # See https://openweathermap.org/weather-conditions 133 # default to no rain or thunder 134 raining = snowing = thundering = has_sound = False 135 if weather_type == 'Sunny': 136 palette = sunny_palette 137 wave_file = open("sound/Clear.wav", "rb") 138 wave = audiocore.WaveFile(wave_file) 139 has_sound = True 140 if weather_type == 'Clouds': 141 palette = cloudy_palette 142 wave_file = open("sound/Clouds.wav", "rb") 143 wave = audiocore.WaveFile(wave_file) 144 has_sound = True 145 if weather_type == 'Rain': 146 palette = cloudy_palette 147 wave_file = open("sound/Rain.wav", "rb") 148 wave = audiocore.WaveFile(wave_file) 149 raining = True 150 has_sound = True 151 if weather_type == 'Thunderstorm': 152 palette = thunder_palette 153 raining = thundering = True 154 has_sound = True 155 # pick next thunderbolt time now 156 next_bolt_time = time.monotonic() + random.randint(1, 5) 157 if weather_type == 'Snow': 158 palette = cloudy_palette 159 wave_file = open("sound/Snow.wav", "rb") 160 wave = audiocore.WaveFile(wave_file) 161 snowing = True 162 has_sound = True 163 weather_refresh = time.monotonic() 164 except RuntimeError as e: 165 print("Some error occured, retrying! -", e) 166 time.sleep(5) 167 continue 168 169 if not audio.playing and has_sound: 170 if not thundering: 171 audio.play(wave) 172 173 if palette: 174 for i in range(len(pixels)): 175 color = fancy.palette_lookup(palette, pal_offset + i / len(pixels)) 176 color = fancy.gamma_adjust(color, brightness=levels) 177 pixels[i] = color.pack() 178 pixels.show() 179 pal_offset += 0.01 # Bigger number = faster spin 180 181 if raining: 182 # don't have a droplet every time 183 for i in range(random.randint(1, 5)): # up to 3 times... 184 pixels[random.randint(0, len(pixels)-1)] = 0x0000FF # make a random pixel Blue 185 pixels.show() 186 187 if snowing: 188 # don't have a droplet every time 189 for i in range(random.randint(1, 5)): # up to 3 times... 190 pixels[random.randint(0, len(pixels)-1)] = 0xFFFFFF # make a random pixel white 191 pixels.show() 192 193 # if its time for a thunderbolt 194 if thundering and (time.monotonic() > next_bolt_time): 195 print("Ka Bam!") 196 # fill pixels white, delay, a few times 197 for i in range(random.randint(1, 3)): # up to 3 times... 198 pixels.fill(0xFFFFFF) # bright white! 199 pixels.show() 200 time.sleep(random.uniform(0.01, 0.2)) # pause 201 pixels.fill(0x0F0F0F) # gray 202 pixels.show() 203 time.sleep(random.uniform(0.01, 0.3)) # pause 204 # pick next thunderbolt time now 205 Thunder = random.randint(0, 2) 206 if Thunder == 0: 207 wave_file = open("sound/Thunderstorm0.wav", "rb") 208 elif Thunder == 1: 209 wave_file = open("sound/Thunderstorm1.wav", "rb") 210 elif Thunder == 2: 211 wave_file = open("sound/Thunderstorm2.wav", "rb") 212 wave = audiocore.WaveFile(wave_file) 213 audio.play(wave) 214 next_bolt_time = time.monotonic() + random.randint(5, 15) # between 5 and 15 s