esphome:
  name: bunt
  friendly_name: bunt
  on_boot:
    priority: -10
    then:
      - delay: 3s
      - script.execute: send_program_list
      - delay: 3s
      - lambda: |-
          id(current_program) = 0;
          id(play_program).execute();

esp32:
  board: m5stack-atom
  framework:
    type: esp-idf

# ---------------------------------------------------------------------------
# LOGGING & API
# ---------------------------------------------------------------------------
logger:
  level: DEBUG

api:
  encryption:
    key: !secret buntkey

ota:
  - platform: esphome
    password: !secret buntpassword

captive_portal:

# ---------------------------------------------------------------------------
# NETZWERK
# ---------------------------------------------------------------------------
wifi:
  power_save_mode: none
  fast_connect: true
  networks:
    - ssid: !secret wifi10_ssid
      password: !secret wifi10_password
      priority: 100
    - ssid: !secret wifi2_ssid
      password: !secret wifi2_password
      priority: 50
    - ssid: !secret wifi3_ssid
      password: !secret wifi2_password
      priority: 50
    - ssid: !secret wifi4_ssid
      password: !secret wifi4_password
      priority: 10
  ap:
    ssid: "Bunt Fallback Hotspot"
    password: !secret wifi10_password
  on_connect:
    then:
      - delay: 2s
      - script.execute: send_program_list

# ---------------------------------------------------------------------------
# ESP-NOW
# ---------------------------------------------------------------------------
espnow:
  auto_add_peer: true
  peers:
    - !secret gelbmac
    - !secret orangemac
  on_receive:
    then:
      - lambda: |-
          std::string data_str((const char*)data, size);
          if (data_str.length() < 2) return;
          std::string prefix = data_str.substr(0, 2);
          std::string val_str = data_str.substr(2);

          if (prefix == "p:") {
            int prog = atoi(val_str.c_str());
            if (prog == -1) {
              id(matrix_light).turn_off().perform();
              id(current_program) = -1;
            } else {
              id(current_program) = prog;
              id(play_program).execute();
            }
          }
          else if (data_str == "r:list") {
            id(send_program_list).execute();
          }
          else if (prefix == "h:") {
            int pct = atoi(val_str.c_str());
            const float MAX_CAP = 0.6f;
            id(max_brightness) = (pct / 100.0f) * MAX_CAP;
            if (id(current_program) >= 0) {
              auto call = id(matrix_light).turn_on();
              call.set_brightness(id(max_brightness));
              call.perform();
            }
          }
          else if (prefix == "k:") {
            id(base_color) = atoi(val_str.c_str());
            if (id(current_program) >= 0) {
              id(play_program).execute();
            }
          }
          else if (prefix == "m:") {
            size_t colon = val_str.find(':');
            if (colon != std::string::npos) {
              id(scroll_variant) = atoi(val_str.substr(0, colon).c_str());
              id(scroll_text)    = val_str.substr(colon + 1);
            }
            id(current_program) = 10;
            id(play_program).execute();
          }
          else if (prefix == "s:") {
            id(scroll_variant) = atoi(val_str.c_str());
          }
          else if (prefix == "x:") {
            id(matrix_light).turn_off().perform();
            id(current_program) = -1;
          }
          // ── Matrix-Breite setzen ──────────────────────────────────────
          else if (prefix == "w:") {
            int w = atoi(val_str.c_str());
            if (w >= 8 && w <= 96) {
              id(matrix_width) = w;
              ESP_LOGI("bunt", "Matrix-Breite: %d", w);
              // Laufendes Programm neu starten damit Größe sofort wirkt
              if (id(current_program) >= 0) {
                id(play_program).execute();
              }
            }
          }

