Рубрики
Без рубрики

Столковый веб -портал для ESP8266 с MicropyThon – Часть 1

Идея проекта, которую я недавно работал над несколькими небольшими проектами, используя SOC ESP8266, и один … Теги с микропитоном, Python, DNS, ESP8266.

Я недавно работал над несколькими небольшими проектами, используя SOC ESP8266, и одна вещь, которая беспокоила меня, заключается в том, что мне нужно было жестко кодировать свой домашний SSID доступа к Wi-Fi и пароль в файл Python или в отдельный файл конфигурации. Это не такая большая сделка для небольших личных проектов, но когда я покупаю «интеллектуальные» гаджеты из любого другого, они всегда поставляются с возможностью настроить устройство, подключившись к временной точке доступа Wi -Fi на самом устройстве, и и Затем вводит мой домашний Wi -Fi SSID и пароль в форму HTML.

Эта цель этого проекта – запрограммировать MCU ESP8266:

  • При запуске сначала проверьте, знает ли он, как войти в мой дом Wi -Fi. После того, как я настрою устройство, я ожидаю, что оно запомнит учетные данные Wi -Fi, которые я сказал ему, даже если оно будет перезагружен.
  • Если у него нет никаких известных учетных данных, или ранее сохраненные учетные данные не работают, тогда запустите необеспеченную точку доступа Wi -Fi на загрузке.
  • С помощью моего телефона подключитесь к AP MCU Wi -Fi, а затем введите SSID и пароль для моего реального домашнего WiFi.
  • Затем MCU пытается подключиться к моему домашнему Wi -Fi, используя вновь предоставленные учетные данные, и отобразить страницу базового состояния, показывающую, к какой сети он подключен, и какова его IP -адрес в моей домашней сети.

Эта идея не совсем нова, и она называется «пленным порталом» в других контекстах. Это то, что вы, возможно, видели при входе в публичный Wi-Fi в своей любимой кофейне, где вы перенаправляете на страницу входа, прежде чем разрешить онлайн. Есть несколько разных способов сделать это, но то, как я собираюсь сделать это, потребуется HTTP -сервер (для обслуживания HTML, чтобы задать Wi -Fi SSID и пароль), а также сервер DNS для перенаправления всех вопросов DNS на IP -адрес MCU, так что мне не нужно знать IP -адрес Правления. Я смогу просто подключиться к точке доступа платы, а затем перейти на любой (не-HTTPS) веб-сайт, и это перенаправляет меня на страницу входа в систему.

Часть без HTTPS важна; Для простоты HTTP -сервер прослушивает только на порту 80, а не 443. Запросы HTTPS все равно будут перенаправлены на доску, но там нет, чтобы их не слушали розетки HTTPS, поэтому они пройдут. Можно добавить перенаправление HTTPS, как это, но есть несколько проблем:

  • Многие браузеры будут отображать предупреждение или отказываться отображать страницу, если будет перенаправлен сайт HTTPS. Это, очевидно, хорошо для безопасности, но делает его болью для этого конкретного варианта использования.
  • Мне нужно было бы настроить сертификаты SSL, запустить третий сервер сокетов на MCU и иметь возможность обрабатывать соединения TLS/SSL, что более вовлечено, чем простой http. Я Подумайте ESP8266, вероятно, способен на это, но это крошечное устройство с ограниченными ресурсами, и это было бы много излишнего для того, что мне действительно нужно.

