ESPNOW and Lora


(Sveinutne) #1

I pland to have esp32 with several sensors in my sailboat, and send the data by Lora to TTN and Cayenne. To get better reach I was planing to have the sensors and the esp32 in the bottom of the boat, and a second esp32 with Lora in the mast. The two esp32 connect with ESPNOW. I got three programs that is working. The first is reading the sensors, the second is sending and receiving data between two esp32, and the tird is talking to TTN with Lora. When I tried to murge the three programs into two, I got the sensor and ESPNOW to work, but the one with Lora and ESPNOW is not working right. I put in a lot of debugging lines, but it will not connect to TTN. I will uploade the code, and hope some experts can find the bug.


(Sveinutne) #2
[details]
/**This part got ESPNOW and Lora communication
   ESPNOW - Basic communication - Master
   Date: 26th September 2017
   Author: Arvind Ravulavaru <https://github.com/arvindr21>
   Purpose: ESPNow Communication between a Master ESP32 and multiple ESP32 Slaves
   Description: This sketch consists of the code for the Master module.
   Resources: (A bit outdated)
   a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf
   b. http://www.esploradores.com/practica-6-conexion-esp-now/

   << This Device Master >>

   Flow: Master
   Step 1 : ESPNow Init on Master and set it in STA mode
   Step 2 : Start scanning for Slave ESP32 (we have added a prefix of `slave` to the SSID of slave for an easy setup)
   Step 3 : Once found, add Slave as peer
   Step 4 : Register for send callback
   Step 5 : Start Transmitting data from Master to Slave(s)

   Flow: Slave
   Step 1 : ESPNow Init on Slave
   Step 2 : Update the SSID of Slave with a prefix of `slave`
   Step 3 : Set Slave in AP mode
   Step 4 : Register for receive callback and wait for data
   Step 5 : Once data arrives, print it in the serial monitor

   Note: Master and Slave have been defined to easily understand the setup.
         Based on the ESPNOW API, there is no concept of Master and Slave.
         Any devices can act as master or salve.


  // Sample Serial log with 1 master & 2 slaves
      Found 12 devices 
      1: Slave:24:0A:C4:81:CF:A4 [24:0A:C4:81:CF:A5] (-44)
      3: Slave:30:AE:A4:02:6D:CC [30:AE:A4:02:6D:CD] (-55)
      2 Slave(s) found, processing..
      Processing: 24:A:C4:81:CF:A5 Status: Already Paired
      Processing: 30:AE:A4:2:6D:CD Status: Already Paired
      Sending: 9
      Send Status: Success
      Last Packet Sent to: 24:0a:c4:81:cf:a5
      Last Packet Send Status: Delivery Success
      Send Status: Success
      Last Packet Sent to: 30:ae:a4:02:6d:cd
      Last Packet Send Status: Delivery Success

*/
[/details]
[details]
#include <esp_now.h>
#include <WiFi.h>
//TTGO first
#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include <U8x8lib.h>

#define LED_PIN 2

// Global copy of slave
#define NUMSLAVES 20
esp_now_peer_info_t slaves[NUMSLAVES] = {};
int SlaveCnt = 0;

#define CHANNEL_MASTER 3
#define CHANNEL_SLAVE 1
#define PRINTSCANRESULTS 0
#define DATASIZE 48
#include <CayenneLPP.h>

#define BUILTIN_LED 25
CayenneLPP lpp(51);
uint8_t key[] = {0x63, 0x63, 0x07, 0xA6};
#define timeSeconds 50

// the OLED used
//U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/ 15, /* data=*/ 4, /* reset=*/ 16); //org

U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/ 22, /* data=*/ 21, /* reset=*/ 16); 
static const u1_t PROGMEM APPEUI[8] = { 0x6B, 0x08, 0x01, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };
void os_getArtEui (u1_t* buf) {
  memcpy_P(buf, APPEUI, 8);
}

// This should also be in little endian format, see above.
static const u1_t PROGMEM DEVEUI[8] = { 0xFF, 0x........ };
void os_getDevEui (u1_t* buf) {
  memcpy_P(buf, DEVEUI, 8);
}

// This key should be in big endian format (or, since it is not really a
// number but a block of memory, endianness does not really apply). In
// practice, a key taken from ttnctl can be copied as-is.


static const u1_t PROGMEM APPKEY[16] = { 0xD2........ };
void os_getDevKey (u1_t* buf) {
  memcpy_P(buf, APPKEY, 16);
}
[/details]
[details]
// Timer: Auxiliary variables
unsigned long now = millis();
unsigned long lastSend = 0;
boolean startSend = false;

