Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

espnow_sensor.ino - ESPNOW: Peer interface is invalid #5

Open
Picalz opened this issue Apr 23, 2024 · 0 comments
Open

espnow_sensor.ino - ESPNOW: Peer interface is invalid #5

Picalz opened this issue Apr 23, 2024 · 0 comments

Comments

@Picalz
Copy link

Picalz commented Apr 23, 2024

I realize that this may be caused updated ArduinoIDE packages and what not, but I'm not sure how to get around it.

Hardware: ESP32 (WROOM32) (Gateway set up with WROOM32 as well)

Code as tested:
NOTE: I've *undefined the sensors and comment out their uses, and simplified the data struct to modify the code as little as possible.

#define SKETCH_NAME     "ESP-Now Sensor"
#define SKETCH_VERSION  "2021-12-31"
#define SKETCH_ABOUT    "Temp sensor, Deep Sleep, ESP-Now, ESP8266 and ESP32."

//
//  This is a template code for an ESP-Now sensor for ESP8266 and ESP32. It Assumes Arduino IDE.
//
//  Note. ESP8266 and ESP32 use different WiFi implementations why you must set the appropriate
//  #define USE_ESP8266 or USE_ESP32. Please remember to also set the appropriate BOARD in the 
//  ARDUINO IDE to find the correct include files.
//
//  The ESP-Now sensor sends messages on ESP-Now to a MAC address of a Gateway which is 
//  connected to WiFi and Internet.
//
//  A sensor unit consists of; ESP8266 board, a Temp Sensor and a LiPo/Li-Ion battery cell. 
//  An optional Solar panel and Solar panel manager/Battery charger can be connected.
//
//  The ESP8266 operates in deep sleep mode and wakes every 5 mins, takes a sensor reading, 
//  transmits the data using ESP-Now to an ESP-Now Gateway and then returns to deep sleep.
//  The design is aimed for Battery Cell and/or Solar Panel powered units with as low power 
//  consumption as possible, using standard ESP8266 boards. No special, or modified, ultra low 
//  power ESP8266 boards are required.
//
//  ESP-Now is much faster than ordinary WiFi (TCP/IP), reducing the "sending energy" dramatically. 
//  The drawback is that ESP-Now is a proprietary protocol of Espressif and is only implemented 
//  (what i know) for ESP MCU's.
//
//  The wakeup time of the MCU is heavily dependent on the temp sensor used. Some temp sensors 
//  will return sensor data within 100 ms or shorter, some requires 500 ms or more. This varies 
//  with sensor type/manufacturer (spec) and samples. Specs often claim a wake-up or stabilization
//  time of upto 2 secs, but most sensors can return a stable (?) measurement in 200-500 ms typically.
//
//  (Generally, SHT30 and DS18B20 temp sensors perform well and decently fast. DHT11/21/22 are slower 
//  and less reliant in my testes. I dont use them in real life.)
//
//  AUTHOR:
//  Jonas Byström, https://github.com/jonasbystrom
//
//  CREDITS:
//  This code is based on code from:
//  - Anthony Elder @ https://github.com/HarringayMakerSpace/ESP-Now/blob/master/espnow-sensor-bme280/espnow-sensor-bme280.ino
//  With important info from:
//  - Erik Bakke @ https://www.bakke.online/index.php/2017/05/21/reducing-wifi-power-consumption-on-esp8266-part-2/
//  And great info from:
//  - ArduinoDIY @ https://arduinodiy.wordpress.com/2020/01/18/very-deepsleep-and-energy-saving-on-esp8266/

