ESP Now worked, now "����~f�`�~␀␘�␞����␘fx␆␆x�"

I have some ESP32s, and I’m trying to get a project working. It was working last year when I put it away. It wasn’t working, so I tried messing with it and trying to diagnose. I gave up.

It’s ESP Now, a sensor pod (D1 Mini) transmitting to a base station (R32). There’s a BME680 for temperature and humidity, VOC, and SGP30 for CO.

The sender code appears to be working, but the receiver code is bonkers. It starts normal, ‘setting as wifi station’, but then this:
����~f��~␀␘�␞����␘fx␆␆x����~f��~␀␘�␞����␘fx␆␆x����~f��~␀␘�␞����␘fx␆␆x����~f��~␀␘�␞����␘fx␆␆x����~f�`�~␀␘�␞����␘fx␆

AND THEN it switches to this, which is not called for anywhere:
Board ID: 0
TeTime : 09:57:06
Board ID: 0
TeTime : 09:57:06
Board ID: 0
TeTime : 09:57:06
Board ID: 0

Can you help me debug it?

Receiver code:

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-esp-now-wi-fi-web-server/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/
#include <Arduino.h>
#include <esp_now.h>
#include <WiFi.h>
#include "ESPAsyncWebServer.h"
#include <Arduino_JSON.h>
#include "Adafruit_GFX.h"
#include "Fonts/FreeSansBold9pt7b.h"
#include "Fonts/Org_01.h"
#include "Fonts/Picopixel.h"
#include "Adafruit_SSD1306.h"
#include <NTPClient.h>
#include <WiFiUdp.h>

#define NTP_OFFSET -18000       // In seconds
#define NTP_INTERVAL 60 * 1000 // In miliseconds
#define NTP_ADDRESS "pool.ntp.org"

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);

//Adafruit_SSD1306 display(128, 64, &Wire, 8); //Declaring the display name (display)
Adafruit_SSD1306 display(0x3c, 5, 4);

// Replace with your network credentials (STATION)
const char *ssid = "TP-Link_7C28";
const char *password = "64411811";

// Structure example to receive data
// Must match the sender structure
typedef struct struct_message
{
  int id;
  float temperature;
  float humidity;
  float pressure;
  float altitude;
  float LPG;
  float UV;
  float CO;
  float CO2;
  float NH3;
  float NO2;
  float VOC;
  float TVOC;
  float H2;
  float EtOH;
  int readingId;
} struct_message;

struct_message incomingReadings;

JSONVar board;

AsyncWebServer server(80);
AsyncEventSource events("/events");

// callback function that will be executed when data is received
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *incomingData, int len)
{
  // Copies the sender mac address to a string
  char macStr[18];
  Serial.print("Packet received from: ");
  snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",

           mac_addr[0],
           mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
  Serial.println(macStr);
  memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));

  board["id"] = incomingReadings.id, len;
  board["temperature"] = incomingReadings.temperature;
  board["humidity"] = incomingReadings.humidity;
  board["pressure"] = incomingReadings.pressure;
  board["altitude"] = incomingReadings.altitude;
  board["LPG"] = incomingReadings.LPG;
  board["UV"] = incomingReadings.UV;
  board["CO"] = incomingReadings.CO;
  board["CO2"] = incomingReadings.CO2;
  board["NH3"] = incomingReadings.NH3;
  board["NO2"] = incomingReadings.NO2;
  board["VOC"] = incomingReadings.VOC;
  board["TVOC"] = incomingReadings.TVOC;
  board["H2"] = incomingReadings.H2;
  board["EtOH"] = incomingReadings.EtOH;

  board["readingId"] = String(incomingReadings.readingId);
  String jsonString = JSON.stringify(board);
  
  events.send(jsonString.c_str(), "new_readings", millis());


}

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <title>Monster Laboratories Smart Home</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
  <link rel="icon" href="data:,">
  <style>
    html {font-family: Arial; display: inline-block; text-align: center;}
    p {  font-size: 1.2rem;}
    body {  margin: 0;}
    .topnav { overflow: hidden; background-color: #2f4468; color: white; font-size: 1.7rem; }
    .content { padding: 20px; }
    .card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }
    .cards { max-width: 3500px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
    .reading { font-size: 2.8rem; }
    .packet { color: #bebebe; }
    .card.temperature { color: #fd7e14; }
    .card.humidity { color: #1b78e2; }
    .card.pressure { color: #17b8e2; }
    .card.UV { color: #17b8e2; }
  </style>
</head>

<body>
  <div class="topnav">
    <h3>Monster Laboratories SmartHome</h3>
  </div>



<p>Page opened: <span id="datetime"></span></p>
<script>
var dt = new Date();
document.getElementById('datetime').innerHTML=dt;
</script>



  <div class="content">
    <div class="cards">
      
      <div class="card temperature">
        <h4><i class="fas fa-thermometer-half"></i> BOARD #1 - TEMPERATURE</h4>
        <p><span class="reading"><span id="t1"></span> &deg;C</span></p>
        <p class="packet">Reading ID: <span id="rt1"></span></p>
      </div>

       <div class="card temperature">
        <h4><i class="fas fa-thermometer-half"></i> BOARD #2 - TEMPERATURE</h4>
        <p><span class="reading"><span id="t2"></span> &deg;C</span></p>
        <p class="packet">Reading ID: <span id="rt2"></span></p>
      </div>

       <div class="card temperature">
        <h4><i class="fas fa-thermometer-half"></i> BOARD #3 - TEMPERATURE</h4>
        <p><span class="reading"><span id="t3"></span> &deg;C</span></p>
        <p class="packet">Reading ID: <span id="rt3"></span></p>
      </div>
      
      <div class="card humidity">
        <h4><i class="fas fa-tint"></i> BOARD #1 - HUMIDITY</h4>
        <p><span class="reading"><span id="h1"></span> &percnt;</span></p>
        <p class="packet">Reading ID: <span id="rh1"></span></p>
      </div>     

      <div class="card pressure">
        <h4><i class="fas fa-tint"></i> BOARD #1 - PRESSURE</h4>
        <p><span class="reading"><span id="p1"></span> "Hg</span></p>
        <p class="packet">Reading ID: <span id="rp1"></span></p>
      </div>

      <div class="card UV">
        <h4><i class="fas fa-tint"></i> BOARD #2 - UV</h4>
        <p><span class="reading"><span id="u2"></span> ... </span></p>
        <p class="packet">Reading ID: <span id="ru2"></span></p>
      </div>

    </div>
  </div>
<script>
if (!!window.EventSource) {
 var source = new EventSource('/events');
 
 source.addEventListener('open', function(e) {
  console.log("Events Connected");
 }, false);
 source.addEventListener('error', function(e) {
  if (e.target.readyState != EventSource.OPEN) {
    console.log("Events Disconnected");
  }
 }, false);
 
 source.addEventListener('message', function(e) {
  console.log("message", e.data);
 }, false);
 
 source.addEventListener('new_readings', function(e) {
  console.log("new_readings", e.data);
  var obj = JSON.parse(e.data);

  document.getElementById("t"+obj.id).innerHTML = obj.temperature.toFixed(1);
  document.getElementById("h"+obj.id).innerHTML = obj.humidity.toFixed(0);
  document.getElementById("p"+obj.id).innerHTML = obj.pressure.toFixed(1);
  document.getElementById("u"+obj.id).innerHTML = obj.UV.toFixed(0);

  document.getElementById("rt"+obj.id).innerHTML = obj.readingId;
  document.getElementById("rh"+obj.id).innerHTML = obj.readingId;
  document.getElementById("rp"+obj.id).innerHTML = obj.readingId;
  document.getElementById("ru"+obj.id).innerHTML = obj.readingId;
  console.log(obj.readingId);

 }, false);
}
</script>
 
</body>
</html>)rawliteral";

void setup()
{
  // Initialize Serial Monitor
  Serial.begin(9600);

  // Set the device as a Station and Soft Access Point simultaneously
  WiFi.mode(WIFI_AP_STA);

  // Set device as a Wi-Fi Station
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(1000);
    Serial.println("Setting as a Wi-Fi Station..");
  }
  Serial.print("Station IP Address: ");
  Serial.println(WiFi.localIP());
  Serial.print("Wi-Fi Channel: ");
  Serial.println(WiFi.channel());

  timeClient.begin();

  Wire.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //Start the OLED display

  display.setTextColor(WHITE);
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(2, 5);
  display.print("MonsterLaboratories"); //Show the name, you can remove it or replace it
  display.setCursor(32, 17);
  display.setTextSize(2);
  display.println("Smart");
  display.setCursor(32, 31);
  display.println("Home");
  display.display();
  delay(3000);
 
  // 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 recv CB to
  // get recv packer info
  esp_now_register_recv_cb(OnDataRecv);

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send_P(200, "text/html", index_html);
  });

  events.onConnect([](AsyncEventSourceClient *client) {
    if (client->lastId())
    {
      Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
    }
    // send event with message "hello!", id current millis
    // and set reconnect delay to 1 second
    client->send("hello!", NULL, millis(), 10000);
  });
  server.addHandler(&events);
  server.begin();
}



void loop()
{  
  static unsigned long lastEventTime = millis();
  static const unsigned long EVENT_INTERVAL_MS = 5000;
  if ((millis() - lastEventTime) > EVENT_INTERVAL_MS)
  {
    events.send("ping", NULL, millis());
    lastEventTime = millis();
  }
  timeClient.update();
  String formattedTime = timeClient.getFormattedTime();

  display.setTextColor(WHITE);
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(1, 7);
  display.print("Station IP : ");
  display.println(WiFi.localIP());
  display.setFont(&Org_01);
  display.print("Time (-12 h): ");
  display.println(formattedTime);
  display.setCursor(1, 20);
  display.print("Board ID: ");
  display.println(incomingReadings.id);
  display.print("Temp:    "),
  display.println(incomingReadings.temperature, 1);
  display.print("Hum:     "),
  display.println(incomingReadings.humidity, 0);
  display.print("Press:   "),
  display.println(incomingReadings.pressure, 0);
  display.print("Alt:     "),
  display.println(incomingReadings.altitude, 0);
  display.print("Uv:      "),
  display.println(incomingReadings.UV, 0);
  display.setCursor(64, 20);
  display.print("CO:     "),
  display.print(incomingReadings.CO, 0);
  display.setCursor(64, 27);
  display.print("CO2:    "),
  display.println(incomingReadings.CO2, 0);
  display.setCursor(64, 34);
  display.print("VOC:    "),
  display.println(1/incomingReadings.VOC, 0);
  display.setCursor(64, 41);
  display.print("TVOC:   "),
  display.println(incomingReadings.TVOC, 0);
  display.setCursor(64, 48);
  display.print("H2:     ");
  display.println(incomingReadings.H2, 0);
  display.setCursor(64, 55);
  display.print("EtOH:   "),
  display.println(incomingReadings.EtOH, 0);
  display.setCursor(1, 62);
  display.print("readingID: ");
  display.println(incomingReadings.readingId, 0);
  display.display();

  Serial.print("Time : ");
  Serial.println(formattedTime);
  Serial.print("Board ID: ");
  Serial.println(incomingReadings.id);
  Serial.print("Temp:    "),
      Serial.println(incomingReadings.temperature, 1);
  Serial.print("Hum:     "),
      Serial.println(incomingReadings.humidity, 0);
  Serial.print("Press:   "),
      Serial.println(incomingReadings.pressure, 0);
  Serial.print("Alt:     "),
      Serial.println(incomingReadings.altitude, 0);
  Serial.print("Uv:      "),
      Serial.println(incomingReadings.UV, 0);
  Serial.print("CO:     "),
      Serial.println(incomingReadings.CO, 0);
  Serial.print("CO2:    "),
      Serial.println(incomingReadings.CO2, 0);
  Serial.print("VOC:    "),
      Serial.println(1 / incomingReadings.VOC, 0);
  Serial.print("TVOC:   "),
      Serial.println(incomingReadings.TVOC, 0);
  Serial.print("H2:     ");
  Serial.println(incomingReadings.H2, 0);
  Serial.print("EtOH:   "),
      Serial.println(incomingReadings.EtOH, 0);
  Serial.print("readingID: ");
  Serial.println(incomingReadings.readingId, 0);
  delay(5000);
}
'''

Sender code:

#include <Arduino.h>

/*

Rui Santos

Complete project details at ESP32: ESP-NOW and Wi-Fi Web Server Dashboard (Arduino) | Random Nerd Tutorials

Permission is hereby granted, free of charge, to any person obtaining a copy

of this software and associated documentation files.

The above copyright notice and this permission notice shall be included in all

copies or substantial portions of the Software.

*/

#include <esp_now.h>

#include <esp_wifi.h>

#include <WiFi.h>

#include <Adafruit_Sensor.h>

#include “Adafruit_BME680.h”

#include “Adafruit_SGP30.h”

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_SGP30 sgp;

Adafruit_BME680 bme; // I2C

// Set your Board ID (ESP32 Sender #1 = BOARD_ID 1, ESP32 Sender #2 = BOARD_ID 2, etc)

#define BOARD_ID 2

//MAC Address of the receiver

uint8_t broadcastAddress[] = {0xFC, 0xF5, 0xC4, 0x2F, 0xA1, 0x04};

//Structure example to send data

//Must match the receiver structure

typedef struct struct_message

{

int id;

float completed;

float temperature;

float humidity;

float pressure;

float altitude;

float LPG;

float CO;

float CO2;

float NH3;

float NO2;

float VOC;

float TVOC;

float H2;

float EtOH;

int readingId;

} struct_message;

//Create a struct_message called myData

struct_message myData;

unsigned long previousMillis = 0; // Stores last time temperature was published

const long interval = 10000; // Interval at which to publish sensor readings

unsigned int readingId = 0;

// Insert your SSID

constexpr char WIFI_SSID[] = “TP-Link_7C28”;

int32_t getWiFiChannel(const char *ssid)

{

if (int32_t n = WiFi.scanNetworks())

{

for (uint8_t i = 0; i < n; i++)

{

  if (!strcmp(ssid, WiFi.SSID(i).c_str()))

  {

    return WiFi.channel(i);

  }

}

}

return 0;

}

// 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”);

}

void setup()

{

Serial.begin(9600);

//Init Serial Monitor

while (!Serial)

;

Serial.println(F(“BME680 test”));

if (!bme.begin())

{

Serial.println(F("BME680 not found"));

while (1)

  ;

}

Serial.println(“SGP30 test”);

if (!sgp.begin())

{

Serial.println("SGP30 not found :(");

while (1)

  ;

}

pinMode(35, INPUT);

pinMode(34, INPUT);

pinMode(36, INPUT);

pinMode(39, INPUT);

// Set device as a Wi-Fi Station and set channel

WiFi.mode(WIFI_STA);

int32_t channel = getWiFiChannel(WIFI_SSID);

WiFi.printDiag(Serial); // Uncomment to verify channel number before

esp_wifi_set_promiscuous(true);

esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);

esp_wifi_set_promiscuous(false);

WiFi.printDiag(Serial); // Uncomment to verify channel change after

//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.encrypt = false;

//Add peer

if (esp_now_add_peer(&peerInfo) != ESP_OK)

{

Serial.println("Failed to add peer");

return;

}

// Set up oversampling and filter initialization

bme.setTemperatureOversampling(BME680_OS_8X);

bme.setHumidityOversampling(BME680_OS_2X);

bme.setPressureOversampling(BME680_OS_4X);

bme.setIIRFilterSize(BME680_FILTER_SIZE_3);

bme.setGasHeater(320, 150); // 320*C for 150 ms

}

void loop()

{

float LPG = analogRead(35);

float NH3 = analogRead(34);

float NO2 = analogRead(36);

float CO = analogRead(39);

float CO2 = sgp.eCO2;

float VOC = bme.gas_resistance;

float TVOC = sgp.TVOC;

float H2 = sgp.rawH2;

float EtOH = sgp.rawEthanol;

float altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);

unsigned long currentMillis = millis();

if (currentMillis - previousMillis >= interval)

{

if (!bme.endReading())

{

  Serial.println(F("Failed to complete reading :("));

  return;

}

Serial.print(F("Reading completed at "));

Serial.println(millis());

float completed = millis();

Serial.print(F("Temperature = "));

Serial.print(bme.temperature, 0);

Serial.println(F(" *C"));

Serial.print(F("Humidity = "));

Serial.print(bme.humidity, 0);

Serial.println(F(" %"));

Serial.print(F("CO = "));

Serial.print(CO, 0);

Serial.println(F(" %"));

Serial.print(F("NH3 = "));

Serial.print(NH3, 0);

Serial.println(F(" %"));

Serial.print(F("CO2 = "));

Serial.print(sgp.eCO2, 0);

Serial.println(F(" %"));

// Save the last time a new reading was published

previousMillis = currentMillis;

//Set values to send

myData.id = BOARD_ID;

myData.completed = completed;

myData.temperature = (bme.temperature);

myData.humidity = (bme.humidity);

myData.pressure = (bme.pressure);

myData.altitude = altitude;

myData.LPG = LPG;

myData.CO = CO;

myData.CO2 = CO2;

myData.NH3 = NH3;

myData.NO2 = NO2;

myData.VOC = VOC;

myData.TVOC = TVOC;

myData.H2 = H2;

myData.EtOH = EtOH;

myData.readingId = readingId++;

//Send message via ESP-NOW

esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&myData, sizeof(myData));

if (result == ESP_OK)

{

  Serial.println("Sent with success");

}

else

{

  Serial.println("Error sending the data");

}

}

delay(5000);

}