Below is the code that I am currently using to control my LuciLED illuminators. It is currently setup with the intention of being able to control dual rings with a ‘Lucigen-style’ central illuminator. The outer ring consists of 36 neopixels, the inner ring has 18 pixels and the centre illuminator has 3. The second page allows for control of a 54 pixel ring without a centre. I hope that the code is pretty self-explanatory and easy to modify. Please let me know if you come up with improvements ! The two pictures after the code section show the two control screens for the Nextion display.
//3 ring version of LuciLED 24/07/2026 11:25
// P Mobbs - code to be in the public domain
// Controls 36, 18 and 54 neopixel rings and
// a 3 pixel central 'Lucigen' illumination
//
#include "EasyNextionLibrary.h"
#include <Wire.h>
#include <FastLED.h>
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
#define NUM_LEDS 57
#define DATA_PIN 6
#define BRIGHTNESS 150
const int REFRESH_TIME = 100; //responsive enough?
unsigned long refresh_timer = millis();
int Red_val = 0;
int Green_val = 0;
int Blue_val = 0;
int Red_val_P1 = 0;
int Green_val_P1 = 0;
int Blue_val_P1 = 0;
String myString;
bool Set_colour_flag = true;
EasyNex myNex(Serial);
CRGB leds[NUM_LEDS];
void setup() {
myNex.begin(115200); // necessary??
delay (100);
Serial.begin(115200); //115200
delay (100);
FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.clear(); FastLED.show();
}
void loop() {
if ((millis() - refresh_timer) > REFRESH_TIME) {
myNex.NextionListen();
refresh_timer = millis();
}
}
//------------------------------
// Set the colour for the pixels
//------------------------------
int Set_colour() {
if ((millis() - refresh_timer) > REFRESH_TIME) {
Red_val = myNex.readNumber("h0.val");
Green_val = myNex.readNumber("h1.val");
Blue_val = myNex.readNumber("h2.val");
refresh_timer = millis();
}
return (Red_val, Green_val, Blue_val);
}
int Set_colour_P1() {
if ((millis() - refresh_timer) > REFRESH_TIME) {
Red_val_P1 = myNex.readNumber("page1.h0.val");
Green_val_P1 = myNex.readNumber("page1.h1.val");
Blue_val_P1 = myNex.readNumber("page1.h2.val");
refresh_timer = millis();
}
return (Red_val_P1, Green_val_P1, Blue_val_P1);
}
//----------------------------------------------
// OUTER RING (36 pixels):
//----------------------------------------------
// Outer ring quadrant 1
void trigger0() {
bool flag;
flag = myNex.readNumber("bt0.val");
if (flag == false) {
fill_solid(leds + 0, 9, CRGB::Black);
} else if (flag == true) {
Set_colour (); // sub to set the colur
fill_solid(leds + 0, 9, CRGB(Red_val, Green_val, Blue_val));
}
FastLED.show();
}
// Outer ring quadrant 2
void trigger1() {
bool flag;
flag = myNex.readNumber("bt1.val");
if (flag == false) {
fill_solid(leds + 9, 9, CRGB::Black);
} else if (flag == true) {
Set_colour (); // sub to set the colur
fill_solid(leds + 9, 9, CRGB(Red_val, Green_val, Blue_val));
}
FastLED.show();
}
// Outer ring quadrant 3
void trigger2() {
bool flag;
flag = myNex.readNumber("bt2.val");
if (flag == false) {
fill_solid(leds + 18, 9, CRGB::Black);
} else if (flag == true) {
Set_colour (); // sub to set the colur
fill_solid(leds + 18, 9, CRGB(Red_val, Green_val, Blue_val));
}
FastLED.show();
}
// Outer ring quadrant 4
void trigger3() {
bool flag;
flag = myNex.readNumber("bt3.val");
if (flag == false) {
fill_solid(leds + 27, 9, CRGB::Black);
} else if (flag == true) {
Set_colour (); // sub to set the colour
fill_solid(leds + 27, 9, CRGB(Red_val, Green_val, Blue_val));
}
FastLED.show();
}
//---------------------------------------
// INNER RING (18 pixels):
//---------------------------------------
// Inner ring quadrant 1
void trigger4() {
bool flag;
flag = myNex.readNumber("bt4.val");
if (flag == false) {
fill_solid(leds + 36, 5, CRGB:: Black);
} else if (flag == true) {
Set_colour (); // sub to set the colur
fill_solid(leds + 36, 5, CRGB(Red_val, Green_val, Blue_val));
}
FastLED.show();
}
// Inner ring quadrant 2
void trigger5() {
bool flag;
flag = myNex.readNumber("bt5.val");
if (flag == false) {
//leds[+41, 4] = CRGB::Black;
fill_solid(leds + 41, 4, CRGB::Black);
} else if (flag == true) {
Set_colour (); // sub to set the coluor
fill_solid(leds + 41, 4, CRGB(Red_val, Green_val, Blue_val));
// leds [+41, 4] = CRGB(Red_val, Green_val, Blue_val);
}
FastLED.show();
}
// Inner ring quadrant 3
void trigger6() {
bool flag;
flag = myNex.readNumber("bt6.val");
if (flag == false) {
fill_solid(leds + 45, 5, CRGB::Black);
// leds[+45, 5] = CRGB::Black;
} else if (flag == true) {
Set_colour (); // sub to set the colur
fill_solid(leds + 45, 5, CRGB(Red_val, Green_val, Blue_val));
}
FastLED.show();
}
// Inner ring quadrant 4
void trigger7() {
bool flag;
flag = myNex.readNumber("bt7.val");
if (flag == false) {
fill_solid(leds + 50, 4, CRGB::Black);
} else if (flag == true) {
Set_colour (); // sub to set the colur
fill_solid(leds + 50, 4, CRGB(Red_val, Green_val, Blue_val));
}
FastLED.show();
}
//---------------------------------------
// Lucigen centre (3 pixels) - ON or OFF
//---------------------------------------
void trigger8() {
bool flag;
flag = myNex.readNumber("bt8.val");
if (flag == false) {
fill_solid(leds + 54, 3, CRGB::Black);
} else if (flag == true) {
Set_colour (); // sub to set the colour
fill_solid(leds + 54, 3, CRGB(Red_val, Green_val, Blue_val));
}
FastLED.show();
}
//----------------------------------------------
// All outer ON or OFF
//----------------------------------------------
void trigger9() {
bool flag;
flag = myNex.readNumber("bt9.val");
if (flag == false) {
fill_solid(leds + 0, 36, CRGB::Black);
} else if (flag == true) {
Set_colour (); // sub to set the colur
fill_solid(leds + 0, 36, CRGB(Red_val, Green_val, Blue_val));
}
FastLED.show();
}
//---------------------------------------------
// Inner ring - all ON or OFF
//---------------------------------------------
void trigger10() {
bool flag;
flag = myNex.readNumber("bt10.val");
if (flag == false) {
fill_solid(leds + 36, 18, CRGB::Black);
} else if (flag == true) {
Set_colour_P1(); // sub to set the colur
fill_solid(leds + 36, 18, CRGB(Red_val, Green_val, Blue_val));
}
FastLED.show();
}
//---------
// All OFF
//---------
void trigger11() {
bool flag;
flag = myNex.readNumber("bt11.val");
if (flag == false) {
fill_solid(leds + 0, 57, CRGB::Black);
// reset buttons that might be in ON colours to OFF colours
myNex.writeNum("bt0.val", 0);
myNex.writeNum("bt1.val", 0);
myNex.writeNum("bt2.val", 0);
myNex.writeNum("bt3.val", 0);
myNex.writeNum("bt4.val", 0);
myNex.writeNum("bt5.val", 0);
myNex.writeNum("bt6.val", 0);
myNex.writeNum("bt7.val", 0);
myNex.writeNum("bt8.val", 0);
myNex.writeNum("bt9.val", 0);
myNex.writeNum("bt10.val", 0);
}
FastLED.show();
}
//---------------------
// Big ring (54 pixels)
//---------------------
//---------------------------------------------
// Big ring - 54 Pix - Q1 ON or OFF
//---------------------------------------------
void trigger12() {
bool flag;
flag = myNex.readNumber("page1.bt1.val");
if (flag == false) {
fill_solid(leds + 0, 14, CRGB::Black);
} else if (flag == true) {
Set_colour_P1(); // sub to set the colur
fill_solid(leds + 0, 14, CRGB(Red_val_P1, Green_val_P1, Blue_val_P1));
}
FastLED.show();
}
//---------------------------------------------
// Big ring - 54 Pix - Q2 ON or OFF
//---------------------------------------------
void trigger13() {
bool flag;
flag = myNex.readNumber("page1.bt2.val");
delay(10);
if (flag == false) {
fill_solid(leds + 14, 13, CRGB::Black);
} else if (flag == true) {
Set_colour_P1(); // sub to set the colur
fill_solid(leds + 14, 13, CRGB(Red_val_P1, Green_val_P1, Blue_val_P1));
}
FastLED.show();
}
//---------------------------------------------
// Big ring - 54 Pix - Q3 ON or OFF
//---------------------------------------------
void trigger14() {
bool flag;
flag = myNex.readNumber("page1.bt3.val");
delay(10);
if (flag == false) {
fill_solid(leds + 27, 13, CRGB::Black);
} else if (flag == true) {
Set_colour_P1(); // sub to set the colur
fill_solid(leds + 27, 13, CRGB(Red_val_P1, Green_val_P1, Blue_val_P1));
}
FastLED.show();
}
//---------------------------------------------
// Big ring - 54 Pix - Q4 ON or OFF
//---------------------------------------------
void trigger15() {
bool flag;
flag = myNex.readNumber("page1.bt4.val");
delay(10);
if (flag == false) {
fill_solid(leds + 40, 14, CRGB::Black);
} else if (flag == true) {
Set_colour_P1(); // sub to set the colur
fill_solid(leds + 40, 14, CRGB(Red_val_P1, Green_val_P1, Blue_val_P1));
}
FastLED.show();
}
//------------------------------------------------
// All OFF - 54 pixels - no button in this version
//------------------------------------------------
void trigger16() {
bool flag;
flag = myNex.readNumber("page1.bt5.val");
delay(10);
if (flag == false) {
fill_solid(leds + 0, 53, CRGB::Black);
// reset buttons that might be in ON colours on page 1 to OFF colours
myNex.writeNum("page1.bt1.val", 0);
myNex.writeNum("page1.bt2.val", 0);
myNex.writeNum("page1.bt3.val", 0);
myNex.writeNum("page1.bt4.val", 0);
}
FastLED.show();
}

Page 1 – the colours are picked up each time you activate a button. The buttons are dual-state and go green when on and grey when off.

Page 2 – self-evident (I hope).
I have a version with a second screen that has my favourite presets for Rheinberg, phase etc. It should be easy for anyone who can program an Arduino to figure out how to do that but if you can’t, email me using the form below and I will send you the code.
Leave a Reply