Для моего телефона Android (и я думаю, что и для устройств iOS), ОС обнаруживает, что у нее нет доступа в Интернет, и в любом случае будет автоматически войти в систему, который проходит HTTP и делает перенаправление, которое мне нужно. Если это не сработает, я мог бы просто намеренно перейти на сайт, который, как я знаю, использует только http (например, http://example.com или http://neverssl.com ) запустить перенаправление.

Я написал Предыдущая статья При настройке Nodemcu ESP8266 с микропитоном несколько месяцев назад, Поэтому вместо того, чтобы повторить все инструкции здесь, вы можете проверить эту статью. Я предполагаю, что вы уже можете rshell в ваш MCU до конца этого поста.

Единственная разница в прошлом времени заключается в том, что на этот раз я использую другую доску, а Wemos D1 Mini Я заказал с Amazon. Он имеет такой же чипсет ESP8266 и в основном те же функции, но меньше контактов GPIO, чем у других. В любом случае цена примерно одинакова, но я искал меньший форм -фактор для моего следующего проекта, и это примерно вдвое меньше размера Nodemcu Development Board .

Единственный дополнительный шаг, который мне нужно было, чтобы заставить D1 Mini для работы, – это установить дополнительный драйвер. Все мои результаты поиска для этого закончились с родами схематистыми веб-сайтами, но я думаю, что «Официальный» водитель от производителя должен быть в безопасности. Ссылка выше предназначена для версии драйвера MacOS, но есть и драйверы для Windows и Linux на том же сайте.

Кроме того, все было в основном то же самое, за исключением того, что Wemos D1 Mini появляется в другом серийном порту, в моем случае /dev/cu.wchusbesserial1430 Анкет В качестве напоминания вы можете проверить это самостоятельно, используя инструмент esptool.py от Espressif :

$ esptool.py read_mac
esptool.py v2.8
Found 3 serial ports
Serial port /dev/cu.wchusbserial1430
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: 2c:f4:32:78:d0:c1
Uploading stub...
Running stub...
Stub running...
MAC: 2c:f4:32:78:d0:c1
Hard resetting via RTS pin...

Подключение к доске с rshell После первоначального мигания последнего бинарного микропитона Отсюда (Я использовал v1.12) показывает один файл (boot.py) в /pyboard папка.

Я не касался файла boot.py, и мой выглядел так:

# /pyboard/boot.py
# This file is executed on every boot (including wake-boot from deepsleep)
#import esp
#esp.osdebug(None)
import uos, machine
#uos.dupterm(None, 1) # disable REPL on UART(0)
import gc
#import webrepl
#webrepl.start()
gc.collect()

Файл boot.py – это первый запуск файла каждый раз, когда плата сбрасывается. В моем случае не так много, кроме сборки мусора, но я оставлю его как есть.

Другой файл, который запускается на каждой загрузке, называется main.py, но его еще не существует. Поскольку этот проект предназначен для того, чтобы просто стать кодом Bootstrap для нового устройства, я не хочу загромождать Main.py с помощью кода портала в неволе. Я напишу большую часть этого кода в отдельных файлах, просто импортируйте и позвоню из нескольких строк в main.py.

Еще один важный факт, который я узнал в этом проекте, заключается в том, что, поскольку микропитон должен импортировать и «компилировать» (в замороженный байт -код) каждый файл в одном кусок, необработанные размеры файлов Python должны быть ограничены тем, что доступно в RAM на MCU, минус Что использует переводчик. На практике я обнаружил, что это означает, что я не мог импортировать исходный файл, намного больше ~ 8 кб. В некоторых случаях (для этого и других проектов в микропитоне) мне также нужно было запустить сборы мусора между импортом. Документация Немного говорит об этом, если вы хотите больше деталей. Если вы получите (загадочные, казалось бы, неполные) ошибки, такие как пример ниже, это может означать, что размер вашего файла слишком велик, и вы должны разбить его на несколько файлов:

>>> import captive_http
Traceback (most recent call last):
  File "", line 1, in 
MemoryError:

>>>

Можно использовать rshell Чтобы редактировать файлы напрямую (вроде) на MCU, но я предпочитаю редактировать с моей хост -машины, а затем копировать файлы оттуда во время тестирования. Таким образом, я сохраняю последние обновления в моем GIT Repo на своем рабочем столе, и никогда не нужно беспокоиться о том, какая последняя версия. Мой рабочий процесс выглядит примерно так:

  • Редактировать файлы (например, main.py) на моем хост -ПК
  • rshell в MCU, затем cp main.py/pyboard/
  • На MCU начните Repl а затем Импорт основной

Чтобы начать этот проект, я собираюсь создать два файла:

  • main.py , который начнет код, который я хочу запустить, и в противном случае будет доступен для будущего кода проекта.
  • appitive_portal.py, который будет координировать серверы HTTP и DNS, чтобы этот код начальной загрузки WiFi работал.

Я начну с main.py Так как это всего лишь пара строк:

# main.py
from captive_portal import CaptivePortal

portal = CaptivePortal()

portal.start()

Как видите, здесь не так много, кроме как импортировать мой класс CaptivePortal и запуск его start () функция Я напишу этот класс и метод в новом файле, как это:

# captive_portal.py
import network
import uerrno
import uos as os
import utime as time

class CaptivePortal:
    CRED_FILE = "./wifi.creds"
    MAX_CONN_ATTEMPTS = 10

    def __init__(self):
        self.sta_if = network.WLAN(network.STA_IF)

        self.ssid = None
        self.password = None

    def start(self):
        # turn off station interface to force a reconnect
        self.sta_if.active(False)
        if not self.try_connect_from_file():
            self.captive_portal()

    def connect_to_wifi(self):
        print(
            "Trying to connect to SSID '{:s}' with password {:s}".format(
                self.ssid, self.password
            )
        )
        # initiate the connection
        self.sta_if.active(True)
        self.sta_if.connect(self.ssid, self.password)

        attempts = 0
        while attempts < self.MAX_CONN_ATTEMPTS:
            if not self.sta_if.isconnected():
                print("Connection in progress")
                time.sleep(2)
                attempts += 1
            else:
                print("Connected to {:s}".format(self.ssid))
                self.local_ip = self.sta_if.ifconfig()[0]
                self.write_creds(self.ssid, self.password)
                return True

        print("Failed to connect to {:s} with {:s}. WLAN status={:d}".format(
            self.ssid, self.password, self.sta_if.status()
        ))
        # forget the credentials since they didn't work, and turn off station mode
        self.ssid = self.password = None
        self.sta_if.active(False)
        return False

    def write_creds(self, ssid, password):
        open(self.CRED_FILE, 'wb').write(b','.join([ssid, password]))
        print("Wrote credentials to {:s}".format(self.CRED_FILE))

    def captive_portal(self):
        print("Starting captive portal")

    def try_connect_from_file(self):
        print("Trying to load WiFi credentials from {:s}".format(self.CRED_FILE))
        try:
            os.stat(self.CRED_FILE)
        except OSError as e:
            if e.args[0] == uerrno.ENOENT:
                print("{:s} does not exist".format(self.CRED_FILE))
                return False

        contents = open(self.CRED_FILE, 'rb').read().split(b',')
        if len(contents) == 2:
            self.ssid, self.password = contents
        else:
            print("Invalid credentials file:", contents)
            return False

        if not self.connect_to_wifi():
            print("Connect with saved credentials failed, starting captive portal")
            os.remove(self.CRED_FILE)
            return False

        return True

Есть несколько вещей, которые могут выглядеть странно, если вы приезжаете из CPYTHON («нормальный» Python) и раньше не использовали микропитон. Micropython довольно полнофункциональный, но он все еще является только подмножеством CPYTHON, и поэтому отсутствует часть стандартной библиотеки. В большинстве этих случаев я импортирую «микро» версию библиотеки (например, UOS вместо ОС ) Pycopy Docs действительно превосходны, когда пытаются выяснить сходства и различия между двумя версиями Python и оказали огромную помощь на протяжении всего этого проекта.

Примечание: пикопия – вилка микропитона, но документация намного лучше написана и более полна. Как правило, они эквивалентны функциям, поэтому я склонен использовать документы из пикопии вместо этого.

Класс __init __ () Метод устанавливает переменные для возможного SSID и пароля, а также ссылка на интерфейс станции MCU. Интерфейс станции предназначен для MCU, чтобы подключиться к другой точке Wi -Fi. Позже мы также настроим интерфейс точки доступа MCU.

На данный момент start () Метод просто пытается подключиться к моей домашней точке Wi-Fi из ранее подтвержденных учетных данных, если это возможно, а если нет, то он (в конце концов) запустит сам портал в неволе.

try_connect_from_file () Метод довольно прост:

  • Проверьте, существует ли файл, где мы ожидаем Учетные данные Wi -Fi
  • Если это так, откройте его и проверьте, что у него есть два значения, разделенных запятыми
  • Если это так, попробуйте подключиться с этими значениями, предполагая, что первым является мой домашний Wi -Fi SSID, а второй – пароль Wi -Fi
  • Если какой -либо шаг не удается, верните ЛОЖЬ чтобы мы могли запустить портал «Капля» вместо этого, чтобы предложить пользователю ввести эти учетные данные.

connect_to_wifi () Включите интерфейс станции и пытается связаться с учетными данными, которые у нас есть (которых еще не существует, поскольку мы не читали их из файла и не побудили пользователя). Он ждет до 20 секунд, когда соединение будет установлено, прежде чем выручить. Если он не может подключиться, он распечатает статус интерфейса, который будет одной из перечисленных констант В микропитоне Сеть документация .

Скопируйте оба этих файла в /pyboard/ Папка на MCU, затем запустите Repl и импорт главный :

/pyboard> repl
Entering REPL. Use Control-X to exit.
>
MicroPython v1.12 on 2019-12-20; ESP module with ESP8266
Type "help()" for more information.
>>>
>>> import main
Trying to load WiFi credentials from ./wifi.creds
./wifi.creds does not exist
Starting captive portal

Поскольку мне понадобится как DNS, так и HTTP -сервер, имеет смысл извлечь любые общие части в суперкласс. Основная функциональность этого класса будет заключаться в создании сокета на указанном порту, а затем зарегистрировать его с помощью потокового Poller, который уведомит сервер, когда появится новое событие в сокете. Микропитон имеет модуль USELECT Чтобы помочь справиться с такими потоками, что является подмножеством cpython Выберите модуль. Используя этот Poller, мы можем одновременно запустить как HTTP, так и DNS -серверы, без одного блокировки, ожидая, чтобы прослушать его розетку.

Вот класс сервера, который я создал в новом файле:

# server.py
import usocket as socket
import uselect as select


class Server:
    def __init__(self, poller, port, sock_type, name):
        self.name = name
        # create socket with correct type: stream (TCP) or datagram (UDP)
        self.sock = socket.socket(socket.AF_INET, sock_type)

        # register to get event updates for this socket
        self.poller = poller
        self.poller.register(self.sock, select.POLLIN)

        addr = socket.getaddrinfo("0.0.0.0", port)[0][-1]
        # allow new requests while still sending last response
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind(addr)

        print(self.name, "listening on", addr)

    def stop(self, poller):
        poller.unregister(self.sock)
        self.sock.close()
        print(self.name, "stopped")

HTTP -сервер будет использовать сокет TCP на порту 80, в то время как DNS -сервер будет использовать сокет UDP на порту 53. Как только розетка будет создана, я зарегистрирую его с помощью Poller, проходящего от вызывающего абонента (чтобы я мог повторно использовать один и тот же полий) и подписаться на Поллин Событие, которое будет уведомлять всякий раз, когда у сокета есть новые входящие данные для чтения. Несмотря на то, что я не зарегистрировался для них в событии Bitmask, я также потенциально получу Pollhup (Hangup) и Повес (ошибка) события.

Затем я установил параметры сокета для повторного использования его адреса. Это в основном важно только для сокета TCP, так как могут быть исходящие данные для недавно закрытого сокета, в то время как я хочу отправить новые данные на новом соединении. Для лучшего углубленного обсуждения SO_REUSEADDR Флаг, вот отличный Stackoverflow ответ .

Наконец, я связываю новый розетка с адресом ярлыка «0,0.0.0», который будет прослушать все адреса IPv4 на MCU и данном порту. Документация микропитона для USCOCKET полезен в правильном получении этой настройки.

Помимо конструктора, единственный метод, который я поднял в этот Superclass, – это изящно остановить сервер, когда я закончил, не зарегистрировав его от пола и закрывая гнездо.

Теперь, когда у меня есть скелет на месте, я создам подкласс DNS -сервера в новом файле с именем Captive_dns.py :

# captive_dns.py
import usocket as socket
import gc

from server import Server

class DNSServer(Server):
    def __init__(self, poller, ip_addr):
        super().__init__(poller, 53, socket.SOCK_DGRAM, "DNS Server")
        self.ip_addr = ip_addr

    def handle(self, sock, event, others):
        # server doesn't spawn other sockets, so only respond to its own socket
        if sock is not self.sock:
            return

        # check the DNS question, and respond with an answer
        try:
            data, sender = sock.recvfrom(1024)
            print("Got data:", data, "from sender:", sender)
        except Exception as e:
            print("DNS server exception:", e)

Этот DNS -сервер еще мало что делает. Всякий раз, когда это handle () Метод вызывается с помощью сокета, типа события и, возможно, дополнительными данными, он проверит, чтобы убедиться, что сокет – это то, что он ожидает, а затем попытайтесь прочитать в 1024 байтах данных из сокета. Очевидно, мы скоро добавим больше здесь, но этого должно быть достаточно, чтобы проверить основные функциональные возможности.

Теперь вернемся в CaptivePortal Класс, я создаюсь экземпляр DNS -сервера и настрану петлю Event Poller, чтобы начать прослушивание потока сокетов. Прежде чем мы сможем это сделать, мне нужно настроить MCU, чтобы включить интерфейс точки доступа, чтобы он мог принять входящие Wi -Fi подключения:

# captive_portal.py
import network
import ubinascii as binascii
...

class CaptivePortal:
    AP_IP = "192.168.4.1"
    CRED_FILE = "./wifi.creds"
    MAX_CONN_ATTEMPTS = 10

    def __init__(self, essid=None):
        self.local_ip = self.AP_IP
        self.sta_if = network.WLAN(network.STA_IF)
        self.ap_if = network.WLAN(network.AP_IF)

        if essid is None:
            essid = b"ESP8266-%s" % binascii.hexlify(self.ap_if.config("mac")[-3:])
        self.essid = essid

        self.ssid = None
        self.password = None
    ...

Здесь я настраиваю локальный IP -адрес, который буду использовать для точки доступа (который является адресом ESP8266 по умолчанию, но не должен быть), а затем получить доступ к интерфейсу точки доступа. Я также добавил параметр конструктора для SSID точки доступа, если я захочу назвать его по -другому. Если я не передам особое имя, он будет использовать часть MAC -адреса MCU, чтобы создать уникальный SSID для точки доступа.

Затем я создам метод для фактического включения и настроить интерфейс точки доступа, а затем вызову его в начале saptive_portal () Метод:

# captive_portal.py
...
class CaptivePortal:
    ...
    def start_access_point(self):
        # sometimes need to turn off AP before it will come up properly
        self.ap_if.active(False)
        while not self.ap_if.active():
            print("Waiting for access point to turn on")
            self.ap_if.active(True)
            time.sleep(1)
        # IP address, netmask, gateway, DNS
        self.ap_if.ifconfig(
            (self.local_ip, "255.255.255.0", self.local_ip, self.local_ip)
        )
        self.ap_if.config(essid=self.essid, authmode=network.AUTH_OPEN)
        print("AP mode configured:", self.ap_if.ifconfig())

    def captive_portal(self):
        print("Starting captive portal")
        self.start_access_point()
    ...

Я иногда сталкивался с проблемами, когда, если интерфейс AP уже был включен, когда я пытался перенастроить его, он принесет ошибку, иначе просто никогда не настраиваясь должным образом. Чтобы обойти это, я явно перезагружаю его каждый раз, когда захочу, и жду, пока он сообщит, что он активен, прежде чем продолжить.

ifconfig () Функциональные наборы вызовов (в порядке):

  • айпи адрес
  • Сеть
  • Ворота
  • DNS -сервер

Значения, которые я использую для IP -адреса, сетевой маски и шлюза, – все это по умолчанию для интерфейса, но я меняю сервер DNS, чтобы указать на сам MCU, а не на «реальную» службу DNS, чтобы мы могли иметь MCU отвечает на все запросы DNS для устройств, которые подключаются к нему, чтобы перенаправить их так, как мы хотим.

Наконец, я установил сетевой SSID (имя, которое я увижу, когда попытаюсь подключиться с телефона), и установил его на точку открытого доступа, чтобы мне не нужно вводить пароль для подключения. Тогда это просто вопрос названия этой функции в начале моего saptive_portal () Метод, чтобы начать вещи.

Чтобы проверить все до сих пор, я скопировал свои новые/измененные файлы на MCU, а затем импортировал Main из реплики:

MicroPython v1.12 on 2019-12-20; ESP module with ESP8266
Type "help()" for more information.
>>>
>>> import main
Trying to load WiFi credentials from ./wifi.creds
./wifi.creds does not exist
Starting captive portal
Waiting for access point to turn on
#33 ets_task(4020f510, 29, 3fff8f88, 10)
#34 ets_task(4020f510, 29, 3fff8f88, 10)
AP mode configured: ('192.168.4.1', '255.255.255.0', '192.168.4.1', '192.168.4.1')

Здесь хорошо выглядит. На моем телефоне я искал доступные точки доступа Wi -Fi, и вот он!

Теперь, когда у меня есть точка доступа, к которой может подключиться мой телефон, пришло время начать на самом деле опросы с DNS -сервера. Помните, что конфигурация точки доступа говорит всем его клиенту, что это сервер DNS, поэтому, когда мой телефон подключается и пытается найти доменное имя, он будет спросить сам MCU, какой IP -адрес указывает URL.

Сделайте следующие дополнения к CaptivePortal класс:

# captive_portal.py
...
import gc
import uselect as select

from captive_dns import DNSServer

class CaptivePortal:
    AP_IP = "192.168.4.1"
    CRED_FILE = "./wifi.creds"
    MAX_CONN_ATTEMPTS = 10

    def __init__(self, essid=None):
        ...
        self.dns_server = None
        self.poller = select.poll()
        ...

    def captive_portal(self):
        print("Starting captive portal")
        self.start_access_point()

        if self.dns_server is None:
            self.dns_server = DNSServer(self.poller, self.local_ip)
            print("Configured DNS server")

        try:
            while True:
                gc.collect()
                # check for socket events and handle them
                for response in self.poller.ipoll(1000):
                    sock, event, *others = response
                    self.handle_dns(sock, event, others)
        except KeyboardInterrupt:
            print("Captive portal stopped")
        self.cleanup()

    def handle_dns(self, sock, event, others):
        if sock is self.dns_server.sock:
            # ignore UDP socket hangups
            if event == select.POLLHUP:
                return True
            self.dns_server.handle(sock, event, others)
            return True
        return False

    def cleanup(self):
        print("Cleaning up")
        if self.dns_server:
            self.dns_server.stop(self.poller)
        gc.collect()
    ...

Здесь я использую USELECT модуль для создания Опрос объект. Когда я создаю экземпляр класса DNSServer, он регистрирует свой розетка с помощью Poller, и любые события в этом потоке сокета будут отображаться как ответ, через который я могу выполнить. Я звоню ipoll Метод с тайм -аутом 1000 мс., И если есть какое -либо событие, я проверяю, хочет ли DNSServer справиться с этим.

Поскольку UDP является протоколом без соединения (и, возможно, из -за ошибки в порту MicropyThon ESP8266), я обнаружил, что получаю десятки Pollhup (Stream Hangup) События в секунду после первой, которые бесполезны для меня в этом приложении. Я уже игнорирую их и в противном случае отправляю мероприятие DNSServer, чтобы справиться с собой.

Чтобы проверить все это, я сохранил, скопировал и снова побежал от Repl. После того, как я подключил свой телефон к точке доступа, я вижу несколько запросов DNS. После подтверждения, это сработало, я использовал Ctrl-C Чтобы выйти и проверить, был также вызван код очистки.

MicroPython v1.12 on 2019-12-20; ESP module with ESP8266
Type "help()" for more information.
>>>
>>> import main
Trying to load WiFi credentials from ./wifi.creds
./wifi.creds does not exist
Starting captive portal
Waiting for access point to turn on
#50 ets_task(4020f510, 29, 3fff9428, 10)
AP mode configured: ('192.168.4.1', '255.255.255.0', '192.168.4.1', '192.168.4.1')
DNS Server listening on ('0.0.0.0', 53)
Configured DNS server
Got data: b'\xa7A\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x06google\x03com
\x00\x00\x01\x00\x01' from sender: ('192.168.4.2', 42434)
Got data: b'Eo\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x11connectivitycheck\x07gs
tatic\x03com\x00\x00\x01\x00\x01' from sender: ('192.168.4.2', 13197)
Got data: b'\xa7A\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x06google\x03com
\x00\x00\x01\x00\x01' from sender: ('192.168.4.2', 42434)
Got data: b'Eo\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x11connectivitycheck\x07gs
tatic\x03com\x00\x00\x01\x00\x01' from sender: ('192.168.4.2', 13197)
Captive portal stopped
Cleaning up
DNS Server stopped

Пока что я выполнил следующее:

  • Настроил мини -MCU Wemos D1 с прошивкой из микропитона и установил последовательное соединение.
  • Заставил MCU попытаться подключиться к уже известной точке Wi-Fi, если он имеет один, на загрузке.
  • Записал класс базового сервера, который может привязаться к розетку и зарегистрироваться для получения событий в этом потоке сокета.
  • Написал скелет сервера DNS, который слушает DADP Datagrams на порте 53 и отображает их на экране.
  • Установите базовую петлю события сервера Captive для опроса для событий и обработки их надлежащим образом.

В следующей части я пойму, как понять вопросы DNS и сгенерировать ответ, который укажет все запросы DNS обратно на IP -адрес MCU, чтобы пользователь всегда был представлен страницей входа в систему, когда они подключаются к Access MCU WiFi. точка.

Примечание. Если вы покупаете товар у Amazon, используя любую из ссылок в этой статье, я могу получить небольшую комиссию.

Оригинал: “https://dev.to/ansonvandoren/captive-web-portal-for-esp8266-with-micropython-part-1-d56”