//  HARDWARE:
//  - D1 Mini Pro v2.0 (or, D1 Mini v3.1.0), or
//  - Any ESP32 board
//  - SHT30 or DS18B20 temp sensor
//  - 3.7V LiPo/Li-Ion battery with JST connector. Flat 1200mAh, 18650 2200mAh or similar.
//  - Optional: Solar panel and solar panel charger board
//
//  CONNECTIONS:
//
//  D1 Mini Pro V2.0.0:
//  ===================
//  BAT --- A0          (solder/short the "BAT-A0" pad for battery level measurement)
//  RST --- D0/GPIO16   (solder/short the "SLEEP" pad)
//
//
//  D1 Mini SHT30 (If using WEMOS/LOLIN boards, just plug them together.)
//  ======= =====
//  GND     GND
//  3V3     VCC
//  D1/SCL  SCK
//  D2/SDA  SDA
//
//  or, if using a DS18B20
//
//  D1 Mini - DS18B20 (with an internal resistor)
//  =======   =======
//  GND       G (GND)
//  3V        V (VCC)
//  D3
//  D4        S (DATA)
//
//
//  HISTORY:
//  ========
//  2021-12-30  Cleaned for public publish on GitHub.
//  2021-12-31  Support for ESP32 added.
//

// ------------------------------------------------------------------------------------------
// ESP CONFIGS
// ------------------------------------------------------------------------------------------
//
// IMPORTANT. Select ESP8266 or ESP32. - Remember to also set the appropriate ESP8266 or ESP32 board in the ARDUINO IDE !
#define USE_ESP32               // Select (uncomment) one of ESP8266 or ESP32. (And set BOARD in ARDUINO IDE.) 
//#define USE_ESP8266  
      
// Different Wifi and ESP-Now implementations for ESP8266 and ESP32
#ifdef USE_ESP8266
#include <ESP8266WiFi.h>
#include <espnow.h>
#endif

#ifdef USE_ESP32
#include <WiFi.h>
#include <esp_now.h>
#endif


// ------------------------------------------------------------------------------------------
// ESP-NOW SYSTEM CONFIGS
// ------------------------------------------------------------------------------------------
#define WIFI_CHANNEL        1      // Must be 1. (!IMPORTANT)
                                  // ESP-Now can work on other channels, but the receiving ESP Gateway must operate on
                                  // channel 1 in order to also work for TCP/IP WiFi.
                                  // It has been reported to work also for other Channels, but I have only succeeded on ch 1.

//uint8_t Gateway_Mac[] = {0x02, 0x10, 0x11, 0x12, 0x13, 0x14};
uint8_t Gateway_Mac[] = {0xC8, 0x2B, 0x96, 0xA1, 0x93, 0x78};
                                  // MAC Address of the remote ESP Gateway we send to.
                                  // This is the "system address" all Sensors send to and the Gateway listens on.
                                  // (The ESP Gateway will set this "soft" MAC address in its HW. See Gateway code for info.)

typedef struct sensor_data_t {    // Sensor data format for sending on ESP-Now to Gateway
  int           id;               // Unit no to identy which sensor is sending
  int           on_delay;
  bool          active;
  //char          confg[30]; // Meh
  unsigned long updated;            // Epoch time when received by Gateway. Set by gateway/receiver. (Not used by sensor, but part of struct for convenience reasons.)
} sensor_data_t;


// -----------------------------------------------------------------------------------------
// ESP SENSOR CONFIGS
// -----------------------------------------------------------------------------------------
#define UNIT                1       // Sensor unit ID to identify THIS unit for the receiving gateway. Recommended to use [1 -20]

//#define USE_SHT30                   // Select (uncomment) the temp sensor type in use
//#define USE_DS18B20

#define DEBUG_LOG                   // Enable (uncomment) to print debug info. Disabling (comment) debug output saves some 4-5 ms ...

//ADC_MODE(ADC_VCC);                // Uncomment to Enable reading Vcc (if board cannot read VBAT).

#define SLEEP_SECS        5*60-8    // [sec] Sleep time between wake up and readings. Will be 5 mins +/- 8 secs. Varying to avoid transmit collusions.
#define MAX_WAKETIME_MS   1000      // [ms]  Timeout until forced gotosleep if no sending success 



