jandelgado / jled

Non-blocking LED controlling library for Arduino and friends.
MIT License
324 stars 51 forks source link

How to control 15 gpio pins #119

Closed aGGreSSiv closed 5 months ago

aGGreSSiv commented 11 months ago

Since I am not a software developer, it is difficult for me to control 15 LED strips connected to different GPIOs of ESp32. For better or worse, I managed to do this, but for a programmer, the long code below could have been much shorter.. In addition, I tried to run it with the codes under the "Controlling a group of LEDs" title in order not to introduce each led strip separately, but I could not succeed.

Stair tread lighting that has no unusual design, and has been applied in many ways. In essence, there is a sensor at both the beginning and the end of the steps. With the trigger of the sensor, the LEDs start to turn on in fade effect and sequence. As I said, the code works, I just wanted to ask how it could be cleaner to improve myself.

// https://github.com/jandelgado/jled
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <TimeLib.h>
#include <WidgetRTC.h>
#include <jled.h>

auto led1 = JLed(12);
auto led2 = JLed(13);
auto led3 = JLed(14);
auto led4 = JLed(25);
auto led5 = JLed(26);
auto led6 = JLed(27);
auto led7 = JLed(32);
auto led8 = JLed(33);
auto led9 = JLed(19);
auto led10 = JLed(23);
auto led11 = JLed(18);
auto led12 = JLed(5);
auto led13 = JLed(17);
auto led14 = JLed(16);
auto led15 = JLed(4);

bool flagState = false;
bool virtualState = false;

String newHostname = "Deneme";
const char* ssid = "barisea";
const char* pass = "xxx";
int ReCnctFlag;       // Reconnection Flag
int ReCnctCount = 0;  // Reconnection counter

bool isFirstConnect = true;
char auth[] = "xxxx";
char server[] = "192.168.1.2";  // IP for Local Cloud Server
int port = 8080;

int sensorPin = 15;
int sensorNewState;
bool upTrigger = false;
bool downTrigger = false;

int maxB = 255;
int minB = 0;

BlynkTimer timer;
WidgetRTC rtc;

unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
long interval = 9000;

BLYNK_WRITE(V27) {
  maxB = param.asInt();
}

BLYNK_WRITE(V28) {
  minB = param.asInt();
}

BLYNK_WRITE(V25) {

  virtualState = param.asInt();
  if (virtualState == 1 & flagState == 0) {  // Run only if Switch ON and Flag set to 0
    flagState = 1;                           // Set flag to prevent multiple occurrences.
    led1.Fade(0, maxB, 200).DelayBefore(100);
    led2.Fade(0, maxB, 200).DelayBefore(200);
    led3.Fade(0, maxB, 200).DelayBefore(300);
    led4.Fade(0, maxB, 200).DelayBefore(400);
    led5.Fade(0, maxB, 200).DelayBefore(500);
    led6.Fade(0, maxB, 200).DelayBefore(600);
    led7.Fade(0, maxB, 200).DelayBefore(700);
    led8.Fade(0, maxB, 200).DelayBefore(800);
    led9.Fade(0, maxB, 200).DelayBefore(900);
    led10.Fade(0, maxB, 200).DelayBefore(1000);
    led11.Fade(0, maxB, 200).DelayBefore(1100);
    led12.Fade(0, maxB, 200).DelayBefore(1200);
    led13.Fade(0, maxB, 200).DelayBefore(1300);
    led14.Fade(0, maxB, 200).DelayBefore(1400);
    led15.Fade(0, maxB, 200).DelayBefore(1500);
    flagState = 0;  // Reset flag
    downTrigger = true;
  } else {
    led1.Fade(200, minB, 200).DelayBefore(1500);  
    led2.Fade(200, minB, 200).DelayBefore(1400); 
    led3.Fade(200, minB, 200).DelayBefore(1300);
    led4.Fade(200, minB, 200).DelayBefore(1200);
    led5.Fade(200, minB, 200).DelayBefore(1100);
    led6.Fade(200, minB, 200).DelayBefore(1000);
    led7.Fade(200, minB, 200).DelayBefore(900);
    led8.Fade(200, minB, 200).DelayBefore(800);
    led9.Fade(200, minB, 200).DelayBefore(700);
    led10.Fade(200, minB, 200).DelayBefore(600);
    led11.Fade(200, minB, 200).DelayBefore(500);
    led12.Fade(200, minB, 200).DelayBefore(400);
    led13.Fade(200, minB, 200).DelayBefore(300);
    led14.Fade(200, minB, 200).DelayBefore(200);
    led15.Fade(200, minB, 200).DelayBefore(100);
    downTrigger = false;
  }
}