// Send byte buffer
static const uint8_t size = 50;
uint8_t data[DATASIZE];
uint64_t pos=0;
uint8_t mydata[size];
uint8_t Lora_data[size]= {0x01, 0x67, 0x00,0xF3,0x02, 0x68, 0x37, 0x03, 0x67, 0x02, 0xF5, 0x04, 0x67, 0x00, 0x49};
uint8_t cursor = 0;
int16_t help;
 // Send byte buffer
byte buff[size];
static osjob_t sendjob;

// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = 120;

// Pin mapping
const lmic_pinmap lmic_pins = {
  .nss = 18,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = 12,
  .dio = {26, 33, 32},
};

[/details]
[details]
void onEvent (ev_t ev) {
  Serial.print(os_getTime());
  u8x8.setCursor(0, 5);
  u8x8.printf("TIME %lu", os_getTime());
  Serial.print(": ");
  u8x8.clearLine(7);
  switch (ev) {
case EV_SCAN_TIMEOUT:
  Serial.println(F("EV_SCAN_TIMEOUT"));
  u8x8.drawString(0, 7, "EV_SCAN_TIMEOUT");
  break;
case EV_BEACON_FOUND:
  Serial.println(F("EV_BEACON_FOUND"));
  u8x8.drawString(0, 7, "EV_BEACON_FOUND");
  break;
case EV_BEACON_MISSED:
  Serial.println(F("EV_BEACON_MISSED"));
  u8x8.drawString(0, 7, "EV_BEACON_MISSED");
  break;
case EV_BEACON_TRACKED:
  Serial.println(F("EV_BEACON_TRACKED"));
  u8x8.drawString(0, 7, "EV_BEACON_TRACKED");
  break;
case EV_JOINING:
  Serial.println(F("EV_JOINING"));
  u8x8.drawString(0, 7, "EV_JOINING");
  break;
case EV_JOINED:
  Serial.println(F("EV_JOINED"));
  u8x8.drawString(0, 7, "EV_JOINED ");

  // Disable link check validation (automatically enabled
  // during join, but not supported by TTN at this time).
  LMIC_setLinkCheckMode(0);
  break;
case EV_RFU1:
  Serial.println(F("EV_RFU1"));
  u8x8.drawString(0, 7, "EV_RFUI");
  break;
case EV_JOIN_FAILED:
  Serial.println(F("EV_JOIN_FAILED"));
  u8x8.drawString(0, 7, "EV_JOIN_FAILED");
  break;
case EV_REJOIN_FAILED:
  Serial.println(F("EV_REJOIN_FAILED"));
  u8x8.drawString(0, 7, "EV_REJOIN_FAILED");
  //break;
  break;
case EV_TXCOMPLETE:
  Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
  u8x8.drawString(0, 7, "EV_TXCOMPLETE");
  digitalWrite(BUILTIN_LED, LOW);
  if (LMIC.txrxFlags & TXRX_ACK) {
    Serial.println(F("Received ack"));
    u8x8.drawString(0, 7, "Received ACK");
  }
[/details]
[details]
  if (LMIC.dataLen) {
    Serial.println(F("Received "));
    u8x8.drawString(0, 6, "RX ");
    Serial.println(LMIC.dataLen);
    u8x8.setCursor(4, 6);
    u8x8.printf("%i bytes", LMIC.dataLen);
    Serial.println(F(" bytes of payload"));
    u8x8.setCursor(0, 7);
    u8x8.printf("RSSI %d SNR %.1d", LMIC.rssi, LMIC.snr);
  }
  // Schedule next transmission
  os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
  break;
case EV_LOST_TSYNC:
  Serial.println(F("EV_LOST_TSYNC"));
  u8x8.drawString(0, 7, "EV_LOST_TSYNC");
  break;
case EV_RESET:
  Serial.println(F("EV_RESET"));
  u8x8.drawString(0, 7, "EV_RESET");
  break;
case EV_RXCOMPLETE:
  // data received in ping slot
  Serial.println(F("EV_RXCOMPLETE"));
  u8x8.drawString(0, 7, "EV_RXCOMPLETE");
  break;
case EV_LINK_DEAD:
  Serial.println(F("EV_LINK_DEAD"));
  u8x8.drawString(0, 7, "EV_LINK_DEAD");
  break;
case EV_LINK_ALIVE:
  Serial.println(F("EV_LINK_ALIVE"));
  u8x8.drawString(0, 7, "EV_LINK_ALIVE");
  break;
default:
  Serial.println(F("Unknown event"));
  u8x8.setCursor(0, 7);
  u8x8.printf("UNKNOWN EVENT %d", ev);
  break;
  }
}
[/details]
[details]
void do_send(osjob_t* j) {
  // Check if there is not a current TX/RX job running
  if (LMIC.opmode & OP_TXRXPEND) {
    Serial.println(F("OP_TXRXPEND, not sending"));
    u8x8.drawString(0, 7, "OP_TXRXPEND, not sent");
  } else {
  // Prepare upstream data transmission at the next possible time.
   // make_buff_Lora();
  //LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 0);
    Serial.print("Nå kommer Lora melding!: ");
    PrintHex8(Lora_data,15);
    Serial.println("");
    LMIC_setTxData2(1, Lora_data, 15, 0);
    Serial.println(F("Packet queued"));
    u8x8.drawString(0, 7, "PACKET QUEUED");
    digitalWrite(BUILTIN_LED, HIGH);
  }
  // Next TX is scheduled after TX_COMPLETE event.
}
[/details]
[details]
void PrintHex8(uint8_t *data, uint8_t length) // prints 8-bit data in hex with leading zeroes
{
       Serial.print("0x");
       for (int i=0; i<length; i++) {
         if (data[i]<0x10) {Serial.print("0");}
         Serial.print(data[i],HEX);
         Serial.print(" ");
       }
}
// Init ESP Now with fallback
void InitESPNow() {
  if (esp_now_init() == ESP_OK) {
    Serial.println("ESPNow Init Success");
  }
  else {
    Serial.println("ESPNow Init Failed");
    // Retry InitESPNow, add a counte and then restart?
    // InitESPNow();
    // or Simply Restart
    ESP.restart();
  }
}