# ---------------------------------------------------------------------------
# GLOBALS
# ---------------------------------------------------------------------------
globals:
  - id: current_program
    type: int
    initial_value: '-1'
  - id: max_brightness
    type: float
    initial_value: '0.6'
  - id: demo_index
    type: int
    initial_value: '0'
  - id: scroll_text
    type: std::string
    initial_value: '"Laufschrift"'
  - id: scroll_variant
    type: int
    initial_value: '1'
  - id: base_color
    type: int
    initial_value: '0'
  # Matrix-Breite wird im NVS gespeichert
  - id: matrix_width
    type: int
    restore_value: true
    initial_value: '32'

# ---------------------------------------------------------------------------
# INTERVAL  –  Demo-Modus
# ---------------------------------------------------------------------------
interval:
  - interval: 30s
    then:
      - lambda: |-
          if (id(current_program) != 8) return;
          const char* effects[] = {
            "Knight Rider", "Regenbogen", "Regenbogen Diagonal", "Feuer",
            "Matrix-Regen", "Farbwellen", "Sternenhimmel", "Lauflicht",
            "Knight Rider Feuer"
          };
          const int NUM_EFFECTS = 9;
          id(demo_index) = (id(demo_index) + 1) % NUM_EFFECTS;
          auto call = id(matrix_light).turn_on();
          call.set_brightness(id(max_brightness));
          call.set_effect(effects[id(demo_index)]);
          call.perform();

