Pico W: set a static IP for a reliable local device
Give a Pico W a fixed IP address with MicroPython so bookmarks, port forwards, and automations keep working after the router reboots.
Every Pico W project I have that survived long-term has a fixed IP address. The web-server tutorial on this site gets a Pico W serving a page, but the address it prints is whatever the router’s DHCP server handed out that morning (e.g. 192.168.1.117 today, 192.168.1.124 after the next router reboot). A sensor dashboard with a moving address is a dashboard you stop opening.
The trap I hit: I set a static IP by guesswork, picked 192.168.1.200 because it sounded far enough from the crowd, and the Pico connected to Wi-Fi but reached nothing. The router’s DHCP pool started at .100 and ran to .199, and .200 was outside the pool but also outside the router’s subnet mask config for guests. The fix took ten minutes and one conversation with the router’s admin page. Do that conversation first, then write the code.
What you need
Needed
- Raspberry Pi Pico W with MicroPython installed
- Your Wi-Fi SSID and password
- Your router’s admin login (to check the DHCP pool and reserve the address you pick)
- Thonny or another MicroPython REPL
Nice to have
- A label maker or masking tape: write the IP on the Pico’s USB cable
- A network scanner app (e.g. Fing, or
nmap -sn 192.168.1.0/24from a laptop) to confirm nothing already owns the address - Anti-static wristband
The two ways to fix an address
Pick one. They are not equal.
DHCP reservation (the right way). You tell the router: “when the device with this MAC address asks for an address, always hand it 192.168.1.50.” The Pico does nothing special, the router keeps the book. The address stays inside the DHCP pool, so no conflicts, and the config lives in one place. Find the Pico’s MAC with a one-liner:
import network
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
print(wlan.config('mac'))
Then: router admin page >> LAN / DHCP settings >> Address Reservation (the menu name varies by brand: “DHCP Static Lease” on some, “Address Reservation” on ASUS, “DHCP Reservations” on Google Wifi). Add the MAC, pick the IP, reboot the router’s DHCP if it asks. Done. If you can do this, stop reading and do it.
Static IP in code (the portable way). You hard-code the address in
the Pico’s program. This is what this tutorial covers, because it works
when you cannot touch the router (a school network, a family member’s
house, a spare router at the shed) and it travels with main.py.
Setup: gather the facts from your network
A static config needs four numbers. Get them from a working device on the
same network first (e.g. your laptop): IP, netmask, gateway, DNS. On
Windows, ipconfig prints them; on macOS, System Settings >> Network >>
Details.
Typical home values look like:
| Setting | Typical value |
|---|---|
| Static IP | 192.168.1.50 (choose one OUTSIDE the DHCP pool) |
| Subnet mask | 255.255.255.0 |
| Gateway | 192.168.1.1 (the router) |
| DNS | 192.168.1.1 or 1.1.1.1 |
The Pico W reports its current values the same way you will later set them:
import network
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("your-wifi-ssid", "your-wifi-password")
import time
time.sleep(3)
print(wlan.ifconfig())
# (ip, subnet, gateway, dns) e.g. ('192.168.1.117', '255.255.255.0', '192.168.1.1', '192.168.1.1')
Copy those four values. They are the ground truth for your network, and the static config only changes the first one.
The code
Save as main.py on the Pico W:
import network
import time
SSID = "your-wifi-ssid"
PASSWORD = "your-wifi-password"
# The four numbers from your network (change the IP to your pick)
STATIC_IP = "192.168.1.50"
SUBNET = "255.255.255.0"
GATEWAY = "192.168.1.1"
DNS = "192.168.1.1"
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.config(pm = 0xa11140) # disable Wi-Fi power save: web server duty
wlan.ifconfig((STATIC_IP, SUBNET, GATEWAY, DNS))
wlan.connect(SSID, PASSWORD)
print("Connecting with static IP", STATIC_IP)
for _ in range(20):
if wlan.isconnected():
break
print(".", end="")
time.sleep(1)
if wlan.isconnected():
print()
print("Connected:", wlan.ifconfig())
else:
print()
print("Failed to connect. Common cause: static IP outside the subnet,")
print("or the router refuses non-DHCP clients on a guest network.")
The one line that matters is wlan.ifconfig(...). Call it BEFORE
connect(): you are telling the interface its address, then asking it to
join. Set it after connecting and the router’s DHCP answer overwrites
yours (or the connection just fails, depending on firmware version).
Run it. The REPL should print your four numbers with the static IP first.
From a computer on the same network, ping 192.168.1.50 should now
answer, and it will answer at the same address after every reboot, router
update, and power cut.
Static IP plus a device you can actually reach
The point of this exercise is a fixed URL for whatever the Pico does. Pair it with the Pico W web server tutorial and the address becomes the bookmark:
# after wlan.isconnected() and the socket setup from the web server tutorial
print("Sensor dashboard: http://{}".format(STATIC_IP))
Two extras worth doing once:
- A hostname entry on your own machine (e.g.
/etc/hostson Linux/macOS orC:\Windows\System32\drivers\etc\hostson Windows: add a line192.168.1.50 picow.local) so you type a name and not digits. - mDNS: MicroPython does not ship an mdns responder for the Pico W, so
picow.localdoes not work out of the box. The hosts-file entry is the two-minute fix.
What you learned
- DHCP reservation beats code-level static IP when you control the router; static IP in code is the portable fallback.
wlan.ifconfig((ip, subnet, gateway, dns))sets the address, and it goes beforeconnect().- The four numbers come from a working device on the same network, not from guesswork.
- The address you pick must be outside the router’s DHCP pool, and you confirm it is unused before assigning it.
When something breaks
- Connects to Wi-Fi, but nothing answers on the static IP. The IP is outside the router’s subnet or the DHCP pool handed the same address to someone else. Check the DHCP pool range in the router admin page, pick outside it, and ping the chosen address first to confirm it is unused.
wlan.ifconfig()keeps returning the old DHCP address. You set the static config afterconnect(). Reorder:active(True), thenifconfig(...), thenconnect(...).- Works at home, fails at a friend’s house. The static IP belongs to
your subnet. For portable projects, fall back: try static for a few
seconds, and if
isconnected()stays false, clear it withwlan.ifconfig('dhcp')and reconnect. - Drops off the network after a few minutes. Unrelated to the static
IP but it will get blamed for it: that is Wi-Fi power saving. The
wlan.config(pm = 0xa11140)line in the code above is the fix. - Guest network refuses the connection entirely. Many guest networks isolate clients from each other and pin devices to DHCP. Static IPs are for the main network; the portable fallback above handles the rest.
What to build next
- The Pico W sensor web server tutorial: serve readings at the address you just fixed.
- The Pico W MQTT publish tutorial: a fixed IP is not required for MQTT, but a fixed client identity keeps broker ACLs sane.
- The Raspberry Pi static-lease habit: reserve the same address for the Pi running Mosquitto or Samba, and your whole small network becomes predictable.