Interactive Target System - 3D Archery

A little more looking into it & Ive decided to go with a 3 way Wemos set up.

Get rid of the UNO & the Rf24, replace them with a wemos which will handle being the reciever & managing the Mp3 player.

2 x wemos set to transmit. (sensors attached)
1 x Wemos set to recieve & manage the Mp3 player (with a radar sensor aswell)

Mick.

Sounds like fun, as the Wemos can do the network and sensor stuff.

New developement.
Setting up the two Wemos units I currently have to talk to each other.

Each has an external LED & a sensor attached,
one is a PIR & the other is a vibration sensor.
We will not be including the vibration sensor in the code at this point.
Same for the LED in the transmitter, both are null but I have still declared the LED in this transmitter code for later on as a power indicator.

The Goal - to set off the PIR in one unit (transmitter) & make the LED flash in the recieving unit.

So I set about copying & modifying some code to make it happen.

This is where I'm at ATM with the transmitter unit.

#include <ESP8266WiFi.h>
#include <espnow.h>

uint8_t receiverMac[] = {"c8:c9:a3:14:5c:f5"}; // CHANGE THIS
const int PIRPin = D2;
const int LEDPin = D6;

int motionStatus = 0;
int PIRState = 0;

void setup() {
  pinMode(PIRPin, INPUT);
  WiFi.mode(WIFI_STA);

  Serial.begin (9600);

  if (esp_now_init() != 0) {
    Serial.println("ESP-NOW init failed");
    return;
  }

  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  esp_now_add_peer(receiverMac, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
}

void loop() {
  uint8_t value = digitalRead(PIRPin);
  if (PIRPin == 1);
  esp_now_send ("Motion detected"); //Error here somewhere
  Serial.println ("Motion detected"); 
  delay(50);
}

I'm getting this error message that I dont understand

Compilation error: invalid conversion from 'const char*' to 'u8*' {aka 'unsigned char*'} [-fpermissive]

What the hell is a char?
I wasnt planning on a BBQ? :slightly_frowning_face:

Mick.

uint8_t receiverMac[] = { 'c8:c9:a3:14:5c:f5' };  // CHANGE THIS

Single quotation marks are used with single characters, ie chars

Try this instead

uint8_t receiverMac[] = { "c8:c9:a3:14:5c:f5" };  // CHANGE THIS

to send the string

    esp_now_send("Motion detected");  //Error here somewhere

Check the parameters needed when calling the esp_now_send() function

    Serial.Write("Motion detected");  // Error here somewhere

Check the name of the function that you are calling as what you used is wrong

Fix those problems and others of a similar nature

Yeah, thx.
already picked up on the serial.println mistake & sorted that one.

Parethasis changed but still getting this char error & the esp_send line error:-

Compilation error: invalid conversion from 'const char*' to 'u8*' {aka 'unsigned char*'} [-fpermissive]

Mick.

Can I suggest that you look at the examples in Getting Started with ESP-NOW (ESP8266 NodeMCU with Arduino IDE) | Random Nerd Tutorials

That is some good stuff right there, thankyou!
Several hours of mental torture in that! :+1:

Mick.

In the error report, the line number and column of the start of the error will be given.

void setup() {
  Serial.begin(115200);
  Serial.print("Hello, World!");
  x = 1; // intentional error
}

void loop() {
}

In this sketch, the error is in the sketch_feb8a.ino file, on line 4 column 3, where "x" is used, but not previously declared.

C:\Users\user\AppData\Local\Temp\.arduinoIDE-unsaved202618-16224-172ufjt.78mo\sketch_feb8a\sketch_feb8a.ino: In function 'void setup()':
C:\Users\user\AppData\Local\Temp\.arduinoIDE-unsaved202618-16224-172ufjt.78mo\sketch_feb8a\sketch_feb8a.ino:4:3: error: 'x' was not declared in this scope
   x=1;
   ^
exit status 1

Compilation error: 'x' was not declared in this scope

Yeah I did look at the entire error message but all gobledygook to me.

Any way, have gone away from the previous coding now thx to Helibobs link above.
(Thankyou, very helpful)

I do have a question or two on it though (of course)

Working on the "many to one" Tutorial here - ESP-NOW: Receive Data from Multiple ESP8266 Boards (many-to-one) | Random Nerd Tutorials

It sets up a couple of variables here.
The id is obvious.

// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
    int id;
    int x;
    int y;
} struct_message;