BLYNK_WRITE(V26) {
  if (param.asInt()) {
  }
}

BLYNK_CONNECTED() {  //Start Blynk connection
  rtc.begin();
  ReCnctCount = 0;
  if (isFirstConnect) {
    Blynk.syncAll();
    Serial.println("Blynk.synced");
    isFirstConnect = false;
  }
}

void setup() {
  Serial.begin(115200);
  WiFi.hostname(newHostname.c_str());
  WiFi.begin(ssid, pass);
  Blynk.config(auth, server, port);
  Blynk.connect();
  setSyncInterval(60);
  timer.setInterval(100L, checkLights);
  attachInterrupt(sensorPin, sensorButtonPressed, RISING);
}

void sensorButtonPressed() {
  Serial.println("sensorButtonPressed");
  int sensorNewState = digitalRead(sensorPin);
  if (sensorNewState == HIGH) {
    previousMillis = currentMillis;
    if (downTrigger == false) {
      upTrigger = true;
    }
  }
  return;
}

void loop() {
  timer.run();
  currentMillis = millis();
  //sensorNewState = digitalRead(sensorPin);

  led1.Update();
  led2.Update();
  led3.Update();
  led4.Update();
  led5.Update();
  led6.Update();
  led7.Update();
  led8.Update();
  led9.Update();
  led10.Update();
  led11.Update();
  led12.Update();
  led13.Update();
  led14.Update();
  led15.Update();

  if (sensorNewState == HIGH) {
  }

  if (upTrigger == true) {
    Blynk.virtualWrite(V25, 1);
    Blynk.syncVirtual(V25);
    upTrigger = false;
  }

  if ((currentMillis - previousMillis >= interval) && (downTrigger == true)) {
    Blynk.virtualWrite(V25, 0);
    Blynk.syncVirtual(V25);
  }

  if (Blynk.connected()) {  // If connected run as normal
    Blynk.run();
  } else if (ReCnctFlag == 0) {  // If NOT connected and not already trying to reconnect, set timer to try to reconnect in 30 seconds
    WiFi.disconnect();
    WiFi.hostname(newHostname.c_str());
    WiFi.begin(ssid, pass);
    ReCnctFlag = 1;  // Set reconnection Flag
    Serial.println("Starting reconnection timer in 30 seconds...");
    timer.setTimeout(5000L, []() {  // Lambda Reconnection Timer Function
      ReCnctFlag = 0;               // Reset reconnection Flag
      ReCnctCount++;                // Increment reconnection Counter
      Serial.print("Attempting reconnection #");
      Serial.println(ReCnctCount);
      Blynk.connect();  // Try to reconnect to the server
    });                 // END Timer Function
  }
}

void checkLights() {
}
jandelgado commented 11 months ago

hi @aGGreSSiv , have a look at the multiled example, where multiple LEDs are stored in an array . In your case you could simplify the code to (excerpts):

JLed leds[] = {
  JLed(12),
  JLed(13),
  JLed(14),
  JLed(25), 
  JLed(26),
  JLed(27),
  JLed(32),
  JLed(33),
  JLed(19),
  JLed(23),
  JLed(18),
  JLed(5),
  JLed(1),
  JLed(16),
  JLed(4)
};

auto sequence = JLedSequence(JLedSequence::eMode::PARALLEL, leds);
....

BLYNK_WRITE(V25) {

  virtualState = param.asInt();
  if (virtualState == 1 & flagState == 0) {  // Run only if Switch ON and Flag set to 0
    flagState = 1;                           // Set flag to prevent multiple occurrences.
    auto delay = 100;
    for(auto &led: leds) {
      led.Fade(0, maxB, 200).DelayBefore(delay);
      delay += 100;
    }
    flagState = 0;  // Reset flag
    downTrigger = true;
  } else {
    auto delay = 1500;
    for(auto &led: leds) {
      led.Fade(0, minB, 200).DelayBefore(delay);
      delay -= 100;
    }
    downTrigger = false;
  }
}

...

void loop() {
...
   sequence.Update();
...
}
aGGreSSiv commented 11 months ago

Thank you for the help.

