ESP32/ESP8266 MicroPython веб-сервер – управление выходами

Узнайте, как создать веб-сервер для управления выходами ESP32 или ESP8266 с помощью фреймворка MicroPython. В качестве примера мы создадим веб-сервер с кнопками ON и OFF для управления встроенным светодиодом ESP32/ESP8266. Мы будем использовать сокеты и Python socket API.

ESP32 веб-сервер с MicroPython на смартфоне

Предварительные требования

Для программирования ESP32 и ESP8266 на MicroPython мы используем uPyCraft IDE в качестве среды разработки. Следуйте следующим руководствам для установки uPyCraft IDE и прошивки MicroPython на вашу плату:

Если это ваш первый опыт работы с MicroPython, рекомендуем ознакомиться со следующими руководствами:

Необходимые компоненты

Для этого руководства вам понадобится плата ESP32 или ESP8266:

Подготовка файлов

Подключите плату ESP32 или ESP8266 к компьютеру. Откройте uPyCraft IDE, перейдите в Tools > Serial и выберите последовательный порт.

uPyCraft IDE выбор последовательного порта

Вы должны увидеть файлы на плате ESP32/ESP8266 в папке устройства. По умолчанию при прошивке MicroPython создаётся файл boot.py.

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

Файл main.py будет содержать код, запускающий веб-сервер для обслуживания файлов и выполнения задач на основе запросов, полученных от клиента.

Создание файла main.py на вашей плате

1. Нажмите кнопку «New file», чтобы создать новый файл.

uPyCraft IDE кнопка нового файла

2. Нажмите кнопку «Save file», чтобы сохранить файл на вашем компьютере.

uPyCraft IDE кнопка сохранения файла

3. Откроется новое окно, назовите файл main.py и сохраните его на компьютере:

Новый файл main.py создан в uPyCraft IDE

4. После этого вы должны увидеть следующее в вашей uPyCraft IDE (файл boot.py на устройстве и новую вкладку с файлом main.py):

main.py файл создан

5. Нажмите кнопку «Download and run», чтобы загрузить файл на плату ESP:

uPyCraft IDE кнопка загрузки и запуска

6. В директории устройства теперь должен появиться файл main.py. На вашей ESP хранится файл main.py.

uPyCraft IDE создание файла main.py

boot.py

Скопируйте следующий код в файл boot.py на ESP32/ESP8266.

# Подробности проекта на https://RandomNerdTutorials.com

try:
  import usocket as socket
except:
  import socket

from machine import Pin
import network

import esp
esp.osdebug(None)

import gc
gc.collect()

ssid = 'REPLACE_WITH_YOUR_SSID'
password = 'REPLACE_WITH_YOUR_PASSWORD'

station = network.WLAN(network.STA_IF)

station.active(True)
station.connect(ssid, password)

while station.isconnected() == False:
  pass

print('Connection successful')
print(station.ifconfig())

led = Pin(2, Pin.OUT)

Просмотреть исходный код boot.py

Как упоминалось ранее, мы создаём наш веб-сервер с помощью сокетов и Python socket API. Официальная документация импортирует библиотеку socket следующим образом:

try:
  import usocket as socket
except:
  import socket

Нам нужно импортировать класс Pin из модуля machine, чтобы иметь возможность взаимодействовать с GPIO.

from machine import Pin

После импорта библиотеки socket нам нужно импортировать библиотеку network. Библиотека network позволяет подключить ESP32 или ESP8266 к сети Wi-Fi.

import network

Следующие строки отключают отладочные сообщения ОС:

import esp
esp.osdebug(None)

Затем мы запускаем сборщик мусора:

import gc
gc.collect()

Сборщик мусора (garbage collector) – это форма автоматического управления памятью. Это способ освободить память, занятую объектами, которые больше не используются программой. Это полезно для экономии места во flash-памяти.

Следующие переменные содержат ваши сетевые учётные данные:

ssid = 'REPLACE_WITH_YOUR_SSID'
password = 'replace_with_your_password'

Вы должны заменить выделенные красным слова на ваш SSID сети и пароль, чтобы ESP могла подключиться к вашему роутеру.