// Scan for slaves in AP mode
void ScanForSlave() {
  int8_t scanResults = WiFi.scanNetworks();
  //reset slaves
  memset(slaves, 0, sizeof(slaves));
  SlaveCnt = 0;
  Serial.println("");
  if (scanResults == 0) {
    Serial.println("No WiFi devices in AP Mode found");
  } else {
    Serial.print("Found "); Serial.print(scanResults); Serial.println(" devices ");
    for (int i = 0; i < scanResults; ++i) {
      // Print SSID and RSSI for each device found
      String SSID = WiFi.SSID(i);
      int32_t RSSI = WiFi.RSSI(i);
      String BSSIDstr = WiFi.BSSIDstr(i);

      if (PRINTSCANRESULTS) {
        Serial.print(i + 1); Serial.print(": "); Serial.print(SSID); Serial.print(" ["); Serial.print(BSSIDstr); Serial.print("]"); Serial.print(" ("); Serial.print(RSSI); Serial.print(")"); Serial.println("");
      }
      delay(10);
      // Check if the current device starts with `Slave`
      if (SSID.indexOf("ESPNOW") == 0) {
        // SSID of interest
        Serial.print(i + 1); Serial.print(": "); Serial.print(SSID); Serial.print(" ["); Serial.print(BSSIDstr); Serial.print("]"); Serial.print(" ("); Serial.print(RSSI); Serial.print(")"); Serial.println("");
        // Get BSSID => Mac Address of the Slave
        int mac[6];

        if ( 6 == sscanf(BSSIDstr.c_str(), "%02x:%02x:%02x:%02x:%02x:%02x",  &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5] ) ) {
          for (int ii = 0; ii < 6; ++ii ) {
            slaves[SlaveCnt].peer_addr[ii] = (uint8_t) mac[ii];
          }
        }
        slaves[SlaveCnt].channel = CHANNEL_MASTER; // pick a channel
        slaves[SlaveCnt].encrypt = 0; // no encryption
        SlaveCnt++;
      }
    }
  }

  if (SlaveCnt > 0) {
    Serial.print(SlaveCnt); Serial.println(" Slave(s) found, processing..");
  } else {
    Serial.println("No Slave Found, trying again.");
  }

  // clean up ram
  WiFi.scanDelete();
}
[/details]
[details]
// Check if the slave is already paired with the master.
// If not, pair the slave with master
void manageSlave() {
  if (SlaveCnt > 0) {
    for (int i = 0; i < SlaveCnt; i++) {
      const esp_now_peer_info_t *peer = &slaves[i];
      const uint8_t *peer_addr = slaves[i].peer_addr;
      Serial.print("Processing: ");
      for (int ii = 0; ii < 6; ++ii ) {
        Serial.print((uint8_t) slaves[i].peer_addr[ii], HEX);
        if (ii != 5) Serial.print(":");
      }
      Serial.print(" Status: ");
      // check if the peer exists
      bool exists = esp_now_is_peer_exist(peer_addr);
      if (exists) {
        // Slave already paired.
        Serial.println("Already Paired");
      } else {
        // Slave not paired, attempt pair
        esp_err_t addStatus = esp_now_add_peer(peer);
        if (addStatus == ESP_OK) {
          // Pair success
          Serial.println("Pair success");
        } else if (addStatus == ESP_ERR_ESPNOW_NOT_INIT) {
          // How did we get so far!!
          Serial.println("ESPNOW Not Init");
        } else if (addStatus == ESP_ERR_ESPNOW_ARG) {
          Serial.println("Add Peer - Invalid Argument");
        } else if (addStatus == ESP_ERR_ESPNOW_FULL) {
          Serial.println("Peer list full");
        } else if (addStatus == ESP_ERR_ESPNOW_NO_MEM) {
          Serial.println("Out of memory");
        } else if (addStatus == ESP_ERR_ESPNOW_EXIST) {
          Serial.println("Peer Exists");
        } else {
          Serial.println("Not sure what happened");
        }
        delay(100);
      }
    }
  } else {
    // No slave found to process
    Serial.println("No Slave found to process");
  }
}
[/details]
[details]
void sendData() {
  //sprintf((char *)data,"espnow %lld",pos);
  //data = {0x03, 0x67, 0x01,0x10,0x05, 0x67, 0x00, 0xFF, 0x00};
  for (int i = 0; i < SlaveCnt; i++) {
    const uint8_t *peer_addr = slaves[i].peer_addr;
    if (i == 0) { // print only for first slave
      Serial.print("Sending: ");
      PrintHex8(mydata,19);
      Serial.println("");
    }
    esp_err_t result = esp_now_send(peer_addr, mydata, DATASIZE);
    Serial.print("Send Status: ");
    if (result == ESP_OK) {
      Serial.println("Success");
    } else if (result == ESP_ERR_ESPNOW_NOT_INIT) {
      // How did we get so far!!
      Serial.println("ESPNOW not Init.");
    } else if (result == ESP_ERR_ESPNOW_ARG) {
      Serial.println("Invalid Argument");
    } else if (result == ESP_ERR_ESPNOW_INTERNAL) {
      Serial.println("Internal Error");
    } else if (result == ESP_ERR_ESPNOW_NO_MEM) {
      Serial.println("ESP_ERR_ESPNOW_NO_MEM");
    } else if (result == ESP_ERR_ESPNOW_NOT_FOUND) {
      Serial.println("Peer not found.");
    } else {
      Serial.println("Not sure what happened");
    }
    delay(100);
  }
}
[/details]
void SendDataIfTime(){
  Serial.println("Is it time to send data?");
  if(millis() - lastSend > (timeSeconds*1000)) {
    Serial.println("Time to send data...");
    make_buff();
    sendData();
    lastSend = millis();
  }
}


void make_buff() {
  uint8_t *lpp_buff;
  uint8_t lpp_cursor;
  lpp.reset();
  lpp.addTemperature(4,7.3);
  lpp_buff = lpp.getBuffer();
  lpp_cursor = lpp.getSize();
  lpp_buff[lpp_cursor++] = key[0];
  lpp_buff[lpp_cursor++] = key[1];
  lpp_buff[lpp_cursor++] = key[2];
  lpp_buff[lpp_cursor++] = key[3];
  memcpy_P(mydata,lpp.getBuffer(), lpp.getSize()+4);
}

[details]
// callback when data is sent from Master to Slave
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  char macStr[18];
  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.print("Last Packet Sent to: "); Serial.println(macStr);
  Serial.print("Last Packet Send Status: "); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

// callback when data is recv from Master
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) {
  uint8_t pos=0;
  char macStr[18];
  digitalWrite(LED_PIN, 1);
  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.print("\t\tLast Packet Recv from: "); Serial.println(macStr);
  Serial.print("\t\tLast Packet Recv Data: "); 
  for(pos=0;pos<data_len;pos++){
    if(data[pos] == key[0]){
      if(data[pos+1] == key[1] && data[pos+2] == key[2]&& data[pos+3] == key[3]){
        PrintHex8((uint8_t *)data,pos);
        Serial.println("");
          // Start job (sending automatically starts OTAA too)
          memcpy_P(Lora_data,data, pos);
          memcpy_P(mydata,data, pos);
          do_send(&sendjob); //Send with Lora
      }
    }
  }
}
[/details]

