Stuck with GPT coding a Glow in the dark, Neopixel night lamp

I'm new to both Arduino and to this forum. This is my first post. I know there are plenty of posts regarding both generic leds, other libraries and neopixels but I'm not experienced enough to see the forest for just trees and piece something together. I expect nothing, but I would really appreciate any help possible.

I recently had a son, and got hold of glow in the dark PLA filament, which resulted in an idea to make a night lamp for him using parts I had laying around (Arduino Nano, 2x pushbuttons, and a ledstrip of 6x WS2812 GRB LEDs.)

Link to my schematic

  1. Am I right in believing I am within the power budget, powering 6 "Neopixels" from USB? From my research this should total a max current draw of 360mA
  2. Can I also get by without the resistor between the Nano and the ledstrip, or is this strictly necessary?
  3. Can I get by using the internal pullup-resistor for the two pushbuttons or do I need resistors here aswell?
    Based on my testing, it seems to work alright but I would appreciate an experienced opinion.

Self-aware of my lack of prowess in coding, I turned to ChatGPT. This got me quite a ways, but context from one iteration to another quickly got lost, the code got messy and I gave up.
I never achieved the primary goal with ChatGPT, but here's the latest output which lets me toggle the lights, but when I turn them on they dim down and then back up to full brightness and that's it.

#include <Adafruit_NeoPixel.h>

#define PIN            6   // The digital pin connected to the NeoPixel strip
#define BUTTON_PIN     7   // The digital pin connected to the push button
#define NUMPIXELS      4   // The number of NeoPixels in your strip

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

bool lightsOn = false;
int brightness = 255;  // Initial brightness (0 to 255)
int buttonState = HIGH; // Initial button state
unsigned long timePUSHED = 0;  // Add this line for the time of the last button press

// Function declaration
void colorWipe(uint32_t color, int wait);
void decreaseBrightness();
void increaseBrightness();

void setup() {
  strip.begin();
  strip.show();  // Initialize all pixels to 'off'
  pinMode(BUTTON_PIN, INPUT_PULLUP);  // Enable internal pull-up resistor for the button pin
}

void loop() {
  // Check button press
  if (digitalRead(BUTTON_PIN) == LOW && !lightsOn) {
    // Button is pressed, turn on the lights
    lightsOn = true;
    brightness = 255; // Reset brightness to full
    colorWipe(strip.Color(255, 255, 255), 10);
    delay(500);  // Debounce delay
  } else if (digitalRead(BUTTON_PIN) == LOW && lightsOn) {
    // Button is pressed, turn off the lights
    lightsOn = false;
    colorWipe(strip.Color(0, 0, 0), 10);
    delay(500);  // Debounce delay
  }

  // Check button hold for continuous brightness adjustment
  if (digitalRead(BUTTON_PIN) == HIGH && millis() - timePUSHED > 500) {
    // Debounce delay and ensure it's not triggered immediately after button press
    delay(50);

    // Check the state of the button
    if (buttonState == LOW) {
      // Button was low, decrease the lights continuously
      decreaseBrightness();
    } else {
      // Button was high, increase the lights continuously
      increaseBrightness();
    }
    timePUSHED = millis(); // Reset timePUSHED to avoid immediate re-triggering
  }

  // Update the button state
  buttonState = digitalRead(BUTTON_PIN);
}

// Function definition
void colorWipe(uint32_t color, int wait) {
  for(int i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, color);
    strip.show();
    delay(wait);
  }
}

// New functions for continuous brightness adjustment

void decreaseBrightness() {
  while (digitalRead(BUTTON_PIN) == HIGH && brightness > 26) {
    brightness = constrain(brightness - 5, 26, 255);  // Decrease brightness to minimum 10%
    strip.setBrightness(brightness);
    strip.show();
    delay(50);
  }
}

void increaseBrightness() {
  while (digitalRead(BUTTON_PIN) == HIGH && brightness < 255) {
    brightness = constrain(brightness + 5, 26, 255);  // Increase brightness to maximum
    strip.setBrightness(brightness);
    strip.show();
    delay(50);
  }
}

Primary goal
I want start with the LEDs OFF and toggle a white light ON/OFF with a short press of pushbutton connected to D7. Then I would like to be able to dim/increase brightness with a button hold determined by if the current brightness is below or above mid brightness. If I am below mid brightness and hold the button, I want the LEDs to increase from current brightness to full brightness or the level I release the button at, and if I am above mid brightness, I want the LEDs to dim from the current brightness down to 10% or the brightness where I release the button.

