Giter Club home page Giter Club logo

adafruit_circuitpython_esp32spi's Introduction

Introduction

Documentation Status Discord Build Status Code Style: Black

CircuitPython driver library for using ESP32 as WiFi co-processor using SPI. The companion firmware is available on GitHub. Please be sure to check the example code for any specific firmware version dependencies that may exist.

Dependencies

This driver depends on:

Please ensure all dependencies are available on the CircuitPython filesystem. This is easily achieved by downloading the Adafruit library and driver bundle.

Installing from PyPI

On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally from PyPI. To install for current user:

pip3 install adafruit-circuitpython-esp32spi

To install system-wide (this may be required in some cases):

sudo pip3 install adafruit-circuitpython-esp32spi

To install in a virtual environment in your current project:

mkdir project-name && cd project-name
python3 -m venv .venv
source .venv/bin/activate
pip3 install adafruit-circuitpython-esp32spi

Usage Example

Check the examples folder for various demos for connecting and fetching data!

Documentation

API documentation for this library can be found on Read the Docs.

For information on building library documentation, please check out this guide.

Contributing

Contributions are welcome! Please read our Code of Conduct before contributing to help this project stay welcoming.

adafruit_circuitpython_esp32spi's People

Contributors

anecdata avatar brentru avatar cpforbes avatar dannystaple avatar dearmash avatar dhalbert avatar docmollo avatar evaherrada avatar flameeyes avatar foamyguy avatar jepler avatar jerryneedell avatar justmobilize avatar kattni avatar ladyada avatar makermelissa avatar martymcguire avatar mikejc58 avatar mscosti avatar mytechnotalent avatar neradoc avatar retiredwizard avatar rivques avatar siddacious avatar sommersoft avatar tannewt avatar tekktrik avatar us3r64 avatar zachariahpifer avatar zachno avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

adafruit_circuitpython_esp32spi's Issues

Expose RGB LEDs in WiFiManager, instead of NeoPixels

Some of the AirLift breakouts use RGB LEDS instead of NeoPixels. It'd be nice to have an status indicator LED within the WiFiManager for cases when NeoPixels aren't present.

The AirLift Breakout follows the pin ordering: 25 (Red), 26 (Green), 27 (Blue).

get_time( ) returns (0,) for awhile

while investgating this issue
adafruit/Adafruit_CircuitPython_NTP#2

I found that esp.get_time() sometimes returns (0,) after first connectng.
It eventually returns a good value but it can take >15 seconds

using this test code"

import time
import board
import busio
from digitalio import DigitalInOut
from adafruit_esp32spi import adafruit_esp32spi

# If you are using a board with pre-defined ESP32 Pins:
esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)


spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)

print("Connecting to AP...")
while not esp.is_connected:
    try:
        esp.connect_AP(b"Needell Airport", b"browndog")
    except RuntimeError as e:
        print("could not connect to AP, retrying: ", e)
        continue

while True:
    print(esp.get_time())
    time.sleep(1)

you can see the problem

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.

Adafruit CircuitPython 5.0.0-alpha.1-2-gfebfc7e4e on 2019-09-02; Adafruit PyPortal with samd51j20
>>> 
>>> import gettime
Connecting to AP...
could not connect to AP, retrying:  ('No such ssid', b'Needell Airport')
(0,)
(0,)
(0,)
(0,)
(0,)
(0,)
(0,)
(0,)
(0,)
(0,)
(0,)
(0,)
(0,)
(0,)
(1568372023,)
(1568372024,)
(1568372025,)
(1568372026,)
(1568372027,)
(1568372028,)

HTTP server response headers are not cleared between fetches

This issue will probably have to get moved. I'm seeing some interesting behavior with web server response headers, not sure where to put the issue. Somewhere, I don't think it's here in ESP32SPI, but then must be either NINA FW or the depths of CP.

Headers not served by the current server are delivered back to the client. I see this on every HEAD or GET from virtually any site after the first site. After pulling a couple of pages from disparate sources, an accumulation of unique headers from prior server responses are presented to the client in response.headers along with the correct headers from the current site.

Clearing the response in the client using response = None does not clear the headers, the accumulated set of headers is still returned on subsequent calls.

failure to fetch data results in looping failures

While running the esp32spi_cheerlights.py example I have occasionally found it stuck in a loop of failures at https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI/blob/master/examples/esp32spi_cheerlights.py#L49

It typically runs for several hours before this failure occurs.

A simple workaround appears to be to add an

esp.reset()

when this error is detected - I am running a long test to see if I can catch the error and verify that it recovers. adding the esp.reset() before every "get" as a test seemed to work OK.

If this works - I'll put in PR's for the examples

Linking to or including ESP32 Firmware

I'm wondering if we should include the ESP32 firmware in the examples (along with instructions) or maybe even just link to it. Currently it's available at https://github.com/ladyada/CircuitPython_WiFi_Demos/blob/master/esp32program/NINA_W102.bin

and the command to flash it (on a Mac at least) is:
/usr/local/bin/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 115200 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0 NINA_W102.bin

Of course /dev/ttyUSB0 is bound to be different on different systems such as COM6 on windows. I believe there's a command to display this, but I couldn't find it just now. I think updating the guide (which it mentions should be soon) would take care of the instructions, but I'm wondering if we should include the firmware in the examples.

Expose additional NINA FW SPI command handlers (AKA Release the Kraken)

The ESP32 module used as an ESP32SPI co-processor is a bit of monolith. It does its job silently, in the dark, with no external user controls or indicators. But there is untapped power even as a co-processor.

This issue is an enhancement request to expose additional command handlers from CommandHandler.cpp from the adafruit/nina-fw, especially setPinMode, setDigitalWrite, and setAnalogWrite.

There are also other potentially interesting command handlers, but I'm not sure which are fully implemented even in the C code; I don't seem to get much meaningful returned from getTime or getTemperature for example (I could easily be doing something wrong).

In Arduino, the Airlift breakout can control its on-board red, green, and blue LEDs via the adafruit/WiFiNINA library. But for CircuitPython on a separate M4 processor, the ESP32SPI library would need to expose additional command handlers to be able to control the GPIO pins.

Potentially, many ESP32 co-processor pins could be made available to CircuitPython, depending on form factor:

• ESP 32 Airlift breakout GPIO/A pins:
25[Green LED], 26[Red LED], 27[Blue LED]

• ESP32 Huzzah32 breakout GPIO/A pins:
2, 4, 12, 13, 15, 16, 17, 19, 21, 22, 25, 26, 27, 32

• ESP32 Huzzah32 Feather GPIO/A pins:
A5/4, 12[PULLDOWN], 13[LED], 15, 16/RX, 17/TX, 19/MI, 21, 22/SCL, A1/25, A0/26, 27, 32

• ESP32 Airlift Feather GPIO/A pins:
25[Green LED], 26[Red LED], 27[Blue LED]

[ P.S. I spent several hours trying to do this myself, but between the python code, SPI protocol, and layers of C code, it's beyond my current level. I'll keep digging though. I'm sure someone more skilled in the arts would look at it and say "oh, of course you'd just..." ;-) ]

UDP send() does not clear esp32 write buffer

My Platform:

  • metro m4 airlift lite
  • adafruit nina-fw 1.7.3
  • circuitpython 6.2.0
  • April 20, 2021 library bundle

The problem:

udp.send() appends to the write buffer instead of replacing it. This results in the following behavior:

sock.send("line 1+\n")
sock.send("line 2++\n")
sock.send("line 3+++\n")

will actually send

line 1+             <--- datagram 1
line 1+             <--- datagram 2
line 2++               |
line 1+             <--- datagram 3
line 2++               |
line 3+++              |

and this continues until the esp32's internal write buffer is full. at which point calls to send() will only send the buffer and not append anything new.

The expected behavior is that a call to write() will send the provided data as a datagram packet and nothing else.

Why this happens

In the nina-fw WiFiUdp.c implementation we can see the following:

  • _sndSize tracks the write buffer size for the current packet
  • beginPacket() sets _sndSize to 0. This is the only place where _sndSize is set to 0.
  • endPacket() does not set _sndSize to 0.

The only nina-fw command that calls beginPacket() is the startTcpClient() command which, despite the outdated name, is also used to initialize UDP sockets.

sendUDPData() only calls endPacket(). It does not call beginPacket().

socket_write() has code roughly equivalent (with simplification and no handling of large buffers) to this:

if self.UDP_MODE:
    self._send_command_get_response(_INSERT_DATABUF_TCP_CMD, self._socknum_ll[0], memoryview(buffer))
    self._send_command_get_response(_SEND_UDP_DATA_CMD, self._socknum_ll)

_INSERT_DATABUF_TCP_CMD writes data to the UDP socket buffer, and then _SEND_UDP_DATA_CMD calls endPacket() which sends the current buffer as a datagram packet. beginPacket() is never called during a socket_write().

Workaround

Currently you can work around this problem by closing and re-opening the socket before every write. So every write() now becomes

sock.close()
sock.connect(socketaddr, conntype=esp.UDP_MODE)
sock.write()

The close() is necessary because connect() also opens a "server" port for receiving responses, and so connect() will fail if that server port is already open.

Potential fixes

It's not entirely clear to me whether this is a bug in esp32spi or in nina-fw. Changing esp32spi's socket_write to send a _START_SERVER_TCP_CMD message after sending _SEND_UDP_DATA_CMD would fix this issue. Changing nina-fw's sendUDPData() command to call beginPacket() again after endPacket() would also solve this issue. So would changing both to add a new command specifically to call beginPacket() into nina-fw and using it in esp32wifi.

So I'm happy to write a patch to fix this, but I don't know which project i should be writing the patch for.

Example code to cause this problem

import board
import time
from digitalio import DigitalInOut
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
from adafruit_esp32spi import adafruit_esp32spi
from secrets import secrets

esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)
spi = board.SPI()
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)


HOST = "192.168.1.100"
PORT = 3000


def connect():
    esp.reset()
    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])
    print("Connecting to AP...")
    while not esp.is_connected:
        try:
            esp.connect_AP(secrets["ssid"], secrets["password"])
        except RuntimeError as e:
            print("could not connect to AP, retrying: ", e)
            continue
    print("Connected to", str(esp.ssid, "utf-8"), "\tRSSI:", esp.rssi)
    print("My IP address is", esp.pretty_ip(esp.ip_address))

    

    socket.set_interface(esp)
    socketaddr = socket.getaddrinfo(HOST, PORT)[0][4]
    
    global sock
    sock = socket.socket(type=socket.SOCK_DGRAM)

    sock.connect(socketaddr, conntype=esp.UDP_MODE)


connect()

i = 0


while True:
    if esp.is_connected:
        sock.send("{}\n".format(i))
        i = i + 1
    else:
        print("wifi is down :<")
        sock.close()
        connect()
    time.sleep(1.0)

It took a long time to connect to WiFi.