// config AP SSID
void configDeviceAP() {
  String Prefix = "ESPNOW:";
  String Mac = WiFi.macAddress();
  String SSID = Prefix + Mac;
  String Password = "123456789";
  bool result = WiFi.softAP(SSID.c_str(), Password.c_str(), CHANNEL_SLAVE, 0);
  if (!result) {
    Serial.println("AP Config failed.");
  } else {
    Serial.println("AP Config Success. Broadcasting with AP: " + String(SSID));
  }
}

void setup() {
  Serial.begin(115200);

  u8x8.begin();
  u8x8.setFont(u8x8_font_chroma48medium8_r);
  u8x8.drawString(0, 1, "LoRaWAN LMiC");

  SPI.begin(5, 19, 27);

  // LMIC init
  os_init();
  // Reset the MAC state. Session and pending data transfers will be discarded.
  LMIC_reset();
  // This tells LMIC to make the receive windows bigger, in case your clock is 1% faster or slower.
  LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);

  // Start job (sending automatically starts OTAA too)
  do_send(&sendjob);

  pinMode(LED_PIN, OUTPUT);
  //Set device in STA mode to begin with
  WiFi.mode(WIFI_MODE_APSTA);
  Serial.println("ESPNow/Multi-Slave/Master Example");
  // configure device AP mode
  configDeviceAP();
  // This is the mac address of the Master in Station Mode
  Serial.print("STA MAC: "); Serial.println(WiFi.macAddress());
  Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
  // Init ESPNow with a fallback logic
  InitESPNow();
  // Once ESPNow is successfully Init, we will register for Send CB to
  // get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);
  esp_now_register_recv_cb(OnDataRecv);
}

void loop() {
  // In the loop we scan for slave
  ScanForSlave();
  // If Slave is found, it would be populate in `slave` variable
  // We will check if `slave` is defined and then we proceed further
  if (SlaveCnt > 0) { // check if slave channel is defined
    // `slave` is defined
    // Add slave as peer if it has not been added already
    manageSlave();
    // pair success or already paired
    // Send data to device
    SendDataIfTime();

  } else {
    // No slave found to process
  }
  os_runloop_once(); 
}

(Sveinutne) #3

This is sensor part, and it is working OK
ESPNOW - Basic communication - Master
Date: 26th September 2017
Author: Arvind Ravulavaru https://github.com/arvindr21
Purpose: ESPNow Communication between a Master ESP32 and multiple ESP32 Slaves

/**
Purpose: ESPNow Communication between a Master ESP32 and multiple ESP32 Slaves
Description: This sketch consists of the code for the Master module.
Resources: (A bit outdated)
a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf
b. http://www.esploradores.com/practica-6-conexion-esp-now/

<< This Device Master >>

Flow: Master
Step 1 : ESPNow Init on Master and set it in STA mode
Step 2 : Start scanning for Slave ESP32 (we have added a prefix of slave to the SSID of slave for an easy setup)
Step 3 : Once found, add Slave as peer
Step 4 : Register for send callback
Step 5 : Start Transmitting data from Master to Slave(s)

Flow: Slave
Step 1 : ESPNow Init on Slave
Step 2 : Update the SSID of Slave with a prefix of slave
Step 3 : Set Slave in AP mode
Step 4 : Register for receive callback and wait for data
Step 5 : Once data arrives, print it in the serial monitor

Note: Master and Slave have been defined to easily understand the setup.
Based on the ESPNOW API, there is no concept of Master and Slave.
Any devices can act as master or salve.

// Sample Serial log with 1 master & 2 slaves
Found 12 devices
1: Slave:24:0A:C4:81:CF:A4 [24:0A:C4:81:CF:A5] (-44)
3: Slave:30:AE:A4:02:6D:CC [30:AE:A4:02:6D:CD] (-55)
2 Slave(s) found, processing…
Processing: 24:A:C4:81:CF:A5 Status: Already Paired
Processing: 30:AE:A4:2:6D:CD Status: Already Paired
Sending: 9
Send Status: Success
Last Packet Sent to: 24:0a:c4:81:cf:a5
Last Packet Send Status: Delivery Success
Send Status: Success
Last Packet Sent to: 30:ae:a4:02:6d:cd
Last Packet Send Status: Delivery Success

*/

