Switching Neopixel with ESP8266 and Arduino

Hello all!

Project description
I am currently working on a simple project regarding a 60-LED WS2812 strip which is switched on and off remotely by using an ESP8266 and an iPhone.

Aim
The goal of my project is to turn on the LED-strip with my iPhone which is connected to my home LAN using an ESP8266 and an Arduino Nano. The sketch on the Arduino will result in the LED-strip displaying a nice rainbow pattern.

How it intended to work
The ESP8266 is programmed to display a tiny web server on a dedicated IP-address, which enables me to turn the strip on or off. When switched, one of the GPIO pins from the ESP8266 turns to HIGH and turns on the LED in optocoupler. The transistor on the other side of the opto is connected to an input pin on the Arduino, which in turn sets the Arduino pin to a LOW state. Now the program for the led strip will have to run.

Problem
The problem is that I have tried if and while statements on different locations in the sketch, to no avail. Eventually I got the strip to turn on by switching the Arduino pin to LOW, but the program seems to continue looping, even when the Arduino pin is returned to the HIGH state.
Of course I have done some searching on Google/Arduino forum. But almost every topic seems to discuss the ability to switch between different programs.

Question
My question is fairly straight forward. I am seeking advice on how to change my sketch so it switches the strip on and completely off if an input pin is switched from for example HIGH to LOW.

Schematic


#include <Adafruit_NeoPixel.h>

const int ledPin = 8;     //pin van Arduino voor Neopixel
const int numLeds = 60;

int optoPin = 12; //input pin van opto
int val = 0;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(numLeds, ledPin, NEO_GRB + NEO_KHZ800);


void setup() {
  pinMode(optoPin, INPUT); //INPUT
  digitalWrite(optoPin, HIGH); //PULLUP
  Serial.begin(9600);
  strip.begin();
  strip.setBrightness(240); // 80 is 1/3 brightness
  
}

void loop() {
  val = digitalRead(optoPin);
  while (val == LOW)
  {
    rainbow(30);
    delay(10);
  }
}

