user67028: I am trying to set up two ESP32s so that they can be updated via OTA and at the same time send sensor readings using ESP-NOW, from Sender Board to Receiver Board.
For this to work both boards must connect to wifi and simultaneously send messages over ESP-NOW.
I don't mind using a mode where a button is pressed and Wifi is only then enabled but switching wifi on and off seems to have intermittent success.
I have tried setting the channels to the same on both boards but this does not work.
In the example below I have stripped all the OTA code out and the code needed for ESP-NOW and just the line for WIFI enable

WiFi.begin(ssid, password);

which when enabled causes the delivery to fail.
Here is my Sender Code:
        #include <esp_now.h>
        #include <WiFi.h>
        #include <Wire.h>
        #define ssid "MYNETWORKSSID"
        #define password "mynetworkpassword"
        
         const int sNine = 33;
        
         #define CHAN_AP 2
        
        
        uint8_t broadcastAddress[] = {0x24, 0x62, 0xAB, 0xDC, 0x70, 0x90};
        int hall;
        
        String success;
        
        typedef struct struct_message {
            int hall;
        } struct_message;
        struct_message hallReadings;
        
        
        // Callback when data is sent
        void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
          Serial.print("\r\nLast Packet Send Status:\t");
          Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
          if (status ==0){
            success = "Delivery Success :)";
          }
          else{
            success = "Delivery Fail :(";
          }
        }
        
        void setup() {
          // Init Serial Monitor
          Serial.begin(115200);
          WiFi.mode(WIFI_STA);
         WiFi.begin(ssid, password); // PROBLEMATIC LINE
    
          // Init ESP-NOW
          if (esp_now_init() != ESP_OK) {
            Serial.println("Error initializing ESP-NOW");
            return;
          }
          // Once ESPNow is successfully Init, we will register for Send CB to
          // get the status of Trasnmitted packet
          esp_now_register_send_cb(OnDataSent);
        
          // Register peer
          esp_now_peer_info_t peerInfo;
          memcpy(peerInfo.peer_addr, broadcastAddress, 6);
          peerInfo.channel = CHAN_AP;
          peerInfo.encrypt = false;
        
          // Add peer
          if (esp_now_add_peer(&peerInfo) != ESP_OK){
            Serial.println("Failed to add peer");
            return;
          }
        }
        
        void loop() {
          // getReadings();
        
           hallReadings.hall = analogRead(sNine);
        
          esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &hallReadings, sizeof(hallReadings));
        
          if (result == ESP_OK) {
            Serial.println("Sent with success");
          }
          else {
            Serial.println("Error sending the data");
          }
          delay(100);
        }

Here is my Receiver code:
#include <esp_now.h>
#include <WiFi.h>
#include <Wire.h>

 const int sNine = 15;


//Wi-Fi channel (must match the gateway wi-fi channel as an access point)
#define CHAN_AP 2


// Define variables to store incoming readings
int incomingHall;

//Structure example to send data
//Must match the receiver structure
typedef struct struct_message {
    int hall;
} struct_message;

// Create a struct_message to hold incoming sensor readings
struct_message incomingReadings;

void updateDisplay(){

  Serial.print(incomingReadings.hall);
}

// Callback when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
  incomingHall = incomingReadings.hall;
}

void setup() {
  // Init Serial Monitor
  Serial.begin(115200);
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);
  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  // Register for a callback function that will be called when data is received
  esp_now_register_recv_cb(OnDataRecv);
}

void loop() {

  updateDisplay();
  delay(100);
}


user65522: I do something similar on a ESP8266 retrieving time from a NTP-server.
Though it is just a "work around".

I connect to the router retrieving the NTP-time.
storing the time-information into RTC-RAM including a flag that indicates "time received"
then do a software-RESET
the setup-function checks this flag to decide if the ESP8266 shall connect to the router or shall keep WiFi OFF and activate ESP-NOW

if you want to use this for OTA it could "work" like this
sending a special ESP-NOW-Message initiating setting a flag "do_OTA" in RTC-RAM and then re-boot
the setup-function looks for this flag "do_OTA" to be set does what its name says
clearing the "do_OTA"-flag
What I don't know is writing new code into flash is a different thing than just re-booting through a software-reset. So maybe the content of the RTC-RAM gets lost through the update-process.
If so you could write the flag into flash using LittleFS
best regards Stefan