Click to see the code
#include <esp_now.h>
#include <WiFi.h>
#include <EEPROM.h>

#include <Adafruit_Sensor.h>
#include <DHT.h>
#define LED_PIN 2
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321

// DHT Sensor
const int DHTPin = 27;
// Initialize DHT sensor.
DHT dht(DHTPin, DHTTYPE);
float h, t, f;  // h=humidity, t= tempcelsius, f=tempfahrenheit


// EEPROM size
// Address 0: Last output state (0 = off or 1 = on)
// Address 1: Selected mode (0 = Manual, 1 = Auto PIR,
// 2 = Auto LDR, or 3 = Auto PIR and LDR)
// Address 2: Timer (time 0 to 255 seconds)
// Address 3: LDR threshold value (luminosity in percentage 0 to 100%)
#define EEPROM_SIZE 4

// Set GPIOs for: output variable, RGB LED, PIR Motion Sensor, and LDR
const int output = 2;
const int redRGB = 14;
const int greenRGB = 12;
const int blueRGB = 13;
const int motionSensor = 25;
const int ldr = 33;
// Global copy of slave
#define NUMSLAVES 20
esp_now_peer_info_t slaves[NUMSLAVES] = {};
int SlaveCnt = 0;

#define CHANNEL_MASTER 3
#define CHANNEL_SLAVE 1
#define PRINTSCANRESULTS 0
#include <CayenneLPP.h>

#define BUILTIN_LED 25
CayenneLPP lpp(51);
uint8_t key[] = {0x63, 0x63, 0x07, 0xA6};
#define timeSeconds 60
#define DATASIZE 48
// Timer: Auxiliary variables
unsigned long now = millis();
unsigned long lastSend = 0;
boolean startSend = false;

// Send byte buffer
static const uint8_t size = 50;
byte buff[size];
uint8_t mydata[size];
uint8_t data[DATASIZE];
uint64_t pos=0;


void PrintHex8(uint8_t *data, uint8_t length) // prints 8-bit data in hex with leading zeroes
{
       Serial.print("0x");
       for (int i=0; i<length; i++) {
         if (data[i]<0x10) {Serial.print("0");}
         Serial.print(data[i],HEX);
         Serial.print(" ");
       }
}
// Init ESP Now with fallback
void InitESPNow() {
  if (esp_now_init() == ESP_OK) {
    Serial.println("ESPNow Init Success");
  }
  else {
    Serial.println("ESPNow Init Failed");
    // Retry InitESPNow, add a counte and then restart?
    // InitESPNow();
    // or Simply Restart
    ESP.restart();
  }
}

// Scan for slaves in AP mode
void ScanForSlave() {
  int8_t scanResults = WiFi.scanNetworks();
  //reset slaves
  memset(slaves, 0, sizeof(slaves));
  SlaveCnt = 0;
  Serial.println("");
  if (scanResults == 0) {
    Serial.println("No WiFi devices in AP Mode found");
  } else {
    Serial.print("Found "); Serial.print(scanResults); Serial.println(" devices ");
    for (int i = 0; i < scanResults; ++i) {
      // Print SSID and RSSI for each device found
      String SSID = WiFi.SSID(i);
      int32_t RSSI = WiFi.RSSI(i);
      String BSSIDstr = WiFi.BSSIDstr(i);

      if (PRINTSCANRESULTS) {
        Serial.print(i + 1); Serial.print(": "); Serial.print(SSID); Serial.print(" ["); Serial.print(BSSIDstr); Serial.print("]"); Serial.print(" ("); Serial.print(RSSI); Serial.print(")"); Serial.println("");
      }
      delay(10);
      // Check if the current device starts with `Slave`
      if (SSID.indexOf("ESPNOW") == 0) {
        // SSID of interest
        Serial.print(i + 1); Serial.print(": "); Serial.print(SSID); Serial.print(" ["); Serial.print(BSSIDstr); Serial.print("]"); Serial.print(" ("); Serial.print(RSSI); Serial.print(")"); Serial.println("");
        // Get BSSID => Mac Address of the Slave
        int mac[6];

        if ( 6 == sscanf(BSSIDstr.c_str(), "%02x:%02x:%02x:%02x:%02x:%02x",  &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5] ) ) {
          for (int ii = 0; ii < 6; ++ii ) {
            slaves[SlaveCnt].peer_addr[ii] = (uint8_t) mac[ii];
          }
        }
        slaves[SlaveCnt].channel = CHANNEL_MASTER; // pick a channel
        slaves[SlaveCnt].encrypt = 0; // no encryption
        SlaveCnt++;
      }
    }
  }

  if (SlaveCnt > 0) {
    Serial.print(SlaveCnt); Serial.println(" Slave(s) found, processing..");
  } else {
    Serial.println("No Slave Found, trying again.");
  }

  // clean up ram
  WiFi.scanDelete();
}

