Skip to content
apolo-mejia edited this page Apr 9, 2023 · 11 revisions

OVERVIEW Communication between ESP32's, using ESP-NOW.

  sequenceDiagram
    participant VPN-GATEWAY
    participant ESPNOW-GATEWAY-DAEMON
    participant SENSOR-DATA_ACQUISITION
    VPN-GATEWAY-->>ESPNOW-GATEWAY-DAEMON: It's time to get measure: "measXX"
    ESPNOW-GATEWAY-DAEMON-->>SENSOR-DATA_ACQUISITION: Take a measure: "request 0xXX"
    SENSOR-DATA_ACQUISITION-->>SENSOR-DATA_ACQUISITION: Data Acquisition
    ESPNOW-GATEWAY-DAEMON-->>SENSOR-DATA_ACQUISITION: Send me a measure: "request 0xXX"
    ESPNOW-GATEWAY-DAEMON-->>ESPNOW-GATEWAY-DAEMON: Save Data
    VPN-GATEWAY-->>ESPNOW-GATEWAY-DAEMON: Send a Data {JSON}
    VPN-GATEWAY-->>VPN-GATEWAY: Write in CVS file.
Loading

JUSTIFICATION

As in many companies it is difficult to obtain access to a WiFi network, although a possibility of install a self owned network it could incurs in a new hardware installation and maintenance.

Considerations

We use a ESP-NOW, to solve the problem of communications as with this protocol, NO routers are needed.

ROLES

CAJA_SERVER

FALTA !!! y tiene su propio repo (hace Link!!!)

GATEWAY - ESP32

An ESP32 connected to a Computer via USB, via this interface peripheral an API request the measures from sensors. The code gateway should upload to this ESP32.

SENSOR

An ESP32 located in sensors is controlling the peripherals used for data acquisition, this data is store fist in the internal memory and then transmitted to GATEWAY - ESP32, in order to accomplish the requests made by the Computer.

Operation

Note that in this protocol does not exits something like MASTER-SLAVE roles, any role mentioned do not escape of the inner scope proyect.

Pier using

Others functions

Data Structures

As the ESP-NOW protocol uses a payload up to a 250-byte, data structures are limited to this size. Therefore, if you need to modify this structure make a payload test before implement it. All data structures used to interchange data should have code global scope.

Requesting Structure

This is the structure in charge of asking for measures.

typedef struct struct_message2 {
    byte request;           // request needed
  }struct_message2;

The request are dealing with binary mask at de sensor-side, clearing bit to bit request, in this way any combination of measure is possible.

Requesting table
Hex Binary Request
0x00 b00000000 The request is clear
0x01 b00000001 Take acceleration data in 3 axis
0x02 b00000010 Send acceleration 3 axis data
0x04 b00000100 Pairing request
0x08 b00001000
0x10 b00010000
0x20 b00100000
0x40 b01000000 Take temperature form ADC
0x80 b10000000 Send temperature

**Example given: ** From a Gateway ESP32

Response Structure

This is the structure which transport the data, form measures.

typedef struct struct_message {
  char id[12];            // Name + identification
  byte s2write;           // s2write flag
  int variable;           // Variable to be affected
  int tsample, nsamples;  // en-lapsed time of the measure ad number of samples
  int pos[2];             // Positions to be affected
  float datos[50];        // data itself
} struct_message;
int variable table

This variable is a pointer to allocate the data in the inner memory of receiver/sender.

Hex Binary Variable Description
0x0000 b0000000000000000 Clear Indicates that there is not variables to be sent
0x0001 b0000000000000001 accx Vector points of acceleration in x axis
0x0002 b0000000000000010 accy Vector points of acceleration in y axis
0x0004 b0000000000000100 accz Vector points of acceleration in z axis
0x0008 b0000000000001000 temp Temperature form ADC - termocouple
0x0010 b0000000000010000 MAC Senders Save a MAC Sender to a caheAddress
0x0020 b0000000000100000 N/A No assigned
0x0040 b0000000001000000 N/A No assigned
0x0080 b0000000010000000 N/A No assigned
0x0100 b0000000100000000 N/A No assigned
0x0200 b0000001000000000 N/A No assigned
0x0400 b0000010000000000 N/A No assigned
0x0800 b0000100000000000 N/A No assigned
0x1000 b0001000000000000 N/A No assigned
0x2000 b0010000000000000 N/A No assigned
0x4000 b0100000000000000 N/A No assigned
0x8000 b1000000000000000 N/A No assigned

Call back Function (GATEWAY as Receiver - Sensor as Sender)

Callback functions are register in both peers of the communication, in this case (GATEWAY - SENSOR). This force us to have different callbacks at both peers.

SENSOR OnDataSent Callback function

This generic function in placed at both peers sides.

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");
}

As the pay load of a ESP-NOW API is limited, we need to slice the long measures in a 50 dots pack. That is why we use enviopack function. Note that this wrapper is synchronized with recepack at the GATEWAY peer side.

void enviopack(float medida[1750], int lon){
  int ini;
  while( ini <= lon ){
    data2send.pos[0] = ini;
    data2send.pos[1] = ini + 50;
    for(int y = data2send.pos[0]; y < data2send.pos[1]; y++){
      data2send.datos[y-ini] = medida[y];
    }
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &data2send, sizeof(data2send)); 
    if (result == ESP_OK) {Serial.println("Sending confirmed");
    }else {Serial.println("Sending error");
    }
    delay(10);
    ini=ini+50;
  }
}

GATEWAY OnDataRecv Callback function

This OnDataOnRecv function is invoked every time a registered is sending data. At this side (Gateway) is in-charge of register sensor data in a internal memory to be used later.

void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&myData, incomingData, sizeof(myData));
  if (myData.variable == 0x0001){`
    recepack(accx, myData.pos);`
  }else if(myData.variable == 0x0002){
    recepack(accy, myData.pos);`
  }else if(myData.variable == 0x0004){
    recepack(accz, myData.pos);
  }
}

As we can see the call this callback-function invoke a recepack function with two parameters (measure, position), these are pointers:

  • measure: points to a variable to be affected
  • position: points to the positions in the vector to be affected
void recepack(float medida[1750], int ind[2]){
  for (int x = ind[0]; x < ind[1]; x++){
    medida[x] = myData.datos[x-ind[0]];
  }
}

Note that this wrapper is synchronized with enviopack at the SENSOR peer side.

Call back Function (SENSOR as Receiver - GATEWAY as Sender)

When the GATEWAY is required by the CAJA_SERVER for a specific measure, a message requesting this information in needed.