esphome:
  name: $devicename
  comment: $comment
  project:
    name: "billament.controller"
    version: "0.1"
  on_boot:
    - priority: -100
      then:
        - lambda: |-
            id(sntp_time).update();
    - priority: 800
      then:
        - switch.turn_on: display_active
        - delay: 3s
        - lvgl.widget.hide: boot_screen

substitutions:
  devicename: "billabox"
  comment: "BILLament Controller"
  domain: !secret domain
  timezone: !secret timezone

esp32:
  board: esp32dev
  framework:
    type: arduino

preferences:
  flash_write_interval: 15s

logger:
  level: DEBUG

api:
  password: !secret api_password
  reboot_timeout: 0s

ota:
  platform: esphome
  password: !secret ota_password

time:
  - platform: sntp
    id: sntp_time
    timezone: ${timezone}
    update_interval: 1h

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  power_save_mode: none
  fast_connect: on
  reboot_timeout: 1min
  domain: .${domain}
  use_address: ${devicename}.${domain}

web_server:
  port: 80
  version: 3
  local: true
  # include_internal: true
  sorting_groups:
    - id: g_environment
      name: "Environment"
      sorting_weight: 10
    - id: g_doors
      name: "Doors"
      sorting_weight: 20
    - id: g_lights
      name: "Lights"
      sorting_weight: 30
    - id: g_controls
      name: "Display"
      sorting_weight: 40
    - id: g_diagnostics
      name: "Diagnostics"
      sorting_weight: 50

prometheus:
  include_internal: true
  relabel:
    rssi:
      id: rssi
      name: RSSI
    device_uptime:
      id: uptime
      name: Uptime

debug:
  update_interval: 5s

i2c:
  sda: 21
  scl: 22
  #frequency: 10kHz

sensor:
  - platform: wifi_signal
    id: rssi
    name: "Wifi Signal"
    web_server:
      sorting_group_id: g_diagnostics
    update_interval: 60s

  - platform: uptime
    id: device_uptime_seconds
    update_interval: 15s
    internal: true
  
  - platform: bme280_i2c
    id: bme280_0
    address: 0x76
    temperature:
      name: "Temperature 0"
      web_server:
        sorting_group_id: g_environment
    pressure:
      name: "Pressure 0"
      internal: true
      web_server:
        sorting_group_id: g_environment
    humidity:
      name: "Humidity 0"
      web_server:
        sorting_group_id: g_environment

  - platform: bme280_i2c
    id: bme280_1
    address: 0x77
    temperature:
      name: "Temperature 1"
      web_server:
        sorting_group_id: g_environment
    pressure:
      name: "Pressure 1"
      internal: true
      web_server:
        sorting_group_id: g_environment
    humidity:
      name: "Humidity 1"
      web_server:
        sorting_group_id: g_environment

  - platform: rotary_encoder
    id: encoder
    name: "Encoder Position"
    web_server:
      sorting_group_id: g_controls
    pin_a: GPIO04
    pin_b: GPIO16
    resolution: 2
    restore_mode: ALWAYS_ZERO
    publish_initial_value: true
    on_clockwise:
      - then:
        - switch.turn_on: display_active
        - lvgl.indicator.update:
            id: val_needle
            value: !lambda 'return id(encoder).state + 1;'
    on_anticlockwise:
      - then:
        - switch.turn_on: display_active
        - lvgl.indicator.update:
            id: val_needle
            value: !lambda 'return id(encoder).state - 1;'

binary_sensor:
  - platform: gpio
    id: encoder_button
    name: "Encoder Button"
    web_server:
      sorting_group_id: g_controls
    pin:
      number: GPIO17
      inverted: true
      mode:
        input: true
        pullup: true
    on_click:
      then:
        - switch.turn_on: display_active
    on_double_click:
      then:
        - light.addressable_set:
            id: lightbars
            red: 0
            green: 0
            blue: 0 
            white: 100%

  - platform: gpio
    id: door_left_closed
    name: "Left Door Closed"
    web_server:
      sorting_group_id: g_doors
    pin:
      number: GPIO18
      inverted: true
      mode:
        input: true
        pullup: true
    on_press:
      then:
        - switch.turn_on: display_active
    on_release:
      then:
        - switch.turn_off: display_active

  - platform: gpio
    id: door_right_closed
    name: "Right Door Closed"
    web_server:
      sorting_group_id: g_doors
    pin:
      number: GPIO19
      inverted: true
      mode:
        input: true
        pullup: true
    on_press:
      then:
        - switch.turn_on: display_active
    on_release:
      then:
        - switch.turn_off: display_active

switch:
  - platform: template
    id: display_active
    name: "Active"
    web_server:
      sorting_group_id: g_controls
    optimistic: true
    restore_mode: ALWAYS_ON
    on_turn_on:
      then:
        - light.turn_on:
            id: display_backlight
            brightness: !lambda 'return id(display_brightness).state / 100.0;'
        - delay: !lambda 'return id(display_timeout).state * 1000;'
        - light.turn_on:
            id: display_backlight
            brightness: !lambda 'return id(display_brightness_dimmed).state / 100.0;'
        - switch.turn_off: display_active
    on_turn_off:
      then:
        - light.turn_on:
            id: display_backlight
            brightness: !lambda 'return id(display_brightness_dimmed).state / 100.0;'