// Check if the slave is already paired with the master.
// If not, pair the slave with master
void manageSlave() {
  if (SlaveCnt > 0) {
    for (int i = 0; i < SlaveCnt; i++) {
      const esp_now_peer_info_t *peer = &slaves[i];
      const uint8_t *peer_addr = slaves[i].peer_addr;
      Serial.print("Processing: ");
      for (int ii = 0; ii < 6; ++ii ) {
        Serial.print((uint8_t) slaves[i].peer_addr[ii], HEX);
        if (ii != 5) Serial.print(":");
      }
      Serial.print(" Status: ");
      // check if the peer exists
      bool exists = esp_now_is_peer_exist(peer_addr);
      if (exists) {
        // Slave already paired.
        Serial.println("Already Paired");
      } else {
        // Slave not paired, attempt pair
        esp_err_t addStatus = esp_now_add_peer(peer);
        if (addStatus == ESP_OK) {
          // Pair success
          Serial.println("Pair success");
        } else if (addStatus == ESP_ERR_ESPNOW_NOT_INIT) {
          // How did we get so far!!
          Serial.println("ESPNOW Not Init");
        } else if (addStatus == ESP_ERR_ESPNOW_ARG) {
          Serial.println("Add Peer - Invalid Argument");
        } else if (addStatus == ESP_ERR_ESPNOW_FULL) {
          Serial.println("Peer list full");
        } else if (addStatus == ESP_ERR_ESPNOW_NO_MEM) {
          Serial.println("Out of memory");
        } else if (addStatus == ESP_ERR_ESPNOW_EXIST) {
          Serial.println("Peer Exists");
        } else {
          Serial.println("Not sure what happened");
        }
        delay(100);
      }
    }
  } else {
    // No slave found to process
    Serial.println("No Slave found to process");
  }
}



uint8_t data2[] = {0x03, 0x67, 0x01,0x10,0x05, 0x67, 0x00, 0xFF, 0x00};
// send data
void sendData() {
  pos++;
  //sprintf((char *)data,"espnow %lld",pos);
 //data = {0x03, 0x67, 0x01,0x10,0x05, 0x67, 0x00, 0xFF, 0x00};
  for (int i = 0; i < SlaveCnt; i++) {
    const uint8_t *peer_addr = slaves[i].peer_addr;
    if (i == 0) { // print only for first slave
      Serial.print("Sending: ");
      PrintHex8(mydata,19);
      Serial.println("");
    }
    esp_err_t result = esp_now_send(peer_addr, mydata, DATASIZE);
    Serial.print("Send Status: ");
    if (result == ESP_OK) {
      Serial.println("Success");
    } else if (result == ESP_ERR_ESPNOW_NOT_INIT) {
      // How did we get so far!!
      Serial.println("ESPNOW not Init.");
    } else if (result == ESP_ERR_ESPNOW_ARG) {
      Serial.println("Invalid Argument");
    } else if (result == ESP_ERR_ESPNOW_INTERNAL) {
      Serial.println("Internal Error");
    } else if (result == ESP_ERR_ESPNOW_NO_MEM) {
      Serial.println("ESP_ERR_ESPNOW_NO_MEM");
    } else if (result == ESP_ERR_ESPNOW_NOT_FOUND) {
      Serial.println("Peer not found.");
    } else {
      Serial.println("Not sure what happened");
    }
    delay(100);
  }
}

void SendDataIfTime(){
  Serial.println("Is it time to send data?");
  if(millis() - lastSend > (timeSeconds*1000)) {
    Serial.println("Time to send data...");
    make_buff();
    sendData();
    lastSend = millis();
  }
}

void make_buff() {
  uint8_t *lpp_buff;
  uint8_t lpp_cursor;
  lpp.reset();
  sensor_dht();
  lpp.addTemperature(1, t);
  lpp.addRelativeHumidity(2, h);
  lpp.addTemperature(3, f);
  lpp.addTemperature(4,7.3);
  lpp_buff = lpp.getBuffer();
  lpp_cursor = lpp.getSize();
  lpp_buff[lpp_cursor++] = key[0];
  lpp_buff[lpp_cursor++] = key[1];
  lpp_buff[lpp_cursor++] = key[2];
  lpp_buff[lpp_cursor++] = key[3];
  memcpy_P(mydata,lpp.getBuffer(), lpp.getSize()+4);
}

