🎯 Exemples recommandés
Balanced sample collections from various categories for you to explore
Exemples de Développement ESP32
Exemples complets de développement ESP32 incluant les applications WiFi et Bluetooth, le développement MicroPython et C/C++, les appareils IoT basse consommation et les réseaux de capteurs de bord
💻 Station WiFi et Point d'Accès ESP32 cpp
Configuration complète de connectivité WiFi incluant mode station, point d'accès, reconnexion automatique et balayage réseau
// ESP32 WiFi Station and Access Point Example
// Complete WiFi management with auto-reconnection and network scanning
// PlatformIO IDE or Arduino IDE with ESP32 board support
#include <WiFi.h>
#include <WiFiMulti.h>
#include <DNSServer.h>
#include <WebServer.h>
#include <ESPmDNS.h>
// WiFi Configuration
const char* AP_SSID = "ESP32_Config";
const char* AP_PASSWORD = "12345678";
// Known WiFi networks (can be extended)
const char* KNOWN_SSIDS[] = {
"YourHomeWiFi",
"YourOfficeWiFi",
"YourMobileHotspot"
};
const char* KNOWN_PASSWORDS[] = {
"YourHomePassword",
"YourOfficePassword",
"YourMobilePassword"
};
const int KNOWN_NETWORKS = 3;
// Global objects
WiFiMulti wifiMulti;
WebServer server(80);
DNSServer dnsServer;
// Network status variables
bool wifiConnected = false;
bool apMode = false;
unsigned long lastReconnectAttempt = 0;
const unsigned long RECONNECT_INTERVAL = 30000; // 30 seconds
// Network scan results
int networkCount = 0;
String networks[20];
// Setup function
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n=== ESP32 WiFi Manager ===");
Serial.println("Initializing WiFi...");
// Initialize GPIO pins for status LEDs
pinMode(LED_BUILTIN, OUTPUT);
pinMode(2, OUTPUT); // Additional status LED
// Setup WiFi
setupWiFi();
// Setup DNS server for captive portal
dnsServer.start(53, "*", WiFi.softAPIP());
// Setup web server
setupWebServer();
// Start mDNS
if (MDNS.begin("esp32")) {
Serial.println("mDNS responder started");
}
Serial.println("WiFi Manager ready!");
}
// Main loop
void loop() {
// Handle DNS requests
if (apMode) {
dnsServer.processNextRequest();
}
// Handle web server requests
server.handleClient();
// Manage WiFi connection
manageWiFiConnection();
// Blink status LED based on connection status
blinkStatusLED();
// Periodic network scan
static unsigned long lastScan = 0;
if (millis() - lastScan > 60000) { // Scan every minute
if (wifiConnected) {
scanNetworks();
}
lastScan = millis();
}
delay(100);
}
// WiFi setup function
void setupWiFi() {
// Add known networks to WiFiMulti
for (int i = 0; i < KNOWN_NETWORKS; i++) {
wifiMulti.addAP(KNOWN_SSIDS[i], KNOWN_PASSWORDS[i]);
Serial.printf("Added network: %s\n", KNOWN_SSIDS[i]);
}
// Try to connect to known networks
Serial.println("Attempting to connect to known networks...");
int attempts = 0;
const int MAX_ATTEMPTS = 10;
while (wifiMulti.run() != WL_CONNECTED && attempts < MAX_ATTEMPTS) {
delay(500);
Serial.print(".");
attempts++;
}
if (wifiMulti.run() == WL_CONNECTED) {
wifiConnected = true;
apMode = false;
Serial.println();
Serial.printf("Connected to WiFi: %s\n", WiFi.SSID());
Serial.printf("IP Address: %s\n", WiFi.localIP().toString());
Serial.printf("Signal Strength: %d dBm\n", WiFi.RSSI());
// Start web server in station mode
server.begin();
Serial.println("HTTP server started");
} else {
Serial.println();
Serial.println("Failed to connect to known networks");
Serial.println("Starting Access Point mode...");
startAccessPoint();
}
}
// Start Access Point mode
void startAccessPoint() {
apMode = true;
wifiConnected = false;
// Start WiFi in AP mode
WiFi.mode(WIFI_AP_STA);
WiFi.softAP(AP_SSID, AP_PASSWORD);
IPAddress IP = WiFi.softAPIP();
Serial.printf("Access Point started\n");
Serial.printf("SSID: %s\n", AP_SSID);
Serial.printf("Password: %s\n", AP_PASSWORD);
Serial.printf("IP Address: %s\n", IP.toString());
// Start web server in AP mode
server.begin();
Serial.println("HTTP server started in AP mode");
}
// Manage WiFi connection
void manageWiFiConnection() {
if (apMode) {
return; // Skip connection management in AP mode
}
if (wifiConnected && WiFi.status() == WL_CONNECTED) {
// Connection is stable
return;
}
// Connection lost, try to reconnect
if (millis() - lastReconnectAttempt > RECONNECT_INTERVAL) {
Serial.println("WiFi connection lost, attempting to reconnect...");
lastReconnectAttempt = millis();
// Try to reconnect
if (wifiMulti.run() == WL_CONNECTED) {
wifiConnected = true;
Serial.printf("Reconnected to: %s\n", WiFi.SSID());
Serial.printf("IP Address: %s\n", WiFi.localIP().toString());
} else {
Serial.println("Reconnection failed");
// After multiple failed attempts, switch to AP mode
static int reconnectFailures = 0;
reconnectFailures++;
if (reconnectFailures >= 3) {
Serial.println("Multiple reconnection failures, switching to AP mode");
startAccessPoint();
reconnectFailures = 0;
}
}
}
}
// Scan for available networks
void scanNetworks() {
Serial.println("\nScanning for networks...");
networkCount = WiFi.scanNetworks();
if (networkCount == 0) {
Serial.println("No networks found");
return;
}
Serial.printf("Found %d networks:\n", networkCount);
for (int i = 0; i < min(networkCount, 20); i++) {
networks[i] = WiFi.SSID(i);
Serial.printf("%d: %s (RSSI: %d dBm, Encryption: %s)\n",
i + 1,
networks[i].c_str(),
WiFi.RSSI(i),
getEncryptionType(WiFi.encryptionType(i)).c_str());
}
WiFi.scanDelete();
}
// Get encryption type as string
String getEncryptionType(wifi_auth_mode_t encryptionType) {
switch (encryptionType) {
case WIFI_AUTH_OPEN: return "Open";
case WIFI_AUTH_WEP: return "WEP";
case WIFI_AUTH_WPA_PSK: return "WPA";
case WIFI_AUTH_WPA2_PSK: return "WPA2";
case WIFI_AUTH_WPA_WPA2_PSK: return "WPA+WPA2";
case WIFI_AUTH_WPA2_ENTERPRISE: return "WPA2-Enterprise";
default: return "Unknown";
}
}
// Setup web server
void setupWebServer() {
// Root page
server.on("/", HTTP_GET, []() {
String html = generateMainPage();
server.send(200, "text/html", html);
});
// WiFi scan page
server.on("/scan", HTTP_GET, []() {
String html = generateScanPage();
server.send(200, "text/html", html);
});
// Status page
server.on("/status", HTTP_GET, []() {
String json = generateStatusJSON();
server.send(200, "application/json", json);
});
// Connect to network
server.on("/connect", HTTP_POST, []() {
String ssid = server.arg("ssid");
String password = server.arg("password");
WiFi.begin(ssid.c_str(), password.c_str());
server.send(200, "text/plain", "Connecting to " + ssid);
});
// Disconnect from current network
server.on("/disconnect", HTTP_GET, []() {
WiFi.disconnect();
wifiConnected = false;
server.send(200, "text/plain", "Disconnected");
});
// Restart ESP32
server.on("/restart", HTTP_GET, []() {
server.send(200, "text/plain", "Restarting...");
delay(1000);
ESP.restart();
});
// Not found page
server.onNotFound([]() {
server.send(404, "text/plain", "Not found");
});
}
// Generate main HTML page
String generateMainPage() {
String html = R"(
<!DOCTYPE html>
<html>
<head>
<title>ESP32 WiFi Manager</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.container { max-width: 800px; margin: 0 auto; }
.status { background: #f0f8ff; padding: 15px; border-radius: 5px; margin: 10px 0; }
.connected { background: #e8f5e8; }
.disconnected { background: #ffe8e8; }
.network-list { list-style: none; padding: 0; }
.network-item { background: #f8f8f8; margin: 5px 0; padding: 10px; border-radius: 3px; }
.button { background: #007bff; color: white; padding: 10px 20px; text-decoration: none; border-radius: 3px; }
.button:hover { background: #0056b3; }
.rssi { float: right; color: #666; }
</style>
<script>
function refreshStatus() {
fetch('/status')
.then(response => response.json())
.then(data => {
document.getElementById('status').className = 'status ' + (data.connected ? 'connected' : 'disconnected');
document.getElementById('connection-info').innerHTML = data.html;
});
}
function connectToNetwork(ssid) {
const password = prompt('Enter password for ' + ssid + ':');
if (password) {
fetch('/connect', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'ssid=' + encodeURIComponent(ssid) + '&password=' + encodeURIComponent(password)
})
.then(response => response.text())
.then(data => {
alert(data);
setTimeout(refreshStatus, 3000);
});
}
}
// Auto-refresh status every 5 seconds
setInterval(refreshStatus, 5000);
refreshStatus();
</script>
</head>
<body>
<div class="container">
<h1>📡 ESP32 WiFi Manager</h1>
<div id="status" class="status">
<h3>Connection Status</h3>
<div id="connection-info">Loading...</div>
</div>
<div style="margin: 20px 0;">
<a href="/scan" class="button">🔍 Scan Networks</a>
<a href="javascript:location.reload()" class="button">🔄 Refresh</a>
<a href="/disconnect" class="button" onclick="return confirm('Disconnect from WiFi?')">❌ Disconnect</a>
<a href="/restart" class="button" onclick="return confirm('Restart ESP32?')">🔄 Restart</a>
</div>
</div>
</body>
</html>
)";
return html;
}
// Generate scan page
String generateScanPage() {
scanNetworks();
String html = R"(
<!DOCTYPE html>
<html>
<head>
<title>WiFi Networks</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.back-link { margin-bottom: 20px; }
.network-list { list-style: none; padding: 0; }
.network-item { background: #f8f8f8; margin: 5px 0; padding: 15px; border-radius: 5px; display: flex; justify-content: space-between; align-items: center; }
.network-info { flex: 1; }
.signal { float: right; color: #666; }
.encryption { font-size: 0.9em; color: #888; }
.button { background: #007bff; color: white; padding: 8px 16px; text-decoration: none; border-radius: 3px; margin-left: 10px; }
</style>
</head>
<body>
<div class="back-link">
<a href="/" class="button">← Back</a>
</div>
<h1>🔍 Available Networks</h1>
<p>Found )"+ String(networkCount) + R"( networks:</p>
<ul class="network-list">)";
for (int i = 0; i < min(networkCount, 20); i++) {
html += "<li class='network-item'>";
html += "<div class='network-info'>";
html += "<strong>" + networks[i] + "</strong><br>";
html += "<span class='encryption'>" + getEncryptionType(WiFi.encryptionType(i)) + "</span>";
html += "</div>";
html += "<div class='signal'>" + String(WiFi.RSSI(i)) + " dBm</div>";
html += "<button class='button' onclick='connectToNetwork("" + networks[i] + "")'>Connect</button>";
html += "</li>";
}
html += R"(</ul>
<script>
function connectToNetwork(ssid) {
const password = prompt('Enter password for ' + ssid + ':');
if (password) {
fetch('/connect', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'ssid=' + encodeURIComponent(ssid) + '&password=' + encodeURIComponent(password)
})
.then(response => response.text())
.then(data => {
alert(data);
window.location.href = '/';
});
}
}
</script>
</body>
</html>)";
return html;
}
// Generate status JSON
String generateStatusJSON() {
String json = "{";
json += ""connected":" + String(wifiConnected) + ",";
json += ""apMode":" + String(apMode) + ",";
json += ""html":"";
if (apMode) {
IPAddress IP = WiFi.softAPIP();
json += "<strong>Access Point Mode</strong><br>";
json += "SSID: " + String(AP_SSID) + "<br>";
json += "IP: " + IP.toString() + "<br>";
json += "Connected devices: " + String(WiFi.softAPgetStationNum());
} else if (wifiConnected) {
json += "<strong>Connected to:</strong> " + WiFi.SSID() + "<br>";
json += "<strong>IP Address:</strong> " + WiFi.localIP().toString() + "<br>";
json += "<strong>Signal Strength:</strong> " + String(WiFi.RSSI()) + " dBm<br>";
json += "<strong>Gateway:</strong> " + WiFi.gatewayIP().toString() + "<br>";
json += "<strong>DNS:</strong> " + WiFi.dnsIP().toString();
} else {
json += "<strong>Status:</strong> Not connected<br>";
json += "<strong>Scanning for networks...</strong>";
}
json += """;
json += "}";
return json;
}
// Blink status LED
void blinkStatusLED() {
static unsigned long lastBlink = 0;
static bool ledState = false;
unsigned long blinkInterval;
if (apMode) {
blinkInterval = 1000; // Slow blink in AP mode
} else if (wifiConnected) {
blinkInterval = 3000; // Very slow blink when connected
} else {
blinkInterval = 500; // Fast blink when disconnected
}
if (millis() - lastBlink > blinkInterval) {
ledState = !ledState;
digitalWrite(LED_BUILTIN, ledState ? HIGH : LOW);
digitalWrite(2, ledState ? HIGH : LOW);
lastBlink = millis();
}
}
// Helper function to get min value
int min(int a, int b) {
return (a < b) ? a : b;
}
💻 Communication Bluetooth ESP32 cpp
Implémentation Bluetooth Classic et BLE pour ESP32 incluant découverte d'appareils, transfert de données et mode périphérique
// ESP32 Bluetooth Communication Example
// Complete Bluetooth implementation with Classic and BLE
// Supports device discovery, data transfer, and peripheral modes
#include <BluetoothSerial.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#define LED_BUILTIN 2
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
// Global variables
BluetoothSerial SerialBT;
bool btConnected = false;
String connectedDeviceName = "";
String lastCommand = "";
// BLE variables
BLEServer* pServer = nullptr;
BLECharacteristic* pCharacteristic = nullptr;
bool deviceConnected = false;
bool oldDeviceConnected = false;
// Data storage
float temperature = 22.5;
float humidity = 65.0;
int lightLevel = 750;
unsigned long lastSensorUpdate = 0;
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n=== ESP32 Bluetooth Manager ===");
pinMode(LED_BUILTIN, OUTPUT);
// Initialize Bluetooth Classic (SPP)
setupBluetoothClassic();
// Initialize BLE
setupBLE();
// Initialize simulated sensors
initializeSensors();
Serial.println("Bluetooth Manager Ready!");
Serial.println("Classic SPP and BLE services are active");
}
void loop() {
// Handle Bluetooth Classic
handleBluetoothClassic();
// Handle BLE
handleBLE();
// Update sensor data
updateSensorData();
// Status LED management
manageStatusLED();
delay(100);
}
// Setup Bluetooth Classic (SPP)
void setupBluetoothClassic() {
Serial.begin(115200);
SerialBT.begin("ESP32_BT"); // Bluetooth device name
Serial.println("Bluetooth Classic (SPP) started");
Serial.println("Device name: ESP32_BT");
Serial.println("Ready to pair...");
}
// Setup BLE
void setupBLE() {
// Initialize BLE
BLEDevice::init("ESP32_BLE");
// Create BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create BLE Characteristic
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_INDICATE
);
pCharacteristic->addDescriptor(new BLE2902());
pCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(false);
pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter
BLEDevice::startAdvertising();
Serial.println("BLE server started");
Serial.println("Advertising started");
}
// Handle Bluetooth Classic communication
void handleBluetoothClassic() {
// Check for incoming data
if (SerialBT.available()) {
String command = SerialBT.readString();
command.trim();
Serial.println("BT Command received: " + command);
lastCommand = command;
// Process command
processCommand(command);
}
// Send periodic status updates
static unsigned long lastStatusUpdate = 0;
if (millis() - lastStatusUpdate > 5000) { // Every 5 seconds
if (SerialBT.hasClient()) {
String status = getStatusJSON();
SerialBT.println(status);
}
lastStatusUpdate = millis();
}
}
// Handle BLE events
void handleBLE() {
// Notify connected clients with sensor data
static unsigned long lastBLEUpdate = 0;
if (deviceConnected && millis() - lastBLEUpdate > 2000) {
String sensorData = getSensorJSON();
pCharacteristic->setValue(sensorData.c_str());
pCharacteristic->notify();
lastBLEUpdate = millis();
}
// Handle disconnection
if (!deviceConnected && oldDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
Serial.println("BLE started advertising again");
oldDeviceConnected = deviceConnected;
}
// Handle connection
if (deviceConnected && !oldDeviceConnected) {
Serial.println("BLE device connected");
oldDeviceConnected = deviceConnected;
}
}
// Process received command
void processCommand(String command) {
// Split command and parameters
int spaceIndex = command.indexOf(' ');
String cmd = command;
String param = "";
if (spaceIndex > 0) {
cmd = command.substring(0, spaceIndex);
param = command.substring(spaceIndex + 1);
}
// Command parsing
if (cmd == "LED") {
handleLEDCommand(param);
} else if (cmd == "TEMP") {
handleTemperatureCommand(param);
} else if (cmd == "HUMID") {
handleHumidityCommand(param);
} else if (cmd == "LIGHT") {
handleLightCommand(param);
} else if (cmd == "STATUS") {
sendStatus();
} else if (cmd == "HELP") {
sendHelp();
} else {
SerialBT.println("Unknown command: " + cmd);
SerialBT.println("Type HELP for available commands");
}
}
// Handle LED commands
void handleLEDCommand(String param) {
if (param == "ON") {
digitalWrite(LED_BUILTIN, HIGH);
SerialBT.println("LED turned ON");
} else if (param == "OFF") {
digitalWrite(LED_BUILTIN, LOW);
SerialBT.println("LED turned OFF");
} else if (param == "BLINK") {
for (int i = 0; i < 10; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(200);
digitalWrite(LED_BUILTIN, LOW);
delay(200);
}
SerialBT.println("LED blinked 10 times");
} else {
SerialBT.println("Usage: LED ON|OFF|BLINK");
}
}
// Handle temperature commands
void handleTemperatureCommand(String param) {
if (param == "GET") {
SerialBT.println("Temperature: " + String(temperature, 1) + "°C");
} else if (param.startsWith("SET")) {
float temp = param.substring(4).toFloat();
if (temp >= -40 && temp <= 85) {
temperature = temp;
SerialBT.println("Temperature set to: " + String(temperature, 1) + "°C");
} else {
SerialBT.println("Temperature out of range (-40 to 85°C)");
}
} else {
SerialBT.println("Usage: TEMP GET|SET <value>");
}
}
// Handle humidity commands
void handleHumidityCommand(String param) {
if (param == "GET") {
SerialBT.println("Humidity: " + String(humidity, 1) + "%");
} else if (param.startsWith("SET")) {
float hum = param.substring(4).toFloat();
if (hum >= 0 && hum <= 100) {
humidity = hum;
SerialBT.println("Humidity set to: " + String(humidity, 1) + "%");
} else {
SerialBT.println("Humidity out of range (0 to 100%)");
}
} else {
SerialBT.println("Usage: HUMID GET|SET <value>");
}
}
// Handle light commands
void handleLightCommand(String param) {
if (param == "GET") {
SerialBT.println("Light level: " + String(lightLevel));
} else if (param.startsWith("SET")) {
int light = param.substring(4).toInt();
if (light >= 0 && light <= 1023) {
lightLevel = light;
SerialBT.println("Light level set to: " + String(lightLevel));
} else {
SerialBT.println("Light level out of range (0 to 1023)");
}
} else {
SerialBT.println("Usage: LIGHT GET|SET <value>");
}
}
// Send status information
void sendStatus() {
String status = getStatusJSON();
SerialBT.println(status);
}
// Send help information
void sendHelp() {
SerialBT.println("\n=== ESP32 Bluetooth Commands ===");
SerialBT.println("LED ON|OFF|BLINK - Control built-in LED");
SerialBT.println("TEMP GET|SET <value> - Get/Set temperature");
SerialBT.println("HUMID GET|SET <value> - Get/Set humidity");
SerialBT.println("LIGHT GET|SET <value> - Get/Set light level");
SerialBT.println("STATUS - Get device status");
SerialBT.println("HELP - Show this help");
SerialBT.println("\nExamples:");
SerialBT.println("LED ON");
SerialBT.println("TEMP SET 25.5");
SerialBT.println("STATUS");
}
// Initialize simulated sensors
void initializeSensors() {
// Simulate sensor calibration
randomSeed(analogRead(0));
// Set initial values
temperature = 20.0 + (random(100) / 10.0);
humidity = 40.0 + (random(400) / 10.0);
lightLevel = random(1024);
Serial.println("Sensors initialized");
}
// Update sensor data (simulated)
void updateSensorData() {
if (millis() - lastSensorUpdate > 3000) { // Update every 3 seconds
// Simulate temperature changes
temperature += (random(200) - 100) / 100.0;
temperature = constrain(temperature, -40.0, 85.0);
// Simulate humidity changes
humidity += (random(100) - 50) / 10.0;
humidity = constrain(humidity, 0.0, 100.0);
// Simulate light level changes
lightLevel += (random(200) - 100);
lightLevel = constrain(lightLevel, 0, 1023);
lastSensorUpdate = millis();
}
}
// Get sensor data as JSON string
String getSensorJSON() {
String json = "{";
json += ""temperature":" + String(temperature, 1) + ",";
json += ""humidity":" + String(humidity, 1) + ",";
json += ""lightLevel":" + String(lightLevel) + ",";
json += ""timestamp":" + String(millis()) + ",";
json += ""device":"ESP32"";
json += "}";
return json;
}
// Get status as JSON string
String getStatusJSON() {
String json = "{";
json += ""status":"ok",";
json += ""device":"ESP32",";
json += ""btConnected":" + String(SerialBT.hasClient() ? "true" : "false") + ",";
json += ""bleConnected":" + String(deviceConnected ? "true" : "false") + ",";
json += ""temperature":" + String(temperature, 1) + ",";
json += ""humidity":" + String(humidity, 1) + ",";
json += ""lightLevel":" + String(lightLevel) + ",";
json += ""ledState":" + String(digitalRead(LED_BUILTIN) == HIGH ? "true" : "false") + ",";
json += ""uptime":" + String(millis());
json += "}";
return json;
}
// Manage status LED
void manageStatusLED() {
static unsigned long lastBlink = 0;
static bool ledState = false;
unsigned long blinkInterval = 1000;
if (SerialBT.hasClient() || deviceConnected) {
blinkInterval = 2000; // Slower blink when connected
} else {
blinkInterval = 500; // Faster blink when waiting for connection
}
if (millis() - lastBlink > blinkInterval) {
ledState = !ledState;
digitalWrite(LED_BUILTIN, ledState ? HIGH : LOW);
lastBlink = millis();
}
}
// BLE Server Callbacks
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
Serial.println("BLE device connected");
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
Serial.println("BLE device disconnected");
}
};
// BLE Characteristic Callbacks
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = pCharacteristic->getValue();
if (value.length() > 0) {
Serial.println("BLE received: " + String(value.c_str()));
// Parse BLE command
String bleCommand = String(value.c_str());
processCommand(bleCommand);
}
}
};
// Helper function to constrain value
float constrain(float value, float min_val, float max_val) {
if (value < min_val) return min_val;
if (value > max_val) return max_val;
return value;
}
💻 Appareil IoT ESP32 MicroPython python
Implémentation IoT complète utilisant MicroPython avec intégration de capteurs, journalisation des données et connectivité cloud
# ESP32 MicroPython IoT Device
# Complete IoT implementation with sensors, data logging, and cloud connectivity
# Requirements: MicroPython firmware on ESP32
import machine
import network
import time
import json
import ujson
import urequests
import ubinascii
import uos
import gc
from machine import Pin, I2C, ADC, PWM, RTC
from time import sleep_ms, sleep
# Device configuration
DEVICE_ID = ubinascii.hexlify(machine.unique_id()).decode()
DEVICE_NAME = f"ESP32_IOT_{DEVICE_ID[-6:]}"
WIFI_SSID = "YOUR_WIFI_SSID"
WIFI_PASSWORD = "YOUR_WIFI_PASSWORD"
# Cloud configuration (AWS IoT)
AWS_ENDPOINT = "YOUR_IOT_ENDPOINT.iot.us-west-2.amazonaws.com"
AWS_CLIENT_ID = f"esp32-{DEVICE_ID}"
AWS_KEY_PATH = "/private_key.der"
AWS_CERT_PATH = "/certificate.pem"
# Sensor configuration
SENSOR_UPDATE_INTERVAL = 5000 # 5 seconds
DATA_UPLOAD_INTERVAL = 30000 # 30 seconds
LOG_RETENTION_DAYS = 7
# Pins configuration
LED_PIN = 2
TEMP_SENSOR_PIN = 4
LIGHT_SENSOR_PIN = 32
PIR_SENSOR_PIN = 27
RELAY_PIN = 25
BUTTON_PIN = 0
# Global variables
wifi_connected = False
cloud_connected = False
last_sensor_reading = 0
last_cloud_upload = 0
sensor_data = {}
motion_detected = False
relay_state = False
# Initialize hardware components
class ESP32IoTDevice:
def __init__(self):
self.led = Pin(LED_PIN, Pin.OUT)
self.temp_sensor = ADC(Pin(TEMP_SENSOR_PIN))
self.light_sensor = ADC(Pin(LIGHT_SENSOR_PIN))
self.pir_sensor = Pin(PIR_SENSOR_PIN, Pin.IN)
self.relay = Pin(RELAY_PIN, Pin.OUT)
self.button = Pin(BUTTON_PIN, Pin.IN, Pin.PULL_UP)
# Configure ADC resolution
self.temp_sensor.atten(ADC.ATTN_11DB) # 0-3.6V range
self.light_sensor.atten(ADC.ATTN_11DB)
# Initialize RTC for data logging
self.rtc = RTC()
# Initialize I2C for potential future sensors
self.i2c = I2C(scl=Pin(22), sda=Pin(21), freq=400000)
# Data storage
self.local_data = []
self.setup_filesystem()
# Setup interrupt handlers
self.setup_interrupts()
print(f"{DEVICE_NAME} initialized")
self.led.off()
def setup_filesystem(self):
"""Setup filesystem for data logging"""
try:
# Create data directory if it doesn't exist
if '/data' not in uos.listdir():
uos.mkdir('/data')
# Initialize data log file
log_file = f'/data/sensor_log_{time.strftime("%Y%m%d")}.json'
if not self.file_exists(log_file):
with open(log_file, 'w') as f:
f.write('[]')
print("Filesystem initialized")
except Exception as e:
print(f"Filesystem setup error: {e}")
def setup_interrupts(self):
"""Setup hardware interrupt handlers"""
# Motion detection interrupt
self.pir_sensor.irq(trigger=Pin.IRQ_RISING, handler=self.motion_detected)
# Button press interrupt
self.button.irq(trigger=Pin.IRQ_FALLING, handler=self.button_pressed)
print("Interrupts configured")
def motion_detected(self, pin):
"""Motion detection interrupt handler"""
global motion_detected
motion_detected = True
print("Motion detected!")
def button_pressed(self, pin):
"""Button press interrupt handler"""
print("Button pressed - toggling relay")
self.toggle_relay()
def toggle_relay(self):
"""Toggle relay state"""
global relay_state
relay_state = not relay_state
self.relay.value(1 if relay_state else 0)
print(f"Relay {'ON' if relay_state else 'OFF'}")
def read_temperature(self):
"""Read temperature from sensor (simulated for demo)"""
# For demo purposes, using random values
# In real implementation, connect DS18B20 or DHT22 sensor
import random
temp = 20 + random.uniform(-5, 15)
return round(temp, 1)
def read_humidity(self):
"""Read humidity (simulated for demo)"""
import random
humidity = 50 + random.uniform(-20, 30)
return round(humidity, 1)
def read_light_level(self):
"""Read light level from LDR"""
# Read ADC value (0-4095 for 12-bit ADC)
raw_value = self.light_sensor.read()
# Convert to percentage (0-100%)
light_percent = (raw_value / 4095.0) * 100
return round(light_percent, 1)
def read_battery_level(self):
"""Read battery level (if battery monitoring is setup)"""
# For demo, return simulated battery level
import random
return round(80 + random.uniform(-10, 10), 1)
def collect_sensor_data(self):
"""Collect all sensor data"""
global sensor_data, motion_detected
sensor_data = {
'device_id': DEVICE_ID,
'timestamp': time.time(),
'datetime': time.strftime('%Y-%m-%d %H:%M:%S'),
'temperature': self.read_temperature(),
'humidity': self.read_humidity(),
'light_level': self.read_light_level(),
'battery_level': self.read_battery_level(),
'motion_detected': motion_detected,
'relay_state': relay_state,
'wifi_rssi': self.get_wifi_rssi() if wifi_connected else None,
'free_heap': gc.mem_free(),
'uptime': time.ticks_ms(),
'device_status': 'online'
}
# Reset motion detection flag
motion_detected = False
print(f"Sensor data collected: Temp={sensor_data['temperature']}°C, "
f"Humidity={sensor_data['humidity']}%, "
f"Light={sensor_data['light_level']}%")
return sensor_data
def log_data_locally(self, data):
"""Log data to local file"""
try:
log_file = f'/data/sensor_log_{time.strftime("%Y%m%d")}.json'
# Read existing data
with open(log_file, 'r') as f:
logs = ujson.load(f)
# Add new data
logs.append(data)
# Keep only last 1000 entries per day
if len(logs) > 1000:
logs = logs[-1000:]
# Write back to file
with open(log_file, 'w') as f:
ujson.dump(logs, f)
print(f"Data logged to {log_file}")
except Exception as e:
print(f"Local logging error: {e}")
def cleanup_old_logs(self):
"""Remove old log files"""
try:
current_date = time.strftime("%Y%m%d")
cutoff_date = time.time() - (LOG_RETENTION_DAYS * 24 * 3600)
for filename in uos.listdir('/data'):
if filename.startswith('sensor_log_') and filename.endswith('.json'):
# Extract date from filename
try:
date_str = filename[11:19] # sensor_log_YYYYMMDD.json
file_date = time.mktime(time.strptime(date_str, "%Y%m%d"))
if file_date < cutoff_date:
uos.remove(f'/data/{filename}')
print(f"Removed old log file: {filename}")
except:
continue
except Exception as e:
print(f"Log cleanup error: {e}")
def file_exists(self, filename):
"""Check if file exists"""
try:
uos.stat(filename)
return True
except OSError:
return False
class WiFiManager:
def __init__(self):
self.sta_if = network.WLAN(network.STA_IF)
self.ap_if = network.WLAN(network.AP_IF)
def connect(self):
"""Connect to WiFi network"""
global wifi_connected
if wifi_connected:
return True
print("Connecting to WiFi...")
# Activate station interface
self.sta_if.active(True)
# Connect to WiFi
self.sta_if.connect(WIFI_SSID, WIFI_PASSWORD)
# Wait for connection
max_wait = 20
while max_wait > 0:
if self.sta_if.status() == network.STAT_GOT_IP:
wifi_connected = True
print("WiFi connected!")
print(f"IP address: {self.sta_if.ifconfig()[0]}")
return True
max_wait -= 1
print(".", end="")
sleep(1)
print("WiFi connection failed!")
return False
def disconnect(self):
"""Disconnect from WiFi"""
global wifi_connected
self.sta_if.disconnect()
wifi_connected = False
print("WiFi disconnected")
def get_wifi_rssi(self):
"""Get WiFi signal strength"""
if wifi_connected:
return self.sta_if.scan()[0][3] if self.sta_if.scan() else None
return None
def check_connection(self):
"""Check WiFi connection status"""
if self.sta_if.status() != network.STAT_GOT_IP:
wifi_connected = False
return False
return True
class CloudManager:
def __init__(self, wifi_manager):
self.wifi_manager = wifi_manager
self.endpoint = AWS_ENDPOINT
self.client_id = AWS_CLIENT_ID
def connect_to_cloud(self):
"""Connect to AWS IoT cloud"""
global cloud_connected
if not wifi_connected:
print("WiFi not connected, cannot connect to cloud")
return False
try:
# For demo purposes, simulate cloud connection
# In real implementation, use MQTT with TLS certificates
print(f"Connecting to AWS IoT: {self.endpoint}")
sleep(2) # Simulate connection time
cloud_connected = True
print("Connected to AWS IoT cloud!")
return True
except Exception as e:
print(f"Cloud connection error: {e}")
return False
def upload_data(self, data):
"""Upload sensor data to cloud"""
if not cloud_connected:
print("Cloud not connected, data not uploaded")
return False
try:
# Prepare data for cloud
payload = {
'device_id': DEVICE_ID,
'timestamp': int(time.time()),
'data': data
}
# For demo, simulate upload
print(f"Uploading to cloud: {json.dumps(payload)}")
# In real implementation, use MQTT publish:
# mqtt_client.publish(b'esp32/sensors', json.dumps(payload))
sleep(1) # Simulate upload time
print("Data uploaded successfully!")
return True
except Exception as e:
print(f"Cloud upload error: {e}")
return False
# Initialize components
device = ESP32IoTDevice()
wifi_manager = WiFiManager()
cloud_manager = CloudManager(wifi_manager)
# Main application
def main():
global wifi_connected, cloud_connected, last_sensor_reading, last_cloud_upload
print(f"Starting {DEVICE_NAME}")
# Connect to WiFi
if not wifi_manager.connect():
print("Failed to connect to WiFi, continuing in offline mode")
# Connect to cloud
if wifi_connected:
cloud_manager.connect_to_cloud()
# Main loop
while True:
try:
current_time = time.ticks_ms()
# Collect sensor data periodically
if time.ticks_diff(current_time, last_sensor_reading) >= SENSOR_UPDATE_INTERVAL:
sensor_data = device.collect_sensor_data()
device.log_data_locally(sensor_data)
last_sensor_reading = current_time
# Upload to cloud periodically
if (wifi_connected and cloud_connected and
time.ticks_diff(current_time, last_cloud_upload) >= DATA_UPLOAD_INTERVAL):
cloud_manager.upload_data(sensor_data)
last_cloud_upload = current_time
# Run garbage collection
gc.collect()
# Check WiFi connection
if wifi_connected and not wifi_manager.check_connection():
print("WiFi connection lost, attempting to reconnect...")
wifi_connected = False
if wifi_manager.connect():
cloud_manager.connect_to_cloud()
# Cleanup old logs daily
if time.ticks_ms() % (24 * 3600 * 1000) < 5000: # Once per day
device.cleanup_old_logs()
# Blink LED to show device is active
device.led.on()
sleep_ms(100)
device.led.off()
sleep(1)
except Exception as e:
print(f"Main loop error: {e}")
sleep(5) # Wait before retrying
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\nDevice shutting down...")
device.led.off()
device.relay.off()
except Exception as e:
print(f"Fatal error: {e}")
machine.reset()
💻 Nœud Capteur ESP32 Basse Consommation cpp
Implémentation ESP32 optimisée pour réseaux de capteurs IoT alimentés par batterie avec sommeil profond, gestion d'énergie et communication LoRa
// ESP32 Low-Power Sensor Node
// Optimized for battery-powered IoT with deep sleep and LoRa communication
// PlatformIO with ESP32 Dev Module and LoRa module (SX1276/SX1278)
#include <Arduino.h>
#include <WiFi.h>
#include <LoRa.h>
#include <driver/adc.h>
#include <esp_sleep.h>
#include <esp_bt.h>
#include <esp_wifi.h>
#include <esp_adc_cal.h>
// Power management configuration
#define DEEP_SLEEP_DURATION 60 // Sleep for 60 seconds
#define WAKEUP_REASON_NONE 0
#define WAKEUP_REASON_TIMER 1
#define WAKEUP_REASON_BUTTON 2
#define WAKEUP_REASON_SENSOR 3
// Hardware configuration
#define LORA_CS_PIN 18
#define LORA_RST_PIN 14
#define LORA_IRQ_PIN 26
#define LORA_FREQ 915E6 // 915 MHz (US) / 868E6 (EU)
#define BUTTON_PIN 0 // Boot button for manual wakeup
// Sensor configuration
#define TEMP_SENSOR_PIN 4 // Analog temperature sensor (TMP36)
#define LIGHT_SENSOR_PIN 32 // LDR light sensor
#define BATTERY_PIN 33 // Battery voltage divider
// Power management
#define VOLTAGE_DIVIDER_RATIO 2.0f
#define ADC_RESOLUTION 4096
#define ADC_VOLTAGE 3.3f
#define BATTERY_LOW_THRESHOLD 3.2f
// Data packet structure
struct SensorData {
float temperature;
float light_level;
float battery_voltage;
float battery_percent;
uint32_t wake_count;
uint8_t wake_reason;
uint32_t timestamp;
int16_t rssi;
float free_heap;
};
// Global variables
RTC_DATA_ATTR uint32_t wake_count = 0;
RTC_DATA_ATTR uint8_t last_transmission_success = 0;
SensorData sensor_data;
bool low_battery = false;
esp_adc_cal_characteristics_t *adc_chars;
// LoRa configuration
const long LORA_BANDWIDTH = 125E3;
const int LORA_SPREADING_FACTOR = 7;
const int LORA_CODING_RATE = 5;
const int LORA_TX_POWER = 20; // 20 dBm
void setup() {
// Initialize serial for debugging
Serial.begin(115200);
delay(1000);
print_wakeup_reason();
wake_count++;
// Power management optimization
setup_power_management();
// Initialize hardware
setup_gpio();
setup_adc();
setup_lora();
// Collect sensor data
collect_sensor_data();
// Check battery level
check_battery_level();
// Transmit data via LoRa
if (transmit_data()) {
last_transmission_success = 1;
Serial.println("Transmission successful");
} else {
last_transmission_success = 0;
Serial.println("Transmission failed");
}
// Prepare for deep sleep
prepare_deep_sleep();
// Enter deep sleep
enter_deep_sleep();
}
void loop() {
// This function should never be reached due to deep sleep
delay(1000);
}
void print_wakeup_reason() {
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
Serial.println("\n=== ESP32 Sensor Node Waking Up ===");
Serial.printf("Wake count: %d\n", wake_count);
switch (wakeup_reason) {
case ESP_SLEEP_WAKEUP_TIMER:
Serial.println("Wakeup caused by timer");
sensor_data.wake_reason = WAKEUP_REASON_TIMER;
break;
case ESP_SLEEP_WAKEUP_EXT0:
Serial.println("Wakeup caused by external signal (RTC_IO)");
sensor_data.wake_reason = WAKEUP_REASON_BUTTON;
break;
case ESP_SLEEP_WAKEUP_EXT1:
Serial.println("Wakeup caused by external signal (RTC_CNTL)");
sensor_data.wake_reason = WAKEUP_REASON_SENSOR;
break;
case ESP_SLEEP_WAKEUP_TOUCHPAD:
Serial.println("Wakeup caused by touchpad");
break;
case ESP_SLEEP_WAKEUP_ULP:
Serial.println("Wakeup caused by ULP program");
break;
default:
Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
sensor_data.wake_reason = WAKEUP_REASON_NONE;
break;
}
}
void setup_power_management() {
Serial.println("Setting up power management...");
// Disable WiFi and Bluetooth to save power
WiFi.mode(WIFI_OFF);
btStop();
// Configure CPU frequency to minimum for power saving
setCpuFrequencyMhz(80); // 80 MHz instead of 240 MHz
// Disable brownout detector for power saving (optional)
// WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
// Configure ADC calibration for better battery measurement
adc_chars = (esp_adc_cal_characteristics_t*)calloc(1, sizeof(esp_adc_cal_characteristics_t));
esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 3300, adc_chars);
Serial.printf("CPU Frequency: %d MHz\n", getCpuFrequencyMhz());
Serial.printf("Free Heap before ADC: %d bytes\n", ESP.getFreeHeap());
}
void setup_gpio() {
Serial.println("Setting up GPIO pins...");
// Configure pins for low power consumption
pinMode(LORA_CS_PIN, OUTPUT);
pinMode(LORA_RST_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
// Initialize pin states
digitalWrite(LORA_CS_PIN, HIGH);
digitalWrite(LORA_RST_PIN, HIGH);
// Configure unused pins as inputs with pull-down to prevent floating
pinMode(1, INPUT_PULLDOWN);
pinMode(3, INPUT_PULLDOWN);
pinMode(5, INPUT_PULLDOWN);
pinMode(6, INPUT_PULLDOWN);
pinMode(7, INPUT_PULLDOWN);
pinMode(8, INPUT_PULLDOWN);
pinMode(9, INPUT_PULLDOWN);
pinMode(10, INPUT_PULLDOWN);
pinMode(11, INPUT_PULLDOWN);
pinMode(12, INPUT_PULLDOWN);
pinMode(13, INPUT_PULLDOWN);
pinMode(15, INPUT_PULLDOWN);
pinMode(16, INPUT_PULLDOWN);
pinMode(17, INPUT_PULLDOWN);
// Configure button pin for wakeup
esp_sleep_enable_ext0_wakeup(GPIO_NUM_0, LOW); // Wake up when button is pressed
}
void setup_adc() {
Serial.println("Setting up ADC...");
// Configure ADC
analogReadResolution(12); // 12-bit resolution (0-4095)
analogSetAttenuation(ADC_11db); // 0-3.6V range
// Test battery measurement
uint16_t raw_bat = analogRead(BATTERY_PIN);
uint32_t bat_mv = esp_adc_cal_raw_to_voltage(adc_chars, raw_bat);
float battery_voltage = (bat_mv / 1000.0f) * VOLTAGE_DIVIDER_RATIO;
Serial.printf("Battery voltage: %.2fV\n", battery_voltage);
}
void setup_lora() {
Serial.println("Setting up LoRa...");
// Initialize LoRa pins
pinMode(LORA_CS_PIN, OUTPUT);
pinMode(LORA_RST_PIN, OUTPUT);
// Reset LoRa module
digitalWrite(LORA_RST_PIN, LOW);
delay(10);
digitalWrite(LORA_RST_PIN, HIGH);
delay(10);
// Initialize LoRa
SPI.begin(5, 19, 27, 18); // SCK, MISO, MOSI, CS
LoRa.setPins(LORA_CS_PIN, LORA_RST_PIN, LORA_IRQ_PIN);
if (!LoRa.begin(LORA_FREQ)) {
Serial.println("Starting LoRa failed!");
while (1) {
delay(100);
}
}
// Configure LoRa parameters
LoRa.setBandwidth(LORA_BANDWIDTH);
LoRa.setSpreadingFactor(LORA_SPREADING_FACTOR);
LoRa.setCodingRate4(LORA_CODING_RATE);
LoRa.setTxPower(LORA_TX_POWER);
LoRa.setSyncWord(0xF3); // Private network sync word
Serial.printf("LoRa initialized: Freq=%.0f Hz, BW=%.0f kHz, SF=%d, CR=4/%d\n",
LORA_FREQ, LORA_BANDWIDTH/1000, LORA_SPREADING_FACTOR, LORA_CODING_RATE);
// Test LoRa transmission
LoRa.beginPacket();
LoRa.print("TEST");
LoRa.endPacket();
delay(100);
}
void collect_sensor_data() {
Serial.println("Collecting sensor data...");
// Collect wake count and timestamp
sensor_data.wake_count = wake_count;
sensor_data.timestamp = millis();
// Read temperature sensor (TMP36)
uint16_t temp_raw = analogRead(TEMP_SENSOR_PIN);
float temp_voltage = (temp_raw / 4096.0f) * 3.3f;
sensor_data.temperature = (temp_voltage - 0.5f) * 100.0f; // Convert to Celsius
// Read light sensor (LDR)
uint16_t light_raw = analogRead(LIGHT_SENSOR_PIN);
sensor_data.light_level = (light_raw / 4096.0f) * 100.0f; // Convert to percentage
// Read battery voltage
uint16_t bat_raw = analogRead(BATTERY_PIN);
uint32_t bat_mv = esp_adc_cal_raw_to_voltage(adc_chars, bat_raw);
sensor_data.battery_voltage = (bat_mv / 1000.0f) * VOLTAGE_DIVIDER_RATIO;
// Calculate battery percentage
sensor_data.battery_percent = calculate_battery_percentage(sensor_data.battery_voltage);
// Get LoRa RSSI (will be updated after transmission)
sensor_data.rssi = 0;
// Get free heap memory
sensor_data.free_heap = ESP.getFreeHeap();
Serial.printf("Temperature: %.1f°C\n", sensor_data.temperature);
Serial.printf("Light level: %.1f%%\n", sensor_data.light_level);
Serial.printf("Battery: %.2fV (%.1f%%)\n", sensor_data.battery_voltage, sensor_data.battery_percent);
Serial.printf("Free heap: %.0f bytes\n", sensor_data.free_heap);
}
float calculate_battery_percentage(float voltage) {
// Simple battery percentage calculation
// Adjust these values based on your battery characteristics
if (voltage >= 4.2f) return 100.0f;
if (voltage <= 3.0f) return 0.0f;
// Linear approximation between 3.0V and 4.2V
return ((voltage - 3.0f) / 1.2f) * 100.0f;
}
void check_battery_level() {
low_battery = sensor_data.battery_percent < 20.0f;
if (low_battery) {
Serial.println("WARNING: Low battery detected!");
// Reduce transmission frequency to save power
if (sensor_data.battery_percent < 10.0f) {
Serial.println("CRITICAL: Very low battery, entering extended sleep mode");
// You could modify sleep duration here based on battery level
}
}
}
bool transmit_data() {
Serial.println("Transmitting data via LoRa...");
// Prepare data packet
LoRa.beginPacket();
// Send data as binary for efficiency
LoRa.write((uint8_t*)&sensor_data, sizeof(SensorData));
// Add checksum
uint16_t checksum = calculate_checksum((uint8_t*)&sensor_data, sizeof(SensorData));
LoRa.write((uint8_t*)&checksum, sizeof(checksum));
bool success = LoRa.endPacket();
if (success) {
sensor_data.rssi = LoRa.packetRssi();
Serial.printf("Packet sent, RSSI: %d dBm\n", sensor_data.rssi);
} else {
Serial.println("Failed to send packet");
}
// Wait for transmission to complete
delay(100);
return success;
}
uint16_t calculate_checksum(uint8_t* data, size_t length) {
uint16_t checksum = 0;
for (size_t i = 0; i < length; i++) {
checksum ^= data[i];
}
return checksum;
}
void prepare_deep_sleep() {
Serial.println("Preparing for deep sleep...");
// Put LoRa module to sleep
LoRa.sleep();
// Configure wakeup sources
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
// Timer wakeup
esp_sleep_enable_timer_wakeup(DEEP_SLEEP_DURATION * 1000000ULL); // Convert to microseconds
// External wakeup (button)
esp_sleep_enable_ext0_wakeup(GPIO_NUM_0, LOW);
// Optional: ULP sensor wakeup for continuous monitoring
// enable_ulp_wakeup();
// Print status before sleep
Serial.printf("Entering deep sleep for %d seconds...\n", DEEP_SLEEP_DURATION);
Serial.printf("Wake count: %d\n", wake_count);
Serial.printf("Last transmission success: %s\n", last_transmission_success ? "Yes" : "No");
Serial.printf("Battery: %.2fV (%.1f%%)\n", sensor_data.battery_voltage, sensor_data.battery_percent);
// Give some time for serial output to complete
delay(100);
// Flash LED to indicate going to sleep
blink_led(3, 100);
}
void enter_deep_sleep() {
Serial.flush();
esp_deep_sleep_start();
}
void enable_ulp_wakeup() {
// ULP (Ultra Low Power) wakeup example
// Configure ULP to monitor sensor thresholds
// This is a simplified example
// In practice, you'd need to write ULP assembly code
/*
ulp_set_wakeup_period(0, 0);
ulp_set_wakeup_period(1, 5000000); // Check every 5 seconds
// Enable ULP wakeup
esp_sleep_enable_ulp_wakeup();
*/
Serial.println("ULP wakeup would be configured here");
}
void blink_led(int count, int duration_ms) {
for (int i = 0; i < count; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(duration_ms);
digitalWrite(LED_BUILTIN, LOW);
delay(duration_ms);
}
}
// Optional: OTA update via LoRa (advanced feature)
void check_for_ota_update() {
// Check if there's an OTA update request from gateway
// This would require a more complex protocol
static uint32_t last_ota_check = 0;
uint32_t current_time = millis();
if (current_time - last_ota_check > 3600000) { // Check every hour
last_ota_check = current_time;
// Send OTA status request
LoRa.beginPacket();
LoRa.print("OTA_STATUS");
LoRa.endPacket();
// Listen for OTA response (would need receiver)
// This is a placeholder for OTA functionality
}
}
// Power saving functions
void optimize_power_consumption() {
// Additional power optimizations
// Disable Brownout detector
// WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
// Set ADC resolution to minimum
// analogReadResolution(9); // 9-bit resolution for power saving
// Lower clock speed further if possible
// setCpuFrequencyMhz(10); // 10 MHz for maximum power saving
// Configure flash to low power mode
// gpio_deep_sleep_hold_en();
Serial.println("Power optimizations applied");
}
// Debug and monitoring functions
void print_system_info() {
Serial.println("\n=== System Information ===");
Serial.printf("Chip model: %s\n", ESP.getChipModel());
Serial.printf("Chip revision: %d\n", ESP.getChipRevision());
Serial.printf("Flash size: %d bytes\n", ESP.getFlashChipSize());
Serial.printf("CPU frequency: %d MHz\n", getCpuFrequencyMhz());
Serial.printf("Free heap: %d bytes\n", ESP.getFreeHeap());
Serial.printf("Minimum free heap: %d bytes\n", ESP.getMinFreeHeap());
Serial.printf("Wake count: %d\n", wake_count);
}
// Emergency functions
void emergency_low_power_mode() {
// When battery is critically low, enter emergency mode
Serial.println("EMERGENCY: Entering ultra-low power mode");
// Disable all non-essential features
LoRa.sleep();
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
btStop();
// Set extended sleep duration (e.g., 1 hour)
esp_sleep_enable_timer_wakeup(3600 * 1000000ULL);
// Only enable timer wakeup
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
esp_sleep_enable_timer_wakeup(3600 * 1000000ULL);
esp_deep_sleep_start();
}