#ifdef USE_SHT30
// -----------------------------------------------------------------------------------------
//  WEMOS SHT30 Temp and Humidity sensor
// -----------------------------------------------------------------------------------------
#include "Wire.h"
#define ADDR              0x45      // I2C address of SHT30.
#endif


#ifdef USE_DS18B20
// -----------------------------------------------------------------------------------------
// DS18B20 - TEMP SENSOR
// -----------------------------------------------------------------------------------------
// Temp probe is connected with onewire interface.
//
#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into port D3 & D4 on the ESP8266
#define ONE_WIRE_BUS            D4                // Change to other port if wanted/needed
#define TEMPERATURE_PRECISION   12                // [9-12]. 12 => resolution of 0.0625 C
                      /*  12-bit precision:
                          1-bit for sign, 7-bit for integer part, and 4-bit for fractional part (4-digit after decimal point)
                          Temperature range: xxx.0000 C to xxx.9375 C in 0.0625 C discrete step.
                      */        
OneWire oneWire (ONE_WIRE_BUS);                   // Setup a oneWire instance to communicate with any OneWire devices
DallasTemperature tempSensor(&oneWire);           // Pass our oneWire reference to Dallas Temperature.
DeviceAddress tempDeviceAddress;                  // We'll use this variable to store a found device address

#endif


// -----------------------------------------------------------------------------------------
//  BATTERY LEVEL CALIBRATION
// -----------------------------------------------------------------------------------------
#define CALIBRATION         4.21 / 4.35                       // Measured V by multimeter / reported (raw) V 
                                                              // (Set to 1 if no calibration is needed/wanted)
#define VOLTAGE_DIVIDER     (130+220+100)/100 * CALIBRATION   // D1 Mini Pro voltage divider to A0. 
                                                              // May be different for other boards.


// -----------------------------------------------------------------------------------------
// GLOBALS
// -----------------------------------------------------------------------------------------
sensor_data_t sensorData;
volatile boolean messageSent;     // flag to tell when message is sent out and we can safely goto sleep


#ifdef USE_SHT30
// -----------------------------------------------------------------------------------------
byte sht30_get(float &temp, float &humid)
// -----------------------------------------------------------------------------------------
// Read the SHT30 temp/humid sensor.
// Code is from WEMOS_sht3x.cpp - modified by reducing delays and adjusting types.
{
  unsigned int data[6];

  temp = NAN;
  humid = NAN;

  Wire.beginTransmission(ADDR);           // Start I2C Transmission
  Wire.write(0x2C);                       // Send measurement command
  Wire.write(0x06);
  if (Wire.endTransmission() != 0)        // Stop I2C transmission
    return 1;

  delay(100);         // 100 ms sensor stabilization time. Shorter than spec, but works OK.  Can be tweaked if needed.
                      // (I have seen Tasmota code to read SHT30 a bit different and as it seems even faster - would be interesting to try ...)

  Wire.requestFrom(ADDR, 6);              // Read the 6 data bytes
  for (int i = 0; i < 6; i++) {
    data[i] = Wire.read();
  };

  delay(50);                              // Let it stabilize. Can be tweaked
  if (Wire.available() != 0)
    return 2;
  // Convert the data
  temp = ((((data[0] * 256.0) + data[1]) * 175) / 65535.0) - 45;
  //fahrenheit version: temp = (temp * 1.8) + 32;
  humid = ((((data[3] * 256.0) + data[4]) * 100) / 65535.0);

  return 0;
}
#endif


