Hi everyone!
Im working on a project where i want to measure some RSSI values with different technologies. Basically im using ESP NOW protocol to send some Start signals to other boards and modules, and they also exchange datas via ESP NOW. My problem is, that i want to measure WiFi RSSI too, but as far as i know, ESP NOW and WiFi cant work simultaneously, am i right? Both boards runs in WIFI_AP_STA mode, one using softAP(ssid,password) and the other WiFi.begin(ssid,password) and they cant connect. Could someone give me some helpful information, about how should i do this correctly?
I read the forum about how could i paste my code in here, but for me there isnt any symbol or option. I created my account 2 days ago, maybe it could be the reason.
ESPNOW is using the only WiFi transmitter/receiver on the board. You could get another ESP32 that's just using WiFi and have the ESP32NOW board serially send the info to the ESP32WiFi module for retransmission.
Thank you for your fast reply!
If you go that route, investigate an ESP-01, that's pretty just for WiFi already, you can link it to any Arduino, and they are uber cheap.
more discussion here:
https://rntlab.com/question/esp-now-gateway-wifi_mode_sta-with-a-wifi-router/
Hi @schroomy,
I faced the same issue a few months ago where I found you could not run ESP-NOW & WiFi together on the same ESP32.
After some digging around, I came across this ESPNOW to Internet Gateway video on YouTube
With the code the for the ESP32's HERE
I was able to modify the code to now work with Arduino IoT cloud instead of BLYNK
I using an Adafruit ESP32-S2 Feather with BME280 Sensor that talks to an SparkFun Thing Plus - ESP32 WROOM (U.FL) via ESP-NOW This also has an 0.96 OLED display connected to the Qwiic
connector. This then has a 2nd UART connection + power to a cheap AZ-Delivery ESP32 Lolin LOLIN32 that connects to the Arduino IoT cloud. I'm also using the Scheduler task in the Arduino IoT cloud to control ON/OFF times of the OLED display.
This has now been running 24/7 for just over two months now
Hope some of this helps you out?
Thank you guys for the answers, im sure these will help me a lot. I will check the links, and the video too
As long as your WiFi router is on channel 1 the implementation of simultaneous ESP-NOW and WiFi is almost trivial.
A simplified version of what I have going so far has one ESP32 sending the status of a push-button switch to a second ESP32 using ESP-NOW. The second ESP32 is also using MQTT to communicate via WiFi with Node-RED running on a RaspberryPi.
I started with a simple one way ESP-NOW link between the two ESP32s. In order to implement the WiFi link on the second ESP32 all I had to do was change the WiFi mode from WIFI_STA to WIFI_AP_STA and add the usual code to connect to my access point. No changes were needed on the device with the push-button switch.
It's a bit trickier if your WiFi router is on a channel other than channel 1 but I think I have it working OK with an access point on on channel 11.
Don
It doesn't have to disconnect and reconnect between ESP-NOW transmissions?
Can you please provide a sample code?
Not right now, I don't have any simple examples available. I'll try to put something together in the next few days.
Don
That would be wonderful, when you have the time. Thank you.
I tried to set different channels on the ESP32 who is doing the WiFi.softAP(ssid,password,channel) part, but nothin worked. And both devices are set in WIFI_AP_STA mode. And what really interesting for me is, that with my phone i could connect to the Network AP device, and also, if i did WiFi hotspot with my phone, the connecting device could connect to my network. But if that device trying to connect to the other ESP32, its just returns me the WL_DISCONNECTED error.
I think you will have to explain how many devices you are talking about and how they are trying to communicate. A drawing would help.
You obviously have at least two ESP devices communicating with each other via ESP-NOW.
- How many WiFi access points (routers) are involved?
- What channel(s) are they on?
- Which AP connects with which ESP?
In my current application I have two ESP devices and one AP. The first ESP makes a measurement and sends the result via ESP-NOW to the second ESP. The second ESP passes the measurement on to other devices via WiFi and the router.
In any case all of the devices have to be using the same channel and things are (currently) a lot easier if that is channel 1.
Don
Now i have 3 ESP32 boards, 1 is acting like an AP, one is acting like STA and connected to it, and the last one is only communicating via ESP NOW. The first 2 boards are both running in AP_STA mode. But in the end, hopefully in 1-2 weeks, i'll have 6 ESP32 boards, 4 AP device, 1 STA device, and 1 only ESP NOW using device.
I'll just explain the current situation. The ESP NOW device is sending out a "Start" signal to the STA device, to start the measurements. That device sends this "Start" signal forwards for the AP device via ESP NOW too, to start sending his packets, and measures RF and WiFi RSSI values. In this part comes in the WiFi connecting, i have to measure the WiFi RSSI values while they are connected because it takes much less time, then just scanning the available networks. After the measurements are completed, this ESP stores the datas into arrays, and then send them to the only ESP NOW using ESP32 via ESP NOW. And thats it. All device is using channel 1 by the way.
Now im able to connect to this network and measure its RSSI, but when i will have 3 more AP devices, i'll have to disconnect after the measurement is completed and have to connect to the others one by one. This is the hard part now.
Another question, why am i not able to connect to a WiFi network in the loop function? I have to make sure, that after every measurements, the ESP is disconnected from the previous network, and can connect to the next network. But i cant do that only in the Setup function
Here are the sample programs promised in reply #10.
This 'Initiator' program sends ESP-NOW data to the other programs.
In this example the data is information about the state of a push-button switch.
// 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
}
}
// ....................................................................................
This 'Responder' program acts upon the data sent by the 'Initiator' program.
In this example it activates some LEDs.
// 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);
}
// ....................................................................................
This 'Gateway' program is an expansion of the 'Responder' program.
In addition to activating the LEDs it also obtains a UNIX timestamp from an internet NTP server and displays that timestamp on the serial monitor.
I have reduced the time between NTP updates from the default 3600 seconds to 120 seconds so that it is easier to see that the WiFi capability is maintained along with the ESP-NOW capability.
// 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();
}
// ....................................................................................
Here's what the output of the 'Gateway' program looks like on the serial monitor.
ResponderA_22A v01 2022-09-25 Donald Weiman
MAC address: 34:94:54:24:3D:E0
.....
Connected to Area51
IP address: 10.12.12.214
connecting to NTP time server
setup complete
*** NTP update *** 1664199483
102 5 HIGH Received from 34:94:54:24:22:58 at 1664199497
102 5 LOW Received from 34:94:54:24:22:58 at 1664199497
102 6 HIGH Received from 34:94:54:24:22:58 at 1664199497
102 6 LOW Received from 34:94:54:24:22:58 at 1664199498
102 7 HIGH Received from 34:94:54:24:22:58 at 1664199502
102 7 LOW Received from 34:94:54:24:22:58 at 1664199504
102 8 HIGH Received from 34:94:54:24:22:58 at 1664199590
102 8 LOW Received from 34:94:54:24:22:58 at 1664199590
*** NTP update *** 1664199603
102 9 HIGH Received from 34:94:54:24:22:58 at 1664199608
102 9 LOW Received from 34:94:54:24:22:58 at 1664199608
102 10 HIGH Received from 34:94:54:24:22:58 at 1664199609
102 10 LOW Received from 34:94:54:24:22:58 at 1664199610
102 11 HIGH Received from 34:94:54:24:22:58 at 1664199664
102 11 LOW Received from 34:94:54:24:22:58 at 1664199664
102 12 HIGH Received from 34:94:54:24:22:58 at 1664199680
102 12 LOW Received from 34:94:54:24:22:58 at 1664199685
102 13 HIGH Received from 34:94:54:24:22:58 at 1664199688
102 13 LOW Received from 34:94:54:24:22:58 at 1664199691
102 14 HIGH Received from 34:94:54:24:22:58 at 1664199719
*** NTP update *** 1664199724
102 14 LOW Received from 34:94:54:24:22:58 at 1664199725
102 15 HIGH Received from 34:94:54:24:22:58 at 1664199823
102 15 LOW Received from 34:94:54:24:22:58 at 1664199823
*** NTP update *** 1664199844
*** NTP update *** 1664199964
*** NTP update *** 1664200084
*** NTP update *** 1664200205
*** NTP update *** 1664200325
*** NTP update *** 1664200446
*** NTP update *** 1664200566
102 16 HIGH Received from 34:94:54:24:22:58 at 1664200644
Note that the majority of the additional code in the 'Gateway' program is there to deal with obtaining the timestamp and this capability has been provided as a means of showing that the WiFi is working. As I mentioned in my previous post actually adding this WiFi capability is trivial.
All three programs are available in this zip file.
ProgramCode.zip (5.9 KB)
EDIT: I created the 'Gateway' program by starting with the 'Responder' program. I see that I forgot to change the name in the "program information" section so the program name shows up improperly in the serial output.
Don
Thank you, Don. This is a very useful contribution to the forum.
@Idahowalker check this out.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.