I think we used the delay command for the fade effect and all of them are opened or closed in the same time. I will set up my test environment again shortly. I will try again so that each led turns on or off one after the other. I will try to do the next part to improve myself, if I fail, I will ask for help.

Maybe I didn't fully understand. led.Fade(0 part turns off all the LEDs in the array, while the transition delay to the next LED in the array?

aGGreSSiv commented 10 months ago

Hello. I had a chance to test the code today. Thank you for the help. When I tried it with the hardware, I understood better.. Some of the features I wanted were asked by others, I will try them too.

aGGreSSiv commented 9 months ago

Hello again. I thought I had tried the code you shared, but when I checked, it turned out that I had uploaded my old code. Now, when I try your post, whenever I press the button, the microprocessor reboots itself by giving a Kernal Panic warning. (I use lolin d32 Pro.)

attachInterrupt(sensorPin, sensorButtonPressed, RISING);

When I cancel this line and try to constantly check the button pins with a small delay in the loop, I do not get the kernal panic error, but the LEDs do not light even though I see that I pressed the button on the terminal screen.

This part is an observation about my own code: Initially, I connected only 8 of the 15 Outputs for testing. Yesterday, I connected LEDs to the outputs of all of them and I noticed that if I try the GPIOs one by one with the sample files, there is no problem. But if I try all of them at the same time with my code I shared above, when the 1st LED is on, the 9th LED is also on. When the 2nd lights up, the 10th lights up too... and so on. I think I'm causing a problem with the number of PWM channels with my own code. WhatsApp Görsel 2023-10-10 saat 12 05 42_d4f2cd4f

WhatsApp Görsel 2023-10-10 saat 12 05 42_f9f56cb1

aGGreSSiv commented 9 months ago

Hello again, This is the last time I tried it in its cleaned form.

#include <jled.h>

static uint8_t maxB = 255;
static uint8_t minB = 0;

JLed leds[] = {
  JLed(12),
  JLed(13),
  JLed(14),
  JLed(25),
  JLed(26),
  JLed(27),
  JLed(32),
  JLed(33),
  JLed(19),
  JLed(23),
  JLed(18),
  JLed(5),
  JLed(1),
  JLed(16),
  JLed(4),
};
auto sequence = JLedSequence(JLedSequence::eMode::PARALLEL, leds);

int sensorPin = 15;
int sensorNewState;

void setup() {
  Serial.begin(115200);
}

void loop() {
  sensorNewState = digitalRead(sensorPin);
  if (sensorNewState == HIGH) {
    auto delay = 100;
    for (auto &led : leds) {
      led.Fade(0, maxB, 200).DelayBefore(delay);
      delay += 100;
    }
    Serial.println("HIGH");
  } else {
    auto delay = 1500;
    for (auto &led : leds) {
      led.Fade(0, minB, 200).DelayBefore(delay);
      delay -= 100;
    }
    Serial.println("LOW");
  }
  sequence.Update();
  delay(1);
}
jandelgado commented 8 months ago

@aGGreSSiv , sorry for the late response, overlooked this one. I think the problem is in the loop function, it is basically:

void loop() {
  ... 
  if (sensorNewState == HIGH) {
    // set LEDs to  led.Fade(0, maxB, 200).DelayBefore(delay);
  } else {
      // set LEDs to led.Fade(0, minB, 200).DelayBefore(delay);
  }
  sequence.Update();
}

So since it is an if-then-else block, in every iteration the LEDs will be re-initialized, since in either case Fade is called. What you actually need is to re-initialize only when the button state changes, like:

void loop() {
 static int sensorLastState = -1;
  ... 
  if (sensorNewState == HIGH && sensorLastState != sensorNewState) {
    sensorLastState = sensorNewState;
    // set LEDs to  led.Fade(0, maxB, 200).DelayBefore(delay);
  } else 
  if (sensorNewState == LOW && sensorLastState != sensorNewState) {
  {
       sensorLastState = sensorNewState;
      // set LEDs to led.Fade(0, minB, 200).DelayBefore(delay);
  }
  sequence.Update();
}

See also https://github.com/jandelgado/jled/issues/92#issuecomment-1082325999 for an example using a Button library.

aGGreSSiv commented 8 months ago

Hello, It is important to me that you answered. I looked at the button example. I think I understand what you mean. I haven't replaced the circuit I made yet, I will try again according to your warning.

Thank you.

github-actions[bot] commented 5 months ago

This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 5 days