user71322: Another method that works if you don't mind having both at the same time:
Instead of WiFi.begin(ssid, password);
I use WiFi.softAp(ssid,password,channel); for both Sender and Receiver.

user71330: If you want to switch the softAP connection On/OFF you can do like StefanL38 suggests and have the Receiver transmit a ESP-NOW message with a value to the Sender, but you don't need a reboot. You can drop softAP and come up as STA or vise versa, for example.
    if(incomingid == 3){
      incomingValue = incomingReadings.Value;

      // to allow OTA, using Elegant OTA, haven't tried others.
          
    if(incomingValue == 1){
      WiFi.softAP(ssid,password,6);
      Serial.print("Connecting to ESP32 SSID ");
      Serial.println(ssid);  
      IPAddress IP = WiFi.softAPIP();
      Serial.print("AP IP address: ");
      Serial.println(IP);
      WiFi.printDiag(Serial);
    }

      // to disconnect and allow ESP-NOW via Station mode.

   else if(incomingValue == 0){
      WiFi.softAPdisconnect(true);
      delay(1000);
      WiFi.mode(WIFI_STA);
      delay(1000);
      WiFi.printDiag(Serial); // STA Defaults to channel 1
      esp_wifi_set_promiscuous(true);
      esp_wifi_set_channel(6, WIFI_SECOND_CHAN_NONE); // channel 6 setup
      esp_wifi_set_promiscuous(false);
      WiFi.printDiag(Serial);
    }
  }


67028: <p>I am trying to set up two ESP32s so that they can be updated via OTA and at the same time send sensor readings using ESP-NOW, from Sender Board to Receiver Board.</p>
<p>For this to work both boards must connect to wifi and simultaneously send messages over ESP-NOW.</p>
<p>I don't mind using a mode where a button is pressed and Wifi is only then enabled but switching wifi on and off seems to have intermittent success.</p>
<p>I have tried setting the channels to the same on both boards but this does not work.</p>
<p>In the example below I have stripped all the OTA code out and the code needed for ESP-NOW and just the line for WIFI enable</p>
<blockquote>
<p>WiFi.begin(ssid, password);</p>
</blockquote>
<p>which when enabled causes the delivery to fail.</p>
<p>Here is my Sender Code:</p>
<pre><code>        #include &lt;esp_now.h&gt;
        #include &lt;WiFi.h&gt;
        #include &lt;Wire.h&gt;
        #define ssid &quot;MYNETWORKSSID&quot;
        #define password &quot;mynetworkpassword&quot;
        
         const int sNine = 33;
        
         #define CHAN_AP 2
        
        
        uint8_t broadcastAddress[] = {0x24, 0x62, 0xAB, 0xDC, 0x70, 0x90};
        int hall;
        
        String success;
        
        typedef struct struct_message {
            int hall;
        } struct_message;
        struct_message hallReadings;
        
        
        // Callback when data is sent
        void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
          Serial.print(&quot;\r\nLast Packet Send Status:\t&quot;);
          Serial.println(status == ESP_NOW_SEND_SUCCESS ? &quot;Delivery Success&quot; : &quot;Delivery Fail&quot;);
          if (status ==0){
            success = &quot;Delivery Success :)&quot;;
          }
          else{
            success = &quot;Delivery Fail :(&quot;;
          }
        }
        
        void setup() {
          // Init Serial Monitor
          Serial.begin(115200);
          WiFi.mode(WIFI_STA);
         WiFi.begin(ssid, password); // PROBLEMATIC LINE
    
          // Init ESP-NOW
          if (esp_now_init() != ESP_OK) {
            Serial.println(&quot;Error initializing ESP-NOW&quot;);
            return;
          }
          // Once ESPNow is successfully Init, we will register for Send CB to
          // get the status of Trasnmitted packet
          esp_now_register_send_cb(OnDataSent);
        
          // Register peer
          esp_now_peer_info_t peerInfo;
          memcpy(peerInfo.peer_addr, broadcastAddress, 6);
          peerInfo.channel = CHAN_AP;
          peerInfo.encrypt = false;
        
          // Add peer
          if (esp_now_add_peer(&amp;peerInfo) != ESP_OK){
            Serial.println(&quot;Failed to add peer&quot;);
            return;
          }
        }
        
        void loop() {
          // getReadings();
        
           hallReadings.hall = analogRead(sNine);
        
          esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &amp;hallReadings, sizeof(hallReadings));
        
          if (result == ESP_OK) {
            Serial.println(&quot;Sent with success&quot;);
          }
          else {
            Serial.println(&quot;Error sending the data&quot;);
          }
          delay(100);
        }
