substitutions: hostname: tablica-wyjsciowa esphome: name: ${hostname} on_boot: priority: -100 then: # Start the LED at boot with the test sequence running - light.turn_on: id: led_strip brightness: 100% effect: "Sequence" esp32: board: esp-wrover-kit framework: type: arduino logger: ota: - platform: esphome web_server: port: 80 ethernet: type: LAN8720 mdc_pin: GPIO23 mdio_pin: GPIO18 clk_mode: GPIO17_OUT phy_addr: 0 mqtt: broker: !secret mqtt_host port: 1883 username: !secret mqtt_user password: !secret mqtt_password reboot_timeout: 0s # keep running even if the broker is briefly unreachable # Per-room status codes, indexed by the physical row order of the panel # (ROOM_NAMES in tablica_wyjsciowa/generate_panel.py): # 0 Wejście, 1 Audytorium, 2 Korytarz, 3 Elelab, 4 Arts & Crafts, # 5 Łazienka, 6 Magazynek, 7 Kuźnia, 8 CNC, 9 Maszynownia # Values: 0 = green, 1 = red, 2 = red blinking, -1 = unknown (LED off). globals: - id: room_status type: int[10] restore_value: no initial_value: '{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}' # One subscription per room; on_value parses the "0"/"1"/"2" payload into the # matching room_status slot. text_sensor: - platform: mqtt_subscribe id: room_0 topic: "exit_board/8706711b-6465-45d8-9e7e-a1b4ed02b4c3" # Wejście on_value: - lambda: 'id(room_status)[0] = atoi(x.c_str());' - platform: mqtt_subscribe id: room_1 topic: "exit_board/681d6e64-6a6b-4cae-b393-d265a051a0b0" # Audytorium on_value: - lambda: 'id(room_status)[1] = atoi(x.c_str());' - platform: mqtt_subscribe id: room_2 topic: "exit_board/3ac4b8f1-a88e-4fcf-9443-7d161717968f" # Korytarz on_value: - lambda: 'id(room_status)[2] = atoi(x.c_str());' - platform: mqtt_subscribe id: room_3 topic: "exit_board/7314b325-f673-4a67-a6e4-4ce1d9325cf6" # Elelab on_value: - lambda: 'id(room_status)[3] = atoi(x.c_str());' - platform: mqtt_subscribe id: room_4 topic: "exit_board/3af90d15-dbd3-405c-aa04-447829856ca1" # Arts & Crafts on_value: - lambda: 'id(room_status)[4] = atoi(x.c_str());' - platform: mqtt_subscribe id: room_5 topic: "exit_board/a6cd3850-91aa-4719-9824-212075c75e45" # Łazienka on_value: - lambda: 'id(room_status)[5] = atoi(x.c_str());' - platform: mqtt_subscribe id: room_6 topic: "exit_board/528c5e8c-660f-4544-be0b-1c2c6a007c89" # Magazynek on_value: - lambda: 'id(room_status)[6] = atoi(x.c_str());' - platform: mqtt_subscribe id: room_7 topic: "exit_board/426acc7e-e544-4a2e-ac17-5fbb16d71027" # Kuźnia on_value: - lambda: 'id(room_status)[7] = atoi(x.c_str());' - platform: mqtt_subscribe id: room_8 topic: "exit_board/c0bc933f-7321-4437-9a09-7f2edfebd23d" # CNC on_value: - lambda: 'id(room_status)[8] = atoi(x.c_str());' - platform: mqtt_subscribe id: room_9 topic: "exit_board/699741b2-298a-4c4a-a017-3d61ec1e321c" # Maszynownia on_value: - lambda: 'id(room_status)[9] = atoi(x.c_str());' # 4x WS2805 (5 channels each = 20 monochrome LEDs) on GPIO2. # WS2805 is a 5-channel IC, but ESPHome addressable lights model max 4 # channels/pixel, so we drive the strip as plain RGB pixels and walk the raw # channel bytes individually. 7 RGB pixels = 21 bytes, enough for the 20 # monochrome channels. Timing uses the WS2812 chipset preset (close to WS2805); # switch to explicit bitN_high/low timings here if you see flicker. light: - platform: esp32_rmt_led_strip id: led_strip name: "LED strip" pin: GPIO2 num_leds: 7 chipset: WS2812 rgb_order: RGB default_transition_length: 0s effects: # Boot self-test (all on 3s, then each channel 100ms) followed by live # room-status rendering. LEDs are wired GREEN, RED, GREEN, RED... so # room r uses channel 2*r (green) and 2*r+1 (red). - addressable_lambda: name: "Sequence" update_interval: 50ms lambda: |- static uint32_t start = 0; if (start == 0) start = millis(); uint32_t elapsed = millis() - start; const int TOTAL = 20; // 20 monochrome channels const uint32_t ALL_MS = 3000; // all-on phase const uint32_t STEP_MS = 100; // per-channel walk const uint32_t SEQ_END = ALL_MS + (uint32_t) TOTAL * STEP_MS; // raw channel -> RGB pixel byte (pixel = ch/3, sub = ch%3) auto set_ch = [&](int ch, uint8_t v) { int p = ch / 3; switch (ch % 3) { case 0: it[p].set_red(v); break; case 1: it[p].set_green(v); break; case 2: it[p].set_blue(v); break; } }; it.all() = Color::BLACK; if (elapsed < ALL_MS) { // test: all on for (int ch = 0; ch < TOTAL; ch++) set_ch(ch, 255); } else if (elapsed < SEQ_END) { // test: walk each int ch = (elapsed - ALL_MS) / STEP_MS; if (ch >= 0 && ch < TOTAL) set_ch(ch, 255); } else { // live render bool blink_on = ((millis() / 500) % 2) == 0; // 1 Hz for (int r = 0; r < 10; r++) { int g = 2 * r, red = 2 * r + 1; switch (id(room_status)[r]) { case 0: set_ch(g, 255); break; // green case 1: set_ch(red, 255); break; // red case 2: if (blink_on) set_ch(red, 255); break; // blink red default: break; // unknown: off } } }