Secondary goal
I would like the second pushbutton to cycle through a few colours on buttonpress and back to white in the cycle, maintaining the functionality of the first button on each colour

Above and beyond goal
Holding both buttons down to reset LEDs to white and implement some more colours

My experience shows me that it takes about 10 days to debug chatGPT code that took 10 minutes to generate. If I do it myself it takes about two days including debugging.

Make a list of the order of events without digression... that is to say, take it out of paragraph form.

Can you elaborate on this? Because I'm not sure if I understand you correctly.
Is your suggestion to present the list to chatGPT in the belief that it would give better results?
Or is the way I want the program to function unclear to this forum when I present it in paragraph form?

What I communicated to chatGPT was pretty much in line with how I layed out the primary goal. Which although is in paragraph form, I think is lacking digressions. That was the most concrete way I could think of presenting the way I want the program to function.

In any case, because of my lack of experience with programming, the hierarchy of events is not clear to me. For instance, do I need to list the elements in void setup first? in that case, should the minimum brightness (10%) and max brightness (full) be presented here or later down in the list? I don't know which functions I need to achieve my goal, let alone where they would come in a list and how that list looks like if I were to make one

Yeah, I think you're right :sweat_smile:
I guess even though I'm completely blank, those 10 days is better invested in trying to learn it from scratch.
As @b707 eludes to in the reply below, I guess I need to learn functions and code practices I don't need aswell to recognise an efficient way to achieve what I want through ChatGPT

The GPT coding is instrument for experiencing programmers. You have to know how to handle it in order to use it. Without the understanding the code it does more harm than good. It is like a Ferrari for novice driver - you're more likely to crash than in a cheap family hatchback.
It's better for beginner to start writing code yourself.

I think that's an excellent analogy. Ive got experience with building drones and modifying code for flight controllers, automating things around the house with my Home Assistant etc, but all those things have some guard rails in the sense that the options available is somewhat limited in that environment. So I can look at the ChatGPT code and have some understanding of how it functions, but it's a much greater task understanding why a ChatGPT coded function is misplaced, how it isn't quite what I need etc. Also, if I understand the function or to some extent how the code works, I'm not at all familiar with the syntax, so errors in the code isn't immediately apparent to me.

The conclusion is I am a much more novice driver than I thought I'd be :laughing:

Discard ChatGPT.
Make a list of events you intend to happen.

I apologize for my ignorance, and I appreciate you taking the time to help.

Like this?

  • Loop start, LEDs OFF
  • On short press D7, toggle white LEDs ON, 100% brightness/OFF
  • On long press D7, above mid brightness, from current brightness, dim LEDs to level at release or 10%
  • On long press D7, below mid brightness, from current brightness, increase brightness to level at release or 100%
  • On short press D8, cycle colour to red
  • On 2 short press D8, cycle colour to green
  • On 3 short press D8, cycle colour to blue
  • On 4 short press D8, cycle colour to white
  • On short press D7 and D8, reset LEDs to white, 100% brightness

If I succeed in the final bullet point, I want to implement more colours on further presses of D8 rather than cycle back to white

Yes.

Here is a simulation that I REMOVED the ChatGPT code...

  1. "initilalise LEDs off"
  2. On short press D7, toggle white LEDs ON/OFF (using ColorWipe)

I included a very messy "delay(150)" for the button debounce, which will need to be removed to get a "long press" to work.

  1. I'm not sure if the quotes are referring to the misspelling or the term, I edited the post to communicate clearer.

Thank you for taking the time to setup, reply and show me this. It answers many of my questions.
When browsing your profile and reading some of your posts I think it's very clear you know what you're talking about and given the fact that you're continuing to engage with this annoying newbie without adressing any of my first three questions, you are using the internal pullup resistor for the buttons in your code aswell, I am going to assume the answers to all of them are yes. Either that, or I guess I am provoking an answer.

With the risk of expending your patience, please let me know if I have understood this correctly;

