#include <esp_now.h>
#include <WiFi.h>
// New version ADC oneshot API header (compatible with ESP-IDF 5.x)
#include "esp_adc/adc_oneshot.h"
// ************************* Configuration Parameters *************************
#define LEADER_AB 97 // Last two digits of team leader's ID number
#define TX_POWER 19 // Transmission power: 19(19.5dBm) / 2(2dBm)
// ****************************************************************************
// Calculate deep sleep time X (seconds) → microseconds
const float X = (LEADER_AB % 50 + 5) / 10.0;
const unsigned long DEEP_SLEEP_US = X * 1000000;
// Hardware pin definitions
#define PIR_PIN 23 // PIR motion sensor pin
#define POT_PIN 34 // Potentiometer output pin (GPIO34=ADC1_CH6)
#define ADC_MAX_VALUE 4095 // 12-bit ADC maximum value
// ADC configuration (new API)
adc_oneshot_unit_handle_t adc1_handle; // ADC1 handle
// ESP-NOW broadcast address
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// Timing measurement variables
unsigned long t_start, t_sensor, t_transmit, t_end;
unsigned long t_sensor_duration, t_transmit_duration, t_cycle_total;
// ESP-NOW send callback function (new signature, compatible with ESP-IDF 5.x)
void OnDataSent(const wifi_tx_info_t *tx_info, esp_now_send_status_t status) {
// tx_info can be NULL, does not affect status judgment - only print send result
Serial.printf("Transmission status: %s\n", status == ESP_NOW_SEND_SUCCESS ? "Success" : "Failed");
}
// Read potentiometer value (replaces original LDR reading function, mapped to 0~1000 analog light intensity)
int readPotValue() {
// Initialize ADC1 (only on first call)
static bool adc_init = false;
if (!adc_init) {
adc_oneshot_unit_init_cfg_t init_config = {
.unit_id = ADC_UNIT_1, // Explicitly specify ADC1
.ulp_mode = ADC_ULP_MODE_DISABLE,
};
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc1_handle));
// Configure ADC channel (GPIO34=ADC1_CH6 → use ADC_CHANNEL_6 for new version)
adc_oneshot_chan_cfg_t chan_config = {
.atten = ADC_ATTEN_DB_12, // 12dB attenuation (compatible with new version)
.bitwidth = ADC_BITWIDTH_12, // 12-bit precision
};
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, ADC_CHANNEL_6, &chan_config));
adc_init = true;
}
// Multiple sampling for average value to reduce noise
int adc_sum = 0;
int adc_value;
for(int i=0; i<10; i++) {
ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, ADC_CHANNEL_6, &adc_value));
adc_sum += adc_value;
delayMicroseconds(50);
}
adc_value = adc_sum / 10;
// Map potentiometer value to 0~1000 (consistent with original LDR light intensity range)
// Turning potentiometer clockwise → higher ADC value → higher analog light intensity (intuitive operation)
int pot_value = map(adc_value, 0, ADC_MAX_VALUE, 0, 1000);
// Boundary protection
if(pot_value < 0) pot_value = 0;
if(pot_value > 1000) pot_value = 1000;
return pot_value;
}
void setup() {
Serial.begin(115200);
delay(100); // Ensure serial port is ready
pinMode(PIR_PIN, INPUT); // Initialize PIR sensor pin
Serial.println("ESP-NOW initialization failed");
// Configure WiFi and transmission power
WiFi.mode(WIFI_STA);
WiFi.disconnect(); // Disconnect irrelevant connections
// New version WiFi power enumeration (compatible with ESP-IDF 5.x)
if (TX_POWER == 19) {
WiFi.setTxPower(WIFI_POWER_19_5dBm);
} else if (TX_POWER == 2) {
WiFi.setTxPower(WIFI_POWER_2dBm);
}
// Initialize ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("ESP-NOW initialization failed");
// Enter deep sleep even if initialization fails to avoid system hang
esp_sleep_enable_timer_wakeup(DEEP_SLEEP_US);
esp_deep_sleep_start();
return;
}
// Register new version ESP-NOW callback function (core fix)
esp_now_register_send_cb(OnDataSent);
// Add broadcast peer node
esp_now_peer_info_t peerInfo;
memset(&peerInfo, 0, sizeof(peerInfo));
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = WiFi.channel(); // Adapt to current WiFi channel
peerInfo.encrypt = false;
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
Serial.println("Failed to add peer node");
}
// Start timing
t_start = micros();
// Read sensor data (potentiometer replaces LDR)
t_sensor = micros();
int motionState = digitalRead(PIR_PIN);
int pot_value = readPotValue(); // Read potentiometer value
t_sensor_duration = micros() - t_sensor;
// Log message adapted to potentiometer, keep format consistent
Serial.printf("Sensor reading time: %lu us | Motion state: %d | Analog light intensity: %d \n",
t_sensor_duration, motionState, pot_value);
// Construct transmission data (keep original format, only variable name modified)
char sendData[50];
if (motionState == HIGH) {
snprintf(sendData, sizeof(sendData), "MOTION_DETECTED-LUMINOSITY:%d", pot_value);
} else {
snprintf(sendData, sizeof(sendData), "MOTION_NOT_DETECTED-LUMINOSITY:%d", pot_value);
}
Serial.printf("Transmitted data: %s\n", sendData);
// Send ESP-NOW data
t_transmit = micros();
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)sendData, strlen(sendData));
t_transmit_duration = micros() - t_transmit;
Serial.printf("Transmission time: %lu us\n", t_transmit_duration);
// Calculate total cycle time
t_end = micros();
t_cycle_total = t_end - t_start;
Serial.printf("Total duration of a single work cycle: %lu us\n", t_cycle_total);
Serial.printf("Enter deep sleep: %.1f seconds\n", X);
// Force flush serial port to ensure all logs are output
Serial.flush();
delay(200); // Extend delay to avoid log truncation by deep sleep
// Enter deep sleep
esp_sleep_enable_timer_wakeup(DEEP_SLEEP_US);
esp_deep_sleep_start();
}
void loop() {
// setup() will re-run after deep sleep wake-up, no code needed in loop()
}