# ---------------------------------------------------------------------------
# NEOPIXEL  –  max. 96x8 = 768 LEDs, aktive Breite via matrix_width
# ---------------------------------------------------------------------------
light:
  - platform: esp32_rmt_led_strip
    id: matrix_light
    pin: GPIO32
    num_leds: 768
    chipset: WS2812
    rgb_order: GRB
    name: "Bunt Matrix"
    default_transition_length: 0s
    restore_mode: ALWAYS_OFF

    effects:

      # ── 1. Knight Rider (Basisfarbe) ─────────────────────────────────
      - addressable_lambda:
          name: "Knight Rider"
          update_interval: 30ms
          lambda: |-
            auto XY = [](int x, int y, int W, int H) -> int {
              if (x % 2 == 0) return x * H + y;
              else            return x * H + (H - 1 - y);
            };
            static int pos=0, dir=1;
            static float tr[96]={0};
            const int W = id(matrix_width), H = 8;
            // Nicht verwendete Pixel löschen
            for (int i = W*H; i < 768; i++) it[i] = Color(0,0,0);
            for (int x=0;x<W;x++) tr[x]*=0.75f;
            if (pos >= W) pos = W-1;
            tr[pos]=255.0f;
            int bc = id(base_color);
            for(int y=0;y<H;y++) for(int x=0;x<W;x++) {
              uint8_t b=(uint8_t)tr[x]; Color c;
              if      (bc==0) c=Color(b,0,0);
              else if (bc==1) c=Color(0,b,0);
              else if (bc==2) c=Color(0,0,b);
              else            c=Color(b,b/2,0);
              it[XY(x,y,W,H)]=c;
            }
            pos+=dir;
            if(pos>=W-1){pos=W-1;dir=-1;} if(pos<=0){pos=0;dir=1;}

      # ── 2. Regenbogen ─────────────────────────────────────────────────
      - addressable_lambda:
          name: "Regenbogen"
          update_interval: 50ms
          lambda: |-
            auto XY = [](int x, int y, int W, int H) -> int {
              if (x % 2 == 0) return x * H + y;
              else            return x * H + (H - 1 - y);
            };
            static uint16_t offset = 0;
            const int W = id(matrix_width), H = 8;
            for (int i = W*H; i < 768; i++) it[i] = Color(0,0,0);
            for (int y=0;y<H;y++)
              for (int x=0;x<W;x++)
                it[XY(x,y,W,H)] = ESPHSVColor((uint8_t)((offset + x*8) & 0xFF), 255, 220);
            offset = (offset + 2) & 0xFF;

      # ── 3. Regenbogen Diagonal ────────────────────────────────────────
      - addressable_lambda:
          name: "Regenbogen Diagonal"
          update_interval: 50ms
          lambda: |-
            auto XY = [](int x, int y, int W, int H) -> int {
              if (x % 2 == 0) return x * H + y;
              else            return x * H + (H - 1 - y);
            };
            static uint16_t offset = 0;
            const int W = id(matrix_width), H = 8;
            for (int i = W*H; i < 768; i++) it[i] = Color(0,0,0);
            for (int y=0;y<H;y++)
              for (int x=0;x<W;x++)
                it[XY(x,y,W,H)] = ESPHSVColor((uint8_t)((offset + x*6 + y*12) & 0xFF), 255, 200);
            offset = (offset + 2) & 0xFF;

      # ── 4. Feuer ───────────────────────────────────────────────────────
      - addressable_lambda:
          name: "Feuer"
          update_interval: 50ms
          lambda: |-
            auto XY = [](int x, int y, int W, int H) -> int {
              if (x % 2 == 0) return x * H + y;
              else            return x * H + (H - 1 - y);
            };
            static uint8_t heat[768] = {0};
            const int W = id(matrix_width), H = 8;
            for (int i = W*H; i < 768; i++) it[i] = Color(0,0,0);
            for (int i=0;i<W*H;i++) { uint8_t c=esp_random()%3; heat[i]=heat[i]>c?heat[i]-c:0; }
            for (int y=0;y<=H-3;y++) for (int x=0;x<W;x++)
              heat[y*W+x]=(heat[(y+1)*W+x]+heat[(y+2)*W+x]+heat[(y+1)*W+(x>0?x-1:x)])/3;
            for (int x=0;x<W;x++) if((esp_random()%4)<3) heat[(H-1)*W+x]=160+(esp_random()%95);
            for (int y=0;y<H;y++) for (int x=0;x<W;x++) {
              uint8_t h=heat[y*W+x]; Color c;
              if(h<85) c=Color(h*3,0,0); else if(h<170) c=Color(255,(h-85)*3,0); else c=Color(255,255,(h-170)*3);
              it[XY(x,y,W,H)]=c;
            }

      # ── 5. Matrix-Regen (immer grün) ──────────────────────────────────
      - addressable_lambda:
          name: "Matrix-Regen"
          update_interval: 80ms
          lambda: |-
            auto XY = [](int x, int y, int W, int H) -> int {
              if (x % 2 == 0) return x * H + y;
              else            return x * H + (H - 1 - y);
            };
            static uint8_t dp[96]={0}, don[96]={0}, br[768]={0};
            const int W = id(matrix_width), H = 8;
            for (int i = W*H; i < 768; i++) it[i] = Color(0,0,0);
            for(int i=0;i<W*H;i++) br[i]=br[i]>25?br[i]-25:0;
            for(int x=0;x<W;x++) {
              if(don[x]){br[dp[x]*W+x]=255;dp[x]++;if(dp[x]>=H){dp[x]=0;don[x]=0;}}
              else if((esp_random()%6)==0){don[x]=1;dp[x]=0;}
            }
            for(int y=0;y<H;y++) for(int x=0;x<W;x++)
              it[XY(x,y,W,H)] = Color(0, br[y*W+x], 0);

      # ── 6. Farbwellen ─────────────────────────────────────────────────
      - addressable_lambda:
          name: "Farbwellen"
          update_interval: 50ms
          lambda: |-
            auto XY = [](int x, int y, int W, int H) -> int {
              if (x % 2 == 0) return x * H + y;
              else            return x * H + (H - 1 - y);
            };
            static float t=0.0f;
            const int W = id(matrix_width), H = 8;
            for (int i = W*H; i < 768; i++) it[i] = Color(0,0,0);
            for(int y=0;y<H;y++) for(int x=0;x<W;x++) {
              float wave=sinf(x*0.35f+t)*sinf(y*0.7f+t*0.6f);
              it[XY(x,y,W,H)]=ESPHSVColor((uint8_t)(((int)(x*7+y*15+t*18))&0xFF),240,(uint8_t)((wave+1.0f)*100.0f)+30);
            }
            t+=0.08f; if(t>1000.0f) t=0.0f;

      # ── 7. Sternenhimmel ───────────────────────────────────────────────
      - addressable_lambda:
          name: "Sternenhimmel"
          update_interval: 80ms
          lambda: |-
            auto XY = [](int x, int y, int W, int H) -> int {
              if (x % 2 == 0) return x * H + y;
              else            return x * H + (H - 1 - y);
            };
            static uint8_t br[768]={0}; static int8_t dir[768]={0};
            const int W = id(matrix_width), H = 8;
            for (int i = W*H; i < 768; i++) it[i] = Color(0,0,0);
            if(initial_run) for(int i=0;i<W*H;i++){br[i]=esp_random()%60;dir[i]=(esp_random()%2)?3:-3;}
            for(int y=0;y<H;y++) for(int x=0;x<W;x++) {
              int i=y*W+x; int16_t nb=(int16_t)br[i]+dir[i];
              if(nb>=220){nb=220;dir[i]=-(int8_t)(3+esp_random()%3);}
              if(nb<=0){nb=0;dir[i]=(int8_t)(2+esp_random()%4);if((esp_random()%3)==0)nb=esp_random()%10;}
              br[i]=(uint8_t)nb; uint8_t b=br[i];
              it[XY(x,y,W,H)]=Color(b,b,b<40?0:b);
            }

      # ── 8. Lauflicht (Basisfarbe) ─────────────────────────────────────
      - addressable_lambda:
          name: "Lauflicht"
          update_interval: 40ms
          lambda: |-
            auto XY = [](int x, int y, int W, int H) -> int {
              if (x % 2 == 0) return x * H + y;
              else            return x * H + (H - 1 - y);
            };
            static int pos=0; static bool fwd=true; static uint8_t tr[96]={0};
            const int W = id(matrix_width), H = 8;
            for (int i = W*H; i < 768; i++) it[i] = Color(0,0,0);
            for(int x=0;x<W;x++) tr[x]=tr[x]>18?tr[x]-18:0;
            if(pos>=W) pos=W-1;
            tr[pos]=255;
            int bc=id(base_color);
            for(int y=0;y<H;y++) for(int x=0;x<W;x++) {
              uint8_t b=tr[x]; Color c;
              if      (bc==0) c=Color(b,0,0);
              else if (bc==1) c=Color(0,b,0);
              else if (bc==2) c=Color(0,0,b);
              else            c=Color(b,b/2,0);
              it[XY(x,y,W,H)]=c;
            }
            if(fwd){pos++;if(pos>=W){pos=W-1;fwd=false;}} else{pos--;if(pos<0){pos=0;fwd=true;}}

      # ── 9. Demo ───────────────────────────────────────────────────────
      - addressable_lambda:
          name: "Demo"
          update_interval: 50ms
          lambda: |-
            auto XY = [](int x, int y, int W, int H) -> int {
              if (x % 2 == 0) return x * H + y;
              else            return x * H + (H - 1 - y);
            };
            static uint16_t offset = 0;
            const int W = id(matrix_width), H = 8;
            for (int i = W*H; i < 768; i++) it[i] = Color(0,0,0);
            for(int y=0;y<H;y++)
              for(int x=0;x<W;x++)
                it[XY(x,y,W,H)] = ESPHSVColor((uint8_t)((offset + x*8) & 0xFF), 255, 220);
            offset = (offset + 2) & 0xFF;

      # ── 10. Knight Rider Feuer (Basisfarbe) ───────────────────────────
      - addressable_lambda:
          name: "Knight Rider Feuer"
          update_interval: 30ms
          lambda: |-
            auto XY = [](int x, int y, int W, int H) -> int {
              if (x % 2 == 0) return x * H + y;
              else            return x * H + (H - 1 - y);
            };
            static int pos=0, dir=1;
            static float tr[8][96]={{0}};
            const int W = id(matrix_width), H = 8;
            for (int i = W*H; i < 768; i++) it[i] = Color(0,0,0);
            for(int y=0;y<H;y++) for(int x=0;x<W;x++){
              if(tr[y][x]>10.0f&&(esp_random()%4)==0) tr[y][x]*=1.1f;
              tr[y][x]*=0.80f; if(tr[y][x]<1.0f) tr[y][x]=0.0f;
            }
            if(pos>=W) pos=W-1;
            for(int y=0;y<H;y++){
              int off=(int)(((float)(H-1-y)/(float)(H-1))*2.0f+0.5f);
              int fx=pos+(dir>0?off:-off); fx=std::max(0,std::min(W-1,fx));
              tr[y][fx]=255.0f; int fx2=fx+dir; if(fx2>=0&&fx2<W) tr[y][fx2]=180.0f;
            }
            int bc=id(base_color);
            for(int y=0;y<H;y++) for(int x=0;x<W;x++){
              uint8_t b=(uint8_t)tr[y][x]; Color c;
              if(bc==0){if(b>200)c=Color(255,200,b-200);else if(b>120)c=Color(255,b-120,0);else c=Color(b,0,0);}
              else if(bc==1){if(b>200)c=Color(200,255,b-200);else if(b>120)c=Color(b-120,255,0);else c=Color(0,b,0);}
              else if(bc==2){if(b>200)c=Color(b-200,200,255);else if(b>120)c=Color(0,b-120,255);else c=Color(0,0,b);}
              else{if(b>200)c=Color(255,255,b-200);else if(b>120)c=Color(255,b-120,0);else c=Color(b,b/3,0);}
              it[XY(x,y,W,H)]=c;
            }
            pos+=dir;
            if(pos>=W-1){pos=W-1;dir=-1;} if(pos<=0){pos=0;dir=1;}

      # ── 11. Laufschrift ───────────────────────────────────────────────
      - addressable_lambda:
          name: "Laufschrift"
          update_interval: 40ms
          lambda: |-
            auto XY = [](int x, int y, int W, int H) -> int {
              if (x % 2 == 0) return x * H + y;
              else            return x * H + (H - 1 - y);
            };
            static const uint8_t F[][5] = {
              {0x00,0x00,0x00,0x00,0x00},{0x00,0x00,0x5f,0x00,0x00},{0x00,0x07,0x00,0x07,0x00},
              {0x14,0x7f,0x14,0x7f,0x14},{0x24,0x2a,0x7f,0x2a,0x12},{0x23,0x13,0x08,0x64,0x62},
              {0x36,0x49,0x55,0x22,0x50},{0x00,0x05,0x03,0x00,0x00},{0x00,0x1c,0x22,0x41,0x00},
              {0x00,0x41,0x22,0x1c,0x00},{0x14,0x08,0x3e,0x08,0x14},{0x08,0x08,0x3e,0x08,0x08},
              {0x00,0x50,0x30,0x00,0x00},{0x08,0x08,0x08,0x08,0x08},{0x00,0x60,0x60,0x00,0x00},
              {0x20,0x10,0x08,0x04,0x02},{0x3e,0x51,0x49,0x45,0x3e},{0x00,0x42,0x7f,0x40,0x00},
              {0x42,0x61,0x51,0x49,0x46},{0x21,0x41,0x45,0x4b,0x31},{0x18,0x14,0x12,0x7f,0x10},
              {0x27,0x45,0x45,0x45,0x39},{0x3c,0x4a,0x49,0x49,0x30},{0x01,0x71,0x09,0x05,0x03},
              {0x36,0x49,0x49,0x49,0x36},{0x06,0x49,0x49,0x29,0x1e},{0x00,0x36,0x36,0x00,0x00},
              {0x00,0x56,0x36,0x00,0x00},{0x08,0x14,0x22,0x41,0x00},{0x14,0x14,0x14,0x14,0x14},
              {0x00,0x41,0x22,0x14,0x08},{0x02,0x01,0x51,0x09,0x06},{0x32,0x49,0x79,0x41,0x3e},
              {0x7e,0x11,0x11,0x11,0x7e},{0x7f,0x49,0x49,0x49,0x36},{0x3e,0x41,0x41,0x41,0x22},
              {0x7f,0x41,0x41,0x22,0x1c},{0x7f,0x49,0x49,0x49,0x41},{0x7f,0x09,0x09,0x09,0x01},
              {0x3e,0x41,0x49,0x49,0x7a},{0x7f,0x08,0x08,0x08,0x7f},{0x00,0x41,0x7f,0x41,0x00},
              {0x20,0x40,0x41,0x3f,0x01},{0x7f,0x08,0x14,0x22,0x41},{0x7f,0x40,0x40,0x40,0x40},
              {0x7f,0x02,0x0c,0x02,0x7f},{0x7f,0x04,0x08,0x10,0x7f},{0x3e,0x41,0x41,0x41,0x3e},
              {0x7f,0x09,0x09,0x09,0x06},{0x3e,0x41,0x51,0x21,0x5e},{0x7f,0x09,0x19,0x29,0x46},
              {0x46,0x49,0x49,0x49,0x31},{0x01,0x01,0x7f,0x01,0x01},{0x3f,0x40,0x40,0x40,0x3f},
              {0x1f,0x20,0x40,0x20,0x1f},{0x3f,0x40,0x38,0x40,0x3f},{0x63,0x14,0x08,0x14,0x63},
              {0x07,0x08,0x70,0x08,0x07},{0x61,0x51,0x49,0x45,0x43},{0x00,0x7f,0x41,0x41,0x00},
              {0x02,0x04,0x08,0x10,0x20},{0x00,0x41,0x41,0x7f,0x00},{0x04,0x02,0x01,0x02,0x04},
              {0x40,0x40,0x40,0x40,0x40},{0x00,0x01,0x02,0x04,0x00},{0x20,0x54,0x54,0x54,0x78},
              {0x7f,0x48,0x44,0x44,0x38},{0x38,0x44,0x44,0x44,0x20},{0x38,0x44,0x44,0x48,0x7f},
              {0x38,0x54,0x54,0x54,0x18},{0x08,0x7e,0x09,0x01,0x02},{0x0c,0x52,0x52,0x52,0x3e},
              {0x7f,0x08,0x04,0x04,0x78},{0x00,0x44,0x7d,0x40,0x00},{0x20,0x40,0x44,0x3d,0x00},
              {0x7f,0x10,0x28,0x44,0x00},{0x00,0x41,0x7f,0x40,0x00},{0x7c,0x04,0x18,0x04,0x78},
              {0x7c,0x08,0x04,0x04,0x78},{0x38,0x44,0x44,0x44,0x38},{0x7c,0x14,0x14,0x14,0x08},
              {0x08,0x14,0x14,0x18,0x7c},{0x7c,0x08,0x04,0x04,0x08},{0x48,0x54,0x54,0x54,0x20},
              {0x04,0x3f,0x44,0x40,0x20},{0x3c,0x40,0x40,0x20,0x7c},{0x1c,0x20,0x40,0x20,0x1c},
              {0x3c,0x40,0x30,0x40,0x3c},{0x44,0x28,0x10,0x28,0x44},{0x0c,0x50,0x50,0x50,0x3c},
              {0x44,0x64,0x54,0x4c,0x44},{0x00,0x08,0x36,0x41,0x00},{0x00,0x00,0x7f,0x00,0x00},
              {0x00,0x41,0x36,0x08,0x00},{0x10,0x08,0x08,0x10,0x08},
              {0x20,0x55,0x54,0x55,0x78},{0x38,0x45,0x44,0x45,0x38},{0x3c,0x41,0x40,0x21,0x7c},
              {0x7e,0x12,0x11,0x12,0x7e},{0x3e,0x42,0x41,0x42,0x3e},{0x3f,0x41,0x40,0x41,0x3f},
              {0x7e,0x09,0x49,0x36,0x00},
            };
            const int W = id(matrix_width), H = 8;
            for (int i = W*H; i < 768; i++) it[i] = Color(0,0,0);
            static std::string last_txt = "";
            static int scroll_pos = 32;
            std::string& txt = id(scroll_text);
            int var = id(scroll_variant);
            if (txt != last_txt) { last_txt = txt; scroll_pos = W; }
            int char_count = 0;
            for (int i = 0; i < (int)txt.size(); i++) {
              uint8_t b = (uint8_t)txt[i];
              if (b == 0xC3 && i+1 < (int)txt.size()) { i++; char_count++; }
              else if (b >= 0x20 && b <= 0x7e) char_count++;
            }
            int txt_px = char_count * 6;
            it.all() = Color(0, 0, 0);
            Color tc;
            if      (var==0) tc=Color(0,100,255);
            else if (var==1) tc=Color(0,255,0);
            else if (var==2) tc=Color(255,140,0);
            else             tc=Color(255,0,0);
            int xc = scroll_pos;
            for (int i = 0; i < (int)txt.size() && xc < W; i++) {
              uint8_t b = (uint8_t)txt[i];
              int fi = 0;
              if (b == 0xC3 && i+1 < (int)txt.size()) {
                uint8_t n = (uint8_t)txt[++i];
                if(n==0xA4)fi=95; else if(n==0xB6)fi=96; else if(n==0xBC)fi=97;
                else if(n==0x84)fi=98; else if(n==0x96)fi=99; else if(n==0x9C)fi=100;
                else if(n==0x9F)fi=101; else fi=0x3f-0x20;
              } else if (b>=0x20&&b<=0x7e) { fi=b-0x20; } else continue;
              for (int col=0;col<5;col++) {
                int px=xc+col;
                if (px>=0&&px<W) {
                  uint8_t cd=F[fi][col];
                  for (int row=0;row<7;row++)
                    if(cd&(1<<row)) it[XY(px,row,W,H)]=tc;
                }
              }
              xc+=6;
            }
            scroll_pos--;
            if (scroll_pos < -(txt_px+4)) scroll_pos = W;