You are setting up a boolean for the toggling of the leds with an if/else if, and storing the brightness of 255 with an integer constant? And when doing a digitalread of BUTTON1_PIN, finding it is low and the lights are OFF, the boolean is flipped and you envoke a colorWipe with the RGB-colors set to white and a delay of 10, and the brightness is determined by the int on every toggle? And by envoking another colorWipe with the RGB-colors set to 0 for the false boolean (The brightness still at 255 from the int?) the LEDs turn OFF? (I'm sure I wreaked havoc on the terminology)

If the above is true I'm not sure I understand the need for setting the brightness in void setup?

When testing the code, it seems clear that my pushbuttons are of the particularly bad variety and I'll start to work on understanding and implementing a better and more robust way of debouncing before I move down the list.

#1 - Each Neopix is made of 3 LEDs, 1 red, 1 green, 1 blue. Assume 20mA current per LED, that would be 60mA per NeoPix at 100% (dec 255/hex 0xff). Arduino maximum current sourcing is 200mA total... with 40mA per pin... you are at 30% current maximum with one Neopix. If you test your four Neopix in your project at 10%/dec25/hex0x20, your Arduino should be safe. For this reason, get a power supply for the Neopixels, learn how to set it up, and make a power supply part of every project.

#2 - You want the resistor from Arduino data pin to first Neopix to limit the current - between 300 ohm and 500 ohm (I have seen some project pages use 1k ohm). I use 330 ohm and in the three years since beginning with Arduino, have not lost a Neopix to bad wiring (I did lose two WS2812/5050 while soldering on the small pads with a large soldering tip... so lesson learned for me).

#3 - For the pushbuttons... I use the internal pullups exclusively and write programs around their use. Before seeing this popular use in the Arduino pages, I used buttons with pull-down resistors, waiting for a HIGH during button press.

1 Like

I was trying to write comfortably... not "air quotes"... just repeating back to you what you listed. In the simulation, I started with the first two points you made... start "off", push a button, Neopix on 100%. I left a little "flair" in with the "color wipe" from 0 to 100%.

A little warm up before the answer... we first think of button presses as the action that makes the lights turn on, like a light switch on a wall. With microprocessors (the Arduino's brain), the act of pressing a button causes thousands of make/break transitions/switches (also called bouncing or ringing) as the button is being pressed (find a super-slo-motion video of a button press). We program-out that bounce by not using the button press, but using the state change (1/0, high/low) of a variable after an amount of time to wait for the bouncing to stop, then checking that variable state - which is the boolean variable that you mentioned. I wrote "a bad way to debounce" after using "delay(150);"... which you will learn soon why it is bad, but at times it can be used in a good way (like this project). If you remove "delay(150);" and run the simulation, you will see the Neopix might or might not turn on... that is the simulation "bouncing" (simulated bouncing).

Yes, I left that in from your ChatGPT code... it worked good enough, so why not keep it for viewing? It can always be removed. The "10" of the color wipe is the rate of "wipe"... you can experiment with that.

The best thing for you to do with this first revision of your code is to play with the numbers until you break it, then refer to the original code (just refresh the page) if you get stuck.

Setting "brightness" in setup() lets you NOT burn your data pin if you have a string of neopix set to 255,255,255 (white). Set brightness to a low number during testing on live components. When you have a power supply dedicated to the LEDs, then you can use 255. In the simulator, 255 is never a problem (simulators do not melt). I find "10" bright enough when testing my 10-pix hardware with patterns and timing.

You can program the badness out of the buttons. Reference Arduino's "how to debounce a button"... and ask questions about it to make sure you are not just re-enacting the code, but understanding the code.

I was butchering the explanation and taking shortcuts, but based on yours, I think I understood that part correctly.

That's what I saw when testing the code on my hardware and what I based my statement on

They still bounced, as in the LEDs were behaving a bit erratic. And considering I want to progress down the list and implement the long press, that's the next step to understand and implement.

Thanks for clearing that up. Seeing as the leds will be diffused by the figurine and I will be using the strip as one uniform light source, I prefer a short wipe. I won't bother changing the function though.

What I meant was, wouldn't "int brightness = 255" call for full brightness of the LEDs on a toggle anyway, regardless of "strip.setBrightness(25)" in setup()?

After playing around with the simulation I understand the question above is misunderstood. It's the brightness in setup() which determines the brightness of the LEDs when toggling in the programs current state. In spite of seeing the untagged comment in the code, what I don't understand is what the "int brightness = 255" is doing?

Set brightness once, usually in setup().

If you set brightness to "10" in setup, a value of (255, 255, 255) in the functions will actually be (10, 10, 10)... and a value of (127, 127, 127) in the functions will be (5, 5, 5)

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.