2x ESP32 synchronising LED effect code

Hi all.
I am not a programmer, and my programming knowledge is pretty much depleted when I insert some LED effects code or a little bit of modification of those.
I really would like to do a project where I need 2 ESP32 boards with LED effects (effects are ready), and they should be running in parallel, synchronised through the BT. If the secondary board is not getting any signal from the server board - BT drops etc - still carry on the LED effects. When the BT signal is back, it would synchronize itself and both LED effects would run parallel again. I want it fully automatic, so when both boards are switched on, doesn't matter which one first, eventually they would be synchronised.
Could someone please help with this? ChatGP is not so good in that, and I had some problems, but time, what I don't have :frowning: I cannot play with it.
1000 Thx! :slight_smile:

Start by posting your best effort, or at least ChatGPT's best effort, and describe what is wrong

Please use code tags when you post the code

Something like this? (click)
They are using ESPNow.
Leo..

Explain how you are synchronising, I do not have a clue as to what "BT"
is.

Can you post your annotated schematic showing all connections. Be sure to include power, ground and note any wires over 10"/25cm.

I am not sure what is wrong with it, I couldn't really try it out yet, but I can start with the second line.
There is no such file in the installed library. If I reach the point when the code would compile I would build the ESPs. However, ChatGP tried to explain to me some more to do to set up Bluetooth...
What I didn't get even didn't care at that point because of this library problem... I like to sort the things step by step.
I have read about ChatGp and somehow is good but some say it is not so good for programming.
I just want the described action, because ESP32s I have home.

#include <BLEDevice.h>
#include <BLEServer.h> // THAT IS NOT AVAILALBE in the library! 
#include <BLEUtils.h>
#include <BLE2902.h>

// LED control pins
# define SIZE 10
byte pins[10] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

# define t0  50
# define t1  400
# define t2  800

// UUIDs for BLE characteristics and services
#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;

// LED chasing effect function
 // I have just put something here quickly... that part is not important at this moment.
void ledChasingEffect() {
 
  for (int ix = 0; ix < SIZE; ix++) {
    byte K = SIZE - 1;

    for (int iy = 0; iy < SIZE - ix; iy++) {
      digitalWrite(pins[K - iy], HIGH);
      delay(t0);
      digitalWrite(pins[K - iy], LOW);
    }

    digitalWrite(pins[ix], HIGH);
    delay(t1);
  }
  delay(t2);


 for (int ix = 0; ix < SIZE; ix++) {
    byte K = ix - 1;

    digitalWrite(pins[ix], LOW);

    for (int iy = 0; iy < ix; iy++) {
      digitalWrite(pins[K - iy], HIGH);
      delay(t0);
      digitalWrite(pins[K - iy], LOW);
    }

    delay(t1);
  }
  delay(t2);
}


class MyServerCallbacks : public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};

void setup() {
  Serial.begin(115200);
  Serial.println("for loop version N\n");

  for (int ix = 0; ix < SIZE; ix++)
    pinMode(pins[ix], OUTPUT);

  
  BLEDevice::init("ESP32");
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());
  BLEService *pService = pServer->createService(SERVICE_UUID);
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_READ |
                      BLECharacteristic::PROPERTY_WRITE |
                      BLECharacteristic::PROPERTY_NOTIFY |
                      BLECharacteristic::PROPERTY_INDICATE
                    );
  pService->start();
  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();
}

void loop() {


  if (deviceConnected) {
    // Synchronize LED effects with primary board
    ledChasingEffect(); // Call your LED effect function
  } else {
    // Continue LED effect independently
    ledChasingEffect(); // Call your LED effect function
  }

  // Update connection status
  if (!deviceConnected && oldDeviceConnected) {
    // Device disconnected
    // Perform any cleanup or reset necessary
  }
  oldDeviceConnected = deviceConnected;

  // Handle BLE events
  BLEDevice::handleEvents();
}

Yes, something similar.
2 ESP32, 10 LEDs hooked to the one board, 10 LEDs hooked to the other board.
The point is they should run the same LED effect codes separately but if they "see each other" the effects would run in perfect order, in other words: parallel.

