Skip to content

Wi-Fi & APIs

The ESP32 has Wi-Fi built in. Once it's online, your projects can pull in live data (weather, time, sports scores) and send messages out, like a notification to your phone. No new parts needed!

You'll need:

  • A 2.4 GHz Wi-Fi network and its password
  • A phone with the free ntfy app (for the notification example)

2.4 GHz only

The ESP32 can't see 5 GHz networks. Most home routers broadcast both, so this is rarely a problem. School and office networks that need a login page after you connect won't work, though.

Setup

Keep your password in secrets.py

Instead of typing your Wi-Fi password into every program, keep it in one file called secrets.py:

  1. Open secrets_example.py and copy its contents into a new file in Thonny.
  2. Fill in your Wi-Fi name (SSID) and PASSWORD, keeping the quote marks.
  3. Save it onto your ESP32 as secrets.py.
secrets.py
# Copy this file to your ESP32 as secrets.py and fill in your details.
# Keep secrets.py private: don't share it or upload it anywhere.

SSID = "your-wifi-name"
PASSWORD = "your-wifi-password"

# Only needed for the Motion Alert project. Pick something long and
# hard to guess - anyone who knows the topic name can see your alerts.
NTFY_TOPIC = "circuitcoder-change-me-7f3k9q"

# Only needed for the Alarm Clock project: your offset from UTC in hours.
# e.g. -5 for New York in winter, -4 in summer, 1 for Berlin in winter.
UTC_OFFSET_HOURS = -5

Don't share secrets.py

If you post your code online or send it to a friend, leave secrets.py out. That way you never leak your password by accident.

The wifi module

Connecting takes a few steps, so, just like button.py, we've wrapped them in a module. Save wifi.py onto your ESP32 too.

wifi.py
wifi.py
# wifi.py - connect the ESP32 to your Wi-Fi network.
#
# Usage:
#   import wifi
#   wifi.connect()     # uses the SSID and PASSWORD from secrets.py

import time
import network


def connect(timeout_s=20):
    import secrets  # your Wi-Fi name and password live in secrets.py

    wlan = network.WLAN(network.WLAN.IF_STA)
    wlan.active(True)
    if not wlan.isconnected():
        print("Connecting to", secrets.SSID, "...")
        wlan.connect(secrets.SSID, secrets.PASSWORD)
        start = time.ticks_ms()
        while not wlan.isconnected():
            if time.ticks_diff(time.ticks_ms(), start) > timeout_s * 1000:
                raise RuntimeError("Could not connect to Wi-Fi. "
                                   "Check the name and password in secrets.py")
            time.sleep(0.25)
    print("Connected! IP address:", wlan.ipconfig("addr4")[0])
    return wlan

It switches on the ESP32's station interface (the part that joins an existing network, like your phone does), connects, and waits until it has an IP address. If it hasn't connected after 20 seconds, it stops with an error instead of waiting forever.

Connect!

wifi_connect.py
# Connect to Wi-Fi (needs wifi.py and your secrets.py on the board)
import wifi

wlan = wifi.connect()
print("Signal strength:", wlan.status("rssi"), "dBm")

You should see something like:

Connecting to MyHomeWiFi ...
Connected! IP address: 192.168.1.42
Signal strength: -58 dBm

Signal strength is measured in negative numbers. Closer to 0 is stronger: −50 is excellent, and below −80 is weak.

What's an API?

When you visit a website, the server sends back a page designed for people to look at. An API (application programming interface) is a web address built for programs instead. It sends back just the data, usually as JSON, which looks a lot like a Python dictionary:

{"current": {"temperature_2m": 18.4, "wind_speed_10m": 11.2}}

There are two main kinds of request:

  • GET asks a server for data. "What's the weather?"
  • POST sends data to a server. "Deliver this message."

MicroPython's built-in requests module handles both.

GET: live weather

Open-Meteo is a free weather API that doesn't need an account. Change LATITUDE and LONGITUDE to your own location: right-click a spot on Google Maps and the coordinates appear at the top of the menu.

api_weather.py
# Get the current weather from the free Open-Meteo API (no account needed)
import requests
import wifi

# Change these to your own location (find them on a map site)
LATITUDE = 40.71
LONGITUDE = -74.01

URL = ("https://api.open-meteo.com/v1/forecast"
       "?latitude=" + str(LATITUDE) +
       "&longitude=" + str(LONGITUDE) +
       "&current=temperature_2m,wind_speed_10m")

wifi.connect()

response = requests.get(URL)   # send the GET request
print("Status code:", response.status_code)   # 200 means OK
data = response.json()          # turn the JSON text into a dictionary
response.close()                # always close, to free up memory

current = data["current"]
print("Temperature:", current["temperature_2m"], "°C")
print("Wind speed:", current["wind_speed_10m"], "km/h")
  • requests.get(URL) sends the request and waits for the reply.
  • response.status_code is 200 if everything went well. Codes in the 400s mean something was wrong with the request (like a typo in the URL), and 500s mean the server had a problem.
  • response.json() converts the JSON text into a Python dictionary, so data["current"]["temperature_2m"] digs out the temperature.
  • response.close() frees up the memory the reply was using. The ESP32 doesn't have much, so always close your responses.

Prefer Fahrenheit?

Add &temperature_unit=fahrenheit&wind_speed_unit=mph to the end of the URL. The Open-Meteo docs list everything else you can ask for, from rain to UV index.

POST: notifications on your phone

ntfy ("notify") is a free service that pushes a notification to your phone whenever something POSTs a message to a topic. No account needed.

  1. Install the ntfy app from your phone's app store.
  2. Make up a topic name that's long and hard to guess, like circuitcoder-alex-7f3k9q. Topics are public: anyone who knows the name can read your messages, or send you some!
  3. In the app, tap + and subscribe to your topic.
  4. Put the same name in NTFY_TOPIC in your secrets.py, and save it to the board again.
ntfy_hello.py
# Send a push notification to your phone with ntfy.sh
import requests
import secrets
import wifi

wifi.connect()

response = requests.post(
    "https://ntfy.sh/" + secrets.NTFY_TOPIC,
    data="Hello from my ESP32!",
)
print("Status code:", response.status_code)   # 200 means it was sent
response.close()

Run it and your phone should buzz within a second or two. 🎉

Getting the time

The ESP32 has a clock, but it resets to the year 2000 every time the board restarts. The built-in ntptime module sets it correctly from an internet time server:

ntp_time.py
# Set the ESP32's clock from the internet and print the local time
import time
import ntptime
import secrets
import wifi

wifi.connect()
ntptime.settime()   # sets the clock to UTC (world time)

while True:
    # add your time zone offset to get local time
    local = time.localtime(time.time() + secrets.UTC_OFFSET_HOURS * 3600)
    year, month, day, hour, minute, second = local[0:6]
    print("{}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(
        year, month, day, hour, minute, second))
    time.sleep(1)

The time server gives UTC (world time), so the code adds UTC_OFFSET_HOURS from secrets.py to get your local time. You'll need to change it by an hour when the clocks go forward or back. You'll use this in the Alarm Clock project.

Challenge

Combine what you've learned: every time the button on GPIO 14 is pressed, fetch the temperature and send it to your phone with ntfy. (No solution this time. You've got everything you need!)

Next up: RGB LEDs: mix any colour you like from red, green and blue.