CircuitPython — как подключить Adafruit esp32 AirLift к Adafuit HttpServer — несовместимый объект сокета

Я создаю метеостанцию CircuitPython на основе платы Adafruit M4 с модулем Adafruit ESP32 AirLift. Оба прекрасно работают вместе, когда дело доходит до HTTP-вызовов (через библиотеку Adafruit_requests). Однако вместо этого я хотел бы создать HTTP-сервер, обслуживающий данные о погоде. И вот проблема: все примеры Adafuit основаны на платах ESP32 или Raspberry Pico, изначально оснащенных WIFI. Плата Adafuit M4 не имеет таких же основных пакетов Python, поскольку на ней нет WIFI. Таким образом, пример, написанный для Pico, не работает на M4 с ESP AirLift, для этого не хватает ряда пакетов (например, wifi и socket), вместо этого необходимо использовать пакет adafuit_esp. Однако этот пакет кажется несовместимым с Adafuit HTTPServer: https://docs.circuitpython.org/projects/httpserver/en/stable/index.html HttpServer требует объект сокета в качестве параметра для инициализации:

esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
socket.set_interface(esp)
server = HTTPServer(socket)

этот код не работает, когда я пытаюсь запустить сервер:

try:
    server.start(esp.pretty_ip(esp.ip_address))
    print("Listening on http://%s:80" % esp.pretty_ip(esp.ip_address))
#  if the server fails to begin, restart the pico w
except OSError:
    time.sleep(5)
    print("restarting..")
    microcontroller.reset()

и ошибка:

>>> %Run -c $EDITOR_CONTENT
Creating display
Creating server socket
ESP32 found and in idle mode
Firmware vers. bytearray(b'1.2.2\x00')
MAC addr: ...
...
Connecting to AP...
Connected to jama   RSSI: -27
My IP address is 192.168.0.24
Creating HTTP Server...
starting server..
Traceback (most recent call last):
  File "<stdin>", line 175, in <module>
  File "adafruit_httpserver/server.py", line 91, in start
AttributeError: 'socket' object has no attribute 'bind'
>>> 

Похоже, это не тот разъем? он работает для библиотек ESP и Requests, но не для HTTPServer.

Вот импорт:

from adafruit_esp32spi import adafruit_esp32spi
import adafruit_esp32spi.adafruit_esp32spi_socket as socket

Тогда мой вопрос (или два) заключается в том, знает ли кто-нибудь обходной путь для этой проблемы. и/или другой пакет сокета или сервера, который я могу использовать вместо этого?

Вот полный код для справки, он не закончен и содержит больше вещей, описанных здесь, но не связанных с проблемой:

import os
import time
import busio
import board
import microcontroller
from digitalio import DigitalInOut, Direction
import adafruit_bh1750
# import adafruit_requests as requests
from adafruit_bme280 import basic as adafruit_bme280
from adafruit_httpserver.server import HTTPServer
from adafruit_httpserver.request import HTTPRequest
from adafruit_httpserver.response import HTTPResponse
from adafruit_httpserver.methods import HTTPMethod
from adafruit_httpserver.mime_type import MIMEType
from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.il0373 import Adafruit_IL0373
from adafruit_esp32spi import adafruit_esp32spi
import adafruit_esp32spi.adafruit_esp32spi_socket as socket

try:
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in secrets.py, please add them there!")
    raise


#  onboard LED setup
# led = DigitalInOut(board.LED)
# led.direction = Direction.OUTPUT
# led.value = False

i2c = board.I2C()  # uses board.SCL and board.SDA
bh1750 = adafruit_bh1750.BH1750(i2c)
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c, 0x76)
bme280.sea_level_pressure = 1012.50

spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
ecs = DigitalInOut(board.D9)
dc = DigitalInOut(board.D10)
srcs = DigitalInOut(board.D6)  # can be None to use internal memory
rst = None #DigitalInOut(board.D1)  # can be None to not use this pin
busy = None #DigitalInOut(board.D5)  # can be None to not use this pin

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

print("Creating display")
display = Adafruit_IL0373(
    128,
    296,  # 2.9" Tri-color display
    spi,
    cs_pin=ecs,
    dc_pin=dc,
    sramcs_pin=srcs,
    rst_pin=rst,
    busy_pin=busy,
)

display.set_black_buffer(1, True)
display.set_color_buffer(1, True)
display.rotation = 1
display.fill(Adafruit_EPD.WHITE)
# display.display()
# display.text(splash, 12, 12, Adafruit_EPD.BLACK, size=1)

#  connect to network
print("Creating server socket")
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
socket.set_interface(esp)

if esp.status == adafruit_esp32spi.WL_IDLE_STATUS:
    print("ESP32 found and in idle mode")
print("Firmware vers.", esp.firmware_version)
print("MAC addr:", [hex(i) for i in esp.MAC_address])

for ap in esp.scan_networks():
    print("\t%s\t\tRSSI: %d" % (str(ap["ssid"], "utf-8"), ap["rssi"]))

print("Connecting to AP...")
while not esp.is_connected:
    try:
        esp.connect_AP(secrets["ssid"], secrets["password"])
    except OSError 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))

print("Creating HTTP Server...")
server = HTTPServer(socket)

#  font for HTML
font_family = "monospace"

