esphome / feature-requests

ESPHome Feature Request Tracker
https://esphome.io/
413 stars 26 forks source link

Allow effects for addressable LEDs to work on "groups" of N LEDs instead of single LEDs #554

Open Boggie opened 4 years ago

Boggie commented 4 years ago

Describe the problem you have/What new integration you would like

I have just made some "Smart Nano leaf replicas" like these https://www.thingiverse.com/thing:3354082 and put three WS2811 LEDs in each corner. The project on thingiverse comes with some firmware, but I obviously wanted to use esphome instead :)

It was easy to get things to light up with a configuration like below:

light:
  - platform: fastled_clockless
    chipset: WS2811
    pin: D7
    num_leds: 9
    rgb_order: GRB
    name: "FastLED WS2811 Light"
    effects:
      - addressable_random_twinkle:
          name: Random Twinkle Effect With Custom Values
          twinkle_probability: 5%
          progress_interval: 32ms

My problem is that when I use things like the twinkle effect, it twinkle the single LEDs instead of each corner, since each corner is 3 LEDs and not just one.

It would be perfect if I could specify a "group_leds: 3" or similar to make the effects work on corners instead of single LEDs.

Please describe your use case for this integration and alternatives you've tried:

It would look way cooler ..

Additional context

brandond commented 4 years ago

I am actually working on something like this and have it most of the way done.

My use case is a little different - I've hacked a bunch of LED strips together into a 30x30 pixel display panel (30 rows of 30 pixels). I want to address 3x3 pixel groups as a virtual lights in a 10x10 grid. To support this, I'm working on code to group multiple ranges of lights together into a single virtual light that's updated as a single entity.

I'd eventually like to support using it as an output for some of the drawing and printing primitives, like you can do with some of the other outputs, but that's waiting on some other core stuff like RGB display support.

brandond commented 4 years ago

I have a custom component you might try. If it works for you and @OttoWinter thinks it's not too terrible I'll try to get it added to core. I'm not settled on the name but for the moment I'm calling it an Addressable Panel since it groups light across multiple rows and columns.

  1. Install esphome from this branch (needed for custom addressable lights)
  2. Grab the component code from this gist
  3. Configure the base addressable light. In my example, I'm using fastled_clockless as the base.
  4. Configure the custom component. The AddressablePanel constructor arguments are height, width, rows, cols. For your purposes (simply grouping lights in a single row as opposed to across multiple rows), and assuming you have 10 leafs, you probably want a height=1, width=3, rows=10, cols=3. Height and width are the size of each group; rows and cols are the size of the entire panel in groups.
  5. Check your setup. The base light num_leds should equal height x width x rows x cols.
esphome:
  includes:
    - panel.h

light:
  - platform: fastled_clockless
    chipset: WS2812
    pin: GPIO23
    num_leds: 9
    rgb_order: BRG
    id: base_light
  - platform: custom
    lambda: |-
      auto panel = new esphome::panel::AddressablePanel(id(base_light), 1, 3, 10, 3);
      auto light = new esphome::panel::PanelLightOutput(*panel);
      App.register_component(light);
      return {light};
    lights:
      id: panel0
      name: "Panel Light"
wwebers commented 4 years ago

Nice workm @brandond. I face the same problem with the very same nanoleaf clones.

However, the parameters for the AddressablePanel seem to work perfectly for describing square panels, but what about other shapes like triangles or hexgons? Or do I misunderstand something in your description?

1 panel = 12 led in total, 4 at each corner. All panels are connected in series, so the last group is connected to the first group of the next panel.

Problem: Sometimes I would like to adress the panel as a whole (all 3 groups per panel), sometimes I would like to address each group. Call me stupid, but I don't understand how achieve that with your specification of the AddressablePanel?

OttoWinter commented 4 years ago

So this actually already exists: https://esphome.io/components/light/partition.html

It doesn't do more complex things like shape of the LED array, but it does what the feature request is about: partitioning an addressable light into smaller parts.

wwebers commented 4 years ago

So this actually already exists: https://esphome.io/components/light/partition.html

It doesn't do more complex things like shape of the LED array, but it does what the feature request is about: partitioning an addressable light into smaller parts.

Not quiet sure about that. I tested the existing partitioning with my leafs (11 panels, with 3 groups with 4 leds in each of them).

I see no difference if, for example, applying the "rainbow" effect. I would expect the rainbow would be applied to my 11 leafs as a whole, but it isn't. Am I doing something wrong? How should such a configuration look like to work correctly?

Again:

132 leds in total, all leds connected in sequence 11 panels (12 leds per panel) 3 groups per panel á 4 leds

Boggie commented 4 years ago

I think the partition module would require me to make three lights per panel, that I would need to control individually, so as wwebers comments it solves another problem.

wwebers commented 4 years ago

@Boggie Yepp, as far as I understood this partitioning I could apply different effects on each panel (partition) seperately. But that not what I want. I would like to handle a sequence of leds (a panel in my case or a group inside a panel in Henriks case) just as a single led in those effects. That's a huge difference. I still have not understood how Brandons solution solves this.

brandond commented 4 years ago

@OttoWinter this works different than a partition.

A partition gives you a window into a set of elements on a larger array, or groups multiple arrays together into a larger array. However, addressing a single element in the partition still only updates a single LED.

The panel concept groups elements. Iterating across the array or updating a single element affects multiple LEDs as a single unit. The size of that unit, and how the pixels are selected, is such that the pixels might not be in a single contiguous range.

For my example, consider an 30x30 LED panel that I want to treat as a 10x10 panel, with groups of 3x3 LEDs updated in bulk. Setting panel[0] = ESPColor(0, 128, 255) actually sets the LEDs at [0,1,2,30,31,32,60,61,62].

@wwebers example could be thought of as an 11x12 panel that he wants to treat as a 11x3 panel: AddressablePanel(id(base_light), 1, 4, 11, 3). Each corner of 4 LEDs should be set as a single unit, so setting panel[0] actually affects the first corner of the first leaf: [0,1,2,3]. Addressing rows and columns isn't yet possible, but if he sets row(0) that would set all 12 LEDs on the first leaf. Setting column(0) would set the first corner (first 4 LEDs) on all 11 leafs. Applying a rainbow effect to the panel as a whole will ripple across all leafs, but each corner will have all LEDs illuminated in the same color.

@Boggie has a similar ask, except he has 3 LEDs per corner. I don't know how many leafs he has, but lets say 10 for 3x3x10=90 LEDs total. That would be configured as AddressablePanel(id(base_light), 1, 3, 10, 3)

wwebers commented 4 years ago

@brandond Many thank for your reply. So, num_leds is still the total amount of leds in my strip, which happens to be height width rows * columns ? I'll go and test your code right away 😁

wwebers commented 4 years ago

@brandond I managed to try out your branch and tested several effects. Works like a charm! However, only thing I experience is that this grouping demands more memory and performance of my ESP8266. E.g. the rainbow animation is not as smooth as it is when adressing single leds. Maybe, it will be better on a more performant ESP32 😕 ? Anyway, this branch and addition works for me, many thanks! I would vote for adding it to the upstream.

brandond commented 4 years ago

I'll admit I haven't tried it on an esp8266 yet. I do have a couple around I can test with. I'm not sure why it would be significantly slower, the total number of changes should be about the same. I can look at inlining some of the more common math bits or precalculating the groups to see if that helps.

wwebers commented 4 years ago

Any news regarding brandons proposal?

brandond commented 4 years ago

I will admit that I have yet to test this on an esp8266. I also want to add some more row and column controls before I merge it.

Also needs docs.