text_sensor:
  - platform: version
    name: "ESPHome Version"
    web_server:
      sorting_group_id: g_diagnostics
    hide_timestamp: true

  - platform: debug
    # device:
    #   name: "Info"
    #   web_server:
    #       sorting_group_id: g_diagnostics
    reset_reason:
      name: "Reset Reason"
      web_server:
          sorting_group_id: g_diagnostics

  - platform: template
    id: device_uptime
    name: "Uptime"
    web_server:
      sorting_group_id: g_diagnostics
    update_interval: 15s
    lambda: |-
      uint32_t dur = id(device_uptime_seconds).state;
      int dys = 0;
      int hrs = 0;
      int mnts = 0;
      if (dur > 86399) {
        dys = trunc(dur / 86400);
        dur = dur - (dys * 86400);
      }
      if (dur > 3599) {
        hrs = trunc(dur / 3600);
        dur = dur - (hrs * 3600);
      }
      if (dur > 59) {
        mnts = trunc(dur / 60);
        dur = dur - (mnts * 60);
      }
      char buffer[38];
      sprintf(buffer, "%ud %02uh %02um %02us", dys, hrs, mnts, dur);
      return {buffer};

button:
  - platform: restart
    id: device_reset
    name: "Reset"
    web_server:
        sorting_group_id: g_diagnostics

spi:
  - id: spi_bus
    clk_pin: GPIO32
    mosi_pin: GPIO33
    # miso_pin: 
    interface: hardware

display:
  - platform: ili9xxx
    model: GC9A01A
    dc_pin: GPIO26
    cs_pin: GPIO27
    reset_pin: GPIO25
    invert_colors: true
    transform:
      swap_xy: true
      mirror_x: true
      mirror_y: true
    auto_clear_enabled: false
    update_interval: never
    #show_test_card: true

output:
  - platform: ledc
    pin: GPIO14
    id: backlight_pwm

light:
  - platform: monochromatic
    id: display_backlight
    name: "Backlight"
    web_server:
      sorting_group_id: g_controls
    internal: true
    output: backlight_pwm
    restore_mode: ALWAYS_ON

  - platform: neopixelbus
    id: lightbars
    name: "Lightbars"
    web_server:
      sorting_group_id: g_lights
    type: WRGB
    variant: WS2811
    pin: GPIO13
    num_leds: 180
    restore_mode: RESTORE_AND_ON
    initial_state:
      color_mode: RGB_WHITE

number:
  - platform: template
    name: "Backlight Timeout"
    web_server:
      sorting_group_id: g_controls
    optimistic: true
    id: display_timeout
    unit_of_measurement: "s"
    initial_value: 30
    restore_value: true
    min_value: 10
    max_value: 180
    step: 5
    mode: box

  - platform: template
    id: display_brightness
    name: "Backlight"
    web_server:
      sorting_group_id: g_controls
    optimistic: true
    unit_of_measurement: "%"
    initial_value: 100
    restore_value: true
    min_value: 0
    max_value: 100
    step: 5
    on_value:
      - switch.turn_on: display_active
      - light.turn_on:
          id: display_backlight
          brightness: !lambda 'return x/100.0;'

  - platform: template
    id: display_brightness_dimmed
    name: "Backlight (Dimmed)"
    web_server:
      sorting_group_id: g_controls
    optimistic: true
    unit_of_measurement: "%"
    initial_value: 20
    restore_value: true
    min_value: 0
    max_value: 100
    step: 5
    on_value:
      then:
        - if:
            condition:
              switch.is_off: display_active
            then:
              - light.turn_on:
                  id: display_backlight
                  brightness: !lambda 'return x/100.0;'

image:
  - file: https://esphome.io/_static/favicon-512x512.png
    id: boot_logo
    resize: 128x128
    type: RGB565

lvgl:
  buffer_size: 25%
  theme:
    label:
      text_color: 0xffffff
  top_layer:
    widgets:
      - obj:
          id: boot_screen
          x: 0
          y: 0
          width: 100%
          height: 100%
          bg_color: 0x000000
          bg_opa: COVER
          radius: 0
          pad_all: 0
          border_width: 0
          widgets:
            - image:
                align: CENTER
                src: boot_logo
                y: -40
            - spinner:
                align: CENTER
                y: 80
                height: 50
                width: 50
                spin_time: 1s
                arc_length: 60deg
                arc_width: 8
                arc_rounded: true
                bg_color: 0xfcfcfc
                indicator:
                  arc_color: 0x18bcf2
                  arc_width: 8
  pages:
    - id: main_page
      bg_color: 0x000000
      widgets:
          - obj:
              height: 240
              width: 240
              align: CENTER
              bg_color: 0x000000
              border_width: 0
              pad_all: 4
              widgets:
                - meter:
                    height: 100%
                    width: 100%
                    border_width: 0
                    bg_opa: TRANSP
                    align: CENTER
                    scales:
                      - range_from: -10
                        range_to: 10
                        angle_range: 180 # sets the total angle to 180 = starts mid left and ends mid right
                        ticks:
                          count: 0
                        indicators:
                          - line:
                              id: val_needle
                              width: 8
                              r_mod: 12 # sets line length by this much difference from the scale default radius
                              value: -2
                          - arc: # first half of the scale background
                              color: 0xFF3000
                              r_mod: 10 # radius difference from the scale default radius
                              width: 31
                              start_value: -10
                              end_value: 0
                          - arc: # second half of the scale background
                              color: 0x00FF00
                              r_mod: 10
                              width: 31
                              start_value: 0
                              end_value: 10
                - obj: # to cover the middle part of meter indicator line
                    height: 146
                    width: 146
                    radius: 73
                    align: CENTER
                    border_width: 0
                    bg_color: 0x000000
                    pad_all: 0
                - label: # gauge numeric indicator
                    id: val_text
                    text_font: montserrat_48
                    align: CENTER
                    y: -5
                    text: "0"
                - label: # lower range indicator
                    text_font: montserrat_18
                    align: CENTER
                    y: 8
                    x: -90
                    text: "-10"
                - label: # higher range indicator
                    text_font: montserrat_18
                    align: CENTER
                    y: 8
                    x: 90
                    text: "+10"