BT means Bluetooth, sorry. Power and grounding are not the problem here, I am sorting that out. Electronics that I understand a bit more :smiley:
I just need a working code for 2 ESPs that are sync any code included in:
"void ledChasingEffect()"
When I switch the boards on - independently which one would be the first - they would see each other through Bluetooth and sync the LED effects. If they cannot see each other, LED effects would run anyway.

For my project - where I will use this - would be very nice if the LED effects on two subjects would run at the same time :smiley:

Data transfer is about 3MBps under ideal conditions. For sync I recommend using a RTC (Real Time Clock)of some form. You can get UTP time with the ESP parts quite easily and program the clock function/hardware from that. Then Have one send a command to start at the same time. then they both start at that time. This would remove the latency of the Bluetooth processing but start concurrently would be maybe a second in the future from when the command is sent. You did not state the same time tolerance so this is just a guess that might work.

Let one ESP32 send a number for each step your effect makes.
Let the second ESP32 sync on that number (or run at it's own speed, if the signal is missing).

With two ESP32 I would use ESP Now - or if you have a Wifi existing, send a UDP packet.

First step would be to make the effect NON - Blocking - without the usage of a delay().

An straight forward concept would be to let the sending ESP32 at least indicate when it starts the effect - an the second ESP32 to Restart its effect when the other ESP32 has indicated a start.

1 Like

Well, that sounds great! And partially I even understand it. I hope my ESP32 support this ESP Now function, but the docs say: "generic ESP32" supported. I am sure my one is not, but I don't know what it is!? As I mentioned I am not a programmer :smiley: I could NEVER done this :smiley:
The second thing and that gives you - and others - more idea, is that the boards would be on "vehicles". So they would be moving mostly. That means WIFI sync may not be the best idea. That's why I figured, BT is the solution. (I hope.)
Led effects. Well :smiley: They are fully loaded with Delay :smiley:

Isn't there any simple method - not a perfect one? I don't mind the perfect one, but again - I am not a programmer! :smiley: and even I don't fully understand the code that ChatGp created.
Any chance that would work? :smiley: Have you seen it? I pasted it above.
I doubt it, but who knows?
Thank you.

#define t   20
#define t1  40
#define t2  60
#define t3  80
#define t4  200
#define t5  500
#define t6  800
#define t7  1000

void setup() {
  // set up pins 2 to 11 as outputs
  for (int i = 2; i <= 11; i++) {
    pinMode(i, OUTPUT);
  }
}
//Effects setup
void loop()
{

//effect_change();

effect_1_fill_in_out();
effect_1_fill_in_out();
//effect_1_fill_in_out();
effect_change();
effect_1_fill_in_out_otherend();
effect_1_fill_in_out_otherend();
//effect_1_fill_in_out_otherend();
effect_change();
effect_2_chasing_with_vibration();
effect_2_chasing_with_vibration();
effect_change();
effect_3_LefFilltoRightAndBack();
effect_3_LefFilltoRightAndBack();
effect_change();
effect_4_chasing_with_vibration_negative();
effect_4_chasing_with_vibration_negative();
effect_change();
effect_5_police();
effect_5_police();
effect_5_police();
effect_5_police();
effect_5_police();
effect_5_police();
effect_change();
effect_6_RainDropp_Left();
effect_6_RainDropp_Left();
effect_6_RainDropp_Left();
effect_change();
effect_6_RainDropp_Right();
effect_6_RainDropp_Right();
effect_6_RainDropp_Right();
effect_change();

}

void effect_change()
{
  delay(t5);
  for (int i=2; i<=12; i++){
    digitalWrite(i, HIGH);
    }
    delay(t2);
  for (int i=2; i<=12; i++){
    digitalWrite(i, LOW);
    }
    delay(t2);
  //***  
  for (int i=2; i<=12; i++){
    digitalWrite(i, HIGH);
    }
    delay(t2);
  for (int i=2; i<=12; i++){
    digitalWrite(i, LOW);
    }
    delay(t2);
  //***
  for (int i=2; i<=12; i++){
    digitalWrite(i, HIGH);
    }
    delay(t2);
  for (int i=2; i<=12; i++){
    digitalWrite(i, LOW);
    }
    delay(t6);
}

//******** EFFECT 1 ********  
  void effect_1_fill_in_out()
{

// *** in ***
   for(int pinX = 2; pinX <= 11; pinX++) {
    for(int pin = 11; pin > pinX; pin--) {
      digitalWrite(pin, HIGH);
      delay(t3);
      digitalWrite(pin, LOW);
    }
    digitalWrite(pinX, HIGH);
  }
  delay(t4);

// *** OUT ***
  for(int pinX = 2; pinX <= 11; pinX++) {
    digitalWrite(pinX, LOW);
    for(int pin = pinX; pin >= 2; pin--) {
      digitalWrite(pin, HIGH);
      delay(t3);
      digitalWrite(pin, LOW);
    }
  }
  delay(t4);
  }

//******** EFFECT 1 - FROM OTHER END ********
void effect_1_fill_in_out_otherend()
{
// *** in ***
   for(int pinX = 11; pinX >= 2; pinX--) {
    for(int pin = 2; pin < pinX; pin++) {
      digitalWrite(pin, HIGH);
      delay(t3);
      digitalWrite(pin, LOW);
    }
    digitalWrite(pinX, HIGH);
  }
  delay(t4);

// *** OUT ***
  for(int pinX = 11; pinX >= 2; pinX--) {
    digitalWrite(pinX, LOW);
    for(int pin = pinX; pin <= 11; pin++) {
      digitalWrite(pin, HIGH);
      delay(t3);
      digitalWrite(pin, LOW);
    }
  }
  delay(t4);
}
//******** EFFECT 2 ********

void effect_2_chasing_with_vibration()
{
for(int i=2; i<12; i++){
digitalWrite(i, HIGH);
delay(t);
digitalWrite(i+1, HIGH);
delay(t);
digitalWrite(i+2, HIGH);
delay(t);
digitalWrite(i, LOW);
delay(t);
digitalWrite(i+1, LOW);
delay(t);
}
for(int i=11; i>1; i--){
digitalWrite(i, HIGH);
delay(t);
digitalWrite(i-1, HIGH);
delay(t);
digitalWrite(i-2, HIGH);
delay(t);
digitalWrite(i, LOW);
delay(t);
digitalWrite(i-1, LOW);
delay(t);
}

}

//******** EFFECT 3 ********

void effect_3_LefFilltoRightAndBack()
{
for(int i=2; i<12; i++){
  digitalWrite(i, HIGH);
  delay(t3);
}
delay(t5);
for(int i=2; i<12; i++){
  digitalWrite(i, LOW);
  delay(t3);
}
delay(t5);
for(int i = 12; i>=2; i--){
  digitalWrite(i, HIGH);
  delay(t3);
}
delay(t5);
for(int i = 12; i>=2; i--){
  digitalWrite(i, LOW);
  delay(t3);
}
delay(t5);
//delay(500);
}

//******** EFFECT 4 ********

void effect_4_chasing_with_vibration_negative()
{
  for(int i=2; i<=12; i++){
  digitalWrite(i, HIGH);  
  }
    for(int i=2; i<12; i++){
    digitalWrite(i, LOW);
    delay(t1);
    digitalWrite(i+1, LOW);
    delay(t1);
    digitalWrite(i+2, LOW);
    delay(t1);
    digitalWrite(i, HIGH);
    delay(t1);
    digitalWrite(i+1, HIGH);
    delay(t1);
    }
    for(int i=11; i>1; i--){
    digitalWrite(i, LOW);
    delay(t1);
    digitalWrite(i-1, LOW);
    delay(t1);
    digitalWrite(i-2, LOW);
    delay(t1);
    digitalWrite(i, HIGH);
    delay(t1);
    digitalWrite(i-1, HIGH);
    delay(t1);
    }

}

//******** EFFECT 5 ********

void effect_5_police(){

  for (int i=2; i<=6; i++){
    digitalWrite(i, HIGH);
    }
    delay(t3);
    for (int i=2; i<=6; i++){
    digitalWrite(i, LOW);
    }
    delay(t3);
    for (int i=2; i<=6; i++){
    digitalWrite(i, HIGH);
    }
    delay(t3);
    for (int i=2; i<=6; i++){
    digitalWrite(i, LOW);
    }
    delay(t3);
    for (int i=2; i<=6; i++){
    digitalWrite(i, HIGH);
    }
    delay(t3);
    for (int i=2; i<=6; i++){
    digitalWrite(i, LOW);
    }
    delay(t3);


    for (int i=7; i<=12; i++){
    digitalWrite(i, HIGH);
    }
    delay(t3);
    for (int i=7; i<=12; i++){
    digitalWrite(i, LOW);
    }
    delay(t3);
    for (int i=7; i<=12; i++){
    digitalWrite(i, HIGH);
    }
    delay(t3);
    for (int i=7; i<=12; i++){
    digitalWrite(i, LOW);
    }
    delay(t3);
    for (int i=7; i<=12; i++){
    digitalWrite(i, HIGH);
    }
    delay(t3);
    for (int i=7; i<=12; i++){
    digitalWrite(i, LOW);
    }
    delay(t3);

}

//******** EFFECT 3 ********

void effect_6_RainDropp_Left()
{
for(int i=2; i<12; i++){
  digitalWrite(i, HIGH);
  delay(t3);
}

for(int i=2; i<12; i++){
  digitalWrite(i, LOW);
  delay(t3);
}
}

void effect_6_RainDropp_Right()
{
for(int i = 12; i>=2; i--){
  digitalWrite(i, HIGH);
  delay(t3);
}
for(int i = 12; i>=2; i--){
  digitalWrite(i, LOW);
  delay(t3);
}
}

I think the first thing you must evaluate is what kind of transmission will work for the planned distance. But honestly I think a Wifi with a router on one of the vehicles will give you the best performance. Better than WIFI with one ESP in AP mode (or ESP Now) and BT comming last.

Regarding your delays. Imho there is no way around it you must remove them.. When you have an delay you BLOCK your code. The second ESP needs the possibility to "stop" an ongoing function and jump to the right function if the first ESP sends its sync to another function. Therefore you must get rid of your delays.

@noiasca The master board of ESPNow acts as a router, but without the layers of WiFi. That means faster than WiFi. It also has a much longer range.

I think OP should first concentrate on ESPNow. There are examples on the net that blink the onboard LED in unison on several ESPNow clients. There is your sync example. Then adding the LED effects should be easy.
Leo..

1 Like

Imho there is no "simple" way as long as you are using delay.

I would redo the effects and define frames/patterns. Then I have a long list of steps and can sync several nodes on to a specific pattern.

This should give you idea:

one ESP broadcasts it's position within the pattern list, the other can react on it.
When the connection gets losts, the second ESP still continues.

establish a common timebase, then things suddely get easy.

Thank you all, that idea does not sound bad at all. However, I never could accomplish such a complicated code. This is not what I am doing daily guys. True, I love to learn, but you have no idea how many different things I have learned and done in my life. (still doing) Would be even crazy to list them :smiley: It is obvious that no one is capable of learning everything. I don't think so I will be a programmer overnight. So I have to find someone who write this for me. It is worth me some euros if it would work well. :smiley: AI programmer modules are so suck.
I have tried black-box AI to remove delays from a simple LED effect, and it is not capable of doing that. 5 times it tried and always failed. :smiley: "AI here but don't be afraid of it just yet. :smiley: "

can you follow what the sketch in the wokwi simulator is doing or is that out of reach?

Yes, I have seen the simulator and watched it. Nice and the code is nice. But don't get me wrong, I want to understand, how does it help me to be a programmer and program down my requirements? :smiley: I so would like to do that, but I have mentioned already, I am not a programmer, I am working many different circuits currently, working as "working" (earning money :smiley: ) still here my house and my family, I do not have much time to LEARN and be a programmer overnight. Also, this project, won't be just a "project". It would be part of a project (projects) that I want to do for a living. (but mostly because I love it.) It is a bit crucial to be able to get a working code for this. (if I have to do it, well, that won't happen soon.) :frowning:

Well it shows you how to write non blocking code. And if you examine the code very carefully you will even find where you have to integrate the communication between the ESPs.

In general - learn from the examples you find in the internet.

If you want to get a working code, you could estimate how long it will take you, multiply this with the rate of your mechanician and make an request for paid support.

Thank you anyway. I will try what I can, but comparing "how long it will take me" with "how long it takes for a professional" is not fair :smiley:

Why not? It's your lifetime you put on one side and what that' worth for you on the other. Otherwise you would put the lifetime of "somebody else" on one side and what that' you think the lifetime of that "sombody" is worth for you on the other. Needless to say, that "somebody" will not agree with your calculation.