// -----------------------------------------------------------------------------------------
void setup()
// -----------------------------------------------------------------------------------------
{
  // Disable WiFi until we shall use it, to save energy
  WiFi.persistent( false );         // Dont save WiFi info to Flash - to save time
  #ifdef USE_ESP8266
  WiFi.mode( WIFI_OFF );            // Wifi OFF - during sensor reading - to save current/power
  WiFi.forceSleepBegin();
  delay( 1 );                       // Necessary for the OFF to work. (!IMPORTANT)
  #endif
  
  #ifdef USE_SHT30
  Wire.begin();                     // Prepare the I2C communication
  #endif

  #ifdef DEBUG_LOG
  Serial.begin(115200);
  while (!Serial) {};
  Serial.println("\n\nStart");
  #endif

  #ifdef USE_DS18B20
  // Init sensor/bus
  //pinMode(ONE_WIRE_BUS, OUTPUT);     // use this if using PARASITE mode of DS18B20 (vcc from data line, and probably a pull up resistor ...)
  tempSensor.begin();
  tempSensor.getAddress(tempDeviceAddress, 0);
  tempSensor.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION);
  tempSensor.requestTemperatures();
  #endif

  // read battery voltage
  //int raw = analogRead(A0);
  //sensorData.Vbat = raw * VOLTAGE_DIVIDER / 1023.0;
          // Alternative. If cannot read Battery level on your board, Read Vcc instead
          // const float calVal = 0.001108;     // 3.27/2950=0.001108. Vcc 3.27 on Multimeter, 2950 from getVcc()
          // sensorData.Vbat = ESP.getVcc()/1023; // * calVal;
 
  #ifdef DEBUG_LOG
  //Serial.print("Battery voltage:"); Serial.print(sensorData.Vbat); Serial.println(" V");
  #endif

  // compile message to send
  //strcpy (sensorData.ID, SKETCH_NAME);
  //strcat (sensorData.ID, " - ");
  //strcat (sensorData.ID, SKETCH_VERSION);
  sensorData.id = 1;
  //sensorData.unit = UNIT;

  // Read the temp sensor
  #ifdef USE_SHT30
  if (sht30_get(sensorData.temp, sensorData.humidity) == 0) {
    // reading ok   
  } else {
    // SHT30 reading error, use -999 as "invalid data". (Maybe it is better to use NAN instead (?))
    sensorData.temp = -999;
    sensorData.humidity = -999;
  }
  #elif defined USE_DS18B20
  sensorData.temp     = tempSensor.getTempC(tempDeviceAddress);
  #endif

#ifdef USE_8266
  // WiFi ON                    (This step seems not to be necessary, but anyway ...)
  WiFi.forceSleepWake();
  delay( 1 );