i use raspberry pi zero with esp-wroom-32, it took too long to connect ap. about 30 sec

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"""
if self._debug:
print("Connect to AP", ssid, password)
if isinstance(ssid, str):
ssid = bytes(ssid, 'utf-8')
if password:
if isinstance(password, str):
password = bytes(password, 'utf-8')
self.wifi_set_passphrase(ssid, password)
else:
self.wifi_set_network(ssid)
for _ in range(10): # retries
stat = self.status
if stat == WL_CONNECTED:
return stat
time.sleep(1)
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)

Add a reconnect method to the WiFi manager

There is currently no single method way to reconnect the WiFi manager if the connection is lost. Currently it's a two step process:

wifi.reset()
wifi.connect()

It would be nice to have a single call to do this - wifi.reconnect()

Analog read

given the huzzah32 with it's battery & voltage divider attached directly to one of the analog pins; and the release the kraken patch, #34?, would it be possible to add an analog read function? and maybe a digital read?

I'd like to use the built in battery functionality of the huzzah32 to power a portion of a project; and possibly use it for supplementary IO; but i'd want to monitor the voltage. the added voltage regulator & power storage would be able to provide an easier way than making a voltage regulator tacked a feather & it's battery pin.

I don't pretend to understand the nina-fw and the command handler language; but it reminds me alot of arduino. after reading through it, would something like:

int setAnalogRead(const uint8_t command[], uint8_t response[])
{
uint8_t pin = command[4];
unit8_result = 255

result=analogRead(pin);

response[2] = 1; // number of parameters
response[3] = sizeof(result); // parameter 1 length
memcpy(&response[4], result, sizeof(result));

return 9;
}

be sufficient?

WiFiManager debug not working

An error is thrown upon connection if you set debug to true:

wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, None)
wifi.debug = True

File "adafruit_esp32spi/adafruit_esp32spi_wifimanager.py", line 108, in get
File "adafruit_esp32spi/adafruit_esp32spi_wifimanager.py", line 72, in connect
AttributeError: 'module' object has no attribute 'WL_IDLE_STATUS'

Also the status_pixel parameter is supposed to be optional, but it's not.

Unstable connectivity with Matrix Portal and most of the internet demos

Having issues w/ the Matrix Portal and the internet demos. The only internet demo that works is the Quote board matrix display.

Using adabox016 components
adafruit-circuitpython-matrixportal_m4-en_US-6.0.0-rc.1.uf2
adafruit-circuitpython-bundle-6.x-mpy-20201101.zip

It takes a very long time (~30seconds-1minute) to get a wifi connection and grab quotes with the Quote board matrix display.

Serial shows these types of errors while connecting -

Socket missing recv_into. Using more memory to be compatible
An error occurred, retrying! 1 - Failed to send 3 bytes (sent 0)

Again, the quotes demo is the only one that worked. Getting errors around adafruit_requests?) in both the weather clock and the demo that pulls examples from adafruit..

esp.disconnect leaves the ESP32 in a bad state

I am writing an application on a PyPortal that needs to talk to two access points. After connecting to the first and communicating via socket with a host there, I close the socket and do an esp.disconnect() to disconnect from the access point. This seems to work. The esp's status goes to WL_DISCONNECTED.
I then connect to the second access point with the esp's status going back to WL_CONNECTED. But, at that point the ESP seems to be in a bad state. Any function requiring communication with the AP fails, in one way or another. I wrote a simple test case that demonstrates the problem:

import board
from digitalio import DigitalInOut
import busio
import sys
from adafruit_esp32spi import adafruit_esp32spi
from adafruit_esp32spi import adafruit_esp32spi_socket

esp32_cs_pin = DigitalInOut(board.ESP_CS)
esp32_ready_pin = DigitalInOut(board.ESP_BUSY)
esp32_reset_pin = DigitalInOut(board.ESP_RESET)

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)

esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs_pin, esp32_ready_pin, esp32_reset_pin)

ssids = (('linkme', '***********'), ('corrigan', '**********'))
fwstr = str(esp.firmware_version, 'utf-8')

major, minor, sub = sys.implementation.version
print("Circuitpython {}.{}.{},  ESP32 firmware {}".format(major, minor, sub, fwstr))

test_ip = esp.unpretty_ip('192.168.43.148')
port = 65432

for ssid, password in ssids:
    print("Testing ssid = {}".format(ssid))

    # connect to an AP
    esp.connect_AP(ssid, password, timeout_s = 30)
    print("Create socket")

    # create a socket
    adafruit_esp32spi_socket.set_interface(esp)
    my_sock = adafruit_esp32spi_socket.socket()
    print("Connect socket")

    # connect to socket server on other system        
    my_sock.connect((test_ip, port))
    print("close socket")

    # close socket
    my_sock.close()
    print("disconnect from AP")

    # disconnect from AP
    esp.disconnect()    

The output is:

code.py output:
Circuitpython 6.1.0,  ESP32 firmware 1.7.3
Testing ssid = linkme
Create socket
Connect socket
close socket
disconnect from AP
Testing ssid = corrigan
Create socket
Connect socket
Traceback (most recent call last):
  File "code.py", line 35, in <module>
  File "adafruit_esp32spi/adafruit_esp32spi_socket.py", line 75, in connect
  File "/lib/adafruit_esp32spi/adafruit_esp32spi.py", line 783, in socket_connect
  File "/lib/adafruit_esp32spi/adafruit_esp32spi.py", line 685, in socket_open
  File "/lib/adafruit_esp32spi/adafruit_esp32spi.py", line 345, in _send_command_get_response
  File "/lib/adafruit_esp32spi/adafruit_esp32spi.py", line 296, in _wait_response_cmd
  File "/lib/adafruit_esp32spi/adafruit_esp32spi.py", line 199, in _wait_for_ready
RuntimeError: ESP32 not responding

Code done running.

Everything works for the first access point, and seems to work for the second until the attempt to connect the socket. It also fails in the same way if I re-connect to the first access point instead. Other functions also fail. For example, esp.get_host_by_name(host) fails with RuntimeError: Failed to request hostname.

A more elaborate test shows that after connecting to the second access point, the ESP32's internal state is inconsistent. Asking the ESP32 for the bssid and ssid that it is connected to show the second access point, but asking the ESP32 for its 'network data', gives back the ip address, and gateway of the first access point.

If I change the timeout in _wait_for_ready, I find that the socket.connect request actual finishes after 18 seconds (waiting for the response, the normal timeout is 10). But, when the socket.connect finishes, it is with a RuntimeError: Expected 01 but got 00, which is what you get when the connection fails.

If you do an esp.reset(), everything works again.

Runtime Errors in WiFiManager when posting in a loop

The following (simplified) code snippet:

while True:
    package = {
        some dictionary
    }
    try:
        wifi.post("http://159.69.220.75:8000/pub", json=package)
        print("+", end="")
    except (ValueError, RuntimeError):
        print("-", end="")
        wifi.reset()
        wifi.connect()
        print("reconnected")
    gc.collect()
    time.sleep(1)

leads to this output:

++++++++++-reconnected
++++++++++-reconnected
++++-reconnected
+++++++++-reconnected
++++++++++-reconnected
++++++++++-reconnected
++++++++++-reconnected
++++++++++-reconnected
++++++++++-reconnected
++++++++++-reconnected

So you can see that it pretty reliably does 10 requests, fails at the 11th and then resets.

Although it is easy to make your code robust against this issue, the consistency of the number of requests you can do makes me think that there might be a fixable underlying issue worth investigating.

Spaces in SSID results in couldn't connect and 'No such ssid'

Running the sample code from https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI/blob/master/examples/esp32spi_simpletest.py

On a PyPortal and using:

SSID: 'MY SSID NAME'
Password: 'My Super Secure WiFi Password'

Noting the SSID has a space in it.

esp.connect_AP(b'MY_SSID_NAME', b'MY_SSID_PASSWORD')

results in:

ESP32 found and in idle mode
Firmware vers. bytearray(b'1.2.2\x00')
MAC addr: ['0xAA', '0xBB', '0xCC', '0xDD', '0x00', '0x11']
        MY SSID NAME            RSSI: -56
        NeighborFi              RSSI: -57
        OtherNeighborFi           RSSI: -57
        BillWitheScienceFi         RSSI: -57
        MY SSID NAME        RSSI: -57
        Linksys        RSSI: -57
        Open Free Wifi        RSSI: -57
`could not connect to AP, retrying:  ('No such ssid', b'MY SSID NAME')`

Also noting that, yes, I'm running multiple access points with MY SSID NAME, they are working fine particularly with other ESP32 and ESP8266 devices that don't happen to run CircuitPython.

Switching to an SSID without spaces works fine however. Tested against several (4) networks that work that have spaces in them, and against one that does not. Failed, identically, on the 4 networks with spaces, and worked fine with the network that did not.

Documentation on status LED?

I can't seem to find documentation on how this library controls the NeoPixel on my MatrixPortal. Could someone please point me to where I could find that?

Radio and Connection Sleep/Reopen

This is an enhancement request to provide for dropping a connection and shutting off the radio after a specified time period of no use or after a fixed time period. Upon request e.g. post(), WifiManager will turn on the radio and reestablish the connection and reset the timer. This could be useful for battery-powered projects where always-on radio and connections will drain the battery quickly.

Implement Digital Read & Analog Read counterparts to proposed NINA FW command handlers

@docmollo, @brentru, @tannewt, @ladyada

I'm moving the discussion here for the ESP32SPI side of handling analog and digital reads from ESP32 hardware in the context of CircuitPython ESP32SPI. This issue consolidates #46 (which could be closed since it's subsumed under this one), and the later discussions in #74 (read there for more background on this issue) which were only tangentially related to that issue and will (hopefully) be closed soon (PR submitted).

The present enhancement proposal is to:

  1. Implement setDigitalRead() and setAnalogRead() command handlers in the Adafruit fork of the NINA firmware. setPinMode() already exists. setDigitalWrite() and setAnalogWrite() also already exist. An issue or PR needs to be expanded or opened on the NINA side for this.
  2. Implement set_digital_read() and set_analog_read() in adafruit_esp32spi.py. set_pin_mode() is already implemented. set_digital_write() and set_analog_write() are also already implemented.
  3. Expand the ESP32SPI digitalio.py module for digital reads.
  4. Create an ESP32SPI analogio.py module for analog writes and reads.

Implementation could be roughly in this order. Complete low-level functionality would become available with items 1 and 2 above. Then, expanding ESP32SPI digitalio and adding ESP32SPI analogio would provide higher-level class interfaces analogous to Circuitpython digitalio and analogio usage.

MatrixPortal won't soft reboot using esp.reset()

Using firmware version 1.7.1 and CircuitPython 6.0.0 rc2 I'm not able to soft reboot via esp.reset(). Example code is shown below. It's as if esp.reset() simply acts as a no-op.

I am occasionally getting an 'ESP not responding' error which I'm trying to consistently reproduce. But in the meantime I'm not able to recover from the error by forcing a reset.

from adafruit_esp32spi import adafruit_esp32spi
import digitalio
import busio
import board

esp32_ready = digitalio.DigitalInOut(board.ESP_BUSY)
esp32_gpio0 = digitalio.DigitalInOut(board.ESP_GPIO0)
esp32_reset = digitalio.DigitalInOut(board.ESP_RESET)
esp32_cs = digitalio.DigitalInOut(board.ESP_CS)

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)

esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset, esp32_gpio0)

firmware_version = str(esp.firmware_version, "utf-8")

print(f"ESP Firmware Version: {firmware_version}")

print("resetting...")
esp.reset()
print("done resetting.")

Variable Request Timeouts

adafruit_esp32spi_requests.py request() sets socks.settimeout() to 1 second. This is fine in many cases, but due to server, traffic, and various other issues, it may not be enough to reliably fetch data. Retries can partially resolve this, but more user control over timeouts would give users the ability to make their own trade-offs between speed and reliability.

I'd propose initially making the timeout within request() into a keyword argument with default of 1 second, and rippling it up to WiFiManager and device-specific classes like PyPortal.

Other than ping ttl and hard-coded delays and timeouts deep in ESP_SPIcontrol, everything in ESP32SPI appears to rely on the 1-second timeout set in the request (notably in socket read and readline). Other than ping and wifi scans, NINA firmware doesn't seem to introduce any substantial delays or timeouts that I could find. I'm not sure what the ESP core does. I haven't tested to determine if there's a max name lookup time within the system (DNS servers will eventually time out and provide an error response).

Ideally (long-term), perhaps users could have separate control over timeouts for name lookup, connections, and requests. In theory, CircuitPython users would typically be fetching more concise payloads than a typical web user, but for reference, browsers have many-second timeouts for connections and requests. cURL also has separate connection and overall timeouts, with relatively high defaults (300 on connection, ∞ on the overall request). We don't need to be concerned about persistent connections for now since ESP32SPI uses HTTP/1.0 and there is no keep-alive.

ESP_SPIcontrol._wait_for_ready is eating lots of time polling the READY/BUSY pin

Context:
#106
https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI/blob/master/adafruit_esp32spi/adafruit_esp32spi.py#L176

I haven't verified this exhaustively, but as far as I can tell, practically every method in ESP_SPIcontrol will at some point call _wait_for_ready somewhere in it's call stack.

I've got a simple sensor logger that's calling IO using an airlift, and round trip for a successful post is on average about 8 seconds. Only about 2-3 seconds of that is actually opening sockets, sending, receiving, parsing, etc, the rest of the time we're waiting for the ESP32.

This means that until I added the hack in the PR above, I couldn't have a UI. The hack was admittedly a hack so I closed it, but this is a problem that should be solved one way or another

@tannewt suggested starting on the async/concurrency project which would be nice, but I don't see that being done any time soon and it would be nice to have this addressed in some capacity before then

PyPortal download fails

Hi folks, I have a project that needs the PyPortal to download multiple .wav, .bmp, and .json files from a server. It then caches them on the SD card.

I am getting these errors when downloading multiple files:
Fetching stream from http://api.atmakers.org/sounds/Joey/next.wav Traceback (most recent call last): File "code.py", line 92, in <module> File "code.py", line 54, in loadBoard File "code.py", line 42, in cacheFile File "adafruit_pyportal.py", line 600, in wget File "adafruit_esp32spi/adafruit_esp32spi_requests.py", line 241, in get File "adafruit_esp32spi/adafruit_esp32spi_requests.py", line 226, in request File "adafruit_esp32spi/adafruit_esp32spi_socket.py", line 153, in close File "adafruit_esp32spi/adafruit_esp32spi.py", line 618, in socket_close File "adafruit_esp32spi/adafruit_esp32spi.py", line 308, in _send_command_get_response File "adafruit_esp32spi/adafruit_esp32spi.py", line 297, in _wait_response_cmd File "adafruit_esp32spi/adafruit_esp32spi.py", line 281, in _wait_response_cmd File "adafruit_esp32spi/adafruit_esp32spi.py", line 257, in _wait_spi_char RuntimeError: Error response to command

If I rerun, it succeeds in that file just to fail a few files further down the list.

I am running CP 4.0.1 and the latest published 4.x libraries. Is there an ESP update I'm missing? If so, how do I tell?

(On a separate note, I am still getting hard crashes into safe mode after a minute or so... I'll file that in a separate issue if an update doesn't fix it).

adafruit_esp32spi_socket.py:readline hardcoded end of line marker

readline in adafruit_esp32spi_socket uses a hardcoded end of line marker as '\r\n', this obviously does not work for all systems, it should be made definable.

I have updated the routine to do this and tested it out on a pyportal but do not have permissions to push a new branch back to the repo, please see the attached updated code (used a .txt suffix as .py is not allowed)

adafruit_esp32spi_socket.py.txt

regards,
Grae Morrison

PyPortal pynt WiFi not working

I just received 2 pyportals, a normal and a pynt. The normal works fine but the pynt cannot connect to my home AP. I have tried CP versions 4.0.0-beta5, 4.1.2 and 5.0.0-beta4.

The home AP gives the message 'No such ssid'. It has spaces in the name, no idea if that is relevant.

I am able to intermittently connect to my iphone (no spaces in the SSID) but it usually fails with 'Failed to connect to ssid'. Even when it does connect, I not able retrieve data over WiFi.

parse_header Error trying to import adafruit_esp32spi.adafruit_esp32spi_wsgiserver

I'm new to the entire CircuitPython library.
Was following an online example to create a HTTP server and this line in the example is throwing an error...

import adafruit_esp32spi.adafruit_esp32spi_wsgiserver as server

Error is..

Traceback (most recent call last):
  File "code.py", line 1, in <module>
  File "adafruit_esp32spi/adafruit_esp32spi_wsgiserver.py", line 34, in <module>
ImportError: cannot import name parse_headers

I do have the adafruit_requests library installed.

But maybe I have something incorrect in my installation.
I do have other things working using CircuitPython so in general I am running code fine.

No recovery after Timed out waiting for SPI char

I have an application that polls a couple of endpoints, with adafruit_requests, every few seconds and makes a nice display. Every few minutes adafruit_requests fails with: "Timed out waiting for SPI char" in adafruit_esp32spi.py line 271. Once this happens the stack becomes permanently borked with all subsequent calls failing with the same error. The only way to recover that I've found is to reboot.

This happens with 2 pyportals, 2 physically different networks and multiple USB cables.

Firmware: 1.2.2 and 1.6.1 (current stable)
Circuit python: 4.something and 5.3.0 (current stable)
Libraries: 4.something and 5.x (current stable)

The following code reproduces the problem about 90% of the time with an occasional success in the second GET and occasionally a different error.

import time
import board
import busio
from digitalio import DigitalInOut
from adafruit_esp32spi import adafruit_esp32spi
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
import adafruit_requests as requests
from secrets import secrets

# Non existent endpoint
BAD_DATA_SOURCE = "http://1.2.3.4/hello"

# Good data source
# GOOD_DATA_SOURCE = "http://httpbin.org/get"
GOOD_DATA_SOURCE = 'http://54.236.246.173/get'

# Start WiFi
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_gpio0 = DigitalInOut(board.ESP_GPIO0)
esp32_reset = DigitalInOut(board.ESP_RESET)
esp32_cs = DigitalInOut(board.ESP_CS)

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset, esp32_gpio0)

requests.set_socket(socket, esp)

print("MAC: " + ':'.join('{:02x}'.format(x) for x in reversed(esp.MAC_address)))
print("Connecting to AP...")
while not esp.is_connected:
  try:
    esp.connect_AP(secrets['ssid'], secrets['password'])
  except RuntimeError as e:
    print("could not connect to AP, retrying: ",e)
    continue
print("Connected to", str(esp.ssid, 'utf-8'), "\tRSSI:", esp.rssi)
print("Firmware vers.", esp.firmware_version)
print("My IP address is", esp.pretty_ip(esp.ip_address))


try:
  r = requests.get(BAD_DATA_SOURCE)
except RuntimeError as e:
  # Timed out waiting for SPI char
  # A failure here is to be expected
  print(e)


# This GET always fails
r = requests.get(GOOD_DATA_SOURCE)
print(r.text)

Request to local IP does not work

All library versions are from the adafruit-circuitpython-bundle-6.x-mpy-20210612 bundle.

  • adafruit_apds9960
  • adafruit_ble
  • adafruit_bluefruit_connect
  • adafruit_bus_device
  • adafruit_esp32spi
  • adafruit_lsm6ds
  • adafruit_register
  • adafruit_bmp280.mpy
  • adafruit_lis3mdl.mpy
  • adafruit_requests.mpy
  • adafruit_sht31d.mpy
  • neopixel.mpy

Not sure if this is the correct project to report this in.

I just set up a Feather nRF52840 Sense with an AirLift FeatherWing, and while all of the example code works (all of this works), I am having some issues trying to set up something a little more custom.

I am running into an issue sending a request to a local IP. I am running a flask server from a Raspberry Pi with a simple GET endpoint exposed. The endpoint works perfectly fine when hitting it with Postman, but when trying to hit it using adafruit_esp32spi, I receive an odd error. I tried digging into the source here as well as in adafruit_requests, but I couldn't figure anything out.

My simple flask server (ultimately running at http://127.0.0.1:5000 with the endpoint boop):

import json
from flask import Flask

app = Flask(__name__)

@app.route('/boop', methods=['GET'])
def boop():
    return json.dumps({'success':True}), 200, {'ContentType':'application/json'} 

if __name__ == '__main__':
    app.run(debug=True)

Code I am running on the Sense/Airlift:

# SPDX-FileCopyrightText: 2019 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
import board
import busio
from digitalio import DigitalInOut
import adafruit_requests as requests
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
from adafruit_esp32spi import adafruit_esp32spi

# Get wifi details and more from a secrets.py file
try:
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in secrets.py, please add them there!")
    raise

print("ESP32 SPI webclient test")

LOCAL_URL = "http://127.0.0.1:5000/boop"

esp32_cs = DigitalInOut(board.D13)
esp32_ready = DigitalInOut(board.D11)
esp32_reset = DigitalInOut(board.D12)

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)

socket.set_interface(esp)
requests.set_socket(socket, 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"]))

print("Connecting to AP...")
while not esp.is_connected:
    try:
        esp.connect_AP(secrets["ssid"], secrets["password"])
    except RuntimeError as e:
        print("could not connect to AP, retrying: ", e)
        continue
print("Connected to", str(esp.ssid, "utf-8"), "\tRSSI:", esp.rssi)
print("My IP address is", esp.pretty_ip(esp.ip_address))

esp._debug = True

r = requests.get(LOCAL_URL)
print("-" * 40)
print(r.text)
print("-" * 40)
r.close()

print("Done!")

And here is the output when I run everything (networks redacted):

code.py output:
ESP32 SPI webclient test
ESP32 found and in idle mode
Firmware vers. bytearray(b'1.2.2\x00')
MAC addr: ['0x64', '0x8d', '0xb8', '0x57', '0xdd', '0xc4']
        Home          RSSI: -46
Connecting to AP...
Connected to Home     RSSI: -46
My IP address is 10.0.0.123
*** Get host by name
*** Get socket
Allocated socket #0
*** Socket connect mode 0
*** Open socket to bytearray(b'\x7f\x00\x00\x01') 5000 0
Traceback (most recent call last):
  File "code.py", line 52, in <module>
  File "adafruit_requests.py", line 684, in get
  File "adafruit_requests.py", line 562, in request
  File "adafruit_requests.py", line 454, in _get_socket
  File "adafruit_requests.py", line 448, in _get_socket
  File "adafruit_esp32spi/adafruit_esp32spi_socket.py", line 75, in connect
  File "adafruit_esp32spi/adafruit_esp32spi.py", line 761, in socket_connect
  File "adafruit_esp32spi/adafruit_esp32spi.py", line 663, in socket_open
  File "adafruit_esp32spi/adafruit_esp32spi.py", line 325, in _send_command_get_response
  File "adafruit_esp32spi/adafruit_esp32spi.py", line 308, in _wait_response_cmd
  File "adafruit_esp32spi/adafruit_esp32spi.py", line 295, in _wait_response_cmd
  File "adafruit_esp32spi/adafruit_esp32spi.py", line 277, in _check_data
RuntimeError: Expected 01 but got 00

Code done running.

Thanks in advance for any information, insight, or help!

Can not get it to work on Feather M4 + AirLift: RuntimeError: Error response to command

I have a Feather M4 Express with an AirLift FeatherWing. They are not stacked but sit next to each other on a breadboard. They share a common ground and get +5V through the VUSB pin. I believe I have connected all required (and more) pins: SCK, MOSI, MISO, RX, TX, as well as D10, D11, D12, D13.

I'm running CircuitPython 6.0.1 (or 6.1.0rc0 and lately 6.1.0-rc.0-13-g6abf0a5d1, but same error there) and the latest libraries and bootloader v3.10.0.

This simple program fails:

from adafruit_esp32spi import adafruit_esp32spi
from digitalio import DigitalInOut
from busio import SPI
import board 

esp32_cs    = DigitalInOut(board.D13)
esp32_ready = DigitalInOut(board.D11)
esp32_reset = DigitalInOut(board.D12)

spi = SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)

if esp.status == adafruit_esp32spi.WL_IDLE_STATUS:
  print("ESP32 Firmware v{}, MAC: {}".format(esp.firmware_version.decode('ascii'), ':'.join('%02X' % b for b in esp.MAC_address_actual)))

  for ap in esp.scan_networks():
    print("\t%s\t\tRSSI: %d" % (str(ap['ssid'], 'utf-8'), ap['rssi']))
  else:
    print("ESP not in idle state!")

And this is the output:

ESP32 Firmware v1.2.2, MAC: B8:F0:09:95:BD:7C
Traceback (most recent call last):
  File "code.py", line 466, in <module>
  File "adafruit_esp32spi/adafruit_esp32spi.py", line 402, in scan_networks
  File "adafruit_esp32spi/adafruit_esp32spi.py", line 379, in get_scan_networks
  File "adafruit_esp32spi/adafruit_esp32spi.py", line 308, in _wait_response_cmd
  File "adafruit_esp32spi/adafruit_esp32spi.py", line 292, in _wait_response_cmd
  File "adafruit_esp32spi/adafruit_esp32spi.py", line 268, in _wait_spi_char
RuntimeError: Error response to command

So clearly the Feather M4 can communicate with the AirLift featherwing (it retrieves the firmware version and MAC) but I can't execute any commands (every _send_command call fails). It also needs a hardware reset to get back to the same state, otherwise all following commands return a different error: RuntimeError: Timed out waiting for SPI char.

set_analog_read value returned

issue or not, looking for some clarification as to why.

when set_analog_read is returned, the result is passed but first multiplied by 16.

This means the resultant value has to be divided by 16 to get an accurate value. is there a reason for this? i used a huzzah32, with a voltage divider of :2 with 2 100k ohm resisters tied to a lipo battery and to an analog pin.

the resultant formula should be

battery=esp.set_analog_read()/4096*7.445

however, since the ESP32SPI passes back the value multiplied by 16 it didn't work and took me forever to figure out why. the docs didn't make it quite clear that to get an accurate number you needed to divide it by 16. i know it mentions the range being 0-65536, but as there are no examples, and any examples in arduino and the traditional way of doing analog reads aren't pre-ranged, it makes it very confusing to try and back track/read through the libraries to figure out whats wrong.

Using Adafruit.io weather API, responses often truncated

I've tried adapting the PyPortal weather example to use the Dark Sky data from Adafruit.io

I'm still using the PyPortal library from adafruit_pyportal as in the original code.

When pyportal.fetch() is called, at least 50% of the time the JSON is truncated, resulting in an exception for json.loads.

I've noticed that successful fetches gather around 6k of data and the failing ones are all truncated at 3214 bytes (this is the length of the results of the pyportal.fetch, so I don't believe it has headers in it)

Please Advise.

Thanks!

requests fails sending large header values or paths over socket

I'm trying to make an HTTP request with a ~356 byte access token, and when making the request via requests.get(...) it fails with:

Failed to send 363 bytes (sent 107)

With the ESP's _debug turned on, I see something like this (redacted for token privacy):

...
*** Get host by name
*** Get socket
Allocated socket #0
*** Socket connect mode 2
*** Open socket
Writing: b'GET /microsub/1?action=timeline&channel=duQSjrTyDhvn2BQvrs7jLkV5v4Q4ZYw3 HTTP/1.0\r\n'
Writing: b'Host: aperture.maktro.net\r\n'
Writing: b'User-Agent: Adafruit CircuitPython\r\n'
Writing: b'authorization'
Writing: b': '
Writing: b'Bearer XXXX...FOR_356_BYTES...XXX'
Failed to send 363 bytes (sent 107)
...

The server I'm talking to allows me to pass the token in the query string, but I end up with a very similar error (failing on the GET /microsub/1?... line).

If I truncate the value of the access token so it's less than ~100 bytes, the request goes through, but the server of course fails it because it's not a valid access token.

It looks like I'm running into an issue with this code: https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI/blob/master/adafruit_esp32spi/adafruit_esp32spi.py#L535

Is it possible to have the requests lib chunk these sends over the socket?

Thanks!!

change local time example to use adafruit.io

Should the esp32spi_localtime.py example be updated to use adafruit.io instead of worldtimeapi as was done for PyPortal?
Would it be good to show how to use both? Two examples or use comment blocks to allow either?

Or just close this if you want to leave it as is?

json error in get

I was trying to test @brentru adafruit_io library and started getting jason errors when trying to use his "get_all_feeds" function -- I then tried the same "get" just using esp32spi (via wifimanager) and get the same error so there seems to be an underlying issue in esp32spi

here is the test case

import time
import board
import busio
from digitalio import DigitalInOut

from adafruit_esp32spi import adafruit_esp32spi
from adafruit_esp32spi import adafruit_esp32spi_wifimanager

print("ESP32 SPI webclient test")

# Get wifi details and more from a settings.py file
try:
    from esp32spi_settings import settings
except ImportError:
    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)
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, settings, board.NEOPIXEL)
esp._debug=True
while True:
    try:
        print("Get data...", end='')
        response = wifi.get(
            "https://io.adafruit.com/api/v2/"+settings['aio_username']+"/feeds",
            headers={bytes("X-AIO-KEY","utf-8"):bytes(settings['aio_key'],"utf-8")})
        print(response.json())
        response.close()
        print("OK")
    except (ValueError, RuntimeError) as e:
        print("Failed to get data, retrying\n", e)
        wifi.reset()
        continue
    response = None
    time.sleep(15)


here is the log -- with some repeated lines removed



Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 4.0.0-beta.2-97-g0dc260058 on 2019-02-19; Adafruit Feather nRF52840 Express with nRF52840
>>> 
>>> import aio_get_esp32spi
ESP32 SPI webclient test
Get data...Connection status
Conn status: 0
Connection status
Conn status: 0
Connect to AP b'REDACTED' b'REDACTED'
Connection status
Conn status: 1

repeated lines removed

Connection status
Conn status: 1
Connection status
Conn status: 3
Connection status
Conn status: 3
*** Get host by name
*** Get socket
Allocated socket #0
*** Socket connect mode 2
*** Open socket
Writing: b'GET /api/v2/REDACTED/feeds HTTP/1.0\r\n'
Writing: b'Host: io.adafruit.com\r\n'
Writing: b'User-Agent: Adafruit CircuitPython\r\n'
Writing: b'X-AIO-KEY'
Writing: b': '
Writing: b'REDACTED'
Writing: b'\r\n'
Writing: b'\r\n'
ESPSocket: 0 bytes available
ESPSocket: 0 bytes available

repeated lines removed

ESPSocket: 0 bytes available
ESPSocket: 0 bytes available
ESPSocket: 8308 bytes available
Reading 4000 bytes from ESP socket with status 4
ESPSocket: 4308 bytes available
Reading 4000 bytes from ESP socket with status 4
ESPSocket: 308 bytes available
Reading 308 bytes from ESP socket with status 4
ESPSocket: 0 bytes available
Failed to get data, retrying
 syntax error in JSON
Reset ESP32

Adding HTTP request headers doesn't work (adafruit_esp32spi_requests.py)

There is a facility for any HTTP request (HEAD, GET, POST, etc.) to have optional user-specified HTTP headers added. For example, 'Http-X-MyCustomHeader: BlahBlahBlah'.

def request(method, url, data=None, json=None, headers=None, stream=False):
...'headers' is optional HTTP headers sent along.

Current version pieces together the header components to write the header to the socket based on user-specified dict containing one or more key-value pairs describing the header name and value, but there's a runtime error when trying to process the dictionary I believe due to unencoded string elements of the headers:

  File "/lib/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py", line 110, in get
  File "/lib/adafruit_esp32spi/adafruit_esp32spi_requests.py", line 235, in get
  File "/lib/adafruit_esp32spi/adafruit_esp32spi_requests.py", line 221, in request
  File "/lib/adafruit_esp32spi/adafruit_esp32spi_requests.py", line 176, in request
  File "/lib/adafruit_esp32spi/adafruit_esp32spi_socket.py", line 82, in write
  File "/lib/adafruit_esp32spi/adafruit_esp32spi.py", line 531, in socket_write
  File "/lib/adafruit_esp32spi/adafruit_esp32spi.py", line 298, in _send_command_get_response
  File "/lib/adafruit_esp32spi/adafruit_esp32spi.py", line 210, in _send_command
TypeError: can't convert str to int

To fix, I think it's just a matter of changing lines 176 & 178 in adafruit_esp32spi_requests.py to encode the strings into (default ASCII) bytestrings, changing from:

        for k in headers:
            sock.write(k)
            sock.write(b": ")
            sock.write(headers[k])
            sock.write(b"\r\n")

to:

        for k in headers:
            sock.write(k.encode())
            sock.write(b": ")
            sock.write(headers[k].encode())
            sock.write(b"\r\n")

I tested it in a basic scenario, and the program runs, and I receive the custom request headers on my server. But I'd really appreciate more seasoned Python eyes looking at this.

hang during get

Not much to go on, but I wanted to document this as well as I can:
I was running the cheerlights demo overnight. In the morning I noticed it was not updating and appeared to just be hung. I entered control-C ather REPL and this is the traceback:

Fetching json from https://api.thingspeak.com/channels/1417/feeds.json?results=1
Traceback (most recent call last):
  File "code.py", line 51, in <module>
  File "code.py", line 41, in <module>
  File "adafruit_esp32spi/adafruit_esp32spi_wifimanager.py", line 114, in get
  File "adafruit_esp32spi/adafruit_esp32spi_requests.py", line 229, in get
  File "adafruit_esp32spi/adafruit_esp32spi_requests.py", line 215, in request
  File "adafruit_esp32spi/adafruit_esp32spi_requests.py", line 188, in request
  File "adafruit_esp32spi/adafruit_esp32spi_socket.py", line 88, in readline
  File "adafruit_esp32spi/adafruit_esp32spi.py", line 545, in socket_available
  File "adafruit_esp32spi/adafruit_esp32spi.py", line 299, in _send_command_get_response
  File "adafruit_esp32spi/adafruit_esp32spi.py", line 288, in _wait_response_cmd
  File "adafruit_esp32spi/adafruit_esp32spi.py", line 285, in _wait_response_cmd
KeyboardInterrupt:

It appears to have been stuck in _waot_response_cmd()

That's all the information I have at this point.

Expose more NINA FW SPI command handlers: getCurrBSSID, getIdxBSSID, getIdxChannel

These handlers are useful for general LAN troubleshooting, especially in networks with multiple APs having the same SSID (sometimes called 'roaming networks').

I have working code, will test more then submit a PR.

NINA FW SPI command handlers not defined or implemented in esp32spi.py after this PR:

  • setKey
  • setIPconfig
  • setDNSconfig
  • setHostname
  • setPowerMode
  • getTemperature (I tried, always returns 128. After some checking looks like it's unsupported.
  • sendUDPdata
  • getRemoteData (to be exposed as part of #69 )
  • insertDataBuf
  • wpa2EntSetCACert
  • wpa2EntSetCertKey

EDIT: Found these later. Their counterparts are defined in esp32spi.py, but unimplemented:

  • getCurrEnct
  • getDataTcp
  • disconnect

Potential new command handlers:

I submitted an issue awhile back in the Arduino NINA repo to add a digitalRead command handler, but the devs closed it as "wontfix". There's also an open issue there for analogRead. Not sure why they closed digitalRead but left analogRead open.

Also not sure how much Adafruit wants its NINA fork to deviate from Arduino... could submit issues to the Adafruit NINA repo for the read handlers?

RGB LED doesn't turn off on arduino nano connect 2040

The following code on the Arduino Nano Connect 2040 results in a dim white light:

import time
import board
import busio
from digitalio import DigitalInOut
from adafruit_esp32spi import adafruit_esp32spi
esp32_cs = DigitalInOut(board.CS1)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)
spi = busio.SPI(board.SCK1, board.MOSI1, board.MISO1)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)

# The LED-related part:

import adafruit_rgbled
from adafruit_esp32spi import PWMOut

LEDR = 27
LEDG = 25
LEDB = 26

RED_LED = PWMOut.PWMOut(esp, LEDR)
GREEN_LED = PWMOut.PWMOut(esp, LEDG)
BLUE_LED = PWMOut.PWMOut(esp, LEDB)
status_light = adafruit_rgbled.RGBLED(RED_LED, GREEN_LED, BLUE_LED, invert_pwm=True)

status_light.color = (0,0,0)

To be able to turn it off, I used esp.set_digital_write and ended up changing the PWM pin to digital when the duty cycle is 0 or 100% like this:

class PWMOut2(PWMOut.PWMOut):
    @property
    def duty_cycle(self):
        return super().duty_cycle()

    @duty_cycle.setter
    def duty_cycle(self, duty_cycle):
        self._is_deinited()
        if not isinstance(duty_cycle, (int, float)):
            raise TypeError("Invalid duty_cycle, should be int or float.")
        duty_cycle /= 65535.0
        if not 0.0 <= duty_cycle <= 1.0:
            raise ValueError("Invalid duty_cycle, should be between 0.0 and 1.0")
        # If the value is 0 or 1, turn into a digital pin instead of PWM
        if duty_cycle == 0.0:
            self._esp.set_pin_mode(self._pwm_pin,1)
            self._esp.set_digital_write(self._pwm_pin, False)
        elif duty_cycle == 1.0:
            self._esp.set_pin_mode(self._pwm_pin,1)
            self._esp.set_digital_write(self._pwm_pin, True)
        else:
            self._esp.set_analog_write(self._pwm_pin, duty_cycle)

RED_LED = PWMOut2(esp, LEDR)
GREEN_LED = PWMOut2(esp, LEDG)
BLUE_LED = PWMOut2(esp, LEDB)
status_light = adafruit_rgbled.RGBLED(RED_LED, GREEN_LED, BLUE_LED, invert_pwm=True)

status_light.color = (0,0,0)

This might be an issue with the Nina firmware or the board's design, but I wonder if it would be ok to have that kind of things in the base code, or if it would be better to make a community library for the Nano.

WSGI Server example fails trying to import `parse_headers`

>>> import server_test
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "server_test.py", line 9, in <module>
  File "adafruit_esp32spi/adafruit_esp32spi_wsgiserver.py", line 53, in <module>
ImportError: cannot import name parse_headers

there is no parse_headers in adafruit_requests, it was inlined into the body of the request method

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.