Skip to content

Instantly share code, notes, and snippets.

@ZanzyTHEbar
Last active September 16, 2024 11:01
Show Gist options
  • Save ZanzyTHEbar/5cc372b86fcf1bf591f3b33f817df04b to your computer and use it in GitHub Desktop.
Save ZanzyTHEbar/5cc372b86fcf1bf591f3b33f817df04b to your computer and use it in GitHub Desktop.
ESPNow and Wifi simultaneously
// use ESP-NOW to do something based on a message from another device
// and also connect to WiFi to display a web page, deal with MQTT etc
// in this case just light an LED and get UNIX timestamp from an NTP server
// NOTE: WiFi router must be on Channel 1 for this simple version to work
// Compiled using Arduino 1.8.19, and ESP32 v2.0.2
// Compiled for board: ESP32 Dev Module
// (but running on an AI Thinker ESP-CAM since I have a bunch of them)
// Based on "ResponderA_22A.ino v01
// ...... program information
char programName[] = "ResponderA_22A";
char versionNumber[] = "v01";
char programDate[] = "2022-09-25";
char programAuthor[] = "Donald Weiman";
// ...... required libraries
#include <esp_now.h>
#include <WiFi.h>
#include "esp_sntp.h" // ntp
// define data structure for received data
struct s_message {
int i_id;
int i_count;
char c_level[20];
} ;
// create structured data object
s_message s_switchInfo; // from initiator
// ...... LED
const byte flashLedPin = 4; // white led on AI Thinker ESP-CAM board
#define flashLedOff 0 // active high
const byte builtinLedPin = 33; // red led on AI Thinker ESP-CAM board
#define builtinLedOff 1 // active low
// ...... misc
char thisDeviceMac[20] ; // Mac address for this device (for info only)
bool newDataFlag = false;
// ...... WiFi
const char* ssid = "plugh"; // on WiFi channel 1
const char* pass = "xyzzy";
// ...... NTP
char ntpPool[] = "pool.ntp.org";
char ntpTzEnvData[] = "EST+5EDT,M3.2.0/2:00:00,M11.1.0/2:00:00"; // US/Eastern
bool ntpUpdateFlag = false;
bool changeNtpSync = true; // false --> use default 3600 seconds
const uint32_t ntpSyncInterval = 120; // true --> use this interval (seconds)
// ...... timing parameters (for example procedure in loop())
time_t timestampNow;
// ....................................................................................
void setup() {
Serial.begin(115200);
delay(1000);
// ...... display sign-on message
Serial.println();
Serial.println();
Serial.print(programName);
Serial.print(" ");
Serial.print(versionNumber);
Serial.print(" ");
Serial.print(programDate);
Serial.print(" ");
Serial.print(programAuthor);
Serial.print("\n");
// ...... display MAC address (of this device)
WiFi.macAddress().toCharArray(thisDeviceMac, 20);
Serial.printf("\nMAC address: %s", thisDeviceMac);
// ...... WiFi
WiFi.mode(WIFI_AP_STA); // AP needed to maintain ESP-NOW
WiFi.begin(ssid, pass);
// Wait for connection
Serial.println("");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// ...... NTP
Serial.print("\nconnecting to NTP time server");
connectToNtp();
// ...... esp-now
// initalize ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// register callback function
esp_now_register_recv_cb(OnDataRecv);
// ...... LEDs
pinMode(flashLedPin, OUTPUT); // turn LEDs off
digitalWrite(flashLedPin, flashLedOff);
pinMode(builtinLedPin, OUTPUT);
digitalWrite(builtinLedPin, builtinLedOff);
// ...... end of setup
Serial.print("\nsetup complete\n");
}
// ....................................................................................
void loop() {
// act on received data if appropriate
if(newDataFlag == true) {
newDataFlag = false;
// act on received data
if(strcmp (s_switchInfo.c_level, "HIGH") == 0) {
digitalWrite(flashLedPin, !flashLedOff);
digitalWrite(builtinLedPin, builtinLedOff);
} else {
digitalWrite(flashLedPin, flashLedOff);
digitalWrite(builtinLedPin, !builtinLedOff);
}
}
// NTP
timestampNow = time(nullptr);
if(ntpUpdateFlag == true) {
ntpUpdateFlag = false;
Serial.print("\n *** NTP update *** ");
Serial.print(timestampNow);
}
// do something else ...
}
// ....................................................................................
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
// extract the received data
char receivedData[100];
memcpy(&s_switchInfo, incomingData, sizeof(s_switchInfo));
// deal with received data
newDataFlag = true; // handled in loop()
// display received data - (interesting, but not essential)
char recvStr[50];
snprintf(recvStr, sizeof(recvStr), "\n %u %u %s",
s_switchInfo.i_id, s_switchInfo.i_count, s_switchInfo.c_level);
Serial.print(recvStr);
// display MAC of sending device - (interesting, but not essential)
char macStr[20];
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Serial.print(" Received from ");
Serial.print(macStr);
// display UNIX timestamp obtained from NTP server
Serial.print(" at ");
Serial.print(timestampNow);
}
// ....................................................................................
// NTP time synchronization callback
// this callback will place the current UNIX timestamp that was obtained
// via NTP into a structure of type 'timeval' which is defined in time.h
// it looks like this must be done even if the data isn't subsequently used
// NOTE: This is apparently being executed in a different core from the
// main program. Any Serial.print data here may be interspersed with
// Serial.print data from the main program.
void time_is_set (struct timeval *bogus) {
ntpUpdateFlag = true;
}
// ....................................................................................
void connectToNtp() {
// possibly change NTP sync interval (default = 3600 seconds)
if(changeNtpSync == true) {
sntp_set_sync_interval(ntpSyncInterval * 1000);
}
// register a callback to notify about the time synchronization process
sntp_set_time_sync_notification_cb(time_is_set);
// obtain system time from an NTP server, do not adjust for timezone or dst here
configTime(0, 0, ntpPool); // obtain time from an NTP server
// set the TZ environment variable to the correct value for the device location
setenv("TZ", ntpTzEnvData, 1);
// update the C library runtime data for the new time zone
tzset();
}
// ....................................................................................
// use ESP-NOW to send input level information to another device
// input can be from switch, PIR sensor, light sensor, etc.
// Compiled using Arduino 1.8.19, and ESP32 v2.0.2
// Compiled for board: ESP32 Dev Module
// (but running on an AI Thinker ESP-CAM since I have a bunch of them)
// ...... program information
char programName[] = "InitiatorA_22A";
char versionNumber[] = "v01";
char programDate[] = "2022-09-25";
char programAuthor[] = "Donald Weiman";
// ...... hardware connections
// Push-button switch between Vcc and GPIO13
// or
// HC-SR501 PIR Motion Detector module connected to GPIO13
// ...... required libraries
#include <esp_now.h>
#include <WiFi.h>
// ...... esp-now
// remote MAC Address
uint8_t responderAddress[] = {0x34, 0x94, 0x54, 0x24, 0x3D, 0xE0};
// specify where to store information about the other devices
// NOTE: this structure is defined in 'esp_now.h'
esp_now_peer_info_t responderInfo;
// define data structure for transmitted data
struct s_message {
int i_id;
int i_count;
char c_level[20];
} ;
// create structured data object
s_message s_switchInfo; // to responder
// ...... switch
const byte inputPin = 13;
int oldValue = 0;
bool newValueFlag = false;
int lowCount = 0;
int highCount = 0;
// ...... misc
char thisDeviceMac[20] ; // Mac address for this device (for info only)
int unitId = 102; // arbitrary 'unit id'
// ....................................................................................
void setup() {
Serial.begin(115200);
delay(1000);
// ...... display sign-on message
Serial.println();
Serial.println();
Serial.print(programName);
Serial.print(" ");
Serial.print(versionNumber);
Serial.print(" ");
Serial.print(programDate);
Serial.print(" ");
Serial.print(programAuthor);
Serial.print("\n");
// ...... display MAC address (of this device)
WiFi.macAddress().toCharArray(thisDeviceMac, 20);
Serial.printf("\nMAC address: %s", thisDeviceMac);
// ...... switch
pinMode(inputPin, INPUT_PULLDOWN); // active HIGH
// ...... WiFi
WiFi.mode(WIFI_STA);
// ...... esp-now
// initalize ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// register callback function
esp_now_register_send_cb(OnDataSent);
// register peer (remote device)
// put peer information into the 'responderInfo' data structure
memcpy(responderInfo.peer_addr, responderAddress, 6); // address has 6 bytes
responderInfo.channel = 0; // use current channel
responderInfo.encrypt = false; // don't encrypt
// add peer to paired device list
if (esp_now_add_peer(&responderInfo) != ESP_OK) {
Serial.println("Failed to add peer");
return;
}
// ...... end of setup
Serial.print("\nsetup complete\n");
}
// ....................................................................................
void loop() {
checkInputLevel();
// send message if appropriate
if(newValueFlag == true) {
newValueFlag = false;
if(esp_now_send(responderAddress, (uint8_t *) &s_switchInfo, sizeof(s_switchInfo)) != ESP_OK) {
Serial.println("Failed to send the data");
}
}
// do something else ...
}
// ....................................................................................
void OnDataSent(const uint8_t *macAddr, esp_now_send_status_t status) {
// callback when data is sent
Serial.print("\nMessage sent");
// display MAC of where the data was sent
char macStr[25];
snprintf(macStr, sizeof(macStr)," to %02X:%02X:%02X:%02X:%02X:%02X",
macAddr[0], macAddr[1], macAddr[2],
macAddr[3], macAddr[4], macAddr[5]);
Serial.print(macStr);
// display the status returned by the other device
Serial.print(", status: ");
Serial.print(status == ESP_NOW_SEND_SUCCESS ? "OK" : "Fail");
// display the data that was sent
displayTransmittedData();
}
// ....................................................................................
void displayTransmittedData() {
// desired data is in 's_switchInfo' structure
char dataStr[50];
snprintf(dataStr, sizeof(dataStr), "\n Device number %u, Level %s, Count %u ",
s_switchInfo.i_id, s_switchInfo.c_level, s_switchInfo.i_count);
Serial.print(dataStr);
}
// ....................................................................................
void checkInputLevel() {
int value = digitalRead(inputPin);
if (value != oldValue) {
newValueFlag = true;
oldValue = value;
if(value == 1) {
Serial.print("\n--> level has gone high");
++highCount;
s_switchInfo.i_id = unitId;
s_switchInfo.i_count = highCount;
strcpy(s_switchInfo.c_level, "HIGH");
}
else {
if(value == 0)
Serial.print("\n--> level has gone low");
++lowCount;
s_switchInfo.i_id = unitId;
s_switchInfo.i_count = lowCount;
strcpy(s_switchInfo.c_level, "LOW");
}
delay(10); // crude debounce
}
}
// ....................................................................................
// use ESP-NOW to do something based on a message from another device
// in this case just light an LED
// Compiled using Arduino 1.8.19, and ESP32 v2.0.2
// Compiled for board: ESP32 Dev Module
// (but running on an AI Thinker ESP-CAM since I have a bunch of them)
// ...... program information
char programName[] = "ResponderA_22A";
char versionNumber[] = "v01";
char programDate[] = "2022-09-25";
char programAuthor[] = "Donald Weiman";
// ...... required libraries
#include <esp_now.h>
#include <WiFi.h>
// define data structure for received data
struct s_message {
int i_id;
int i_count;
char c_level[20];
} ;
// create structured data object
s_message s_switchInfo; // from initiator
// ...... LED
const byte flashLedPin = 4; // white led on AI Thinker ESP-CAM board
#define flashLedOff 0 // active high
const byte builtinLedPin = 33; // red led on AI Thinker ESP-CAM board
#define builtinLedOff 1 // active low
// ...... misc
char thisDeviceMac[20] ; // Mac address for this device (for info only)
bool newDataFlag = false;
// ....................................................................................
void setup() {
Serial.begin(115200);
delay(1000);
// ...... display sign-on message
Serial.println();
Serial.println();
Serial.print(programName);
Serial.print(" ");
Serial.print(versionNumber);
Serial.print(" ");
Serial.print(programDate);
Serial.print(" ");
Serial.print(programAuthor);
Serial.print("\n");
// ...... display MAC address (of this device)
WiFi.macAddress().toCharArray(thisDeviceMac, 20);
Serial.printf("\nMAC address: %s", thisDeviceMac);
// ...... WiFi
WiFi.mode(WIFI_STA);
// ...... esp-now
// initalize ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// register callback function
esp_now_register_recv_cb(OnDataRecv);
// ...... LEDs
pinMode(flashLedPin, OUTPUT); // turn LEDs off
digitalWrite(flashLedPin, flashLedOff);
pinMode(builtinLedPin, OUTPUT);
digitalWrite(builtinLedPin, builtinLedOff);
// ...... end of setup
Serial.print("\nsetup complete\n");
}
// ....................................................................................
void loop() {
// act on received data if appropriate
if(newDataFlag == true) {
newDataFlag = false;
// act on received data
if(strcmp (s_switchInfo.c_level, "HIGH") == 0) {
digitalWrite(flashLedPin, !flashLedOff);
digitalWrite(builtinLedPin, builtinLedOff);
} else {
digitalWrite(flashLedPin, flashLedOff);
digitalWrite(builtinLedPin, !builtinLedOff);
}
}
// do something else ...
}
// ....................................................................................
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
// extract the received data
char receivedData[100];
memcpy(&s_switchInfo, incomingData, sizeof(s_switchInfo));
// deal with received data
newDataFlag = true; // handled in loop()
// display received data - (interesting, but not essential)
char recvStr[50];
snprintf(recvStr, sizeof(recvStr), "\n %u %u %s",
s_switchInfo.i_id, s_switchInfo.i_count, s_switchInfo.c_level);
Serial.print(recvStr);
// display MAC of sending device - (interesting, but not essential)
char macStr[20];
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Serial.print(" Received from ");
Serial.print(macStr);
}
// ....................................................................................
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment