Skip to content

ESP32 Setup Guide

There are two ways to get an ESP32 working with SiliconWit.io. Most people should use browser flashing - it needs no coding and takes a couple of minutes. If you want to write your own firmware instead, skip to Manual Setup with Arduino IDE.

Flash SiliconWit’s generic firmware straight from your browser - no Arduino IDE, no drivers, no code to write. It works for most ESP32 boards over USB.

Requirements: Chrome, Edge, or Opera on desktop or Android (Web Serial API - Safari and Firefox aren’t supported by any site, it’s a browser limitation). On Linux, if your board isn’t detected, run sudo usermod -aG dialout $USER and log back in.

  1. Log in to siliconwit.io and go to Add DeviceI have hardwareFlash an ESP32 (browser, no IDE)
  2. Plug in your board over USB. New or already flashed with something else - it gets erased automatically.
  3. Click Connect device and pick your board from the browser’s port picker
  4. Wait for flashing to finish (progress bar, usually under a minute)
  5. Give your device a name, then type your Wi-Fi network name and password - this goes straight from your browser to the board over the same USB cable, never through our servers
  6. Done - the device is created and claimed into your account automatically. No copying device IDs or access tokens by hand.

Already have a flashed board and just want to reconnect it (for example, after a factory reset) without erasing and reflashing again? Use Already flashed? Reconnect and set up Wi-Fi on the same page.

Setting Up a Purchased Device (Claim Code)

Section titled “Setting Up a Purchased Device (Claim Code)”

If you bought a SiliconWit Module - a unit that arrives already flashed, with a claim code or QR code printed on its label - you don’t need to flash or claim it manually:

  1. Go to Add DeviceI have hardwareFlash an ESP32 (browser, no IDE)
  2. Click Set up a purchased device (I have a claim code)
  3. Plug the unit in over USB and connect
  4. Enter the claim code from the label (format SW-XXXX-XXXX, or paste the full claim link/token)
  5. Type your Wi-Fi network name and password

The unit fetches its own real device ID and access token from our servers using that claim code and writes them to itself over the same USB connection - nobody, including us, ever has to type or copy the raw access token by hand. The unit stays unclaimed and ready for whoever activates it into their own account; setting up its Wi-Fi here doesn’t claim it into yours.

Every generic-firmware device can optionally stream its boot and debug logs to your browser over the same USB cable, useful when troubleshooting Wi-Fi or sensor issues. It’s off by default - turn it on from the device’s Settings tab, or check Enable Serial Monitor during the flash setup steps. No reflashing needed either way, and you can toggle it any time.

The generic firmware doesn’t need reflashing to support a sensor or actuator - you tell it what’s wired where from the dashboard instead. This is available in three places: the Flash a dev board wizard’s wiring step, the Hardware Wiring section when creating a custom device, and any existing device’s Settings → Hardware Wiring tab.

  1. Click Add pin, enter the GPIO number, and pick what’s connected
  2. Pick a command or field name from the dropdown - it lists this device’s existing names first, then some common suggestions, or choose Custom to type your own. New names are created automatically when you save
  3. Click Save Hardware Config

The firmware reads this configuration once at boot, so power-cycle the board (or send it a restart) after changing it.

Digital Output

Anything that’s simply on or off: relay, LED, buzzer, valve, solenoid. 1 GPIO.

Digital Input

Anything that reports a simple on/off state: motion sensor, button, door switch, float switch. 1 GPIO.

Analog Input

Anything with a variable voltage output: soil moisture, light, potentiometer, current sensor. 1 GPIO, must be GPIO1-10.

PWM Output

Variable output: dimming, motor/fan speed. Not for hobby servos. 1 GPIO.

DS18B20

Waterproof 1-Wire temperature probe. 1 GPIO + pull-up resistor.

DHT22

Temperature + humidity, single-wire timing protocol (also covers AM2302/AM2321). 1 GPIO.

BME280

Temperature + humidity + pressure, I2C. 2 GPIOs (SDA + SCL).

BH1750

Light level (lux), I2C. 2 GPIOs (SDA + SCL), its own bus - see note below.

These 8 types cover the large majority of common sensors and actuators. The first four are general electrical forms, not specific products - anything that fits the shape works, so pick by what your part actually does electrically, not by brand name. The last four are specific chip protocols the firmware speaks directly.

