Complete Documentation for ESP32 Master and ESP8266 Slave Devices
This project implements an energy optimization system using ESP32 and ESP8266 microcontrollers with various sensors to monitor or detect energy loss and optimize energy usage in a building or home environment.
The system consists of:
The system consists of 1 ESP32 master controller and 4 ESP8266 slave nodes with different sensors:
All devices communicate via ESP-NOW protocol for low-latency communication.
Before uploading code to your devices, you need to install the following libraries through the Arduino Library Manager:
Library | Installation Method | Required For |
---|---|---|
ESP8266WiFi | Built-in with ESP8266 Board Package | All ESP8266 devices |
ESP32WiFi | Built-in with ESP32 Board Package | ESP32 master |
espnow.h / esp_now.h | Built-in with ESP boards | All devices for ESP-NOW communication |
FS.h / SPIFFS.h | Built-in with ESP boards | All devices for filesystem operations |
Updater.h | Built-in with ESP boards | All devices for OTA updates |
ACS712 | Install from Library Manager | Current sensing ESP8266 |
DHT sensor library | Install from Library Manager | Temperature/Humidity ESP8266 |
ArduinoJson | Install from Library Manager | ESP32 master for JSON handling |
WiFiClientSecure | Built-in with ESP boards | ESP32 master for secure connections |
HTTPClient | Built-in with ESP boards | ESP32 master for HTTP requests |
Note: To install libraries from the Arduino IDE, go to Sketch > Include Library > Manage Libraries
and search for the library names.
Before uploading code, you need to install the board support packages:
File > Preferences
http://arduino.esp8266.com/stable/package_esp8266com_index.json
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
Tools > Board > Boards Manager
#include <WiFi.h> #include <esp_now.h> #include <WiFiClientSecure.h> #include <HTTPClient.h> #include <SPIFFS.h> #include <ArduinoJson.h> #include "esp_task_wdt.h" // For watchdog resets #define FIRMWARE_FILE_PATH "/firmware.bin" // Save firmware in SPIFFS #define DOWNLOAD_TIMEOUT 30000 // 15 seconds timeout #define CHUNK_SIZE 240 // ESP-NOW packet size limit #define WINDOW_SIZE 4 // Number of packets sent before waiting for ACK #define BATCH_SIZE 5 // Acknowledge structure typedef struct { uint8_t slaveAddress[6]; bool ack = false; } Acknowledge; typedef struct { char sensorType[10]; int numValues; float values[2]; char sensorID[20]; } SensorData; typedef struct{ char serverversion[10] ; // Buffer to store received OTA version char slaveversion[10] ; //store version of slave char firmwareUrl[128]; uint8_t slaveAddress[6]; //update a microcontroller } updatemac; typedef struct { uint8_t slaveAddress[6]; bool ack; } ackData_t; ackData_t ackData; SensorData receivedData; bool batchReady = false ; // when batch will send DynamicJsonDocument doc(4096); JsonArray batchArray = doc.to<JsonArray>(); // JSON array for batch storage int batchCount = 0; // Track the number of received packets bool esp_now=true ;// by default its true to maitain sattus of es32 unsigned long previousMillis = 0; // Stores the last execution time const unsigned long interval = 30000; // how much later check ota requesrt from server bool inloop=true ; // maitain ota state updatemac Otarun ; const char* ssid = "FTTH"; const char* password = "12345678"; const char* serverUrl = "http://172.25.2.129:3001"; const char* otaUrl = "http://172.25.2.129:3001/firmwareuse"; const char *mongoDBEndpoint = "http://172.25.2.129:3001/sensor-data-batch"; bool sending=false ; bool pair=false ; bool slave_version_send=false ; bool sendMessage(const uint8_t *mac_addr, const uint8_t *message, size_t messageLength) { memcpy(ackData.slaveAddress, mac_addr, 6); ackData.ack = false; if (esp_now_send(mac_addr, message, messageLength) != ESP_OK) { Serial.println("Error: Failed to send ESP-NOW message."); return false; } unsigned long startTime = millis(); while (millis() - startTime < 500) { // Wait up to 500ms for ACK if (ackData.ack) return true; delay(10); } return false; // Timeout, return failure } void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t sendStatus) { if(sendStatus == ESP_NOW_SEND_SUCCESS) { Serial.println("Packet sent successfully") ; slave_version_send=true ; } else Serial.println("Failed to send packet") ; } // ESP-NOW Receive Callback void onDataRecv(const esp_now_recv_info_t *info, const uint8_t *data, int len) { if(sending) { if(memcmp(ackData.slaveAddress, info->src_addr, 6) == 0) { ackData.ack=true ; } return ; } if (len != sizeof(receivedData)&&len!=sizeof(Otarun.slaveversion)) { Serial.println("Invalid data size received."); return; } if(len==sizeof(Otarun.slaveversion)) { if(memcmp(Otarun.slaveAddress, info->src_addr, 6) != 0) return ; memcpy(Otarun.slaveversion, data, sizeof(Otarun.slaveversion)); // Copy data to slaveversion Serial.printf("Received firmware version: %s\n", Otarun.slaveversion); } else { memcpy(&receivedData, data, sizeof(receivedData)); char macStr[18]; //add mac address of sender microcontroller snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X", info->src_addr[0], info->src_addr[1], info->src_addr[2], info->src_addr[3], info->src_addr[4], info->src_addr[5]); // Display received data on Serial Monitor 📺 Serial.println("====================================="); Serial.printf("Sensor ID: %s\n", receivedData.sensorID); Serial.printf("Sensor Type: %s\n", receivedData.sensorType); Serial.printf("MAC Address: %s\n", macStr); Serial.print("Values: "); for (int i = 0; i < receivedData.numValues; i++) { Serial.printf("Value %d: [%.2f] ", i + 1, receivedData.values[i]); } Serial.println("\n====================================="); // Create new JSON object inside the batch array JsonObject sensorData = batchArray.createNestedObject(); sensorData["sensorId"] = receivedData.sensorID; sensorData["sensorType"] = receivedData.sensorType; sensorData["macAddress"] = macStr; // Store MAC as a string // Add values as an array JsonArray valuesArray = sensorData.createNestedArray("values"); for (int i = 0; i < receivedData.numValues; i++) { valuesArray.add(receivedData.values[i]); } batchCount++; // Increment batch count if (batchCount == BATCH_SIZE) { batchReady = true; // Set flag when batch is ready } } } bool sendmessage(const uint8_t *mac_addr, const uint8_t *message, size_t messageLength) { memcpy(ackData.slaveAddress, mac_addr, 6); // Store MAC address ackData.ack = false; // Reset acknowledgment status // Send the message via ESP-NOW if (esp_now_send(mac_addr, message, messageLength) != ESP_OK) { Serial.println("Error: Failed to send ESP-NOW message."); return false; } // Wait for acknowledgment unsigned long startTime = millis(); while (millis() - startTime < 500) { // Wait up to 500ms for ACK if (ackData.ack) return true; delay(10); // Small delay to avoid CPU overload } return false; // If timeout, return false } bool sendBatchToDatabase() { if (!wificonnect()) { doc.clear(); batchArray = doc.to<JsonArray>(); batchCount = 0 ; batchReady = false; return false ; } bool ans=false ; HTTPClient http; http.end() ; delay(200) ; http.begin(mongoDBEndpoint); http.addHeader("Content-Type", "application/json"); String jsonPayload; serializeJson(doc, jsonPayload); // Convert JSON array to string Serial.println("Sending JSON batch:"); Serial.println(jsonPayload); int httpResponseCode = http.POST(jsonPayload); if (httpResponseCode == HTTP_CODE_OK) { ans=true ; } else { Serial.printf("Batch send failed. HTTP Code: %d\n", httpResponseCode); } http.end(); doc.clear(); batchArray = doc.to<JsonArray>(); batchCount = 0 ; batchReady = false; return ans ; } bool setupespnow() { esp_now=true ; WiFi.disconnect(true); WiFi.mode(WIFI_OFF); delay(1000); WiFi.mode(WIFI_STA); if (esp_now_init() != ESP_OK) { Serial.println("ESP-NOW Initialization Failed!"); return false; } esp_now_register_send_cb(OnDataSent); esp_now_register_recv_cb(onDataRecv); return true; } bool wificonnect() { WiFi.disconnect(true); // Reset WiFi delay(200); WiFi.mode(WIFI_STA); // Station mode WiFi.begin(ssid, password); Serial.print("Connecting to WiFi"); unsigned long startTime = millis(); while (WiFi.status() != WL_CONNECTED && millis() - startTime < 10000) { // 10s timeout delay(500); Serial.print("."); } if (WiFi.status() == WL_CONNECTED) { Serial.println("\n✅ WiFi Connected! IP: " + WiFi.localIP().toString()); esp_now=false ; return true; } else { Serial.println("\n❌ WiFi Failed! Status: " + String(WiFi.status())); return false; } } bool checkForOTAUpdate() { if (!wificonnect()) return false; WiFiClient client; HTTPClient http; http.end(); delay(200); Serial.println("Checking OTA Request..."); const char* labNumber = "Lab102"; String requestUrl = String(serverUrl) + "/getData?lab=" + String(labNumber); if (!http.begin(client, requestUrl)) { Serial.println("Failed to connect to server."); client.stop(); return false; } int httpCode = http.GET(); if (httpCode != HTTP_CODE_OK) { Serial.printf("HTTP Request failed. Code: %d\n", httpCode); http.end(); client.stop(); return false; } String payload = http.getString(); if (payload.length() == 0) { Serial.println("Empty response from server!"); http.end(); client.stop(); return false; } Serial.println("Server Response: " + payload); // Increased buffer size for JSON parsing StaticJsonDocument<512> doc; DeserializationError error = deserializeJson(doc, payload); if (error) { Serial.print("JSON Parse Error: "); Serial.println(error.c_str()); http.end(); client.stop(); return false; } if (doc.containsKey("error")) { Serial.println("No OTA update available."); http.end(); client.stop(); return false; } // Extract version from response String serverVersion = doc["version"].as<String>(); if (serverVersion.length() == 0) { Serial.println("Invalid version in response"); http.end(); client.stop(); return false; } // Extract MAC address String macStr = doc["mac"].as<String>(); if (macStr.length() == 17) { // MAC addresses are 17 characters (XX:XX:XX:XX:XX:XX) int values[6]; if (sscanf(macStr.c_str(), "%x:%x:%x:%x:%x:%x", &values[0], &values[1], &values[2], &values[3], &values[4], &values[5]) == 6) { for (int i = 0; i < 6; i++) { Otarun.slaveAddress[i] = (uint8_t)values[i]; } Serial.print("Received MAC Address: "); for (int i = 0; i < 6; i++) { Serial.printf("0x%X ", Otarun.slaveAddress[i]); } Serial.println(); } else { Serial.println("Failed to parse MAC Address!"); http.end(); client.stop(); return false; } } else { Serial.println("Invalid MAC Address length."); http.end(); client.stop(); return false; } // Extract firmware URL String firmwareUrl = doc["firmwareUrl"].as<String>(); if (firmwareUrl.length() == 0) { Serial.println("No firmware URL in response"); http.end(); client.stop(); return false; } // Store version and URL strncpy(Otarun.serverversion, serverVersion.c_str(), sizeof(Otarun.serverversion) - 1); Otarun.serverversion[sizeof(Otarun.serverversion) - 1] = '\0'; strncpy(Otarun.firmwareUrl, firmwareUrl.c_str(), sizeof(Otarun.firmwareUrl) - 1); Otarun.firmwareUrl[sizeof(Otarun.firmwareUrl) - 1] = '\0'; memset(Otarun.slaveversion, 0, sizeof(Otarun.slaveversion)); Serial.print("Stored OTA Version: "); Serial.println(Otarun.serverversion); Serial.print("Firmware URL: "); Serial.println(Otarun.firmwareUrl); http.end(); client.stop(); return true; } bool setupESPNowpair(uint8_t PairAddress[]) { esp_now = true ; pair=true ; WiFi.disconnect(true); WiFi.mode(WIFI_OFF); delay(1000); WiFi.mode(WIFI_STA); if (esp_now_init() != ESP_OK) { Serial.println("ESP-NOW Initialization Failed!"); return false; } esp_now_register_send_cb(OnDataSent); esp_now_register_recv_cb(onDataRecv); esp_now_peer_info_t peerInfo = {}; memcpy(peerInfo.peer_addr, PairAddress, 6); peerInfo.channel = 0; peerInfo.encrypt = false; if (esp_now_add_peer(&peerInfo) == ESP_OK) { Serial.println("ESP-NOW Peer added."); return true; } else { Serial.println("Failed to add ESP-NOW peer."); return false; } } bool checkversion() { if (!setupESPNowpair(Otarun.slaveAddress)) return false; const char* message = "checkversion"; slave_version_send = false; // Reset before sending if (esp_now_send(Otarun.slaveAddress, (uint8_t*)message, strlen(message) + 1) != ESP_OK) { Serial.println("Failed to send version check message"); return false; } // Wait for send to complete (up to 200ms) unsigned long sendStart = millis(); while (!slave_version_send && millis() - sendStart < 200) { delay(20); } if (!slave_version_send) { Serial.println("Send callback not triggered in time."); } // Wait for slave version response bool sver = false; unsigned long startTime = millis(); while (millis() - startTime < 2000) { delay(100); if (Otarun.slaveversion[0] != '\0') { sver = true; break; } } if (!sver) { Serial.println("Slave version not received"); return false; } Serial.printf("Master OTA Version: %s\n", Otarun.serverversion); Serial.printf("Slave Reported Version: %s\n", Otarun.slaveversion); if (strcmp(Otarun.serverversion, Otarun.slaveversion) != 0) { Serial.println("Version mismatch: Slave needs update."); return true; } Serial.println("Versions match: No update needed."); return false; } bool downloadFirmware() { Serial.println("Starting firmware download..."); if (!SPIFFS.begin(true)) { Serial.println("Failed to mount SPIFFS."); return false; } // Clear old firmware file if (SPIFFS.exists(FIRMWARE_FILE_PATH)) { Serial.println("Clearing previous firmware file..."); SPIFFS.remove(FIRMWARE_FILE_PATH); } HTTPClient http; WiFiClient client; // Construct full URL - ensure it's properly encoded String fullUrl = String(serverUrl) + "/firmware/" + Otarun.firmwareUrl; Serial.print("Downloading from: "); Serial.println(fullUrl); // Add retry logic int retryCount = 0; const int maxRetries = 3; while (retryCount < maxRetries) { http.end(); delay(200); if (!http.begin(client, fullUrl)) { Serial.println("Failed to begin HTTP connection"); retryCount++; delay(1000); continue; } // Add some headers if needed http.addHeader("Accept", "application/octet-stream"); int httpCode = http.GET(); if (httpCode != HTTP_CODE_OK) { Serial.printf("HTTP error: %d (attempt %d/%d)\n", httpCode, retryCount+1, maxRetries); http.end(); retryCount++; delay(1000); continue; } // Get file size int firmwareSize = http.getSize(); if (firmwareSize <= 0) { Serial.println("Invalid content length"); http.end(); retryCount++; delay(1000); continue; } Serial.printf("Firmware size: %d bytes\n", firmwareSize); // Open file for writing File firmwareFile = SPIFFS.open(FIRMWARE_FILE_PATH, FILE_WRITE); if (!firmwareFile) { Serial.println("Failed to create firmware file"); http.end(); return false; } // Get stream pointer WiFiClient *stream = http.getStreamPtr(); // Download with progress size_t bytesRead = 0; unsigned long startTime = millis(); uint8_t buffer[1024]; // Larger buffer for better performance while (http.connected() && bytesRead < firmwareSize) { if (millis() - startTime > DOWNLOAD_TIMEOUT) { Serial.println("Download timeout"); firmwareFile.close(); http.end(); retryCount++; delay(1000); break; } size_t available = stream->available(); if (available > 0) { size_t readSize = stream->readBytes(buffer, min(available, sizeof(buffer))); size_t written = firmwareFile.write(buffer, readSize); bytesRead += written; // Print progress every 10% static int lastPercent = -1; int percent = (bytesRead * 100) / firmwareSize; if (percent != lastPercent && percent % 10 == 0) { Serial.printf("Downloaded %d%% (%d/%d bytes)\n", percent, bytesRead, firmwareSize); lastPercent = percent; } } delay(1); } firmwareFile.close(); http.end(); if (bytesRead == firmwareSize) { Serial.println("Download completed successfully"); return true; } else { Serial.printf("Download incomplete: %d/%d bytes\n", bytesRead, firmwareSize); SPIFFS.remove(FIRMWARE_FILE_PATH); retryCount++; delay(1000); } } Serial.println("Max retries reached, download failed"); return false; } bool sendFirmwareToSlave() { Serial.println("Starting firmware transfer via ESP-NOW..."); if (!setupESPNowpair(Otarun.slaveAddress)) return false; File firmwareFile = SPIFFS.open(FIRMWARE_FILE_PATH, "r"); if (!firmwareFile) { Serial.println("Error: Failed to open firmware file."); return false; } size_t firmwareSize = firmwareFile.size(); size_t totalPackets = (firmwareSize + CHUNK_SIZE - 1) / CHUNK_SIZE; Serial.printf("Firmware size: %d bytes, Total packets: %d\n", firmwareSize, totalPackets); // Send metadata: magic header + firmware size + total packets uint8_t metadata[12]; uint32_t magicHeader = 0xABCD1234; memcpy(metadata, &magicHeader, 4); memcpy(metadata + 4, &firmwareSize, 4); memcpy(metadata + 8, &totalPackets, 4); if (!sendMessage(Otarun.slaveAddress, metadata, sizeof(metadata))) { Serial.println("Error: Failed to send firmware metadata."); firmwareFile.close(); return false; } size_t i = 0; while (i < totalPackets) { esp_task_wdt_reset(); // Reset watchdog if enabled uint8_t packet[CHUNK_SIZE + 4]; memcpy(packet, &i, 4); // First 4 bytes = packet index firmwareFile.seek(i * CHUNK_SIZE); size_t readBytes = firmwareFile.read(packet + 4, CHUNK_SIZE); if (readBytes == 0) { Serial.printf("Error: Read failed at packet %d\n", i); break; } Serial.printf("Sending packet %d, size: %d, Free heap: %d bytes\n", i, readBytes, ESP.getFreeHeap()); int retryCount = 0; bool success = false; while (retryCount < 2) { if (sendMessage(Otarun.slaveAddress, packet, readBytes + 4)) { success = true; break; } else { Serial.printf("Retrying packet %d... (%d)\n", i, retryCount + 1); retryCount++; delay(100); // Increased delay on retry } } if (!success) { Serial.printf("Error: Failed to send firmware packet %d after retries.\n", i); firmwareFile.close(); return false; } i++; delay(100); // Increased delay between packets to reduce pressure } firmwareFile.close(); uint32_t endSignal = 0xFFFFFFFF; esp_now_send(Otarun.slaveAddress, (uint8_t*)&endSignal, sizeof(endSignal)); Serial.println("Firmware transfer complete. Sending termination signal..."); return true ; } void removeAllESPNOWPeers() { esp_now_peer_num_t peerNum; esp_err_t result = esp_now_get_peer_num(&peerNum); if (result != ESP_OK) { Serial.println("Failed to get peer count."); return; } int peerCount = peerNum.total_num; // Get the total number of peers if (peerCount == 0) { Serial.println("No ESP-NOW peers found."); pair=false ; return; } Serial.printf("Removing %d ESP-NOW peers...\n", peerCount); esp_now_peer_info_t peerList[ESP_NOW_MAX_TOTAL_PEER_NUM]; for (int i = 0; i < peerCount; i++) { esp_now_del_peer(peerList[i].peer_addr); } Serial.println("All ESP-NOW peers removed."); pair=false ; return ; } bool sendversionserver() { if (!wificonnect()) { Serial.println("Failed to connect to WiFi for version update"); return false; } WiFiClient client; HTTPClient http; http.end(); delay(200); // Create JSON payload DynamicJsonDocument doc(256); doc["mac"] = String(Otarun.slaveAddress[0], HEX) + ":" + String(Otarun.slaveAddress[1], HEX) + ":" + String(Otarun.slaveAddress[2], HEX) + ":" + String(Otarun.slaveAddress[3], HEX) + ":" + String(Otarun.slaveAddress[4], HEX) + ":" + String(Otarun.slaveAddress[5], HEX); doc["version"] = Otarun.serverversion; doc["status"] = "completed"; doc["lab"] = "Lab102"; // Replace with your lab number or make it dynamic String jsonPayload; serializeJson(doc, jsonPayload); String url = String(serverUrl) + "/update-ota-status"; http.begin(client, url); http.addHeader("Content-Type", "application/json"); int httpCode = http.POST(jsonPayload); if (httpCode == HTTP_CODE_OK) { String payload = http.getString(); Serial.println("Server response: " + payload); http.end(); return true; } else { Serial.printf("Failed to update OTA status. HTTP Code: %d\n", httpCode); http.end(); return false; } } void setup() { Serial.begin(115200); pinMode(2, INPUT_PULLUP); if (SPIFFS.begin(true)) { Serial.println("SPIFFS Initialized."); } else { Serial.println("SPIFFS Initialization Failed!"); } if (wificonnect()) { Serial.println("WiFi Setup Done."); } else { Serial.println("WiFi Setup Failed!"); } if (setupespnow()) { Serial.println("ESP-NOW Setup Done."); } else { Serial.println("ESP-NOW Setup Failed!"); } } void loop() { delay(500); if(batchReady&&sendBatchToDatabase()) //send data to server { Serial.println("Batch sent successfully."); } delay(500) ; if(!esp_now&&setupespnow()) esp_now=true ; //set all time in espnow mode delay(500) ; unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; // Update previousMillis correctly inloop = true; } else { inloop = false; } if (inloop && checkForOTAUpdate()&&checkversion()&&wificonnect()) { Serial.println("OTA Update Requested!"); if (downloadFirmware()) { //sendFirmwareToSlave(); Serial.println("file is downloaded"); int i=0 ; while(i<4) { sending=true ; if(sendFirmwareToSlave()) { delay(15000) ; break ; } delay(100) ; sending=false ; i++ ; } delay(500) ; if(!checkversion()) sendversionserver() ; } else { Serial.println("its is not updated") ; } if (SPIFFS.exists(FIRMWARE_FILE_PATH)) { if (SPIFFS.remove(FIRMWARE_FILE_PATH)) { Serial.println("Firmware file deleted successfully."); } else { Serial.println("Error: Failed to delete firmware file."); } } else { Serial.println("Firmware file does not exist."); } delay(1000) ; } delay(500) ; if(!esp_now&&setupespnow()) esp_now=true ; //set all time in espnow mode delay(500) ; if(pair) removeAllESPNOWPeers() ; // remove pairs delay(500) ; }
Parameter | Default Value | Description |
---|---|---|
BATCH_SIZE | 5 | Number of sensor readings to collect before sending to server |
CHUNK_SIZE | 240 | Size of firmware chunks for OTA updates |
DOWNLOAD_TIMEOUT | 30000 (30s) | Timeout for firmware downloads |
serverUrl | http://172.25.2.129:3001 | Base URL for server communication |
Measures ambient light and temperature/humidity with OTA update capability.
#include <ESP8266WiFi.h> #include <espnow.h> #include <FS.h> #include <Updater.h> #include "DHT.h" #define FIRMWARE_FILE "/firmware.bin" #define CHUNK_SIZE 240 // ESP-NOW max payload size #define DHTPIN D4 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); int ldrPin = A0; size_t firmwareSize = 0; size_t totalPackets = 0; size_t receivedPackets = 0; bool updateReady = false; File firmwareFile; char FIRMWARE_VERSION[10] = "1.0.0"; //current version uint8_t ackMessage = 1; // Simple ACK response uint8_t masterAddress[] = {0x24, 0xDC, 0xC3, 0xAE, 0x8B, 0x2C}; // Structure for sending sensor data typedef struct { char sensorType[10]; // Sensor type (e.g., LDR, DHT) int numValues; // Number of values sent float values[2]; // Sensor data values char sensorID[20]; // Unique sensor ID } SensorData; // Sensor data to send SensorData dataToSend; // Callback for data sent status void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) { Serial.println(sendStatus == 0 ? "Packet sent successfully" : "Failed to send packet"); } void OnDataRecv(uint8_t *mac, uint8_t *incomingData, uint8_t len) { if (len < 4) return; if (memcmp(mac, masterAddress, 6) != 0) return; // If master requests firmware version if (strncmp((char*)incomingData, "checkversion", len) == 0) { Serial.printf("Sending firmware version: '%s' (size: %d bytes)\n", FIRMWARE_VERSION, sizeof(FIRMWARE_VERSION)); esp_now_send(mac, (uint8_t*)FIRMWARE_VERSION, sizeof(FIRMWARE_VERSION)); return; } // If receiving metadata (firmware size + total packets) if (len == 12) { uint32_t receivedMagic; memcpy(&receivedMagic, incomingData, 4); if (receivedMagic == 0xABCD1234) { // Validate magic header memcpy(&firmwareSize, incomingData + 4, 4); memcpy(&totalPackets, incomingData + 8, 4); receivedPackets = 0; // Reset received packets counter Serial.println("START PACKET RECEIVED!"); Serial.printf("Firmware Size: %u bytes\n", firmwareSize); Serial.printf("Total Packets: %u\n", totalPackets); // Open firmware file for writing firmwareFile = SPIFFS.open(FIRMWARE_FILE, "w"); if (!firmwareFile) { Serial.println("ERROR: Cannot open firmware file for writing!"); return; } Serial.println("Firmware file opened for writing."); esp_now_send(mac, &ackMessage, sizeof(ackMessage)); // Send ACK return; } } // Read packet index uint32_t packetIndex; memcpy(&packetIndex, incomingData, 4); size_t dataSize = len - 4; // If end signal is received if (packetIndex == 0xFFFFFFFF) { Serial.println("Firmware transfer complete. Ready for update."); updateReady = true; if (firmwareFile) { firmwareFile.close(); Serial.println("Firmware file closed."); } esp_now_send(mac, &ackMessage, sizeof(ackMessage)); // Send ACK return; } // If wrong packet sequence, ignore it if (packetIndex != receivedPackets) { Serial.printf("Unexpected packet %d, expected %d. Ignoring...\n", packetIndex, receivedPackets); return; } // Write firmware data to SPIFFS firmwareFile.write(incomingData + 4, dataSize); receivedPackets++; Serial.printf("Received packet %d, size: %d\n", packetIndex, dataSize); esp_now_send(mac, &ackMessage, sizeof(ackMessage)); // Send ACK } bool applyFirmwareUpdate() { // Check if firmware file exists if (!SPIFFS.exists(FIRMWARE_FILE)) { Serial.println("ERROR: Firmware file does not exist!"); return false; } // Open firmware file for reading File firmwareFile = SPIFFS.open(FIRMWARE_FILE, "r"); if (!firmwareFile) { Serial.println("ERROR: Failed to open firmware file!"); return false; } size_t firmwareSize = firmwareFile.size(); Serial.printf("Applying update, size: %d bytes\n", firmwareSize); // Begin update process if (!Update.begin(firmwareSize)) { Serial.println("ERROR: Update failed to start!"); return false; } size_t written = Update.writeStream(firmwareFile); firmwareFile.close(); // Validate firmware write if (written != firmwareSize) { Serial.println("ERROR: Firmware write failed!"); return false; } if (!Update.end()) { Serial.println("ERROR: Update error!"); return false; } Serial.println("Update successful! Restarting..."); ESP.restart(); return true; } void setup() { Serial.begin(115200); WiFi.mode(WIFI_STA); // Set Wi-Fi to station mode // Initialize DHT sensor dht.begin(); pinMode(ldrPin, INPUT); if (!SPIFFS.begin()) { Serial.println("SPIFFS mount failed! Formatting..."); SPIFFS.format(); if (!SPIFFS.begin()) { Serial.println("SPIFFS mount failed again! Aborting."); return; } } // Initialize ESP-NOW if (esp_now_init() != 0) { Serial.println("ESP-NOW initialization failed!"); return; } esp_now_set_self_role(ESP_NOW_ROLE_SLAVE); esp_now_register_recv_cb(OnDataRecv); esp_now_register_send_cb(OnDataSent); esp_now_add_peer(masterAddress, ESP_NOW_ROLE_CONTROLLER, 1, NULL, 0); Serial.println("ESP-NOW Ready!"); } void loop() { // Read and send LDR data int ldrValue = analogRead(ldrPin); strcpy(dataToSend.sensorType, "LDR"); strcpy(dataToSend.sensorID, "LDR100112202428"); dataToSend.numValues = 1; dataToSend.values[0] = ldrValue; if (esp_now_send(masterAddress, (uint8_t *)&dataToSend, sizeof(dataToSend)) == 0) { Serial.printf("LDR Value Sent: %d\n", ldrValue); } else { Serial.println("Failed to send LDR data!"); } delay(1000); // Read and send DHT data float temperature = dht.readTemperature(); float humidity = dht.readHumidity(); if (isnan(temperature) || isnan(humidity)) { Serial.println("Failed to read from DHT sensor!"); } else { strcpy(dataToSend.sensorType, "DHT22"); strcpy(dataToSend.sensorID, "DHT100112202428"); dataToSend.numValues = 2; dataToSend.values[0] = temperature; dataToSend.values[1] = humidity; if (esp_now_send(masterAddress, (uint8_t *)&dataToSend, sizeof(dataToSend)) == 0) { Serial.printf("DHT Values Sent - Temperature: %.2f, Humidity: %.2f\n", temperature, humidity); } else { Serial.println("Failed to send DHT data!"); } } delay(1000); if (updateReady) { applyFirmwareUpdate(); } delay(15000); }
Parameter | Value | Description |
---|---|---|
FIRMWARE_VERSION | "1.0.0" | Current firmware version |
masterAddress | 0x24,0xDC,0xC3,0xAE,0x8B,0x2C | MAC address of master device |
CHUNK_SIZE | 240 | Max payload size for ESP-NOW packets |
Data Interval | 15 seconds | Time between sensor readings |
Note: The device will automatically check for firmware updates every cycle. When an update is received, it will be stored in SPIFFS and applied before restarting.
Measures AC current consumption and calculates power with OTA update capability.
#include <ESP8266WiFi.h> #include <espnow.h> #include <FS.h> #include <Updater.h> #include "ACS712.h" #define FIRMWARE_FILE "/firmware.bin" #define CHUNK_SIZE 240 ACS712 ACS(A0, 1.035, 1023, 100); // Pin A0, Vref, ADC max, sensitivity in mV/A size_t firmwareSize = 0; size_t totalPackets = 0; size_t receivedPackets = 0; bool updateReady = false; File firmwareFile; char FIRMWARE_VERSION[10] = "1.0.0"; uint8_t metadata[12]; uint8_t ackMessage = 1; uint8_t receiverAddress[] = {0x24, 0xdc, 0xc3, 0xae, 0x8b, 0x2c}; typedef struct { char sensorType[10]; int numValues; float values[2]; char sensorID[20]; } SensorData; SensorData acsData; void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) { Serial.println(sendStatus == 0 ? "Packet sent successfully" : "Failed to send packet"); } void OnDataRecv(uint8_t *mac, uint8_t *incomingData, uint8_t len) { if (len < 4) return; if (memcmp(mac, receiverAddress, 6) != 0) return; if (strncmp((char*)incomingData, "checkversion", len) == 0) { Serial.printf("Sending firmware version: '%s' (size: %d bytes)\n", FIRMWARE_VERSION, sizeof(FIRMWARE_VERSION)); esp_now_send(mac, (uint8_t*)FIRMWARE_VERSION, sizeof(FIRMWARE_VERSION)); return; } if (len == sizeof(metadata)) { uint32_t receivedMagic; memcpy(&receivedMagic, incomingData, 4); if (receivedMagic == 0xABCD1234) { memcpy(&firmwareSize, incomingData + 4, 4); memcpy(&totalPackets, incomingData + 8, 4); receivedPackets = 0; Serial.println("START PACKET RECEIVED!"); Serial.printf("Firmware Size: %u bytes\n", firmwareSize); Serial.printf("Total Packets: %u\n", totalPackets); firmwareFile = SPIFFS.open(FIRMWARE_FILE, "w"); if (!firmwareFile) { Serial.println("ERROR: Cannot open firmware file for writing!"); return; } Serial.println("Firmware file opened for writing."); esp_now_send(mac, &ackMessage, sizeof(ackMessage)); return; } } uint32_t packetIndex; memcpy(&packetIndex, incomingData, 4); size_t dataSize = len - 4; if (packetIndex == 0xFFFFFFFF) { Serial.println("Firmware transfer complete. Ready for update."); updateReady = true; if (firmwareFile) { firmwareFile.close(); Serial.println("Firmware file closed."); } esp_now_send(mac, &ackMessage, sizeof(ackMessage)); return; } if (packetIndex != receivedPackets) { Serial.printf("Unexpected packet %d, expected %d. Ignoring...\n", packetIndex, receivedPackets); return; } firmwareFile.write(incomingData + 4, dataSize); receivedPackets++; Serial.printf("Received packet %d, size: %d\n", packetIndex, dataSize); esp_now_send(mac, &ackMessage, sizeof(ackMessage)); } bool applyFirmwareUpdate() { if (!SPIFFS.exists(FIRMWARE_FILE)) { Serial.println("ERROR: Firmware file does not exist!"); return false; } File firmwareFile = SPIFFS.open(FIRMWARE_FILE, "r"); if (!firmwareFile) { Serial.println("ERROR: Failed to open firmware file!"); return false; } size_t firmwareSize = firmwareFile.size(); Serial.printf("Applying update, size: %d bytes\n", firmwareSize); if (!Update.begin(firmwareSize)) { Serial.println("ERROR: Update failed to start!"); return false; } size_t written = Update.writeStream(firmwareFile); firmwareFile.close(); if (written != firmwareSize) { Serial.println("ERROR: Firmware write failed!"); return false; } if (!Update.end()) { Serial.println("ERROR: Update error!"); return false; } Serial.println("Update successful! Restarting..."); ESP.restart(); return true; } void setup() { Serial.begin(115200); delay(100); Serial.println("ACS712 Calibrated Example"); WiFi.mode(WIFI_STA); if (!SPIFFS.begin()) { Serial.println("SPIFFS mount failed! Formatting..."); SPIFFS.format(); if (!SPIFFS.begin()) { Serial.println("SPIFFS mount failed again! Aborting."); return; } } if (esp_now_init() != 0) { Serial.println("Error initializing ESP-NOW"); return; } esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); esp_now_register_send_cb(OnDataSent); esp_now_register_recv_cb(OnDataRecv); esp_now_add_peer(receiverAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0); ACS.autoMidPoint(); // Calibrate zero-current point Serial.print("MidPoint: "); Serial.println(ACS.getMidPoint()); } void loop() { float current_mA = ACS.mA_AC_sampling(); if (current_mA < 20) current_mA = 0; // Noise filtering float current_A = current_mA / 1000.0; float voltage = 230.0; float powerFactor = 0.9; float power_W = voltage * current_A * powerFactor; strcpy(acsData.sensorType, "ACS712"); strcpy(acsData.sensorID, "ACS712100112202428"); acsData.numValues = 2; acsData.values[0] = current_A; acsData.values[1] = power_W; esp_now_send(receiverAddress, (uint8_t*)&acsData, sizeof(acsData)); Serial.print("Current (mA): "); Serial.print(current_mA); Serial.print(" | Power (W): "); Serial.println(power_W); Serial.println("--------------------"); if (updateReady) { applyFirmwareUpdate(); } delay(15000); }
Parameter | Value | Description |
---|---|---|
ACS712 Configuration | A0, 1.035, 1023, 100 | Pin, Vref, ADC max, sensitivity (mV/A) |
FIRMWARE_VERSION | "1.0.0" | Current firmware version |
receiverAddress | 0x24,0xDC,0xC3,0xAE,0x8B,0x2C | MAC address of master device |
Noise Threshold | 20mA | Current values below this are set to 0 |
Voltage | 230V | Assumed line voltage for power calculation |
Power Factor | 0.9 | Assumed power factor for power calculation |
Note: The ACS712 sensor requires calibration on first use. The autoMidPoint()
function automatically calibrates the zero-current point.
Detects human presence using infrared with OTA update capability.
#include <ESP8266WiFi.h> #include <espnow.h> #include <FS.h> #include <Updater.h> #define SENSOR_ID_PIR 1001 #define FIRMWARE_FILE "/firmware.bin" #define CHUNK_SIZE 240 // ESP-NOW max payload size int pirPin = D1; uint8_t receiverAddress[] = {0x24, 0xDC, 0xC3, 0xAE, 0x8B, 0x2C}; // Receiver MAC address typedef struct { char sensorType[10]; // Sensor type (e.g., LDR, DHT) int numValues; // Number of values sent float values[2]; // Sensor data values char sensorID[20]; // Unique sensor ID } SensorData; SensorData pirData; size_t firmwareSize = 0; size_t totalPackets = 0; size_t receivedPackets = 0; bool updateReady = false; File firmwareFile; char FIRMWARE_VERSION[10] = "1.0.0"; // Fixed 10-byte array uint8_t metadata[12]; uint8_t ackMessage = 1; // Simple ACK response void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) { Serial.println(sendStatus == 0 ? "Packet sent successfully" : "Failed to send packet"); } void OnDataRecv(uint8_t *mac, uint8_t *incomingData, uint8_t len) { if (len < 4) return; if (memcmp(mac, receiverAddress, 6) != 0) return; // If master requests firmware version if (strncmp((char*)incomingData, "checkversion", len) == 0) { Serial.printf("Sending firmware version: '%s' (size: %d bytes)\n", FIRMWARE_VERSION, sizeof(FIRMWARE_VERSION)); esp_now_send(mac, (uint8_t*)FIRMWARE_VERSION, sizeof(FIRMWARE_VERSION)); return; } // If receiving metadata (firmware size + total packets) if (len == sizeof(metadata)) { uint32_t receivedMagic; memcpy(&receivedMagic, incomingData, 4); if (receivedMagic == 0xABCD1234) { // Validate magic header memcpy(&firmwareSize, incomingData + 4, 4); memcpy(&totalPackets, incomingData + 8, 4); receivedPackets = 0; // Reset received packets counter Serial.println("START PACKET RECEIVED!"); Serial.printf("Firmware Size: %u bytes\n", firmwareSize); Serial.printf("Total Packets: %u\n", totalPackets); // Open firmware file for writing firmwareFile = SPIFFS.open(FIRMWARE_FILE, "w"); if (!firmwareFile) { Serial.println("ERROR: Cannot open firmware file for writing!"); return; } Serial.println("Firmware file opened for writing."); esp_now_send(mac, &ackMessage, sizeof(ackMessage)); // Send ACK return; } } // Read packet index uint32_t packetIndex; memcpy(&packetIndex, incomingData, 4); size_t dataSize = len - 4; // If end signal is received if (packetIndex == 0xFFFFFFFF) { Serial.println("Firmware transfer complete. Ready for update."); updateReady = true; if (firmwareFile) { firmwareFile.close(); Serial.println("Firmware file closed."); } esp_now_send(mac, &ackMessage, sizeof(ackMessage)); // Send ACK return; } // If wrong packet sequence, ignore it if (packetIndex != receivedPackets) { Serial.printf("Unexpected packet %d, expected %d. Ignoring...\n", packetIndex, receivedPackets); return; } // Write firmware data to SPIFFS firmwareFile.write(incomingData + 4, dataSize); receivedPackets++; Serial.printf("Received packet %d, size: %d\n", packetIndex, dataSize); esp_now_send(mac, &ackMessage, sizeof(ackMessage)); // Send ACK } bool applyFirmwareUpdate() { // Check if firmware file exists if (!SPIFFS.exists(FIRMWARE_FILE)) { Serial.println("ERROR: Firmware file does not exist!"); return false; } // Open firmware file for reading File firmwareFile = SPIFFS.open(FIRMWARE_FILE, "r"); if (!firmwareFile) { Serial.println("ERROR: Failed to open firmware file!"); return false; } size_t firmwareSize = firmwareFile.size(); Serial.printf("Applying update, size: %d bytes\n", firmwareSize); // Begin update process if (!Update.begin(firmwareSize)) { Serial.println("ERROR: Update failed to start!"); return false; } size_t written = Update.writeStream(firmwareFile); firmwareFile.close(); // Validate firmware write if (written != firmwareSize) { Serial.println("ERROR: Firmware write failed!"); return false; } if (!Update.end()) { Serial.println("ERROR: Update error!"); return false; } Serial.println("Update successful! Restarting..."); ESP.restart(); return true; } void setup() { Serial.begin(115200); WiFi.mode(WIFI_STA); pinMode(pirPin, INPUT); if (!SPIFFS.begin()) { Serial.println("SPIFFS mount failed! Formatting..."); SPIFFS.format(); if (!SPIFFS.begin()) { Serial.println("SPIFFS mount failed again! Aborting."); return; } } if (esp_now_init() != 0) { Serial.println("Error initializing ESP-NOW"); return; } esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); esp_now_register_send_cb(OnDataSent); esp_now_register_recv_cb(OnDataRecv); esp_now_add_peer(receiverAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0); Serial.println(""); printf("Firmware Version: %s\n", FIRMWARE_VERSION); } void loop() { int value = digitalRead(pirPin); pirData.values[0] = value; strcpy(pirData.sensorType, "PIR"); strcpy(pirData.sensorID, "PIR100112202428"); pirData.numValues = 1; // Send motion detection data esp_now_send(receiverAddress, (uint8_t *) &pirData, sizeof(pirData)); Serial.print("Motion: "); Serial.println(value == HIGH ? "Detected" : "Not Detected"); if (updateReady) { applyFirmwareUpdate(); } delay(15000); }
Parameter | Value | Description |
---|---|---|
PIR Pin | D1 | Digital input pin for PIR sensor |
FIRMWARE_VERSION | "1.0.0" | Current firmware version |
receiverAddress | 0x24,0xDC,0xC3,0xAE,0x8B,0x2C | MAC address of master device |
Detection Interval | 15 seconds | Time between motion checks |
Sensor ID | PIR100112202428 | Unique identifier for this sensor |
Note: The PIR sensor requires 30-60 seconds to stabilize after power-up. During this time, it may give false triggers.
Monitors door and window open/close status with magnetic contact sensors.
#include <ESP8266WiFi.h> #include <espnow.h> // Pin definitions #define DOOR_SENSOR_PIN D1 #define WINDOW_SENSOR_PIN D3 // Structure for sending sensor data typedef struct { char sensorType[10]; // Type of sensor int numValues; // Number of values sent float values[2]; // Array to hold sensor values char sensorID[20]; // Unique sensor ID as a char array } SensorData; // Replace with the receiver's MAC address uint8_t receiverAddress[] = {0x24, 0xDC, 0xC3, 0xAE, 0x8B, 0x2C}; // Sensor data to send SensorData dataToSend; // Callback for data sent status void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) { Serial.print("Packet send status: "); Serial.println(sendStatus == 0 ? "Success" : "Fail"); } void setup() { Serial.begin(115200); WiFi.mode(WIFI_STA); // Set Wi-Fi to station mode pinMode(DOOR_SENSOR_PIN, INPUT_PULLUP); pinMode(WINDOW_SENSOR_PIN, INPUT_PULLUP); // Initialize ESP-NOW if (esp_now_init() != 0) { Serial.println("ESP-NOW initialization failed!"); return; } esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); esp_now_register_send_cb(OnDataSent); // Add peer device if (esp_now_add_peer(receiverAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0) != 0) { Serial.println("Failed to add peer!"); return; } Serial.println("ESP-NOW setup complete!"); } void loop() { // Read door sensor data int doorStatus = digitalRead(DOOR_SENSOR_PIN); // Prepare door data to send strcpy(dataToSend.sensorType, "DOORWIN"); strcpy(dataToSend.sensorID, "DOORWIN100112202428"); // Unique ID for door sensor dataToSend.numValues = 1; dataToSend.values[0] = doorStatus; // Door status // Send door data via ESP-NOW if (esp_now_send(receiverAddress, (uint8_t *)&dataToSend, sizeof(dataToSend)) == 0) { Serial.printf("Door Data Sent - Door: %s\n", doorStatus == HIGH ? "Open" : "Closed"); } else { Serial.println("Failed to send Door data!"); } delay(1000); // Delay before sending window data // Read window sensor data int windowStatus = digitalRead(WINDOW_SENSOR_PIN); // Prepare window data to send strcpy(dataToSend.sensorType, "DOORWIN"); strcpy(dataToSend.sensorID, "DOORWIN100212202428"); // Unique ID for window sensor dataToSend.numValues = 1; dataToSend.values[0] = windowStatus; // Window status // Send window data via ESP-NOW if (esp_now_send(receiverAddress, (uint8_t *)&dataToSend, sizeof(dataToSend)) == 0) { Serial.printf("Window Data Sent - Window: %s\n", windowStatus == HIGH ? "Open" : "Closed"); } else { Serial.println("Failed to send Window data!"); } delay(15000); // Delay before next cycle }
Parameter | Value | Description |
---|---|---|
Door Sensor Pin | D1 | Digital input with pull-up |
Window Sensor Pin | D3 | Digital input with pull-up |
receiverAddress | 0x24,0xDC,0xC3,0xAE,0x8B,0x2C | MAC address of master device |
Door Sensor ID | DOORWIN100112202428 | Unique identifier for door sensor |
Window Sensor ID | DOORWIN100212202428 | Unique identifier for window sensor |
Update Interval | 15 seconds | Time between status checks |
State | Digital Read Value | Interpretation |
---|---|---|
Contact Closed | LOW | Door/Window is closed |
Contact Open | HIGH | Door/Window is open |
Note: Magnetic contact sensors work by closing a circuit when the magnet is near (closed position) and opening it when apart (open position). The internal pull-up resistors ensure a clean HIGH signal when the circuit is open.