</code></pre>
<p>Here is my Receiver code:</p>
<pre><code>#include &lt;esp_now.h&gt;
#include &lt;WiFi.h&gt;
#include &lt;Wire.h&gt;

 const int sNine = 15;


//Wi-Fi channel (must match the gateway wi-fi channel as an access point)
#define CHAN_AP 2


// Define variables to store incoming readings
int incomingHall;

//Structure example to send data
//Must match the receiver structure
typedef struct struct_message {
    int hall;
} struct_message;

// Create a struct_message to hold incoming sensor readings
struct_message incomingReadings;

void updateDisplay(){

  Serial.print(incomingReadings.hall);
}

// Callback when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&amp;incomingReadings, incomingData, sizeof(incomingReadings));
  incomingHall = incomingReadings.hall;
}

void setup() {
  // Init Serial Monitor
  Serial.begin(115200);
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);
  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println(&quot;Error initializing ESP-NOW&quot;);
    return;
  }
  // Register for a callback function that will be called when data is received
  esp_now_register_recv_cb(OnDataRecv);
}

void loop() {

  updateDisplay();
  delay(100);
}
</code></pre>
 65522: <p>I do something similar on a ESP8266 retrieving time from a NTP-server.
Though it is just a &quot;work around&quot;.</p>
<ul>
<li>I connect to the router retrieving the NTP-time.</li>
<li>storing the time-information into RTC-RAM including a flag that indicates &quot;time received&quot;</li>
<li>then do a software-RESET</li>
<li>the setup-function checks this flag to decide if the ESP8266 shall connect to the router or shall keep WiFi OFF and activate ESP-NOW</li>
</ul>
<p>if you want to use this for OTA it could &quot;work&quot; like this</p>
<p>sending a special ESP-NOW-Message initiating setting a flag &quot;do_OTA&quot; in RTC-RAM and then re-boot
the setup-function looks for this flag &quot;do_OTA&quot; to be set does what its name says
clearing the &quot;do_OTA&quot;-flag</p>
<p>What I don't know is writing new code into flash is a different thing than just re-booting through a software-reset. So maybe the content of the RTC-RAM gets lost through the update-process.</p>
<p>If so you could write the flag into flash using LittleFS</p>
<p>best regards Stefan</p>
 71322: <p>Another method that works if you don't mind having both at the same time:</p>
<p>Instead of WiFi.begin(ssid, password);
I use WiFi.softAp(ssid,password,channel); for both Sender and Receiver.</p>
 71330: <p>If you want to switch the softAP connection On/OFF you can do like StefanL38 suggests and have the Receiver transmit a ESP-NOW message with a value to the Sender, but you don't need a reboot. You can drop softAP and come up as STA or vise versa, for example.</p>
<pre class="lang-cpp prettyprint-override"><code>    if(incomingid == 3){
      incomingValue = incomingReadings.Value;

      // to allow OTA, using Elegant OTA, haven't tried others.
          
    if(incomingValue == 1){
      WiFi.softAP(ssid,password,6);
      Serial.print(&quot;Connecting to ESP32 SSID &quot;);
      Serial.println(ssid);  
      IPAddress IP = WiFi.softAPIP();
      Serial.print(&quot;AP IP address: &quot;);
      Serial.println(IP);
      WiFi.printDiag(Serial);
    }

      // to disconnect and allow ESP-NOW via Station mode.

   else if(incomingValue == 0){
      WiFi.softAPdisconnect(true);
      delay(1000);
      WiFi.mode(WIFI_STA);
      delay(1000);
      WiFi.printDiag(Serial); // STA Defaults to channel 1
      esp_wifi_set_promiscuous(true);
      esp_wifi_set_channel(6, WIFI_SECOND_CHAN_NONE); // channel 6 setup
      esp_wifi_set_promiscuous(false);
      WiFi.printDiag(Serial);
    }
  }
</code></pre>
