This is my first post , so please be kind.
I have 2 ESP32 dev kit C set up as master and slave.
You can see from the coding below that if any of the input gpios on the master is taken LOW then the corresponding pin on the slave also moves to LOW and triggers an 8 channel relay module which stays on until the pin on the master moves back to HIGH and the Pin on the slave moves HIGH.
My challenge is for the Pin on the slave to only move LOW for 100ms and return to HIGH even though the master continues to send LOW until the pin on the master moves back to HIGH again.
The Pins on the master are taken low by PIR sensors which can be active for as long as they are triggered, but the corresponding pin on the slave must only go LOW for 100ms.
I have tried numerous combinations of millis() based loops on the slave to try and manipulate the pin data received ,but nothing seems to work.
Does anyone have any ideas on how this can be achieved.?
Graham
// This sketch sends pin data to a single slave (S1) at //0x24, 0x6f, 0x28, 0x7c, 0x7a, 0x10 //The Gpios in the array 16,17,18,19,21,22,23,25 //Are set to PULL UP internally and when any of these pins are taken LOW //The corresponding pin on the slave is taken from HI to LOW to activate //the relay board which needs a LOW input to trigger // The sketch also provides for a local relay attached to the Master to be triggered at the same time as the slave //Libs for espnow and wifi #include <esp_now.h> #include <WiFi.h> //Channel used in the connection #define CHANNEL 1 //Gpios that we are going to read (digitalRead) and send to the Slaves //It's important that the Slave source code has this same array //with the same gpios in the same order uint8_t gpios[] = {16,17,18,19,21,22,23,25}; //Sets up the array for the local relays uint8_t relayPins[]={2,4,5,13,26,27,32,33}; //In the setup function we'll calculate the gpio and relay count and put in these variables, //so we don't need to change this variable everytime we change //the gpios array total size, everything will be calculated automatically //in setup function int gpioCount; int relayCount; //Slaves Mac Addresses that will receive data from the Master //If you want to send data to all Slaves, use only the broadcast address {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}. //If you want to send data to specific Slaves, put their Mac Addresses seperated with comma (use WiFi.macAddress()) //to find out the Mac Address of the ESPs while in STATION MODE) uint8_t macSlaves[][6] = { //To send to specific Slaves MAC addresses seperated by a comma eg // {0x24, 0x62, 0xAB, 0xF3, 0xC3, 0xC8}, {0x24, 0x0A, 0xC4, 0x0E, 0x4E, 0xC3} {0x24, 0x6f, 0x28, 0x7c, 0x7a, 0x10} //Or to send to all Slaves //{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} }; void setup() { Serial.begin(115200); //Calculation of gpio and local relay array sizes: //sizeof(gpios) returns how many bytes "gpios" array points to. //Elements in this array are of type uint8_t. //sizeof(uint8_t) returns how many bytes uint8_t type has. //Therefore if we want to know how many gpios and relays there are, //we divide the total byte count of the array by how many bytes //each element has. gpioCount = sizeof(gpios)/sizeof(uint8_t); relayCount = sizeof(relayPins)/sizeof(uint8_t); //Puts ESP in STATION MODE WiFi.mode(WIFI_STA); //Shows on the Serial Monitor the STATION MODE Mac Address of this ESP Serial.print("Mac Address in Station: "); Serial.println(WiFi.macAddress()); //Calls the function that will initialize the ESP-NOW protocol InitESPNow(); //Calculation of the size of the slaves array: //sizeof(macSlaves) returns how many bytes the macSlaves array points to. //Each Slave Mac Address is an array with 6 elements. //If each element is sizeof(uint8_t) bytes //then the total of slaves is the division of the total amount of bytes //by how many elements each MAc Address has //by how much bytes each element has. int slavesCount = sizeof(macSlaves)/6/sizeof(uint8_t); //For each Slave for(int i=0; i<slavesCount; i++){ //We create a variable that will store the slave information esp_now_peer_info_t slave; //We inform the channel slave.channel = CHANNEL; // 0 not to use encryption or 1 to use slave.encrypt = 0; //Copies the array address to the structure memcpy(slave.peer_addr, macSlaves[i], sizeof(macSlaves[i])); //Add the slave esp_now_add_peer(&slave); } //Registers the callback that will give us feedback about the data sent //The function that will be executed is called OnDataSent esp_now_register_send_cb(OnDataSent); //for each pin in the gpio array for(int i=0; i<gpioCount; i++){ //Set the GPIO mode to INPUT puuled up by internal resistors pinMode(gpios[i], INPUT_PULLUP); // Set the local relay pins to OUTPUT. These need to be taken LOW to activate the relays for(int i = 0; i < relayCount; i++) pinMode(relayPins[i], OUTPUT); } //Call the send function send(); } void InitESPNow() { //If the initialization was successful if (esp_now_init() == ESP_OK) { Serial.println("ESPNow Init Success"); } //If there was an initialisation error else { Serial.println("ESPNow Init Failed"); ESP.restart(); } } //Function that will read the gpios and send //the read values to the other ESP Slaves void send(){ //Array that will store the read values uint8_t values[gpioCount]; //For each gpio for(int i=0; i<gpioCount; i++){ //Reads the value (HIGH or LOW) of the gpio //and stores the value on the array values[i] = digitalRead(gpios[i]); } //To broadcast to all the ESPs use {0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF} but to send //to a specific ESP call the function //esp_now_send for each Mac Address with its parameters as below. uint8_t broadcast[] = {0x24, 0x6f, 0x28, 0x7c, 0x7a, 0x10}; esp_err_t result = esp_now_send(broadcast, (uint8_t*) &values, sizeof(values)); Serial.print("Send Status: "); //If successful if (result == ESP_OK) { Serial.println("Success"); } //If send failed else { Serial.println("Error"); } } //Callback function that gives us feedback about the sent data void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { char macStr[18]; //Copies the receiver Mac Address to a string 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]); //Prints the Mac address to which the message has been sent on Serial Monitor Serial.print("Sent to: "); Serial.println(macStr); //Shows the status of the sent message and whether succful or not. Serial.print("Status: "); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail"); //print gpioCount for ref //Serial.print("gpioCount: "); //Serial.println(gpioCount); //print sizeof gpios for ref //Serial.print("sizeof(gpios): "); //Serial.println(sizeof (gpios)); //print sizeof uint8_t data for ref //Serial.print("sizeof(uint8_t): "); //Serial.println(sizeof (uint8_t)); //Send new data send(); } //In this example we are going to using the broadcast address {0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF} //to send the values to all Slaves. //If you want to send to a specific Slave, you have to put its Mac Address on macAddr. //If you want to send to more then one specific Slave you will need to create //a "for loop" and call esp_now_send for each mac address on the macSlaves array uint8_t macAddr[] = {0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF}; //esp_err_t result = esp_now_send(macAddr, (uint8_t*) &values, sizeof(values)); Serial.print("Send Status: "); //If it was successful if (result == ESP_OK) { Serial.println("Success"); } //if it failed else { Serial.println("Error"); } } //Callback function that gives us feedback about the sent data //void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { char macStr[18]; //Copies the receiver Mac Address to a string 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]); //Prints it on Serial Monitor Serial.print("Sent to: "); Serial.println(macStr); //Prints if it was successful or not Serial.print("Status: "); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail"); //Sends again send(); } //The Loop function is only used to operate the local relays in line with GPIO inputs. //Every time we receive feedback about the last sent data, //we'll be calling the send function again, //therefore the data is always being sent in Setup void loop() { //if an input GPIO is taken low, take the corresponding local relay low. for(int i = 0; i < gpioCount; i++) { int buttonState = digitalRead(gpios[i]); digitalWrite(relayPins[i], buttonState); } }
Code:
#include <esp_now.h> #include <WiFi.h> uint8_t gpios[] = {16,17,18,19,21,22,23,25}; int gpioCount; void setup() { Serial.begin(115200); gpioCount = sizeof(gpios)/sizeof(uint8_t); WiFi.mode(WIFI_STA); Serial.print("Mac Address in Station: "); Serial.println(WiFi.macAddress()); InitESPNow(); esp_now_register_recv_cb(OnDataRecv); for(int i=0; i<gpioCount; i++){ //Sets the gpois pinmode to OUTPUT pinMode(gpios[i], OUTPUT); } } void InitESPNow() { if (esp_now_init() == ESP_OK) { Serial.println("ESPNow Init Success"); } else { Serial.println("ESPNow Init Failed"); ESP.restart(); } } void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) { 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("Received from: "); Serial.println(macStr); Serial.println(""); for(int i=0; i<gpioCount; i++){ digitalWrite(gpios[i], data[i]); } } void loop() { }
You may want to use interrupts. There is a great article series over at Adafruit.
Thanks Steve
The fundamental issue seems to be that the slave is continually receiving a stream of HIGHs from the master,
I’m really unsure as to whether I deal with the timing on the Slave or whether to get the master to send short duration LOWs that are mirrored on the slave
I sense that the master will be the place to start.
I really and stuck on this one so any help is appreciated.
The issue appears to be at the slave end so that is where I would put it. All you are doing is creating a state machine.
Hi Graham.
In the sender side:
In your ESP-NOW sender board, you have a PIR motion sensor attached. So, when it detects movement, it will send a HIGH signal. In order to only send one message when it goes from LOW to HIGH, you should use interrupts.
In the “Learn ESP32 with Arduino IDE eBook” there’s a section about a interrupts (page 76).
For example, imagine your PIR sensor is on GPIO 27
const int motionSensor = 27;
Create a boolean variable to indicate if it is time to send a high signal:
bool sendMessage = false;
Then, set hte PIR as interrupt in the setup()
// PIR Motion Sensor mode INPUT_PULLUP pinMode(motionSensor, INPUT_PULLUP); // Set motionSensor pin as interrupt, assign interrupt function and set RISING mode attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);
Before the setup(), you must declare the detectsMovement callback function. When that function is called, set the sendMessage function to true.
void IRAM_ATTR detectsMovement() { Serial.println("MOTION DETECTED!!!"); sendMessage = true; }
Then, in the loop(), you can check the state of the sendMessage variable, and if it is true, send the message via ESP-NOW
void loop(){ if (sendMessage==true){ SEND WHATEVER MESSAGE YOU WANT USING ESP-NOW sendMessage = false; //set the sendMessage to false, so that it doesn't send any additional messages. } }
In your ESP-NOW receiver board, when it receives a message from the sender board, you can use a flag variable in the OnDataRecv function that will change value if it is time to send a pulse to the output.
Then, in the loop() check the state of that variable and send the pulse to the output. Because you just want to set it to high for 100ms, most of the times, there is not harm if you use a delay:
digitalWrite(led, HIGH); delay(100); digitalWrite(led, LOW);
I hope this helps.
Regards,
Sara
Thanks for that Sara,
this will take me a bit of time to adsorb, but one immediate question
I have 8 PIRs in the array on gpios 16,17,18,19,21,22,23,25
Will I need 8 interrupts to be setup or can the interrupts be linked directly to the 8 pins on the array.
Any PIR can be activated at any time, sometimes two at the same time.?
Graham