#endif

  // Set up ESP-Now link ---------------------------
  WiFi.mode(WIFI_STA);          // Station mode for esp-now sensor node
  WiFi.disconnect();
  #ifdef DEBUG_LOG
  Serial.printf("My HW mac: %s", WiFi.macAddress().c_str());
  Serial.println("");
  Serial.printf("Sending to MAC: %02x:%02x:%02x:%02x:%02x:%02x", Gateway_Mac[0], Gateway_Mac[1], Gateway_Mac[2], Gateway_Mac[3], Gateway_Mac[4], Gateway_Mac[5]);
  Serial.printf(", on channel: %i\n", WIFI_CHANNEL);
  #endif

  // Initialize ESP-now ----------------------------
  if (esp_now_init() != 0) {
    #ifdef DEBUG_LOG
    Serial.println("*** ESP_Now init failed. Going to sleep");
    #endif
    delay(100);
    gotoSleep();
  }

  #ifdef USE_ESP8266
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  esp_now_add_peer(Gateway_Mac, ESP_NOW_ROLE_SLAVE, WIFI_CHANNEL, NULL, 0);
  #endif
  #ifdef USE_ESP32
  esp_now_peer_info_t gateway;
  memcpy(gateway.peer_addr, Gateway_Mac, 6);
  gateway.channel = WIFI_CHANNEL;
  gateway.encrypt = false;            // no encryption
  //esp_now_add_peer(&gateway);  
  if (esp_now_add_peer(&gateway) != ESP_OK) {
    Serial.println("Failed to add peer");
    return;
  } else {
    Serial.println("Added peer");
  }
  #endif

  #ifdef USE_ESP8266
  esp_now_register_send_cb([](uint8_t* mac, uint8_t sendStatus) {
  #endif
  #ifdef USE_ESP32
  esp_now_register_send_cb([](const uint8_t* mac, esp_now_send_status_t sendStatus) {
  #endif
    // callback for message sent out
    messageSent = true;         // flag message is sent out - we can now safely go to sleep ...
    #ifdef DEBUG_LOG
    Serial.printf("Message sent out, sendStatus = %i\n", sendStatus);
    #endif
  });

  messageSent = false;
  sensorData.id = 1;
  sensorData.on_delay = 12;
  sensorData.active = false;
  sensorData.updated = 16151;
  // Send message -----------------------------------
  #ifdef DEBUG_LOG
  Serial.println("Message Data: " + \
                  String(sensorData.id));// + ", Unit:" + \
                  //String(sensorData.unit) + ", Temp:" + \
                  //String(sensorData.temp) + "C, Hum: " + \
                  //String(sensorData.humidity) + "%, Lux: " + \
                  //String(sensorData.lux) + ", Vbat:" + \
                  //String(sensorData.Vbat) \
                );
  #endif
  
  uint8_t sendBuf[sizeof(sensorData)];          // create a send buffer for sending sensor data (safer)
  //sensorData.wakeTimeMS = millis();             // set wake time until now
  memcpy(sendBuf, &sensorData, sizeof(sensorData));
  #ifdef USE_ESP8266
  uint16_t result = esp_now_send(NULL, sendBuf, sizeof(sensorData));
  #endif
  #ifdef USE_ESP32
  const uint8_t *peer_addr = gateway.peer_addr;
  esp_err_t result=esp_now_send(peer_addr, (uint8_t *) &sensorData, sizeof(sensorData)); 
  #endif
  
  #ifdef DEBUG_LOG
  //Serial.print("Wake: "); Serial.print(sensorData.wakeTimeMS); Serial.println(" ms");
  Serial.print("Sending result: "); Serial.println(result);
  #endif
}

// -----------------------------------------------------------------------------------------
void loop()
// -----------------------------------------------------------------------------------------
{
  // Wait until ESP-Now message is sent, or timeout, then goto sleep
  if (messageSent || (millis() > MAX_WAKETIME_MS)) {
    //gotoSleep();
  }
}


// -----------------------------------------------------------------------------------------
void gotoSleep()
// -----------------------------------------------------------------------------------------
{
  int sleepSecs;

  #ifdef USE_ESP8266
  sleepSecs = SLEEP_SECS + ((uint8_t)RANDOM_REG32 / 16);  // add random time to avoid traffic jam collisions
  #ifdef DEBUG_LOG
  Serial.printf("Up for %i ms, going to deep sleep for %i secs ...\n", millis(), sleepSecs);
  #endif

  ESP.deepSleep(sleepSecs * 1000000, RF_NO_CAL);
  delay (10);                                             // good convention with delay after call to deep sleep.

  // Never return here - ESP will be reset after deep sleep
  #endif

  #ifdef USE_ESP32
  sleepSecs = SLEEP_SECS + ((uint8_t)esp_random()/16);      // add random time to avoid traffic jam collisions
  #ifdef DEBUG_SENSOR      
    Serial.printf("Up for %i ms, going to sleep for %i secs...\n", millis(), sleepSecs); 
  #endif

  esp_sleep_enable_timer_wakeup(sleepSecs * 1000000);
  //esp_sleep_enable_ext0_wakeup((gpio_num_t)BUTTON_PIN, LOW);
  esp_deep_sleep_start(); 

  // Never return here - ESP will be reset after deep sleep  
  #endif
}

The code complies and uploads, but the serial output shows :
15:43:53.886 -> Sending to MAC: c8:2b:96:a1:93:78, on channel: 1 15:43:53.886 -> E (156) ESPNOW: Peer interface is invalid 15:43:53.886 -> Failed to add peer
"Failed to add peer" was added by me to check response code of esp_now_add_peer(&gateway)

ANy help would be greatly appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant