// Include necessary libraries for WiFi and ESP-NOW communication
#include <WiFi.h>
#include <esp_now.h>
// Define pin connections for encoder and button
#define ENCODER_A D0 // Encoder pin A
#define ENCODER_B D1 // Encoder pin B
#define BUTTON_PIN D2 // Pushbutton pin
// Create a structure to organize our data for transmission
typedef struct {
int16_t encoderValue; // Stores encoder position (0-100)
bool buttonState; // Stores button state (0 or 1)
} EncoderData;
// Broadcast address for ESP-NOW (send to all devices)
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
EncoderData myData; // Create instance of our data structure
// Encoder tracking variables
volatile int encoderPos = 0; // Current encoder position
bool buttonToggleState = false; // Current toggle state of button
bool lastButtonReading = HIGH; // Previous reading of button
bool buttonPressed = false; // Flag for button press detection
unsigned long lastDebounceTime = 0; // Timer for debouncing
const unsigned long debounceDelay = 50; // Debounce delay in milliseconds
// Interrupt Service Routine for encoder updates
void IRAM_ATTR updateEncoder() {
static uint8_t oldAB = 0; // Stores previous encoder states
// Combine current A and B states with previous states
oldAB = ((oldAB << 2) | (digitalRead(ENCODER_A) << 1) | digitalRead(ENCODER_B)) & 0x0F;
// Lookup table for quadrature decoding
const int8_t encoderTable[16] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
// Update encoder position based on state change
encoderPos += encoderTable[oldAB];
// Keep encoder value within 0-100 range
encoderPos = constrain(encoderPos, 0, 100);
}
void setup() {
// Configure encoder pins with pullup resistors
pinMode(ENCODER_A, INPUT_PULLUP);
pinMode(ENCODER_B, INPUT_PULLUP);
// Configure button pin with pullup resistor
pinMode(BUTTON_PIN, INPUT_PULLUP);
// Attach interrupts to encoder pins
attachInterrupt(digitalPinToInterrupt(ENCODER_A), updateEncoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENCODER_B), updateEncoder, CHANGE);
// Initialize WiFi in Station mode
WiFi.mode(WIFI_STA);
// Initialize ESP-NOW protocol
esp_now_init();
// Configure peer information for broadcasting
esp_now_peer_info_t peerInfo;
memset(&peerInfo, 0, sizeof(peerInfo)); // Clear peer info structure
memcpy(peerInfo.peer_addr, broadcastAddress, 6); // Set broadcast address
// Add peer to ESP-NOW
esp_now_add_peer(&peerInfo);
// Initialize data values
myData.encoderValue = 0;
myData.buttonState = false;
}
void loop() {
// Read current button state (LOW when pressed due to pullup)
bool currentReading = digitalRead(BUTTON_PIN);
// Check for button state change for debouncing
if (currentReading != lastButtonReading) {
lastDebounceTime = millis(); // Reset debounce timer
lastButtonReading = currentReading; // Update last reading
}
// If button state has been stable for debounce period
if ((millis() - lastDebounceTime) > debounceDelay) {
// Detect button press (transition to LOW)
if (currentReading == LOW && !buttonPressed) {
buttonPressed = true; // Mark button as pressed
buttonToggleState = !buttonToggleState; // Toggle the state
}
// Detect button release (transition to HIGH)
else if (currentReading == HIGH && buttonPressed) {
buttonPressed = false; // Mark button as released
}
}
// Update data structure with current values
myData.encoderValue = encoderPos;
myData.buttonState = buttonToggleState;
// Send data via ESP-NOW
esp_now_send(broadcastAddress, (uint8_t *)&myData, sizeof(myData));
delay(10); // Small delay to prevent flooding
}
// Include necessary libraries for WiFi and ESP-NOW
#include <WiFi.h>
#include <esp_now.h>
// Match the data structure used in transmitter
typedef struct {
int16_t encoderValue; // Encoder position (0-100)
bool buttonState; // Button state (0 or 1)
} EncoderData;
// ESP-NOW receive callback function
void OnDataRecv(const esp_now_recv_info_t *info, const uint8_t *incomingData, int len) {
EncoderData receivedData; // Create local variable to store received data
// Copy received data into our structure
memcpy(&receivedData, incomingData, sizeof(receivedData));
// Print encoder value on first line
Serial.println(receivedData.encoderValue);
// Print button state on second line
Serial.println(receivedData.buttonState);
}
void setup() {
// Initialize serial communication at 115200 baud
Serial.begin(115200);
// Set WiFi to station mode
WiFi.mode(WIFI_STA);
// Initialize ESP-NOW
if (esp_now_init() != ESP_OK) {
return; // Exit if initialization fails
}
// Register callback function for received data
esp_now_register_recv_cb(OnDataRecv);
}
// Main loop does nothing - all work happens in callback
void loop() {}