Затем установите ESP32 или ESP8266 в режим Wi-Fi станции:

station = network.WLAN(network.STA_IF)

После этого активируйте станцию:

station.active(True)

Наконец, ESP32/ESP8266 подключается к вашему роутеру, используя SSID и пароль, определённые ранее:

station.connect(ssid, password)

Следующая инструкция гарантирует, что код не продолжит выполнение, пока ESP не подключится к вашей сети.

while station.isconnected() == False:
  pass

После успешного подключения выведите параметры сетевого интерфейса, такие как IP-адрес ESP32/ESP8266 – используйте метод ifconfig() на объекте station.

print('Connection successful')
print(station.ifconfig())

Создайте объект Pin с именем led, который является выходом и ссылается на GPIO2 ESP32/ESP8266:

led = Pin(2, Pin.OUT)

main.py

Скопируйте следующий код в файл main.py на ESP32/ESP8266.

# Подробности проекта на https://RandomNerdTutorials.com

def web_page():
  if led.value() == 1:
    gpio_state="ON"
  else:
    gpio_state="OFF"

  html = """<html><head> <title>ESP Web Server</title> <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,"> <style>html{font-family: Helvetica; display:inline-block; margin: 0px auto; text-align: center;}
  h1{color: #0F3376; padding: 2vh;}p{font-size: 1.5rem;}.button{display: inline-block; background-color: #e7bd3b; border: none;
  border-radius: 4px; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}
  .button2{background-color: #4286f4;}</style></head><body> <h1>ESP Web Server</h1>
  <p>GPIO state: <strong>""" + gpio_state + """</strong></p><p><a href="/?led=on"><button class="button">ON</button></a></p>
  <p><a href="/?led=off"><button class="button button2">OFF</button></a></p></body></html>"""
  return html

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)

while True:
  conn, addr = s.accept()
  print('Got a connection from %s' % str(addr))
  request = conn.recv(1024)
  request = str(request)
  print('Content = %s' % request)
  led_on = request.find('/?led=on')
  led_off = request.find('/?led=off')
  if led_on == 6:
    print('LED ON')
    led.value(1)
  if led_off == 6:
    print('LED OFF')
    led.value(0)
  response = web_page()
  conn.send('HTTP/1.1 200 OK\n')
  conn.send('Content-Type: text/html\n')
  conn.send('Connection: close\n\n')
  conn.sendall(response)
  conn.close()

Просмотреть исходный код main.py

Скрипт начинается с создания функции web_page(). Эта функция возвращает переменную html, содержащую HTML-текст для построения веб-страницы.

def web_page():

Веб-страница отображает текущее состояние GPIO. Поэтому перед генерацией HTML-текста нам нужно проверить состояние светодиода. Мы сохраняем его состояние в переменной gpio_state:

if led.value() == 1:
  gpio_state="ON"
else:
  gpio_state="OFF"

После этого переменная gpio_state включается в HTML-текст с помощью знаков "+" для конкатенации строк.

html = """<html><head> <title>ESP Web Server</title> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,"> <style>html{font-family: Helvetica; display:inline-block; margin: 0px auto; text-align: center;}
h1{color: #0F3376; padding: 2vh;}p{font-size: 1.5rem;}.button{display: inline-block; background-color: #e7bd3b; border: none;
border-radius: 4px; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}
.button2{background-color: #4286f4;}</style></head><body> <h1>ESP Web Server</h1>
<p>GPIO state: <strong>""" + gpio_state + """</strong></p><p><a href="/?led=on"><button class="button">ON</button></a></p>
<p><a href="/?led=off"><button class="button button2">OFF</button></a></p></body></html>"""

Создание сокет-сервера

После создания HTML для построения веб-страницы нам нужно создать слушающий сокет для приёма входящих запросов и отправки HTML-текста в ответ. Для лучшего понимания на следующей схеме показана диаграмма создания сокетов для взаимодействия сервер-клиент:

Python сокет-сервер и клиент

