Raspberry Pi Pico W и Wi-Fi: веб-сервер на MicroPython
Pico W и Wi-Fi: правильный UF2, network.WLAN и коды статуса, веб-сервер для светодиода, страница с живыми данными датчика, запросы к API через urequests и время по NTP.
Wi-Fi на Raspberry Pi Pico W — один из самых дешёвых и простых способов сделать небольшое устройство, которым можно управлять с телефона. Pico W — это версия знакомой Raspberry Pi Pico, в которую добавлены Wi-Fi 2,4 GHz и Bluetooth: несколько строк на MicroPython, и плата подключается к домашней сети, раздаёт собственную веб-страницу и получает из интернета погоду и точное время. В этом руководстве мы с нуля подключим Pico W к Wi-Fi, сделаем веб-сервер, который включает светодиод с телефона, а затем страницу, на которой данные датчика обновляются в реальном времени.
К концу статьи станет понятно, как выбрать правильный файл UF2, подключиться через network.WLAN и читать коды статуса, получать данные из API с помощью urequests, выставлять часы по NTP и делать то же самое в Arduino IDE. Если Pico для тебя в новинку, сначала загляни в статью Что такое Raspberry Pi Pico?, так будет проще, а основные команды разобраны в руководстве Что такое MicroPython?.

Что такое Raspberry Pi Pico W и чем она отличается от Pico?
У Pico W тот же процессор RP2040, тот же размер и та же 40-контактная раскладка, что и у Pico. Отличие — добавленная на плату беспроводная микросхема Infineon CYW43439: она даёт Wi-Fi 2,4 GHz стандарта 802.11n и Bluetooth 5.2. Процессор общается с этой микросхемой по линии SPI внутри платы, а тебе нужен только модуль network в MicroPython. Позже Raspberry Pi выпустила Pico 2 W с процессором RP2350; беспроводная микросхема там та же, поэтому весь код из этой статьи работает и на ней.
| Характеристика | Pico W | Pico 2 W | ESP32 (WROOM-32) |
|---|---|---|---|
| Процессор | RP2040, двухъядерный Cortex-M0+, 133 MHz | RP2350, двухъядерный Cortex-M33 (или RISC-V), 150 MHz | Xtensa LX6, двухъядерный, 240 MHz |
| ОЗУ (RAM) | 264 КБ | 520 КБ | 520 КБ |
| Флеш-память | 2 МБ | 4 МБ | Обычно 4 МБ |
| Wi-Fi | 2,4 GHz, 802.11n (CYW43439) | 2,4 GHz, 802.11n (CYW43439) | 2,4 GHz, 802.11 b/g/n (встроен в микросхему) |
| Bluetooth | 5.2 (Classic и BLE) | 5.2 (Classic и BLE) | 4.2 (Classic и BLE) |
| Аналоговые входы | 3 канала, 12 бит | 3 канала, 12 бит | 18 каналов, 12 бит |
| Файл MicroPython | RPI_PICO_W (.uf2) | RPI_PICO2_W (.uf2) | ESP32_GENERIC (.bin) |
На бумаге ESP32 быстрее, и примеров для неё в мире Arduino больше. Сильные стороны Pico W — официальная и зрелая поддержка MicroPython, аккуратная документация и пины без ловушек вроде «при старте должен быть вот такой уровень». Если нравится учиться на Python, Pico W — отличный выбор; если на первом месте код Arduino и готовые библиотеки, удобнее может оказаться ESP32. Если не получается выбрать между двумя платами, поможет сравнение Arduino или ESP32?.
Беспроводная микросхема Pico W и отличия в пинах
Выведенные наружу пины у Pico W точно такие же, как у Pico: GP0–GP22 и GP26–GP28 свободны, аналоговые входы по-прежнему на GP26, GP27 и GP28. Меняются четыре пина, которые остаются внутри платы. На Pico они отвечают за встроенный светодиод, режим питания и обнаружение USB, а на Pico W отданы под связь с беспроводной микросхемой; сам светодиод подключён прямо к беспроводной микросхеме. Полную карту пинов платы можно посмотреть в утилите распиновки.
| Внутренний пин | Назначение на Pico | Назначение на Pico W |
|---|---|---|
| GP23 | Режим источника питания (SMPS) | Включение беспроводной микросхемы (WL_ON) |
| GP24 | Обнаружение напряжения USB (VBUS) | Линия данных и прерываний беспроводной микросхемы (WL_D) |
| GP25 | Встроенный светодиод | Выбор беспроводной микросхемы (WL_CS) |
| GP29 | Измерение напряжения VSYS (ADC3) | Линия тактового сигнала беспроводной микросхемы (WL_CLK) и измерение VSYS |
| Встроенный светодиод | GP25: Pin(25) | Вывод WL_GPIO0 беспроводной микросхемы: Pin("LED") |
Шаг 1: загрузи в Pico W правильный файл UF2
Самая частая ошибка — загрузить в Pico W файл MicroPython для обычной Pico. Плата при этом работает, в окне Shell в Thonny видно приглашение, но стоит набрать import network, и появляется «ImportError: no module named 'network'» (модуль network не найден), потому что в сборке для обычной Pico нет беспроводного драйвера. У каждой платы свой файл UF2:
| Плата | Файл MicroPython UF2 | Диск в режиме BOOTSEL |
|---|---|---|
| Raspberry Pi Pico | RPI_PICO-….uf2 | RPI-RP2 |
| Raspberry Pi Pico W / WH | RPI_PICO_W-….uf2 | RPI-RP2 |
| Raspberry Pi Pico 2 | RPI_PICO2-….uf2 | RP2350 |
| Raspberry Pi Pico 2 W | RPI_PICO2_W-….uf2 | RP2350 |
- На странице загрузок micropython.org найди плату RPI_PICO_W (для Pico 2 W — RPI_PICO2_W) и скачай последний стабильный файл .uf2, то есть без пометки «preview».
- Зажми кнопку BOOTSEL на Pico W и, не отпуская её, подключи USB-кабель с передачей данных к компьютеру, затем отпусти кнопку.
- На компьютере появится диск RPI-RP2. Перетащи на него скачанный файл; когда копирование закончится, диск сам исчезнет, а плата перезагрузится уже с MicroPython.
- Открой Thonny и в меню интерпретатора в правом нижнем углу выбери MicroPython (Raspberry Pi Pico). Если удобнее, ту же установку можно сделать в один клик в окне Thonny «Install or update MicroPython» (установить или обновить MicroPython), выбрав вариант Pico W / Pico WH.
- Набери в Shell import network. Если ошибки нет, установлена правильная прошивка с поддержкой беспроводной связи.
Шаг 2: подключение к Wi-Fi через network.WLAN
У Pico W два беспроводных интерфейса: в режиме WLAN.IF_STA (станция) она подключается к домашнему роутеру, как телефон, а в режиме WLAN.IF_AP (точка доступа) создаёт собственную сеть Wi-Fi. Начнём с режима станции. Вставь код ниже в новый файл в Thonny, впиши имя сети и пароль и сохрани его на Pico под именем wifi.py. Все следующие примеры подключают этот файл через import wifi, так что пароль хранится только в одном месте. Если версия MicroPython старше 1.24, пиши эти константы как network.STA_IF и network.AP_IF; старые имена работают и в новых версиях.
1# wifi.py: Pico W'ye bu adla kaydet / save it to the Pico W with this name
2import network
3import time
4
5SSID = "AgAdi" # Wi-Fi adın / your Wi-Fi name
6PASSWORD = "Sifre123" # Wi-Fi şifren / your Wi-Fi password
7HOSTNAME = "picow" # http://picow.local adresi için / for http://picow.local
8
9STATUS = {
10 0: "Boşta / idle",
11 1: "Ağa katılıyor / joining",
12 2: "IP bekleniyor / waiting for IP",
13 3: "Bağlandı / connected",
14 -1: "Bağlantı başarısız / connection failed",
15 -2: "Ağ bulunamadı / network not found",
16 -3: "Şifre hatalı / wrong password",
17}
18
19
20def connect(timeout=20):
21 network.country("TR") # ülke kodu / country code
22 network.hostname(HOSTNAME) # ağdaki adı / name on the network
23 wlan = network.WLAN(network.WLAN.IF_STA)
24 wlan.active(True)
25 wlan.config(pm=network.WLAN.PM_NONE) # güç tasarrufunu kapat / disable power saving
26 if not wlan.isconnected():
27 wlan.connect(SSID, PASSWORD)
28 for _ in range(timeout):
29 code = wlan.status()
30 print(code, STATUS.get(code, "?"))
31 if code < 0 or code == 3:
32 break
33 time.sleep(1)
34 if wlan.status() != 3:
35 raise RuntimeError("Wi-Fi: " + STATUS.get(wlan.status(), "?"))
36 print("IP:", wlan.ifconfig()[0])
37 return wlan
38
39
40if __name__ == "__main__":
41 connect()Разберём главные строки. network.country("TR") сообщает беспроводной микросхеме, правилам каналов какой страны следовать; замени TR на двухбуквенный код своей страны, например RU, GB или US. Без этой строки могут плохо находиться сети на каналах 12 и 13, которые используют некоторые роутеры (в старых прошивках то же самое делает rp2.country()). wlan.config(pm=network.WLAN.PM_NONE) отключает энергосбережение (в старых примерах та же настройка записана как pm=0xa11140): по умолчанию Pico W экономит энергию, из-за чего веб-сервер может отвечать с задержкой, а соединение — обрываться через несколько часов. Цикл каждую секунду выводит код статуса и останавливается, когда тот доходит до 3 или приходит отрицательный код ошибки. Так плата не ждёт бесконечно, а на экране сразу видно, что пошло не так.
Что означают коды wlan.status()?
Большинство проблем с подключением решается за секунды, если посмотреть на число, которое возвращает wlan.status(). Для этих чисел в модуле network MicroPython есть и готовые константы; в таблице ниже есть и то и другое:
| Код | Константа | Значение | Что делать |
|---|---|---|---|
| 0 | STAT_IDLE | Подключения нет, ничего не запущено | Проверь, что вызваны wlan.active(True) и wlan.connect() |
| 1 | STAT_CONNECTING | Идёт подключение к сети | Подожди несколько секунд |
| 2 | (константы нет) | Подключено к сети, ожидание IP-адреса от роутера | Если это затянулось, проверь настройки DHCP на роутере |
| 3 | STAT_GOT_IP | Подключено, IP-адрес получен | Всё готово |
| -1 | STAT_CONNECT_FAIL | Подключиться не удалось | Проверь сигнал и питание, затем попробуй ещё раз |
| -2 | STAT_NO_AP_FOUND | Сеть не найдена | Проверь имя сети, диапазон 2,4 GHz и расстояние |
| -3 | STAT_WRONG_PASSWORD | Ошибка аутентификации | Введи пароль заново, следя за регистром букв |
Код -2 означает, что Pico W не видит твою сеть. Список окрестных сетей сразу показывает, в чём дело: если твоей сети в нём нет, она либо вещает на 5 GHz, либо сигнал слишком слабый. RSSI лучше -70 dBm (например, -55 dBm) — это комфортный уровень; около -80 dBm соединение начинает обрываться.
1import network
2
3wlan = network.WLAN(network.WLAN.IF_STA)
4wlan.active(True)
5for ssid, bssid, channel, rssi, security, hidden in wlan.scan():
6 print(ssid.decode(), "| kanal / channel:", channel, "| RSSI:", rssi, "dBm")Шаг 3: простой веб-сервер на MicroPython (страница вкл/выкл светодиода)
Теперь превратим Pico W в маленький веб-сервер, который можно открыть с телефона. Дополнительная библиотека не нужна, хватит модуля socket из MicroPython. Сохрани код ниже как main.py и запусти. Введи адрес, показанный в Shell (например, http://192.168.1.42), в браузере телефона, подключённого к той же сети Wi-Fi; кнопки ON и OFF на странице включают и выключают светодиод на плате.
1import socket
2from machine import Pin
3import wifi
4
5wlan = wifi.connect()
6led = Pin("LED", Pin.OUT) # Pico W dahili LED / Pico W onboard LED
7led_on = False
8
9
10def page(on):
11 state = "AÇIK / ON" if on else "KAPALI / OFF"
12 return """<!DOCTYPE html>
13<html><head><meta charset="utf-8">
14<meta name="viewport" content="width=device-width, initial-scale=1">
15<title>Pico W LED</title></head>
16<body style="font-family:sans-serif;text-align:center">
17<h1>Pico W LED</h1>
18<p>Durum / State: <b>""" + state + """</b></p>
19<p><a href="/on"><button style="font-size:24px">AÇ / ON</button></a>
20<a href="/off"><button style="font-size:24px">KAPAT / OFF</button></a></p>
21</body></html>"""
22
23
24addr = socket.getaddrinfo("0.0.0.0", 80)[0][-1]
25server = socket.socket()
26server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # EADDRINUSE hatasını önler / prevents EADDRINUSE
27server.bind(addr)
28server.listen(2)
29print("Tarayıcıda aç / open in browser: http://" + wlan.ifconfig()[0])
30
31while True:
32 client, remote = server.accept() # bir tarayıcı bekle / wait for a browser
33 try:
34 request = client.recv(1024) # b"GET /on HTTP/1.1 ..."
35 parts = request.split(b" ")
36 path = parts[1] if len(parts) > 1 else b"/"
37 if path == b"/on":
38 led.on()
39 led_on = True
40 elif path == b"/off":
41 led.off()
42 led_on = False
43 if path in (b"/", b"/on", b"/off"):
44 client.sendall("HTTP/1.0 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")
45 client.sendall(page(led_on))
46 else:
47 client.sendall("HTTP/1.0 404 Not Found\r\n\r\n") # ör. /favicon.ico / e.g. /favicon.ico
48 except OSError as e:
49 print("Bağlantı hatası / connection error:", e)
50 finally:
51 client.close()Как это работает. С помощью bind и listen Pico W начинает слушать порт 80 (HTTP), а accept() ждёт, пока подключится браузер. Первая строка запроса браузера выглядит как «GET /on HTTP/1.1»; код разбивает её по пробелам, находит запрошенный путь (/on) и выставляет светодиод в нужное состояние. Затем он отправляет HTTP-заголовок («HTTP/1.0 200 OK» и тип содержимого), пустую строку и, наконец, HTML-страницу, после чего закрывает соединение. Строка meta viewport отвечает за правильный масштаб страницы на телефоне, а charset=utf-8 — за корректное отображение кириллицы и других особых символов.
| Путь | Что делает |
|---|---|
| / | Показывает страницу и текущее состояние светодиода |
| /on | Включает светодиод и снова отправляет страницу |
| /off | Выключает светодиод и снова отправляет страницу |
| /favicon.ico и другие | Возвращает 404; браузеры сами запрашивают этот путь ради значка вкладки |
Реле или внешний светодиод вместо встроенного
Когда всё заработает со встроенным светодиодом, для управления настоящим устройством с той же страницы достаточно поменять одну строку: вместо Pin("LED", Pin.OUT) напиши, например, Pin(16, Pin.OUT). Подходящий резистор для внешнего светодиода можно рассчитать в калькуляторе резистора для светодиода; для пина 3,3 V хватит 220–330 Ω. Если используется модуль реле, питай его от пина VBUS (5 V), а его вход IN подключи к GPIO. Многие модули реле срабатывают по сигналу LOW; в этом случае поменяй местами строки led.on() и led.off(). Подробнее о подключении реле — в статье Что такое модуль реле?
| Деталь | Вывод детали | Пин Pico W (номер физического вывода) |
|---|---|---|
| Внешний светодиод | Анод (+), через резистор 220 Ω | GP14 (19) |
| Внешний светодиод | Катод (−) | GND (18) |
| DHT22 | VCC / DATA / GND | 3V3(OUT) (36) / GP15 (20) / GND (38) |
| Модуль реле | VCC | VBUS, 5 V от USB (40) |
| Модуль реле | IN | GP16 (21) |
| Модуль реле | GND | GND (23) |
Шаг 4: данные датчика на веб-странице в реальном времени
Страница со светодиодом при каждом нажатии кнопки перезагружалась целиком. На странице с измерениями гораздо приятнее, когда значения обновляются без перезагрузки. Для этого используем два пути: / отдаёт саму страницу, а /data — только измерения в формате JSON. Небольшой кусок JavaScript на странице каждые две секунды читает /data и обновляет цифры. В примере показаны встроенный датчик температуры, которому не нужны дополнительные детали, и уровень сигнала Wi-Fi (RSSI); сервер построен на модуле asyncio из MicroPython, поэтому Pico W продолжает измерять, пока ждёт запросов.
1import asyncio
2import json
3import time
4from machine import ADC, Pin
5import wifi
6
7wlan = wifi.connect()
8sensor = ADC(4) # dahili sıcaklık sensörü / internal temperature sensor
9led = Pin("LED", Pin.OUT)
10start = time.time()
11readings = {"temp": 0, "rssi": 0, "uptime": 0}
12
13HTML = """<!DOCTYPE html>
14<html><head><meta charset="utf-8">
15<meta name="viewport" content="width=device-width, initial-scale=1">
16<title>Pico W</title></head>
17<body style="font-family:sans-serif;text-align:center">
18<h1>Pico W</h1>
19<p>Sıcaklık / Temperature: <b id="t">-</b> °C</p>
20<p>Wi-Fi sinyali / signal: <b id="r">-</b> dBm</p>
21<p>Çalışma süresi / uptime: <b id="u">-</b> s</p>
22<script>
23async function update() {
24 try {
25 const d = await (await fetch("/data")).json();
26 document.getElementById("t").textContent = d.temp;
27 document.getElementById("r").textContent = d.rssi;
28 document.getElementById("u").textContent = d.uptime;
29 } catch (e) {}
30}
31update();
32setInterval(update, 2000);
33</script>
34</body></html>"""
35
36
37def read_temp():
38 volts = sensor.read_u16() * 3.3 / 65535
39 return round(27 - (volts - 0.706) / 0.001721, 1)
40
41
42async def measure():
43 while True:
44 readings["temp"] = read_temp()
45 readings["rssi"] = wlan.status("rssi") # yalnız STA modunda / STA mode only
46 readings["uptime"] = time.time() - start
47 led.toggle() # kalp atışı / heartbeat
48 await asyncio.sleep(2)
49
50
51async def handle(reader, writer):
52 try:
53 line = await reader.readline() # b"GET /data HTTP/1.1"
54 while True: # başlıkları atla / skip the headers
55 header = await reader.readline()
56 if header in (b"\r\n", b""):
57 break
58 parts = line.split(b" ")
59 path = parts[1] if len(parts) > 1 else b"/"
60 if path == b"/":
61 writer.write(b"HTTP/1.0 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")
62 writer.write(HTML.encode())
63 elif path == b"/data":
64 writer.write(b"HTTP/1.0 200 OK\r\nContent-Type: application/json\r\n\r\n")
65 writer.write(json.dumps(readings).encode())
66 else:
67 writer.write(b"HTTP/1.0 404 Not Found\r\n\r\n")
68 await writer.drain()
69 except OSError as e:
70 print("Bağlantı hatası / connection error:", e)
71 finally:
72 writer.close()
73 await writer.wait_closed()
74
75
76async def main():
77 await asyncio.start_server(handle, "0.0.0.0", 80)
78 print("Tarayıcıda aç / open in browser: http://" + wlan.ifconfig()[0])
79 await measure()
80
81
82asyncio.run(main())asyncio.start_server() запускает функцию handle отдельной задачей для каждого нового подключения браузера, а задача measure() в фоне каждые две секунды снимает показание и переключает встроенный светодиод. Мигающий светодиод заодно показывает, что плата не зависла. Обрати внимание: при работе с asyncio перед отправкой переводи текст в байты через .encode(), иначе страницы с кириллицей и другими особыми символами будут вызывать ошибку. Встроенный датчик температуры измеряет температуру самой микросхемы, поэтому его показания шумные и на несколько градусов отличаются от комнатной; формула 27 − (V − 0.706) / 0.001721 в коде взята из даташита RP2040. Для настоящей комнатной температуры используй внешний датчик.

Для настоящей температуры и влажности подключи DHT22 (вывод DATA к GP15). Драйвер датчиков DHT встроен в прошивку Pico W, так что загружать ничего дополнительно не нужно. В функции measure() кода с датчиком замени строку readings["temp"] = read_temp() вызовом read_sensor() из кода ниже и добавь в HTML ещё одну строку для влажности. DHT22 нельзя опрашивать чаще чем раз в две секунды, а цикл как раз работает с таким шагом. Подробнее о датчике — в статье Датчик температуры и влажности DHT11.
1import dht
2from machine import Pin
3
4dht_sensor = dht.DHT22(Pin(15)) # DATA ucu GP15'te / DATA pin on GP15
5
6
7def read_sensor():
8 try:
9 dht_sensor.measure() # ölçümü başlat / trigger a reading
10 readings["temp"] = dht_sensor.temperature() # °C
11 readings["hum"] = dht_sensor.humidity() # % bağıl nem / % relative humidity
12 except OSError as e:
13 print("DHT22 okunamadı / read failed:", e)Шаг 5: запросы к API через urequests (данные из интернета)
Pico W может быть не только сервером, но и клиентом: отправить запрос онлайн-сервису и прочитать ответ. Модуль requests уже встроен в прошивку Pico W; имя urequests из старых примеров указывает на тот же модуль, поэтому работают оба варианта. Пример ниже получает текущую температуру, влажность и скорость ветра для Стамбула из бесплатного погодного сервиса Open-Meteo, которому не нужен ключ API. Для своего города достаточно поменять LAT и LON, например 55.75 и 37.62 для Москвы или 51.51 и -0.13 для Лондона.
1import requests
2import wifi
3
4wifi.connect()
5
6# İstanbul; kendi konumunu yaz / Istanbul; put your own location
7LAT, LON = 41.01, 28.98
8URL = ("https://api.open-meteo.com/v1/forecast?latitude={}&longitude={}"
9 "¤t=temperature_2m,relative_humidity_2m,wind_speed_10m").format(LAT, LON)
10
11response = requests.get(URL)
12try:
13 if response.status_code == 200:
14 current = response.json()["current"]
15 print("Sıcaklık / temperature:", current["temperature_2m"], "°C")
16 print("Nem / humidity:", current["relative_humidity_2m"], "%")
17 print("Rüzgâr / wind:", current["wind_speed_10m"], "km/h")
18 else:
19 print("HTTP hatası / HTTP error:", response.status_code)
20finally:
21 response.close() # soketi ve belleği serbest bırak / free the socket and memoryВ этом коде стоит следить за тремя вещами. Первое: после каждого ответа вызывай response.close(); незакрытые ответы съедают сокеты и память, и через несколько запросов появится «OSError: [Errno 12] ENOMEM» (не хватает памяти). Второе: response.json() загружает весь ответ в память; у Pico W всего 264 КБ ОЗУ, поэтому с API, которые возвращают большой JSON, используй адреса, запрашивающие только нужные поля (как параметр current здесь). Третье: HTTPS-соединению нужна дополнительная память для шифрования; если запросы в цикле идут регулярно, вызов gc.collect() между ними уменьшает фрагментацию памяти. Тем же способом можно отправлять сообщения в Telegram, записывать данные в таблицу или получать курсы валют; настройка Telegram-бота такая же, как в статье Telegram-бот на ESP32.
Шаг 6: точное время из интернета по NTP
Внутри Pico W есть часы реального времени (RTC), но без резервной батарейки: при каждом включении платы часы сбрасываются на 1 января 2021 года. Пока есть подключение к Wi-Fi, получить точное время с NTP-серверов в интернете очень просто: функция settime() встроенного модуля ntptime выставляет внутренние часы по UTC. Для местного времени код добавляет постоянное смещение; в примере стоит 3 часа (10 800 секунд), как в Турции и в Москве (UTC+3), так что выставь UTC_OFFSET под свой часовой пояс, например 0 для Лондона зимой или -5 * 3600 для Нью-Йорка.
1import time
2import ntptime
3import wifi
4
5wifi.connect()
6ntptime.host = "pool.ntp.org" # varsayılan sunucu / default server
7UTC_OFFSET = 3 * 3600 # Türkiye UTC+3; kendi saat dilimini yaz / set your own time zone
8
9for attempt in range(5):
10 try:
11 ntptime.settime() # dahili saati UTC'ye ayarlar / sets the internal clock to UTC
12 print("Saat ayarlandı / time set")
13 break
14 except OSError as e:
15 print("NTP hatası / NTP error:", e)
16 time.sleep(2)
17
18DAYS = ("Pzt/Mon", "Sal/Tue", "Çar/Wed", "Per/Thu", "Cum/Fri", "Cmt/Sat", "Paz/Sun")
19
20while True:
21 y, mo, d, h, mi, s, wd, yd = time.localtime(time.time() + UTC_OFFSET)
22 print("%02d.%02d.%d %s %02d:%02d:%02d" % (d, mo, y, DAYS[wd], h, mi, s))
23 time.sleep(1)По умолчанию ntptime обращается к серверу pool.ntp.org и ждёт ответа одну секунду; если ответа нет, появляется «OSError: [Errno 110] ETIMEDOUT» (истекло время ожидания), поэтому код делает пять попыток. Внутренние часы со временем могут уходить на несколько секунд, так что в проектах, которые работают долго, вызывай settime() заново раз в день. В странах с переходом на летнее время смещение меняется дважды в год; это придётся учесть в коде проверкой даты. Чтобы показывать время на дисплее, объедини этот код с примерами на MicroPython из статей про OLED-дисплей или I2C LCD; версия для ESP32 — в статье ESP32 NTP.
Собственная сеть (режим AP) и адрес picow.local
Там, где роутера нет, например на стенде научной выставки или в саду, Pico W может раздавать собственную сеть Wi-Fi. В режиме точки доступа телефон подключается прямо к сети «PicoW-BlueGrays», а страница открывается по адресу http://192.168.4.1. Код веб-сервера работает без изменений: просто напиши строки ниже вместо wlan = wifi.connect() и добавь wlan = ap. Пароль должен быть не короче 8 символов. Строка с RSSI в примере с датчиком работает только в режиме станции, поэтому в режиме AP удали её. В этом режиме у Pico W нет доступа в интернет, так что примеры с NTP и API работать не будут.
1import network
2
3ap = network.WLAN(network.WLAN.IF_AP)
4ap.config(ssid="PicoW-BlueGrays", password="bluegrays123") # şifre en az 8 karakter / at least 8 characters
5ap.active(True)
6while not ap.active():
7 pass
8print("Ağ hazır / network ready:", ap.ifconfig()[0]) # genellikle 192.168.4.1 / usually 192.168.4.1Если каждый раз искать IP-адрес в Shell неудобно, можно пользоваться именем. Свежие версии MicroPython поддерживают mDNS на Pico W: благодаря строке network.hostname("picow") в wifi.py плата доступна и по адресу http://picow.local. Обычно этот адрес работает в Windows, macOS, Linux и на iPhone; некоторые телефоны на Android не открывают адреса .local, там используй IP-адрес. Чтобы IP-адрес никогда не менялся, надёжнее всего закрепить постоянный IP за MAC-адресом Pico W в настройках роутера (резервирование DHCP).
Заметка о Pico 2 W: что меняется?
У Pico 2 W те же размеры и та же раскладка пинов, что у Pico W, и та же беспроводная микросхема CYW43439, а процессор — более быстрый RP2350. С программной стороны отличается только прошивка: скачай с micropython.org файл RPI_PICO2_W, а при подключении с BOOTSEL диск появится под именем RP2350. Весь код на MicroPython из этой статьи работает без изменений. Благодаря 520 КБ ОЗУ HTTPS-запросы, большие ответы JSON и длинные HTML-страницы помещаются на Pico 2 W гораздо свободнее. В Arduino IDE выбери плату Raspberry Pi Pico 2W. Одно замечание: у ранних версий RP2350 есть известная ошибка микросхемы (E9), связанная со встроенными стягивающими резисторами (pull-down); для кнопок надёжнее всего подключать их к GND и использовать PULL_UP. О продвинутых возможностях вроде двух ядер и PIO читай в статье PIO и два ядра Pico.
Альтернатива: программирование Pico W в Arduino IDE (arduino-pico)
Если C++ и библиотеки Arduino привычнее, Pico W можно программировать из Arduino IDE с ядром arduino-pico от Earle Philhower. В нём есть библиотеки WiFi и WebServer, совместимые с библиотеками для ESP32, поэтому код веб-сервера, написанный для ESP32, работает на Pico W с небольшими изменениями.
- В Arduino IDE открой «Файл › Настройки» (File › Preferences) и добавь https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json в поле «Дополнительные ссылки для Менеджера плат» (Additional boards manager URLs).
- Найди pico в «Менеджере плат» (Boards Manager) и установи пакет Raspberry Pi Pico/RP2040/RP2350 от Earle F. Philhower.
- Выбери Raspberry Pi Pico W в «Инструменты › Плата» (Tools › Board); для Pico 2 W — Raspberry Pi Pico 2W.
- Для первой загрузки подключи плату с зажатой кнопкой BOOTSEL: Arduino IDE найдёт её как диск UF2. Для следующих загрузок достаточно выбрать последовательный порт в «Инструменты › Порт» (Tools › Port).
- После загрузки открой монитор порта на скорости 115200 бод и посмотри IP-адрес.
1#include <WiFi.h>
2#include <WebServer.h>
3#include <LEAmDNS.h>
4
5const char* ssid = "AgAdi"; // Wi-Fi adın / your Wi-Fi name
6const char* password = "Sifre123"; // Wi-Fi şifren / your Wi-Fi password
7
8WebServer server(80);
9bool ledOn = false;
10
11void sendPage() {
12 String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>"
13 "<meta name='viewport' content='width=device-width, initial-scale=1'>"
14 "<title>Pico W</title></head>"
15 "<body style='font-family:sans-serif;text-align:center'><h1>Pico W LED</h1>";
16 html += "<p>Durum / State: <b>";
17 html += ledOn ? "AÇIK / ON" : "KAPALI / OFF";
18 html += "</b></p><p><a href='/on'><button>AÇ / ON</button></a> ";
19 html += "<a href='/off'><button>KAPAT / OFF</button></a></p>";
20 html += "<p>Sıcaklık / Temp: ";
21 html += String(analogReadTemp(), 1); // dahili sensör / internal sensor
22 html += " °C</p></body></html>";
23 server.send(200, "text/html", html);
24}
25
26void setup() {
27 Serial.begin(115200);
28 pinMode(LED_BUILTIN, OUTPUT); // Pico W'de kablosuz yongadaki LED / the LED on the wireless chip
29 WiFi.mode(WIFI_STA);
30 WiFi.begin(ssid, password);
31 while (WiFi.status() != WL_CONNECTED) {
32 delay(500);
33 Serial.print(".");
34 }
35 Serial.println();
36 Serial.print("IP: ");
37 Serial.println(WiFi.localIP()); // bu adresi telefonda aç / open this address on your phone
38
39 MDNS.begin("picow"); // http://picow.local
40 server.on("/", sendPage);
41 server.on("/on", []() { ledOn = true; digitalWrite(LED_BUILTIN, HIGH); sendPage(); });
42 server.on("/off", []() { ledOn = false; digitalWrite(LED_BUILTIN, LOW); sendPage(); });
43 server.onNotFound([]() { server.send(404, "text/plain", "404"); });
44 server.begin();
45}
46
47void loop() {
48 server.handleClient();
49 MDNS.update();
50}Этот скетч делает то же, что и страница со светодиодом на MicroPython, и добавляет внутреннюю температуру, считанную через analogReadTemp(). На Pico W LED_BUILTIN автоматически управляет светодиодом на беспроводной микросхеме, а строка MDNS.begin("picow") делает страницу доступной и по адресу http://picow.local. Драйвер Wi-Fi добавляет к скомпилированной программе около 220 КБ, поэтому первая сборка может занять время. Выбирая между MicroPython и Arduino, держи в голове: в MicroPython код сохраняется и сразу проверяется, а в Arduino приходится ждать компиляции, зато код работает быстрее и поддержка библиотек шире.
Идеи проектов на Raspberry Pi Pico W
- Wi-Fi-термометр: следи с телефона за температурой и влажностью, которые измеряет DHT11 или DHT22.
- Лампа с управлением с телефона: добавь к странице со светодиодом из этой статьи модуль реле и включай и выключай настольную лампу.
- Контроль влажности растения: показывай на странице показания датчика влажности почвы и предупреждение, когда земля пересыхает.
- Оповещение о движении: когда PIR-датчик замечает человека, отправляй через urequests сообщение в Telegram на телефон.
- Интернет-часы: выводи время по NTP с датой и днём недели на OLED-дисплей.
- Домашняя автоматизация: установи библиотеку umqtt.simple через mip и отправляй показания в Home Assistant по MQTT; идея разобрана в статье ESP32 MQTT.
- Панель в реальном времени: для страниц, которые обновляются быстрее, перенеси на Pico W идеи из статьи об асинхронном веб-сервере на ESP32 с WebSocket.
Частые ошибки и их решение
| Симптом или ошибка | Причина | Решение |
|---|---|---|
| ImportError: no module named 'network' (нет модуля network) | В Pico W загружена прошивка для обычной Pico | Загрузи файл UF2 для RPI_PICO_W (для Pico 2 W — RPI_PICO2_W) |
| wlan.status() всё время -2 | Сеть не видна: 5 GHz, неверное имя сети или слабый сигнал | Включи диапазон 2,4 GHz, поищи сеть через wlan.scan(), поднеси плату ближе к роутеру |
| wlan.status() возвращает -3 | Неверный пароль | Введи пароль заново, следя за регистром и пробелами |
| OSError: [Errno 98] EADDRINUSE | Сокет предыдущего сервера всё ещё держит порт 80 | Используй SO_REUSEADDR, перезапусти через Ctrl+D |
| Страница не открывается на телефоне | Телефон в мобильной сети или гостевой сети Wi-Fi, либо на роутере включена изоляция клиентов | Подключи телефон к той же сети Wi-Fi и вводи адрес с http, а не https |
| OSError: -2 (urequests) | Не удалось определить адрес по имени хоста: нет Wi-Fi или проблема с DNS | Сначала вызови wifi.connect() и проверь URL |
| OSError: [Errno 12] ENOMEM | Закончилась память | Используй response.close() и gc.collect(), запрашивай ответы поменьше |
| Соединение обрывается через несколько часов | Энергосбережение или перезагрузка роутера | Используй pm=network.WLAN.PM_NONE, проверяй wlan.isconnected() в цикле и подключайся заново |
| Не работает после отключения от компьютера | Код не сохранён как main.py, или на Pico нет wifi.py | Сохрани оба файла на Pico |
Как видно, чтобы подключить Raspberry Pi Pico W к Wi-Fi, раздавать веб-страницу и получать данные из интернета, хватает пары файлов: wifi.py отвечает за подключение, а main.py — за сам проект. Чтобы закрепить основы Pico, в приложении BlueGrays есть проекты на Raspberry Pi Pico с мигающими светодиодами, светофором, ШИМ и RGB-светодиодами, а для ESP32 — проекты с подключением к Wi-Fi, асинхронным веб-сервером, часами по NTP и погодным API, и в каждом пошаговые схемы и код.
Частые вопросы
Поддерживает ли Raspberry Pi Pico W Wi-Fi 5 GHz?
Нет. Микросхема CYW43439 на Pico W и Pico 2 W работает только в диапазоне 2,4 GHz и не видит сети 5 GHz. Проверь, что диапазон 2,4 GHz на роутере включён; если оба диапазона используют одно имя и возникают проблемы, помогает дать сети 2,4 GHz отдельное имя.
Как установить MicroPython на Pico W?
Скачай с micropython.org файл .uf2 для платы RPI_PICO_W. Зажми кнопку BOOTSEL, подключи Pico W к компьютеру и перетащи файл на появившийся диск RPI-RP2. Плата перезагрузится и будет готова к работе с Thonny; то же самое делает окно Thonny «Install or update MicroPython» (установить или обновить MicroPython).
Как узнать IP-адрес Pico W?
После подключения IP-адрес выдаёт wlan.ifconfig()[0], а файл wifi.py из этой статьи выводит его в Shell. Если плата не подключена к компьютеру, посмотри список подключённых устройств в настройках роутера или попробуй http://picow.local на устройствах с поддержкой mDNS.
Почему встроенный светодиод Pico W не загорается через Pin(25)?
На Pico W встроенный светодиод подключён не к процессору, а к беспроводной микросхеме, а GP25 используется как линия выбора этой микросхемы. Пиши Pin("LED", Pin.OUT) в MicroPython или LED_BUILTIN в Arduino IDE, и светодиод загорится как надо. Такая запись работает и на обычной Pico, так что её можно использовать всегда.
Можно ли открыть веб-сервер Pico W из интернета?
Технически да, через проброс портов на роутере, но так делать не рекомендуется: в простом сервере на MicroPython нет ни шифрования, ни аутентификации. Для удалённого управления гораздо безопаснее посредник: MQTT, Telegram-бот или облачный IoT-сервис.
Pico W или ESP32: что лучше для проектов с Wi-Fi?
Обе платы дают Wi-Fi 2,4 GHz и Bluetooth. Если хочется работать на MicroPython с аккуратной документацией и пинами без сюрпризов, выбирай Pico W; если нужны большая скорость, много аналоговых входов и широкая поддержка библиотек Arduino, лучше подойдёт ESP32. Для простых проектов с веб-сервером, датчиками и API обе справляются без труда.
Что собрать после прочтения
Все проекты
Мигание встроенным светодиодом Raspberry Pi Pico (Pico и Pico W)
Первый проект серии Raspberry Pi Pico! Мигаем зелёным встроенным светодиодом, чтобы проверить, что плата работает, — классический первый опыт «Hello World». НИКАКИХ внешних компонентов, только Pico и USB-кабель. Код написан на MicroPython (официальном языке, поддерживаемом Raspberry Pi Foundation). Изучи в Thonny IDE класс machine.Pin, режим Pin.OUT, методы led.on()/off() и time.sleep(). Каждое переключение видно в выводе (REPL).

Raspberry Pi Pico: управление внешним светодиодом (макетная плата)
Следующий шаг после встроенного светодиода Pico: подключить внешний светодиод на макетной плате и управлять им через пин GP14. В этом проекте ты узнаешь, как использовать любой пин GPIO общего назначения у Pico как выход, какая полярность у светодиода (длинная ножка = анод/+, короткая = катод/–) и зачем нужен токоограничивающий резистор (220Ω). Без резистора через светодиод пойдёт слишком большой ток, и он может сгореть. Схема очень простая: Pico GP14 → резистор 220Ω → светодиод → GND.

Симулятор светофора на Pico (3 светодиода по очереди)
Настоящий светофор на красном, жёлтом и зелёном светодиодах — первый проект серии Pico с 3 светодиодами! Зелёный 4 с «едем», жёлтый 1,5 с «внимание», красный 3 с «стоп» и красный + жёлтый 1 с «приготовиться» (европейская схема светофора). Изучи объявление функций (def all_off()), логику конечного автомата (последовательность) и синхронизацию нескольких GPIO. Простая схема: 3 светодиода на GP11 (зелёный), GP12 (жёлтый), GP13 (красный), у каждого токоограничивающий резистор 220Ω.

Плавное затухание светодиода с PWM на Pico (эффект дыхания)
Светодиод больше не просто мигает — он дышит! С помощью PWM (широтно-импульсной модуляции) Raspberry Pi Pico яркость светодиода медленно растёт и медленно падает, как огонёк спящего MacBook. Изучи класс machine.PWM, duty_u16() (16-битная яркость 0–65535), частоту PWM (freq(1000) — 1000 циклов вкл/выкл в секунду, мерцания не видно), циклы range() с шагом (вверх и вниз) и почти аналоговый выход с цифрового пина.

Асинхронный веб-сервер на ESP32 (с выводом IP на LCD)
В этом проекте ESP32 превращается в асинхронный веб-сервер, которым можно управлять с телефона или компьютера в той же сети Wi-Fi. Благодаря библиотеке ESPAsyncWebServer сервер может обрабатывать несколько запросов одновременно (в отличие от классического WebServer.h, который блокируется на одном запросе). Открыв IP-адрес ESP32 в браузере, ты нажимаешь кнопки ON/OFF (маршруты /on и /off) и включаешь и выключаешь светодиод на GPIO 5.

Подключение ESP32 к Wi-Fi в режиме STA (с экраном LCD)
В этом проекте ESP32 надёжно и устойчиво к сбоям подключается к домашней сети Wi-Fi в режиме станции (STA). SSID и пароль хранятся в отдельном файле secrets.h, чтобы не утекли в Git; настроено автоматическое переподключение, а уровень сигнала RSSI и IP-адрес выводятся на I2C LCD-экран. Встроенный светодиод служит индикатором состояния. Это менеджер подключения уровня реальных устройств.

Точное время из интернета через NTP на ESP32
ESP32 подключается к Wi-Fi и получает точное время с точностью до миллисекунд от серверов NTP (Network Time Protocol). Благодаря функции configTzTime() автоматически применяется часовой пояс Турции (TRT, UTC+3), а в странах с летним временем переходы обрабатываются автоматически по строке POSIX TZ. Время выводится в монитор порта и на необязательный I2C LCD. configTzTime() запускает службу SNTP, которая периодически пересинхронизирует часы.

ESP32 HTTPClient + API погоды (с экраном LCD)
В этом проекте ESP32 через HTTPClient.h делает вызов REST API к сервису погоды (wttr.in) через интернет. Полученный ответ в JSON разбирается с помощью ArduinoJson v7, а город, температура, влажность, погода и ветер выводятся на I2C LCD на турецком и английском. wttr.in бесплатен и не требует ключа API — достаточно указать любое название города, чтобы получить текущую погоду. Данные автоматически обновляются каждые 30 минут.
Другие статьи
Приложение BlueGrays
Собери эту схему шаг за шагом в телефоне
Схема подключения, код и список деталей на одном экране. 200+ проектов на Arduino, ESP32 и Pico готовы к сборке.
Наведи камеру телефона
Наведи камеру на код — откроется магазин приложений на телефоне.
или открыть магазин

