Cylindrical WS2812 Light

I had a few of the 8x32 LED matrices around, and wanted to work on making a few things with them. One for me and my home assistant install, and one for my daughter.
In all honesty, I got a 3D printer for Christmas and wanted to use it for the list of projects I have had on backlog.
So I worked with someone on Upwork.com to help with the 3D modeling and design based on a sketch. I am not a 3D modeling person, so didn’t want to waste time. He was great and would use him again. Maybe ultimately I would learn how to manage myself or modify something, but until then, outsourcing.
This is the sketch I started with.
No screws, power inlet, etc. You can see in the perfect diagram below.

From that, I received the following (only showing the grid). But I have the grid, the top and bottom caps, and the diffuser.


For assembly, the grid snaps into the bottom cap, then I install the LED inside, slide the diffuser around the grid, and close with the top cap. All are snap in pieces, no screws.
I am using a BambuLab X1C printer. The beauty of it is that I could print straight up with NO support. The printer was able to bridge from one column of the grid to the next without sagging. That was the biggest win.

The assembly fits great, the LED matrix is a little loose inside given the designer did not have the actual hardware (anyone venture to fix and tighten is more than welcome).
Grid and caps printed with black ABS filament.
Diffuser printed with transparent PETG filament.

Some pictures of the assembly:



The ESPHome program I have running for now is this simple one. It is the start of what I want to hang by my garage door and send message to it via MQTT.
I have not started on the firmware yet, so there is a lot of work there to do, but at least I could test it.

#Name the Project here to identify the specific node
substitutions:
  project: Garage-LED-Sign-01
  id: garage-led-sign-01
  xscrollpadding: "4" # in pix
  
mqtt:
  <<: !include common/mqtt_credentials.yaml
      
#Include the board used  
<<: !include common/esphome/esp32.yaml
#include common Wifi-OTA-API, etc
<<: !include common/common.yaml

binary_sensor:
#Include the status 
  - !include common/binary_sensors/status.yaml
  - platform: gpio
    pin: GPIO34
    name: "PIR Sensor"
    device_class: motion
    id: garage_pir_sensor
    
switch:
  #Include restart button
  - !include common/switches/restart.yaml
  
sensor:
#Include wifi signal sensor
  - !include common/sensors/wifi_signal.yaml
  - !include common/sensors/uptime.yaml
 
text_sensor:
  - platform: mqtt_subscribe
    id: garage_led_sign_text
    internal: true
    topic: garage/led_sign/text
    on_value:
      then:
        - if:
            condition:
              lambda: return true;
            then:
              lambda: id(garage_led_text).publish_state(x);
  - platform: template
    id: garage_led_text
    internal: true
    
font:
  - file: "fonts/arial.ttf"
    id: text_font_tiny
    size: 10
  - file: "fonts/materialdesignicons-webfont.ttf"
    id: icon_font_10
    size: 10
color:
  - id: my_red
    red: 100%
    green: 0%
    blue: 0%
  - id: my_green
    red: 0%
    green: 100%
    blue: 0%
  - id: my_blue
    red: 0%
    green: 0%
    blue: 100%
  - id: my_yellow
    red: 100%
    green: 100%
    blue: 0%
  - id: my_black
    red: 0%
    green: 0%
    blue: 0%  
    
# Configure WS2815
light:
  - platform: fastled_clockless
    chipset: WS2812b
    id: led_matrix_light
    pin: GPIO5
    num_leds: 256
    rgb_order: GRB
    name: "Garage Traffic Sign"
    default_transition_length: 0s
    color_correct: [50%, 50%, 50%]
    restore_mode: ALWAYS_ON
    effects:
      - addressable_rainbow:
      - addressable_color_wipe:    
      - flicker:
      - strobe:
      - random:
      - addressable_scan:
      - addressable_twinkle:
      - addressable_random_twinkle:
      - addressable_fireworks:
      - addressable_flicker:
      - addressable_rainbow:
          name: Rainbow Effect With Custom Values
          speed: 10
          width: 50
          
display:
  - platform: addressable_light
    id: led_matrix_display
    addressable_light_id: led_matrix_light
    width: 32
    height: 8
    pixel_mapper: |-
      if (x % 2 == 0) {
        return (x * 8) + y;
      }
      return (x * 8) + (7 - y);
    rotation: 180°
    update_interval: 200ms
    pages:
      - id: page1
        lambda: |-
              if (id(mqtt_client)->is_connected()) {
                // do something if MQTT is connected
                static uint16_t xpos = 0;
                int x_start, y_start;
                int width, height;
                it.get_text_bounds(0, 0, "MQTT Connected", id(text_font_tiny), 
                    TextAlign::TOP_LEFT, &x_start, &y_start, &width, &height); 
                it.print(-(xpos % (width + $xscrollpadding)), -2, 
                  id(text_font_tiny), Color(id(my_blue)), 
                  TextAlign::TOP_LEFT, "MQTT Connected"); 
                xpos++;
              }
      - id: page2
        lambda: |-
              it.print(0, 0, id(icon_font_10), Color(id(my_blue)), TextAlign::TOP_LEFT, "󰽔");
      - id: page3
        lambda: |-
              // Draw the same rectangle, but this time filled.
              //it.filled_rectangle(0, 0, it.get_width(), it.get_height());    
              it.fill(my_red);
      - id: page4
        lambda: |-
              // Draw the same rectangle, but this time filled.
              //it.filled_rectangle(0, 0, it.get_width(), it.get_height());    
              it.fill(my_black);        
      - id: page5
        lambda: |-
              static uint16_t xpos = 0;
              const char * text = id(garage_led_sign_text).state.c_str();
              int x_start, y_start;
              int width, height;
              it.get_text_bounds(0, 0, text, id(text_font_tiny), 
                  TextAlign::TOP_LEFT, &x_start, &y_start, &width, &height); 
              it.print(-(xpos % (width + $xscrollpadding)), -2, 
                id(text_font_tiny), Color(id(my_green)), 
                TextAlign::TOP_LEFT, text); 
              xpos++;              
        
interval:        
  - interval: 2s
    then:
      if:
        condition: 
          lambda: |-
            return id(garage_led_text).state == "STOP";
        then:
          - display.page.show: !lambda |-
              static int pagenum = 0;
              static display::DisplayPage* pages[] = {id(page2), id(page3)};
              auto page = pages[pagenum++];
              if (pagenum >= 2)
                pagenum = 0;
              return page;
          - component.update: led_matrix_display
  - interval: 2s
    then:
      if:
        condition: 
          lambda: |-
            return id(garage_led_text).state == "START";
        then:
          - display.page.show: !lambda |-
              static int pagenum = 0;
              static display::DisplayPage* pages[] = {id(page5), id(page3)};
              auto page = pages[pagenum++];
              if (pagenum >= 2)
                pagenum = 0;
              return page;
          - component.update: led_matrix_display     

The other one I am making is a lamp for my daughter, using WLED so she can interface with her phone, adding a mic to the it for sound effect.

Anyways, thought I’d share.
I will share the files for the 3D models on one of the 3D sites, but if anyone needs now just let me know.

2 Likes