TypeWiringGPIO notes
Digital output3V3 (or 5V, check your module) + GND + 1 signal GPIOAny free GPIO. Does nothing if unwired, so it’s safe to leave configured
Digital input3V3/5V + GND + 1 signal GPIOAny free GPIO. Reads a stable “no motion”/off if unwired (pulled down in firmware)
Analog input3V3 + GND + 1 signal GPIOMust be GPIO1-10 (ADC1 only - ADC2 on GPIO11-20 has a documented Wi-Fi coexistence issue, so this firmware doesn’t use it). An unwired pin reads floating noise, not a stable value
PWM output3V3 (or a driver circuit for higher-power loads) + GND + 1 signal GPIOAny free GPIO, up to 8 PWM pins total. Outputs 0% duty until a command sets it

A reference for common real-world parts:

If you have this…Pick this typeField/command examples
Relay module (1/2/4/8-channel)Digital outputrelay, pump, valve
LED, buzzer, sirenDigital outputlight, buzzer, siren
Solenoid valve, lockDigital outputvalve, lock
PIR motion sensor (e.g. HC-SR501, AM312)Digital inputmotion
Push buttonDigital inputbutton
Door/window reed switchDigital inputdoor, window
Float switch (water level)Digital inputfloat_switch
Tilt/vibration switchDigital inputtilt, vibration
Capacitive or resistive soil moisture sensorAnalog inputsoil_moisture
LDR / photoresistorAnalog inputlight_level
PotentiometerAnalog inputposition
Current sensor with analog output (e.g. ACS712)Analog inputcurrent
Gas sensor with analog output (e.g. MQ-series)Analog inputcustom field name
Dimmable LED strip, DC motor/fan speedPWM outputbrightness, fan_speed
DS18B20 waterproof probeDS18B20probe_temp
DHT22 / AM2302 / AM2321DHT22temperature, humidity
BME280 breakout boardBME280bme280_temp, bme280_humidity, pressure
BH1750 / GY-302 light sensor breakoutBH1750light_level

Not supported yet - these need their own driver or a timing/protocol this firmware doesn’t implement:

  • Hobby servos (needs fixed 50Hz timing, different from this firmware’s PWM)
  • Ultrasonic distance sensors (e.g. HC-SR04 - needs a trigger/echo two-pin protocol)
  • mmWave presence/radar sensors (e.g. LD2410 - UART-based)
  • Other I2C sensor chips (e.g. MPU6050 accelerometer/gyro, ADS1115 precision ADC) - more can be added the same way BME280 and BH1750 were, each needs its own driver
  • RFID/NFC readers, SPI devices, capacitive touch sensors

If you need one of these, contact us or vote/request it on the roadmap - or write your own firmware instead, which can do anything the ESP32 itself is physically capable of.

A common pairing - detect motion, switch something on.

  1. Wire the PIR sensor: VCC → 3V3 (or 5V, check your module), GND → GND, OUT → GPIO 5
  2. Wire the relay module: VCC → 3V3 or 5V (check your module), GND → GND, IN → GPIO 4
  3. In Hardware Wiring, add a pin: GPIO 5, type Digital input, field motion
  4. Add another pin: GPIO 4, type Digital output, command relay
  5. Save, then power-cycle the board
  6. In Automation, create a rule: when motion becomes true, run command relaytrue

Not exhaustive - PSRAM and flash pins vary by module - but these are worth avoiding on ESP32-S3 dev boards specifically:

GPIOWhy
0BOOT button, also triggers factory reset (hold 5s at startup). Wiring something here means holding it low can reset the device
3Strapping pin (JTAG boot mode). Usually fine once booted, avoid if you see boot issues
19Native USB D- on most ESP32-S3 boards. Wiring this can break flashing/provisioning over USB
20Native USB D+ on most ESP32-S3 boards. Same risk as GPIO19
43UART0 TX (debug serial output). Wiring this can interfere with logs and flashing
44UART0 RX (debug serial input). Same risk as GPIO43
45Strapping pin, sets flash voltage at boot. Must stay floating or LOW at boot
46Strapping pin, controls boot messages. Must stay floating or LOW at boot

The Hardware Wiring page warns inline if you pick one of these.

There are two ways to wipe a device’s Wi-Fi and identity (for example, to hand it to someone else or reprovision it as a different device):

  • From the dashboard: send the Factory Reset command from the device’s Settings tab. Works any time the device is still in your account.
  • On the board itself: hold the board’s BOOT button while it’s running for a full, slow count of 5 seconds, then let go. There’s no LED or other physical signal for this - just hold the full 5 seconds (not less) and release. This works with no dashboard or account needed at all - use it if the device was already deleted, or you don’t remember which account it belongs to. To check it worked, try the Already flashed? Reconnect option on the flash page - if it responds, the reset worked.

