How to adress Neopixel LEDs individually?
-
Hi everyone,
maybe I'm just missing it somehow, but I feel the following should be possible but I've not been able to figure it out using the M150 documentation.
My setup is as follows; I have three single Neopixel LEDs (WS2812B chips) installed in my Voron's printhead, of which the first is sort of a status LED and the two following illuminate the nozzle area (all wired in "series" as they would be on an LED strip).
In my config.g I have a single M150 X1 to initialise the LEDs, for now all other operations are done in macros and/or the slicer's start/stop gcode.I'm now trying, for example, to create macros that allow me to quickly switch the nozzle lights on and off. For this, I'd have to first send a M150 R...U...B... S1 F1 command and then a M150 R255 U255 B255 S3 F0 to set the two nozzle lights to "white". If I leave the first command empty, e.g. M150 S1 F1, it will turn off this LED after entering the second M150 command and lighting up the nozzle lights. Thus I'm concluding that I have to re-send the RGB values that the first LED already has, so that it will stay the way it is when the macro is executed. However I don't know these values since they have been set by another arbitrary macro or print gcode file.
It seems as if what I'm trying to do is not yet possible with the current set of M150 options. Ideally I'd have a "start" parameter for the M150 command, indicating the first LED in the strip that the command is meant for and skipping the LEDs that come before this one. The S parameter would of course still be used to pass the number of LEDs that should be adressed.
Any pointers are appreciated.
Best regards, Niklas
-
If I remember correctly, the way communication with neopixels works is that you always have to send the complete string for the whole strip/chain/etc.
Each of the neopixels grabs only the amount of data it needs for itself, then sends on the remainder of the signal onwards.
So there's no way to just send data to a single neopixel somewhere down the line.
One way to do it is to use variables and store what the last selection for that neopixel was.
In my case (also on a Voron with the SB beta), I just created a set of macros based off klipper suggestion config and trigger them when needed. I only want nozzle leds to be on during printing, they should remain off otherwise, so the macros are simple.
For example, QGL is:
M150 S1 R128 U25 B100 W0 P255 F1 M150 R0 U0 B0 W0
And so on.
This could be modified so that only the toolhead led gets changed, without touching the other two (just remove the F1 and second line and you're done).
-
@pkos correct, all the Neopixels need to be sent data at the same time. Your suggestion of using variables should be a good solution for @sonderzug because he is using a string of just 3 pixels.
-
@pkos said in How to adress Neopixel LEDs individually?:
I just created a set of macros
You can also have a single macro file that accepts a pattern selection parameter.
I update the neopixels in daemon.g using conditional code that looks at various object model variables.
-
@zapta yes I think that is also what I should be doing, since it is mostly what I'm trying to achieve anyways.
thank you to all for commenting.
-
@sonderzug , this is the led control logic in my daemon.g. Daemon.g runs every 10 secs so sometime I also call it directly for faster response, e.g. when starting a print.
; LED control if {state.status} == "paused" M150 R255 B255 P255 S20 ; purple M300 S4000 P50 G4 P300 M300 S4000 P50 ; double beep elif {state.status} == "processing" || {state.status} == "busy" M150 R255 U255 B255 P255 S20 ; white elif {heat.heaters[0].current} > 50 || {heat.heaters[1].current} > 70 M150 R255 U0 B0 P255 S20 ; red elif {state.status} == "idle" M150 R0 U255 B0 P255 S20 ; green else M150 R150 U0 B150 P255 S20 ; purple
-
I was just thinking of this today, then went to search and found this! Sorry to hijack, different uses but same requirement.
I wanted to used the LEDS as a status lights that I could just attach to front of printers to see how all printers are doing at that moment.
But mounted in a fixed adapter so each color is in its own location. Like those CNC Signal Light towers. But just a strip of a few LEDs.
What I was thinking,,
RED = Error
ALL off = power short/other major alarm
RED Blinking = out of filament
Solid GREEN = Done
GREEN slow blink = printing , GREEN faster blinking near finish OR
Groups of green = printing and how much done (1 green led just started, 5 out of 6 all most done)
Same Green Light But blue for start /warm up times. %50 blue once bed is heated, then remainder light up blue until hotend is at temp then turns to green for printing.
Orange/ blue network connectivity
ALL white blink = find printer location
Yellow= on, no job
Custom Color for groups of printers doing same jobIF not can I Have 3 separate Neopixel LEDs strips, and just control those 3 separately from each other rather than just having a single strip?
`mike
-
@gallaghersart from what I understand now, it can be handled in daemon.g, maybe in a submacro for better structure.
You'd have to make extensive use of variables. The macro could be something like this (mockup):
-
determine RGB values for each individual "light" (=group of LEDs), much like @zapta 's example, according to your specification. Store in variables (e.g. "R_group1, U_group1, B_group1, R_group2 ...")
-
send M150 string at the end of the macro:
M150 R{R_group1} U{B_group1} B{B_group1} S{[number of LEDs in first group]} P{P_group1} F1 M150 R{R_group2} U{B_group2} B{B_group2} S{[number of LEDs in second group]} P{P_group2} F1 M150 R{R_group3} U{B_group3} B{B_group3} S{[number of LEDs in third group]} P{P_group3} F0
this way, all RGB values for the whole strip would be send at once, which was what my initial confusion was about.
If this macro is called regularly in daemon.g, it should all be quite smooth.
another thing is "blinking"; this would be more difficult. It could be done with a variable for brightness that is changed in each iteration of daemon.g, e.g.
P_group1 = 255 (initialised once at start, e.g. in config.g) P_group2 ... P_sign = 1
then in daemon.g:
if {P_group1} == 0 || {P_group1} == 255 P_sign = -P_sign if {P_group1} < 255 && {P_group1} > 0 P_group1 = P_group1 + (P_sign*5)
this way in each iteration of daemon.g, the brightness value is changed. the speed of blinking is dependent on how often daemon.g is called (I understand that this can be adjusted) and the value added in the last operation (e.g. 5)
note: not tested, just what I imagine could work.
I think there has been a request for a more elaborate way of handling LED colours before. Until then, we'd have to work like this.best, Niklas
-
-
This post is deleted!