From b9befbf6d6611016f404717d73381c93a2e7670e Mon Sep 17 00:00:00 2001 From: mscosti Date: Sat, 29 Jun 2019 00:35:17 -0400 Subject: [PATCH 01/17] add access point creation SPI commands and wifimanager helper --- adafruit_esp32spi/adafruit_esp32spi.py | 42 +++++++++++++++++++ .../adafruit_esp32spi_wifimanager.py | 24 ++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/adafruit_esp32spi/adafruit_esp32spi.py b/adafruit_esp32spi/adafruit_esp32spi.py index e5f109a..dff2741 100644 --- a/adafruit_esp32spi/adafruit_esp32spi.py +++ b/adafruit_esp32spi/adafruit_esp32spi.py @@ -54,6 +54,8 @@ # pylint: disable=bad-whitespace _SET_NET_CMD = const(0x10) _SET_PASSPHRASE_CMD = const(0x11) +_SET_AP_NET_CMD = const(0x18) +_SET_AP_PASSPHRASE_CMD = const(0x19) _SET_DEBUG_CMD = const(0x1A) _GET_CONN_STATUS_CMD = const(0x20) @@ -409,6 +411,18 @@ def wifi_set_entenable(self): if resp[0][0] != 1: raise RuntimeError("Failed to enable enterprise mode") + def wifi_set_ap_network(self, ssid, channel): + """TODO Docs""" + resp = self._send_command_get_response(_SET_AP_NET_CMD, [ssid, channel]) + if resp[0][0] != 1: + raise RuntimeError("Failed to setup AP network") + + def wifi_set_ap_passphrase(self, ssid, passphrase, channel): + """TODO Docs""" + resp = self._send_command_get_response(_SET_AP_PASSPHRASE_CMD, [ssid, passphrase, channel]) + if resp[0][0] != 1: + raise RuntimeError("Failed to setup AP network") + @property def ssid(self): """The name of the access point we're connected to""" @@ -443,6 +457,15 @@ def is_connected(self): self.reset() return False + @property + def ap_listening(self): + """Whether the ESP32 is in access point mode and is listening for connections""" + try: + return self.status == WL_AP_LISTENING + except RuntimeError: + self.reset() + return False + def connect(self, secrets): """Connect to an access point using a secrets dictionary that contains a 'ssid' and 'password' entry""" @@ -473,6 +496,25 @@ def connect_AP(self, ssid, password): # pylint: disable=invalid-name raise RuntimeError("No such ssid", ssid) raise RuntimeError("Unknown error 0x%02X" % stat) + def create_AP(self, ssid, password, channel=1): + """Create an access point with the given name and password.""" + if isinstance(ssid, str): + ssid = bytes(ssid, 'utf-8') + if password: + if isinstance(password, str): + password = bytes(password, 'utf-8') + self.wifi_set_ap_passphrase(ssid, password, channel) + else: + self.wifi_set_ap_network(ssid, channel) + for _ in range(10): # retries + stat = self.status + if stat == WL_AP_LISTENING: + return stat + time.sleep(1) + if stat == WL_AP_FAILED: + raise RuntimeError("Failed to create AP", ssid) + raise RuntimeError("Unknown error 0x%02x" % stat) + def pretty_ip(self, ip): # pylint: disable=no-self-use, invalid-name """Converts a bytearray IP address to a dotted-quad string for printing""" return "%d.%d.%d.%d" % (ip[0], ip[1], ip[2], ip[3]) diff --git a/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py index f0acae2..952a9a2 100755 --- a/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py +++ b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py @@ -31,8 +31,9 @@ # pylint: disable=no-name-in-module -from adafruit_esp32spi import adafruit_esp32spi import adafruit_esp32spi.adafruit_esp32spi_requests as requests +from adafruit_esp32spi import adafruit_esp32spi + class ESPSPI_WiFiManager: """ @@ -93,6 +94,27 @@ def connect(self): self.reset() continue + def create_ap(self): + """ + Attempt to initialize in Access Point (AP) mode. + Other WiFi devices will be able to connect to the created Access Point + """ + while not self._esp.ap_listening: + try: + if self.debug: + print("Waiting for AP to be initialized...") + self.pixel_status((100,0,0)) + self._esp.create_AP(bytes.ssid, 'utf-8'), bytes(self.password, 'utf-8') + failure_count = 0 + self.pixel_status((0,100,0)) + except (ValueError, RuntimeError) as error: + print("Failed to create access point\n", error) + failure_count += 1 + if failure_count >= self.attempts: + failure_count = 0 + self.reset() + continue + def get(self, url, **kw): """ Pass the Get request to requests and update status LED From 45cf5c1df7001b63f789ddeaac1a5a1ef139424b Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Fri, 5 Jul 2019 12:54:34 -0400 Subject: [PATCH 02/17] - Can now create AP w/out passphrase - channel needed to be in hex byte format. - Add begining of a server example example program. - TODO: figure out why cannot create AP w/ passphrase --- adafruit_esp32spi/adafruit_esp32spi.py | 9 +++---- .../adafruit_esp32spi_wifimanager.py | 13 ++++++---- examples/esp32spi_server.py | 24 +++++++++++++++++++ 3 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 examples/esp32spi_server.py diff --git a/adafruit_esp32spi/adafruit_esp32spi.py b/adafruit_esp32spi/adafruit_esp32spi.py index dff2741..7f67479 100644 --- a/adafruit_esp32spi/adafruit_esp32spi.py +++ b/adafruit_esp32spi/adafruit_esp32spi.py @@ -416,13 +416,14 @@ def wifi_set_ap_network(self, ssid, channel): resp = self._send_command_get_response(_SET_AP_NET_CMD, [ssid, channel]) if resp[0][0] != 1: raise RuntimeError("Failed to setup AP network") - + def wifi_set_ap_passphrase(self, ssid, passphrase, channel): """TODO Docs""" + """ TODO: Why does this command refuse to work? creating AP w/out password works fine""" resp = self._send_command_get_response(_SET_AP_PASSPHRASE_CMD, [ssid, passphrase, channel]) if resp[0][0] != 1: - raise RuntimeError("Failed to setup AP network") - + raise RuntimeError("Failed to setup AP password") + @property def ssid(self): """The name of the access point we're connected to""" @@ -496,7 +497,7 @@ def connect_AP(self, ssid, password): # pylint: disable=invalid-name raise RuntimeError("No such ssid", ssid) raise RuntimeError("Unknown error 0x%02X" % stat) - def create_AP(self, ssid, password, channel=1): + def create_AP(self, ssid, password, channel=b'\x01'): """Create an access point with the given name and password.""" if isinstance(ssid, str): ssid = bytes(ssid, 'utf-8') diff --git a/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py index 952a9a2..9d7dd3f 100755 --- a/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py +++ b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py @@ -39,7 +39,7 @@ class ESPSPI_WiFiManager: """ A class to help manage the Wifi connection """ - def __init__(self, esp, secrets, status_pixel=None, attempts=2): + def __init__(self, esp, secrets, status_pixel=None, attempts=2, debug=False): """ :param ESP_SPIcontrol esp: The ESP object we are using :param dict secrets: The WiFi and Adafruit IO secrets dict (See examples) @@ -50,9 +50,9 @@ def __init__(self, esp, secrets, status_pixel=None, attempts=2): """ # Read the settings self._esp = esp - self.debug = False + self.debug = debug self.ssid = secrets['ssid'] - self.password = secrets['password'] + self.password = secrets.get('password', None) self.attempts = attempts requests.set_interface(self._esp) self.statuspix = status_pixel @@ -99,12 +99,16 @@ def create_ap(self): Attempt to initialize in Access Point (AP) mode. Other WiFi devices will be able to connect to the created Access Point """ + failure_count = 0 while not self._esp.ap_listening: try: if self.debug: print("Waiting for AP to be initialized...") self.pixel_status((100,0,0)) - self._esp.create_AP(bytes.ssid, 'utf-8'), bytes(self.password, 'utf-8') + if(self.password): + self._esp.create_AP(bytes(self.ssid, 'utf-8'), bytes(self.password, 'utf-8')) + else: + self._esp.create_AP(bytes(self.ssid, 'utf-8'), None) failure_count = 0 self.pixel_status((0,100,0)) except (ValueError, RuntimeError) as error: @@ -114,6 +118,7 @@ def create_ap(self): failure_count = 0 self.reset() continue + print("Access Point created! Connect to ssid: {}".format(self.ssid)) def get(self, url, **kw): """ diff --git a/examples/esp32spi_server.py b/examples/esp32spi_server.py new file mode 100644 index 0000000..56cb52d --- /dev/null +++ b/examples/esp32spi_server.py @@ -0,0 +1,24 @@ +import board +import busio +from digitalio import DigitalInOut +from secrets import secrets + +from adafruit_esp32spi import adafruit_esp32spi +import adafruit_esp32spi.adafruit_esp32spi_requests as requests +import adafruit_esp32spi.adafruit_esp32spi_wifimanager as wifimanager + +print("ESP32 SPI web server test!!!!!!") + +esp32_cs = DigitalInOut(board.D10) +esp32_ready = DigitalInOut(board.D9) +esp32_reset = DigitalInOut(board.D7) + + +spi = busio.SPI(board.SCK, board.MOSI, board.MISO) +esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset, debug=True) + +wifi = wifimanager.ESPSPI_WiFiManager(esp, secrets, debug=True) + +wifi.create_ap(); + +print("done!") From c72cd97f02dc3bd33a8d94e0a98ea92ef33407cc Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Fri, 5 Jul 2019 20:34:44 -0400 Subject: [PATCH 03/17] attempt at start_server method --- adafruit_esp32spi/adafruit_esp32spi.py | 20 ++++++++++++++ adafruit_esp32spi/adafruit_esp32spi_socket.py | 4 +++ examples/esp32spi_server.py | 27 ++++++++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/adafruit_esp32spi/adafruit_esp32spi.py b/adafruit_esp32spi/adafruit_esp32spi.py index 7f67479..41ede37 100644 --- a/adafruit_esp32spi/adafruit_esp32spi.py +++ b/adafruit_esp32spi/adafruit_esp32spi.py @@ -66,6 +66,7 @@ _GET_CURR_ENCT_CMD = const(0x26) _SCAN_NETWORKS = const(0x27) +_START_SERVER_TCP_CMD = const(0x28) _GET_SOCKET_CMD = const(0x3F) _GET_STATE_TCP_CMD = const(0x29) _DATA_SENT_TCP_CMD = const(0x2A) @@ -662,6 +663,25 @@ def socket_close(self, socket_num): if resp[0][0] != 1: raise RuntimeError("Failed to close socket") + def start_server(self, port, socket_num, conn_mode=TCP_MODE, ip=None): + if self._debug: + print("*** starting server") + self._socknum_ll[0][0] = socket_num + port_param = struct.pack('>H', port) + if ip: # use the 4 arg version + resp = self._send_command_get_response(_START_SERVER_TCP_CMD, + (ip, + port_param, + self._socknum_ll[0], + (conn_mode,))) + else: # use the 3 arg version + resp = self._send_command_get_response(_START_SERVER_TCP_CMD, + (port_param, + self._socknum_ll[0], + (conn_mode,))) + if resp[0][0] != 1: + raise RuntimeError("Could not start server") + def set_esp_debug(self, enabled): """Enable/disable debug mode on the ESP32. Debug messages will be written to the ESP32's UART.""" diff --git a/adafruit_esp32spi/adafruit_esp32spi_socket.py b/adafruit_esp32spi/adafruit_esp32spi_socket.py index ccf5b4f..9aef70b 100644 --- a/adafruit_esp32spi/adafruit_esp32spi_socket.py +++ b/adafruit_esp32spi/adafruit_esp32spi_socket.py @@ -66,6 +66,7 @@ def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None): raise RuntimeError("Only SOCK_STREAM type supported") self._buffer = b'' self._socknum = _the_interface.get_socket() + print("socknum: ", self._socknum) self.settimeout(0) def connect(self, address, conntype=None): @@ -148,6 +149,9 @@ def settimeout(self, value): """Set the read timeout for sockets, if value is 0 it will block""" self._timeout = value + def get_sock_num(self): + return self._socknum + def close(self): """Close the socket, after reading whatever remains""" _the_interface.socket_close(self._socknum) diff --git a/examples/esp32spi_server.py b/examples/esp32spi_server.py index 56cb52d..3883116 100644 --- a/examples/esp32spi_server.py +++ b/examples/esp32spi_server.py @@ -6,6 +6,7 @@ from adafruit_esp32spi import adafruit_esp32spi import adafruit_esp32spi.adafruit_esp32spi_requests as requests import adafruit_esp32spi.adafruit_esp32spi_wifimanager as wifimanager +import adafruit_esp32spi.adafruit_esp32spi_socket as socket print("ESP32 SPI web server test!!!!!!") @@ -19,6 +20,30 @@ wifi = wifimanager.ESPSPI_WiFiManager(esp, secrets, debug=True) -wifi.create_ap(); +wifi.create_ap() +time.sleep(10) + +sock = socket.socket() # gets and creates a socket +sock_num = sock.get_sock_num() # returns socket number + +esp.start_server(sock_num, 80) +print("socket num: ", sock_num) +print("socket status?: ", esp.socket_status(sock_num)) +print("IP addr: ", esp.pretty_ip(esp.ip_address)) + +status = 0 +while True: + if status != esp.status: + status = esp.status + + if status == 8: + print("Device connected!") ## works + else: + print("Device disconnected status=", status) ## works + + print("socket available?: ", esp.socket_available(sockNum)) + print("socket_status: ", esp.socket_status(sockNum)) + print(sock.read()) + print("done!") From ea630d27d1549d977dded6d33fc649eab07c1dcd Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Sun, 7 Jul 2019 17:32:30 -0400 Subject: [PATCH 04/17] Working hello world server example --- adafruit_esp32spi/adafruit_esp32spi.py | 5 ++ examples/esp32spi_server.py | 65 ++++++++++++++++++++------ 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/adafruit_esp32spi/adafruit_esp32spi.py b/adafruit_esp32spi/adafruit_esp32spi.py index 41ede37..dea1787 100644 --- a/adafruit_esp32spi/adafruit_esp32spi.py +++ b/adafruit_esp32spi/adafruit_esp32spi.py @@ -682,6 +682,11 @@ def start_server(self, port, socket_num, conn_mode=TCP_MODE, ip=None): if resp[0][0] != 1: raise RuntimeError("Could not start server") + def get_server_state(self, socket_num): + self._socknum_ll[0][0] = socket_num + resp = self._send_command_get_response(_GET_STATE_TCP_CMD, self._socknum_ll) + return resp[0][0] + def set_esp_debug(self, enabled): """Enable/disable debug mode on the ESP32. Debug messages will be written to the ESP32's UART.""" diff --git a/examples/esp32spi_server.py b/examples/esp32spi_server.py index 3883116..bc722d3 100644 --- a/examples/esp32spi_server.py +++ b/examples/esp32spi_server.py @@ -1,5 +1,6 @@ import board import busio +import time from digitalio import DigitalInOut from secrets import secrets @@ -13,37 +14,73 @@ esp32_cs = DigitalInOut(board.D10) esp32_ready = DigitalInOut(board.D9) esp32_reset = DigitalInOut(board.D7) +esp32_gpio0 = DigitalInOut(board.D12) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) -esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset, debug=True) +esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset, gpio0_pin=esp32_gpio0, debug=False) +## Create Access Point from SSID and optional password in secrets wifi = wifimanager.ESPSPI_WiFiManager(esp, secrets, debug=True) - wifi.create_ap() time.sleep(10) -sock = socket.socket() # gets and creates a socket -sock_num = sock.get_sock_num() # returns socket number +socket.set_interface(esp) +sock = socket.socket() # Request a socket for the server +curr_sock = sock +sockNum = sock.get_sock_num() +print("server status: ", esp.get_server_state(sockNum)) + +# Start the server on port 80 with the socket number we just requested for it. +esp.start_server(80, sockNum) -esp.start_server(sock_num, 80) -print("socket num: ", sock_num) -print("socket status?: ", esp.socket_status(sock_num)) +print("socket num: ", sockNum) +print("server status: ", esp.get_server_state(sockNum)) print("IP addr: ", esp.pretty_ip(esp.ip_address)) +print("info: ", esp.network_data) +print("done!") + status = 0 +last_sock = 255 +def server_avail(): # TODO: make a server helper class + global last_sock + sock = 255; + + if (curr_sock != 255): + # if (last_sock != 255): + # TODO: if last sock, check that last_sock is still connected and available + # sock = last_sock + if (sock == 255): + sock = esp.socket_available(sockNum) + if (sock != 255): + last_sock = sock + return sock + + return 255 + while True: - if status != esp.status: + if status != esp.status: # TODO: Move device connected check to server class ? status = esp.status if status == 8: - print("Device connected!") ## works + print("Device connected! status=", status) else: - print("Device disconnected status=", status) ## works + print("Device disconnected! status=", status) - print("socket available?: ", esp.socket_available(sockNum)) - print("socket_status: ", esp.socket_status(sockNum)) - print(sock.read()) + avail = server_avail() + if (avail != 255): + sock.set_sock_num(avail) # TODO: Server class should return a new client socket + data = sock.read() + if (len(data)): + print(data) + sock.write(b"HTTP/1.1 200 OK\r\n"); + sock.write(b"Content-type:text/html\r\n"); + sock.write(b"\r\n"); -print("done!") + sock.write(b"Click here turn the LED on!!!
\r\n"); + sock.write(b"Click here turn the LED off!!!!
\r\n"); + + sock.write(b"\r\n") + sock.close() From 130f966af984748f21273d44774b4a91e9ddc1ae Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Sun, 7 Jul 2019 17:32:57 -0400 Subject: [PATCH 05/17] fix spacing --- adafruit_esp32spi/adafruit_esp32spi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_esp32spi/adafruit_esp32spi.py b/adafruit_esp32spi/adafruit_esp32spi.py index dea1787..8ca576c 100644 --- a/adafruit_esp32spi/adafruit_esp32spi.py +++ b/adafruit_esp32spi/adafruit_esp32spi.py @@ -54,7 +54,7 @@ # pylint: disable=bad-whitespace _SET_NET_CMD = const(0x10) _SET_PASSPHRASE_CMD = const(0x11) -_SET_AP_NET_CMD = const(0x18) +_SET_AP_NET_CMD = const(0x18) _SET_AP_PASSPHRASE_CMD = const(0x19) _SET_DEBUG_CMD = const(0x1A) From 832b79be3fe85f74dba6340753805a64fe933881 Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Wed, 10 Jul 2019 22:11:48 -0400 Subject: [PATCH 06/17] Revert "fix spacing" This reverts commit 130f966af984748f21273d44774b4a91e9ddc1ae. --- adafruit_esp32spi/adafruit_esp32spi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_esp32spi/adafruit_esp32spi.py b/adafruit_esp32spi/adafruit_esp32spi.py index 8ca576c..dea1787 100644 --- a/adafruit_esp32spi/adafruit_esp32spi.py +++ b/adafruit_esp32spi/adafruit_esp32spi.py @@ -54,7 +54,7 @@ # pylint: disable=bad-whitespace _SET_NET_CMD = const(0x10) _SET_PASSPHRASE_CMD = const(0x11) -_SET_AP_NET_CMD = const(0x18) +_SET_AP_NET_CMD = const(0x18) _SET_AP_PASSPHRASE_CMD = const(0x19) _SET_DEBUG_CMD = const(0x1A) From 06d7bd1e5035c1c1aedf95a34c0db9eae743d21d Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Wed, 10 Jul 2019 22:11:52 -0400 Subject: [PATCH 07/17] Revert "Working hello world server example" This reverts commit ea630d27d1549d977dded6d33fc649eab07c1dcd. --- adafruit_esp32spi/adafruit_esp32spi.py | 5 -- examples/esp32spi_server.py | 65 ++++++-------------------- 2 files changed, 14 insertions(+), 56 deletions(-) diff --git a/adafruit_esp32spi/adafruit_esp32spi.py b/adafruit_esp32spi/adafruit_esp32spi.py index dea1787..41ede37 100644 --- a/adafruit_esp32spi/adafruit_esp32spi.py +++ b/adafruit_esp32spi/adafruit_esp32spi.py @@ -682,11 +682,6 @@ def start_server(self, port, socket_num, conn_mode=TCP_MODE, ip=None): if resp[0][0] != 1: raise RuntimeError("Could not start server") - def get_server_state(self, socket_num): - self._socknum_ll[0][0] = socket_num - resp = self._send_command_get_response(_GET_STATE_TCP_CMD, self._socknum_ll) - return resp[0][0] - def set_esp_debug(self, enabled): """Enable/disable debug mode on the ESP32. Debug messages will be written to the ESP32's UART.""" diff --git a/examples/esp32spi_server.py b/examples/esp32spi_server.py index bc722d3..3883116 100644 --- a/examples/esp32spi_server.py +++ b/examples/esp32spi_server.py @@ -1,6 +1,5 @@ import board import busio -import time from digitalio import DigitalInOut from secrets import secrets @@ -14,73 +13,37 @@ esp32_cs = DigitalInOut(board.D10) esp32_ready = DigitalInOut(board.D9) esp32_reset = DigitalInOut(board.D7) -esp32_gpio0 = DigitalInOut(board.D12) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) -esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset, gpio0_pin=esp32_gpio0, debug=False) +esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset, debug=True) -## Create Access Point from SSID and optional password in secrets wifi = wifimanager.ESPSPI_WiFiManager(esp, secrets, debug=True) + wifi.create_ap() time.sleep(10) -socket.set_interface(esp) -sock = socket.socket() # Request a socket for the server -curr_sock = sock -sockNum = sock.get_sock_num() -print("server status: ", esp.get_server_state(sockNum)) - -# Start the server on port 80 with the socket number we just requested for it. -esp.start_server(80, sockNum) +sock = socket.socket() # gets and creates a socket +sock_num = sock.get_sock_num() # returns socket number -print("socket num: ", sockNum) -print("server status: ", esp.get_server_state(sockNum)) +esp.start_server(sock_num, 80) +print("socket num: ", sock_num) +print("socket status?: ", esp.socket_status(sock_num)) print("IP addr: ", esp.pretty_ip(esp.ip_address)) -print("info: ", esp.network_data) -print("done!") - status = 0 -last_sock = 255 -def server_avail(): # TODO: make a server helper class - global last_sock - sock = 255; - - if (curr_sock != 255): - # if (last_sock != 255): - # TODO: if last sock, check that last_sock is still connected and available - # sock = last_sock - if (sock == 255): - sock = esp.socket_available(sockNum) - if (sock != 255): - last_sock = sock - return sock - - return 255 - while True: - if status != esp.status: # TODO: Move device connected check to server class ? + if status != esp.status: status = esp.status if status == 8: - print("Device connected! status=", status) + print("Device connected!") ## works else: - print("Device disconnected! status=", status) + print("Device disconnected status=", status) ## works + print("socket available?: ", esp.socket_available(sockNum)) + print("socket_status: ", esp.socket_status(sockNum)) + print(sock.read()) - avail = server_avail() - if (avail != 255): - sock.set_sock_num(avail) # TODO: Server class should return a new client socket - data = sock.read() - if (len(data)): - print(data) - sock.write(b"HTTP/1.1 200 OK\r\n"); - sock.write(b"Content-type:text/html\r\n"); - sock.write(b"\r\n"); - sock.write(b"Click here turn the LED on!!!
\r\n"); - sock.write(b"Click here turn the LED off!!!!
\r\n"); - - sock.write(b"\r\n") - sock.close() +print("done!") From 02477df464b4a8058a84e658ae659f3865a5802f Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Wed, 10 Jul 2019 22:11:54 -0400 Subject: [PATCH 08/17] Revert "attempt at start_server method" This reverts commit c72cd97f02dc3bd33a8d94e0a98ea92ef33407cc. --- adafruit_esp32spi/adafruit_esp32spi.py | 20 -------------- adafruit_esp32spi/adafruit_esp32spi_socket.py | 4 --- examples/esp32spi_server.py | 27 +------------------ 3 files changed, 1 insertion(+), 50 deletions(-) diff --git a/adafruit_esp32spi/adafruit_esp32spi.py b/adafruit_esp32spi/adafruit_esp32spi.py index 41ede37..7f67479 100644 --- a/adafruit_esp32spi/adafruit_esp32spi.py +++ b/adafruit_esp32spi/adafruit_esp32spi.py @@ -66,7 +66,6 @@ _GET_CURR_ENCT_CMD = const(0x26) _SCAN_NETWORKS = const(0x27) -_START_SERVER_TCP_CMD = const(0x28) _GET_SOCKET_CMD = const(0x3F) _GET_STATE_TCP_CMD = const(0x29) _DATA_SENT_TCP_CMD = const(0x2A) @@ -663,25 +662,6 @@ def socket_close(self, socket_num): if resp[0][0] != 1: raise RuntimeError("Failed to close socket") - def start_server(self, port, socket_num, conn_mode=TCP_MODE, ip=None): - if self._debug: - print("*** starting server") - self._socknum_ll[0][0] = socket_num - port_param = struct.pack('>H', port) - if ip: # use the 4 arg version - resp = self._send_command_get_response(_START_SERVER_TCP_CMD, - (ip, - port_param, - self._socknum_ll[0], - (conn_mode,))) - else: # use the 3 arg version - resp = self._send_command_get_response(_START_SERVER_TCP_CMD, - (port_param, - self._socknum_ll[0], - (conn_mode,))) - if resp[0][0] != 1: - raise RuntimeError("Could not start server") - def set_esp_debug(self, enabled): """Enable/disable debug mode on the ESP32. Debug messages will be written to the ESP32's UART.""" diff --git a/adafruit_esp32spi/adafruit_esp32spi_socket.py b/adafruit_esp32spi/adafruit_esp32spi_socket.py index 9aef70b..ccf5b4f 100644 --- a/adafruit_esp32spi/adafruit_esp32spi_socket.py +++ b/adafruit_esp32spi/adafruit_esp32spi_socket.py @@ -66,7 +66,6 @@ def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None): raise RuntimeError("Only SOCK_STREAM type supported") self._buffer = b'' self._socknum = _the_interface.get_socket() - print("socknum: ", self._socknum) self.settimeout(0) def connect(self, address, conntype=None): @@ -149,9 +148,6 @@ def settimeout(self, value): """Set the read timeout for sockets, if value is 0 it will block""" self._timeout = value - def get_sock_num(self): - return self._socknum - def close(self): """Close the socket, after reading whatever remains""" _the_interface.socket_close(self._socknum) diff --git a/examples/esp32spi_server.py b/examples/esp32spi_server.py index 3883116..56cb52d 100644 --- a/examples/esp32spi_server.py +++ b/examples/esp32spi_server.py @@ -6,7 +6,6 @@ from adafruit_esp32spi import adafruit_esp32spi import adafruit_esp32spi.adafruit_esp32spi_requests as requests import adafruit_esp32spi.adafruit_esp32spi_wifimanager as wifimanager -import adafruit_esp32spi.adafruit_esp32spi_socket as socket print("ESP32 SPI web server test!!!!!!") @@ -20,30 +19,6 @@ wifi = wifimanager.ESPSPI_WiFiManager(esp, secrets, debug=True) -wifi.create_ap() -time.sleep(10) - -sock = socket.socket() # gets and creates a socket -sock_num = sock.get_sock_num() # returns socket number - -esp.start_server(sock_num, 80) -print("socket num: ", sock_num) -print("socket status?: ", esp.socket_status(sock_num)) -print("IP addr: ", esp.pretty_ip(esp.ip_address)) - -status = 0 -while True: - if status != esp.status: - status = esp.status - - if status == 8: - print("Device connected!") ## works - else: - print("Device disconnected status=", status) ## works - - print("socket available?: ", esp.socket_available(sockNum)) - print("socket_status: ", esp.socket_status(sockNum)) - print(sock.read()) - +wifi.create_ap(); print("done!") From f6e16950ea12f89ca8f33d8c6034a7f6c70c8260 Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Wed, 10 Jul 2019 22:43:46 -0400 Subject: [PATCH 09/17] Add more docs and fix linting --- adafruit_esp32spi/adafruit_esp32spi.py | 18 ++++++++++++++---- .../adafruit_esp32spi_wifimanager.py | 11 ++++++----- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/adafruit_esp32spi/adafruit_esp32spi.py b/adafruit_esp32spi/adafruit_esp32spi.py index 7f67479..648e432 100644 --- a/adafruit_esp32spi/adafruit_esp32spi.py +++ b/adafruit_esp32spi/adafruit_esp32spi.py @@ -412,14 +412,24 @@ def wifi_set_entenable(self): raise RuntimeError("Failed to enable enterprise mode") def wifi_set_ap_network(self, ssid, channel): - """TODO Docs""" + """ + Creates an Access point with SSID and Channel + + :param ssid: the SSID of the created Access Point. Must be 8 or more characters + :param channel: channel of created Access Point (1 - 14). + """ resp = self._send_command_get_response(_SET_AP_NET_CMD, [ssid, channel]) if resp[0][0] != 1: raise RuntimeError("Failed to setup AP network") def wifi_set_ap_passphrase(self, ssid, passphrase, channel): - """TODO Docs""" - """ TODO: Why does this command refuse to work? creating AP w/out password works fine""" + """ + Creates an Access point with SSID, passphrase, and Channel + + :param ssid: the SSID of the created Access Point. Must be 8 or more characters + :param passphrase: the password of the created Access Point. Must be 8 or more characters. + :param channel: channel of created Access Point (1 - 14). + """ resp = self._send_command_get_response(_SET_AP_PASSPHRASE_CMD, [ssid, passphrase, channel]) if resp[0][0] != 1: raise RuntimeError("Failed to setup AP password") @@ -497,7 +507,7 @@ def connect_AP(self, ssid, password): # pylint: disable=invalid-name raise RuntimeError("No such ssid", ssid) raise RuntimeError("Unknown error 0x%02X" % stat) - def create_AP(self, ssid, password, channel=b'\x01'): + def create_ap(self, ssid, password, channel=b'\x01'): """Create an access point with the given name and password.""" if isinstance(ssid, str): ssid = bytes(ssid, 'utf-8') diff --git a/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py index 9d7dd3f..de9f32f 100755 --- a/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py +++ b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py @@ -97,6 +97,7 @@ def connect(self): def create_ap(self): """ Attempt to initialize in Access Point (AP) mode. + Uses SSID and optional passphrase from the current settings Other WiFi devices will be able to connect to the created Access Point """ failure_count = 0 @@ -104,13 +105,13 @@ def create_ap(self): try: if self.debug: print("Waiting for AP to be initialized...") - self.pixel_status((100,0,0)) - if(self.password): - self._esp.create_AP(bytes(self.ssid, 'utf-8'), bytes(self.password, 'utf-8')) + self.pixel_status((100, 0, 0)) + if self.password: + self._esp.create_ap(bytes(self.ssid, 'utf-8'), bytes(self.password, 'utf-8')) else: - self._esp.create_AP(bytes(self.ssid, 'utf-8'), None) + self._esp.create_ap(bytes(self.ssid, 'utf-8'), None) failure_count = 0 - self.pixel_status((0,100,0)) + self.pixel_status((0, 100, 0)) except (ValueError, RuntimeError) as error: print("Failed to create access point\n", error) failure_count += 1 From 7a87e4eceb5f73aa2c1502015192325cd3ebe6df Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Wed, 10 Jul 2019 22:48:11 -0400 Subject: [PATCH 10/17] remove server example to be re-worked in future commits --- examples/esp32spi_server.py | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 examples/esp32spi_server.py diff --git a/examples/esp32spi_server.py b/examples/esp32spi_server.py deleted file mode 100644 index 56cb52d..0000000 --- a/examples/esp32spi_server.py +++ /dev/null @@ -1,24 +0,0 @@ -import board -import busio -from digitalio import DigitalInOut -from secrets import secrets - -from adafruit_esp32spi import adafruit_esp32spi -import adafruit_esp32spi.adafruit_esp32spi_requests as requests -import adafruit_esp32spi.adafruit_esp32spi_wifimanager as wifimanager - -print("ESP32 SPI web server test!!!!!!") - -esp32_cs = DigitalInOut(board.D10) -esp32_ready = DigitalInOut(board.D9) -esp32_reset = DigitalInOut(board.D7) - - -spi = busio.SPI(board.SCK, board.MOSI, board.MISO) -esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset, debug=True) - -wifi = wifimanager.ESPSPI_WiFiManager(esp, secrets, debug=True) - -wifi.create_ap(); - -print("done!") From d0ee4954bd790113849fb54a814e83d9d674604b Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Wed, 10 Jul 2019 22:55:11 -0400 Subject: [PATCH 11/17] appease pylint --- adafruit_esp32spi/adafruit_esp32spi_wifimanager.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py index de9f32f..5651bb1 100755 --- a/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py +++ b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py @@ -39,6 +39,7 @@ class ESPSPI_WiFiManager: """ A class to help manage the Wifi connection """ + # pylint: disable=too-many-arguments def __init__(self, esp, secrets, status_pixel=None, attempts=2, debug=False): """ :param ESP_SPIcontrol esp: The ESP object we are using @@ -57,6 +58,7 @@ def __init__(self, esp, secrets, status_pixel=None, attempts=2, debug=False): requests.set_interface(self._esp) self.statuspix = status_pixel self.pixel_status(0) + # pylint: enable=too-many-arguments def reset(self): """ From f67a2e4ef11f61d6c48b66eba928db32006554f1 Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Wed, 10 Jul 2019 23:00:18 -0400 Subject: [PATCH 12/17] tabs -> spaces --- adafruit_esp32spi/adafruit_esp32spi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_esp32spi/adafruit_esp32spi.py b/adafruit_esp32spi/adafruit_esp32spi.py index 648e432..5a6b46a 100644 --- a/adafruit_esp32spi/adafruit_esp32spi.py +++ b/adafruit_esp32spi/adafruit_esp32spi.py @@ -54,7 +54,7 @@ # pylint: disable=bad-whitespace _SET_NET_CMD = const(0x10) _SET_PASSPHRASE_CMD = const(0x11) -_SET_AP_NET_CMD = const(0x18) +_SET_AP_NET_CMD = const(0x18) _SET_AP_PASSPHRASE_CMD = const(0x19) _SET_DEBUG_CMD = const(0x1A) From 917ef2dd5d72cfeeee97018307b5f9bb68461744 Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Sun, 21 Jul 2019 17:18:18 -0400 Subject: [PATCH 13/17] Address PR comments --- adafruit_esp32spi/adafruit_esp32spi.py | 72 +++++++++++-------- .../adafruit_esp32spi_wifimanager.py | 4 +- 2 files changed, 46 insertions(+), 30 deletions(-) diff --git a/adafruit_esp32spi/adafruit_esp32spi.py b/adafruit_esp32spi/adafruit_esp32spi.py index 671815b..e19ff9a 100644 --- a/adafruit_esp32spi/adafruit_esp32spi.py +++ b/adafruit_esp32spi/adafruit_esp32spi.py @@ -411,25 +411,14 @@ def wifi_set_entenable(self): if resp[0][0] != 1: raise RuntimeError("Failed to enable enterprise mode") - def wifi_set_ap_network(self, ssid, channel): - """ - Creates an Access point with SSID and Channel - - :param ssid: the SSID of the created Access Point. Must be 8 or more characters - :param channel: channel of created Access Point (1 - 14). - """ + def _wifi_set_ap_network(self, ssid, channel): + """Creates an Access point with SSID and Channel""" resp = self._send_command_get_response(_SET_AP_NET_CMD, [ssid, channel]) if resp[0][0] != 1: raise RuntimeError("Failed to setup AP network") - def wifi_set_ap_passphrase(self, ssid, passphrase, channel): - """ - Creates an Access point with SSID, passphrase, and Channel - - :param ssid: the SSID of the created Access Point. Must be 8 or more characters - :param passphrase: the password of the created Access Point. Must be 8 or more characters. - :param channel: channel of created Access Point (1 - 14). - """ + def _wifi_set_ap_passphrase(self, ssid, passphrase, channel): + """Creates an Access point with SSID, passphrase, and Channel""" resp = self._send_command_get_response(_SET_AP_PASSPHRASE_CMD, [ssid, passphrase, channel]) if resp[0][0] != 1: raise RuntimeError("Failed to setup AP password") @@ -470,7 +459,7 @@ def is_connected(self): @property def ap_listening(self): - """Whether the ESP32 is in access point mode and is listening for connections""" + """Returns if the ESP32 is in access point mode and is listening for connections""" try: return self.status == WL_AP_LISTENING except RuntimeError: @@ -482,10 +471,16 @@ def connect(self, secrets): that contains a 'ssid' and 'password' entry""" self.connect_AP(secrets['ssid'], secrets['password']) - def connect_AP(self, ssid, password): # pylint: disable=invalid-name - """Connect to an access point with given name and password. - Will retry up to 10 times and return on success or raise - an exception on failure""" + def connect_AP(self, ssid, password, timeout_s=10): # pylint: disable=invalid-name + """ + Connect to an access point with given name and password. + Will wait until specified timeout seconds and return on success + or raise an exception on failure. + + :param ssid: the SSID to connect to + :param passphrase: the password of the access point + :param timeout_s: number of seconds until we time out and fail to create AP + """ if self._debug: print("Connect to AP", ssid, password) if isinstance(ssid, str): @@ -496,32 +491,53 @@ def connect_AP(self, ssid, password): # pylint: disable=invalid-name self.wifi_set_passphrase(ssid, password) else: self.wifi_set_network(ssid) - for _ in range(10): # retries + times = time.monotonic() + while (time.monotonic() - times) < timeout_s: # wait up until timeout stat = self.status if stat == WL_CONNECTED: return stat - time.sleep(1) + time.sleep(0.05) if stat in (WL_CONNECT_FAILED, WL_CONNECTION_LOST, WL_DISCONNECTED): raise RuntimeError("Failed to connect to ssid", ssid) if stat == WL_NO_SSID_AVAIL: raise RuntimeError("No such ssid", ssid) raise RuntimeError("Unknown error 0x%02X" % stat) - def create_ap(self, ssid, password, channel=b'\x01'): - """Create an access point with the given name and password.""" + def create_AP(self, ssid, password, channel=1, timeout_s=10): # pylint: disable=invalid-name + """ + Create an access point with the given name, password, and channel. + Will wait until specified timeout seconds and return on success + or raise an exception on failure. + + :param ssid: the SSID of the created Access Point. Must be 8 or more characters + :param passphrase: the password of the created Access Point. Must be 8 or more characters. + :param channel: channel of created Access Point (1 - 14). + :param timeout_s: number of seconds until we time out and fail to create AP + """ + if len(ssid) < 8: + raise RuntimeError("ssid must be 8 more more characters") + if len(password) < 8: + raise RuntimeError("password must be 8 or more characters") + if channel < 1 or channel > 14: + raise RuntimeError("channel must be between 1 and 14") + + if isinstance(channel, int): + channel = bytes(channel) if isinstance(ssid, str): ssid = bytes(ssid, 'utf-8') if password: if isinstance(password, str): password = bytes(password, 'utf-8') - self.wifi_set_ap_passphrase(ssid, password, channel) + self._wifi_set_ap_passphrase(ssid, password, channel) else: - self.wifi_set_ap_network(ssid, channel) - for _ in range(10): # retries + self._wifi_set_ap_network(ssid, channel) + + times = time.monotonic() + while (time.monotonic() - times) < timeout_s: # wait up until timeout stat = self.status if stat == WL_AP_LISTENING: return stat - time.sleep(1) + time.sleep(0.05) if stat == WL_AP_FAILED: raise RuntimeError("Failed to create AP", ssid) raise RuntimeError("Unknown error 0x%02x" % stat) diff --git a/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py index 4f3ae8d..b08b269 100755 --- a/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py +++ b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py @@ -109,9 +109,9 @@ def create_ap(self): print("Waiting for AP to be initialized...") self.pixel_status((100, 0, 0)) if self.password: - self.esp.create_ap(bytes(self.ssid, 'utf-8'), bytes(self.password, 'utf-8')) + self.esp.create_AP(bytes(self.ssid, 'utf-8'), bytes(self.password, 'utf-8')) else: - self.esp.create_ap(bytes(self.ssid, 'utf-8'), None) + self.esp.create_AP(bytes(self.ssid, 'utf-8'), None) failure_count = 0 self.pixel_status((0, 100, 0)) except (ValueError, RuntimeError) as error: From eb1a8b0fe0dfb850256a8d5a13a74da6ed238550 Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Sun, 21 Jul 2019 22:27:32 -0400 Subject: [PATCH 14/17] wrap argument list instead of disabling lint rule --- adafruit_esp32spi/adafruit_esp32spi_wifimanager.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py index 501a8b4..1882cb4 100755 --- a/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py +++ b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py @@ -44,8 +44,9 @@ class ESPSPI_WiFiManager: NORMAL = const(1) ENTERPRISE = const(2) - # pylint: disable=too-many-arguments, line-too-long - def __init__(self, esp, secrets, status_pixel=None, attempts=2, connection_type=NORMAL, debug=False): + # pylint: disable=too-many-arguments + def __init__(self, esp, secrets, status_pixel=None, attempts=2, + connection_type=NORMAL, debug=False): """ :param ESP_SPIcontrol esp: The ESP object we are using :param dict secrets: The WiFi and Adafruit IO secrets dict (See examples) @@ -79,7 +80,7 @@ def __init__(self, esp, secrets, status_pixel=None, attempts=2, connection_type= self.ent_user = secrets['ent_user'] if secrets.get('ent_password'): self.ent_password = secrets['ent_password'] - # pylint: enable=too-many-arguments, line-too-long + # pylint: enable=too-many-arguments def reset(self): """ From 180ceaa5e0ef0974200b6f49a84f141e3986a273 Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Fri, 2 Aug 2019 12:09:27 -0400 Subject: [PATCH 15/17] fix valid SSID and passphrase requirements --- adafruit_esp32spi/adafruit_esp32spi.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/adafruit_esp32spi/adafruit_esp32spi.py b/adafruit_esp32spi/adafruit_esp32spi.py index 1eece74..e2f2af1 100644 --- a/adafruit_esp32spi/adafruit_esp32spi.py +++ b/adafruit_esp32spi/adafruit_esp32spi.py @@ -504,21 +504,21 @@ def connect_AP(self, ssid, password, timeout_s=10): # pylint: disable=invalid-na raise RuntimeError("No such ssid", ssid) raise RuntimeError("Unknown error 0x%02X" % stat) - def create_AP(self, ssid, password, channel=1, timeout_s=10): # pylint: disable=invalid-name + def create_AP(self, ssid, password, channel=1, timeout=10): # pylint: disable=invalid-name """ Create an access point with the given name, password, and channel. Will wait until specified timeout seconds and return on success or raise an exception on failure. - :param ssid: the SSID of the created Access Point. Must be 8 or more characters - :param passphrase: the password of the created Access Point. Must be 8 or more characters. - :param channel: channel of created Access Point (1 - 14). - :param timeout_s: number of seconds until we time out and fail to create AP + :param str ssid: the SSID of the created Access Point. Must be less than 32 chars. + :param str password: the password of the created Access Point. Must be 8-63 chars. + :param int channel: channel of created Access Point (1 - 14). + :param int timeout: number of seconds until we time out and fail to create AP """ - if len(ssid) < 8: - raise RuntimeError("ssid must be 8 more more characters") - if len(password) < 8: - raise RuntimeError("password must be 8 or more characters") + if len(ssid) > 32: + raise RuntimeError("ssid must be no more than 32 characters") + if len(password) < 8 or len(password) < 64: + raise RuntimeError("password must be 8 - 63 characters") if channel < 1 or channel > 14: raise RuntimeError("channel must be between 1 and 14") @@ -534,7 +534,7 @@ def create_AP(self, ssid, password, channel=1, timeout_s=10): # pylint: disable= self._wifi_set_ap_network(ssid, channel) times = time.monotonic() - while (time.monotonic() - times) < timeout_s: # wait up until timeout + while (time.monotonic() - times) < timeout: # wait up to timeout stat = self.status if stat == WL_AP_LISTENING: return stat From a349bac38c6aff1ec4dd0aa47810f59334921bb1 Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Sun, 11 Aug 2019 17:53:07 -0400 Subject: [PATCH 16/17] add protected and unprotected AP code snippets to wsgi server demo --- adafruit_esp32spi/adafruit_esp32spi.py | 2 +- adafruit_esp32spi/adafruit_esp32spi_wifimanager.py | 2 +- examples/server/esp32spi_wsgiserver.py | 12 +++++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/adafruit_esp32spi/adafruit_esp32spi.py b/adafruit_esp32spi/adafruit_esp32spi.py index e2f2af1..3e16df0 100644 --- a/adafruit_esp32spi/adafruit_esp32spi.py +++ b/adafruit_esp32spi/adafruit_esp32spi.py @@ -517,7 +517,7 @@ def create_AP(self, ssid, password, channel=1, timeout=10): # pylint: disable=in """ if len(ssid) > 32: raise RuntimeError("ssid must be no more than 32 characters") - if len(password) < 8 or len(password) < 64: + if password and (len(password) < 8 or len(password) > 64): raise RuntimeError("password must be 8 - 63 characters") if channel < 1 or channel > 14: raise RuntimeError("channel must be between 1 and 14") diff --git a/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py index 1882cb4..5719e95 100755 --- a/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py +++ b/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py @@ -154,7 +154,7 @@ def create_ap(self): failure_count = 0 self.reset() continue - print("Access Point created! Connect to ssid: {}".format(self.ssid)) + print("Access Point created! Connect to ssid:\n {}".format(self.ssid)) def connect_enterprise(self): """ diff --git a/examples/server/esp32spi_wsgiserver.py b/examples/server/esp32spi_wsgiserver.py index c971300..a247c77 100644 --- a/examples/server/esp32spi_wsgiserver.py +++ b/examples/server/esp32spi_wsgiserver.py @@ -45,10 +45,20 @@ # import adafruit_dotstar as dotstar # status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=1) -## Connect to wifi with secrets +## If you want to connect to wifi with secrets: wifi = wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) wifi.connect() +## If you want to create a WIFI hotspot to connect to with secrets: +# secrets = {"ssid": "My ESP32 AP!", "password": "supersecret"} +# wifi = wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +# wifi.create_ap() + +## To you want to create an un-protected WIFI hotspot to connect to with secrets:" +# secrets = {"ssid": "My ESP32 AP!"} +# wifi = wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +# wifi.create_ap() + class SimpleWSGIApplication: """ An example of a simple WSGI Application that supports From bea04e4b46894be9c7143c149de4ee14abdef3a8 Mon Sep 17 00:00:00 2001 From: Matt Costi Date: Sun, 11 Aug 2019 17:54:44 -0400 Subject: [PATCH 17/17] make example web app not depend on externally hosted assets, to support AP without internet --- examples/server/static/index.html | 6 +- .../server/static/led_color_picker_example.js | 147 +++++++++++++++--- 2 files changed, 126 insertions(+), 27 deletions(-) diff --git a/examples/server/static/index.html b/examples/server/static/index.html index 460a37b..11568a2 100755 --- a/examples/server/static/index.html +++ b/examples/server/static/index.html @@ -1,14 +1,10 @@ - - - -