Either way, reconnect using the Already flashed? option on the flash page afterward, even on the same network.

If a device’s saved credentials are ever rejected by our servers (for example, if it was deleted from a dashboard while still running), it now detects this automatically and resets itself into Wi-Fi setup mode the next time it’s powered on with a network connection - no button press needed.

Prefer to write and control your own firmware instead of SiliconWit’s generic one? Use the Define my own device path and program the board yourself.

  1. Log in to siliconwit.io and go to Add DeviceI have hardwareDefine my own device
  2. Choose a template or Start from Scratch
  3. Fill in:
    • Device Name: e.g., “ESP32 Sensor”
    • Device Type: Sensor
    • Data Interval: 10 seconds (for testing)
  4. In the Data Fields section, click Import and paste:
[
{ "name": "temperature", "label": "Temperature", "unit": "°C" },
{ "name": "humidity", "label": "Humidity", "unit": "%" }
]
  1. Click Validate, then Import
  2. Click Create Device
  3. Copy your Device ID (format: SWD-XXXXXX) and Access Token from the device page

See the Field Schema guide for nested fields, roles, and more examples.

  1. Open Arduino IDE
  2. Go to File → Preferences
  3. Add to “Additional Board Manager URLs”:
    https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
  4. Go to Tools → Board → Boards Manager
  5. Search for “esp32” and install

Install these libraries via Sketch → Include Library → Manage Libraries:

  • PubSubClient - MQTT client library
  • ArduinoJson - JSON parsing (optional but recommended)
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
// WiFi credentials
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
// SiliconWit.io MQTT settings
const char* mqtt_server = "mqtt.siliconwit.io";
const int mqtt_port = 8883;
const char* device_id = "SWD-XXXXXX"; // Replace with your Device ID
const char* access_token = "your-access-token"; // Replace with your Access Token
WiFiClientSecure espClient;
PubSubClient client(espClient);
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void reconnect() {
while (!client.connected()) {
Serial.print("Connecting to MQTT...");
if (client.connect(device_id, device_id, access_token)) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" retrying in 5 seconds");
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
setup_wifi();
espClient.setInsecure(); // For testing - use setCACert() in production
client.setServer(mqtt_server, mqtt_port);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// Send data every 10 seconds
static unsigned long lastMsg = 0;
if (millis() - lastMsg > 10000) {
lastMsg = millis();
// Create JSON payload
String payload = "{\"temperature\":25.5,\"humidity\":60}";
// Publish to telemetry topic
String topic = "d/" + String(device_id) + "/t";
client.publish(topic.c_str(), payload.c_str());
Serial.println("Data sent: " + payload);
}
}

For production, use TLS encryption:

#include <WiFiClientSecure.h>
WiFiClientSecure espClient;
PubSubClient client(espClient);
void setup() {
// ... WiFi setup ...
espClient.setInsecure(); // For testing only
// For production, use: espClient.setCACert(root_ca);
client.setServer(mqtt_server, 8883); // TLS port
}
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#define DHTPIN 4
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
// ... WiFi and MQTT setup ...
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
static unsigned long lastMsg = 0;
if (millis() - lastMsg > 30000) {
lastMsg = millis();
float temp = dht.readTemperature();
float hum = dht.readHumidity();
if (!isnan(temp) && !isnan(hum)) {
String payload = "{\"temperature\":" + String(temp) +
",\"humidity\":" + String(hum) + "}";
String topic = "d/" + String(device_id) + "/t";
client.publish(topic.c_str(), payload.c_str());
}
}
}
#define uS_TO_S_FACTOR 1000000
#define TIME_TO_SLEEP 300 // 5 minutes
void setup() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
if (client.connect(device_id, device_id, access_token)) {
// Read and send data
String payload = "{\"temperature\":25.5}";
String topic = "d/" + String(device_id) + "/t";
client.publish(topic.c_str(), payload.c_str());
delay(100); // Allow message to send
client.disconnect();
}
// Go to sleep
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
esp_deep_sleep_start();
}
void loop() {
// Never reached
}
ProblemSolution
WiFi won’t connectCheck SSID/password, ensure 2.4GHz network
MQTT connection failsVerify device ID and access token
Messages not appearingCheck topic format matches dashboard

Enable verbose logging:

Serial.setDebugOutput(true);