#  the HTML script
#  setup as an f string
#  this way, can insert string variables from code.py directly
#  of note, use {{ and }} if something from html *actually* needs to be in brackets
#  i.e. CSS style formatting
def webpage():
    html = f"""
    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="Content-type" content="text/html;charset=utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
    html{{font-family: {font_family}; background-color: lightgrey;
    display:inline-block; margin: 0px auto; text-align: center;}}
      h1{{color: deeppink; width: 200; word-wrap: break-word; padding: 2vh; font-size: 35px;}}
      p{{font-size: 1.5rem; width: 200; word-wrap: break-word;}}
      .button{{font-family: {font_family};display: inline-block;
      background-color: black; border: none;
      border-radius: 4px; color: white; padding: 16px 40px;
      text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}}
      p.dotted {{margin: auto;
      width: 75%; font-size: 25px; text-align: center;}}
    </style>
    </head>
    <body>
    <title>Pico W HTTP Server</title>
    <h1>Pico W HTTP Server</h1>
    <br>
    <p class="dotted">This is a Pico W running an HTTP server with CircuitPython.</p>
    <br>
    <p class="dotted">The current ambient temperature near the Pico W is
    <span style="color: deeppink;">{temp_test}°{unit}</span></p><br>
    <h1>Control the LED on the Pico W with these buttons:</h1><br>
    <form accept-charset="utf-8" method="POST">
    <button class="button" name="LED ON" value="ON" type="submit">LED ON</button></a></p></form>
    <p><form accept-charset="utf-8" method="POST">
    <button class="button" name="LED OFF" value="OFF" type="submit">LED OFF</button></a></p></form>
    <h1>Party?</h>
    <p><form accept-charset="utf-8" method="POST">
    <button class="button" name="party" value="party" type="submit">PARTY!</button></a></p></form>
    </body></html>
    """
    return html

#  route default static IP
@server.route("/")
def base(request: HTTPRequest):  # pylint: disable=unused-argument
    #  serve the HTML f string
    #  with content type text/html
    with HTTPResponse(request, content_type=MIMEType.TYPE_HTML) as response:
        response.send(f"{webpage()}")

#  if a button is pressed on the site
@server.route("/", method=HTTPMethod.POST)
def buttonpress(request: HTTPRequest):
    #  get the raw text
    raw_text = request.raw_request.decode("utf8")
    print(raw_text)
    #  if the led on button was pressed
    if "ON" in raw_text:
        #  turn on the onboard LED
        led.value = True
    #  if the led off button was pressed
    if "OFF" in raw_text:
        #  turn the onboard LED off
        led.value = False
    
    #  reload site
    with HTTPResponse(request, content_type=MIMEType.TYPE_HTML) as response:
        response.send(f"{webpage()}")

print("starting server..")
# startup the server
try:
    server.start(esp.pretty_ip(esp.ip_address))
    print("Listening on http://%s:80" % esp.pretty_ip(esp.ip_address))
#  if the server fails to begin, restart the pico w
except OSError:
    time.sleep(5)
    print("restarting..")
    microcontroller.reset()

#  text objects for screen
#  connected to SSID text
connect_text_area.text = "Connected to:"
ssid_text = "%s" % secrets('ssid')
# ssid_text_area = label.Label(terminalio.FONT, text=ssid_text, color=0xFFFFFF, x=0, y=offset_y+15)
#splash.append(ssid_text_area)
#  display ip address
ip_text = "IP: %s" % wifi.radio.ipv4_address
# ip_text_area = label.Label(terminalio.FONT, text=ip_text, color=0xFFFFFF, x=0, y=offset_y+30)
#splash.append(ip_text_area)
#  display temp reading
temp_text = "Temperature: %.02f F" % float(temp_test)
# temp_text_area = label.Label(terminalio.FONT, text=temp_text, color=0xFFFFFF, x=0, y=offset_y+45)
#splash.append(temp_text_area)


def get_weather_conditions():
    temp = bme280.temperature
    print("\nTemperature: %0.1f C" % temp)
    hum = bme280.relative_humidity
    print("Humidity: %0.1f %%" % hum)
    pres = bme280.pressure
    print("Pressure: %0.1f hPa" % pres)
    alt = bme280.altitude
    print("Altitude: %0.2f meters" % alt)
    light = bh1750.lux
    print("Light: %.2f Lux" % light)
    return [temp, hum, pres, alt, light]


clock = time.monotonic() #  time.monotonic() holder for server ping

while True:
    try:
        #  every 30 seconds, ping server & update temp reading
        if (clock + 30) < time.monotonic():
            if wifi.radio.ping(ping_address) is None:
                connect_text_area.text = "Disconnected!"
                ssid_text_area.text = None
                print("lost connection")
            else:
                connect_text_area.text = "Connected to:"
                ssid_text_area.text = "%s" % secrets('ssid')
                print("connected")
            clock = time.monotonic()
            #  comment/uncomment for desired units
            #  temp_test = str(ds18.temperature)
            temp_test = str(c_to_f(19.45))
            temp_text_area.text = "Temperature: %s F" % temp_test

#         display.show(splash)
        #  poll the server for incoming/outgoing requests
        server.poll()
    # pylint: disable=broad-except
    except Exception as e:
        print(e)
        continue

, 👍1


1 ответ


Лучший ответ:

0

Официальный ответ от Adafuit на этот вопрос заключается в том, что библиотека HTTPServer создана для Raspeberry PICO и не работает на других платах, таких как Feather M4 Express. Вместо этого необходимо использовать другой набор библиотек, вот соответствующий пример: https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI/tree/main/examples/server

,