# ---------------------------------------------------------------------------
# SCRIPT: Programmliste an Gelb senden
# ---------------------------------------------------------------------------
script:
  - id: send_program_list
    then:
      - espnow.send:
          address: !secret gelbmac
          data: !lambda |-
            std::string s = "n:0:Knight Rider";
            return std::vector<uint8_t>(s.begin(), s.end());
      - espnow.send:
          address: !secret orangemac
          data: !lambda |-
            std::string s = "n:0:Knight Rider";
            return std::vector<uint8_t>(s.begin(), s.end());
      - delay: 200ms
      - espnow.send:
          address: !secret gelbmac
          data: !lambda |-
            std::string s = "n:1:Regenbogen";
            return std::vector<uint8_t>(s.begin(), s.end());
      - espnow.send:
          address: !secret orangemac
          data: !lambda |-
            std::string s = "n:1:Regenbogen";
            return std::vector<uint8_t>(s.begin(), s.end());
      - delay: 200ms
      - espnow.send:
          address: !secret gelbmac
          data: !lambda |-
            std::string s = "n:2:Regenbogen Diagonal";
            return std::vector<uint8_t>(s.begin(), s.end());
      - espnow.send:
          address: !secret orangemac
          data: !lambda |-
            std::string s = "n:2:Regenbogen Diagonal";
            return std::vector<uint8_t>(s.begin(), s.end());
      - delay: 200ms
      - espnow.send:
          address: !secret gelbmac
          data: !lambda |-
            std::string s = "n:3:Feuer";
            return std::vector<uint8_t>(s.begin(), s.end());
      - espnow.send:
          address: !secret orangemac
          data: !lambda |-
            std::string s = "n:3:Feuer";
            return std::vector<uint8_t>(s.begin(), s.end());
      - delay: 200ms
      - espnow.send:
          address: !secret gelbmac
          data: !lambda |-
            std::string s = "n:4:Matrix-Regen";
            return std::vector<uint8_t>(s.begin(), s.end());
      - espnow.send:
          address: !secret orangemac
          data: !lambda |-
            std::string s = "n:4:Matrix-Regen";
            return std::vector<uint8_t>(s.begin(), s.end());
      - delay: 200ms
      - espnow.send:
          address: !secret gelbmac
          data: !lambda |-
            std::string s = "n:5:Farbwellen";
            return std::vector<uint8_t>(s.begin(), s.end());
      - espnow.send:
          address: !secret orangemac
          data: !lambda |-
            std::string s = "n:5:Farbwellen";
            return std::vector<uint8_t>(s.begin(), s.end());
      - delay: 200ms
      - espnow.send:
          address: !secret gelbmac
          data: !lambda |-
            std::string s = "n:6:Sternenhimmel";
            return std::vector<uint8_t>(s.begin(), s.end());
      - espnow.send:
          address: !secret orangemac
          data: !lambda |-
            std::string s = "n:6:Sternenhimmel";
            return std::vector<uint8_t>(s.begin(), s.end());
      - delay: 200ms
      - espnow.send:
          address: !secret gelbmac
          data: !lambda |-
            std::string s = "n:7:Lauflicht";
            return std::vector<uint8_t>(s.begin(), s.end());
      - espnow.send:
          address: !secret orangemac
          data: !lambda |-
            std::string s = "n:7:Lauflicht";
            return std::vector<uint8_t>(s.begin(), s.end());
      - delay: 200ms
      - espnow.send:
          address: !secret gelbmac
          data: !lambda |-
            std::string s = "n:8:Demo";
            return std::vector<uint8_t>(s.begin(), s.end());
      - espnow.send:
          address: !secret orangemac
          data: !lambda |-
            std::string s = "n:8:Demo";
            return std::vector<uint8_t>(s.begin(), s.end());
      - delay: 200ms
      - espnow.send:
          address: !secret gelbmac
          data: !lambda |-
            std::string s = "n:9:Knight Rider Feuer";
            return std::vector<uint8_t>(s.begin(), s.end());
      - espnow.send:
          address: !secret orangemac
          data: !lambda |-
            std::string s = "n:9:Knight Rider Feuer";
            return std::vector<uint8_t>(s.begin(), s.end());
      - delay: 200ms
      - espnow.send:
          address: !secret gelbmac
          data: !lambda |-
            std::string s = "n:10:Laufschrift";
            return std::vector<uint8_t>(s.begin(), s.end());
      - espnow.send:
          address: !secret orangemac
          data: !lambda |-
            std::string s = "n:10:Laufschrift";
            return std::vector<uint8_t>(s.begin(), s.end());
      - delay: 200ms
      - espnow.send:
          address: !secret gelbmac
          data: !lambda |-
            std::string s = "n:END";
            return std::vector<uint8_t>(s.begin(), s.end());
      - espnow.send:
          address: !secret orangemac
          data: !lambda |-
            std::string s = "n:END";
            return std::vector<uint8_t>(s.begin(), s.end());

  - id: play_program
    then:
      - lambda: |-
          auto call = id(matrix_light).turn_on();
          call.set_brightness(id(max_brightness));
          switch (id(current_program)) {
            case 0:  call.set_effect("Knight Rider");        break;
            case 1:  call.set_effect("Regenbogen");          break;
            case 2:  call.set_effect("Regenbogen Diagonal"); break;
            case 3:  call.set_effect("Feuer");               break;
            case 4:  call.set_effect("Matrix-Regen");        break;
            case 5:  call.set_effect("Farbwellen");          break;
            case 6:  call.set_effect("Sternenhimmel");       break;
            case 7:  call.set_effect("Lauflicht");           break;
            case 8:
              id(demo_index) = 0;
              call.set_effect("Knight Rider");
              break;
            case 9:  call.set_effect("Knight Rider Feuer"); break;
            case 10: call.set_effect("Laufschrift");        break;
            default:
              id(matrix_light).turn_off().perform();
              return;
          }
          call.perform();
