Bare-metal C firmware for the Raspberry Pi Pico W (RP2040 + CYW43439 Wi-Fi) that turns the board into a Wi-Fi-connected smart environment controller. It hosts an embedded HTTP server directly on the microcontroller, serving a web dashboard that monitors temperature and light sensors across four zones and controls a relay in either manual or automatic mode.
- Overview
- Features
- Hardware Requirements
- Software Architecture
- Project Structure
- Getting Started
- Web Interface
- Relay Modes
- Contributing
- License
After booting, the Pico W connects to a configured Wi-Fi network and starts a lwIP-based HTTP server. Any device on the same network can open the dashboard in a browser to view live sensor readings and send control commands — no cloud service or external broker required. Everything runs entirely on the microcontroller.
- 📶 Wi-Fi connectivity via the CYW43439 chip (WPA2-AES)
- 🌐 Embedded HTTP server powered by lwIP's
httpdmodule - 🌡️ Internal ADC temperature sensor — reads the RP2040's on-chip temperature
- 📊 4-zone sensor monitoring — tracks temperature and light levels across four channels
- 🔁 Relay control — toggle on/off with manual override or automatic thermostat mode
- 🤖 Automatic relay mode — relay activates when the average temperature across all four zones falls below the configurable comfort threshold (default: 23 °C)
- 💡 LED control — turn the onboard LED on, off, or set it to blink
- 📁 HTML served from flash — web pages baked into firmware via
makefsdata.py - 🔌 SSI templating — live sensor values injected server-side into HTML pages
- 🖱️ CGI handlers — browser-triggered actions map to hardware state changes
| Component | Details |
|---|---|
| Raspberry Pi Pico W | RP2040 + CYW43439 Wi-Fi/BT |
| Temperature sensors (×4) | Connected to ADC channels (or simulated) |
| Light sensors (×4) | Connected to ADC channels (or simulated) |
| Relay module | Controlled via GPIO |
| Power supply | USB or external 5 V |
| Wi-Fi router | WPA2 network |
┌────────────────────────────────────────────────────┐
│ Pico W Firmware │
│ │
│ ┌──────────┐ ┌─────────┐ ┌────────────────┐ │
│ │ main.c │──▶│ ssi.h │ │ cgi.h │ │
│ │ │ │ │ │ │ │
│ │ Wi-Fi │ │ Inject │ │ /led.cgi │ │
│ │ init │ │ sensor │ │ /relay.cgi │ │
│ │ ADC read │ │ data │ │ /info.cgi │ │
│ │ Auto │ │ into │ │ /send_info.cgi │ │
│ │ relay │ │ HTML │ │ │ │
│ └──────────┘ └─────────┘ └────────────────┘ │
│ │ │
│ ┌─────▼──────────────────────────────────────┐ │
│ │ globaldata.h │ │
│ │ temperatureVector[4] lightVector[4] │ │
│ │ relayState relayMode ledBlink │ │
│ │ confortableTemperature (23.0 °C) │ │
│ └────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────▼──────────────────────┐ │
│ │ lwIP httpd (SSI + CGI + static files) │ │
│ │ HTML served from flash │ │
│ └────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────┘
│
HTTP over Wi-Fi (LAN)
│
┌──────────▼──────────┐
│ Browser / Client │
│ index.shtml │
│ info.shtml │
└─────────────────────┘
Microcontroller-Software/
├── main.c # Entry point — Wi-Fi init, ADC loop, relay automaton
├── ssi.h # Server-Side Include handler (injects live sensor data)
├── cgi.h # CGI handlers (LED, relay, info endpoints)
├── postrequest.h # POST request handling
├── globaldata.h # Shared global state (sensor arrays, relay, LED flags)
├── lwipopts.h # lwIP stack configuration
├── html_files/ # Raw HTML/CSS source for the web dashboard
├── htmldata.c # Compiled HTML filesystem (generated by makefsdata.py)
├── makefsdata.py # Python script — converts html_files/ into htmldata.c
├── CMakeLists.txt # CMake build definition
├── pico_sdk_import.cmake # Pico SDK bootstrapper
└── .vscode/ # VS Code workspace settings
Install the following on your development machine:
- Raspberry Pi Pico SDK (with submodules)
arm-none-eabi-gcctoolchain- CMake ≥ 3.13
- Python 3 (for
makefsdata.py) ninjaormake
On Ubuntu/Debian:
sudo apt update
sudo apt install cmake gcc-arm-none-eabi build-essential python3 gitSet the PICO_SDK_PATH environment variable:
export PICO_SDK_PATH=/path/to/pico-sdkBefore building, update the Wi-Fi credentials in main.c:
const char WIFI_SSID[] = "YOUR_WIFI_SSID";
const char WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD";To change the automatic relay threshold, edit globaldata.h:
float confortableTemperature = 23.0; // °C — relay activates below this value
⚠️ Security notice: Avoid committing real Wi-Fi credentials to a public repository. Consider using asecrets.hfile added to.gitignore.
The web dashboard HTML files must be compiled into a C array before building the firmware:
python3 makefsdata.pyThis reads files from html_files/ and generates htmldata.c, which is linked into the firmware so the Pico W can serve pages directly from flash.
mkdir build && cd build
cmake ..
make -j$(nproc)The build will produce a *.uf2 file in the build/ directory.
- Hold the BOOTSEL button on the Pico W while connecting it via USB — it will mount as a USB mass storage device.
- Copy the
.uf2file onto the drive:
cp build/*.uf2 /media/$USER/RPI-RP2/The board will reboot automatically and begin connecting to Wi-Fi.
Once connected, find the Pico W's IP address (check your router's DHCP table or add serial output) and open it in a browser:
http://<pico-ip>/index.shtml
The firmware injects live data into .shtml pages using these Server-Side Include tags:
| Tag | Description |
|---|---|
<!--#myTemp--> |
Current on-chip ADC temperature (°C) |
<!--#temp1--> – <!--#temp4--> |
Temperature readings for zones 1–4 |
<!--#light1--> – <!--#light4--> |
Light readings for zones 1–4 |
<!--#relay--> |
Current relay state (on / off) |
<!--#mode--> |
Current relay mode (manual / auto) |
Control commands are sent via HTTP GET requests to these CGI endpoints:
| Endpoint | Parameter | Values | Action |
|---|---|---|---|
/led.cgi |
led |
0 |
Turn LED off |
/led.cgi |
led |
1 |
Turn LED on |
/led.cgi |
led |
3 |
Toggle LED blink |
/relay.cgi |
relay |
0 |
Toggle relay on/off |
/relay.cgi |
relay |
1 |
Toggle relay mode (manual ↔ auto) |
/info.cgi |
— | — | Navigate to info page |
Example using curl:
# Turn relay on/off
curl "http://<pico-ip>/relay.cgi?relay=0"
# Switch to automatic mode
curl "http://<pico-ip>/relay.cgi?relay=1"
# Toggle LED blink
curl "http://<pico-ip>/led.cgi?led=3"The relay supports two operating modes, selectable from the web interface:
Manual mode — the relay is toggled directly by the user via the /relay.cgi?relay=0 endpoint.
Automatic mode — the firmware monitors the rolling average temperature across all four sensor zones. If the average drops below confortableTemperature (default 23 °C), the relay is switched on automatically; it turns off once the threshold is exceeded. This enables the Pico W to function as a basic thermostat controller.
Contributions are welcome!
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Commit your changes:
git commit -m "Add my feature" - Push to the branch:
git push origin feature/my-feature - Open a Pull Request
This project does not currently specify a license. Please contact the author before using or distributing this work.
Built with ❤️ using C, the Raspberry Pi Pico SDK, and lwIP.