ESP-Now with Multiple Sensors
Posted: Thu Aug 08, 2019 5:02 am
Hi all,
I am new to using ESP8266 and Arduino etc and have been working on a system of sensors (masters) to go around my home and relay their data to a single slave unit via ESP-Now.
The slave unit will then handle the received data and eventually upload to the web, to ThingSpeak or Adafruit IO.
I started off using code that I found at: https://github.com/HarringayMakerSpace with only a single sensor and that has worked like a dream.
Next I manipulated the code in order for it to work with more than one sensor, at the moment three sensors: DHT22 and two DS18B20
The data is being sent from each sensor to the single slave unit and when I open the serial monitor for the slave unit I can see it all perfectly fine.
Now obviously I would like to display/handle this data specific to a sensor by giving each sensor it's own name i.e.
I have tried a number of ways to code this, initially adding a matching 'String' variable to the 'struct' section of both the Master & Slave in the form of:
adding this to the
function as
I add a line in order to test these changes and show them in the serial monitor of the specific sensor
and this works, I get the output, for instance
in the serial monitor.
For clarity, here is the complete code for one of my sensors which includes the changes to allow sensor ID as laid out above
Unfortunately, even with making some changes to the Slave sketch I am unable to get the [sensor ID] to display relative to the MAC address of the Master sender.
Again, for clarity, here is the complete code for my Slave unit
I have starred out personal details.
You will see the line
in the
function but this does nothing at all and all that is display in the serial monitor of the Slave unit for example is
You will see that the first line of the output to the serial monitor starts with SENSOR 3
I have attempted to distinguish between the three instances of
that there are in my Slave unit sketch by adding text SENSOR 1, SENSOR 2 & SENSOR 3 and although I think that I am sending the data to a specified point in the code i.e. the one containing
which I hoped would relate to that specific sensors data, it seems that it just falls to the last
section in the sketch
You will also see from the second line of the output to the serial monitor, as shown above, that it has completely missed off the sensor ID as I assumed would be displayed by thisline in the sketch
I would appreciate any help on this.
Regards..,
Kirk
I am new to using ESP8266 and Arduino etc and have been working on a system of sensors (masters) to go around my home and relay their data to a single slave unit via ESP-Now.
The slave unit will then handle the received data and eventually upload to the web, to ThingSpeak or Adafruit IO.
I started off using code that I found at: https://github.com/HarringayMakerSpace with only a single sensor and that has worked like a dream.
Next I manipulated the code in order for it to work with more than one sensor, at the moment three sensors: DHT22 and two DS18B20
The data is being sent from each sensor to the single slave unit and when I open the serial monitor for the slave unit I can see it all perfectly fine.
Now obviously I would like to display/handle this data specific to a sensor by giving each sensor it's own name i.e.
- Kitchen - Temperature X
- Bathroom - Temperature Y
- Lounge - Temperature Z
I have tried a number of ways to code this, initially adding a matching 'String' variable to the 'struct' section of both the Master & Slave in the form of:
Code: Select all
String name_[sensor ID];
adding this to the
Code: Select all
void sendReading()
function as
Code: Select all
sd_[sensor ID].name_[sensor ID] = "Kitchen";
I add a line in order to test these changes and show them in the serial monitor of the specific sensor
Code: Select all
Serial.print(sd_[sensor ID].name_[sensor ID]); Serial.print(" Temperature = "); Serial.println(sd_[sensor ID].temp_[sensor ID]);
and this works, I get the output, for instance
Code: Select all
Kitchen Temperature = 21.19
in the serial monitor.
For clarity, here is the complete code for one of my sensors which includes the changes to allow sensor ID as laid out above
Code: Select all
/*
Testing ESP-Now
See https://espressif.com/en/products/software/esp-now/overview
ESP-Now enables fast lightwieght connectionless communication between ESP8266's.
So for example a remote sensor node could send a reading using ESP-Now in just a few
hundred milliseconds and deepSleep the rest of the time and so get increased battery
life compared to the node using a regular WiFi connection which could take 10 times
as long to connect to WiFi and send a sensor reading.
ESP-Now has the concept of controllers and slaves. AFAICT the controller is the remote
sensor node and the slave is the always on "gateway" node that listens for sensor node readings.
**** This sketch is the controller/sensor node ****
*** Note: to compile ESP-Now (with arduino/esp8266 release 2.3.0) need to edit
* ~/Library/Arduino15/packages/esp8266/hardware/esp8266/2.1.0/platform.txt
* Search "compiler.c.elf.libs", and append "-lespnow" at the end of the line.
* See: http://www.esp8266.com/viewtopic.php?p=44161#p44161
***
Ant Elder
License: Apache License v2
*/
#include <ESP8266WiFi.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_PIN D2
OneWire oneWire_ds18b20_1(ONE_WIRE_PIN);
DallasTemperature sensor_ds18b20_1(&oneWire_ds18b20_1);
extern "C" {
#include <espnow.h>
}
// this is the MAC Address of the remote ESP which this ESP sends its data too
uint8_t remoteMac[] = {0x86, 0xF3, 0xEB, 0X62, 0x71, 0xEC};
#define WIFI_CHANNEL 1
#define SLEEP_TIME 36e8 //has to be number of seconds * 1000 * 1000 i.e. 10s is 10 * 1000 * 1000 = 10000000 or 1e7 ( 1 + 7 zeros) for testing 1e7
#define SEND_TIMEOUT 10000
// keep in sync with slave struct
struct SENSOR_DATA_DS18B20_1 {
String name_ds18b20_1;
float temp_ds18b20_1;
float t_ds18b20_1;
};
volatile boolean readingSent;
void setup() {
Serial.begin(115200); Serial.println();
WiFi.mode(WIFI_STA); // Station mode for sensor/controller node
WiFi.begin();
Serial.print("This node mac: "); Serial.println(WiFi.macAddress());
if (esp_now_init()!=0) {
Serial.println("*** ESP_Now init failed");
ESP.restart();
}
delay(1); // This delay seems to make it work more reliably???
esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
esp_now_add_peer(remoteMac, ESP_NOW_ROLE_SLAVE, WIFI_CHANNEL, NULL, 0);
esp_now_register_send_cb([](uint8_t* mac, uint8_t status) {
Serial.print("send_cb, status = "); Serial.print(status);
Serial.print(", to mac: ");
char macString[50] = {0};
sprintf(macString,"%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Serial.println(macString);
readingSent = true;
});
sensor_ds18b20_1.requestTemperatures();
sendReading();
}
void loop() {
if (readingSent || (millis() > SEND_TIMEOUT)) {
Serial.print("Going to sleep, uptime: "); Serial.println(millis());
ESP.deepSleep(SLEEP_TIME, WAKE_RF_DEFAULT);
ESP.restart();
}
}
void sendReading() {
readingSent = false;
SENSOR_DATA_DS18B20_1 sd_ds18b20_1;
sd_ds18b20_1.name_ds18b20_1 = "Kitchen";
sd_ds18b20_1.temp_ds18b20_1 = sensor_ds18b20_1.getTempCByIndex(0);
sd_ds18b20_1.t_ds18b20_1 = millis();
Serial.print("sendReading, t="); Serial.println(sd_ds18b20_1.t_ds18b20_1);
Serial.print(sd_ds18b20_1.name_ds18b20_1); Serial.print(" Temperature = "); Serial.println(sd_ds18b20_1.temp_ds18b20_1);
u8 bs[sizeof(sd_ds18b20_1)];
memcpy(bs, &sd_ds18b20_1, sizeof(sd_ds18b20_1));
esp_now_send(NULL, bs, sizeof(bs)); // NULL means send to all peers
}
Unfortunately, even with making some changes to the Slave sketch I am unable to get the [sensor ID] to display relative to the MAC address of the Master sender.
Again, for clarity, here is the complete code for my Slave unit
Code: Select all
/*
Testing ESP-Now
See https://espressif.com/en/products/software/esp-now/overview
ESP-Now enables fast lightwieght connectionless communication between ESP8266's.
So for example a remote sensor node could send a reading using ESP-Now in just a few
hundred milliseconds and deepSleep the rest of the time and so get increased battery
life compared to the node using a regular WiFi connection which could take 10 times
as long to connect to WiFi and send a sensor reading.
ESP-Now has the concept of controllers and slaves. AFAICT the controller is the remote
sensor node and the slave is the always on "gateway" node that listens for sensor node readings.
*** Note: to compile ESP-Now (with arduino/esp8266 release 2.3.0) need to edit
* ~/Library/Arduino15/packages/esp8266/hardware/esp8266/2.1.0/platform.txt
* Search "compiler.c.elf.libs", and append "-lespnow" at the end of the line.
* See: http://www.esp8266.com/viewtopic.php?p=44161#p44161
***
**** This skecth is the slave/gateway node ****
Ant Elder
License: Apache License v2
*/
#include <ESP8266WiFi.h>
extern "C" {
#include <espnow.h>
}
const char* ssid = "****";
const char* password = "****";
#define WIFI_CHANNEL 1
// keep in sync with sensor struct
struct SENSOR_DATA_DHT22 {
float temp_dht22;
int hum_dht22;
float t_dht22;
};
struct SENSOR_DATA_DS18B20_1 {
String name_ds18b20_1;
float temp_ds18b20_1;
float t_ds18b20_1;
};
struct SENSOR_DATA_DS18B20_2 {
float temp_ds18b20_2;
float t_ds18b20_2;
};
void setup() {
Serial.begin(115200); Serial.println();
initWifi();
if (esp_now_init()!=0) {
Serial.println("*** ESP_Now init failed");
ESP.restart();
}
Serial.print("This node AP mac: "); Serial.print(WiFi.softAPmacAddress());
Serial.print(", STA mac: "); Serial.println(WiFi.macAddress());
// Note: When ESP8266 is in soft-AP+station mode, this will communicate through station interface
// if it is in slave role, and communicate through soft-AP interface if it is in controller role,
// so you need to make sure the remote nodes use the correct MAC address being used by this gateway.
esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
esp_now_register_recv_cb([](uint8_t *mac, uint8_t *data_dht22, uint8_t len) {
Serial.print("SENSOR 1 recv_cb, from mac: ");
char macString[50] = {0};
sprintf(macString, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Serial.print(macString);
getReading_DHT22(data_dht22, len);
});
esp_now_register_recv_cb([](uint8_t *mac, uint8_t *data_ds18b20_1, uint8_t len) {
Serial.print("SENSOR 2 recv_cb, from mac: ");
char macString[50] = {0};
sprintf(macString, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Serial.print(macString);
getReading_DS18B20_1(data_ds18b20_1, len);
});
esp_now_register_recv_cb([](uint8_t *mac, uint8_t *data_ds18b20_2, uint8_t len) {
Serial.print("SENSOR 3 recv_cb, from mac: ");
char macString[50] = {0};
sprintf(macString, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Serial.print(macString);
getReading_DS18B20_2(data_ds18b20_2, len);
});
}
void loop() {
}
void getReading_DHT22(uint8_t *data_dht22, uint8_t len) {
SENSOR_DATA_DHT22 tmp_dht22;
memcpy(&tmp_dht22, data_dht22, sizeof(tmp_dht22));
Serial.print(", parsed data, t="); Serial.println(tmp_dht22.t_dht22);
Serial.print("Temperature = "); Serial.println(tmp_dht22.temp_dht22);
Serial.print("Humidity = "); Serial.println(tmp_dht22.hum_dht22);
}
void getReading_DS18B20_1(uint8_t *data_ds18b20_1, uint8_t len) {
SENSOR_DATA_DS18B20_1 tmp_ds18b20_1;
memcpy(&tmp_ds18b20_1, data_ds18b20_1, sizeof(tmp_ds18b20_1));
Serial.print(", parsed data, t="); Serial.println(tmp_ds18b20_1.t_ds18b20_1);
Serial.print(tmp_ds18b20_1.name_ds18b20_1); Serial.print(" Temperature = "); Serial.println(tmp_ds18b20_1.temp_ds18b20_1);
}
void getReading_DS18B20_2(uint8_t *data_ds18b20_2, uint8_t len) {
SENSOR_DATA_DS18B20_2 tmp_ds18b20_2;
memcpy(&tmp_ds18b20_2, data_ds18b20_2, sizeof(tmp_ds18b20_2));
Serial.print(", parsed data, t="); Serial.println(tmp_ds18b20_2.t_ds18b20_2);
Serial.print("Temperature = "); Serial.println(tmp_ds18b20_2.temp_ds18b20_2);
}
void initWifi() {
WiFi.mode(WIFI_AP_STA);
WiFi.softAP("MyGateway", "12345678", WIFI_CHANNEL, 1);
Serial.print("Connecting to "); Serial.print(ssid);
if (strcmp (WiFi.SSID().c_str(), ssid) != 0) {
WiFi.begin(ssid, password);
}
int retries = 20; // 10 seconds
while ((WiFi.status() != WL_CONNECTED) && (retries-- > 0)) {
delay(500);
Serial.print(".");
}
Serial.println("");
if (retries < 1) {
Serial.print("*** WiFi connection failed");
ESP.restart();
}
Serial.print("WiFi connected, IP address: "); Serial.println(WiFi.localIP());
}
I have starred out personal details.
You will see the line
Code: Select all
Serial.print(tmp_ds18b20_1.name_ds18b20_1); Serial.print(" Temperature = "); Serial.println(tmp_ds18b20_1.temp_ds18b20_1);
in the
Code: Select all
void getReading_DS18B20_1
function but this does nothing at all and all that is display in the serial monitor of the Slave unit for example is
Code: Select all
SENSOR 3 recv_cb, from mac: 84:F3:EB:62:70:6A, parsed data, t=98
Temperature = 21.19
You will see that the first line of the output to the serial monitor starts with SENSOR 3
I have attempted to distinguish between the three instances of
Code: Select all
esp_now_register_recv_cb
that there are in my Slave unit sketch by adding text SENSOR 1, SENSOR 2 & SENSOR 3 and although I think that I am sending the data to a specified point in the code i.e. the one containing
Code: Select all
esp_now_register_recv_cb([](uint8_t *mac, uint8_t *data_ds18b20_1, uint8_t len)
which I hoped would relate to that specific sensors data, it seems that it just falls to the last
Code: Select all
esp_now_register_recv_cb
section in the sketch
You will also see from the second line of the output to the serial monitor, as shown above, that it has completely missed off the sensor ID as I assumed would be displayed by thisline in the sketch
Code: Select all
Serial.print(tmp_ds18b20_1.name_ds18b20_1); Serial.print(" Temperature = "); Serial.println(tmp_ds18b20_1.temp_ds18b20_1);
I would appreciate any help on this.
Regards..,
Kirk