CCCPaste

lilka + display + battery + button + server

esphome:
  name: lilka
  friendly_name: lilka
  on_boot:
    priority: 600
    then:
      - output.turn_on: display_power
      - delay: 100ms

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: esp-idf

logger:

api:
  encryption:
    key: "Yw3yq8lxsaze+jdggjAwxKpV4GD6gNZptvw4d6OPfOc="

ota:
  - platform: esphome
    password: "bb198feb99159fdaefc8092f10039acd"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: "Lilka Fallback Hotspot"
    password: "hnYImYM4O6I0"

captive_portal:

web_server:
  port: 80

# Живлення дисплея
output:
  - platform: gpio
    pin: 46
    id: display_power
    inverted: false

# Глобальні змінні для підрахунку натискань
globals:
  - id: up_count
    type: int
    restore_value: no
    initial_value: '0'
  - id: down_count
    type: int
    restore_value: no
    initial_value: '0'
  - id: left_count
    type: int
    restore_value: no
    initial_value: '0'
  - id: right_count
    type: int
    restore_value: no
    initial_value: '0'

# Кнопки
binary_sensor:
  - platform: gpio
    pin:
      number: 38
      mode: INPUT_PULLUP
      inverted: true
    name: "Button Up"
    id: button_up
    filters:
      - delayed_on: 10ms
    on_press:
      then:
        - logger.log: "UP pressed"
        - globals.set:
            id: up_count
            value: !lambda 'return id(up_count) + 1;'
    
  - platform: gpio
    pin:
      number: 41
      mode: INPUT_PULLUP
      inverted: true
    name: "Button Down"
    id: button_down
    filters:
      - delayed_on: 10ms
    on_press:
      then:
        - logger.log: "DOWN pressed"
        - globals.set:
            id: down_count
            value: !lambda 'return id(down_count) + 1;'
    
  - platform: gpio
    pin:
      number: 39
      mode: INPUT_PULLUP
      inverted: true
    name: "Button Left"
    id: button_left
    filters:
      - delayed_on: 10ms
    on_press:
      then:
        - logger.log: "LEFT pressed"
        - globals.set:
            id: left_count
            value: !lambda 'return id(left_count) + 1;'
    
  - platform: gpio
    pin:
      number: 40
      mode: INPUT_PULLUP
      inverted: true
    name: "Button Right"
    id: button_right
    filters:
      - delayed_on: 10ms
    on_press:
      then:
        - logger.log: "RIGHT pressed"
        - globals.set:
            id: right_count
            value: !lambda 'return id(right_count) + 1;'

# Батарея
sensor:
  - platform: adc
    pin: GPIO3
    name: "Battery Voltage"
    id: battery_voltage
    update_interval: 10s
    attenuation: 11db
    filters:
      - multiply: 1.33
      
  - platform: template
    name: "Battery Level"
    id: battery_level
    unit_of_measurement: "%"
    accuracy_decimals: 0
    update_interval: 10s
    lambda: |-
      float voltage = id(battery_voltage).state;
      float percent = (voltage - 3.0) / (4.2 - 3.0) * 100.0;
      if (percent > 100) percent = 100;
      if (percent < 0) percent = 0;
      return percent;

# SPI
spi:
  clk_pin: 18
  mosi_pin: 17

# Шрифти
font:
  - file: "gfonts://Roboto"
    id: font_small
    size: 16
  - file: "gfonts://Roboto"
    id: font_large
    size: 24

# Дисплей (поки БЕЗ LVGL)
display:
  - platform: mipi_spi
    model: ST7789V
    dc_pin: 15
    cs_pin: 7
    update_interval: 100ms
    rotation: 270
    invert_colors: false
    color_order: RGB
    pixel_mode: 16bit
    dimensions:
      width: 240
      height: 280
      offset_width: 0
      offset_height: 0
    lambda: |-
      // Фон
      it.fill(Color::BLACK);
      
      // Заголовок
      it.print(120, 20, id(font_large), Color::WHITE, TextAlign::CENTER, "Button Test");
      
      // Лінія
      it.line(20, 50, 220, 50, Color(50, 50, 50));
      
      // Батарея
      if (id(battery_level).has_state()) {
        it.printf(120, 60, id(font_small), Color(0, 255, 0), TextAlign::CENTER, 
                  "Battery: %.0f%%", id(battery_level).state);
      }
      
      // Лічильники кнопок
      int y = 100;
      
      // UP
      it.printf(30, y, id(font_small), 
                id(button_up).state ? Color(0, 255, 0) : Color(100, 100, 100), 
                "UP: %d", id(up_count));
      
      // DOWN
      it.printf(30, y + 30, id(font_small), 
                id(button_down).state ? Color(0, 255, 0) : Color(100, 100, 100), 
                "DOWN: %d", id(down_count));
      
      // LEFT
      it.printf(30, y + 60, id(font_small), 
                id(button_left).state ? Color(0, 255, 0) : Color(100, 100, 100), 
                "LEFT: %d", id(left_count));
      
      // RIGHT
      it.printf(30, y + 90, id(font_small), 
                id(button_right).state ? Color(0, 255, 0) : Color(100, 100, 100), 
                "RIGHT: %d", id(right_count));
      
      // Підказка
      it.print(120, 240, id(font_small), Color(150, 150, 150), 
               TextAlign::CENTER, "Press any button");