Browse Source

getting up to date

justadri 1 month ago
parent
commit
357effbea7

+ 367 - 0
blueprints/automation/valentinfrlch/event_summary.yaml

@@ -0,0 +1,367 @@
+blueprint:
+  name: AI Event Summary (v1.4.1)
+  author: valentinfrlch
+  description: 'AI-powered summaries for security camera events. Sends a notification
+    with a preview to your phone that is updated dynamically when the AI summary is
+    available.
+
+    '
+  domain: automation
+  source_url: https://raw.githubusercontent.com/valentinfrlch/ha-llmvision/refs/heads/main/blueprints/event_summary.yaml
+  input:
+    important:
+      name: Important (Experimental)
+      description: 'Use AI to classify events as Critical, Normal or Low. Notifications
+        are sent only for events classified as Normal or higher. Critical events override
+        ''Do Not Disturb'' settings. Use with caution: AI can make mistakes.
+
+        '
+      default: false
+      selector:
+        boolean: {}
+    remember:
+      name: Remember
+      description: Stores this event in the Timeline so you can ask about it. If important
+        is enabled, only events classified as Normal or Critical will be saved.
+      default: false
+      selector:
+        boolean: {}
+    use_memory:
+      name: Use Memory
+      description: Use information stored in memory to provide additional context.
+        Memory must be set up.
+      default: false
+      selector:
+        boolean: {}
+    message:
+      name: Prompt
+      description: Model prompt for the video_analyzer action
+      default: 'Summarize the events based on a series of images captured at short
+        intervals. Focus only on moving subjects such as people, vehicles, and other
+        active elements. Ignore static objects and scenery. Provide a clear and concise
+        account of movements and interactions. Do not mention or imply the existence
+        of images—present the information as if directly observing the events. If
+        no movement is detected, respond with: ''No activity observed.'''
+      selector:
+        text:
+          multiline: true
+          multiple: false
+    run_conditions:
+      name: Run Conditions
+      description: All conditions must be true in order for the blueprint to run.
+      default: []
+      selector:
+        condition: {}
+    notify_device:
+      name: Notify Device
+      description: The devices to send the notification to. Multiple devices may be
+        used. Only works with Home Assistant mobile app.
+      default: []
+      selector:
+        device:
+          multiple: true
+          filter:
+          - integration: mobile_app
+    notification_delivery:
+      name: Notification Delivery
+      description: "Controls how notifications are delivered. \n \n **Dynamic** immediately
+        notifies with a live preview and updates the notification silently with a
+        summary once it is available. \n **Consolidated** Delays the notification
+        until the event summary is generated. Use this if you're receiving multiple
+        notifications for the same event."
+      default: Dynamic
+      selector:
+        select:
+          options:
+          - Dynamic
+          - Consolidated
+          custom_value: false
+          multiple: false
+          sort: false
+    camera_entities:
+      name: Camera Entities
+      description: List of camera entities to monitor
+      default: []
+      selector:
+        entity:
+          multiple: true
+          filter:
+          - domain:
+            - camera
+    trigger_state:
+      name: Trigger State
+      description: Automation starts when one of your camera changes to this state.
+      default: recording
+      selector:
+        text:
+          multiline: false
+          multiple: false
+    motion_sensors:
+      name: Motion Sensor
+      description: Set if your cameras don't change state (Frigate). Use the same
+        order used for camera entities.
+      default: []
+      selector:
+        entity:
+          multiple: true
+          filter:
+          - domain:
+            - binary_sensor
+    preview_mode:
+      name: Preview Mode
+      description: "Choose between a live preview or a snapshot of the event. \n\n
+        **Important:** Live Preview is only supported on iOS."
+      default: Snapshot
+      selector:
+        select:
+          options:
+          - Snapshot
+          - Live Preview
+          custom_value: false
+          multiple: false
+          sort: false
+    cooldown:
+      name: Cooldown
+      description: Time in minutes to wait before running again. Strongly recommended
+        for busy areas.
+      default: 10
+      selector:
+        number:
+          min: 0.0
+          max: 60.0
+          mode: slider
+          step: 1.0
+    tap_navigate:
+      name: Tap Navigate
+      description: Home Assistant dashboard to navigate to when notification is opened
+        (e.g. /lovelace/cameras).
+      default: /lovelace/0
+      selector:
+        text:
+          multiline: false
+          multiple: false
+    duration:
+      name: Duration
+      description: Duration to record for analysis (in seconds).
+      default: 5
+      selector:
+        number:
+          min: 1.0
+          max: 60.0
+          mode: slider
+          step: 1.0
+    max_frames:
+      name: Max Frames
+      description: How many frames to analyze. Picks frames with the most movement.
+      default: 3
+      selector:
+        number:
+          min: 1.0
+          max: 60.0
+          mode: slider
+          step: 1.0
+    provider:
+      name: Provider
+      description: Provider to use for analysis. See docs for additional information.
+      selector:
+        config_entry:
+          integration: llmvision
+    model:
+      name: Model
+      description: Which model to use. Depends on chosen provider.
+      default: gpt-4o-mini
+      selector:
+        text:
+          multiline: false
+          multiple: false
+    target_width:
+      name: Target Width
+      description: Downscale images (uses less tokens and speeds up processing)
+      default: 1280
+      selector:
+        number:
+          min: 512.0
+          max: 3840.0
+          mode: slider
+          step: 1.0
+    max_tokens:
+      name: Maximum Tokens
+      description: Maximum number of tokens to generate. Use this to control the length
+        of the summaries.
+      default: 20
+      selector:
+        number:
+          min: 1.0
+          max: 100.0
+          mode: slider
+          step: 1.0
+    temperature:
+      name: Temperature
+      description: Randomness. Lower is more accurate, higher is more creative.
+      default: 0.1
+      selector:
+        number:
+          min: 0.1
+          max: 1.0
+          step: 0.1
+          mode: slider
+variables:
+  important: !input important
+  remember: !input remember
+  cooldown: !input cooldown
+  preview_mode: !input preview_mode
+  notify_devices: !input notify_device
+  notification_delivery: !input notification_delivery
+  device_name_map: "{% set ns = namespace(device_names=[]) %} {% for device_id in
+    notify_devices %}\n  {% set device_name = device_attr(device_id, \"name\") %}\n
+    \ {% set sanitized_name = \"mobile_app_\" + device_name | slugify  %}\n  {% set
+    ns.device_names = ns.device_names + [sanitized_name] %}\n{% endfor %} {{ ns.device_names
+    }}\n"
+  camera_entities_list: !input camera_entities
+  motion_sensors_list: !input motion_sensors
+  camera_entity: "{% if motion_sensors_list and not trigger.entity_id.startswith(\"camera\")
+    %}\n  {% set index = motion_sensors_list.index(trigger.entity_id) %}\n    {{ camera_entities_list[index]
+    }}\n{% else %}\n  {{ trigger.entity_id }}\n{% endif %}\n"
+  tag: '{{ camera_entity + int(as_timestamp(now()))|string }}
+
+    '
+  group: '{{ camera_entity }}
+
+    '
+  label: Motion detected
+  camera: '{{ camera_entity.replace("camera.", "").replace("_", " ")|capitalize }}
+
+    '
+  importance_prompt: 'Classify the security event based on this image. Choose from
+    the following options: "passive" for unimportant events, "time-sensitive" for
+    notable but non-critical events such as a person at the front door, and "critical"
+    only for potential burglaries or highly suspicious activity. Respond with one
+    of these options exactly, without additional explanation.
+
+    '
+max_exceeded: silent
+mode: single
+triggers:
+- trigger: state
+  entity_id: !input camera_entities
+  to: !input trigger_state
+  id: camera_trigger
+- trigger: state
+  entity_id: !input motion_sensors
+  to: 'on'
+  id: motion_sensor_trigger
+condition:
+- condition: and
+  conditions: !input run_conditions
+action:
+- choose:
+  - conditions:
+    - condition: template
+      value_template: '{{ important }}'
+    sequence:
+    - action: llmvision.image_analyzer
+      data:
+        image_entity: '{{[camera_entity]}}'
+        provider: !input provider
+        model: !input model
+        message: '{{importance_prompt}}'
+        include_filename: true
+        target_width: 1280
+        max_tokens: 3
+        temperature: 0.1
+      response_variable: importance
+- choose:
+  - conditions:
+    - condition: template
+      value_template: '{{ important and importance.response_text|lower == ''passive''
+        }}'
+    sequence:
+    - stop: Event is not important
+- choose:
+  - conditions:
+    - condition: template
+      value_template: '{{ notification_delivery == ''Dynamic'' }}'
+    sequence:
+    - alias: Send instant notification to notify devices
+      repeat:
+        for_each: '{{device_name_map}}'
+        sequence:
+        - action: notify.{{ repeat.item }}
+          data:
+            title: '{{ label }}'
+            message: '{{camera}} has detected activity.'
+            data:
+              entity_id: '{{camera_entity}}'
+              url: !input tap_navigate
+              clickAction: !input tap_navigate
+              tag: '{{tag}}'
+              group: '{{group}}'
+              alert_once: true
+              push:
+                interruption-level: '{{importance.response_text|lower if importance
+                  is defined else ''active''}}'
+- alias: Analyze event
+  action: llmvision.stream_analyzer
+  data:
+    image_entity: '{{[camera_entity]}}'
+    duration: !input duration
+    provider: !input provider
+    model: !input model
+    message: !input message
+    use_memory: !input use_memory
+    remember: !input remember
+    expose_images: '{{preview_mode == ''Snapshot'' or remember}}'
+    generate_title: !input remember
+    include_filename: true
+    max_frames: !input max_frames
+    target_width: !input target_width
+    max_tokens: !input max_tokens
+    temperature: !input temperature
+  response_variable: response
+- alias: Update label with title
+  variables:
+    label: '{{response.title}}'
+- choose:
+  - conditions:
+    - condition: template
+      value_template: '{{ preview_mode==''Snapshot'' }}'
+    sequence:
+    - alias: (Snapshot) Update notification on notify devices
+      repeat:
+        for_each: '{{device_name_map}}'
+        sequence:
+        - action: notify.{{ repeat.item }}
+          data:
+            title: '{{ label }}'
+            message: '{{response.response_text}}'
+            data:
+              image: '{{response.key_frame.replace(''/config/www/'',''/local/'') }}'
+              url: !input tap_navigate
+              clickAction: !input tap_navigate
+              tag: '{{tag}}'
+              group: '{{group}}'
+              push:
+                interruption-level: '{{''passive'' if notification_delivery==''Dynamic''
+                  else ''active''}}'
+  - conditions:
+    - condition: template
+      value_template: '{{ preview_mode==''Live Preview'' }}'
+    sequence:
+    - alias: (Live Preview) Update notification on notify devices
+      repeat:
+        for_each: '{{device_name_map}}'
+        sequence:
+        - action: notify.{{ repeat.item }}
+          data:
+            title: '{{ label }}'
+            message: '{{response.response_text}}'
+            data:
+              entity_id: '{{camera_entity}}'
+              url: !input tap_navigate
+              clickAction: !input tap_navigate
+              tag: '{{tag}}'
+              group: '{{group}}'
+              push:
+                interruption-level: '{{''passive'' if notification_delivery==''Dynamic''
+                  else ''active''}}'
+- delay: 00:{{cooldown|int}}:00

+ 31 - 0
blueprints/script/balloob/add-to-do-item.yaml

@@ -0,0 +1,31 @@
+blueprint:
+  name: Add to-do
+  description: A script that adds an item to a to-do list.
+  domain: script
+  input:
+    to_do_list:
+      selector:
+        entity:
+          domain:
+          - todo
+          multiple: false
+      name: To-do list
+    item_label:
+      selector:
+        text: {}
+      default: Item
+      name: Item label
+  source_url: https://community.home-assistant.io/t/add-to-do-item/699193
+mode: queued
+fields:
+  item:
+    selector:
+      text:
+    name: !input item_label
+    required: true
+sequence:
+- service: todo.add_item
+  data:
+    item: '{{ item }}'
+  target:
+    entity_id: !input to_do_list

+ 27 - 0
blueprints/template/homeassistant/inverted_binary_sensor.yaml

@@ -0,0 +1,27 @@
+blueprint:
+  name: Invert a binary sensor
+  description: Creates a binary_sensor which holds the inverted value of a reference binary_sensor
+  domain: template
+  source_url: https://github.com/home-assistant/core/blob/dev/homeassistant/components/template/blueprints/inverted_binary_sensor.yaml
+  input:
+    reference_entity:
+      name: Binary sensor to be inverted
+      description: The binary_sensor which needs to have its value inverted
+      selector:
+        entity:
+          domain: binary_sensor
+variables:
+  reference_entity: !input reference_entity
+binary_sensor:
+  state: >
+    {% if states(reference_entity) == 'on' %}
+      off
+    {% elif states(reference_entity) == 'off' %}
+      on
+    {% else %}
+      {{ states(reference_entity) }}
+    {% endif %}
+  # delay_on: not_used in this example
+  # delay_off: not_used in this example
+  # auto_off: not_used in this example
+  availability: "{{ states(reference_entity) not in ('unknown', 'unavailable') }}"

+ 141 - 0
custom_sentences/en/media.yaml

@@ -0,0 +1,141 @@
+language: "en"
+intents:
+  MutePlayer:
+    data:
+      - sentences:
+          - "({mute_or_unmute};<media_player>)"
+            
+  MutePlayerArea:
+    data:
+      - sentences:
+          - "{mute_or_unmute}"
+        requires_context:
+          area:
+            slot: true
+            
+  ShuffleSet:
+    data:
+      - sentences:
+          - "(set|change) <media_player> shuffle [mode ]to {shuffle_mode}"
+                      
+  ShuffleSetArea:
+    data:
+      - sentences:
+          - "(set|change) shuffle [mode ]to {shuffle_mode}"
+        requires_context:
+          area:
+            slot: true
+                      
+  RepeatSet:
+    data:
+      - sentences:
+          - "(set|change) <media_player> repeat [mode ]to {repeat_mode}"
+          
+  RepeatSetArea:
+    data:
+      - sentences:
+          - "(set|change) repeat [mode ]to {repeat_mode}"
+        requires_context:
+          area:
+            slot: true
+          
+  ClearQueue:
+    data:
+      - sentences:
+          - "Clear <media_player> (queue|cue|Q|cube)"
+
+  ClearQueueArea:
+    data:
+      - sentences:
+          - "Clear the (queue|cue|Q|cube)"
+        requires_context:
+          area:
+            slot: true
+
+  PlayerStop:
+    data:
+      - sentences:
+          - "(Stop;<media_player>)"
+          
+  PlayerStopArea:
+    data:
+      - sentences:
+          - "Stop"
+        requires_context:
+          area:
+            slot: true
+          
+  SelectSource:
+    data:
+      - sentences:
+          - "Set <media_player> source to {desired_source}"
+          
+  PlayerJoin:
+    data:
+      - sentences:
+          - "(Join|connect) <media_player> to [the ]{media_player_group}"
+
+  PlayerUnjoin:
+    data:
+      - sentences:
+          - "(Unjoin|disconnect|remove) <media_player>"
+
+expansion_rules:
+  media_player: "[the ]{media_player}"
+          
+lists:
+  media_player:
+    values:
+      - in: "Orphne"
+        out: "media_player.squeezeplay_00_87_1c_e7_3a_3c"
+      - in: "Living Room Receiver"
+        out: "media_player.lvr_receiver"
+      - in: "Rumpus TV"
+        out: "media_player.ma_rumpus_tv"
+      - in: "Rumpus Amplifier"
+        out: "media_player.ma_rumpus_amplifier"
+      - in: "Study (Player|Speaker)"
+        out: "media_player.ma_picoreplayer"
+      - in: "Google Speaker Group"
+        out: "media_player.ma_google_speaker_group_2"
+      - in: "TV [player]"
+        out: "media_player.ma_sony_xr_55x90k_3"
+        
+  media_player_group:
+    values:
+      - in: "Rumpus TV"
+        out: "media_player.ma_rumpus_tv"
+      - in: "Rumpus Amplifier"
+        out: "media_player.ma_rumpus_amplifier"
+      - in: "Study Player"
+        out: "media_player.ma_picoreplayer"
+      - in: "TV [player]"
+        out: "media_player.ma_sony_xr_55x90k_3"
+        
+  volume:
+    range:
+      from: 0
+      to: 100
+
+  repeat_mode:
+    values:
+      - "off"
+      - "all"
+      - "one"
+      
+  shuffle_mode:
+    values:
+      - in: "(on|shuffle)"
+        out: "true"
+      - in: "off"
+        out: "false" 
+
+  mute_or_unmute:
+    values:
+      - in: "mute"
+        out: "true"
+      - in: "unmute"
+        out: "false"
+  
+  desired_source:
+    wildcard: true

+ 5 - 0
esphome/.gitignore

@@ -0,0 +1,5 @@
+# Gitignore settings for ESPHome
+# This is an example and may include too much for your use-case.
+# You can modify this file to suit your needs.
+/.esphome/
+/secrets.yaml

+ 3855 - 0
esphome/minion.yaml

@@ -0,0 +1,3855 @@
+## You can change the friendly name if you wish on line 7 below. The friendly name is how the device will show in HA
+## However the <name:> is how HA connects to the device eg. esp32-s3-box-3.local is the mDNS hostname for the device.
+## Once added to HA changing the device name can lead to connection issues, between HA and the device.
+
+substitutions:
+  name: minion
+  friendly_name: minion
+  encryption_key: "cl+UvrGxxeAFVNtdkT9zj0dAvl2C1QQB+8/IigP6aIk="
+  ota_password: "c211e0e8d3b4c2a62f0b81041563b369"
+
+  external_media_player: your_media_player ##change this to your external media player enity_id: do not include media_player.
+  home_assistant_host: http://iris.dgtlu.net:8123 ##change to the full url or IP of your HA server including port
+  tts_voice_speed: "16000" #options #nabu casa "24000" #piper "16000" elevenlabs "44100" must include quotes
+
+  #################### ON DEVICE WAKE WORDS #######################################
+  ####          all of the below wakewords are installed on the device        #####
+  ####      you can use any of these without re-compiling - just say them!    #####
+  #################################################################################
+  # TO REMOVE A WAKE WORD - COMMENT OUT THE CORESPONDING LINE FROM THE CONFIG BELOW - CTRL + F to search for "models"
+  micro_wake_word_model_1: alexa
+  micro_wake_word_model_2: hey_jarvis
+  micro_wake_word_model_3: okay_nabu
+  micro_wake_word_model_4: hey_mycroft
+  ####################################################################
+
+  #####  Days and months #####
+  ## Change the values on the right to match your locale ##
+  monday: Monday
+  tuesday: Tuesday
+  wednesday: Wednesday
+  thursday: Thursday
+  friday: Friday
+  saturday: Saturday
+  sunday: Sunday
+
+  jan: January
+  feb: February
+  mar: March
+  apr: April
+  may: May
+  jun: June
+  jul: July
+  aug: August
+  sept: September
+  oct: October
+  nov: November
+  dec: December
+  
+#####################################################################
+##### DO NOT CHANGE SUBSTITUTIONS BELOW THIS LINE ######
+#####      UNLESS YOU KNOW WHAT YOU ARE DOING     ######
+
+  font_glyphs: '&@!"''%()+=,-_.:°/$€£¥?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyzÀàÁáÂâÃãÄäĀāĂăÅåǺǻẠạĄąÆæǼǽĆćĈĉČčĊċÇçĎďĐđÐðÈèÉéÊêẼẽĚěËëĒēĔĕĖėẸẹĘęĜĝǦǧĞğĠġĢģĤĥĦħıÌìÍíÎîĨĩÏïĪīĬĭİỊịĮįȷĴĵĶķĸĹ弾ĻļŁłĿŀŃńÑñŇňŅņƝɲŊŋʼnÒòÓóÔôÕõÖöŌōŎŏŐőỌọǪǫØøǾǿŒœŔŕŘřŖŗŚśŜŝŠšŞşȘșẞߍťŢţȚțŦŧÞþÙùÚúÛûŨũÜüŪūŬŭŮůŰűỤụŲųẀẁẂẃŴŵẄẅỲỳÝýŶŷỸỹŸÿȲȳŹźŽžŻżIJijƏə'
+
+############# END OF SUBSTITUTIONS #################
+####################################################
+
+esphome:
+  name: ${name}
+  friendly_name: ${friendly_name}
+  min_version: 2025.2.0
+  on_boot:
+    priority: 600
+    then:
+      - lambda: "id(led).turn_on().set_brightness(id(s_default_brightness).state /100).perform();"
+      - display.page.show: loading_page
+      - component.update: s3_box_lcd
+      - script.execute: saver_enabled
+      - lambda: 'id(time_remaining_0).publish_state ("0:00:00");'
+      - if:
+          condition:
+            switch.is_on: output_audio
+          then:
+            media_player.volume_set:
+              id: speaker_media_player
+              volume: 0
+  project:
+    name: "BigBobbas.s3box"
+    version: "2024.09.02"
+
+esp32:
+  board: esp32s3box
+  flash_size: 16MB
+  framework:
+    type: esp-idf
+    sdkconfig_options:
+      CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
+      CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
+      CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
+
+psram:
+  mode: octal
+  speed: 80MHz
+
+api:
+  on_client_connected:
+    - lambda: |-
+        id(api_connection) = true;
+    - lambda: "id(led).turn_on().set_brightness(id(s_default_brightness).state /100).perform();"
+    - component.update: s3_box_lcd
+    - script.execute: saver_enabled
+  on_client_disconnected:
+    - lambda: |-
+        id(api_connection) = false;
+  encryption:
+    key: ${encryption_key}
+
+ota:
+  - platform: esphome
+    on_begin:
+      - lambda: |-
+          id(led).turn_on().set_brightness(1.0).set_transition_length(0).perform();
+          id(led).loop();
+
+      - display.page.show: ota_page
+      - component.update: s3_box_lcd
+
+logger:
+  hardware_uart: USB_SERIAL_JTAG
+  logs:
+    text_sensor: WARN
+    component: ERROR
+
+wifi:
+  ssid: !secret wifi_ssid
+  password: !secret wifi_password
+
+  ap:
+    ssid: ${name}
+    password: s3box123
+  on_connect:
+    - lambda: |-
+        id(wifi_connection) = true;
+    - display.page.show: idle_page
+    - component.update: s3_box_lcd
+    - switch.turn_on: speaker_enable
+  on_disconnect:
+    - lambda: |-
+        id(wifi_connection) = false;
+
+captive_portal:
+
+time:
+  - platform: homeassistant
+    id: ha_time
+
+interval:
+  - interval: 30s
+    then:
+      - component.update: s3_box_lcd
+  - interval: 10s
+    then:
+      - if:
+          condition:
+            - lambda: "return { (id(api_connection) != true) };"
+          then:
+            - if:
+                condition:
+                  api.connected:
+                then:
+                  - lambda: "id(api_connection) = true;"
+          else:
+            - if:
+                condition:
+                  not:
+                    api.connected:
+                then:
+                  - lambda: "id(api_connection) = false;"
+  - interval: 10s
+    then:
+      - if:
+          condition:
+            - lambda: "return { (id(wifi_connection) != true) };"
+          then:
+            - if:
+                condition:
+                  wifi.connected:
+                then:
+                  - lambda: "id(wifi_connection) = true;"
+          else:
+            - if:
+                condition:
+                  not:
+                    wifi.connected:
+                then:
+                  - lambda: "id(wifi_connection) = false;"
+
+select:
+  - platform: template
+    entity_category: config
+    name: Wake word engine location
+    id: wake_word_engine_location
+    optimistic: true
+    restore_value: true
+    options:
+      - In Home Assistant
+      - On device
+    initial_option: In Home Assistant
+    on_value:
+      - if:
+          condition:
+            lambda: 'return x == "In Home Assistant";'
+          then:
+            - micro_wake_word.stop
+            - delay: 500ms
+            - lambda: "id(va).set_use_wake_word(true);"
+            - voice_assistant.start_continuous:
+            - text_sensor.template.publish:
+                id: wakeword_location
+                state: !lambda 'return "Home Assistant";'
+            - component.update: s3_box_lcd
+      - if:
+          condition:
+            lambda: 'return x == "On device";'
+          then:
+            - text_sensor.template.publish:
+                id: wakeword_location
+                state: !lambda 'return "On Device";'
+            - lambda: "id(va).set_use_wake_word(false);"
+            - voice_assistant.stop
+            - delay: 500ms
+            - micro_wake_word.start
+            - component.update: s3_box_lcd
+
+  - platform: template
+    entity_category: config
+    name: Time Format
+    id: time_format
+    optimistic: true
+    restore_value: true
+    options:
+      - 12 Hr
+      - 24 Hr
+    initial_option: 24 Hr
+    on_value:
+      then:
+        - if:
+            condition:
+              lambda: 'return x == "24 Hr";'
+            then:
+              - text_sensor.template.publish:
+                  id: time_display_format
+                  state: !lambda 'return "24 Hr";'
+            else:
+              - text_sensor.template.publish:
+                  id: time_display_format
+                  state: !lambda 'return "12 Hr";'
+        - component.update: s3_box_lcd
+
+script:
+  - id: start_voice_assistant
+    then:
+      - if:
+          condition:
+            switch.is_off: mute_switch
+          then:
+            - if:
+                condition:
+                  lambda: 'return id(wake_word_engine_location).state == "In Home Assistant";'
+                then:
+                  - lambda: "id(va).set_use_wake_word(true);"
+                  - voice_assistant.start_continuous:
+            - if:
+                condition:
+                  lambda: 'return id(wake_word_engine_location).state == "On device";'
+                then:
+                  - lambda: "id(va).set_use_wake_word(false);"
+                  - micro_wake_word.start
+
+  - id: stop_voice_assistant
+    then:
+      - if:
+          condition:
+            lambda: 'return id(wake_word_engine_location).state == "In Home Assistant";'
+          then:
+            - lambda: "id(va).set_use_wake_word(false);"
+            - voice_assistant.stop:
+      - if:
+          condition:
+            lambda: 'return id(wake_word_engine_location).state == "On device";'
+          then:
+            - voice_assistant.stop:
+            - micro_wake_word.stop:
+  
+  - id: set_volume
+    then:
+      - media_player.volume_set:
+          volume: !lambda "return 0.5 + id(speaker_volume) * 0.05 ;"
+  
+  - id: saver_enabled
+    then:
+      - if:
+          condition:
+            switch.is_on: s_saver
+          then:
+            - lambda: "id(led).turn_on().set_brightness(id(s_default_brightness).state /100).perform();"
+            - delay: !lambda "return id(s_saver_delay).state * 1000;"
+            - lambda: "id(led).turn_on().set_brightness(id(s_saver_brightness).state /100).perform();"
+            - display.page.show: saver_page
+            - component.update: s3_box_lcd
+      - if:
+          condition:
+            - switch.is_on: s_saver_mode
+          then:
+            - delay: !lambda "return id(s_saver_blank_delay).state * 1000;"
+            - light.turn_off: led
+    mode: restart
+
+  - id: saver_enabled_manual
+    then:
+      - if:
+          condition:
+            - switch.is_on: s_saver
+          then:
+            - lambda: "id(led).turn_on().set_brightness(id(s_saver_brightness).state /100).perform();"
+            - display.page.show: saver_page
+            - component.update: s3_box_lcd
+      - if:
+          condition:
+            - switch.is_on: s_saver_mode
+          then:
+            - delay: !lambda "return id(s_saver_blank_delay).state * 1000;"
+            - light.turn_off: led
+            - component.update: s3_box_lcd
+    mode: restart
+
+  # - id: timer_started
+  #   then:
+  #     while:
+  #       condition:
+  #         switch.is_on: timer_ringing
+  #       then:
+  #         - media_player.play_media:
+  #             media_url: "${home_assistant_host}/local/sounds/timer_finished.mp3"
+  #         - delay: 1s
+
+  - id: timer_started_external
+    then:
+      while:
+        condition:
+          switch.is_on: timer_ringing
+        then:
+          - homeassistant.service:
+              service: media_player.play_media
+              data:
+                entity_id: media_player.${external_media_player}
+                media_content_id: "${home_assistant_host}/local/sounds/timer_finished.mp3"
+                media_content_type: music
+          - delay: 1700ms
+
+  - id: timer_ending
+    then:
+      - wait_until:
+          - lambda: 'return (id(time_remaining_0).state == "0:00:10");'
+      - script.execute: saver_enabled
+      - display.page.show: time_remaining_page
+      - component.update: s3_box_lcd
+
+  - id: increment_digit_1
+    then:
+      - lambda: |-
+          id(current_pin) += "1"; 
+          ESP_LOGD("increment_digit_1", "Current PIN: %s", id(current_pin).c_str());
+
+  - id: increment_digit_2
+    then:
+      - lambda: |-
+          id(current_pin) += "2";  
+          ESP_LOGD("increment_digit_2", "Current PIN: %s", id(current_pin).c_str());
+
+  - id: increment_digit_3
+    then:
+      - lambda: |-
+          id(current_pin) += "3";  
+          ESP_LOGD("increment_digit_3", "Current PIN: %s", id(current_pin).c_str());
+
+  - id: increment_digit_4
+    then:
+      - lambda: |-
+          id(current_pin) += "4";  
+          ESP_LOGD("increment_digit_4", "Current PIN: %s", id(current_pin).c_str());
+
+  - id: increment_digit_5
+    then:
+      - lambda: |-
+          id(current_pin) += "5";  
+          ESP_LOGD("increment_digit_5", "Current PIN: %s", id(current_pin).c_str());
+
+  - id: increment_digit_6
+    then:
+      - lambda: |-
+          id(current_pin) += "6";  
+          ESP_LOGD("increment_digit_6", "Current PIN: %s", id(current_pin).c_str());
+
+  - id: increment_digit_7
+    then:
+      - lambda: |-
+          id(current_pin) += "7";  
+          ESP_LOGD("increment_digit_7", "Current PIN: %s", id(current_pin).c_str());
+
+  - id: increment_digit_8
+    then:
+      - lambda: |-
+          id(current_pin) += "8";  
+          ESP_LOGD("increment_digit_8", "Current PIN: %s", id(current_pin).c_str());
+
+  - id: increment_digit_9
+    then:
+      - lambda: |-
+          id(current_pin) += "9";  
+          ESP_LOGD("increment_digit_9", "Current PIN: %s", id(current_pin).c_str());
+
+  - id: increment_digit_0
+    then:
+      - lambda: |-
+          id(current_pin) += "0";  
+          ESP_LOGD("increment_digit_0", "Current PIN: %s", id(current_pin).c_str());
+
+  - id: show_notification
+    then:
+      - lambda: "id(led).turn_on().set_brightness(id(s_default_brightness).state /100).perform();"
+      - display.page.show: notification_page
+      - component.update: s3_box_lcd
+      - delay: 10s
+      - display.page.show: idle_page
+      - script.execute: saver_enabled
+      - component.update: s3_box_lcd
+
+globals:
+  - id: wifi_connection
+    type: bool
+    restore_value: no
+    initial_value: "false"
+  - id: api_connection
+    type: bool
+    restore_value: no
+    initial_value: "false"
+  - id: mute_value
+    type: bool
+    restore_value: no
+    initial_value: "false"
+  - id: speaker_volume
+    type: int
+    restore_value: no
+    initial_value: "5"
+  - id: media_state
+    type: bool
+    restore_value: no
+    initial_value: "false"
+  - id: global_first_active_timer
+    type: voice_assistant::Timer
+    restore_value: false
+  - id: global_is_timer_active
+    type: bool
+    restore_value: false
+  - id: global_first_timer
+    type: voice_assistant::Timer
+    restore_value: false
+  - id: global_is_timer
+    type: bool
+    restore_value: false
+  - id: current_pin
+    type: std::string
+    initial_value: ""
+  - id: global_is_assisting
+    type: bool
+    restore_value: false
+  - id: previous_notification_text
+    type: std::string
+    initial_value: ""
+
+number:
+  - id: s_saver_delay
+    platform: template
+    name: "Scr/save delay"
+    icon: "mdi:sleep"
+    entity_category: config
+    unit_of_measurement: "secs"
+    optimistic: true
+    restore_value: true
+    initial_value: 30
+    step: 5
+    min_value: 10
+    max_value: 999999
+    on_value:
+      - component.update: s3_box_lcd
+      - component.update: s_saver_delay
+      - script.execute: saver_enabled
+
+  - id: s_saver_blank_delay
+    platform: template
+    name: "Scr/off delay"
+    icon: "mdi:monitor-off"
+    entity_category: config
+    unit_of_measurement: "secs"
+    optimistic: true
+    restore_value: true
+    initial_value: 30
+    step: 5
+    min_value: 10
+    max_value: 999999
+    on_value:
+      - component.update: s_saver_blank_delay
+      - script.execute: saver_enabled
+      - component.update: s3_box_lcd
+
+  - id: s_saver_brightness
+    platform: template
+    name: "Scr/save Brightness"
+    icon: "mdi:sleep"
+    entity_category: config
+    unit_of_measurement: "%"
+    optimistic: true
+    restore_value: true
+    initial_value: 30
+    step: 5
+    min_value: 20
+    max_value: 100
+    on_value:
+      - component.update: s_saver_brightness
+      - script.execute: saver_enabled
+      - component.update: s3_box_lcd
+
+  - id: s_default_brightness
+    platform: template
+    name: "Default Brightness"
+    icon: "mdi:monitor"
+    entity_category: config
+    unit_of_measurement: "%"
+    optimistic: true
+    restore_value: true
+    initial_value: 100
+    step: 5
+    min_value: 20
+    max_value: 100
+    on_value:
+      - component.update: s_default_brightness
+      - script.execute: saver_enabled
+      - component.update: s3_box_lcd
+
+button:
+  - platform: restart
+    id: reboot
+    name: "Reboot"
+    entity_category: diagnostic
+
+switch:
+  - platform: gpio
+    name: Speaker Enable
+    id: speaker_enable
+    pin: 
+      number: GPIO46
+      ignore_strapping_warning: true
+    restore_mode: ALWAYS_OFF
+    entity_category: config
+    disabled_by_default: true
+
+  - platform: template
+    name: Display conversation
+    id: display_conversation
+    optimistic: true
+    restore_mode: RESTORE_DEFAULT_ON
+    entity_category: config
+    icon: "mdi:chat"
+
+  - platform: template
+    name: Output audio externally
+    id: output_audio
+    icon: "mdi:volume-off"
+    optimistic: true
+    restore_mode: RESTORE_DEFAULT_OFF
+    entity_category: config
+    on_turn_on:
+      media_player.volume_set:
+        id: speaker_media_player
+        volume: 0
+    on_turn_off:
+      media_player.volume_set:
+        id: speaker_media_player
+        volume: 1.0
+
+  - platform: template
+    name: Mute
+    id: mute_switch
+    icon: "mdi:microphone-off"
+    optimistic: true
+    restore_mode: RESTORE_DEFAULT_OFF
+    entity_category: config
+    on_turn_on:
+      then:
+        - voice_assistant.stop
+        - micro_wake_word.stop
+    on_turn_off:
+      - if:
+          condition:
+            not:
+              - voice_assistant.is_running
+          then:
+            - if:
+                condition:
+                  lambda: 'return id(wake_word_engine_location).state == "In Home Assistant";'
+                then:
+                  - lambda: "id(va).set_use_wake_word(true);"
+                  - delay: 50ms
+                  - voice_assistant.start_continuous
+            - if:
+                condition:
+                  lambda: 'return id(wake_word_engine_location).state == "On device";'
+                then:
+                  - lambda: "id(va).set_use_wake_word(false);"
+                  - micro_wake_word.start
+            - component.update: s3_box_lcd
+
+  - platform: template
+    id: media_mute
+    optimistic: true
+    on_turn_on:
+      media_player.volume_set:
+        id: speaker_media_player
+        volume: 0
+    on_turn_off:
+      media_player.volume_set:
+        id: speaker_media_player
+        volume: 1.0
+
+  - platform: template
+    id: s_saver
+    name: Scr/save enable
+    icon: mdi:sleep
+    optimistic: true
+    restore_mode: RESTORE_DEFAULT_OFF
+    entity_category: config
+
+  - platform: template
+    id: s_saver_mode
+    name: Scr/off enable
+    icon: "mdi:monitor-off"
+    optimistic: true
+    restore_mode: RESTORE_DEFAULT_OFF
+    entity_category: config
+
+  - platform: template # remove for no sensor version
+    id: s_saver_presc
+    name: Screen wake on motion
+    icon: "mdi:motion-sensor"
+    entity_category: config
+    optimistic: true
+    restore_mode: RESTORE_DEFAULT_OFF
+
+  - platform: template
+    id: timer_ringing
+    optimistic: true
+    internal: true
+    restore_mode: ALWAYS_OFF
+    on_turn_off:
+      # Turn off the repeat mode and disable the pause between playlist items
+      - lambda: |-
+              id(speaker_media_player)
+                ->make_call()
+                .set_command(media_player::MediaPlayerCommand::MEDIA_PLAYER_COMMAND_REPEAT_OFF)
+                .set_announcement(true)
+                .perform();
+              id(speaker_media_player)->set_playlist_delay_ms(speaker::AudioPipelineType::ANNOUNCEMENT, 0);
+      # Stop playing the alarm
+      - media_player.stop:
+          announcement: true
+      - if:
+          condition:
+            lambda: 'return id(wake_word_engine_location).state == "On device";'
+          then:
+            - lambda: "id(va).set_use_wake_word(false);"
+            - micro_wake_word.start
+          else:
+            - lambda: "id(va).set_use_wake_word(true);"
+            - voice_assistant.start
+    on_turn_on:
+      - lambda: id(va).set_use_wake_word(false);
+      - voice_assistant.stop:
+      - micro_wake_word.stop:
+      - delay: 150ms
+      # Turn on the repeat mode and pause for 1000 ms between playlist items/repeats
+      - lambda: id(led).turn_on().set_brightness(1.0).perform();
+      - lambda: |-
+            id(speaker_media_player)
+              ->make_call()
+              .set_command(media_player::MediaPlayerCommand::MEDIA_PLAYER_COMMAND_REPEAT_ONE)
+              .set_announcement(true)
+              .perform();
+            id(speaker_media_player)->set_playlist_delay_ms(speaker::AudioPipelineType::ANNOUNCEMENT, 1000);
+      - media_player.speaker.play_on_device_media_file:
+          media_file: timer_finished_sound
+          announcement: true
+      - delay: 15min
+      - switch.turn_off: timer_ringing
+
+  - platform: template
+    id: wake_sound
+    name: Play wake sound
+    icon: mdi:music
+    entity_category: config
+    optimistic: true
+    restore_mode: RESTORE_DEFAULT_OFF
+
+  - platform: template
+    id: mute_response_switch
+    name: Mute Responses
+    icon: mdi:chat-sleep
+    entity_category: config
+    optimistic: true
+    restore_mode: RESTORE_DEFAULT_OFF
+
+  - platform: template
+    id: ext_media_mute
+    icon: "mdi:volume-off"
+    optimistic: true
+    restore_mode: RESTORE_DEFAULT_OFF
+    entity_category: config
+    on_turn_on:
+      then:
+        - homeassistant.service:
+            service: media_player.volume_mute
+            data:
+              entity_id: media_player.${external_media_player}
+    on_turn_off:
+      - homeassistant.service:
+          service: media_player.volume_mute
+          data:
+            entity_id: media_player.${external_media_player}
+
+output:
+  - platform: ledc
+    pin: GPIO47
+    id: backlight_output
+
+light:
+  - platform: monochromatic
+    id: led
+    name: LCD Backlight
+    entity_category: config
+    output: backlight_output
+    restore_mode: ALWAYS_ON
+    default_transition_length: 50ms
+
+sensor:
+  - platform: aht10 # remove for no sensor version
+    i2c_id: bus_b
+    variant: AHT20
+    temperature:
+      name: "S3 Temperature"
+      id: s3temp
+    humidity:
+      name: "S3 Humidity"
+    update_interval: 60s
+
+  - platform: adc # remove for no sensor version
+    pin: GPIO10
+    id: battery_voltage
+    unit_of_measurement: "V"
+    accuracy_decimals: 1
+    device_class: "voltage"
+    entity_category: "diagnostic"
+    disabled_by_default: true
+    update_interval: 30s
+    attenuation: auto
+    filters:
+      - multiply: 4.11
+
+  - platform: copy # remove for no sensor version
+    id: battery_percent
+    source_id: battery_voltage
+    name: "Battery level"
+    unit_of_measurement: "%"
+    accuracy_decimals: 0
+    device_class: "battery"
+    entity_category: "diagnostic"
+    filters:
+      - lambda: "return (x - 2.7) / (4.2 - 2.7) * 100;"
+      - clamp:
+          min_value: 0
+          max_value: 100
+
+  - platform: uptime
+    id: up_sens
+    on_value:
+      - lambda: |-
+          int seconds = id(up_sens).state;
+          int days = seconds / 86400;
+          int hours = seconds / 3600;
+          int minutes = (seconds % 3600) / 60;
+          seconds %= 60;
+          id(up_sens_text).publish_state(str_sprintf("%03d:%02d:%02d:%02d", days, hours, minutes, seconds));
+    update_interval: 30s
+
+  - platform: wifi_signal
+    name: "WiFi db"
+    id: wifi_signal_db
+    update_interval: 30s
+
+  - platform: copy
+    source_id: wifi_signal_db
+    name: "WiFi Signal"
+    id: wifi_percent
+    filters:
+      - lambda: "return min(max(2 * (x + 100.0), 0.0), 100.0);"
+    unit_of_measurement: "%"
+    entity_category: "diagnostic"
+    device_class: ""
+
+text_sensor:
+  - id: text_request
+    platform: template
+    on_value:
+      lambda: |-
+        if(id(text_request).state.length()>32) {
+          std::string name = id(text_request).state.c_str();
+          std::string truncated = esphome::str_truncate(name.c_str(),31);
+          id(text_request).state = (truncated+"...").c_str();
+        }
+
+  - id: text_response
+    platform: template
+    on_value:
+      lambda: |-
+        if(id(text_response).state.length()>32) {
+          std::string name = id(text_response).state.c_str();
+          std::string truncated = esphome::str_truncate(name.c_str(),31);
+          id(text_response).state = (truncated+"...").c_str();
+        }
+  - platform: wifi_info
+    ip_address:
+      name: IP Address
+      id: ip_addr
+      entity_category: "diagnostic"
+    ssid:
+      id: connected_ssid
+      name: SSID
+      entity_category: "diagnostic"
+    bssid:
+      id: connected_bssid
+      name: BSSID
+      entity_category: "diagnostic"
+    mac_address:
+      id: device_mac
+
+  - platform: template
+    id: up_sens_text
+    name: Device uptime
+    entity_category: "diagnostic"
+    icon: mdi:clock
+
+  - platform: template
+    id: wakeword_location
+
+  - platform: template
+    id: time_remaining_0
+    name: Timer
+    icon: mdi:clock
+
+  - platform: template
+    id: time_remaining_1
+
+  - platform: template
+    id: time_display_format
+    update_interval: never
+  
+  - platform: homeassistant
+    entity_id: media_player.${external_media_player}
+    id: ha_media_status
+    on_value:
+      component.update: s3_box_lcd
+
+  - platform: homeassistant
+    entity_id: media_player.${external_media_player}
+    id: ha_media_title
+    attribute: media_content_id
+    on_value:
+      component.update: s3_box_lcd
+
+  - platform: homeassistant
+    name: "Alarm Status"
+    entity_id: alarm_control_panel.alarmo
+    id: alarm_status
+    on_value:
+      - component.update: s3_box_lcd
+
+text:
+  - platform: template
+    name: "Notification Text"
+    id: notification_text
+    mode: text
+    optimistic: true
+    on_value:
+      then:
+        - lambda: |-
+            if (!id(notification_text).state.empty() && 
+                (id(previous_notification_text).empty() || id(notification_text).state != id(previous_notification_text))) {
+              id(previous_notification_text) = id(notification_text).state;
+              id(show_notification).execute();
+            }
+
+i2s_audio:
+  - id: i2s_audio_bus
+    i2s_lrclk_pin:
+      number: GPIO45
+      ignore_strapping_warning: true
+    i2s_bclk_pin: GPIO17
+    i2s_mclk_pin: GPIO2
+
+audio_adc:
+  - platform: es7210
+    id: es7210_adc
+    i2c_id: bus_a
+    bits_per_sample: 16bit
+    sample_rate: 16000
+
+audio_dac:
+  - platform: es8311
+    id: es8311_dac
+    i2c_id: bus_a
+    bits_per_sample: 16bit
+    sample_rate: 48000
+
+microphone:
+  - platform: i2s_audio
+    id: box_mic
+    sample_rate: 16000
+    i2s_din_pin: GPIO16
+    bits_per_sample: 16bit
+    adc_type: external
+
+speaker:
+  - platform: i2s_audio
+    id: i2s_audio_speaker
+    i2s_audio_id: i2s_audio_bus
+    i2s_dout_pin: GPIO15
+    dac_type: external
+    sample_rate: 48000
+    bits_per_sample: 16bit
+    channel: left
+    audio_dac: es8311_dac
+    buffer_duration: 500ms  # Increased for stability without timeout @youkorr
+
+# Virtual speakers to combine the announcement and media streams together into one output
+  - platform: mixer
+    id: mixing_speaker
+    output_speaker: i2s_audio_speaker
+    source_speakers:
+      - id: announcement_mixing_input
+      - id: media_mixing_input
+
+# Vritual speakers to resample each pipelines' audio, if necessary, as the mixer speaker requires the same sample rate
+  - platform: resampler
+    id: announcement_resampling_speaker
+    output_speaker: announcement_mixing_input
+    sample_rate: 48000  # Added explicit sample rate
+
+  - platform: resampler
+    id: media_resampling_speaker
+    output_speaker: media_mixing_input
+    sample_rate: 48000  # Added explicit sample rate
+
+media_player:
+  - platform: speaker
+    name: Media Player
+    id: speaker_media_player
+    volume_increment: 0.05
+    volume_min: 0.5
+    volume_max: 0.8
+    task_stack_in_psram: true
+    announcement_pipeline:
+      speaker: announcement_resampling_speaker
+      format: FLAC
+      sample_rate: 48000
+      num_channels: 1  # S3 Box only has one output channel
+    media_pipeline:
+      speaker: media_resampling_speaker
+      format: FLAC  # FLAC is the least processor intensive codec
+      num_channels: 2
+      sample_rate: 48000
+    files:
+      - id: timer_finished_sound
+        file: https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/refs/heads/main/sounds/awake.flac
+      - id: wake_sound_file
+        file: https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/sounds/awake.flac
+    on_state:
+      then:
+        - if:
+            condition:
+              media_player.is_playing:
+            then:
+              - micro_wake_word.stop
+              - voice_assistant.stop
+        - if:
+            condition:
+              and:
+                - lambda: return id(global_is_assisting) == false;
+                - or:
+                    - media_player.is_idle
+                    - media_player.is_paused
+            then:
+              - if:
+                  condition:
+                    and:
+                      - switch.is_off: mute_switch
+                      - lambda: return id(wake_word_engine_location).state == "On device";
+                  then:
+                    - micro_wake_word.start
+                  else:
+                    - if:
+                        condition:
+                          - switch.is_off: mute_switch
+                        then:
+                          - voice_assistant.start
+        - if:
+            condition:
+              and:
+                - switch.is_off: timer_ringing
+                - not:
+                    voice_assistant.is_running:
+                - not:
+                    media_player.is_announcing:
+            then:
+              - mixer_speaker.apply_ducking:
+                  id: media_mixing_input
+                  decibel_reduction: 0
+                  duration: 1.0s
+    on_play:
+      - wait_until:
+          - lambda: return id(global_is_assisting) == false;
+    on_announcement:
+      - mixer_speaker.apply_ducking:
+          id: media_mixing_input
+          decibel_reduction: 20
+          duration: 0.0s
+
+micro_wake_word:
+  vad:
+  models:
+    # - model: ${micro_wake_word_model_1}
+    # - model: ${micro_wake_word_model_2}
+    - model: ${micro_wake_word_model_3}
+    # - model: ${micro_wake_word_model_4}
+  on_wake_word_detected:
+    - lambda: "id(global_is_assisting) = true;"
+    - delay: 50ms
+    - if:
+        condition:
+          and:
+            - switch.is_off: output_audio
+            - switch.is_on: wake_sound
+        then:
+          - media_player.speaker.play_on_device_media_file:
+              media_file: wake_sound_file
+              announcement: true
+          - wait_until:
+              not:
+                - media_player.is_announcing:
+          - delay: 150ms
+        else:
+          if:
+            condition:
+              and:
+                - switch.is_on: output_audio
+                - switch.is_on: wake_sound
+            then:
+              - homeassistant.service:
+                  service: media_player.play_media
+                  data:
+                    entity_id: media_player.${external_media_player}
+                    media_content_id: '${home_assistant_host}/local/sounds/awake.mp3'
+                    media_content_type: music
+    - display.page.show: listening_page
+    - component.update: s3_box_lcd
+    - delay: 100ms
+    - voice_assistant.start:
+        wake_word: !lambda "return wake_word;"
+
+voice_assistant:
+  id: va
+  microphone: box_mic
+  media_player: speaker_media_player
+  use_wake_word: true
+  noise_suppression_level: 2
+  auto_gain: 31dBFS
+  volume_multiplier: 4.0
+  on_wake_word_detected:
+    - lambda: "id(global_is_assisting) = true;"
+    - voice_assistant.stop:
+    - lambda: "id(va).set_use_wake_word(false);"
+    - if:
+        condition:
+          and:
+            - switch.is_off: output_audio
+            - switch.is_on: wake_sound
+        then:
+          # - voice_assistant.stop:
+          # - delay: 150ms
+          # - if:
+              # condition:
+                # not:
+                  # microphone.is_capturing:
+              # then:
+          - media_player.speaker.play_on_device_media_file:
+              media_file: wake_sound_file
+              announcement: true
+          - wait_until:
+              not:
+                - media_player.is_announcing:
+          - delay: 150ms
+          - lambda: "id(va).set_use_wake_word(false);"
+          - display.page.show: listening_page
+          - component.update: s3_box_lcd
+        else:
+          if:
+            condition:
+              and:
+                - switch.is_on: wake_sound
+                - switch.is_on: output_audio
+            then:
+              - homeassistant.service:
+                  service: media_player.play_media
+                  data:
+                    entity_id: media_player.${external_media_player}
+                    media_content_id: "${home_assistant_host}/local/sounds/awake.mp3"
+                    media_content_type: music
+              - voice_assistant.start
+  on_start:
+    if:
+      condition:
+        - display.is_displaying_page: listening_page
+        - display.is_displaying_page: thinking_page
+      then:
+        - display.page.show: idle_page
+        - component.update: s3_box_lcd
+  on_listening:
+    - text_sensor.template.publish:
+        id: text_request
+        state: "..."
+    - text_sensor.template.publish:
+        id: text_response
+        state: "..."
+    - script.execute: saver_enabled
+    - display.page.show: listening_page
+    - component.update: s3_box_lcd
+  on_stt_end:
+    - text_sensor.template.publish:
+        id: text_request
+        state: !lambda "return x;"
+  on_stt_vad_end:
+    - display.page.show: thinking_page
+    - component.update: s3_box_lcd
+  on_tts_start:
+    - text_sensor.template.publish:
+        id: text_response
+        state: !lambda "return x;"
+  on_tts_end:
+    - if:
+        condition:
+          and:
+            - switch.is_on: mute_response_switch
+            - switch.is_off: media_mute
+            - switch.is_off: ext_media_mute
+        then:
+          - switch.turn_on: media_mute
+          - switch.turn_on: ext_media_mute
+    - display.page.show: replying_page
+    - component.update: s3_box_lcd
+    - if:
+        condition:
+          - switch.is_on: output_audio
+        then:
+          - homeassistant.service:
+              service: media_player.play_media
+              data:
+                entity_id: media_player.${external_media_player}
+                media_content_id: !lambda "return x;"
+                media_content_type: music
+                announce: "false"
+    - delay: 5s
+    - display.page.show: idle_page
+    - component.update: s3_box_lcd
+
+  on_error:
+    - if:
+        condition:
+          not:
+            - voice_assistant.is_running
+        then:
+          - display.page.show: error_page
+          - component.update: s3_box_lcd
+          - delay: 4s
+          - if:
+              condition:
+                - display.is_displaying_page: error_page
+              then:
+                - display.page.show: idle_page
+                - component.update: s3_box_lcd
+    - lambda: "id(global_is_assisting) = false;"
+
+  on_idle:
+    - display.page.show: idle_page
+    - component.update: s3_box_lcd
+
+  on_end:
+    - wait_until:
+        not:
+          voice_assistant.is_running:
+    - mixer_speaker.apply_ducking:
+        id: media_mixing_input
+        decibel_reduction: 0
+        duration: 1.0s
+    - lambda: "id(global_is_assisting) = false;"
+    - if:
+        condition:
+          and:
+            - switch.is_off: mute_switch
+            - lambda: 'return id(wake_word_engine_location).state == "On device";'
+        then:
+          - voice_assistant.stop
+          - micro_wake_word.start
+
+        else:
+          if:
+            condition:
+              - switch.is_off: mute_switch
+            then:
+              - lambda: id(va).set_use_wake_word(false);
+              - voice_assistant.stop:
+              - delay: 100ms
+              - lambda: "id(va).set_use_wake_word(true);"
+              - delay: 100ms
+              - voice_assistant.start
+    - if:
+        condition:
+          and:
+            - switch.is_on: mute_response_switch
+            - switch.is_on: media_mute
+            - switch.is_on: ext_media_mute
+        then:
+          - switch.turn_off: media_mute
+          - switch.turn_off: ext_media_mute
+
+  on_client_connected:
+    - if:
+        condition:
+          and:
+            - switch.is_off: mute_switch
+            - lambda: 'return id(wake_word_engine_location).state == "On device";'
+        then:
+          - micro_wake_word.start
+        else:
+          - if:
+              condition:
+                - switch.is_off: mute_switch
+              then:
+                - lambda: "id(va).set_use_wake_word(true);"
+                - voice_assistant.start
+  on_timer_started:
+    - script.execute: timer_ending
+    - component.update: s3_box_lcd
+  on_timer_cancelled:
+    - lambda: 'id(time_remaining_0).publish_state ("0:00:00");'
+    - component.update: s3_box_lcd
+  on_timer_updated:
+    - component.update: s3_box_lcd
+  on_timer_tick:
+    - lambda: |-
+        int seconds = timers[0].seconds_left;
+        int hours = seconds / 3600;
+        int minutes = (seconds % 3600) / 60;
+        seconds %= 60;
+        id(time_remaining_0).publish_state(str_sprintf("%d:%02d:%02d", hours, minutes, seconds));
+    - component.update: s3_box_lcd
+  on_timer_finished:
+    if:
+      condition:
+        - switch.is_on: output_audio
+      then:
+        - switch.turn_on: timer_ringing
+        - script.execute: timer_started_external
+        - display.page.show: timer_finished_page
+        - component.update: s3_box_lcd
+      else:
+        - if:
+            condition:
+              - switch.is_off: output_audio
+            then:
+              - switch.turn_on: timer_ringing
+              # - script.execute: timer_started
+              - display.page.show: timer_finished_page
+              - component.update: s3_box_lcd
+
+image:
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/images/error.png"
+    id: error_img
+    resize: 320x240
+    type: RGB
+    transparency: alpha_channel
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/images/idle.png"
+    id: idle_img
+    resize: 320x240
+    type: RGB
+    transparency: alpha_channel
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/images/listening.png"
+    id: listening_img
+    resize: 320x240
+    type: RGB
+    transparency: alpha_channel
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/images/thinking.png"
+    id: thinking_img
+    resize: 320x240
+    type: RGB
+    transparency: alpha_channel
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/images/replying.png"
+    id: replying_img
+    resize: 320x240
+    type: RGB
+    transparency: alpha_channel
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/images/loading.png"
+    id: loading_img
+    resize: 320x240
+    type: RGB
+    transparency: alpha_channel
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/images/logo.png"
+    id: logo_img
+    resize: 80x75
+    type: RGB
+    transparency: alpha_channel
+
+font:
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/fonts/consola.ttf"
+    id: my_font
+    size: 14
+    glyphs: "${font_glyphs}"
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/fonts/consola.ttf"
+    id: my_font16
+    size: 16
+    glyphs: "${font_glyphs}"
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/fonts/consola.ttf"
+    id: my_font2
+    size: 72
+    glyphs: "${font_glyphs}"
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/fonts/consola.ttf"
+    id: my_font3
+    size: 28
+    glyphs: "${font_glyphs}"
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/fonts/consola.ttf"
+    id: my_font4
+    size: 40
+    glyphs: "${font_glyphs}"
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/fonts/consola.ttf"
+    id: my_font18
+    size: 18
+    glyphs: "${font_glyphs}"
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/fonts/consola.ttf"
+    id: my_font5
+    size: 22
+    glyphs: "${font_glyphs}"
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/fonts/consola.ttf"
+    id: my_font6
+    size: 50
+    glyphs: "${font_glyphs}"
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/fonts/consola.ttf"
+    id: my_font82
+    size: 82
+    glyphs: "${font_glyphs}"
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/fonts/materialdesignicons-webfont.ttf"
+    id: icon_font_55
+    size: 45
+    glyphs: &icon_glyphs
+      - "\U000F0079" #battery 100%
+      - "\U000F007A" #battery 10%
+      - "\U000F007B" #battery 20%
+      - "\U000F007C" #battery 30%
+      - "\U000F007D" #battery 40%
+      - "\U000F007E" #battery 50%
+      - "\U000F007F" #battery 60%
+      - "\U000F0080" #battery 70%
+      - "\U000F0081" #battery 80%
+      - "\U000F0082" #battery 90%
+      - "\U000F009E" #bell
+      - "\U000F0150" #clock
+      - "\U000F01AE" #gbp pound symbol
+      - "\U000F0210" #fan
+      - "\U000F0238" #heating
+      - "\U000F024A" #garden/flower
+      - "\U000F0335" #light bulb off
+      - "\U000F036C" #microphone on
+      - "\U000F036D" #microphone off
+      - "\U000F036F" #voice settings
+      - "\U000F03E4" #pause
+      - "\U000F040A" #play
+      - "\U000F040E" #play/pause
+      - "\U000F0493" #settings cog
+      - "\U000F04AD" #next track
+      - "\U000F04AE" #previous track
+      - "\U000F04B9" #living room
+      - "\U000F04C8" #spots
+      - "\U000F04DB" #stop
+      - "\U000F0502" #screen settings
+      - "\U000F050F" #temp sensor
+      - "\U000F0521" #toggle on
+      - "\U000F0565" #arming
+      - "\U000F057E" #speaker on
+      - "\U000F0581" #speaker off
+      - "\U000F05CB" #voice
+      - "\U000F068A" #alarm home
+      - "\U000F06E8" #light bulb illuminated
+      - "\U000F075A" #music
+      - "\U000F075D" #vol plus
+      - "\U000F075E" #vol minus
+      - "\U000F0769" #ceiling
+      - "\U000F07D0" #api connected
+      - "\U000F07F4" #tv
+      - "\U000F0873" #car miles non
+      - "\U000F0874" #car miles full
+      - "\U000F0875" #car miles low
+      - "\U000F087B" #api disconnected
+      - "\U000F08D6" #settings
+      - "\U000F099D" #alarm away
+      - "\U000F099E" #disarmed
+      - "\U000F0A19" #toggle off
+      - "\U000F0B26" #down
+      - "\U000F0B28" #left
+      - "\U000F0B2A" #right
+      - "\U000F0B2C" #up
+      - "\U000F0B6C" #car battery
+      - "\U000F0D90" #screen off
+      - "\U000F0EBA" #stats
+      - "\U000F0ED4" #voice off
+      - "\U000F0FCE" #scene
+      - "\U000F1061" #dining
+      - "\U000F10CD" #battery warning
+      - "\U000F1160" #kitchen
+      - "\U000F12A8" #touch button
+      - "\U000F12D3" #garage closed
+      - "\U000F12D4" #garage open
+      - "\U000F1322" #tools
+      - "\U000F16BC" #wifidisconnected
+      - "\U000F16BD" #wifi connected
+      - "\U000F1722" #fire off
+      - "\U000F1747" #tall lamp
+      - "\U000F1828" #armed night
+      - "\U000F192D" #electricity
+      - "\U000F1987" #floods
+      - "\U000F1A12" #home button
+      - "\U000F1A1B" #gas
+      - "\U000F1C3B" #battery charging/usb powered
+      - "\U000F1C6F" #info
+
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/fonts/materialdesignicons-webfont.ttf"
+    id: icon_font_180
+    size: 180
+    glyphs: *icon_glyphs
+
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/fonts/materialdesignicons-webfont.ttf"
+    id: icon_font_80
+    size: 75
+    glyphs: *icon_glyphs
+
+  - file: "https://github.com/BigBobbas/ESP32-S3-Box3-Custom-ESPHome/raw/main/fonts/materialdesignicons-webfont.ttf"
+    id: icon_font_60
+    size: 60
+    glyphs: *icon_glyphs
+
+color:
+  - id: green
+    hex: "75D15F"
+  - id: red
+    hex: "FF3131"
+  - id: blue
+    hex: "47B7E9"
+  - id: blue_drk
+    hex: "085296"
+  - id: amber
+    hex: "FBAB35"
+  - id: lime
+    hex: "20FC30"
+  - id: pink
+    hex: "D92BBC"
+  - id: yellow
+    hex: "FFC000"
+  - id: black
+    hex: "000000"
+  - id: white
+    hex: "ffffff"
+  - id: purple
+    hex: "73264D"
+  - id: light_blue
+    hex: "CFE2F3"
+  - id: bg_blue
+    hex: "032341"
+  - id: bg_purple
+    hex: "301020"
+  - id: bg_green
+    hex: "05350B"
+  - id: bg_red
+    hex: "3C0000"
+  - id: bg_pink
+    hex: "61034D"
+  - id: bg_charcoal
+    hex: "323232"
+  - id: bg_brown
+    hex: "41220D"
+  - id: bg_grey
+    hex: "4F4F4F"
+
+spi:
+  clk_pin: 7
+  mosi_pin: 6
+
+display:
+  - platform: ili9xxx
+    id: s3_box_lcd
+    model: S3BOX
+    data_rate: 40MHz
+    cs_pin: 5
+    dc_pin: 4
+    reset_pin:
+      number: 48
+      inverted: true
+    update_interval: never
+    invert_colors: false
+    ##################################################################################################
+    ################ The below section defines, what is displayed on the screen,        ##############
+    ################ the colours and mdi icons are defined above under font: and Color: ##############
+    ################ they are then referenced in the config below.                      ##############
+    ##################################################################################################
+    pages:
+      - id: idle_page ##### home page ######
+        lambda: |-
+          it.fill(id(black));
+          if(id(api_connection) == true) {
+            it.printf(15, 5, id(icon_font_55), blue, "\U000F07D0");      
+          } else {
+            it.printf(15, 5, id(icon_font_55), red, "\U000F087B");
+          }
+          if(id(wifi_connection) == true) {
+            it.printf(80, 5, id(icon_font_55), lime, "\U000F16BD");      
+          } else {
+            it.printf(80, 5, id(icon_font_55), red, "\U000F16BC");
+          }
+          if(id(time_remaining_0).state == "0:00:00"){
+            it.printf(135, 5, id(icon_font_55), red, "\U000F0150");
+          } else {
+            it.printf(135, 5, id(icon_font_55), lime, "\U000F0150");
+          }
+          if(id(mute_switch).state) {
+            it.printf(190, 5, id(icon_font_55), red, "\U000F036D"); 
+          } else {
+            it.printf(190, 5, id(icon_font_55), lime, "\U000F036C"); 
+          }
+          if(id(alarm_status).state == "disarmed") {
+            it.printf(250, 5, id(icon_font_55), red, "\U000F099E"); 
+          } else if(id(alarm_status).state == "arming") {
+            it.printf(250, 5, id(icon_font_55), amber, "\U000F0565"); 
+          } else if(id(alarm_status).state == "armed_home") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F068A");
+          } else if(id(alarm_status).state == "armed_away") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F099D");     
+          } else if(id(alarm_status).state == "armed_night") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F1828");
+          }        
+          it.printf(20, 75, id(icon_font_80), blue,"\U000F050F");
+          it.printf(40, 120, id(my_font3), white, "%.f", id(s3temp).state); // remove for no sensor version
+          it.printf(120, 75, id(icon_font_80), yellow,"\U000F06E8" );
+          it.printf(220, 75, id(icon_font_80), purple,"\U000F0210");
+          it.printf(20, 155, id(icon_font_80), red,"\U000F075A");
+          it.printf(120, 155, id(icon_font_80), blue,"\U000F0FCE");
+          it.printf(220, 155, id(icon_font_80), lime,"\U000F08D6");
+
+      - id: template_page ##### template page ####
+        lambda: |-
+          it.fill(id(black));
+          if(id(api_connection) == true) {
+            it.printf(15, 5, id(icon_font_55), blue, "\U000F07D0");      
+          } else {
+            it.printf(15, 5, id(icon_font_55), red, "\U000F087B");
+          }
+          if(id(wifi_connection) == true) {
+            it.printf(80, 5, id(icon_font_55), lime, "\U000F16BD");      
+          } else {
+            it.printf(80, 5, id(icon_font_55), red, "\U000F16BC");
+          }
+          if(id(time_remaining_0).state == "0:00:00"){
+            it.printf(135, 5, id(icon_font_55), red, "\U000F0150");
+          } else {
+            it.printf(135, 5, id(icon_font_55), lime, "\U000F0150");
+          }
+          if(id(mute_switch).state) {
+            it.printf(190, 5, id(icon_font_55), red, "\U000F036D"); 
+          } else {
+            it.printf(190, 5, id(icon_font_55), lime, "\U000F036C"); 
+          }
+          if(id(alarm_status).state == "disarmed") {
+            it.printf(250, 5, id(icon_font_55), red, "\U000F099E"); 
+          } else if(id(alarm_status).state == "arming") {
+            it.printf(250, 5, id(icon_font_55), amber, "\U000F0565"); 
+          } else if(id(alarm_status).state == "armed_home") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F068A");
+          } else if(id(alarm_status).state == "armed_away") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F099D");     
+          } else if(id(alarm_status).state == "armed_night") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F1828");
+          }  
+          it.printf(20, 75, id(icon_font_80), light_blue,"\U000F06E8");
+          it.printf(120, 75, id(icon_font_80), light_blue,"\U000F06E8");
+          it.printf(220, 75, id(icon_font_80), light_blue, "\U000F06E8");
+          it.printf(20, 155, id(icon_font_80), light_blue,"\U000F06E8");
+          it.printf(120, 155, id(icon_font_80), light_blue,"\U000F06E8");
+          it.printf(220, 155, id(icon_font_80), light_blue, "\U000F06E8");
+
+      - id: info_page ##### info page #####
+        lambda: |-
+          it.fill(id(black));
+          if(id(api_connection) == true) {
+            it.printf(15, 5, id(icon_font_55), blue, "\U000F07D0");      
+          } else {
+            it.printf(15, 5, id(icon_font_55), red, "\U000F087B");
+          }
+          if(id(wifi_connection) == true) {
+            it.printf(80, 5, id(icon_font_55), lime, "\U000F16BD");      
+          } else {
+            it.printf(80, 5, id(icon_font_55), red, "\U000F16BC");
+          }
+          if(id(time_remaining_0).state == "0:00:00"){
+            it.printf(135, 5, id(icon_font_55), red, "\U000F0150");
+          } else {
+            it.printf(135, 5, id(icon_font_55), lime, "\U000F0150");
+          }
+          if(id(mute_switch).state) {
+            it.printf(190, 5, id(icon_font_55), red, "\U000F036D"); 
+          } else {
+            it.printf(190, 5, id(icon_font_55), lime, "\U000F036C"); 
+          }
+          if(id(alarm_status).state == "disarmed") {
+            it.printf(250, 5, id(icon_font_55), red, "\U000F099E"); 
+          } else if(id(alarm_status).state == "arming") {
+            it.printf(250, 5, id(icon_font_55), amber, "\U000F0565"); 
+          } else if(id(alarm_status).state == "armed_home") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F068A");
+          } else if(id(alarm_status).state == "armed_away") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F099D");     
+          } else if(id(alarm_status).state == "armed_night") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F1828");
+          }  
+          it.printf(160, 75, id(my_font5), light_blue, TextAlign::CENTER, "IP Address");
+          it.printf(160, 95, id(my_font5), yellow, TextAlign::CENTER, "%s", id(ip_addr).state.c_str());
+          it.printf(160, 125, id(my_font5), light_blue, TextAlign::CENTER, "Host Name");
+          it.printf(160, 145, id(my_font5), yellow, TextAlign::CENTER, "${name}.local");
+          it.printf(160, 175, id(my_font5), light_blue, TextAlign::CENTER, "Device Uptime DDD:H:M:S");
+          it.printf(160, 195, id(my_font5), yellow, TextAlign::CENTER, "%s", id(up_sens_text).state.c_str());
+          it.printf(40, 210, id(my_font5), light_blue, TextAlign::LEFT, "Battery Level"); // remove for no sensor version
+          it.printf(265, 210, id(my_font5), yellow, TextAlign::RIGHT, "%.f%%", id(battery_percent).state); // remove for no sensor version
+
+      - id: ss_set_page ##### screen saver settings page #####
+        lambda: |-
+          it.fill(id(black));
+          it.printf(160, 70, id(icon_font_80), light_blue, TextAlign::CENTER, "\U000F08D6");  
+          it.printf(160, 20, id(my_font5), light_blue, TextAlign::CENTER, "Screensaver Settings");
+          it.printf(250, 115, id(my_font5), light_blue, TextAlign::RIGHT, "Timeout Settings :");
+          it.printf(255, 95, id(icon_font_55), lime, "\U000F08D6");
+          it.printf(250, 145, id(my_font5), light_blue, TextAlign::RIGHT, "Enable screensaver :");
+          if(id(s_saver).state) {
+            it.printf(255, 135, id(icon_font_55), lime, "\U000F0521");
+          } else {   
+            it.printf(255, 135, id(icon_font_55), blue_drk, "\U000F0A19");
+          } 
+          it.printf(250, 175, id(my_font5), light_blue, TextAlign::RIGHT, "Wake on presence :"); // remove for no sensor version 6 lines          
+          if(id(s_saver_presc).state) {
+            it.printf(255, 165, id(icon_font_55), lime, "\U000F0521");
+          } else {   
+            it.printf(255, 165, id(icon_font_55), blue_drk, "\U000F0A19");
+          } 
+          it.printf(250, 205, id(my_font5), light_blue, TextAlign::RIGHT, "Timeout to blank :");          
+          if(id(s_saver_mode).state) {
+            it.printf(255, 195, id(icon_font_55), lime, "\U000F0521");
+          } else {   
+            it.printf(255, 195, id(icon_font_55), blue_drk, "\U000F0A19");
+          }
+
+      - id: ww_set_page ##### voice settings page #####
+        lambda: |-
+          it.fill(id(black));
+          it.printf(160, 50, id(icon_font_55), light_blue, TextAlign::CENTER, "\U000F08D6");  
+          it.printf(160, 20, id(my_font5), light_blue, TextAlign::CENTER, "Voice Settings");
+          it.printf(155, 85, id(my_font5), light_blue, TextAlign::CENTER, "tap to change");
+          it.printf(135, 115, id(my_font5), light_blue, TextAlign::RIGHT, "WakeWord :");
+          it.printf(310, 115, id(my_font5), lime, TextAlign::RIGHT, "%s", id(wakeword_location).state.c_str());
+          it.printf(250, 145, id(my_font5), light_blue, TextAlign::RIGHT, "Mute responses :"); 
+          if(id(mute_response_switch).state) {
+            it.printf(255, 135, id(icon_font_55), lime, "\U000F0521");
+          } else {   
+            it.printf(255, 135, id(icon_font_55), blue_drk, "\U000F0A19");
+          }          
+          it.printf(250, 175, id(my_font5), light_blue, TextAlign::RIGHT, "Wake up sound :");          
+          if(id(wake_sound).state) {
+            it.printf(255, 165, id(icon_font_55), lime, "\U000F0521");
+          } else {   
+            it.printf(255, 165, id(icon_font_55), blue_drk, "\U000F0A19");
+          } 
+          it.printf(250, 205, id(my_font5), light_blue, TextAlign::RIGHT, "Show Conversation :");          
+          if(id(display_conversation).state) {
+            it.printf(255, 195, id(icon_font_55), lime, "\U000F0521");
+          } else {   
+            it.printf(255, 195, id(icon_font_55), blue_drk, "\U000F0A19");
+          }
+
+      - id: climate_page ##### climate page #####
+        lambda: |-
+          it.fill(id(black));
+          if(id(api_connection) == true) {
+            it.printf(15, 5, id(icon_font_55), blue, "\U000F07D0");      
+          } else {
+            it.printf(15, 5, id(icon_font_55), red, "\U000F087B");
+          }
+          if(id(wifi_connection) == true) {
+            it.printf(80, 5, id(icon_font_55), lime, "\U000F16BD");      
+          } else {
+            it.printf(80, 5, id(icon_font_55), red, "\U000F16BC");
+          }
+          if(id(time_remaining_0).state == "0:00:00"){
+            it.printf(135, 5, id(icon_font_55), red, "\U000F0150");
+          } else {
+            it.printf(135, 5, id(icon_font_55), lime, "\U000F0150");
+          }
+          if(id(mute_switch).state) {
+            it.printf(190, 5, id(icon_font_55), red, "\U000F036D"); 
+          } else {
+            it.printf(190, 5, id(icon_font_55), lime, "\U000F036C"); 
+          }
+          if(id(alarm_status).state == "disarmed") {
+            it.printf(250, 5, id(icon_font_55), red, "\U000F099E"); 
+          } else if(id(alarm_status).state == "arming") {
+            it.printf(250, 5, id(icon_font_55), amber, "\U000F0565"); 
+          } else if(id(alarm_status).state == "armed_home") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F068A");
+          } else if(id(alarm_status).state == "armed_away") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F099D");     
+          } else if(id(alarm_status).state == "armed_night") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F1828");
+          }  
+          it.printf(20, 75, id(icon_font_80), light_blue,"\U000F050F");
+          it.printf(120, 75, id(icon_font_80), light_blue,"\U000F050F");
+          it.printf(220, 75, id(icon_font_80), light_blue, "\U000F050F");
+          it.printf(20, 155, id(icon_font_80), light_blue,"\U000F050F");
+          it.printf(120, 155, id(icon_font_80), light_blue,"\U000F050F");
+          it.printf(220, 155, id(icon_font_80), light_blue, "\U000F050F");
+
+      - id: lights_page ##### lights page ####
+        lambda: |-
+          it.fill(id(black));
+          if(id(api_connection) == true) {
+            it.printf(15, 5, id(icon_font_55), blue, "\U000F07D0");      
+          } else {
+            it.printf(15, 5, id(icon_font_55), red, "\U000F087B");
+          }
+          if(id(wifi_connection) == true) {
+            it.printf(80, 5, id(icon_font_55), lime, "\U000F16BD");      
+          } else {
+            it.printf(80, 5, id(icon_font_55), red, "\U000F16BC");
+          }
+          if(id(time_remaining_0).state == "0:00:00"){
+            it.printf(135, 5, id(icon_font_55), red, "\U000F0150");
+          } else {
+            it.printf(135, 5, id(icon_font_55), lime, "\U000F0150");
+          }
+          if(id(mute_switch).state) {
+            it.printf(190, 5, id(icon_font_55), red, "\U000F036D"); 
+          } else {
+            it.printf(190, 5, id(icon_font_55), lime, "\U000F036C"); 
+          }
+          if(id(alarm_status).state == "disarmed") {
+            it.printf(250, 5, id(icon_font_55), red, "\U000F099E"); 
+          } else if(id(alarm_status).state == "arming") {
+            it.printf(250, 5, id(icon_font_55), amber, "\U000F0565"); 
+          } else if(id(alarm_status).state == "armed_home") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F068A");
+          } else if(id(alarm_status).state == "armed_away") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F099D");     
+          } else if(id(alarm_status).state == "armed_night") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F1828");
+          }  
+          it.printf(20, 75, id(icon_font_80), light_blue,"\U000F0335");
+          it.printf(120, 75, id(icon_font_80), light_blue,"\U000F0335");
+          it.printf(220, 75, id(icon_font_80), light_blue, "\U000F0335");
+          it.printf(20, 155, id(icon_font_80), light_blue,"\U000F0335");
+          it.printf(120, 155, id(icon_font_80), light_blue,"\U000F0335");
+          it.printf(220, 155, id(icon_font_80), light_blue, "\U000F0335");
+
+      - id: media_page ##### media player page #####
+        lambda: |-
+          it.fill(id(black));
+          if(id(api_connection) == true) {
+            it.printf(15, 5, id(icon_font_55), blue, "\U000F07D0");      
+          } else {
+            it.printf(15, 5, id(icon_font_55), red, "\U000F087B");
+          }
+          if(id(wifi_connection) == true) {
+            it.printf(80, 5, id(icon_font_55), lime, "\U000F16BD");      
+          } else {
+            it.printf(80, 5, id(icon_font_55), red, "\U000F16BC");
+          }
+          if(id(time_remaining_0).state == "0:00:00"){
+            it.printf(135, 5, id(icon_font_55), red, "\U000F0150");
+          } else {
+            it.printf(135, 5, id(icon_font_55), lime, "\U000F0150");
+          }
+          if(id(mute_switch).state) {
+            it.printf(190, 5, id(icon_font_55), red, "\U000F036D"); 
+          } else {
+            it.printf(190, 5, id(icon_font_55), lime, "\U000F036C"); 
+          }
+          if(id(alarm_status).state == "disarmed") {
+            it.printf(250, 5, id(icon_font_55), red, "\U000F099E"); 
+          } else if(id(alarm_status).state == "arming") {
+            it.printf(250, 5, id(icon_font_55), amber, "\U000F0565"); 
+          } else if(id(alarm_status).state == "armed_home") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F068A");
+          } else if(id(alarm_status).state == "armed_away") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F099D");     
+          } else if(id(alarm_status).state == "armed_night") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F1828");
+          }  
+          if(id(media_state) == true) {
+            it.printf(160, 80, id(my_font5), lime, TextAlign::CENTER, "Playing");
+          } else {
+            it.printf(160, 80, id(my_font5), light_blue, TextAlign::CENTER, "Nothing Playing");
+          }
+          it.printf(20, 100, id(icon_font_80), blue,"\U000F075E");
+          it.printf(120, 100, id(icon_font_80), blue,"\U000F040E");
+          it.printf(220, 100, id(icon_font_80), blue,"\U000F075D");
+          if(id(media_mute).state) {          
+            it.printf(120, 165, id(icon_font_80), red,"\U000F0581");
+          } else {        
+            it.printf(120, 165, id(icon_font_80), lime,"\U000F057E");
+          }
+
+      - id: ext_media_page ##### media player page #####
+        lambda: |-
+          it.fill(id(black));
+          if(id(api_connection) == true) {
+            it.printf(15, 5, id(icon_font_55), blue, "\U000F07D0");      
+          } else {
+            it.printf(15, 5, id(icon_font_55), red, "\U000F087B");
+          }
+          if(id(wifi_connection) == true) {
+            it.printf(80, 5, id(icon_font_55), lime, "\U000F16BD");      
+          } else {
+            it.printf(80, 5, id(icon_font_55), red, "\U000F16BC");
+          }
+          if(id(time_remaining_0).state == "0:00:00"){
+            it.printf(135, 5, id(icon_font_55), red, "\U000F0150");
+          } else {
+            it.printf(135, 5, id(icon_font_55), lime, "\U000F0150");
+          }
+          if(id(mute_switch).state) {
+            it.printf(190, 5, id(icon_font_55), red, "\U000F036D"); 
+          } else {
+            it.printf(190, 5, id(icon_font_55), lime, "\U000F036C"); 
+          }
+          if(id(alarm_status).state == "disarmed") {
+            it.printf(250, 5, id(icon_font_55), red, "\U000F099E"); 
+          } else if(id(alarm_status).state == "arming") {
+            it.printf(250, 5, id(icon_font_55), amber, "\U000F0565"); 
+          } else if(id(alarm_status).state == "armed_home") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F068A");
+          } else if(id(alarm_status).state == "armed_away") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F099D");     
+          } else if(id(alarm_status).state == "armed_night") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F1828");
+          }  
+          it.printf(160, 80, id(my_font5), lime, TextAlign::CENTER, id(ha_media_status).state.c_str());
+          it.printf(20, 100, id(icon_font_80), blue,"\U000F04AE");
+          it.printf(120, 100, id(icon_font_80), blue,"\U000F040E");
+          it.printf(220, 100, id(icon_font_80), blue,"\U000F04AD");
+          if(id(ext_media_mute).state) {          
+            it.printf(120, 165, id(icon_font_80), red,"\U000F0581");
+          } else {        
+            it.printf(120, 165, id(icon_font_80), lime,"\U000F057E");
+          }
+          it.printf(20, 165, id(icon_font_80), blue,"\U000F075E");
+          it.printf(220, 165, id(icon_font_80), blue,"\U000F075D");
+
+      - id: scenes_page ##### scenes page #####
+        lambda: |-
+          it.fill(id(black));
+          if(id(api_connection) == true) {
+            it.printf(15, 5, id(icon_font_55), blue, "\U000F07D0");      
+          } else {
+            it.printf(15, 5, id(icon_font_55), red, "\U000F087B");
+          }
+          if(id(wifi_connection) == true) {
+            it.printf(80, 5, id(icon_font_55), lime, "\U000F16BD");      
+          } else {
+            it.printf(80, 5, id(icon_font_55), red, "\U000F16BC");
+          }
+          if(id(time_remaining_0).state == "0:00:00"){
+            it.printf(135, 5, id(icon_font_55), red, "\U000F0150");
+          } else {
+            it.printf(135, 5, id(icon_font_55), lime, "\U000F0150");
+          }
+          if(id(mute_switch).state) {
+            it.printf(190, 5, id(icon_font_55), red, "\U000F036D"); 
+          } else {
+            it.printf(190, 5, id(icon_font_55), lime, "\U000F036C"); 
+          }
+          if(id(alarm_status).state == "disarmed") {
+            it.printf(250, 5, id(icon_font_55), red, "\U000F099E"); 
+          } else if(id(alarm_status).state == "arming") {
+            it.printf(250, 5, id(icon_font_55), amber, "\U000F0565"); 
+          } else if(id(alarm_status).state == "armed_home") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F068A");
+          } else if(id(alarm_status).state == "armed_away") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F099D");     
+          } else if(id(alarm_status).state == "armed_night") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F1828");
+          }    
+          it.printf(20, 75, id(icon_font_80), light_blue,"\U000F0FCE");
+          it.printf(120, 75, id(icon_font_80), light_blue,"\U000F0FCE");
+          it.printf(220, 75, id(icon_font_80), light_blue, "\U000F0FCE");
+          it.printf(20, 155, id(icon_font_80), light_blue,"\U000F0FCE");
+          it.printf(120, 155, id(icon_font_80), light_blue,"\U000F0FCE");
+          it.printf(220, 155, id(icon_font_80), light_blue, "\U000F0FCE");
+
+      - id: loading_page ### loading page #####
+        lambda: |-
+          it.fill(Color::BLACK);
+          it.image((it.get_width() / 2), (it.get_height() / 2), id(loading_img), ImageAlign::CENTER);
+
+      - id: listening_page
+        lambda: |-
+          it.fill(Color::BLACK);
+          it.image((it.get_width() / 2), (it.get_height() / 2), id(listening_img), ImageAlign::CENTER);
+
+      - id: thinking_page
+        lambda: |-
+          it.fill(Color::BLACK);
+          it.image((it.get_width() / 2), (it.get_height() / 2), id(thinking_img), ImageAlign::CENTER);
+          if (id(display_conversation).state) {
+            it.filled_rectangle(0 , 0 , 320 , 30 , Color::WHITE );
+            it.printf(10, 10, id(my_font16), Color::BLACK, "%s", id(text_request).state.c_str());
+          }
+  
+      - id: replying_page
+        lambda: |-
+          it.fill(Color::BLACK);
+          it.image((it.get_width() / 2), (it.get_height() / 2), id(replying_img), ImageAlign::CENTER);
+          if (id(display_conversation).state) {
+            it.filled_rectangle(0 , 0 , 320 , 30 , Color::WHITE );
+            it.filled_rectangle(0 , 210 , 320 , 30 , Color::WHITE );
+            it.printf(10, 10, id(my_font16), Color::BLACK, "%s", id(text_request).state.c_str());
+            it.printf(10, 220, id(my_font16), Color::BLACK, "%s", id(text_response).state.c_str());
+          }
+  
+      - id: error_page
+        lambda: |-
+          it.fill(Color::BLACK);
+          it.image((it.get_width() / 2), (it.get_height() / 2), id(error_img), ImageAlign::CENTER);
+
+      - id: timer_finished_page
+        lambda: |-
+          it.fill(id(black));
+          it.printf(160, 20, id(my_font5), light_blue, TextAlign::CENTER, "Timer Finished");
+          it.printf(160, 120, id(icon_font_180), light_blue, TextAlign::CENTER, "\U000F009E");
+          it.printf(160, 215, id(my_font5), light_blue, TextAlign::CENTER, "tap screen to dismiss");
+
+      - id: muted_page
+        lambda: |-
+          it.fill(Color::BLACK);
+          it.printf(160, 120, id(my_font4), yellow, TextAlign::CENTER, "Mic & Speaker - Muted");
+
+      - id: saver_page ##### screen saver display page #####
+        lambda: |-
+          it.fill(id(black));         
+          const char *days[] {"${sunday}","${monday}","${tuesday}","${wednesday}","${thursday}","${friday}","${saturday}"};
+          const char *months[] {"${jan}","${feb}","${mar}","${apr}","${may}","${jun}","${jul}","${aug}","${sept}","${oct}","${nov}","${dec}"};
+          it.printf(160, 28, id(my_font5), light_blue, TextAlign::CENTER, "%s %d %s", days[id(ha_time).now().day_of_week - 1], id(ha_time).now().day_of_month, months[id(ha_time).now().month - 1]);
+          if(id(time_display_format).state == "24 Hr") {
+            it.strftime(160, 88, id(my_font82), TextAlign::CENTER, "%H:%M", id(ha_time).now());
+          } else {
+            it.strftime(160, 88, id(my_font2), TextAlign::CENTER, "%l:%M%p", id(ha_time).now());
+          }
+          it.printf(160, 181, id(my_font2), light_blue, TextAlign::CENTER, "%.f°C", id(s3temp).state); // remove for no sensor version
+
+      - id: ota_page ##### firmware uploading page #####
+        lambda: |-
+          it.fill(Color::BLACK);
+          it.printf(160, 60, id(icon_font_80), red, TextAlign::CENTER, "\U000F08D6");  
+          it.printf((it.get_width() / 2), (it.get_height() / 2), id(my_font3), red, TextAlign::CENTER, "FIRMWARE UPDATING");
+          it.printf(160,155, id(my_font5), blue, TextAlign::CENTER, "Once restarted");
+          it.printf(160,190, id(my_font5), blue, TextAlign::CENTER, "press the reboot button");
+          it.printf(160,225, id(my_font5), blue, TextAlign::CENTER, "to enable touch");
+
+      - id: settings_page ##### settings parent page #####
+        lambda: |-
+          it.fill(id(black));
+          if(id(api_connection) == true) {
+            it.printf(15, 5, id(icon_font_55), blue, "\U000F07D0");      
+          } else {
+            it.printf(15, 5, id(icon_font_55), red, "\U000F087B");
+          }
+          if(id(wifi_connection) == true) {
+            it.printf(80, 5, id(icon_font_55), lime, "\U000F16BD");      
+          } else {
+            it.printf(80, 5, id(icon_font_55), red, "\U000F16BC");
+          }
+          if(id(time_remaining_0).state == "0:00:00"){
+            it.printf(135, 5, id(icon_font_55), red, "\U000F0150");
+          } else {
+            it.printf(135, 5, id(icon_font_55), lime, "\U000F0150");
+          }
+          if(id(mute_switch).state) {
+            it.printf(190, 5, id(icon_font_55), red, "\U000F036D"); 
+          } else {
+            it.printf(190, 5, id(icon_font_55), lime, "\U000F036C"); 
+          }
+          if(id(alarm_status).state == "disarmed") {
+            it.printf(250, 5, id(icon_font_55), red, "\U000F099E"); 
+          } else if(id(alarm_status).state == "arming") {
+            it.printf(250, 5, id(icon_font_55), amber, "\U000F0565"); 
+          } else if(id(alarm_status).state == "armed_home") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F068A");
+          } else if(id(alarm_status).state == "armed_away") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F099D");     
+          } else if(id(alarm_status).state == "armed_night") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F1828");
+          }          
+          it.printf(160, 65, id(my_font5), light_blue, TextAlign::CENTER, "settings");         
+          it.printf(20, 80, id(icon_font_55), light_blue,"\U000F036F");
+          it.printf(140, 80, id(icon_font_55), light_blue,"\U000F0502");
+          it.printf(255, 80, id(icon_font_55), light_blue, "\U000F1C6F");  
+          it.printf(15, 210, id(my_font5), light_blue,"Device");
+          it.printf(245, 130, id(my_font5), light_blue, "Info");           
+          it.printf(20, 160, id(icon_font_55), light_blue,"\U000F08D6");        
+          it.printf(255, 160, id(icon_font_55), light_blue, "\U000F05CB");
+          it.printf(15, 130, id(my_font5), light_blue,"Voice");
+          it.printf(135, 130, id(my_font5), light_blue,"Saver");
+          it.printf(245, 210, id(my_font5), light_blue, "Test"); 
+          it.image((it.get_width() / 2), 195, id(logo_img), ImageAlign::CENTER);
+
+      - id: device_set_page ##### Device settings page #####
+        lambda: |-
+          it.fill(id(black));
+          if(id(api_connection) == true) {
+            it.printf(15, 5, id(icon_font_55), blue, "\U000F07D0");      
+          } else {
+            it.printf(15, 5, id(icon_font_55), red, "\U000F087B");
+          }
+          if(id(wifi_connection) == true) {
+            it.printf(80, 5, id(icon_font_55), lime, "\U000F16BD");      
+          } else {
+            it.printf(80, 5, id(icon_font_55), red, "\U000F16BC");
+          }
+          if(id(time_remaining_0).state == "0:00:00"){
+            it.printf(135, 5, id(icon_font_55), red, "\U000F0150");
+          } else {
+            it.printf(135, 5, id(icon_font_55), lime, "\U000F0150");
+          }
+          if(id(mute_switch).state) {
+            it.printf(190, 5, id(icon_font_55), red, "\U000F036D"); 
+          } else {
+            it.printf(190, 5, id(icon_font_55), lime, "\U000F036C"); 
+          }
+          if(id(alarm_status).state == "disarmed") {
+            it.printf(250, 5, id(icon_font_55), red, "\U000F099E"); 
+          } else if(id(alarm_status).state == "arming") {
+            it.printf(250, 5, id(icon_font_55), amber, "\U000F0565"); 
+          } else if(id(alarm_status).state == "armed_home") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F068A");
+          } else if(id(alarm_status).state == "armed_away") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F099D");     
+          } else if(id(alarm_status).state == "armed_night") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F1828");
+          }          
+          it.printf(15, 75, id(my_font5), light_blue, "Ext media player"); 
+          if(id(output_audio).state) {
+            it.printf(255, 60, id(icon_font_60), lime, "\U000F0521");
+          } else {   
+            it.printf(255, 60, id(icon_font_60), blue_drk, "\U000F0A19");
+          }
+          it.printf(5, 190, id(icon_font_55), light_blue, "\U000F0B28");
+          it.printf(15, 135, id(my_font5), light_blue, "Brightness");          
+          it.printf(238, 148, id(my_font5), light_blue, TextAlign::CENTER, "%.f", id(s_default_brightness).state);  
+          it.printf(160, 125, id(icon_font_55), lime, TextAlign::LEFT, "\U000F0B2C");    
+          it.printf(315, 125, id(icon_font_55), lime, TextAlign::RIGHT, "\U000F0B26");           
+          it.rectangle(215 , 125 , 46 , 40 , light_blue);
+          it.printf(65, 180, id(my_font5), light_blue, "Time Format:");
+          it.printf(210, 180, id(my_font5), lime, "%s", id(time_display_format).state.c_str());
+
+      - id: timeout_settings_page ##### Timeout Settings page #####
+        lambda: |-
+          it.fill(id(black));
+          //it.printf(160, 50, id(icon_font_55), light_blue, TextAlign::CENTER, "\U000F0150"); 
+          it.printf(160, 20, id(my_font5), light_blue, TextAlign::CENTER, "Screen Settings");  
+          it.printf(160, 60, id(my_font5), light_blue, TextAlign::CENTER, "Screen Saver"); 
+          it.printf(50, 80, id(my_font), light_blue, "Delay secs");
+          it.printf(185, 80, id(my_font), light_blue, "Dim Brightness");
+          it.printf(105, 100, id(icon_font_55), lime, TextAlign::LEFT, "\U000F0B2C");    
+          it.printf(65, 100, id(icon_font_55), lime, TextAlign::RIGHT, "\U000F0B26");          
+          it.rectangle(65 , 105 , 40 , 40 , lime);
+          it.printf(85, 125, id(my_font5), light_blue, TextAlign::CENTER, "%.f", id(s_saver_delay).state);
+          it.printf(20, 160, id(my_font), light_blue, "Screen off delay"); 
+          it.printf(105, 180, id(icon_font_55), lime, TextAlign::LEFT, "\U000F0B2C");    
+          it.printf(65, 180, id(icon_font_55), lime, TextAlign::RIGHT, "\U000F0B26");          
+          it.rectangle(65 , 180 , 40 , 40 , lime);
+          it.printf(85, 200, id(my_font5), light_blue, TextAlign::CENTER, "%.f", id(s_saver_blank_delay).state);
+          it.printf(255, 100, id(icon_font_55), pink, TextAlign::LEFT, "\U000F0B2C");    
+          it.printf(215, 100, id(icon_font_55), pink, TextAlign::RIGHT, "\U000F0B26");          
+          it.rectangle(215 , 105 , 40 , 40 , pink);
+          it.printf(235, 125, id(my_font5), light_blue, TextAlign::CENTER, "%.f", id(s_saver_brightness).state);
+
+      - id: time_remaining_page ##### timer countdown page #####
+        lambda: |-
+          it.fill(id(black));
+          it.printf(160, 20, id(my_font5), light_blue, TextAlign::CENTER, "Active Timers");
+          it.printf(160, 70, id(icon_font_80), light_blue, TextAlign::CENTER, "\U000F0150"); 
+          it.printf(160, 155, id(my_font6), light_blue, TextAlign::CENTER, "%s", id(time_remaining_0).state.c_str());
+
+      - id: wifi_page ##### wifi info page #####
+        lambda: |-
+          it.fill(id(black));
+          if(id(api_connection) == true) {
+            it.printf(15, 5, id(icon_font_55), blue, "\U000F07D0");      
+          } else {
+            it.printf(15, 5, id(icon_font_55), red, "\U000F087B");
+          }
+          if(id(wifi_connection) == true) {
+            it.printf(80, 5, id(icon_font_55), lime, "\U000F16BD");      
+          } else {
+            it.printf(80, 5, id(icon_font_55), red, "\U000F16BC");
+          }
+          if(id(time_remaining_0).state == "0:00:00"){
+            it.printf(135, 5, id(icon_font_55), red, "\U000F0150");
+          } else {
+            it.printf(135, 5, id(icon_font_55), lime, "\U000F0150");
+          }
+          if(id(mute_switch).state) {
+            it.printf(190, 5, id(icon_font_55), red, "\U000F036D"); 
+          } else {
+            it.printf(190, 5, id(icon_font_55), lime, "\U000F036C"); 
+          }
+          if(id(alarm_status).state == "disarmed") {
+            it.printf(250, 5, id(icon_font_55), red, "\U000F099E"); 
+          } else if(id(alarm_status).state == "arming") {
+            it.printf(250, 5, id(icon_font_55), amber, "\U000F0565"); 
+          } else if(id(alarm_status).state == "armed_home") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F068A");
+          } else if(id(alarm_status).state == "armed_away") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F099D");     
+          } else if(id(alarm_status).state == "armed_night") {
+            it.printf(250, 5, id(icon_font_55), green, "\U000F1828");
+          }  
+          it.printf(160, 75, id(my_font5), light_blue, TextAlign::CENTER, "ssid");
+          it.printf(160, 95, id(my_font5), yellow, TextAlign::CENTER, "%s", id(connected_ssid).state.c_str());
+          it.printf(160, 125, id(my_font5), light_blue, TextAlign::CENTER, "bssid");
+          it.printf(160, 145, id(my_font5), yellow, TextAlign::CENTER, "%s", id(connected_bssid).state.c_str());
+          it.printf(160, 175, id(my_font5), light_blue, TextAlign::CENTER, "Device MAC");
+          it.printf(160, 195, id(my_font5), yellow, TextAlign::CENTER, "%s", id(device_mac).state.c_str());
+          it.printf(38, 210, id(my_font5), light_blue, TextAlign::LEFT, "Signal Strength");
+          it.printf(283, 210, id(my_font5), yellow, TextAlign::RIGHT, "%4.f%%", id(wifi_percent).state);
+
+      - id: alarm_page #### alarm page #####
+        lambda: |-
+          if(id(alarm_status).state == "disarmed") {
+            it.printf(10, 10, id(icon_font_180), red, "\U000F099E");
+            it.printf(40, 200, id(my_font3), red, "Disarmed");
+          } else if(id(alarm_status).state == "arming") {
+            it.printf(10, 10, id(icon_font_180), amber, "\U000F0565");
+            it.printf(40, 200, id(my_font3), amber, "Arming");
+          } else if(id(alarm_status).state == "armed_home") {
+            it.printf(10, 10, id(icon_font_180), green, "\U000F068A");
+            it.printf(60, 200, id(my_font3), green, "Armed");
+          } else if(id(alarm_status).state == "armed_away") {
+            it.printf(10, 10, id(icon_font_180), green, "\U000F099D");
+            it.printf(60, 200, id(my_font3), green, "Armed");
+          } else if(id(alarm_status).state == "armed_night") {
+            it.printf(10, 10, id(icon_font_180), green, "\U000F1828");
+            it.printf(60, 200, id(my_font3), green, "Armed");
+          }
+          if(id(alarm_status).state == "armed_home") {
+            it.printf(225, 5, id(icon_font_60), green, "\U000F068A");
+            it.printf(233, 60, id(my_font18), light_blue, "Home");
+          } else {
+            it.printf(225, 5, id(icon_font_60), blue_drk, "\U000F068A");
+            it.printf(233, 60, id(my_font18), light_blue, "Home");
+          }
+          if(id(alarm_status).state == "armed_away") {
+            it.printf(225, 80, id(icon_font_60), green, "\U000F099D");
+            it.printf(233, 135, id(my_font18), light_blue, "Away");
+          } else {          
+            it.printf(225, 80, id(icon_font_60), blue_drk, "\U000F099D");
+            it.printf(233, 135, id(my_font18), light_blue, "Away");
+          }
+          if(id(alarm_status).state == "armed_night") {
+            it.printf(225, 155, id(icon_font_60), green, "\U000F1828");         
+            it.printf(228, 215, id(my_font18), light_blue, "Night");
+          } else {
+            it.printf(225, 155, id(icon_font_60), blue_drk, "\U000F1828");         
+            it.printf(228, 215, id(my_font18), light_blue, "Night");
+          }
+
+      - id: alarm_home_activate_page ##### alarm  home activation page #####
+        lambda: |-
+          auto pin_state = id(current_pin).c_str();
+          it.print(310, 80, id(my_font3), TextAlign::RIGHT, pin_state);
+          // loop for numbers 1 - 9
+          for (int i = 0; i < 3; i++) {
+            for (int j = 0; j < 3; j++) {
+              int number = i * 3 + j + 1;
+              int x_position = 15 + j * 56;  // Ajustement de la position en X
+              int y_position = 15 + i * 56;  // Ajustement de la position en Y
+              it.rectangle(x_position, y_position, 48, 48, light_blue);  // Taille du rectangle ajustée
+              char num_str[2];
+              snprintf(num_str, sizeof(num_str), "%d", number);
+              it.print(x_position + 24, y_position + 24, id(my_font3), TextAlign::CENTER, num_str);  // Centrage du chiffre
+            }
+          }
+          it.rectangle(71, 183, 48, 48, light_blue);  // Position et taille du rectangle ajustées
+          it.print(95, 207, id(my_font3), TextAlign::CENTER, "0");  // Centrage du chiffre "0"
+          //it.filled_rectangle(198, 110, 108, 50, green);
+          if(id(alarm_status).state == "disarmed"){
+            it.filled_rectangle(198, 110, 108, 50, red);
+            it.print(255, 135, id(my_font3), white, TextAlign::CENTER, "Arm");
+          } else if(id(alarm_status).state == "armed_home"){
+            it.filled_rectangle(198, 110, 108, 50, green); 
+            it.print(255, 135, id(my_font3), white, TextAlign::CENTER, "Disarm");
+          }                 
+          it.filled_rectangle(198, 170, 108, 50, blue_drk);
+          it.print(255, 195, id(my_font3), white, TextAlign::CENTER, "Clear");
+          if(id(alarm_status).state == "disarmed") {
+            it.printf(255, 30, id(icon_font_55), red, TextAlign::CENTER, "\U000F068A");
+            it.printf(255, 70, id(my_font3), red, TextAlign::CENTER, "Disarmed");
+          } else if(id(alarm_status).state == "arming") {
+            it.printf(255, 30, id(icon_font_55), amber, TextAlign::CENTER, "\U000F0565");
+            it.printf(255, 70, id(my_font3), amber, TextAlign::CENTER, "Arming");
+          } else if(id(alarm_status).state == "armed_home") {
+            it.printf(255, 30, id(icon_font_55), green, TextAlign::CENTER, "\U000F068A");
+            it.printf(255, 70, id(my_font3), green, TextAlign::CENTER, "Armed");
+          }
+
+      - id: alarm_away_activate_page ##### alarm away activation page #####
+        lambda: |-
+          auto pin_state = id(current_pin).c_str();
+          it.print(310, 80, id(my_font3), TextAlign::RIGHT, pin_state);
+          // loop for numbers 1 - 9
+          for (int i = 0; i < 3; i++) {
+            for (int j = 0; j < 3; j++) {
+              int number = i * 3 + j + 1;
+              int x_position = 15 + j * 56;  // Ajustement de la position en X
+              int y_position = 15 + i * 56;  // Ajustement de la position en Y
+              it.rectangle(x_position, y_position, 48, 48, light_blue);  // Taille du rectangle ajustée
+              char num_str[2];
+              snprintf(num_str, sizeof(num_str), "%d", number);
+              it.print(x_position + 24, y_position + 24, id(my_font3), TextAlign::CENTER, num_str);  // Centrage du chiffre
+            }
+          }
+          it.rectangle(71, 183, 48, 48, light_blue);  // Position et taille du rectangle ajustées
+          it.print(95, 207, id(my_font3), TextAlign::CENTER, "0");  // Centrage du chiffre "0"
+          if(id(alarm_status).state == "disarmed"){
+            it.filled_rectangle(198, 110, 108, 50, red);
+            it.print(255, 135, id(my_font3), white, TextAlign::CENTER, "Arm");
+          } else if(id(alarm_status).state == "armed_away"){
+            it.filled_rectangle(198, 110, 108, 50, green); 
+            it.print(255, 135, id(my_font3), white, TextAlign::CENTER, "Disarm");
+          }
+          it.filled_rectangle(198, 170, 108, 50, blue_drk);
+          it.print(255, 195, id(my_font3), white, TextAlign::CENTER, "Clear");
+          if(id(alarm_status).state == "disarmed") {
+            it.printf(255, 30, id(icon_font_55), red, TextAlign::CENTER, "\U000F099D");
+            it.printf(255, 70, id(my_font3), red, TextAlign::CENTER, "Disarmed");
+          } else if(id(alarm_status).state == "arming") {
+            it.printf(255, 30, id(icon_font_55), amber, TextAlign::CENTER, "\U000F0565");
+            it.printf(255, 70, id(my_font3), amber, TextAlign::CENTER, "Arming");
+          } else if(id(alarm_status).state == "armed_away") {
+            it.printf(255, 30, id(icon_font_55), green, TextAlign::CENTER, "\U000F099D");
+            it.printf(255, 70, id(my_font3), green, TextAlign::CENTER, "Armed");
+          }
+      - id: alarm_night_activate_page ##### alarm night activation page #####
+        lambda: |-
+          auto pin_state = id(current_pin).c_str();
+          it.print(310, 80, id(my_font3), TextAlign::RIGHT, pin_state);
+          // loop for numbers 1 - 9
+          for (int i = 0; i < 3; i++) {
+            for (int j = 0; j < 3; j++) {
+              int number = i * 3 + j + 1;
+              int x_position = 15 + j * 56;  // Ajustement de la position en X
+              int y_position = 15 + i * 56;  // Ajustement de la position en Y
+              it.rectangle(x_position, y_position, 48, 48, light_blue);  // Taille du rectangle ajustée
+              char num_str[2];
+              snprintf(num_str, sizeof(num_str), "%d", number);
+              it.print(x_position + 24, y_position + 24, id(my_font3), TextAlign::CENTER, num_str);  // Centrage du chiffre
+            }
+          }
+          it.rectangle(71, 183, 48, 48, light_blue);  // Position et taille du rectangle ajustées
+          it.print(95, 207, id(my_font3), TextAlign::CENTER, "0");  // Centrage du chiffre "0"
+          if(id(alarm_status).state == "disarmed"){
+            it.filled_rectangle(198, 110, 108, 50, red);
+            it.print(255, 135, id(my_font3), white, TextAlign::CENTER, "Arm");
+          } else if(id(alarm_status).state == "armed_night"){
+            it.filled_rectangle(198, 110, 108, 50, green); 
+            it.print(255, 135, id(my_font3), white, TextAlign::CENTER, "Disarm");
+          }
+          it.filled_rectangle(198, 170, 108, 50, blue_drk);
+          it.print(255, 195, id(my_font3), white, TextAlign::CENTER, "Clear");
+          if(id(alarm_status).state == "disarmed") {
+            it.printf(255, 30, id(icon_font_55), red, TextAlign::CENTER, "\U000F1828");
+            it.printf(255, 70, id(my_font3), red, TextAlign::CENTER, "Disarmed");
+          } else if(id(alarm_status).state == "arming") {
+            it.printf(255, 30, id(icon_font_55), amber, TextAlign::CENTER, "\U000F0565");
+            it.printf(255, 70, id(my_font3), amber, TextAlign::CENTER, "Arming");
+          } else if(id(alarm_status).state == "armed_night") {
+            it.printf(255, 30, id(icon_font_55), green, TextAlign::CENTER, "\U000F1828");
+            it.printf(255, 70, id(my_font3), green, TextAlign::CENTER, "Armed");
+          }
+
+      - id: notification_page
+        lambda: |-
+          it.fill(Color::BLACK);
+          const char* text = id(notification_text).state.c_str();
+          int max_chars_per_line = 14;  // Adjusted maximum characters per line
+          int line_height = 40;         // Height of each line
+          int display_width = 320;
+          int display_height = 240;
+          int y = 60;                   // Starting Y position for text
+          std::vector<std::string> lines;
+          
+          // Split text into lines of max_chars_per_line
+          std::string current_line;
+          for (const char* p = text; *p != '\0'; ++p) {
+            if (current_line.length() >= max_chars_per_line || *p == '\n') {
+              lines.push_back(current_line);
+              current_line.clear();
+              if (*p != '\n') {
+                current_line += *p;
+              }
+            } else {
+              current_line += *p;
+            }
+          }
+          if (!current_line.empty()) {
+            lines.push_back(current_line);
+          }
+      
+          // Calculate the starting Y position to center the text vertically
+          int total_height = lines.size() * line_height;
+          y = (display_height - total_height) / 2;
+
+          // Print each line centered
+          for (const auto& line : lines) {
+            int line_width = line.length() * 21; // Approximate width of the line
+            int x = (display_width - line_width) / 2;
+            it.printf(x, y, id(my_font4), Color::WHITE, TextAlign::BASELINE_LEFT, "%s", line.c_str());
+            y += line_height;
+          }
+
+i2c:
+  - id: bus_a
+    sda: GPIO08
+    scl: GPIO18
+    scan: true
+    sda_pullup_enabled: true
+    scl_pullup_enabled: true
+    frequency: 100kHz
+
+  - sda: GPIO41
+    scl: GPIO40
+    scan: true
+    sda_pullup_enabled: true
+    scl_pullup_enabled: true
+    frequency: 50kHz
+    id: bus_b
+
+touchscreen:
+  - platform: gt911
+    i2c_id: bus_a
+    address: 0x5D
+    id: gt911_touchscreen
+    interrupt_pin:
+      number: GPIO3
+      ignore_strapping_warning: true
+    on_touch:
+      - lambda: "id(led).turn_on().set_brightness(id(s_default_brightness).state /100).perform();"
+    on_release:
+      - script.execute: saver_enabled
+
+binary_sensor:
+  ###### top left hand physical button #######
+  - platform: gpio
+    id: top_left_button
+    pin:
+      number: GPIO0
+      mode: INPUT_PULLUP
+      inverted: true
+      ignore_strapping_warning: true
+    on_press:
+      - if:
+          condition:
+            - display.is_displaying_page: saver_page
+          then:
+            - lambda: "id(led).turn_on().set_brightness(id(s_default_brightness).state /100).perform();"
+            - display.page.show: idle_page
+            - script.execute: saver_enabled
+            - component.update: s3_box_lcd
+          else:
+            if:
+              condition:
+                - display.is_displaying_page: idle_page
+              then:
+                - script.execute: saver_enabled
+                - display.page.show: saver_page
+                - component.update: s3_box_lcd
+
+  ########     red circle home button   #####################
+  - platform: gt911
+    id: home_button
+    index: 0
+    on_press:
+      if:
+        condition:
+          - display.is_displaying_page: idle_page
+        then:
+          - script.execute: saver_enabled
+        else:
+          - lambda: "id(led).turn_on().set_brightness(id(s_default_brightness).state /100).perform();"
+          - display.page.show: idle_page
+          - component.update: s3_box_lcd
+
+  ###### radar sensor ########   # remove for no sensor version
+  - platform: gpio
+    pin:
+      number: GPIO21
+    name: "Presence detect"
+    disabled_by_default: false
+    device_class: "occupancy"
+    on_state:
+      if:
+        condition:
+          and:
+            - switch.is_on: s_saver
+            - switch.is_on: s_saver_presc
+            - display.is_displaying_page: saver_page
+        then:
+          - display.page.show: idle_page
+          - component.update: s3_box_lcd
+          - script.execute: saver_enabled
+
+  ##### satus bar buttons #####
+  - platform: touchscreen
+    pages:
+      - idle_page
+      - info_page
+      - lights_page
+      - template_page
+      - media_page
+      - ext_media_page
+      - scenes_page
+      - settings_page
+    id: status_bar_1
+    x_min: 5
+    x_max: 60
+    y_min: 0
+    y_max: 55
+    #### make sure that the following 4 lines are uncommented by removing the prefixed '#' ###
+    # on_click:
+    # min_length: 10ms
+    # max_length: 500ms
+    # then:
+    #### add your action here - make sure to uncomment the following  line by removing the prefixed '#' and keep these below your action #####
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - idle_page
+      - info_page
+      - lights_page
+      - template_page
+      - media_page
+      - ext_media_page
+      - scenes_page
+      - settings_page
+    id: status_bar_2
+    internal: true
+    x_min: 65
+    x_max: 125
+    y_min: 0
+    y_max: 55
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - display.page.show: wifi_page
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - idle_page
+      - info_page
+      - lights_page
+      - template_page
+      - media_page
+      - ext_media_page
+      - scenes_page
+      - settings_page
+    id: status_bar_3
+    internal: true
+    x_min: 130
+    x_max: 185
+    y_min: 0
+    y_max: 55
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        if:
+          condition:
+            - switch.is_on: timer_ringing
+          then:
+            - display.page.show: timer_finished_page
+            - component.update: s3_box_lcd
+          else:
+            - display.page.show: time_remaining_page
+            - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - idle_page
+      - info_page
+      - lights_page
+      - template_page
+      - media_page
+      - ext_media_page
+      - scenes_page
+      - settings_page
+    id: status_bar_4
+    internal: true
+    x_min: 190
+    x_max: 245
+    y_min: 0
+    y_max: 55
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - switch.toggle: mute_switch
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - idle_page
+      - info_page
+      - lights_page
+      - template_page
+      - media_page
+      - ext_media_page
+      - scenes_page
+      - settings_page
+    name: status_bar_5
+    internal: true
+    x_min: 250
+    x_max: 305
+    y_min: 0
+    y_max: 55
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - display.page.show: alarm_page
+        - component.update: s3_box_lcd
+
+  ##### settings page ####
+  - platform: touchscreen
+    page_id: settings_page
+    id: voice_set
+    internal: true
+    x_min: 5
+    x_max: 105
+    y_min: 100
+    y_max: 165
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - display.page.show: ww_set_page
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: settings_page
+    id: ss_set
+    internal: true
+    x_min: 110
+    x_max: 210
+    y_min: 100
+    y_max: 165
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - display.page.show: ss_set_page
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: settings_page
+    id: info_set
+    internal: true
+    x_min: 215
+    x_max: 315
+    y_min: 100
+    y_max: 165
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - display.page.show: info_page
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: settings_page
+    id: device_set
+    internal: true
+    x_min: 5
+    x_max: 105
+    y_min: 175
+    y_max: 240
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - display.page.show: device_set_page
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: settings_page
+    id: voice_test
+    internal: true
+    x_min: 215
+    x_max: 315
+    y_min: 175
+    y_max: 240
+    on_press:
+      then:
+        - switch.turn_on: mute_switch
+        - lambda: "id(va).set_use_wake_word(false);"
+        - delay: 100ms
+        - voice_assistant.start
+        - wait_until:
+            not:
+              - voice_assistant.is_running
+        - voice_assistant.stop
+    on_release:
+      then:
+        - switch.turn_off: mute_switch
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - device_set_page
+    id: back_button
+    internal: true
+    x_min: 5
+    x_max: 105
+    y_min: 175
+    y_max: 240
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - display.page.show: settings_page
+        - component.update: s3_box_lcd
+
+  ##### idle / home page ####
+  - platform: touchscreen
+    page_id: idle_page
+    id: control_1
+    internal: true
+    x_min: 5
+    x_max: 105
+    y_min: 90
+    y_max: 170
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - display.page.show: climate_page
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: idle_page
+    id: control_2
+    internal: true
+    x_min: 110
+    x_max: 210
+    y_min: 90
+    y_max: 170
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - display.page.show: lights_page
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: idle_page
+    id: control_3
+    internal: true
+    x_min: 215
+    x_max: 315
+    y_min: 90
+    y_max: 170
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - display.page.show: template_page
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: idle_page
+    id: control_4
+    internal: true
+    x_min: 5
+    x_max: 105
+    y_min: 175
+    y_max: 240
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        if:
+          condition:
+            switch.is_off: output_audio
+          then:
+            - display.page.show: media_page
+            - component.update: s3_box_lcd
+          else:
+            - display.page.show: ext_media_page
+            - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: idle_page
+    id: control_5
+    internal: true
+    x_min: 110
+    x_max: 210
+    y_min: 175
+    y_max: 240
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - display.page.show: scenes_page
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: idle_page
+    id: control_6
+    internal: true
+    x_min: 215
+    x_max: 315
+    y_min: 175
+    y_max: 240
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - display.page.show: settings_page
+        - component.update: s3_box_lcd
+
+  #### climate page #####
+  - platform: touchscreen
+    page_id: climate_page
+    id: climate1
+    internal: true
+    x_min: 5
+    x_max: 105
+    y_min: 90
+    y_max: 170
+    #### make sure that the following 4 lines are uncommented by removing the prefixed '#' ###
+    # on_click:
+    # min_length: 10ms
+    # max_length: 500ms
+    # then:
+    #### add your action here - make sure to uncomment the following  line by removing the prefixed '#' and keep these below your action #####
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: climate_page
+    id: climate2
+    internal: true
+    x_min: 110
+    x_max: 210
+    y_min: 90
+    y_max: 170
+    #### make sure that the following 4 lines are uncommented by removing the prefixed '#' ###
+    # on_click:
+    # min_length: 10ms
+    # max_length: 500ms
+    # then:
+    #### add your action here - make sure to uncomment the following  line by removing the prefixed '#' and keep these below your action #####
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: climate_page
+    id: climate3
+    internal: true
+    x_min: 215
+    x_max: 315
+    y_min: 90
+    y_max: 170
+    #### make sure that the following 4 lines are uncommented by removing the prefixed '#' ###
+    # on_click:
+    # min_length: 10ms
+    # max_length: 500ms
+    # then:
+    #### add your action here - make sure to uncomment the following  line by removing the prefixed '#' and keep these below your action #####
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: climate_page
+    id: climate4
+    internal: true
+    x_min: 5
+    x_max: 105
+    y_min: 175
+    y_max: 240
+    #### make sure that the following 4 lines are uncommented by removing the prefixed '#' ###
+    # on_click:
+    # min_length: 10ms
+    # max_length: 500ms
+    # then:
+    #### add your action here - make sure to uncomment the following  line by removing the prefixed '#' and keep these below your action #####
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: climate_page
+    id: climate5
+    internal: true
+    x_min: 110
+    x_max: 210
+    y_min: 175
+    y_max: 240
+    #### make sure that the following 4 lines are uncommented by removing the prefixed '#' ###
+    # on_click:
+    # min_length: 10ms
+    # max_length: 500ms
+    # then:
+    #### add your action here - make sure to uncomment the following  line by removing the prefixed '#' and keep these below your action #####
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: climate_page
+    id: climate6
+    internal: true
+    x_min: 215
+    x_max: 315
+    y_min: 175
+    y_max: 240
+    #### make sure that the following 4 lines are uncommented by removing the prefixed '#' ###
+    # on_click:
+    # min_length: 10ms
+    # max_length: 500ms
+    # then:
+    #### add your action here - make sure to uncomment the following  line by removing the prefixed '#' and keep these below your action #####
+
+    # - component.update: s3_box_lcd
+  ##### lights page #####
+  - platform: touchscreen
+    page_id: lights_page
+    id: lights1
+    internal: true
+    x_min: 5
+    x_max: 105
+    y_min: 90
+    y_max: 170
+    #### make sure that the following 4 lines are uncommented by removing the prefixed '#' ###
+    # on_click:
+    # min_length: 10ms
+    # max_length: 500ms
+    # then:
+    #### add your action here - make sure to uncomment the following  line by removing the prefixed '#' and keep these below your action #####
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: lights_page
+    id: lights2
+    internal: true
+    x_min: 110
+    x_max: 210
+    y_min: 90
+    y_max: 170
+    #### make sure that the following 4 lines are uncommented by removing the prefixed '#' ###
+    # on_click:
+    # min_length: 10ms
+    # max_length: 500ms
+    # then:
+    #### add your action here - make sure to uncomment the following  line by removing the prefixed '#' and keep these below your action #####
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: lights_page
+    id: lights3
+    internal: true
+    x_min: 215
+    x_max: 315
+    y_min: 90
+    y_max: 170
+    #### make sure that the following 4 lines are uncommented by removing the prefixed '#' ###
+    # on_click:
+    # min_length: 10ms
+    # max_length: 500ms
+    # then:
+    #### add your action here - make sure to uncomment the following  line by removing the prefixed '#' and keep these below your action #####
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: lights_page
+    id: lights4
+    internal: true
+    x_min: 5
+    x_max: 105
+    y_min: 175
+    y_max: 240
+    #### make sure that the following 4 lines are uncommented by removing the prefixed '#' ###
+    # on_click:
+    # min_length: 10ms
+    # max_length: 500ms
+    # then:
+    #### add your action here - make sure to uncomment the following  line by removing the prefixed '#' and keep these below your action #####
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: lights_page
+    id: lights5
+    internal: true
+    x_min: 110
+    x_max: 210
+    y_min: 175
+    y_max: 240
+    #### make sure that the following 4 lines are uncommented by removing the prefixed '#' ###
+    # on_click:
+    # min_length: 10ms
+    # max_length: 500ms
+    # then:
+    #### add your action here - make sure to uncomment the following  line by removing the prefixed '#' and keep these below your action #####
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: lights_page
+    id: lights6
+    internal: true
+    x_min: 215
+    x_max: 315
+    y_min: 175
+    y_max: 240
+    #### make sure that the following 4 lines are uncommented by removing the prefixed '#' ###
+    # on_click:
+    # min_length: 10ms
+    # max_length: 500ms
+    # then:
+    #### add your action here - make sure to uncomment the following  line by removing the prefixed '#' and keep these below your action #####
+    # - component.update: s3_box_lcd
+
+  ##### media player #####
+  - platform: touchscreen
+    page_id: media_page
+    name: Volume Minus
+    internal: true
+    x_min: 5
+    x_max: 105
+    y_min: 90
+    y_max: 170
+    on_click:
+      min_length: 0ms
+      max_length: 500ms
+      then:
+        - logger.log: "Volume Minus pressed"
+        - lambda: |-
+            if (id(speaker_volume) > 0) {
+              id(speaker_volume) -= 1;
+            }
+        - component.update: s3_box_lcd
+        - script.execute: set_volume
+
+  - platform: touchscreen
+    page_id: media_page
+    name: Volume Plus
+    internal: true
+    x_min: 215
+    x_max: 315
+    y_min: 90
+    y_max: 170
+    on_click:
+      min_length: 0ms
+      max_length: 500ms
+      then:
+        - logger.log: "Volume Plus pressed"
+        - lambda: |-
+            if (id(speaker_volume) < 10) {
+              id(speaker_volume) += 1;
+            }
+        - component.update: s3_box_lcd
+        - script.execute: set_volume
+
+  - platform: touchscreen
+    page_id: media_page
+    name: Play Pause
+    internal: true
+    x_min: 110
+    x_max: 210
+    y_min: 90
+    y_max: 170
+    on_click:
+      min_length: 0ms
+      max_length: 500ms
+      then:
+        - if:
+            condition:
+              media_player.is_idle:
+            then:
+              - media_player.play
+            else:
+              - media_player.stop
+        - logger.log: "Play Paused pressed"
+
+  - platform: touchscreen
+    page_id: media_page
+    name: Mute Media
+    internal: true
+    x_min: 110
+    x_max: 210
+    y_min: 180
+    y_max: 260
+    on_click:
+      min_length: 0ms
+      max_length: 500ms
+      then:
+        - switch.toggle: media_mute
+        - component.update: s3_box_lcd
+
+  #### external media ####
+  - platform: touchscreen
+    page_id: ext_media_page
+    id: ext_prev_track
+    internal: true
+    x_min: 5
+    x_max: 105
+    y_min: 90
+    y_max: 170
+    on_click:
+      min_length: 0ms
+      max_length: 500ms
+      then:
+        - homeassistant.service:
+            service: media_player.media_previous_track
+            data:
+              entity_id: media_player.${external_media_player}
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: ext_media_page
+    id: ext_next_track
+    internal: true
+    x_min: 215
+    x_max: 315
+    y_min: 90
+    y_max: 170
+    on_click:
+      min_length: 0ms
+      max_length: 500ms
+      then:
+        - homeassistant.service:
+            service: media_player.media_next_track
+            data:
+              entity_id: media_player.${external_media_player}
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: ext_media_page
+    name: Play Pause
+    internal: true
+    x_min: 110
+    x_max: 210
+    y_min: 90
+    y_max: 170
+    on_click:
+      min_length: 0ms
+      max_length: 500ms
+      then:
+        - homeassistant.service:
+            service: media_player.media_pause
+            data:
+              entity_id: media_player.${external_media_player}
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: ext_media_page
+    name: Mute Media
+    internal: true
+    x_min: 110
+    x_max: 210
+    y_min: 180
+    y_max: 260
+    on_click:
+      min_length: 0ms
+      max_length: 500ms
+      then:
+        - switch.toggle: ext_media_mute
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: ext_media_page
+    id: vol_minus
+    internal: true
+    x_min: 5
+    x_max: 105
+    y_min: 180
+    y_max: 260
+    on_click:
+      min_length: 0ms
+      max_length: 500ms
+      then:
+        - homeassistant.service:
+            service: media_player.volume_down
+            data:
+              entity_id: media_player.${external_media_player}
+        - component.update: s3_box_lcd
+        - script.execute: set_volume
+
+  - platform: touchscreen
+    page_id: ext_media_page
+    id: vol_plus
+    internal: true
+    x_min: 215
+    x_max: 315
+    y_min: 180
+    y_max: 260
+    on_click:
+      min_length: 0ms
+      max_length: 500ms
+      then:
+        - homeassistant.service:
+            service: media_player.volume_up
+            data:
+              entity_id: media_player.${external_media_player}
+        - component.update: s3_box_lcd
+        - script.execute: set_volume
+
+  ##### scenes page ####
+  - platform: touchscreen
+    page_id: scenes_page
+    id: scenes1
+    internal: true
+    x_min: 5
+    x_max: 105
+    y_min: 90
+    y_max: 170
+    #### make sure that the following 4 lines are uncommented by removing the prefixed '#' ###
+    # on_click:
+    # min_length: 10ms
+    # max_length: 500ms
+    # then:
+    #### add your action here - make sure to uncomment the following  line by removing the prefixed '#' and keep these below your action #####
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: scenes_page
+    id: scenes2
+    internal: true
+    x_min: 110
+    x_max: 210
+    y_min: 90
+    y_max: 170
+    # on_click:
+    #   min_length: 10ms
+    #   max_length: 500ms
+    #### make sure that the following  line are uncommented and sit at the bottom of this block after your action ###
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: scenes_page
+    id: scenes3
+    internal: true
+    x_min: 215
+    x_max: 315
+    y_min: 90
+    y_max: 170
+    # on_click:
+    #   min_length: 10ms
+    #   max_length: 500ms
+    #### make sure that the following  line are uncommented and sit at the bottom of this block after your action ###
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: scenes_page
+    id: scenes4
+    internal: true
+    x_min: 5
+    x_max: 105
+    y_min: 175
+    y_max: 240
+    # on_click:
+    #   min_length: 10ms
+    #   max_length: 500ms
+    #### make sure that the following  line are uncommented and sit at the bottom of this block after your action ###
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: scenes_page
+    id: scenes5
+    internal: true
+    x_min: 110
+    x_max: 210
+    y_min: 175
+    y_max: 240
+    # on_click:
+    #   min_length: 10ms
+    #   max_length: 500ms
+    #### make sure that the following  line are uncommented and sit at the bottom of this block after your action ###
+    # - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: scenes_page
+    id: scenes6
+    internal: true
+    x_min: 215
+    x_max: 315
+    y_min: 175
+    y_max: 240
+    # on_click:
+    #   min_length: 10ms
+    #   max_length: 500ms
+    #### make sure that the following  line are uncommented and sit at the bottom of this block after your action ###
+    # - component.update: s3_box_lcd
+
+  ##### Screensaver Settings #####
+  - platform: touchscreen
+    page_id: ss_set_page
+    id: ss_timeout
+    internal: true
+    x_min: 250
+    x_max: 315
+    y_min: 115
+    y_max: 145
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - display.page.show: timeout_settings_page
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: ss_set_page
+    id: ss_toggle
+    internal: true
+    x_min: 250
+    x_max: 315
+    y_min: 150
+    y_max: 175
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - switch.toggle: s_saver
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen # remove for no sensor version
+    page_id: ss_set_page
+    id: ss_wake_presc
+    internal: true
+    x_min: 250
+    x_max: 315
+    y_min: 180
+    y_max: 205
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - switch.toggle: s_saver_presc
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: ss_set_page
+    id: ss_toggle_blank
+    internal: true
+    x_min: 250
+    x_max: 315
+    y_min: 210
+    y_max: 235
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - switch.toggle: s_saver_mode
+        - component.update: s3_box_lcd
+
+  ##### voice settings page #####
+  - platform: touchscreen
+    page_id: ww_set_page
+    id: ww_chang_hass
+    internal: true
+    x_min: 10
+    x_max: 315
+    y_min: 100
+    y_max: 135
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - select.operation:
+            id: wake_word_engine_location
+            operation: Next
+            cycle: true
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: ww_set_page
+    id: mute_response
+    internal: true
+    x_min: 250
+    x_max: 315
+    y_min: 145
+    y_max: 170
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - switch.toggle: mute_response_switch
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: ww_set_page
+    id: ww_wake_sound
+    internal: true
+    x_min: 250
+    x_max: 315
+    y_min: 180
+    y_max: 205
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - switch.toggle: wake_sound
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: ww_set_page
+    id: ww_toggle_conv
+    internal: true
+    x_min: 250
+    x_max: 315
+    y_min: 210
+    y_max: 235
+    on_click:
+      - switch.toggle: display_conversation
+      - component.update: s3_box_lcd
+
+  ##### touch to wake screen #####
+  - platform: touchscreen
+    page_id: saver_page
+    id: ss_wake
+    internal: true
+    x_min: 0
+    x_max: 320
+    y_min: 0
+    y_max: 240
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - display.page.show: idle_page
+        - component.update: s3_box_lcd
+
+  ##### Timer finished page #####
+  - platform: touchscreen
+    page_id: timer_finished_page
+    id: timer_dismiss
+    internal: true
+    x_min: 0
+    x_max: 320
+    y_min: 0
+    y_max: 240
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - switch.turn_off: timer_ringing
+        - display.page.show: idle_page
+        - component.update: s3_box_lcd
+
+  ##### Timeout settings buttons #####
+  - id: ss_sleep_down
+    page_id: timeout_settings_page
+    platform: touchscreen
+    internal: true
+    x_min: 25
+    x_max: 60
+    y_min: 105
+    y_max: 140
+    on_press:
+      then:
+        - lambda: |-
+            int sleep = id(s_saver_delay).state - 5;
+            if (sleep < 1) {
+              sleep = 1;
+            }
+            auto call = id(s_saver_delay).make_call();
+            call.set_value(sleep);
+            call.perform();
+        - component.update: s3_box_lcd
+
+  - id: ss_sleep_up
+    page_id: timeout_settings_page
+    platform: touchscreen
+    internal: true
+    x_min: 110
+    x_max: 145
+    y_min: 105
+    y_max: 140
+    on_press:
+      then:
+        - lambda: |-
+            int sleep = id(s_saver_delay).state + 5;
+            auto call = id(s_saver_delay).make_call();
+            call.set_value(sleep);
+            call.perform();
+        - component.update: s3_box_lcd
+
+  - id: ss_blank_down
+    page_id: timeout_settings_page
+    platform: touchscreen
+    internal: true
+    x_min: 25
+    x_max: 60
+    y_min: 180
+    y_max: 220
+    on_press:
+      then:
+        - lambda: |-
+            int sleep = id(s_saver_blank_delay).state - 5;
+            if (sleep < 1) {
+              sleep = 1;
+            }
+            auto call = id(s_saver_blank_delay).make_call();
+            call.set_value(sleep);
+            call.perform();
+        - component.update: s3_box_lcd
+
+  - id: ss_blank_up
+    page_id: timeout_settings_page
+    platform: touchscreen
+    internal: true
+    x_min: 110
+    x_max: 145
+    y_min: 180
+    y_max: 220
+    on_press:
+      then:
+        - lambda: |-
+            int sleep = id(s_saver_blank_delay).state + 5;
+            auto call = id(s_saver_blank_delay).make_call();
+            call.set_value(sleep);
+            call.perform();
+        - component.update: s3_box_lcd
+
+  - id: ss_bright_down
+    page_id: timeout_settings_page
+    platform: touchscreen
+    internal: true
+    x_min: 165
+    x_max: 195
+    y_min: 105
+    y_max: 140
+    on_press:
+      then:
+        - lambda: |-
+            int bright = id(s_saver_brightness).state - 5;
+            if (bright < 1) {
+              bright = 1;
+            }
+            auto call = id(s_saver_brightness).make_call();
+            call.set_value(bright);
+            call.perform();
+        - component.update: s3_box_lcd
+
+  - id: ss_bright_up
+    page_id: timeout_settings_page
+    platform: touchscreen
+    internal: true
+    x_min: 260
+    x_max: 295
+    y_min: 105
+    y_max: 140
+    on_press:
+      then:
+        - lambda: |-
+            int bright = id(s_saver_brightness).state + 5;
+            auto call = id(s_saver_brightness).make_call();
+            call.set_value(bright);
+            call.perform();
+        - component.update: s3_box_lcd
+
+  ##### device settings page #####
+  - id: s_default_bright_down
+    page_id: device_set_page
+    platform: touchscreen
+    internal: true
+    x_min: 280
+    x_max: 320
+    y_min: 125
+    y_max: 165
+    on_press:
+      then:
+        - lambda: |-
+            int default_bright = id(s_default_brightness).state - 5;
+            if (default_bright < 1) {
+              default_bright = 1;
+            }
+            auto call = id(s_default_brightness).make_call();
+            call.set_value(default_bright);
+            call.perform();
+        - component.update: s3_box_lcd
+
+  - id: s_default_bright_up
+    page_id: device_set_page
+    platform: touchscreen
+    internal: true
+    x_min: 155
+    x_max: 195
+    y_min: 125
+    y_max: 165
+    on_press:
+      then:
+        - lambda: |-
+            int default_bright = id(s_default_brightness).state + 5;
+            auto call = id(s_default_brightness).make_call();
+            call.set_value(default_bright);
+            call.perform();
+        - component.update: s3_box_lcd
+
+  - id: ext_media_toggle
+    page_id: device_set_page
+    platform: touchscreen
+    internal: true
+    x_min: 280
+    x_max: 320
+    y_min: 80
+    y_max: 120
+    on_press:
+      then:
+        - switch.toggle: output_audio
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: device_set_page
+    id: chang_display_format
+    x_min: 200
+    x_max: 260
+    y_min: 175
+    y_max: 210
+    on_click:
+      min_length: 10ms
+      max_length: 500ms
+      then:
+        - select.operation:
+            id: time_format
+            operation: Next
+            cycle: true
+        - component.update: s3_box_lcd
+
+  ##### alarm panel buttons #####
+  - platform: touchscreen
+    pages:
+      - alarm_away_activate_page
+      - alarm_home_activate_page
+      - alarm_night_activate_page
+    id: alarm_key_1
+    internal: true
+    x_min: 15
+    x_max: 63
+    y_min: 15
+    y_max: 63
+    on_press:
+      - script.execute: increment_digit_1
+      - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - alarm_away_activate_page
+      - alarm_home_activate_page
+      - alarm_night_activate_page
+    id: alarm_key_2
+    internal: true
+    x_min: 71
+    x_max: 119
+    y_min: 15
+    y_max: 63
+    on_press:
+      - script.execute: increment_digit_2
+      - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - alarm_away_activate_page
+      - alarm_home_activate_page
+      - alarm_night_activate_page
+    id: alarm_key_3
+    internal: true
+    x_min: 127
+    x_max: 175
+    y_min: 15
+    y_max: 63
+    on_press:
+      - script.execute: increment_digit_3
+      - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - alarm_away_activate_page
+      - alarm_home_activate_page
+      - alarm_night_activate_page
+    id: alarm_key_4
+    internal: true
+    x_min: 15
+    x_max: 63
+    y_min: 71
+    y_max: 119
+    on_press:
+      - script.execute: increment_digit_4
+      - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - alarm_away_activate_page
+      - alarm_home_activate_page
+      - alarm_night_activate_page
+    id: alarm_key_5
+    internal: true
+    x_min: 71
+    x_max: 119
+    y_min: 71
+    y_max: 119
+    on_press:
+      - script.execute: increment_digit_5
+      - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - alarm_away_activate_page
+      - alarm_home_activate_page
+      - alarm_night_activate_page
+    id: alarm_key_6
+    internal: true
+    x_min: 127
+    x_max: 175
+    y_min: 71
+    y_max: 119
+    on_press:
+      - script.execute: increment_digit_6
+      - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - alarm_away_activate_page
+      - alarm_home_activate_page
+      - alarm_night_activate_page
+    id: alarm_key_7
+    internal: true
+    x_min: 15
+    x_max: 63
+    y_min: 127
+    y_max: 175
+    on_press:
+      - script.execute: increment_digit_7
+      - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - alarm_away_activate_page
+      - alarm_home_activate_page
+      - alarm_night_activate_page
+    id: alarm_key_8
+    internal: true
+    x_min: 71
+    x_max: 119
+    y_min: 127
+    y_max: 175
+    on_press:
+      - script.execute: increment_digit_8
+      - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - alarm_away_activate_page
+      - alarm_home_activate_page
+      - alarm_night_activate_page
+    id: alarm_key_9
+    internal: true
+    x_min: 127
+    x_max: 175
+    y_min: 127
+    y_max: 175
+    on_press:
+      - script.execute: increment_digit_9
+      - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - alarm_away_activate_page
+      - alarm_home_activate_page
+      - alarm_night_activate_page
+    id: alarm_key_0
+    internal: true
+    x_min: 71
+    x_max: 119
+    y_min: 183
+    y_max: 231
+    on_press:
+      - media_player.play_media:
+          media_url: "${home_assistant_host}/local/sounds/key.mp3"
+      - script.execute: increment_digit_0
+      - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - alarm_away_activate_page
+      - alarm_home_activate_page
+      - alarm_night_activate_page
+    id: clear_pin
+    x_min: 198
+    x_max: 306
+    y_min: 170
+    y_max: 220
+    on_press:
+      then:
+        - lambda: |-
+            id(current_pin) = "";
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    pages:
+      - alarm_away_activate_page
+      - alarm_home_activate_page
+      - alarm_night_activate_page
+    id: alarm_ok
+    x_min: 198
+    x_max: 306
+    y_min: 110
+    y_max: 160
+    on_click:
+      min_length: 0ms
+      max_length: 500ms
+      then:
+        - if:
+            condition:
+              - lambda: |-
+                  return (id(alarm_status).state == "arming" || id(alarm_status).state == "armed_away" || id(alarm_status).state == "armed_home" || id(alarm_status).state == "armed_night");
+            then:
+              - homeassistant.service:
+                  service: alarm_control_panel.alarm_disarm
+                  data:
+                    entity_id: alarm_control_panel.alarmo
+                    code: !lambda "return id(current_pin).c_str();"
+              - lambda: |-
+                  id(current_pin) = "";
+            else:
+              - if:
+                  condition:
+                    and:
+                      - lambda: |-
+                          return (id(alarm_status).state == "disarmed");
+                      - display.is_displaying_page: alarm_home_activate_page
+                  then:
+                    - homeassistant.service:
+                        service: alarm_control_panel.alarm_arm_home
+                        data:
+                          entity_id: alarm_control_panel.alarmo
+                          code: !lambda "return id(current_pin).c_str();"
+                    - lambda: |-
+                        id(current_pin) = "";
+                  else:
+                    - if:
+                        condition:
+                          and:
+                            - lambda: |-
+                                return (id(alarm_status).state == "disarmed");
+
+                            - display.is_displaying_page: alarm_away_activate_page
+                        then:
+                          - homeassistant.service:
+                              service: alarm_control_panel.alarm_arm_away
+                              data:
+                                entity_id: alarm_control_panel.alarmo
+                                code: !lambda "return id(current_pin).c_str();"
+                          - lambda: |-
+                              id(current_pin) = "";
+
+                        else:
+                          - if:
+                              condition:
+                                and:
+                                  - lambda: |-
+                                      return (id(alarm_status).state == "disarmed");
+                                  - display.is_displaying_page: alarm_night_activate_page
+                              then:
+                                - homeassistant.service:
+                                    service: alarm_control_panel.alarm_arm_night
+                                    data:
+                                      entity_id: alarm_control_panel.alarmo
+                                      code: !lambda "return id(current_pin).c_str();"
+                                - lambda: |-
+                                    id(current_pin) = "";
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: alarm_page
+    id: arm_disarm_home
+    x_min: 215
+    x_max: 320
+    y_min: 5
+    y_max: 75
+    on_click:
+      min_length: 0ms
+      max_length: 500ms
+      then:
+        - display.page.show: alarm_home_activate_page
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: alarm_page
+    id: arm_disarm_away
+    x_min: 215
+    x_max: 320
+    y_min: 80
+    y_max: 150
+    on_click:
+      min_length: 0ms
+      max_length: 500ms
+      then:
+        - display.page.show: alarm_away_activate_page
+        - component.update: s3_box_lcd
+
+  - platform: touchscreen
+    page_id: alarm_page
+    id: arm_disarm_night
+    x_min: 215
+    x_max: 320
+    y_min: 155
+    y_max: 240
+    on_click:
+      min_length: 0ms
+      max_length: 500ms
+      then:
+        - display.page.show: alarm_night_activate_page
+        - component.update: s3_box_lcd
+################## config end ############################

BIN
image/63c8b8518a12b7afc55e27fa7606a5e9/original.jpg


BIN
image/9cc0353522d83d018c0c6af5a7d690c7/original.jpg


File diff suppressed because it is too large
+ 0 - 0
www/community/lovelace-mushroom/mushroom.js


BIN
www/community/lovelace-mushroom/mushroom.js.gz


BIN
www/favicons/electric-violet/android-chrome-192x192.png


BIN
www/favicons/electric-violet/android-chrome-512x512.png


BIN
www/favicons/electric-violet/apple-touch-icon.png


BIN
www/favicons/electric-violet/electric-violet copy.png


BIN
www/favicons/electric-violet/electric-violet.png


BIN
www/favicons/electric-violet/favicon-16x16.png


BIN
www/favicons/electric-violet/favicon-32x32.png


BIN
www/favicons/electric-violet/favicon.ico


+ 1 - 0
www/favicons/electric-violet/site.webmanifest

@@ -0,0 +1 @@
+{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

BIN
www/favicons/house_icon.png


BIN
www/favicons/purple.png


BIN
www/favicons/red.png


BIN
www/favicons/trans.png


Some files were not shown because too many files changed in this diff