void rainbow(uint8_t wait) {
  uint16_t i, j;
  for (j = 0; j < 256; j++) {
    Serial.println ("j");
    Serial.println (j);
    for (i = 0; i < strip.numPixels(); i++) {
      Serial.println ("i");
      Serial.println (i);
      strip.setPixelColor(i, Wheel((i * 1 + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}



// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if (WheelPos < 85) {
    return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  }
  else if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  else {
    WheelPos -= 170;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

//pixels.clear(); // Set all pixel colors to 'off'

To answer your question, you have created an infinite loop. Ask yourself why would your loop ever end?

I have a question for you. Why are you using a Nano? Why are you using an opto? Why are you not driving the strip with the esp? You seem to be making the project more complex than it should be.

PaulRB:
To answer your question, you have created an infinite loop. Ask yourself why would your loop ever end?

I have a question for you. Why are you using a Nano? Why are you using an opto? Why are you not driving the strip with the esp? You seem to be making the project more complex than it should be.

Thank you for your reply!

I've used the sketch included in the Adafruit Neopixel library, so I wasn't aware of the loop being infinite. Would there be any way to stop it at a given moment/condition?

Good question. The reason I used a combination of the ESP8266 and the Nano that had them both laying around and readily programmed. I thought it would be a simple task to combine the two and slightly modifying the existing sketch. Other than that, i'm not sure the Neopixel strip will work by the 3.3v output from the ESP8266. Surely there must be a way to fix that though, but we're here now anyway :).

The infinite loop is the while( val == low )
Once you enter that loop you never read optoPin again. There is no way out.

boolrules:
The infinite loop is the

while( val == low )

Once you enter that loop you never read optoPin again. There is no way out.

I understand...

I've changed a small part of the sketch as shown below. Am I correct if it will now loop 30 times before reading the optoPin again?
That would be quite inconvenient. I'm looking for a more efficient solution.

void loop() {
  val = digitalRead(optoPin);
  if (val == LOW)
  {
    rainbow(30);
    delay(10);
  }
  else strip.clear();
}

Not 30 times. That's not what the "30" means. Do you understand about functions and parameters? The function is called "rainbow". The parameter is 30. If you look at the definition of the function, you can see that, inside the function, the parameter is referred to as "wait". Have a look where "wait" is used inside the function. It's not used to control how many repeats the loops inside the function perform. They all repeat a fixed number of times, or based on the number of LEDs in your strip. "wait" is only used in the delay() call.

So the rainbow(30) call will take 256 x 30ms which is 7680ms or about 7.6 seconds. And so optoPin will be read every 7.6s. Is that ok?

You are correct to ask if the strip will work if the data signal coming directly from the esp is only 3.3V. The answer is maybe. Try it and see. You may find it works ok, or maybe not at all, or maybe it works unless you touch the circuit with your finger. If it does not work, is easy to fix with a 74hc14 or 74hct14. These chips are cheap, easy to use and don't need to be programmed, unlike Nano. But using Nano like you are doing is just a waste of the Nano.

My next question would be how are you powering the esp? If you are using the Nano's 3.3V pin, this is unsuitable and will soon damage the Nano. The esp needs far more current, at 3.3V, then the Nano can provide.

Another question is - why do you wish to turn off the power to the WS2812 strip? Do you propose to operate this from battery power - in which case there are quite a few design concerns?

The quiescent current of a 60 LED WS2812 strip is approximately 60 mA. If you are running from mains power, it is simply nonsensical to be concerned about saving 300 mW of power draw as your other parts - including the power supply itself - will be consuming as much or more. You just set all the LEDs to black and they are - dark! :roll_eyes:

PaulRB:
Not 30 times. That's not what the "30" means. Do you understand about functions and parameters? The function is called "rainbow". The parameter is 30. If you look at the definition of the function, you can see that, inside the function, the parameter is referred to as "wait". Have a look where "wait" is used inside the function. It's not used to control how many repeats the loops inside the function perform. They all repeat a fixed number of times, or based on the number of LEDs in your strip. "wait" is only used in the delay() call.
So the rainbow(30) call will take 256 x 30ms which is 7680ms or about 7.6 seconds. And so optoPin will be read every 7.6s. Is that ok?

You are correct to ask if the strip will work if the data signal coming directly from the esp is only 3.3V. The answer is maybe. Try it and see. You may find it works ok, or maybe not at all, or maybe it works unless you touch the circuit with your finger. If it does not work, is easy to fix with a 74hc14 or 74hct14. These chips are cheap, easy to use and don't need to be programmed, unlike Nano. But using Nano like you are doing is just a waste of the Nano.
My next question would be how are you powering the esp? If you are using the Nano's 3.3V pin, this is unsuitable and will soon damage the Nano. The esp needs far more current, at 3.3V, then the Nano can provide.

Again, many thanks for your reply and your help.

I‘m actually still quite new to programming, so my understanding of functions and parameters is not that well. I have some more reading to do, thanks for the brief explanation!

7.6 seconds is acceptable, but I’d still like it to turn completely off afterwards. Somehow my sketch was unable to turn off the strip completely. It seems to remain ‘stuck’ somewhere. Strip.clear(); doesn’t seem to cut it.

TTL IC’s is what I’m used to working with, so your suggestion of only using the ESP and a Schmitt trigger is becoming quite at the moment.

Getting back to your question, The ESP is being powered by a cheap AMS1117. I’ve measured the ESP at around 40mA, while the AMS is able to deliver a maximum of 800mA according to the datasheet The LED strip is receiving 5v from a simple buck converter, as its measured current draw has an average of around 700mA.

Paul__B:
Another question is - why do you wish to turn off the power to the WS2812 strip? Do you propose to operate this from battery power - in which case there are quite a few design concerns?

The quiescent current of a 60 LED WS2812 strip is approximately 60 mA. If you are running from mains power, it is simply nonsensical to be concerned about saving 300 mW of power draw as your other parts - including the power supply itself - will be consuming as much or more. You just set all the LEDs to black and they are - dark! :roll_eyes:

Thanks for your reply.

It’s actually not that I want to cut the power to the strip, but send a signal to it, so the LED’s turn off (black :slight_smile: ). Otherwise I might have considered using a relay. The projects is powered off a 1A 12v AC/DC adapter, so luckily no hassle with batteries. You’re right, saving 300mW would be nonsense.

Turning the LED’s to black is exactly what I want to achieve when the optoPin has changed state, but it just doesn’t seem to happen. Any suggestions/advice/tips?

Klavkjir:
It seems to remain ‘stuck’ somewhere. Strip.clear(); doesn’t seem to cut it.

Try Strip.show() after Strip.clear().

Klavkjir:
The ESP is being powered by a cheap AMS1117...

OK, that's fine. Many beginners try to power esp from the 3.3V pin of Nano, which has a very low current capability (from a regulator internal to the USB-serial chip).

I'm surprised your esp draws only 40mA. I would have expected around 80mA.

PaulRB:
Try Strip.show() after Strip.clear().OK, that's fine. Many beginners try to power esp from the 3.3V pin of Nano, which has a very low current capability (from a regulator internal to the USB-serial chip).

I'm surprised your esp draws only 40mA. I would have expected around 80mA.

Thanks! I'll try adding Strip.clear() and Strip.show() after the else statement.

I've read that the ESP8266 needs a dedicated power supply for it to function reliabily. I've already encountered several connection issues with this board, so I hope these issues will be of the past.

Not necessarily a dedicated supply. Just an adequate supply. Many beginners haven't understood the concepts of current yet, let alone regulator power dissipation. They just think if a supply is 3.3V, that must be perfect for esp.