// Create a struct_message called test to store variables to be sent
struct_message myData;

Variables shown as X & Y

I have only one variable to be sent - Sensor = HIGH/LOW.

Does this mean I should remove the ( int y; ) variable?

The only function it has to transmit is the PIRState.

Regards, Mick.

Using a struct to hold the data is useful when you want to send multiple variables, even variables of different types, but if you want to send only a single value then the struct is not required. Simple send that variable.

If you want to make as few changes to the example code as possible then you can still use a struct by deleting any unused variables from it at both ends of the link

If you want more help then please post the full sketches here, using code tags when you do

Thx for the help.

Current code, compiling without error (so far)
Ive changed a couple of variables, added in my pinmodes for the PIR & LED indicator light with the digitalWrite for this at the end.

Added in a few Questions in areas Im still unsure of ATM.

Board 1 Sender


#include <ESP8266WiFi.h>
#include <espnow.h>

// REPLACE WITH RECEIVER MAC Address
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //Do not have this board yet.

// Set your Board ID (ESP32 Sender #1 = BOARD_ID 1, ESP32 Sender #2 = BOARD_ID 2, etc)
#define BOARD_ID 1

// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
    int id;
    int x;
    int y; // Remove this line?
} struct_message;

// Create a struct_message called test to store variables to be sent
struct_message myData;

unsigned long lastTime = 0;
unsigned long timerDelay = 10000;

const int PIRPin = D2;
const int LEDPin = D6;

// Callback when data is sent
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
  Serial.print("\r\nLast Packet Send Status: ");
  if (sendStatus == 0){
    Serial.println("Delivery success");
  }
  else{
    Serial.println("Delivery fail");
  }
   
}
 
void setup() {
  // Init Serial Monitor
  Serial.begin(9600);
  pinMode(D2, INPUT); // Captures signal from the PIR sensor
  pinMode(D6, OUTPUT); //LED output for the "power on" indicator LED
 
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();

  // Init ESP-NOW
  if (esp_now_init() != 0) {
    Serial.println("Error initializing ESP-NOW");
    return;
  } 
  // Set ESP-NOW role
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);

  // Once ESPNow is successfully init, we will register for Send CB to
  // get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);
  
  // Register peer
  esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);

}
 
void loop() {
  //Should there be a digitalRead line here - digitalRead (PIRPin)?
  if ((millis() - lastTime) > timerDelay)
  //Should there be a "PIRPin == HIGH" command line here?
 {
    // Set values to send
    myData.id = BOARD_ID;
    myData.x = random(1, 50); //Is this similar to a didgitaWrite line? Should this be "mydata.x = PIRState"
    myData.y = random(1, 50); // Do I remove this one?

    // Send message via ESP-NOW
    esp_now_send(0, (uint8_t *) &myData, sizeof(myData));
    lastTime = millis();
  }
  {  digitalWrite(D6, HIGH);  // turn the LED on (HIGH is the voltage level)
  delay(500);                      // wait for a half second
  digitalWrite(D6, LOW);   // turn the LED off by making the voltage LOW
  delay(2000);                      // wait for 2 seconds}
}
}

In order to answer the questions in your code please explain what you want to transmit and what triggers the transmission

I assume that you want to transmit something to indicate that the PIR has been triggered rather than constantly transmitting the PIR state. Is that correct ?

Yes.
If I were to do it as if it were hard wired to a UNO or similar, I would be picking up the digitalRead from the PIR sensor & using that as a digitalWrite on the slave board.

In laymans terms -
If
PIR = HIGH
Send

Else
Do nothing.
(excluding the LED power Indicator which is just a constant Loop, locally. ie not sent over the WiFi)

Thx, Mick.

Does the PIR go HIGH when trigger or does it go LOW ? Is there anything keeping it in its untriggered state under normal circumstances ?

It is normally LOW.
Only goes HIGH when triggered & stays high for one second (adjustable)

