pico beginner 20 min

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.

Code available for: MicroPython
Published Sep 22, 2026

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/24 from 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:

SettingTypical value
Static IP192.168.1.50 (choose one OUTSIDE the DHCP pool)
Subnet mask255.255.255.0
Gateway192.168.1.1 (the router)
DNS192.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/hosts on Linux/macOS or C:\Windows\System32\drivers\etc\hosts on Windows: add a line 192.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.local does 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 before connect().
  • 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 after connect(). Reorder: active(True), then ifconfig(...), then connect(...).
  • 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 with wlan.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.