I have been working up a project for a few weeks (as I'm a complete novice).
Two ESP32 development boards talking to each other as "Master and Slave"
The Master sends data to the slave consisting of the state of 8 GPIO PINS and the Slave uses the data received to operate an 8 channel relay module which triggers when a pin in taken LOW.
All is working well and any change to a GPIO on the Master is reflected on the corresponding Pin on the slave.
The Pins on the slave mirror exactly the data sent from the master so if a pin in taken low for 5mins on the master, the slave pin is low for 5 mins.
I now want to limit the length of time that the slave pin is operative.
eg if the master is held low for 5 mins the slave only goes low for 50ms and then returns to a HIGH state waiting for the next data to arrive from the master.
Can anyone suggest how I might approach this?
The slave code is reproduced here.
//Libs for espnow and wifi
#include <esp_now.h>
#include <WiFi.h>
// THIS SLAVE RECEIVES DATA FROM an MASTER ESP32 TRANSMITTING GPIO values
//When the gpio pins values are received from the Master, they are written
//to the gpios on this slave as outputs.
uint8_t gpios[] = {16,17,18,19,21,22,23,25};
// the gpio count is saved in a variable called,
//gpioCount ( declared below)
int gpioCount;
void setup() {
Serial.begin(115200);
//Calculation of gpio array size:
gpioCount = sizeof(gpios)/sizeof(uint8_t);
//Puts ESP in STATION MODE
WiFi.mode(WIFI_STA);
//Prints out on the Serial Monitor the STATION MODE Mac Address of this ESP32
Serial.print("Mac Address in Station: ");
Serial.println(WiFi.macAddress());
//Calls the function that will initialize the ESP-NOW protocol
InitESPNow();
//Registers the callback function, OnDataRecv, that will be executed when
//this Slave receives data from the Master.
esp_now_register_recv_cb(OnDataRecv);
//For each gpio on gpios array
for(int i=0; i<gpioCount; i++){
//Sets the gpois pinmode to OUTPUT //These gpios will drive the relays on an
//8 channel 3.3v relay module
pinMode(gpios[i], OUTPUT);
}
}
void InitESPNow() {
//If the initialization was successful
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success");
}
//If there was an initialistaion error
else {
Serial.println("ESPNow Init Failed");
ESP.restart();
}
}
//Callback function that tells us when data from Master is received
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) {
char macStr[18];
//Copies the sender 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 and shows the origin of the message
Serial.print("Received from: ");
Serial.println(macStr);
Serial.println("");
//For each gpio pin
for(int i=0; i<gpioCount; i++){
//Sets its output on the slave to match the received value from the master
digitalWrite(gpios[i], data[i]);
// The gpios on the master are set to be INPUT and Pulled HIGH
//each time any pin in the array gpio is taken LOW the corrsponding gpio on this slave
// is taken LOW to match and the corresponding relay is triggered and held LOW until the
//pin on the master is taken HIGH again.
}
}
//Everytime something comes from Master
//the OnDataRecv function is executed automatically
//because it is added as a callback using esp_now_register_recv_cb
void loop() {
}
You have accomplished a lot, you will find it is relatively easy to accomplish what you want. Do some reading on the arduino millis(), there will be a lot of examples and your skill level will improve. It will also sharpen your skills on the "if" statement.
Thanks for the pointer. I have been trying to read up on the use of millis but can’t find much in the way of examples of millis in conjunction with reading data from arrays. Any hints would be appreciated.
eg if the master is held low for 5 mins the slave only goes low for 50ms and then returns to a HIGH state waiting for the next data to arrive from the master.
do I understand right. Master is sending low for 5 minutes.
example:
12:00:00 master send low
12:00:01 master send low
12:00:02 master send low
12:00:03 master send low
....
12:04:59 master send low
12:05:00 master send low
that's a "master is held low for 5 mins"
and the other part of your description is
"the slave only goes low for 50ms and then returns to a HIGH state waiting for the next data to arrive from the master"
12:00:00,000 low received by slave slave LOW
12:00:00,001 low received by slave slave LOW
12:00:00,002 low received by slave slave LOW
...
12:00:00,049 low received by slave slave LOW
12:00:00,050 low received by slave slave HIGH
12:00:01,000 low received by slave slave LOW
12:00:01,001 low received by slave slave LOW
12:00:01,002 low received by slave slave LOW
...
12:00:01,049 low received by slave slave LOW
12:00:01,050 low received by slave slave HIGH
12:00:02,000 low received by slave slave LOW
12:00:02,001 low received by slave slave LOW
12:00:02,002 low received by slave slave LOW
...
12:00:02,049 low received by slave slave LOW
12:00:02,050 low received by slave slave HIGH
that is in exaple-numbers what you have described so far. I'm unsiure if this is what you really mean.
So please confirm or correct with example-numbers or with a picture that has a timing-diagram
what the functionality shall bee. In this diagram the master-logig-level (LOW/HIGH) and the slaves logic-level (LOW/HIGH) shall be seen with the timing-correlation to each other.
Your example is correct but it need not be 5 Mins exactly, that was just an example.
Here is another description.
A PIR sensor connected to the master takes pins on the Master from HIGH to LOW when activated.
Present situation:
When a pin on the master is taken from HIGH to LOW, the same pin no. on the slave is taken from HIGH to LOW for as long as the pin on the master remains LOW (all the time the PIR remains activated)
When the PIR sensor deactivates, that pin on the master moves back from LOW to HIGH , the same pin on the slave moves back from LOW to HIGH. They are like identical twins.
What I need is when a pin on the master is taken from HIGH to LOW , the same pin no. on the slave will move from HIGH to LOW , BUT ONLY FOR 50ms before returning to HIGH on the slave, even though the pin on the master continues to be held LOW when the PIR remains activated.
The next time the PIR activates the pin on the Master will move from HIGH to LOW and whole sequence will repeat itself.
This is to be true for each of the 8 PINs in the array gpios in my code.
Result is that each time the PIR is activated the pin on the slave will be taken LOW momentarily (50ms)
If you want a pin to go LOW for a period of time you need to save the value of millis() when the pin changes from HIGH to LOW and then check for when the desired interval has elapsed with a few lines of code like this
if (millis() - timeLowStarted >= interval) {
digitalWrite(pin, HIGH);
}
...R
PS ... your problem seems to have nothing to do with your Title.
Thanks Robin,
I used the Millis approach as suggested and managed to get the Pin to go from LOW to high for 50ms but unfortunately because the Slave is continuously reading in data from the Master (as per the code I submitted) the PIN immediately is sent LOW again in response to a PIR on the master sending a LOW signal to the slave.
So I get a chattering relay which is driven by the GPIO on the slave, 50ms ON, OFF, Immediately ON for 50ms, OFF,Immediately ON for 50ms etc
Maybe the Title of my problem has turned out to be appropriate as its more to do with how ESP NOW functions.
Thanks for your help.
I'm not sure I understand what is written in Reply #7 but I think the following is what it is intended to say.
On the receiver you need to check the incoming value to see if it has changed. I don't know what values are being sent but supposing that 1 is sent when the PIR is On and 0 is sent when it is Off. Then your receiver needs to check when the value changes from 0 to 1 and then switch on the output pin LOW (for 50 msecs).
You need code on your receiver something like this pseudo code
if (new data is available) {
previousValue = value
value = new value from wireless
if (value == 1 and previousValue == 0) {
set Pin LOW
// etc
}
}
after a couple of days of learning about millis and bool I think i'm on the brink of succeeding.
But I have syntax (and probably other errors) which wont let the code compile.
This is what I have added to the code I original posted.
Declared the following global variables
unsigned long currentMillis = millis(); // get current time
unsigned long Relay_onTime; // millis() returns an unsigned long.
unsigned long interval=25; // the time we need to wait
bool Relay_on=true;
Added this code in the Setup immediately below the section which reads in the data from the master (0 equals relay on, 1=relay off
//For each gpio pin
for(int i=0; i<gpioCount; i++){
//Sets its output on the slave to match the received value from the master
digitalWrite(gpios[i], data[i]);
if(digitalRead(gpios[i] == LOW));{
Relay_onTime[i]=millis();
Relay_on[i] = true;
}
if (Relay_on)[i];
{
if (currentMillis[i] - Relay_onTime[i]) < interval){
digitalWrite(gpios[i], LOW);
}
else {
Relay_on[i]=false;
digitalWrite(gpios[i], HIGH);
}
}
previousMillis = millis();
The error I'm getting is
invalid types 'long unsigned int[long unsigned int]' for array subscript
Any help appreciated
I have also renamed the problem Switching relays on and off after period of time elapsed
OK here is the full code for the slave including my latest additions.
//Libs for espnow and wifi
#include <esp_now.h>
#include <WiFi.h>
//Gpios we'll write the values received from the Master
//It's important that the Master 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};
//In the setup function we'll calculate the gpio count and put in this variable,
//gpioCount so we don't need to change this variable everytime we change
//the gpios array total size, everything will be calculated automatically
//on setup function
int gpioCount;
// Timing variable declarations
unsigned long currentMillis = millis(); // get current time
unsigned long Relay_onTime; // millis() returns an unsigned long.
unsigned long interval=100; // the time we need to wait
bool Relay_on=true;
void setup() {
Serial.begin(115200);
//Calculation of gpio array size:
gpioCount = sizeof(gpios)/sizeof(uint8_t);
//Puts ESP32 in STATION MODE
WiFi.mode(WIFI_STA);
//Shows on the Serial Monitor the STATION MODE Mac Address of this ESP32
Serial.print("Mac Address in Station: ");
Serial.println(WiFi.macAddress());
//Calls the function that will initialize the ESP-NOW protocol
InitESPNow();
//Registers the callback function that will be executed when
//this Slave receives data from the Master.
//The function in this case is called OnDataRecv
esp_now_register_recv_cb(OnDataRecv);
//For each gpio on gpios array
for(int i=0; i<gpioCount; i++){
//Sets the gpois pinmode to OUTPUT to drive the 8 channel relay module
pinMode(gpios[i], OUTPUT);
}
}
void InitESPNow() {
//If the initialization was successful
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success");
}
//If there was an initialistaion error
else {
Serial.println("ESPNow Init Failed");
ESP.restart();
}
}
//Callback function that tells us when data from Master is received
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) {
char macStr[18];
//Copies the sender 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 and shows the origin of the message
Serial.print("Received from: ");
Serial.println(macStr);
Serial.println("");
//For each gpio pin
for(int i=0; i<gpioCount; i++){
//Sets its output on the slave to match the received value from the master WHEN HIGH received Relay Off, LOW Relay ON
// PIRs on the master produce the HIGH/LOW sent to the slave
digitalWrite(gpios[i], data[i]);
// This section tests if the data received from the master is LOW or HIGH
//and if LOW switches on a relay for 50ms before moving high again.
//it needs to remain High until the PIR on the master deactivates which results in the data received from the Master being a HIGH again
if(digitalRead(gpios[i] == LOW));{
Relay_onTime[i]=millis();
Relay_on[i] = true;
}
if (Relay_on)[i];
{
if (currentMillis[i] - Relay_onTime[i]) < interval){
digitalWrite(gpios[i], LOW);
}
else {
Relay_on[i]=false;
digitalWrite(gpios[i], HIGH);
}
}
previousMillis = millis();
//Serial.print("PIN STATES: ");Serial.print(gpios[i]);
//Serial.println(" - ");Serial.print(data[i]);
//Serial.println(" ");
}
}
//Nothing to do in the loop.
//Everytime something comes from Master //the OnDataRecv function is executed automatically //because is added as callback using esp_now_register_recv_cb
void loop() {
}
I have attached the error message as a notepad txt file.
//For each gpio pin
for(int i=0; i<gpioCount; i++){
//Sets its output on the slave to match the received value from the master WHEN HIGH received Relay Off, //LOW Relay ON -- PIRs on the master produce the HIGH/LOW sent to the slave
digitalWrite(gpios_, data*);*_ I am trying to check the values written to array gpios
if the values = HIGH -- do nothing as the PIRs on the master are inactive and a stream of HIGHs are being sent by the master and received by the slave. if any of the values in the array = LOW --one or more PIRs have been activated causing LOWs to be sent from master for as long as the PIRs remain activated in this case these LOW signals cause relays to be switched on. I need any relay which has been switched on to remain on for 50ms and then be switched off by writing its gpio value HIGH and for this to remain HIGH until the PIR is deactivated and the master starts sending HIGHs again. The coding I have added is my attempt to implement your previously suggested pseodocode. I have obviously failed on this occasion!
uint8_t gpios[] = {16,17,18,19,21,22,23,25};
//In the setup function we'll calculate the gpio count and put in this variable,
//gpioCount so we don't need to change this variable everytime we change
//the gpios array total size, everything will be calculated automatically
//on setup function
int gpioCount;
// Timing variable declarations
unsigned long currentMillis = millis(); // get current time
unsigned long Relay_onTime; // millis() returns an unsigned long.
unsigned long interval=100; // the time we need to wait
bool Relay_on=true;
you have 8 elements in the array gpios[]
If you want 8 separate relays to match those gpios[] then you you probably need to change these lines to
Thanks for your help but I need to go back to the drawing board.
I have got it going but very erratically I think speed at which ESP32 executes instructions is interferring with the for , if else processes in the code. I think I need to allocate different gpio pins for the relays .