LED color picker demo!

- + \ No newline at end of file diff --git a/examples/server/static/led_color_picker_example.js b/examples/server/static/led_color_picker_example.js index d988944..ba681a8 100755 --- a/examples/server/static/led_color_picker_example.js +++ b/examples/server/static/led_color_picker_example.js @@ -1,23 +1,126 @@ -console.log("initializing color picker") -var colorPicker = $('input#colorPicker'); -colorPicker.minicolors({ - format: "rgb", - changeDelay: 200, - change: function (value, opacity) { - rgbObject = colorPicker.minicolors("rgbObject"); - console.log(rgbObject); - $.ajax({ - type: "POST", - url: "/ajax/ledcolor", - data: JSON.stringify(rgbObject), - contentType: "application/json; charset=utf-8", - dataType: "json", - success: function(data){ - console.log("success!"); - }, - failure: function(errMsg) { - console.log("error! " + errMsg); - } - }); +let canvas = document.getElementById('colorPicker'); +let ctx = canvas.getContext("2d"); +ctx.width = 300; +ctx.height = 300; + +function drawColorPicker() { + /** + * Color picker inspired by: + * https://medium.com/@bantic/hand-coding-a-color-wheel-with-canvas-78256c9d7d43 + */ + let radius = 150; + let image = ctx.createImageData(2*radius, 2*radius); + let data = image.data; + + for (let x = -radius; x < radius; x++) { + for (let y = -radius; y < radius; y++) { + + let [r, phi] = xy2polar(x, y); + + if (r > radius) { + // skip all (x,y) coordinates that are outside of the circle + continue; + } + + let deg = rad2deg(phi); + + // Figure out the starting index of this pixel in the image data array. + let rowLength = 2*radius; + let adjustedX = x + radius; // convert x from [-50, 50] to [0, 100] (the coordinates of the image data array) + let adjustedY = y + radius; // convert y from [-50, 50] to [0, 100] (the coordinates of the image data array) + let pixelWidth = 4; // each pixel requires 4 slots in the data array + let index = (adjustedX + (adjustedY * rowLength)) * pixelWidth; + + let hue = deg; + let saturation = r / radius; + let value = 1.0; + + let [red, green, blue] = hsv2rgb(hue, saturation, value); + let alpha = 255; + + data[index] = red; + data[index+1] = green; + data[index+2] = blue; + data[index+3] = alpha; + } } -}); \ No newline at end of file + + ctx.putImageData(image, 0, 0); +} + +function xy2polar(x, y) { + let r = Math.sqrt(x*x + y*y); + let phi = Math.atan2(y, x); + return [r, phi]; +} + +// rad in [-π, π] range +// return degree in [0, 360] range +function rad2deg(rad) { + return ((rad + Math.PI) / (2 * Math.PI)) * 360; +} + + // hue in range [0, 360] + // saturation, value in range [0,1] + // return [r,g,b] each in range [0,255] + // See: https://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV +function hsv2rgb(hue, saturation, value) { + let chroma = value * saturation; + let hue1 = hue / 60; + let x = chroma * (1- Math.abs((hue1 % 2) - 1)); + let r1, g1, b1; + if (hue1 >= 0 && hue1 <= 1) { + ([r1, g1, b1] = [chroma, x, 0]); + } else if (hue1 >= 1 && hue1 <= 2) { + ([r1, g1, b1] = [x, chroma, 0]); + } else if (hue1 >= 2 && hue1 <= 3) { + ([r1, g1, b1] = [0, chroma, x]); + } else if (hue1 >= 3 && hue1 <= 4) { + ([r1, g1, b1] = [0, x, chroma]); + } else if (hue1 >= 4 && hue1 <= 5) { + ([r1, g1, b1] = [x, 0, chroma]); + } else if (hue1 >= 5 && hue1 <= 6) { + ([r1, g1, b1] = [chroma, 0, x]); + } + + let m = value - chroma; + let [r,g,b] = [r1+m, g1+m, b1+m]; + + // Change r,g,b values from [0,1] to [0,255] + return [255*r,255*g,255*b]; +} + +function onColorPick(event) { + coords = getCursorPosition(canvas, event) + imageData = ctx.getImageData(coords[0],coords[1],1,1) + rgbObject = { + r: imageData.data[0], + g: imageData.data[1], + b: imageData.data[2] + } + console.log(`r: ${rgbObject.r} g: ${rgbObject.g} b: ${rgbObject.b}`); + data = JSON.stringify(rgbObject); + window.fetch("/ajax/ledcolor", { + method: "POST", + body: data, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }).then(response => { + console.log("sucess!: " + response) + }, error => { + console.log("error!: " + error) + }) +} + +function getCursorPosition(canvas, event) { + const rect = canvas.getBoundingClientRect() + const x = event.clientX - rect.left + const y = event.clientY - rect.top + console.log("x: " + x + " y: " + y) + return [x,y] +} + +drawColorPicker(); +canvas.addEventListener('mousedown', onColorPick); +