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 > Preferenceshttp://arduino.esp8266.com/stable/package_esp8266com_index.jsonhttps://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.jsonTools > 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.