No different to a n/o push button switch.

It is a HC-SR501 sensor - https://core-electronics.com.au/modmypi-pir-infrared-motion-sensor-hc-sr501.html?gad_source=1&gad_campaignid=17417005429&gbraid=0AAAAADlEpP4UmlAQVab8bdGWOy_LEUEMX&gclid=Cj0KCQiAy6vMBhDCARIsAK8rOgnIkC2GnN8ywvG4UN_NnJbm7RyGnCWBvYcatB5UEvHOjrRkwhen3tMaAp3fEALw_wcB

Mick.

Here is a version of the code with minimal changes that still uses a struct even though there is only a single data item. I cannot test it but it compiles OK

#include <ESP8266WiFi.h>
#include <espnow.h>

// REPLACE WITH RECEIVER MAC Address
uint8_t broadcastAddress[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };  //Do not have this board yet.

// Set your Board ID (ESP32 Sender #1 = BOARD_ID 1, ESP32 Sender #2 = BOARD_ID 2, etc)
#define BOARD_ID 1

// Structure example to send data
// Must match the receiver structure
struct struct_message
{
    int PIRState;
} message;

// Create a struct_message called test to store variables to be sent
struct_message myData;

unsigned long lastTime = 0;
unsigned long timerDelay = 10000;

const int PIRPin = D2;
const int LEDPin = D6;

// Callback when data is sent
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus)
{
    Serial.print("\r\nLast Packet Send Status: ");
    if (sendStatus == 0)
    {
        Serial.println("Delivery success");
    }
    else
    {
        Serial.println("Delivery fail");
    }
}

void setup()
{
    // Init Serial Monitor
    Serial.begin(9600);
    pinMode(D2, INPUT);   // Captures signal from the PIR sensor
    pinMode(D6, OUTPUT);  //LED output for the "power on" indicator LED

    // Set device as a Wi-Fi Station
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();

    // Init ESP-NOW
    if (esp_now_init() != 0)
    {
        Serial.println("Error initializing ESP-NOW");
        return;
    }
    // Set ESP-NOW role
    esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);

    // Once ESPNow is successfully init, we will register for Send CB to
    // get the status of Trasnmitted packet
    esp_now_register_send_cb(OnDataSent);

    // Register peer
    esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
}

void loop()
{
    static byte prevPirState = LOW;
    byte currentPirState = digitalRead(PIRPin);  //get current PIR state

    if (currentPirState != prevPirState && currentPirState == HIGH)  //PIR state has changed and become triggered
    {
        message.PIRState = currentPirState;
        esp_now_send(0, (uint8_t *)&message, sizeof(message));
    }
    prevPirState = currentPirState;
}

Obviously you need to make corresponding changes to the receiver code to match the data being sent

As I said before, for a single data item you do not need to use a struct but maybe try this first

Thx, & yeah, Id like to simplify it as much as possible but I'll come back to that once I/we have it working.

So we are reading the state change & only sending once it changes from Low to High.
Then the message to be sent is the current state which should show up at the other end as "HIGH"

Then the last bit - "prevPirState = currentPirState;" Shuts it down again, yeah?

I did look at the reciever code earlier & begin to add in my variables.......Holy Crap! That one is going to be a challenge.
Two Masters into the one slave, & the slave is going to have to assign different tracks on an Mp3 player depending on which master it is recieving from.

Anyway, Thx for your help thus far, it has been very helpful after a fortnight tearing my hair out with misguided info prior. :+1:

Mick.

No. The message struct has an int variable named PIRState so what you will get at the receiver is an int variable with a value of 1 when the PIR becomes triggered. This is much easier to detect than a string

Nothing is actually shut down as such. By setting the prevPirState to the current state we are preventing detection of the PIR being triggered until it happens again

We are not affecting the actual state of the PIR

Yep.
That's pretty much what I meant on both counts.

HIGH being the same as a value of 1.

And shutting it down as in ending the send , not the PIRState.

Learning all the way, Thx. :+1:

Mick.

The reason that I queried your previous statement about what was received was because you said that it would be "HIGH", which to me is a string, not an integer, and I didn't want there to be any confusion