Files
Portfolio/blog-posts/63-esp32-development.md
T
damjan_savicandClaude Opus 4.5 43484c5023 Add blog posts, cleanup unused files, update components
- Add 100 blog posts covering AI, development, and tech topics
- Add .env.example for environment configuration
- Add accessibility and lighthouse audit scripts
- Remove obsolete SEO reports and temporary files
- Remove dev-dist build artifacts and backup files
- Remove unused portrait images (moved/consolidated elsewhere)
- Update contact form and component improvements

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 11:42:11 +01:00

735 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ESP32 Development mit PlatformIO
**Meta-Description:** ESP32 Entwicklung mit PlatformIO. WiFi, Sensoren, MQTT Integration und OTA Updates für IoT-Projekte.
**Keywords:** ESP32, PlatformIO, Arduino, IoT, WiFi, MQTT, Sensors, Embedded Development
---
## Einführung
Der **ESP32** ist der vielseitigste Microcontroller für IoT-Projekte. Mit WiFi, Bluetooth, dualen Cores und zahlreichen GPIOs kombiniert mit **PlatformIO** als moderne Entwicklungsumgebung.
---
## ESP32 Overview
```
┌─────────────────────────────────────────────────────────────┐
│ ESP32 ARCHITECTURE │
├─────────────────────────────────────────────────────────────┤
│ │
│ CPU: Xtensa dual-core 32-bit LX6 @ 240MHz │
│ │
│ Memory: │
│ ├── 520 KB SRAM │
│ ├── 4 MB Flash (external) │
│ └── 448 KB ROM │
│ │
│ Connectivity: │
│ ├── WiFi 802.11 b/g/n (2.4 GHz) │
│ ├── Bluetooth 4.2 + BLE │
│ └── Multiple SPI, I2C, UART, I2S │
│ │
│ GPIO: │
│ ├── 34 GPIO Pins │
│ ├── 18 ADC Channels (12-bit) │
│ ├── 2 DAC Channels (8-bit) │
│ ├── 16 PWM Channels │
│ └── 10 Touch Sensors │
│ │
│ Power: │
│ ├── Operating Voltage: 3.3V │
│ ├── Deep Sleep: ~10µA │
│ └── Active WiFi: ~160mA │
│ │
│ Peripherals: RTC, Timers, Watchdog, Hall Sensor │
│ │
└─────────────────────────────────────────────────────────────┘
```
---
## PlatformIO Setup
```bash
# VS Code Extension installieren
# Extensions → PlatformIO IDE
# Oder CLI Installation
pip install platformio
# Neues Projekt erstellen
pio project init --board esp32dev --ide vscode
```
```ini
; platformio.ini
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
upload_speed = 921600
; Build Flags
build_flags =
-DCORE_DEBUG_LEVEL=3
-DCONFIG_ARDUHAL_LOG_COLORS=1
; Libraries
lib_deps =
bblanchon/ArduinoJson@^7.0.0
knolleary/PubSubClient@^2.8
adafruit/DHT sensor library@^1.4.6
adafruit/Adafruit Unified Sensor@^1.1.14
; OTA Updates
upload_protocol = espota
upload_port = 192.168.1.100
; Filesystem
board_build.filesystem = littlefs
; Partitions
board_build.partitions = min_spiffs.csv
```
---
## WiFi Connection
```cpp
// src/main.cpp
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiManager.h>
// Credentials (besser: WiFiManager oder NVS)
const char* ssid = "YourNetwork";
const char* password = "YourPassword";
// Status LED
const int LED_PIN = 2;
void setupWiFi() {
Serial.println("Connecting to WiFi...");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 30) {
delay(500);
Serial.print(".");
digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Blink
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi connected!");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
Serial.print("RSSI: ");
Serial.println(WiFi.RSSI());
digitalWrite(LED_PIN, HIGH);
} else {
Serial.println("\nWiFi connection failed!");
// Fallback: AP Mode für Konfiguration
startConfigPortal();
}
}
void startConfigPortal() {
WiFiManager wifiManager;
// Reset settings for testing
// wifiManager.resetSettings();
// Custom Parameters
WiFiManagerParameter mqtt_server("mqtt", "MQTT Server", "mqtt.local", 40);
wifiManager.addParameter(&mqtt_server);
// Auto-connect oder Config Portal
if (!wifiManager.autoConnect("ESP32-Setup", "password123")) {
Serial.println("Failed to connect, restarting...");
delay(3000);
ESP.restart();
}
Serial.println("Connected via WiFiManager!");
Serial.println(mqtt_server.getValue());
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
setupWiFi();
}
void loop() {
// WiFi Reconnect
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi lost, reconnecting...");
setupWiFi();
}
delay(1000);
}
```
---
## Sensor Reading (DHT22)
```cpp
// src/sensors.cpp
#include <DHT.h>
#include <ArduinoJson.h>
#define DHT_PIN 4
#define DHT_TYPE DHT22
DHT dht(DHT_PIN, DHT_TYPE);
struct SensorData {
float temperature;
float humidity;
float heatIndex;
bool valid;
};
SensorData readDHT22() {
SensorData data = {0, 0, 0, false};
// Mehrere Versuche für zuverlässige Messung
for (int i = 0; i < 3; i++) {
data.temperature = dht.readTemperature();
data.humidity = dht.readHumidity();
if (!isnan(data.temperature) && !isnan(data.humidity)) {
data.heatIndex = dht.computeHeatIndex(
data.temperature,
data.humidity,
false // Celsius
);
data.valid = true;
break;
}
delay(2000); // DHT braucht Zeit zwischen Messungen
}
return data;
}
String sensorDataToJson(const SensorData& data) {
JsonDocument doc;
doc["device_id"] = WiFi.macAddress();
doc["timestamp"] = millis();
doc["temperature"] = round(data.temperature * 10) / 10.0;
doc["humidity"] = round(data.humidity * 10) / 10.0;
doc["heat_index"] = round(data.heatIndex * 10) / 10.0;
doc["valid"] = data.valid;
doc["rssi"] = WiFi.RSSI();
String output;
serializeJson(doc, output);
return output;
}
void setup() {
Serial.begin(115200);
dht.begin();
// Warm-up Zeit
delay(2000);
}
void loop() {
SensorData data = readDHT22();
if (data.valid) {
String json = sensorDataToJson(data);
Serial.println(json);
} else {
Serial.println("Sensor read failed!");
}
delay(10000); // Alle 10 Sekunden
}
```
---
## MQTT Integration
```cpp
// src/mqtt_client.cpp
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
const char* mqtt_server = "mqtt.example.com";
const int mqtt_port = 1883;
const char* mqtt_user = "esp32";
const char* mqtt_pass = "secret";
WiFiClient espClient;
PubSubClient mqtt(espClient);
String deviceId;
String baseTopic;
void mqttCallback(char* topic, byte* payload, unsigned int length) {
Serial.printf("Message [%s]: ", topic);
// Payload zu String
String message;
for (unsigned int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.println(message);
// JSON parsen
JsonDocument doc;
if (deserializeJson(doc, message) == DeserializationError::Ok) {
handleCommand(doc);
}
}
void handleCommand(const JsonDocument& doc) {
const char* action = doc["action"];
if (strcmp(action, "restart") == 0) {
Serial.println("Restart command received");
ESP.restart();
}
else if (strcmp(action, "led") == 0) {
bool state = doc["state"];
digitalWrite(LED_BUILTIN, state);
Serial.printf("LED: %s\n", state ? "ON" : "OFF");
}
else if (strcmp(action, "config") == 0) {
// Konfiguration aktualisieren
int interval = doc["interval"] | 10000;
Serial.printf("New interval: %d\n", interval);
}
}
void mqttReconnect() {
while (!mqtt.connected()) {
Serial.println("Connecting to MQTT...");
// Last Will Testament
String willTopic = baseTopic + "/status";
if (mqtt.connect(
deviceId.c_str(),
mqtt_user,
mqtt_pass,
willTopic.c_str(),
1, // QoS
true, // Retain
"offline"
)) {
Serial.println("MQTT connected!");
// Online Status
mqtt.publish(willTopic.c_str(), "online", true);
// Subscribe to commands
String cmdTopic = baseTopic + "/command";
mqtt.subscribe(cmdTopic.c_str());
// Broadcast Commands
mqtt.subscribe("devices/all/command");
} else {
Serial.printf("MQTT failed, rc=%d\n", mqtt.state());
delay(5000);
}
}
}
void publishSensorData(const SensorData& data) {
if (!mqtt.connected()) {
mqttReconnect();
}
JsonDocument doc;
doc["device_id"] = deviceId;
doc["temperature"] = data.temperature;
doc["humidity"] = data.humidity;
doc["heat_index"] = data.heatIndex;
doc["rssi"] = WiFi.RSSI();
doc["uptime"] = millis() / 1000;
String output;
serializeJson(doc, output);
String topic = baseTopic + "/data";
mqtt.publish(topic.c_str(), output.c_str());
Serial.println("Data published");
}
void setupMQTT() {
deviceId = "esp32-" + WiFi.macAddress();
deviceId.replace(":", "");
baseTopic = "sensors/" + deviceId;
mqtt.setServer(mqtt_server, mqtt_port);
mqtt.setCallback(mqttCallback);
mqtt.setBufferSize(512); // Größerer Buffer für JSON
mqttReconnect();
}
void loopMQTT() {
if (!mqtt.connected()) {
mqttReconnect();
}
mqtt.loop();
}
```
---
## OTA Updates
```cpp
// src/ota.cpp
#include <ArduinoOTA.h>
#include <ESPmDNS.h>
void setupOTA() {
// Hostname
ArduinoOTA.setHostname("esp32-sensor");
// Password
ArduinoOTA.setPassword("ota_secret");
// Port (default: 3232)
ArduinoOTA.setPort(3232);
ArduinoOTA.onStart([]() {
String type = ArduinoOTA.getCommand() == U_FLASH
? "sketch" : "filesystem";
Serial.println("OTA Start: " + type);
// MQTT disconnect
mqtt.disconnect();
});
ArduinoOTA.onEnd([]() {
Serial.println("\nOTA End");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
switch (error) {
case OTA_AUTH_ERROR: Serial.println("Auth Failed"); break;
case OTA_BEGIN_ERROR: Serial.println("Begin Failed"); break;
case OTA_CONNECT_ERROR: Serial.println("Connect Failed"); break;
case OTA_RECEIVE_ERROR: Serial.println("Receive Failed"); break;
case OTA_END_ERROR: Serial.println("End Failed"); break;
}
});
ArduinoOTA.begin();
Serial.println("OTA Ready");
}
void loopOTA() {
ArduinoOTA.handle();
}
```
---
## Deep Sleep für Batterie-Betrieb
```cpp
// src/deep_sleep.cpp
#include <esp_sleep.h>
#define uS_TO_S_FACTOR 1000000ULL
#define SLEEP_DURATION_S 300 // 5 Minuten
RTC_DATA_ATTR int bootCount = 0;
void printWakeupReason() {
esp_sleep_wakeup_cause_t reason = esp_sleep_get_wakeup_cause();
switch (reason) {
case ESP_SLEEP_WAKEUP_EXT0:
Serial.println("Wakeup: External GPIO");
break;
case ESP_SLEEP_WAKEUP_TIMER:
Serial.println("Wakeup: Timer");
break;
case ESP_SLEEP_WAKEUP_TOUCHPAD:
Serial.println("Wakeup: Touchpad");
break;
default:
Serial.printf("Wakeup: Other (%d)\n", reason);
break;
}
}
void goToSleep() {
Serial.println("Going to deep sleep...");
Serial.flush();
// Timer Wakeup
esp_sleep_enable_timer_wakeup(SLEEP_DURATION_S * uS_TO_S_FACTOR);
// GPIO Wakeup (z.B. Button)
esp_sleep_enable_ext0_wakeup(GPIO_NUM_33, LOW);
// WiFi und Bluetooth ausschalten
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
btStop();
// Deep Sleep starten
esp_deep_sleep_start();
}
void setup() {
Serial.begin(115200);
bootCount++;
Serial.printf("Boot count: %d\n", bootCount);
printWakeupReason();
// Sensor lesen und senden
setupWiFi();
setupMQTT();
SensorData data = readDHT22();
if (data.valid) {
publishSensorData(data);
}
// Kurz warten für MQTT
delay(1000);
mqtt.loop();
// Zurück in Deep Sleep
goToSleep();
}
void loop() {
// Wird bei Deep Sleep nicht erreicht
}
```
---
## Web Server für Konfiguration
```cpp
// src/webserver.cpp
#include <ESPAsyncWebServer.h>
#include <LittleFS.h>
#include <ArduinoJson.h>
AsyncWebServer server(80);
void setupWebServer() {
// Static Files aus LittleFS
if (!LittleFS.begin(true)) {
Serial.println("LittleFS mount failed");
return;
}
server.serveStatic("/", LittleFS, "/www/")
.setDefaultFile("index.html");
// API: Sensor Status
server.on("/api/status", HTTP_GET, [](AsyncWebServerRequest *request) {
JsonDocument doc;
doc["device_id"] = deviceId;
doc["ip"] = WiFi.localIP().toString();
doc["rssi"] = WiFi.RSSI();
doc["uptime"] = millis() / 1000;
doc["free_heap"] = ESP.getFreeHeap();
doc["temperature"] = lastReading.temperature;
doc["humidity"] = lastReading.humidity;
String output;
serializeJson(doc, output);
request->send(200, "application/json", output);
});
// API: Konfiguration
server.on("/api/config", HTTP_GET, [](AsyncWebServerRequest *request) {
JsonDocument doc;
doc["mqtt_server"] = mqtt_server;
doc["mqtt_port"] = mqtt_port;
doc["interval"] = readInterval;
String output;
serializeJson(doc, output);
request->send(200, "application/json", output);
});
// API: Konfiguration speichern
AsyncCallbackJsonWebHandler* configHandler = new AsyncCallbackJsonWebHandler(
"/api/config",
[](AsyncWebServerRequest *request, JsonVariant &json) {
JsonObject obj = json.as<JsonObject>();
// Konfiguration in NVS speichern
saveConfig(obj);
request->send(200, "application/json", "{\"success\": true}");
}
);
server.addHandler(configHandler);
// API: Restart
server.on("/api/restart", HTTP_POST, [](AsyncWebServerRequest *request) {
request->send(200, "application/json", "{\"restarting\": true}");
delay(100);
ESP.restart();
});
// 404 Handler
server.onNotFound([](AsyncWebServerRequest *request) {
request->send(404, "text/plain", "Not Found");
});
server.begin();
Serial.println("Web server started");
}
```
---
## GPIO & PWM Control
```cpp
// src/gpio_control.cpp
// LED PWM
const int LED_PIN = 2;
const int PWM_CHANNEL = 0;
const int PWM_FREQ = 5000;
const int PWM_RESOLUTION = 8;
void setupPWM() {
ledcSetup(PWM_CHANNEL, PWM_FREQ, PWM_RESOLUTION);
ledcAttachPin(LED_PIN, PWM_CHANNEL);
}
void setLEDBrightness(int brightness) {
// 0-255
ledcWrite(PWM_CHANNEL, brightness);
}
void fadeLED() {
for (int duty = 0; duty <= 255; duty++) {
ledcWrite(PWM_CHANNEL, duty);
delay(10);
}
for (int duty = 255; duty >= 0; duty--) {
ledcWrite(PWM_CHANNEL, duty);
delay(10);
}
}
// Analog Input
const int ANALOG_PIN = 34;
int readAnalog() {
// 12-bit ADC: 0-4095
int raw = analogRead(ANALOG_PIN);
// Zu Spannung konvertieren (3.3V Ref)
float voltage = (raw / 4095.0) * 3.3;
return raw;
}
// Touch Sensor
const int TOUCH_PIN = T0; // GPIO4
void setupTouch() {
touchAttachInterrupt(TOUCH_PIN, touchCallback, 40);
}
void touchCallback() {
Serial.println("Touch detected!");
}
```
---
## Projektstruktur
```
esp32-sensor/
├── platformio.ini
├── src/
│ ├── main.cpp
│ ├── wifi.cpp
│ ├── mqtt.cpp
│ ├── sensors.cpp
│ ├── ota.cpp
│ └── webserver.cpp
├── include/
│ ├── config.h
│ └── secrets.h
├── lib/
│ └── CustomLibrary/
├── data/
│ └── www/
│ ├── index.html
│ └── style.css
└── test/
└── test_main.cpp
```
---
## Fazit
ESP32 mit PlatformIO bietet:
1. **Dual-Core Power**: 240MHz für anspruchsvolle Aufgaben
2. **Connectivity**: WiFi + Bluetooth integriert
3. **Low Power**: Deep Sleep für Batterie-Betrieb
4. **Modern Tooling**: PlatformIO + VS Code
Ideale Plattform für IoT-Projekte.
---
## Bildprompts
1. "ESP32 microcontroller with connected sensors, breadboard prototype"
2. "PlatformIO IDE with code and serial monitor, embedded development"
3. "IoT sensor node with battery and antenna, compact device design"
---
## Quellen
- [PlatformIO ESP32 Documentation](https://docs.platformio.org/en/latest/platforms/espressif32.html)
- [Random Nerd Tutorials ESP32](https://randomnerdtutorials.com/vs-code-platformio-ide-esp32-esp8266-arduino/)
- [ESP32 Arduino Core](https://docs.espressif.com/projects/arduino-esp32/en/latest/)
- [Sunfounder ESP32 Guide](https://www.sunfounder.com/blogs/news/how-to-set-up-esp32-on-platformio-with-vs-code-complete-step-by-step-guide)