Создайте сокет с помощью socket.socket() и укажите тип сокета. Мы создаём новый объект сокета с именем s с заданным семейством адресов и типом сокета. Это STREAM TCP сокет:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

Далее привяжите сокет к адресу (сетевой интерфейс и номер порта) с помощью метода bind(). Метод bind() принимает кортеж с IP-адресом и номером порта:

s.bind(('', 80))

В нашем примере мы передаём пустую строку '' в качестве IP-адреса и порт 80. В этом случае пустая строка ссылается на IP-адрес localhost (то есть IP-адрес ESP32 или ESP8266).

Следующая строка позволяет серверу принимать соединения; она создаёт «слушающий» сокет. Аргумент указывает максимальное количество соединений в очереди. Максимум – 5.

s.listen(5)

В цикле while мы слушаем запросы и отправляем ответы. Когда клиент подключается, сервер вызывает метод accept() для принятия соединения. Когда клиент подключается, сервер сохраняет новый объект сокета для приёма и отправки данных в переменной conn, а адрес клиента – в переменной addr.

conn, addr = s.accept()

Затем выведите адрес клиента, сохранённый в переменной addr.

print('Got a connection from %s' % str(addr))

Данные обмениваются между клиентом и сервером с помощью методов send() и recv().

Следующая строка получает запрос, принятый на вновь созданном сокете, и сохраняет его в переменной request.

request = conn.recv(1024)

Метод recv() принимает данные от клиентского сокета (помните, что мы создали новый объект сокета в переменной conn). Аргумент метода recv() задаёт максимальный объём данных, который может быть получен за один раз.

Следующая строка просто выводит содержимое запроса:

print('Content = %s' % str(request))

Затем создайте переменную response, которая содержит HTML-текст, возвращённый функцией web_page():

response = web_page()

Наконец, отправьте ответ клиентскому сокету с помощью методов send() и sendall():

conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')
conn.sendall(response)

В конце закройте созданный сокет.

conn.close()

Тестирование веб-сервера

Загрузите файлы main.py и boot.py на ESP32/ESP8266. В папке device должны быть два файла: boot.py и main.py.

После загрузки файлов нажмите кнопку EN/RST на плате ESP.

Кнопка Enable на ESP32

Через несколько секунд устройство должно установить соединение с вашим роутером и вывести IP-адрес в Shell.

IP-адрес ESP32

Откройте браузер и введите только что найденный IP-адрес вашего ESP. Вы должны увидеть страницу веб-сервера, как показано ниже.

ESP32 веб-сервер управление выходами

Когда вы нажимаете кнопку ON, вы отправляете запрос на IP-адрес ESP, дополненный /?led=on. Встроенный светодиод ESP32/ESP8266 загорается, и состояние GPIO обновляется на странице.

Примечание

Некоторые встроенные светодиоды ESP8266 включаются по команде OFF и выключаются по команде ON.

Веб-сервер на смартфоне и ESP32

Когда вы нажимаете кнопку OFF, вы отправляете запрос на IP-адрес ESP, дополненный /?led=off. Светодиод выключается, и состояние GPIO обновляется.

Веб-сервер ESP32 кнопка OFF

Примечание

Для простоты в этом руководстве мы управляем встроенным светодиодом, соответствующим GPIO 2. Вы можете управлять любым другим GPIO с любым другим выходом (например, реле) тем же методом. Также вы можете модифицировать код для управления несколькими GPIO или изменить HTML-текст для создания другой веб-страницы.

Итоги

В этом руководстве показано, как создать простой веб-сервер с прошивкой MicroPython для управления GPIO ESP32/ESP8266 с помощью сокетов и библиотеки Python socket. Если вы ищете руководство по веб-серверу с Arduino IDE, ознакомьтесь со следующими ресурсами:

Если вы ищете больше проектов с платами ESP32 и ESP8266, ознакомьтесь со следующими ресурсами:

Надеемся, что эта статья о создании веб-сервера с MicroPython была полезна. Чтобы узнать больше о MicroPython, ознакомьтесь с нашей электронной книгой: MicroPython Programming with ESP32 and ESP8266.