// callback when data is sent from Master to Slave
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  char macStr[18];
  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.print("Last Packet Sent to: "); Serial.println(macStr);
  Serial.print("Last Packet Send Status: "); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

// callback when data is recv from Master
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) {
  uint8_t pos=0;
  char macStr[18];
  digitalWrite(LED_PIN, 1);
  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.print("\t\tLast Packet Recv from: "); Serial.println(macStr);
  Serial.print("\t\tLast Packet Recv Data: "); 
  for(pos=0;pos<data_len;pos++){
    if(data[pos] == key[0]){
      if(data[pos+1] == key[1] && data[pos+2] == key[2]&& data[pos+3] == key[3]){
        PrintHex8((uint8_t *)data,pos);
        Serial.println("");
      }
    }
  }
  delay(10); // just a little bit
  digitalWrite(LED_PIN, 0);
}


// config AP SSID
void configDeviceAP() {
  String Prefix = "ESPNOW:";
  String Mac = WiFi.macAddress();
  String SSID = Prefix + Mac;
  String Password = "123456789";
  bool result = WiFi.softAP(SSID.c_str(), Password.c_str(), CHANNEL_SLAVE, 0);
  if (!result) {
    Serial.println("AP Config failed.");
  } else {
    Serial.println("AP Config Success. Broadcasting with AP: " + String(SSID));
  }
}

void setup() {
  // initialize the DHT sensor
  dht.begin();

  // Serial port for debugging purposes
  Serial.begin(115200);

  pinMode(LED_PIN, OUTPUT);
  //Set device in STA mode to begin with
  WiFi.mode(WIFI_MODE_APSTA);
  Serial.println("ESPNow/Multi-Slave/Master Example");
  // configure device AP mode
  configDeviceAP();
  // This is the mac address of the Master in Station Mode
  Serial.print("STA MAC: "); Serial.println(WiFi.macAddress());
  Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
  // Init ESPNow with a fallback logic
  InitESPNow();
  // Once ESPNow is successfully Init, we will register for Send CB to
  // get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);
  esp_now_register_recv_cb(OnDataRecv);
} 

void sensor_dht(){
    // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
    h = dht.readHumidity();
    // Read temperature as Celsius (the default)
    t = dht.readTemperature();
    // Read temperature as Fahrenheit (isFahrenheit = true)
    f = dht.readTemperature(true);
    // Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(t) || isnan(f)) {
      Serial.println("Failed to read from DHT sensor!");
    }
}            


void loop() {
  // In the loop we scan for slave
  ScanForSlave();
  // If Slave is found, it would be populate in `slave` variable
  // We will check if `slave` is defined and then we proceed further
  if (SlaveCnt > 0) { // check if slave channel is defined
    // `slave` is defined
    // Add slave as peer if it has not been added already
    manageSlave();
    // pair success or already paired
    // Send data to device

    SendDataIfTime();
  } else {
    // No slave found to process
  }

  // wait for 3seconds to run the logic again
  delay(2000);
}


#4
  • please format your post… (not very nice to read long codechunks on a phone)

details

  • without the complete schematics I doubt someone can help you with this

(Sveinutne) #7

I wonder if the problem is the TTGO T3 2.1_1.5. It will try to connect with the Lora base station, but it behaves like when I got low voltage. I only get the first line, but not the connection with payloade line. Maybe I could try to stop the wifi, to see if that will help the situation.
When I run almost the same code without wifi it connects after one or two try.


(Sveinutne) #8

bilde


(Arinze Izukanne) #9

Is your code using both cores of the ESP32? If not, can you consider making the LoRa and ESPNow codes to run on different cores?


(Sveinutne) #10

I was planing to stop the wifi when I was using the Lora comunincation, but to dedicate one core for wifi and one for Lora might also work. I am a novice, so I need to read up on how to use both cores.


(Cslorabox) #11

Given you’ll need to run power up the mast anyway, a serial link would be simpler. And it would save you power, since it’s easier to wake up on serial data (especially if preceded by an attention pulse) than it is to wake up for coordinated receive windows.

With care there are even ways you could multiplex bi-directional serial and power on a single wire pair.