Output Devices

Add colorful life to the Ceiling Lamp

Project Timeline

Assignment Introduction

Output Devices

This week, the task is to create a PCB that creates an Output. This can either be one that has a screen, makes a sound or shines a beautiful LED.

I wanted to continue my project from the Computer-Controlled Machining Week, the ceiling lamp. For this, I need a board to control the planned LED strip, which serves as the light source.

For the LED strip, a fairly high current of 12 Amperes is required, which is why I also needed a power supply that converts 230V to 5V and provides enough current for the LEDs. The microcontroller I am using - an ESP32-H2 - already has an onboard 5V to 3.3V regulator, so I can also power the board directly. LEDs and the microcontroller also share a GND port. From the microcontroller, a data wire goes to the LED, controlling the color and brightness of the LEDs. The signal/actions are received via ZigBee by the microcontroller and simply forwarded to the LEDs. Since the microcontroller is permanently powered, it is programmed as a ZigBee router and can thus amplify the ZigBee signal in our household.

Material Bill

Components and resources used for this week’s project

  • ESP32-H2 Super Mini

    Low-power microcontroller board for Zigbee, Thread, and Bluetooth LE communication in the lamp controller.

  • Pin Header 1x9 (~2.54 mm pitch)

    Single-row through-hole header used for modular connections and easy access to board signals.

  • Screw Terminal Block 3x1 (5.08 mm pitch)

    Three-position PCB terminal block for clamping external wires securely without soldering them directly to the board.

  • Screw Terminal Block 2x1 (5.08 mm pitch)

    Two-position PCB terminal block for power or signal wiring where a removable screw connection is helpful.

  • WS2812B RGB LED Strip (~1.5 m)

    Addressable 5V RGB light strip used as the main illumination source with individually controllable LEDs.

  • 230V AC to 5V DC Converter (12A class)

    Mains-powered converter that supplies the LED strip and controller with a stable 5V output at high current.

Software & Tools

PCB Design

As described above, these are the requirements for my new PCB. To reliably transmit a current of 12 Amperes, the traces were set to 5mm. Since the microcontroller itself does not require much current, its traces could be designed at only 1mm, which is more than sufficient.

For the PCB stack, I only used a single layer, as simple boards like this do not require top and bottom layers. For export from Altium, it was also important to include the board outline. Sometimes, the outline is not properly exported as a Gerber unless it is placed on a separate layer. I therefore added another mechanical layer and drew the outline there again.

Routing the ceiling lamp board in Altium Designer

When routing the traces, make sure that the traces do not form 90-degree angles, as this can cause critical errors during milling. Therefore, angles of 30 to 45 degrees are always recommended.

Now everything is ready for export. Go to PCB > File > Fabrication Outputs > Gerber Files. A pop-up appears. Only the necessary layers need to be selected. For example, I do not need silkscreens for simple milling with the LPKF. Silkscreens usually contain details like designators on the PCB - indicating which parts go where and therefore an idea of which exact components are used. This is helpful for large product chains and debugging, but for simple prototyping purposes not necessary. The exported file(s) can now be placed on a USB drive. To ensure everything was exported correctly, Altium has an internal CAM viewer, but there are also external options such as Altium Viewer and many more.

PCB Production

PCB Milling

Take the exported files and put them into your PCB machine. Refer to that documentation for a more detailed view of the PCB milling process. For this PCB, there are no especially important things to check, so milling this one is quite straightforward.

PCB milling process
PCB soldering process

PCB Soldering

After the milling is done, you may now sand your board down and clean it with isopropanol. Then you can start attaching your components to the board. As usual, do not forget to check that the connections work properly with a multimeter. When everything looks fine, we can go ahead and connect the wires to the terminal.

Since the LEDs need higher power, we need to refer to an external power supply. As usual, when working with higher voltages, be careful, read any safety material, and work without power. Double-check that the wiring is correct and turn everything on only when there is proper space around the cabling.

PCB Programming

LED Strip Test

For testing, I created a simple code: each LED lights red sequentially. This allows me to check:
a) the number of LEDs, and
b) that each LED can be addressed and works correctly.

Close-up of the addressable LED test sequence
#include <Adafruit_NeoPixel.h>

#define LED_PIN     10
#define NUM_LEDS    200      // guessed amount LEDs | In the end 205

Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  strip.begin();
  strip.show();
}

void loop() {
  for (int i = 0; i < NUM_LEDS; i++) {
    strip.setPixelColor(i, strip.Color(255, 0, 0));
    strip.show();
    delay(200);
  }

  for (int i = 0; i < NUM_LEDS; i++) {
    strip.setPixelColor(i, strip.Color(0, 0, 0));
  }
  strip.show();
  delay(500);
}

ZigBee Integration

Once this worked, I uploaded the final ZigBee router code. It sets up a ZigBee signal, identifies as an RGB lamp, and allows third-party software - in my case Home Assistant - to control it.

The ZigBee setup is very similar to my Embedded Programming Week.

ZigBee ceiling lamp in its assembled state
ZigBee ceiling lamp
Ceiling lamp board with RGB LED strip controlled via ZigBee
RGB LED strip controlled through the finished ZigBee lamp board
#include <Arduino.h>
#ifndef ZIGBEE_MODE_ZCZR
#error "Zigbee router mode must be selected in Tools -> Zigbee Mode"
#endif

#include "Zigbee.h"
#include <FastLED.h>

// ---------------- LED Setup ----------------
#define LED_PIN     10
#define NUM_LEDS    205
#define COLOR_ORDER GRB
#define LED_TYPE    WS2812
CRGB leds[NUM_LEDS];

// ---------------- Zigbee Endpoint ----------------
#define ZIGBEE_LIGHT_ENDPOINT 10
ZigbeeColorDimmableLight zbLight = ZigbeeColorDimmableLight(ZIGBEE_LIGHT_ENDPOINT);

// Callback to apply RGB + brightness
void onColorChange(bool state, uint8_t red, uint8_t green, uint8_t blue, uint8_t level) {
  if (!state) {
    FastLED.clear();
    FastLED.show();
    return;
  }
  float brightness = (float)level / 255.0;
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i].r = red * brightness;
    leds[i].g = green * brightness;
    leds[i].b = blue * brightness;
  }
  FastLED.show();
}

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

  // FastLED init
  FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
  FastLED.clear(); FastLED.show();

  // Set color capabilities (RGB/XY mode)
  zbLight.setLightColorCapabilities(ZIGBEE_COLOR_CAPABILITY_X_Y);

  // Bind callback
  zbLight.onLightChangeRgb(onColorChange);

  // Device info (optional)
  zbLight.setManufacturerAndModel("ESP H2 Maker", "Ceiling Lamp");

  // Register endpoint
  Zigbee.addEndpoint(&zbLight);

  // Start Zigbee as Router (extends mesh)
  if (!Zigbee.begin(ZIGBEE_ROUTER, false)) {
    Serial.println("Zigbee failed to start!");
    while (true) delay(1000);
  }
  Serial.println("Zigbee Router started");
}

void loop() {
  // No Zigbee.update() needed - handled internally
  delay(10); // Optional idle delay
}

Project Files

Downloads

PCB Files

Arduino Files

Start 0%