diff --git a/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py new file mode 100755 index 0000000..3476d8d --- /dev/null +++ b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py @@ -0,0 +1,145 @@ +# The MIT License (MIT) +# +# Copyright (c) 2019 Melissa LeBlanc-Williams for Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +""" +`adafruit_esp32spi_wifimanager` +================================================================================ + +WiFi Manager for making ESP32 SPI as WiFi much easier + +* Author(s): Melissa LeBlanc-Williams, ladyada +""" + +# pylint: disable=no-name-in-module + +import neopixel +import adafruit_esp32spi +import adafruit_esp32spi.adafruit_esp32spi_requests as requests + +class ESPSPI_WiFiManager: + """ + A class to help manage the Wifi connection + """ + def __init__(self, esp, settings, status_neopixel=None): + """ + :param ESP_SPIcontrol esp: The ESP object we are using + :param dict settings: The WiFi and Adafruit IO Settings (See examples) + :param status_neopixel: (Pptional) The neopixel pin - Usually board.NEOPIXEL (default=None) + :type status_neopixel: Pin + """ + # Read the settings + self._esp = esp + self.debug = False + self.ssid = settings['ssid'] + self.password = settings['password'] + requests.set_interface(self._esp) + if status_neopixel: + self.neopix = neopixel.NeoPixel(status_neopixel, 1, brightness=0.2) + else: + self.neopix = None + self.neo_status(0) + + def connect(self): + """ + Attempt to connect to WiFi using the current settings + """ + if self.debug: + if self._esp.status == adafruit_esp32spi.WL_IDLE_STATUS: + print("ESP32 found and in idle mode") + print("Firmware vers.", self._esp.firmware_version) + print("MAC addr:", [hex(i) for i in self._esp.MAC_address]) + for access_pt in self._esp.scan_networks(): + print("\t%s\t\tRSSI: %d" % (str(access_pt['ssid'], 'utf-8'), access_pt['rssi'])) + while not self._esp.is_connected: + try: + if self.debug: + print("Connecting to AP...") + self.neo_status((100, 0, 0)) + self._esp.connect_AP(bytes(self.ssid, 'utf-8'), bytes(self.password, 'utf-8')) + self.neo_status((0, 100, 0)) + except (ValueError, RuntimeError) as error: + print("Failed to connect, retrying\n", error) + continue + + def get(self, url, **kw): + """ + Pass the Get request to requests and update Status NeoPixel + + :param str url: The URL to retrieve data from + :param dict data: (Optional) Form data to submit + :param dict json: (Optional) JSON data to submit. (Data must be None) + :param dict header: (Optional) Header data to include + :param bool stream: (Optional) Whether to stream the Response + :return: The response from the request + :rtype: Response + """ + if not self._esp.is_connected: + self.connect() + self.neo_status((100, 100, 0)) + return_val = requests.get(url, **kw) + self.neo_status(0) + return return_val + + def post(self, url, **kw): + """ + Pass the Post request to requests and update Status NeoPixel + + :param str url: The URL to post data to + :param dict data: (Optional) Form data to submit + :param dict json: (Optional) JSON data to submit. (Data must be None) + :param dict header: (Optional) Header data to include + :param bool stream: (Optional) Whether to stream the Response + :return: The response from the request + :rtype: Response + """ + if not self._esp.is_connected: + self.connect() + self.neo_status((100, 100, 0)) + return_val = requests.post(url, **kw) + self.neo_status(0) + return return_val + + def ping(self, host, ttl=250): + """ + Pass the Ping request to the ESP32, update Status NeoPixel, return response time + + :param str host: The hostname or IP address to ping + :param int ttl: (Optional) The Time To Live in milliseconds for the packet (default=250) + :return: The response time in milliseconds + :rtype: int + """ + if not self._esp.is_connected: + self.connect() + self.neo_status((100, 100, 0)) + response_time = self._esp.ping(host, ttl=ttl) + self.neo_status(0) + return response_time + + def neo_status(self, value): + """ + Change Status NeoPixel if it was defined + + :param value: The value to set the Board's Status NeoPixel to + :type value: int or 3-value tuple + """ + if self.neopix: + self.neopix.fill(value) diff --git a/docs/examples.rst b/docs/examples.rst index 59373bf..49c52d3 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -6,3 +6,15 @@ Ensure your device works with this simple test. .. literalinclude:: ../examples/esp32spi_simpletest.py :caption: examples/esp32spi_simpletest.py :linenos: + + +Other Examples +--------------- + +.. literalinclude:: ../examples/esp32spi_cheerlights.py + :caption: examples/esp32spi_cheerlights.py + :linenos: + +.. literalinclude:: ../examples/esp32spi_aio_post.py + :caption: examples/esp32spi_aio_post.py + :linenos: diff --git a/examples/esp32spi_aio_post.py b/examples/esp32spi_aio_post.py index 817ea70..b6d99a9 100644 --- a/examples/esp32spi_aio_post.py +++ b/examples/esp32spi_aio_post.py @@ -1,12 +1,10 @@ - import time import board import busio from digitalio import DigitalInOut from adafruit_esp32spi import adafruit_esp32spi -import adafruit_esp32spi.adafruit_esp32spi_requests as requests - +from adafruit_esp32spi import adafruit_esp32spi_wifimanager print("ESP32 SPI webclient test") @@ -14,47 +12,24 @@ try: from esp32spi_settings import settings except ImportError: - print("WiFi settings are kept in settings.py, please add them there!") + print("WiFi settings are kept in esp32spi_settings.py, please add them there!") raise - esp32_cs = DigitalInOut(board.D9) esp32_ready = DigitalInOut(board.D10) esp32_reset = DigitalInOut(board.D5) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) - -requests.set_interface(esp) - -if esp.status == adafruit_esp32spi.WL_IDLE_STATUS: - print("ESP32 found and in idle mode") -print("Firmware vers.", esp.firmware_version) -print("MAC addr:", [hex(i) for i in esp.MAC_address]) -for ap in esp.scan_networks(): - print("\t%s\t\tRSSI: %d" % (str(ap['ssid'], 'utf-8'), ap['rssi'])) -while not esp.is_connected: - try: - print("Connecting to AP...") - esp.connect_AP(bytes(settings['ssid'],'utf-8'), bytes(settings['password'],'utf-8')) - except (ValueError, RuntimeError) as e: - print("Failed to connect, retrying\n", e) - continue -print("Connected to", str(esp.ssid, 'utf-8'), "\tRSSI:", esp.rssi) -print("My IP address is", esp.pretty_ip(esp.ip_address)) - +wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, settings, board.NEOPIXEL) counter = 0 while True: try: - while not esp.is_connected: - # settings dictionary must contain 'ssid' and 'password' at a minimum - esp.connect_AP(bytes(settings['ssid'],'utf-8'), bytes(settings['password'],'utf-8')) - # great, lets get the data print("Posting data...", end='') - data=counter - feed='test' - payload={'value':data} - response=requests.post( + data = counter + feed = 'test' + payload = {'value':data} + response = wifi.post( "https://io.adafruit.com/api/v2/"+settings['aio_username']+"/feeds/"+feed+"/data", json=payload,headers={bytes("X-AIO-KEY","utf-8"):bytes(settings['aio_key'],"utf-8")}) print(response.json()) diff --git a/examples/esp32spi_cheerlights.py b/examples/esp32spi_cheerlights.py index 7ef9419..d9f7781 100644 --- a/examples/esp32spi_cheerlights.py +++ b/examples/esp32spi_cheerlights.py @@ -4,87 +4,51 @@ from digitalio import DigitalInOut from adafruit_esp32spi import adafruit_esp32spi -import adafruit_esp32spi.adafruit_esp32spi_requests as requests +from adafruit_esp32spi import adafruit_esp32spi_wifimanager import neopixel import adafruit_fancyled.adafruit_fancyled as fancy - - # Get wifi details and more from a settings.py file try: from esp32spi_settings import settings except ImportError: - print("WiFi settings are kept in settings.py, please add them there!") + print("WiFi settings are kept in esp32spi_settings.py, please add them there!") raise - - print("ESP32 SPI webclient test") DATA_SOURCE = "https://api.thingspeak.com/channels/1417/feeds.json?results=1" DATA_LOCATION = ["feeds", 0, "field2"] - esp32_cs = DigitalInOut(board.D9) esp32_ready = DigitalInOut(board.D10) esp32_reset = DigitalInOut(board.D5) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) - -requests.set_interface(esp) - -if esp.status == adafruit_esp32spi.WL_IDLE_STATUS: - print("ESP32 found and in idle mode") -print("Firmware vers.", esp.firmware_version) -print("MAC addr:", [hex(i) for i in esp.MAC_address]) -for ap in esp.scan_networks(): - print("\t%s\t\tRSSI: %d" % (str(ap['ssid'], 'utf-8'), ap['rssi'])) -while not esp.is_connected: - try: - print("Connecting to AP...") - esp.connect_AP(bytes(settings['ssid'],'utf-8'), bytes(settings['password'],'utf-8')) - except (ValueError, RuntimeError) as e: - print("Failed to connect, retrying\n", e) - continue -print("Connected to", str(esp.ssid, 'utf-8'), "\tRSSI:", esp.rssi) -print("My IP address is", esp.pretty_ip(esp.ip_address)) - +wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, settings, board.NEOPIXEL) # neopixels pixels = neopixel.NeoPixel(board.A1, 16, brightness=0.3) pixels.fill(0) -builtin = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.1) -builtin[0] = 0 # we'll save the value in question last_value = value = None -the_time = None -times = 0 - while True: try: - while not esp.is_connected: - builtin[0] = (100, 0, 0) - # settings dictionary must contain 'ssid' and 'password' at a minimum - esp.connect_AP(bytes(settings['ssid'],'utf-8'), bytes(settings['password'],'utf-8')) - builtin[0] = (0, 100, 0) print("Fetching json from", DATA_SOURCE) - builtin[0] = (100, 100, 0) - r = requests.get(DATA_SOURCE) - builtin[0] = (0, 0, 100) - print(r.json()) - value=r.json() - for x in DATA_LOCATION: - value = value[x] + response = wifi.get(DATA_SOURCE) + print(response.json()) + value=response.json() + for key in DATA_LOCATION: + value = value[key] print(value) - r.close() + response.close() except (ValueError, RuntimeError) as e: print("Failed to get data, retrying\n", e) continue - builtin[0] = (100, 100, 100) if not value: continue if last_value != value: @@ -96,6 +60,5 @@ pixels.fill(gamma_corrected) last_value = value - times += 1 - r = None + response = None time.sleep(60)