diff --git a/.github/workflows/validate_esphome.yml b/.github/workflows/validate_esphome.yml index 2388c43..a516df5 100644 --- a/.github/workflows/validate_esphome.yml +++ b/.github/workflows/validate_esphome.yml @@ -1,6 +1,10 @@ --- name: Validate ESPHome (Latest) +permissions: + contents: read + pull-requests: read + on: # yamllint disable-line rule:truthy workflow_dispatch: @@ -27,36 +31,234 @@ jobs: - name: Validate YAML files run: find . -name "*.yaml" -exec yamllint -c ./.rules/yamllint.yml {} + - build_basic: - name: Basic + build_ard_core: + name: Core (Arduino) + needs: code_scan runs-on: ubuntu-latest steps: - uses: actions/checkout@main - - name: Build core + - name: Build Core (Arduino) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_ard_core.yaml" + version: latest + + build_idf_core: + name: Core (IDF) + needs: code_scan + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build Core (IDF) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf_core.yaml" + version: latest + + build_idf53_core: + name: Core (IDF v5.3) + needs: code_scan + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build Core (IDF v5.3) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf53_core.yaml" + version: latest + + build_ard_basic: + name: Basic (Arduino) + needs: build_ard_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build Basic (Arduino) uses: esphome/build-action@main with: yaml-file: ".test/esphome_ard_basic.yaml" version: latest - build_bluetooth_proxy_4: - name: Bluetooth Proxy (IDF) + build_idf_basic: + name: Basic (IDF) + needs: build_idf_core runs-on: ubuntu-latest steps: - uses: actions/checkout@main - - name: Build core + - name: Build Basic (IDF) uses: esphome/build-action@main with: - yaml-file: ".test/esphome_idf_bluetooth_proxy.yaml" + yaml-file: ".test/esphome_idf_basic.yaml" version: latest - build_bluetooth_proxy_53: - name: Bluetooth Proxy (IDF v5.3) + build_idf53_basic: + name: Basic (IDF v5.3) + needs: build_idf53_core runs-on: ubuntu-latest steps: - uses: actions/checkout@main - - name: Build core + - name: Build Basic (IDF v5.3) uses: esphome/build-action@main with: - yaml-file: ".test/esphome_idf53_bluetooth_proxy.yaml" + yaml-file: ".test/esphome_idf53_basic.yaml" + version: latest + + build_ard_hw_relays: + name: HW Relays (Arduino) + needs: build_ard_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Relays (Arduino) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_ard_hw_relays.yaml" + version: latest + + build_idf_hw_relays: + name: HW Relays (IDF) + needs: build_idf_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Relays (IDF) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf_hw_relays.yaml" + version: latest + + build_idf53_hw_relays: + name: HW Relays (IDF v5.3) + needs: build_idf53_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Relays (IDF v5.3) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf53_hw_relays.yaml" + version: latest + + build_ard_hw_speaker: + name: HW Speaker (Arduino) + needs: build_ard_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Speaker (Arduino) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_ard_hw_speaker.yaml" + version: latest + + build_idf_hw_speaker: + name: HW Speaker (IDF) + needs: build_idf_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Speaker (IDF) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf_hw_speaker.yaml" + version: latest + + build_idf53_hw_speaker: + name: HW Speaker (IDF v5.3) + needs: build_idf53_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Speaker (IDF v5.3) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf53_hw_speaker.yaml" + version: latest + + build_ard_hw_vibration: + name: HW Vibration (Arduino) + needs: build_ard_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Vibration (Arduino) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_ard_hw_vibration.yaml" + version: latest + + build_idf_hw_vibration: + name: HW Vibration (IDF) + needs: build_idf_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Vibration (IDF) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf_hw_vibration.yaml" + version: latest + + build_idf53_hw_vibration: + name: HW Vibration (IDF v5.3) + needs: build_idf53_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Vibration (IDF v5.3) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf53_hw_vibration.yaml" + version: latest + + build_ard_ble_proxy: + name: Bluetooth Proxy (Ard) + needs: build_ard_basic + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build BLE Proxy (Ard) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_ard_ble_proxy.yaml" + version: latest + + build_idf_ble_proxy: + name: Bluetooth Proxy (IDF) + needs: build_idf_basic + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build BLE Proxy (IDF) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf_ble_proxy.yaml" + version: latest + + build_idf53_ble_proxy: + name: Bluetooth Proxy (IDF v5.3) + needs: build_idf53_basic + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build BLE Proxy (IDF v5.3) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf53_ble_proxy.yaml" + version: latest + + build_ard_media_player: + name: Media Player (Ard) + needs: + - build_ard_basic + - build_ard_hw_relays + - build_ard_hw_vibration + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build Media Player (Ard) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_ard_media_player.yaml" version: latest ... diff --git a/.github/workflows/validate_esphome_beta.yml b/.github/workflows/validate_esphome_beta.yml index 917dedb..dedada4 100644 --- a/.github/workflows/validate_esphome_beta.yml +++ b/.github/workflows/validate_esphome_beta.yml @@ -1,27 +1,29 @@ --- name: Validate ESPHome (Beta) +permissions: + contents: read + pull-requests: read + on: # yamllint disable-line rule:truthy push: paths: - - "*.yaml" - - "ESPHome/*.yaml" - - ".test/*.yaml" - - "*.h" - - "*.c" - - "*.cpp" - - "*.py" - branches: - - main + - "**/*.yml" + - "**/*.yaml" + - "**/*.h" + - "**/*.cpp" + - "**/*.c" + - "**/*.py" + pull_request: paths: - - "*.yaml" - - "ESPHome/*.yaml" - - ".test/*.yaml" - - "*.h" - - "*.c" - - "*.cpp" - - "*.py" + - "**/*.yml" + - "**/*.yaml" + - "**/*.h" + - "**/*.cpp" + - "**/*.c" + - "**/*.py" + workflow_dispatch: concurrency: @@ -47,36 +49,234 @@ jobs: - name: Validate YAML files run: find . -name "*.yaml" -exec yamllint -c ./.rules/yamllint.yml {} + - build_basic: - name: Basic + build_ard_core: + name: Core (Arduino) + needs: code_scan runs-on: ubuntu-latest steps: - uses: actions/checkout@main - - name: Build core + - name: Build Core (Arduino) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_ard_core.yaml" + version: beta + + build_idf_core: + name: Core (IDF) + needs: code_scan + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build Core (IDF) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf_core.yaml" + version: beta + + build_idf53_core: + name: Core (IDF v5.3) + needs: code_scan + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build Core (IDF v5.3) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf53_core.yaml" + version: beta + + build_ard_basic: + name: Basic (Arduino) + needs: build_ard_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build Basic (Arduino) uses: esphome/build-action@main with: yaml-file: ".test/esphome_ard_basic.yaml" version: beta - build_bluetooth_proxy_4: - name: Bluetooth Proxy (IDF) + build_idf_basic: + name: Basic (IDF) + needs: build_idf_core runs-on: ubuntu-latest steps: - uses: actions/checkout@main - - name: Build core + - name: Build Basic (IDF) uses: esphome/build-action@main with: - yaml-file: ".test/esphome_idf_bluetooth_proxy.yaml" + yaml-file: ".test/esphome_idf_basic.yaml" version: beta - build_bluetooth_proxy_53: - name: Bluetooth Proxy (IDF v5.3) + build_idf53_basic: + name: Basic (IDF v5.3) + needs: build_idf53_core runs-on: ubuntu-latest steps: - uses: actions/checkout@main - - name: Build core + - name: Build Basic (IDF v5.3) uses: esphome/build-action@main with: - yaml-file: ".test/esphome_idf53_bluetooth_proxy.yaml" + yaml-file: ".test/esphome_idf53_basic.yaml" + version: beta + + build_ard_hw_relays: + name: HW Relays (Arduino) + needs: build_ard_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Relays (Arduino) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_ard_hw_relays.yaml" + version: beta + + build_idf_hw_relays: + name: HW Relays (IDF) + needs: build_idf_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Relays (IDF) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf_hw_relays.yaml" + version: beta + + build_idf53_hw_relays: + name: HW Relays (IDF v5.3) + needs: build_idf53_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Relays (IDF v5.3) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf53_hw_relays.yaml" + version: beta + + build_ard_hw_speaker: + name: HW Speaker (Arduino) + needs: build_ard_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Speaker (Arduino) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_ard_hw_speaker.yaml" + version: beta + + build_idf_hw_speaker: + name: HW Speaker (IDF) + needs: build_idf_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Speaker (IDF) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf_hw_speaker.yaml" + version: beta + + build_idf53_hw_speaker: + name: HW Speaker (IDF v5.3) + needs: build_idf53_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Speaker (IDF v5.3) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf53_hw_speaker.yaml" + version: beta + + build_ard_hw_vibration: + name: HW Vibration (Arduino) + needs: build_ard_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Vibration (Arduino) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_ard_hw_vibration.yaml" + version: beta + + build_idf_hw_vibration: + name: HW Vibration (IDF) + needs: build_idf_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Vibration (IDF) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf_hw_vibration.yaml" + version: beta + + build_idf53_hw_vibration: + name: HW Vibration (IDF v5.3) + needs: build_idf53_core + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build HW Vibration (IDF v5.3) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf53_hw_vibration.yaml" + version: beta + + build_ard_ble_proxy: + name: Bluetooth Proxy (Ard) + needs: build_ard_basic + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build BLE Proxy (Ard) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_ard_ble_proxy.yaml" + version: beta + + build_idf_ble_proxy: + name: Bluetooth Proxy (IDF) + needs: build_idf_basic + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build BLE Proxy (IDF) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf_ble_proxy.yaml" + version: beta + + build_idf53_ble_proxy: + name: Bluetooth Proxy (IDF v5.3) + needs: build_idf53_basic + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build BLE Proxy (IDF v5.3) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_idf53_ble_proxy.yaml" + version: beta + + build_ard_media_player: + name: Media Player (Ard) + needs: + - build_ard_basic + - build_ard_hw_relays + - build_ard_hw_vibration + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - name: Build Media Player (Ard) + uses: esphome/build-action@main + with: + yaml-file: ".test/esphome_ard_media_player.yaml" version: beta ... diff --git a/.github/workflows/validate_markdown.yml b/.github/workflows/validate_markdown.yml index 1991d59..e72179a 100644 --- a/.github/workflows/validate_markdown.yml +++ b/.github/workflows/validate_markdown.yml @@ -17,23 +17,28 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@main + uses: actions/checkout@v4 with: - fetch-depth: '0' + fetch-depth: 0 # Ensures full commit history for diff - # https://github.com/marketplace/actions/markdownlint-cli2-action - name: Identify changed files - uses: tj-actions/changed-files@v41 id: changed-files - with: - files: '**/*.md' - separator: "," - # https://github.com/marketplace/actions/markdownlint-cli2-action + run: | + BASE=${{ github.event.before }} + HEAD=${{ github.sha }} + FILES=$(git diff --name-only $BASE $HEAD -- '**/*.md' | tr '\n' ',') + echo "changed_files=$FILES" >> $GITHUB_ENV + if [[ -n "$FILES" ]]; then + echo "any_changed=true" >> $GITHUB_ENV + else + echo "any_changed=false" >> $GITHUB_ENV + fi + - name: Markdown Lint uses: DavidAnson/markdownlint-cli2-action@v14 - if: steps.changed-files.outputs.any_changed == 'true' + if: env.any_changed == 'true' with: - globs: ${{ steps.changed-files.outputs.all_changed_files }} + globs: ${{ env.changed_files }} separator: "," config: '.rules/.markdownlint.jsonc' fix: true @@ -43,15 +48,27 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@main + uses: actions/checkout@v4 with: - fetch-depth: '0' + fetch-depth: 0 + + - name: Identify changed files + id: changed-files + run: | + BASE=${{ github.event.before }} + HEAD=${{ github.sha }} + FILES=$(git diff --name-only $BASE $HEAD -- '**/*.md' | tr '\n' ',') + echo "changed_files=$FILES" >> $GITHUB_ENV + if [[ -n "$FILES" ]]; then + echo "any_changed=true" >> $GITHUB_ENV + else + echo "any_changed=false" >> $GITHUB_ENV + fi - # https://github.com/gaurav-nelson/github-action-markdown-link-check - name: Markdown links uses: gaurav-nelson/github-action-markdown-link-check@v1 + if: env.any_changed == 'true' with: - # yamllint disable-line rule:truthy check-modified-files-only: yes config-file: '.rules/mlc_config.json' base-branch: 'main' diff --git a/.github/workflows/validate_yamllint.yml b/.github/workflows/validate_yamllint.yml index 87a2c71..cf129a5 100644 --- a/.github/workflows/validate_yamllint.yml +++ b/.github/workflows/validate_yamllint.yml @@ -19,24 +19,29 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@main + uses: actions/checkout@v4 with: - fetch-depth: '0' + fetch-depth: 0 # Ensures full commit history for diff - name: Identify changed files - uses: tj-actions/changed-files@v41 id: changed-files - with: - files: '**/*.y*ml' - separator: "," + run: | + BASE=${{ github.event.before }} + HEAD=${{ github.sha }} + FILES=$(git diff --name-only $BASE $HEAD -- '**/*.yml' '**/*.yaml' | tr '\n' ',') + echo "changed_files=$FILES" >> $GITHUB_ENV + if [[ -n "$FILES" ]]; then + echo "any_changed=true" >> $GITHUB_ENV + else + echo "any_changed=false" >> $GITHUB_ENV + fi - name: Validate YAML - if: steps.changed-files.outputs.any_changed == 'true' + if: env.any_changed == 'true' run: | - IFS=',' read -ra FILES <<< "${{ steps.changed-files.outputs.all_changed_files }}" + IFS=',' read -ra FILES <<< "${{ env.changed_files }}" for file in "${FILES[@]}"; do - if [[ "$file" =~ ^*\.yaml$ ]] || \ - [[ "$file" =~ ^ESPHome/*\.yaml$ ]]; then + if [[ "$file" =~ ^.*\.yaml$ ]] || [[ "$file" =~ ^ESPHome/.*\.yaml$ ]]; then echo "Skipping $file" continue fi diff --git a/.github/workflows/versioning.yml b/.github/workflows/versioning.yml index 31a94d5..ea3c246 100644 --- a/.github/workflows/versioning.yml +++ b/.github/workflows/versioning.yml @@ -4,7 +4,6 @@ # 2. Manual dispatch - allows independent control over stable and latest tags --- - name: Version and Tags on: # yamllint disable-line rule:truthy @@ -56,10 +55,9 @@ jobs: - name: Update stable tag if: | - success() && ( - github.event_name == 'workflow_dispatch' && inputs.update_stable || - github.event_name == 'push' - ) + success() && + github.event_name == 'workflow_dispatch' && + inputs.update_stable run: | # Verify version bump was successful if [ ! -f "./versioning/VERSION" ]; then diff --git a/.test/common.yaml b/.test/common.yaml new file mode 100644 index 0000000..ef08688 --- /dev/null +++ b/.test/common.yaml @@ -0,0 +1,5 @@ +--- +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password +... diff --git a/.test/common_ard.yaml b/.test/common_ard.yaml new file mode 100644 index 0000000..fbd0402 --- /dev/null +++ b/.test/common_ard.yaml @@ -0,0 +1,8 @@ +--- +packages: + common: !include common.yaml + +esp32: + framework: + type: arduino +... diff --git a/.test/common_idf.yaml b/.test/common_idf.yaml new file mode 100644 index 0000000..fb9297c --- /dev/null +++ b/.test/common_idf.yaml @@ -0,0 +1,19 @@ +--- +packages: + common: !include common.yaml + +esp32: + framework: + type: esp-idf + +light: + - id: !extend light_full + platform: esp32_rmt_led_strip + rgb_order: GRB + rmt_channel: 1 + chipset: ws2812 + max_refresh_rate: 33ms + use_psram: false + type: !remove + variant: !remove +... diff --git a/.test/common_idf53.yaml b/.test/common_idf53.yaml new file mode 100644 index 0000000..f2b9b5d --- /dev/null +++ b/.test/common_idf53.yaml @@ -0,0 +1,10 @@ +--- +packages: + common_idf: !include common_idf.yaml + +esp32: + framework: + type: esp-idf + version: 5.3.1 + platform_version: 6.9.0 +... diff --git a/.test/esphome_ard_basic.yaml b/.test/esphome_ard_basic.yaml index ed32a8f..505acee 100644 --- a/.test/esphome_ard_basic.yaml +++ b/.test/esphome_ard_basic.yaml @@ -1,8 +1,6 @@ --- packages: - basic_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml # Basic package - -esp32: - framework: - type: arduino + common_arduino: !include common_ard.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard.yaml ... diff --git a/.test/esphome_ard_ble_proxy.yaml b/.test/esphome_ard_ble_proxy.yaml new file mode 100644 index 0000000..097e273 --- /dev/null +++ b/.test/esphome_ard_ble_proxy.yaml @@ -0,0 +1,7 @@ +--- +packages: + common_arduino: !include common_ard.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard.yaml + addon_bluetooth_proxy: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml +... diff --git a/.test/esphome_ard_core.yaml b/.test/esphome_ard_core.yaml new file mode 100644 index 0000000..6b9bdba --- /dev/null +++ b/.test/esphome_ard_core.yaml @@ -0,0 +1,5 @@ +--- +packages: + common_arduino: !include common_ard.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml +... diff --git a/.test/esphome_ard_hw_relays.yaml b/.test/esphome_ard_hw_relays.yaml new file mode 100644 index 0000000..b12f6fe --- /dev/null +++ b/.test/esphome_ard_hw_relays.yaml @@ -0,0 +1,6 @@ +--- +packages: + common_arduino: !include common_ard.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_hw_relays_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_relays.yaml +... diff --git a/.test/esphome_ard_hw_speaker.yaml b/.test/esphome_ard_hw_speaker.yaml new file mode 100644 index 0000000..e054db8 --- /dev/null +++ b/.test/esphome_ard_hw_speaker.yaml @@ -0,0 +1,6 @@ +--- +packages: + common_arduino: !include common_ard.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_hw_speaker_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_speaker.yaml +... diff --git a/.test/esphome_ard_hw_vibration.yaml b/.test/esphome_ard_hw_vibration.yaml new file mode 100644 index 0000000..b0f06f6 --- /dev/null +++ b/.test/esphome_ard_hw_vibration.yaml @@ -0,0 +1,6 @@ +--- +packages: + common_arduino: !include common_ard.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_hw_vibration_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_vibration.yaml +... diff --git a/.test/esphome_ard_media_player.yaml b/.test/esphome_ard_media_player.yaml new file mode 100644 index 0000000..f12a529 --- /dev/null +++ b/.test/esphome_ard_media_player.yaml @@ -0,0 +1,8 @@ +--- +packages: + common_arduino: !include common_ard.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_hw_relays_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_relays.yaml + standard_hw_vibration_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_vibration.yaml + addon_media_player: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_addon_media_player.yaml +... diff --git a/.test/esphome_idf53_basic.yaml b/.test/esphome_idf53_basic.yaml new file mode 100644 index 0000000..10024d4 --- /dev/null +++ b/.test/esphome_idf53_basic.yaml @@ -0,0 +1,11 @@ +--- +packages: + common_idf53: !include common_idf53.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard.yaml + +media_player: !remove + +switch: + - id: !remove sw_speaker_amplifier +... diff --git a/.test/esphome_idf53_bluetooth_proxy.yaml b/.test/esphome_idf53_ble_proxy.yaml similarity index 70% rename from .test/esphome_idf53_bluetooth_proxy.yaml rename to .test/esphome_idf53_ble_proxy.yaml index a8d3868..5acf57b 100644 --- a/.test/esphome_idf53_bluetooth_proxy.yaml +++ b/.test/esphome_idf53_ble_proxy.yaml @@ -1,6 +1,8 @@ --- packages: + common: !include common.yaml core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard.yaml addon_bluetooth_proxy: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml esp32: diff --git a/.test/esphome_idf53_core.yaml b/.test/esphome_idf53_core.yaml new file mode 100644 index 0000000..82b38fc --- /dev/null +++ b/.test/esphome_idf53_core.yaml @@ -0,0 +1,5 @@ +--- +packages: + common_idf53: !include common_idf53.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml +... diff --git a/.test/esphome_idf53_hw_relays.yaml b/.test/esphome_idf53_hw_relays.yaml new file mode 100644 index 0000000..628bb79 --- /dev/null +++ b/.test/esphome_idf53_hw_relays.yaml @@ -0,0 +1,6 @@ +--- +packages: + common_idf53: !include common_idf53.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_hw_relays_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_relays.yaml +... diff --git a/.test/esphome_idf53_hw_speaker.yaml b/.test/esphome_idf53_hw_speaker.yaml new file mode 100644 index 0000000..4b4581f --- /dev/null +++ b/.test/esphome_idf53_hw_speaker.yaml @@ -0,0 +1,6 @@ +--- +packages: + common_idf53: !include common_idf53.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_hw_speaker_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_speaker.yaml +... diff --git a/.test/esphome_idf53_hw_vibration.yaml b/.test/esphome_idf53_hw_vibration.yaml new file mode 100644 index 0000000..1bc90ad --- /dev/null +++ b/.test/esphome_idf53_hw_vibration.yaml @@ -0,0 +1,6 @@ +--- +packages: + common_idf53: !include common_idf53.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_hw_vibration_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_vibration.yaml +... diff --git a/.test/esphome_idf_basic.yaml b/.test/esphome_idf_basic.yaml new file mode 100644 index 0000000..82e7f09 --- /dev/null +++ b/.test/esphome_idf_basic.yaml @@ -0,0 +1,11 @@ +--- +packages: + common_idf: !include common_idf.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard.yaml + +media_player: !remove + +switch: + - id: !remove sw_speaker_amplifier +... diff --git a/.test/esphome_idf_bluetooth_proxy.yaml b/.test/esphome_idf_ble_proxy.yaml similarity index 62% rename from .test/esphome_idf_bluetooth_proxy.yaml rename to .test/esphome_idf_ble_proxy.yaml index 3e434a5..dc303a6 100644 --- a/.test/esphome_idf_bluetooth_proxy.yaml +++ b/.test/esphome_idf_ble_proxy.yaml @@ -1,5 +1,7 @@ --- packages: + common: !include common.yaml core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard.yaml addon_bluetooth_proxy: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml ... diff --git a/.test/esphome_idf_core.yaml b/.test/esphome_idf_core.yaml new file mode 100644 index 0000000..6cb4742 --- /dev/null +++ b/.test/esphome_idf_core.yaml @@ -0,0 +1,5 @@ +--- +packages: + common_idf: !include common_idf.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml +... diff --git a/.test/esphome_idf_hw_relays.yaml b/.test/esphome_idf_hw_relays.yaml new file mode 100644 index 0000000..b746d8a --- /dev/null +++ b/.test/esphome_idf_hw_relays.yaml @@ -0,0 +1,6 @@ +--- +packages: + common_idf: !include common_idf.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_hw_relays_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_relays.yaml +... diff --git a/.test/esphome_idf_hw_speaker.yaml b/.test/esphome_idf_hw_speaker.yaml new file mode 100644 index 0000000..2ce797a --- /dev/null +++ b/.test/esphome_idf_hw_speaker.yaml @@ -0,0 +1,6 @@ +--- +packages: + common_idf: !include common_idf.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_hw_speaker_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_speaker.yaml +... diff --git a/.test/esphome_idf_hw_vibration.yaml b/.test/esphome_idf_hw_vibration.yaml new file mode 100644 index 0000000..30d7358 --- /dev/null +++ b/.test/esphome_idf_hw_vibration.yaml @@ -0,0 +1,6 @@ +--- +packages: + common_idf: !include common_idf.yaml + core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml + standard_hw_vibration_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_vibration.yaml +... diff --git a/Assets/Logo_dark.png b/Assets/Logo_dark.png new file mode 100644 index 0000000..640555e Binary files /dev/null and b/Assets/Logo_dark.png differ diff --git a/Assets/Logo_dark.webp b/Assets/Logo_dark.webp new file mode 100644 index 0000000..1a5cc8d Binary files /dev/null and b/Assets/Logo_dark.webp differ diff --git a/Assets/Logo_light.png b/Assets/Logo_light.png new file mode 100644 index 0000000..9c1be5a Binary files /dev/null and b/Assets/Logo_light.png differ diff --git a/ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml b/ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml index 331bda3..292ed0a 100644 --- a/ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml +++ b/ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml @@ -11,22 +11,14 @@ ##### - For normal system use, modifications to this file are NOT required. ##### #################################################################################################### --- +packages: + standard_hw_speaker: !include TX-Ultimate-Easy-ESPHome_standard_hw_speaker.yaml + bluetooth_proxy: esp32: framework: type: esp-idf - sdkconfig_options: - CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST: "y" - CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY: "y" - CONFIG_ESP32_REV_MIN_3: "y" - CONFIG_MBEDTLS_DYNAMIC_BUFFER: "y" - CONFIG_MBEDTLS_DYNAMIC_FREE_CA_CERT: "y" - CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA: "y" - CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC: "y" - CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY: "y" - CONFIG_SPIRAM_RODATA: "y" - CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP: "y" esphome: platformio_options: @@ -39,11 +31,28 @@ light: - id: !extend light_full platform: esp32_rmt_led_strip rgb_order: GRB - rmt_channel: 0 + rmt_channel: 1 chipset: ws2812 + max_refresh_rate: 33ms + use_psram: false type: !remove variant: !remove - max_refresh_rate: 33ms media_player: !remove + +script: + - id: !extend dump_config_list_packages + then: + - script.wait: dump_config + - lambda: |- + // Check for requirements + #if !defined(TX_ULTIMATE_EASY_CORE) + #error "The package TX-Ultimate-Easy-ESPHome_core.yaml is required." + #endif + + // Identify itself + ESP_LOGCONFIG(ESPHOME_PROJECT_NAME, " - Add-on - BLE Proxy"); + +switch: + - id: !remove sw_speaker_amplifier ... diff --git a/ESPHome/TX-Ultimate-Easy-ESPHome_addon_media_player.yaml b/ESPHome/TX-Ultimate-Easy-ESPHome_addon_media_player.yaml new file mode 100644 index 0000000..d6985fb --- /dev/null +++ b/ESPHome/TX-Ultimate-Easy-ESPHome_addon_media_player.yaml @@ -0,0 +1,68 @@ +#################################################################################################### +##### TX Ultimate Easy for ESPHome ##### +##### Repository: https://github.com/edwardtfn/TX-Ultimate-Easy ##### +#################################################################################################### +##### Purpose: ESPHome - Add-on - Media player ##### +#################################################################################################### +##### Author: edwardtfn - https://github.com/edwardtfn - https://buymeacoffee.com/edwardfirmo ##### +#################################################################################################### +##### NOTE: ##### +##### - Make changes ONLY if absolutely necessary and you have the required knowledge. ##### +##### - For normal system use, modifications to this file are NOT required. ##### +#################################################################################################### +--- +packages: + standard_hw_audio: !include TX-Ultimate-Easy-ESPHome_standard_hw_audio.yaml + +esp32: + framework: + type: arduino + +esphome: + platformio_options: + build_flags: + - -D TX_ULTIMATE_EASY_ADDON_MEDIA_PLAYER + +media_player: + - id: mp_media_player + name: Media Player + internal: false + platform: i2s_audio + i2s_dout_pin: GPIO15 + i2s_audio_id: if_i2s_audio + i2s_comm_fmt: msb + dac_type: external + mode: mono + mute_pin: + number: GPIO26 + inverted: true + allow_other_uses: true + +script: + - id: !extend dump_config_list_packages + then: + - script.wait: dump_config + - lambda: |- + // Check for requirements + #if !defined(TX_ULTIMATE_EASY_CORE) + #error "The package TX-Ultimate-Easy-ESPHome_core.yaml is required." + #endif + #if !defined(TX_ULTIMATE_EASY_STANDARD_HW_AUDIO) + #error "The package TX-Ultimate-Easy-ESPHome_standard_hw_audio.yaml is required." + #endif + + // Identify itself + ESP_LOGCONFIG(ESPHOME_PROJECT_NAME, " - Add-on - Media Player"); + +switch: + - id: sw_speaker_amplifier + name: Speaker - Amplifier + platform: gpio + pin: + number: GPIO26 + inverted: true + allow_other_uses: true + restore_mode: RESTORE_DEFAULT_ON + internal: true + entity_category: config +... diff --git a/ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml b/ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml index 75bfc76..6672dd3 100644 --- a/ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml +++ b/ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml @@ -11,202 +11,11 @@ ##### - For normal system use, modifications to this file are NOT required. ##### #################################################################################################### --- -substitutions: - name: tx-ultimate-easy - friendly_name: TX Ultimate Easy - - <<: !include ../versioning/VERSION_YAML - - TX_MODEL_FORMAT_EU_TEXT: "EU (Square, T5-xC-86)" - TX_MODEL_FORMAT_US_TEXT: "US (Rectangle, T5-xC-120)" - - TX_MODEL_1_GANG_TEXT: "1 Gang" - TX_MODEL_2_GANG_TEXT: "2 Gang" - TX_MODEL_3_GANG_TEXT: "3 Gang" - TX_MODEL_4_GANG_TEXT: "4 Gang" - packages: # yamllint disable rule:colons - core_hw_buttons: !include TX-Ultimate-Easy-ESPHome_core_hw_buttons.yaml - core_hw_leds: !include TX-Ultimate-Easy-ESPHome_core_hw_leds.yaml - core_hw_relays: !include TX-Ultimate-Easy-ESPHome_core_hw_relays.yaml - core_hw_speaker: !include TX-Ultimate-Easy-ESPHome_core_hw_speaker.yaml - core_hw_touch: !include TX-Ultimate-Easy-ESPHome_core_hw_touch.yaml - core_hw_vibration: !include TX-Ultimate-Easy-ESPHome_core_hw_vibration.yaml + core_common: !include TX-Ultimate-Easy-ESPHome_core_common.yaml + core_hw_buttons: !include TX-Ultimate-Easy-ESPHome_core_hw_buttons.yaml + core_hw_leds: !include TX-Ultimate-Easy-ESPHome_core_hw_leds.yaml + core_hw_touch: !include TX-Ultimate-Easy-ESPHome_core_hw_touch.yaml # yamllint enable rule:colons - -api: - id: api_server - on_client_connected: - then: - - script.execute: publish_device_info - -button: - - id: bt_restart - name: Restart - internal: false - platform: restart - -captive_portal: - id: ap_captive_portal - -esp32: - board: esp32dev - flash_size: 8MB - -esphome: - name: ${name} - friendly_name: ${friendly_name} - comment: TX Ultimate Easy - platformio_options: - build_flags: - - -D TX_ULTIMATE_EASY_CORE - - on_boot: - - priority: 700 - then: - - script.execute: boot_initialize - - - priority: 600 # This is where most sensors are set up. - then: - - script.execute: boot_sequence - - - priority: -100 # At this priority, pretty much everything should already be initialized. - then: - - script.execute: boot_done - -improv_serial: - id: serial_improv - -logger: - level: DEBUG - -ota: - platform: esphome - -psram: - -script: - - id: api_send_ha_event_boot - mode: queued - parameters: - type: string - then: - - homeassistant.event: - event: esphome.tx_ultimate_easy - data: - device_name: !lambda return tx_device_name->state.c_str(); - firmware: ${version} - domain: boot - type: !lambda return type.c_str(); - - - id: boot_done - mode: restart - then: - - script.execute: - id: api_send_ha_event_boot - type: done - - - id: boot_initialize - mode: restart - then: - # Extended by: - # - HW Buttons - # - HW Relays - # - HW Touch - - script.execute: - id: api_send_ha_event_boot - type: start - - - id: boot_sequence - mode: restart - then: - - script.execute: publish_device_info - - - id: publish_device_info - mode: restart - then: - - lambda: |- - tx_fw_version->publish_state("${version}"); - tx_device_name->publish_state(App.get_name().c_str()); - -select: - - id: sl_tx_model_format - name: Model (Format) - platform: template - options: - - "${TX_MODEL_FORMAT_EU_TEXT}" - - "${TX_MODEL_FORMAT_US_TEXT}" - initial_option: "${TX_MODEL_FORMAT_EU_TEXT}" - optimistic: true - restore_value: true - internal: false - entity_category: config - disabled_by_default: false - icon: mdi:tablet-cellphone - - - id: sl_tx_model_gang - name: Model (Gang) - platform: template - options: - - "${TX_MODEL_1_GANG_TEXT}" - - "${TX_MODEL_2_GANG_TEXT}" - - "${TX_MODEL_3_GANG_TEXT}" - - "${TX_MODEL_4_GANG_TEXT}" - initial_option: "${TX_MODEL_1_GANG_TEXT}" - optimistic: true - restore_value: true - internal: false - entity_category: config - disabled_by_default: false - icon: mdi:dip-switch - on_value: - then: - - lambda: tx_ultimate->set_gang_count(static_cast(i)+1); - -text_sensor: - - id: tx_fw_version - name: Firmware version - platform: template - entity_category: diagnostic - icon: mdi:tag-text-outline - internal: false - update_interval: never - lambda: |- - return {"${version}"}; - - - id: tx_device_name - name: Device Name - platform: template - icon: mdi:identifier - entity_category: diagnostic - internal: false - disabled_by_default: false - update_interval: never - lambda: |- - return {"${name}"}; - filters: - - lambda: |- - const std::string raw_name = x; - std::string result; - bool last_was_underscore = false; - for (const char& c : raw_name) { - if (isalnum(c)) { - result += tolower(c); // Add alphanumeric characters as lowercase - last_was_underscore = false; - } else if (!last_was_underscore) { // Replace non-alphanumeric with '_' but avoid consecutive '_' - result += '_'; - last_was_underscore = true; - } - } - return result; - -time: - - id: time_source - platform: homeassistant - -web_server: - -wifi: - ap: ... diff --git a/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_buttons.yaml b/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_buttons.yaml index 3029db4..d93d70b 100644 --- a/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_buttons.yaml +++ b/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_buttons.yaml @@ -19,6 +19,10 @@ substitutions: BUTTON_2_ACTION_TEXT: "Relay 2 (toggle)" BUTTON_3_ACTION_TEXT: "Relay 3 (toggle)" BUTTON_4_ACTION_TEXT: "Relay 4 (toggle)" + BUTTON_1_ACTION_FAILSAFE_TEXT: "Relay 1 (API failsafe only)" + BUTTON_2_ACTION_FAILSAFE_TEXT: "Relay 2 (API failsafe only)" + BUTTON_3_ACTION_FAILSAFE_TEXT: "Relay 3 (API failsafe only)" + BUTTON_4_ACTION_FAILSAFE_TEXT: "Relay 4 (API failsafe only)" BUTTON_CLICK_MIN_LENGTH: '50' # The minimum duration the click should last, in msec BUTTON_CLICK_MAX_LENGTH: '350' # The maximum duration the click should last, in msec @@ -53,6 +57,11 @@ binary_sensor: internal: false <<: *binary_sensor_button_base +esphome: + platformio_options: + build_flags: + - -D TX_ULTIMATE_EASY_CORE_HW_BUTTONS + globals: - id: button_press_button type: uint8_t @@ -82,28 +91,19 @@ script: - id: boot_initialize_buttons mode: restart then: - - wait_until: - condition: - - lambda: return sl_tx_model_gang->active_index().has_value(); - lambda: |- - const uint8_t num_gangs = (sl_tx_model_gang->active_index().has_value()) ? - (sl_tx_model_gang->active_index().value() + 1) : 0; - if (num_gangs < 1 || num_gangs > 4) { - ESP_LOGE("core_hw_buttons", "Invalid number of gangs: %" PRIu8, num_gangs); - return; - } bs_button_1->publish_state(false); - bs_button_1->set_internal(num_gangs < 1); - sl_button_1_action->set_internal(num_gangs < 1); + bs_button_1->set_internal(id(gang_count) < 1); + sl_button_1_action->set_internal(id(gang_count) < 1); bs_button_2->publish_state(false); - bs_button_2->set_internal(num_gangs < 2); - sl_button_2_action->set_internal(num_gangs < 2); + bs_button_2->set_internal(id(gang_count) < 2); + sl_button_2_action->set_internal(id(gang_count) < 2); bs_button_3->publish_state(false); - bs_button_3->set_internal(num_gangs < 3); - sl_button_3_action->set_internal(num_gangs < 3); + bs_button_3->set_internal(id(gang_count) < 3); + sl_button_3_action->set_internal(id(gang_count) < 3); bs_button_4->publish_state(false); - bs_button_4->set_internal(num_gangs < 4); - sl_button_4_action->set_internal(num_gangs < 4); + bs_button_4->set_internal(id(gang_count) < 4); + sl_button_4_action->set_internal(id(gang_count) < 4); - id: button_action mode: parallel @@ -205,6 +205,41 @@ script: } } + - id: !extend dump_config + then: + - lambda: |- + // Button's actions + ESP_LOGCONFIG("core_hw_buttons", "Button%s action%s:", + id(gang_count_plural_suffix).c_str(), + id(gang_count_plural_suffix).c_str()); + ESP_LOGCONFIG("core_hw_buttons", " Relay 1: %s", sl_button_1_action->has_state() + ? sl_button_1_action->state.c_str() + : "Unknown"); + if (id(gang_count) >= 2) + ESP_LOGCONFIG("core_hw_buttons", " Relay 2: %s", sl_button_2_action->has_state() + ? sl_button_2_action->state.c_str() + : "Unknown"); + if (id(gang_count) >= 3) + ESP_LOGCONFIG("core_hw_buttons", " Relay 3: %s", sl_button_3_action->has_state() + ? sl_button_3_action->state.c_str() + : "Unknown"); + if (id(gang_count) >= 4) + ESP_LOGCONFIG("core_hw_buttons", " Relay 4: %s", sl_button_4_action->has_state() + ? sl_button_4_action->state.c_str() + : "Unknown"); + + - id: !extend dump_config_list_packages + then: + - script.wait: dump_config + - lambda: |- + // Check for requirements + #if !defined(TX_ULTIMATE_EASY_CORE) + #error "The package TX-Ultimate-Easy-ESPHome_core.yaml is required." + #endif + + // Identify itself + ESP_LOGCONFIG(ESPHOME_PROJECT_NAME, " - Core - Hardware - Buttons"); + - id: !extend touch_on_multi_touch_release then: - script.execute: buttons_release @@ -289,6 +324,7 @@ select: options: - "${BUTTON_ACTION_NONE_TEXT}" - "${BUTTON_1_ACTION_TEXT}" + - "${BUTTON_1_ACTION_FAILSAFE_TEXT}" initial_option: "${BUTTON_1_ACTION_TEXT}" optimistic: true restore_value: true @@ -303,6 +339,7 @@ select: options: - "${BUTTON_ACTION_NONE_TEXT}" - "${BUTTON_2_ACTION_TEXT}" + - "${BUTTON_2_ACTION_FAILSAFE_TEXT}" initial_option: "${BUTTON_2_ACTION_TEXT}" <<: *button_select_action_base @@ -312,6 +349,7 @@ select: options: - "${BUTTON_ACTION_NONE_TEXT}" - "${BUTTON_3_ACTION_TEXT}" + - "${BUTTON_3_ACTION_FAILSAFE_TEXT}" initial_option: "${BUTTON_3_ACTION_TEXT}" <<: *button_select_action_base @@ -321,6 +359,7 @@ select: options: - "${BUTTON_ACTION_NONE_TEXT}" - "${BUTTON_4_ACTION_TEXT}" + - "${BUTTON_4_ACTION_FAILSAFE_TEXT}" initial_option: "${BUTTON_4_ACTION_TEXT}" <<: *button_select_action_base ... diff --git a/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_leds.yaml b/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_leds.yaml index 3b20c0b..76e3bf6 100644 --- a/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_leds.yaml +++ b/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_leds.yaml @@ -28,7 +28,11 @@ substitutions: LIGHT_FULL_RESTORE_MODE: RESTORE_DEFAULT_OFF LIGHT_SIDES_RESTORE_MODE: RESTORE_DEFAULT_OFF LIGHT_INDIVIDUAL_RESTORE_MODE: RESTORE_DEFAULT_OFF - LIGHT_RELAYS_RESTORE_MODE: RESTORE_DEFAULT_OFF + +esphome: + platformio_options: + build_flags: + - -D TX_ULTIMATE_EASY_CORE_HW_LEDS globals: - id: gb_lights_1 @@ -43,13 +47,12 @@ light: - id: light_full name: Light - All internal: true - platform: neopixelbus - type: GRB - variant: WS2811 - # method: esp32_rmt num_leds: 32 pin: GPIO13 restore_mode: ${LIGHT_FULL_RESTORE_MODE} + platform: neopixelbus + type: GRB + variant: WS2811 # Those lights are available based on the model selections - &light_partition_with_effects @@ -418,370 +421,77 @@ light: from: 31 to: 31 - # These lights are used to indicate relay's statuses - - &light_partition_relays - id: light_eu_rl_1_1_bottom - name: Light - Relay 1 of 1 (bottom) - platform: partition - internal: true - default_transition_length: ${default_transition_length} - restore_mode: ${LIGHT_RELAYS_RESTORE_MODE} - segments: - - id: light_full - from: 9 - to: 9 - - id: light_eu_rl_1_1_top - name: Light - Relay 1 of 1 (top) - <<: *light_partition_relays - segments: - - id: light_full - from: 23 - to: 23 - - id: light_eu_rl_1_2_bottom - name: Light - Relay 1 of 2 (bottom) - <<: *light_partition_relays - segments: - - id: light_full - from: 11 - to: 11 - - id: light_eu_rl_1_2_top - name: Light - Relay 1 of 2 (top) - <<: *light_partition_relays - segments: - - id: light_full - from: 21 - to: 21 - - id: light_eu_rl_2_2_bottom - name: Light - Relay 2 of 2 (bottom) - <<: *light_partition_relays - segments: - - id: light_full - from: 7 - to: 7 - - id: light_eu_rl_2_2_top - name: Light - Relay 2 of 2 (top) - <<: *light_partition_relays - segments: - - id: light_full - from: 25 - to: 25 - - id: light_eu_rl_1_3_bottom - name: Light - Relay 1 of 3 (bottom) - <<: *light_partition_relays - segments: - - id: light_full - from: 12 - to: 12 - - id: light_eu_rl_1_3_top - name: Light - Relay 1 of 3 (top) - <<: *light_partition_relays - segments: - - id: light_full - from: 20 - to: 20 - - id: light_eu_rl_2_3_bottom - name: Light - Relay 2 of 3 (bottom) - <<: *light_partition_relays - segments: - - id: light_full - from: 9 - to: 9 - - id: light_eu_rl_2_3_top - name: Light - Relay 2 of 3 (top) - <<: *light_partition_relays - segments: - - id: light_full - from: 23 - to: 23 - - id: light_eu_rl_3_3_bottom - name: Light - Relay 3 of 3 (bottom) - <<: *light_partition_relays - segments: - - id: light_full - from: 6 - to: 6 - - id: light_eu_rl_3_3_top - name: Light - Relay 3 of 3 (top) - <<: *light_partition_relays - segments: - - id: light_full - from: 26 - to: 26 - - id: light_eu_rl_1_4_bottom - name: Light - Relay 1 of 4 (bottom) - <<: *light_partition_relays - segments: - - id: light_full - from: 12 - to: 12 - - id: light_eu_rl_1_4_top - name: Light - Relay 1 of 4 (top) - <<: *light_partition_relays - segments: - - id: light_full - from: 20 - to: 20 - - id: light_eu_rl_2_4_bottom - name: Light - Relay 2 of 4 (bottom) - <<: *light_partition_relays - segments: - - id: light_full - from: 10 - to: 10 - - id: light_eu_rl_2_4_top - name: Light - Relay 2 of 4 (top) - <<: *light_partition_relays - segments: - - id: light_full - from: 22 - to: 22 - - id: light_eu_rl_3_4_bottom - name: Light - Relay 3 of 4 (bottom) - <<: *light_partition_relays - segments: - - id: light_full - from: 8 - to: 8 - - id: light_eu_rl_3_4_top - name: Light - Relay 3 of 4 (top) - <<: *light_partition_relays - segments: - - id: light_full - from: 24 - to: 24 - - id: light_eu_rl_4_4_bottom - name: Light - Relay 4 of 4 (bottom) - <<: *light_partition_relays - segments: - - id: light_full - from: 6 - to: 6 - - id: light_eu_rl_4_4_top - name: Light - Relay 4 of 4 (top) - <<: *light_partition_relays - segments: - - id: light_full - from: 26 - to: 26 - - id: light_us_rl_1_1_left - name: Light - Relay 1 of 1 (left) - <<: *light_partition_relays - segments: - - id: light_full - from: 15 - to: 24 - - id: light_us_rl_1_1_right - name: Light - Relay 1 of 1 (right) - <<: *light_partition_relays - segments: - - id: light_full - from: 31 - to: 31 - - id: light_full - from: 0 - to: 8 - - id: light_us_rl_1_2_left - name: Light - Relay 1 of 2 (left) - <<: *light_partition_relays - segments: - - id: light_full - from: 20 - to: 24 - - id: light_us_rl_1_2_right - name: Light - Relay 1 of 2 (right) - <<: *light_partition_relays - segments: - - id: light_full - from: 31 - to: 31 - - id: light_full - from: 0 - to: 3 - - id: light_us_rl_2_2_left - name: Light - Relay 2 of 2 (left) - <<: *light_partition_relays - segments: - - id: light_full - from: 15 - to: 19 - - id: light_us_rl_2_2_right - name: Light - Relay 2 of 2 (right) - <<: *light_partition_relays - segments: - - id: light_full - from: 4 - to: 8 - - id: light_us_rl_1_3_left - name: Light - Relay 1 of 3 (left) - <<: *light_partition_relays - segments: - - id: light_full - from: 22 - to: 23 - - id: light_us_rl_1_3_right - name: Light - Relay 1 of 3 (right) - <<: *light_partition_relays - segments: - - id: light_full - from: 0 - to: 1 - - id: light_us_rl_2_3_left - name: Light - Relay 2 of 3 (left) - <<: *light_partition_relays - segments: - - id: light_full - from: 19 - to: 20 - - id: light_us_rl_2_3_right - name: Light - Relay 2 of 3 (right) - <<: *light_partition_relays - segments: - - id: light_full - from: 3 - to: 4 - - id: light_us_rl_3_3_left - name: Light - Relay 3 of 3 (left) - <<: *light_partition_relays - segments: - - id: light_full - from: 17 - to: 18 - - id: light_us_rl_3_3_right - name: Light - Relay 3 of 3 (right) - <<: *light_partition_relays - segments: - - id: light_full - from: 6 - to: 7 - - id: light_us_rl_1_4_left - name: Light - Relay 1 of 4 (left) - <<: *light_partition_relays - segments: - - id: light_full - from: 12 - to: 12 - - id: light_us_rl_1_4_right - name: Light - Relay 1 of 4 (right) - <<: *light_partition_relays - segments: - - id: light_full - from: 31 - to: 31 - - id: light_us_rl_2_4_left - name: Light - Relay 2 of 4 (left) - <<: *light_partition_relays - segments: - - id: light_full - from: 24 - to: 24 - - id: light_us_rl_2_4_right - name: Light - Relay 2 of 4 (right) - <<: *light_partition_relays - segments: - - id: light_full - from: 2 - to: 2 - - id: light_us_rl_3_4_left - name: Light - Relay 3 of 4 (left) - <<: *light_partition_relays - segments: - - id: light_full - from: 21 - to: 21 - - id: light_us_rl_3_4_right - name: Light - Relay 3 of 4 (right) - <<: *light_partition_relays - segments: - - id: light_full - from: 4 - to: 4 - - id: light_us_rl_4_4_left - name: Light - Relay 4 of 4 (left) - <<: *light_partition_relays - segments: - - id: light_full - from: 19 - to: 19 - - id: light_us_rl_4_4_right - name: Light - Relay 4 of 4 (right) - <<: *light_partition_relays - segments: - - id: light_full - from: 7 - to: 7 - script: - id: !extend boot_initialize then: - - wait_until: - condition: - - lambda: return sl_tx_model_format->active_index().has_value(); - - lambda: return sl_tx_model_gang->active_index().has_value(); - lambda: |- - const bool is_model_us = sl_tx_model_format->active_index().has_value() and - sl_tx_model_format->active_index().value() == 1; - const uint8_t num_gangs = (sl_tx_model_gang->active_index().has_value()) ? - (sl_tx_model_gang->active_index().value() + 1) : 0; - if (num_gangs < 1 || num_gangs > 4) { - ESP_LOGE("core_hw_leds", "Invalid number of gangs: %" PRIu8, num_gangs); - return; - } - light_28->set_internal(!is_model_us); - light_29->set_internal(!is_model_us); - light_30->set_internal(!is_model_us); - light_31->set_internal(!is_model_us); - light_eu->set_internal(is_model_us); - light_eu_bottom->set_internal(is_model_us); - light_eu_left->set_internal(is_model_us); - light_eu_right->set_internal(is_model_us); - light_eu_top->set_internal(is_model_us); - light_us->set_internal(!is_model_us); - light_us_bottom->set_internal(!is_model_us); - light_us_left->set_internal(!is_model_us); - light_us_right->set_internal(!is_model_us); - light_us_top->set_internal(!is_model_us); - switch (num_gangs) { - case 1: // 1 Gang - if (is_model_us) { - id(gb_lights_1) = { light_us_rl_1_1_left }; - id(gb_lights_2) = { light_us_rl_1_1_right }; - } else { - id(gb_lights_1) = { light_eu_rl_1_1_bottom }; - id(gb_lights_2) = { light_eu_rl_1_1_top }; - } - break; - case 2: // 2 Gang - if (is_model_us) { - id(gb_lights_1) = { light_us_rl_1_2_left, light_us_rl_2_2_left }; - id(gb_lights_2) = { light_us_rl_1_2_right, light_us_rl_2_2_right }; - } else { - id(gb_lights_1) = { light_eu_rl_1_2_bottom, light_eu_rl_2_2_bottom }; - id(gb_lights_2) = { light_eu_rl_1_2_top, light_eu_rl_2_2_top }; - } - break; - case 3: // 3 Gang - if (is_model_us) { - id(gb_lights_1) = { light_us_rl_1_3_left, light_us_rl_2_3_left, light_us_rl_3_3_left }; - id(gb_lights_2) = { light_us_rl_1_3_right, light_us_rl_2_3_right, light_us_rl_3_3_right }; - } else { - id(gb_lights_1) = { light_eu_rl_1_3_bottom, light_eu_rl_2_3_bottom, light_eu_rl_3_3_bottom }; - id(gb_lights_2) = { light_eu_rl_1_3_top, light_eu_rl_2_3_top, light_eu_rl_3_3_top }; - } - break; - case 4: // 4 Gang - if (is_model_us) { - id(gb_lights_1) = { light_us_rl_1_4_left, light_us_rl_2_4_left, - light_us_rl_3_4_left, light_us_rl_4_4_left }; - id(gb_lights_2) = { light_us_rl_1_4_right, light_us_rl_2_4_right, - light_us_rl_3_4_right, light_us_rl_4_4_right }; - } else { - id(gb_lights_1) = { light_eu_rl_1_4_bottom, light_eu_rl_2_4_bottom, - light_eu_rl_3_4_bottom, light_eu_rl_4_4_bottom }; - id(gb_lights_2) = { light_eu_rl_1_4_top, light_eu_rl_2_4_top, - light_eu_rl_3_4_top, light_eu_rl_4_4_top }; - } - break; - } + light_28->set_internal(!id(is_us_model)); + light_29->set_internal(!id(is_us_model)); + light_30->set_internal(!id(is_us_model)); + light_31->set_internal(!id(is_us_model)); + light_eu->set_internal(id(is_us_model)); + light_eu_bottom->set_internal(id(is_us_model)); + light_eu_left->set_internal(id(is_us_model)); + light_eu_right->set_internal(id(is_us_model)); + light_eu_top->set_internal(id(is_us_model)); + light_us->set_internal(!id(is_us_model)); + light_us_bottom->set_internal(!id(is_us_model)); + light_us_left->set_internal(!id(is_us_model)); + light_us_right->set_internal(!id(is_us_model)); + light_us_top->set_internal(!id(is_us_model)); + + - id: !extend dump_config + then: + - lambda: |- + // Relay's LEDs modes + ESP_LOGCONFIG("core_hw_leds", "Relay%s LEDs mode%s:", + id(gang_count_plural_suffix).c_str(), + id(gang_count_plural_suffix).c_str()); + ESP_LOGCONFIG("core_hw_leds", " Relay 1: %s", id(is_us_model) + ? sl_relay_1_light_mode_us->state.c_str() + : sl_relay_1_light_mode_eu->state.c_str()); + if (id(gang_count) >= 2) + ESP_LOGCONFIG("core_hw_leds", " Relay 2: %s", id(is_us_model) + ? sl_relay_2_light_mode_us->state.c_str() + : sl_relay_2_light_mode_eu->state.c_str()); + if (id(gang_count) >= 3) + ESP_LOGCONFIG("core_hw_leds", " Relay 3: %s", id(is_us_model) + ? sl_relay_3_light_mode_us->state.c_str() + : sl_relay_3_light_mode_eu->state.c_str()); + if (id(gang_count) >= 4) + ESP_LOGCONFIG("core_hw_leds", " Relay 4: %s", id(is_us_model) + ? sl_relay_4_light_mode_us->state.c_str() + : sl_relay_4_light_mode_eu->state.c_str()); + + // Transition times + ESP_LOGCONFIG("core_hw_leds", "Transition times:"); + ESP_LOGCONFIG("core_hw_leds", " Default: ${default_transition_length}"); + if (${LIGHT_TRANSITION_TURN_ON} > 0) + ESP_LOGCONFIG("core_hw_leds", " Turning on: ${LIGHT_TRANSITION_TURN_ON}ms"); + else + ESP_LOGCONFIG("core_hw_leds", " Turning on: Disabled"); + if (${LIGHT_TRANSITION_TURN_OFF} > 0) + ESP_LOGCONFIG("core_hw_leds", " Turning off: ${LIGHT_TRANSITION_TURN_OFF}ms"); + else + ESP_LOGCONFIG("core_hw_leds", " Turning off: Disabled"); + + // Restore modes + ESP_LOGCONFIG("core_hw_leds", "LED restore modes:"); + ESP_LOGCONFIG("core_hw_leds", " Light - All: ${LIGHT_FULL_RESTORE_MODE}"); + ESP_LOGCONFIG("core_hw_leds", " Sides: ${LIGHT_SIDES_RESTORE_MODE}"); + ESP_LOGCONFIG("core_hw_leds", " Individual: ${LIGHT_INDIVIDUAL_RESTORE_MODE}"); + + - id: !extend dump_config_list_packages + then: + - script.wait: dump_config + - lambda: |- + // Check for requirements + #if !defined(TX_ULTIMATE_EASY_CORE) + #error "The package TX-Ultimate-Easy-ESPHome_core.yaml is required." + #endif + + // Identify itself + ESP_LOGCONFIG(ESPHOME_PROJECT_NAME, " - Core - Hardware - LEDs"); - id: light_set_state mode: parallel @@ -795,10 +505,12 @@ script: static const uint32_t LIGHT_TRANSITION_TURN_OFF = ${LIGHT_TRANSITION_TURN_OFF}; static const uint8_t LIGHT_BRIGHTNESS_TURN_ON = ${LIGHT_BRIGHTNESS_TURN_ON}; - const bool is_model_us = sl_tx_model_format->active_index().has_value() and - sl_tx_model_format->active_index().value() == 1; - const std::string light_mode_group_1 = is_model_us ? "${LIGHT_MODE_LEFT_TEXT}" : "${LIGHT_MODE_BOTTOM_TEXT}"; - const std::string light_mode_group_2 = is_model_us ? "${LIGHT_MODE_RIGHT_TEXT}" : "${LIGHT_MODE_TOP_TEXT}"; + const std::string light_mode_group_1 = id(is_us_model) + ? "${LIGHT_MODE_LEFT_TEXT}" + : "${LIGHT_MODE_BOTTOM_TEXT}"; + const std::string light_mode_group_2 = id(is_us_model) + ? "${LIGHT_MODE_RIGHT_TEXT}" + : "${LIGHT_MODE_TOP_TEXT}"; switch (light_group) { case 1: @@ -869,15 +581,12 @@ select: entity_category: config disabled_by_default: false icon: mdi:dots-square - - id: sl_relay_2_light_mode_eu name: Relay 2 light mode <<: *relay_light_mode_eu - - id: sl_relay_3_light_mode_eu name: Relay 3 light mode <<: *relay_light_mode_eu - - id: sl_relay_4_light_mode_eu name: Relay 4 light mode <<: *relay_light_mode_eu @@ -899,15 +608,12 @@ select: entity_category: config disabled_by_default: false icon: mdi:dots-square - - id: sl_relay_2_light_mode_us name: Relay 2 light mode <<: *relay_light_mode_us - - id: sl_relay_3_light_mode_us name: Relay 3 light mode <<: *relay_light_mode_us - - id: sl_relay_4_light_mode_us name: Relay 4 light mode <<: *relay_light_mode_us diff --git a/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_speaker.yaml b/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_media_player.yaml similarity index 88% rename from ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_speaker.yaml rename to ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_media_player.yaml index 11178ec..d206ea6 100644 --- a/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_speaker.yaml +++ b/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_media_player.yaml @@ -2,7 +2,7 @@ ##### TX Ultimate Easy for ESPHome ##### ##### Repository: https://github.com/edwardtfn/TX-Ultimate-Easy ##### #################################################################################################### -##### Purpose: ESPHome Core - Hardware - Speaker ##### +##### Purpose: ESPHome Core - Hardware - Media player ##### #################################################################################################### ##### Author: edwardtfn - https://github.com/edwardtfn - https://buymeacoffee.com/edwardfirmo ##### #################################################################################################### @@ -17,13 +17,13 @@ i2s_audio: i2s_lrclk_pin: GPIO4 media_player: - - id: mp_speaker - name: Speaker + - id: mp_media_player + name: Media Player + internal: false platform: i2s_audio i2s_dout_pin: GPIO15 i2s_audio_id: if_i2s_audio - i2s_comm_fmt: lsb + i2s_comm_fmt: msb # Experimental - It was 'lsb' until v2024.12.12 dac_type: external mode: mono - internal: false ... diff --git a/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_relays.yaml b/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_relays.yaml deleted file mode 100644 index d9a163e..0000000 --- a/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_relays.yaml +++ /dev/null @@ -1,441 +0,0 @@ -#################################################################################################### -##### TX Ultimate Easy for ESPHome ##### -##### Repository: https://github.com/edwardtfn/TX-Ultimate-Easy ##### -#################################################################################################### -##### Purpose: ESPHome Core - Hardware - Relays ##### -#################################################################################################### -##### Author: edwardtfn - https://github.com/edwardtfn - https://buymeacoffee.com/edwardfirmo ##### -#################################################################################################### -##### NOTE: ##### -##### - Make changes ONLY if absolutely necessary and you have the required knowledge. ##### -##### - For normal system use, modifications to this file are NOT required. ##### -#################################################################################################### ---- -substitutions: - RELAY_MODE_TEXT_SWITCH: "Switch" - RELAY_MODE_TEXT_LIGHT: "Light" - RELAY_MODE_TEXT_NOT_USED: "Not in use" - RELAY_RESTORE_MODE: RESTORE_DEFAULT_OFF - -globals: - - id: boot_initialization_relays - type: bool - restore_value: false - initial_value: 'false' - -light: - # These lights are used for the physical relays to be shown as lights - - id: light_output_1 - name: Light output 1 - output: output_relay_1 - platform: binary - internal: true - restore_mode: ${RELAY_RESTORE_MODE} - on_turn_on: - then: - - if: - condition: - - switch.is_off: sw_relay_1 - then: - - switch.turn_on: sw_relay_1 - on_turn_off: - then: - - if: - condition: - - switch.is_on: sw_relay_1 - then: - - switch.turn_off: sw_relay_1 - - id: light_output_2 - name: Light output 2 - output: output_relay_2 - platform: binary - internal: true - on_turn_on: - then: - - if: - condition: - - switch.is_off: sw_relay_2 - then: - - switch.turn_on: sw_relay_2 - on_turn_off: - then: - - if: - condition: - - switch.is_on: sw_relay_2 - then: - - switch.turn_off: sw_relay_2 - - id: light_output_3 - name: Light output 3 - output: output_relay_3 - platform: binary - internal: true - on_turn_on: - then: - - if: - condition: - - switch.is_off: sw_relay_3 - then: - - switch.turn_on: sw_relay_3 - on_turn_off: - then: - - if: - condition: - - switch.is_on: sw_relay_3 - then: - - switch.turn_off: sw_relay_3 - - id: light_output_4 - name: Light output 4 - output: output_relay_4 - platform: binary - internal: true - on_turn_on: - then: - - if: - condition: - - switch.is_off: sw_relay_4 - then: - - switch.turn_on: sw_relay_4 - on_turn_off: - then: - - if: - condition: - - switch.is_on: sw_relay_4 - then: - - switch.turn_off: sw_relay_4 - -output: - - id: output_relay_1 - platform: gpio - pin: GPIO18 - - - id: output_relay_2 - platform: gpio - pin: GPIO17 - - - id: output_relay_3 - platform: gpio - pin: GPIO27 - - - id: output_relay_4 - platform: gpio - pin: GPIO23 - -script: - - id: !extend boot_initialize - then: - - script.execute: boot_initialize_relays - - - id: boot_initialize_relays - mode: restart - then: - - wait_until: - condition: - - lambda: return sl_tx_model_format->active_index().has_value(); - - lambda: return sl_tx_model_gang->active_index().has_value(); - - lambda: |- - const bool is_model_us = sl_tx_model_format->active_index().has_value() and - sl_tx_model_format->active_index().value() == 1; - const uint8_t num_gangs = (sl_tx_model_gang->active_index().has_value()) ? - (sl_tx_model_gang->active_index().value() + 1) : 0; - if (num_gangs < 1 || num_gangs > 4) { - ESP_LOGE("core_hw_relays", "Invalid number of gangs: %" PRIu8, num_gangs); - return; - } - sl_relay_1_mode->set_internal(num_gangs < 1); - sl_relay_1_light_mode_eu->set_internal(is_model_us or num_gangs < 1); - sl_relay_1_light_mode_us->set_internal(!is_model_us or num_gangs < 1); - sl_relay_2_mode->set_internal(num_gangs < 2); - sl_relay_2_light_mode_eu->set_internal(is_model_us or num_gangs < 2); - sl_relay_2_light_mode_us->set_internal(!is_model_us or num_gangs < 2); - sl_relay_3_mode->set_internal(num_gangs < 3); - sl_relay_3_light_mode_eu->set_internal(is_model_us or num_gangs < 3); - sl_relay_3_light_mode_us->set_internal(!is_model_us or num_gangs < 3); - sl_relay_4_mode->set_internal(num_gangs < 4); - sl_relay_4_light_mode_eu->set_internal(is_model_us or num_gangs < 4); - sl_relay_4_light_mode_us->set_internal(!is_model_us or num_gangs < 4); - auto relay_mode_index = sl_relay_1_mode->active_index(); - if (relay_mode_index.has_value()) { - light_output_1->set_internal(false or relay_mode_index.value() != 1); - sw_relay_1->set_internal(false or relay_mode_index.value() != 0); - } - relay_mode_index = sl_relay_2_mode->active_index(); - if (relay_mode_index.has_value()) { - light_output_2->set_internal(num_gangs < 2 or relay_mode_index.value() != 1); - sw_relay_2->set_internal(num_gangs < 2 or relay_mode_index.value() != 0); - } - relay_mode_index = sl_relay_3_mode->active_index(); - if (relay_mode_index.has_value()) { - light_output_3->set_internal(num_gangs < 3 or relay_mode_index.value() != 1); - sw_relay_3->set_internal(num_gangs < 3 or relay_mode_index.value() != 0); - } - relay_mode_index = sl_relay_4_mode->active_index(); - if (relay_mode_index.has_value()) { - light_output_4->set_internal(num_gangs < 4 or relay_mode_index.value() != 1); - sw_relay_4->set_internal(num_gangs < 4 or relay_mode_index.value() != 0); - } - id(boot_initialization_relays) = true; - - - id: !extend button_click_event - then: - - lambda: |- - // Handle only single clicks - if (click_count != 1) - return; - - // Ignore if other touch events are active - if (bs_multi_touch->state || - bs_swipe_left->state || - bs_swipe_down->state || - bs_swipe_right->state) { - return; - } - - // Toggle relay if corresponding button action is enabled - ESP_LOGVV("core_hw_relays", "Toggle relays: (${BUTTON_ACTION_NONE_TEXT})"); - ESP_LOGVV("core_hw_relays", " Relay 1: %s (%s)", - YESNO(sl_button_1_action->state != "${BUTTON_ACTION_NONE_TEXT}"), - sl_button_1_action->state.c_str()); - ESP_LOGVV("core_hw_relays", " Relay 2: %s (%s)", - YESNO(sl_button_2_action->state != "${BUTTON_ACTION_NONE_TEXT}"), - sl_button_2_action->state.c_str()); - ESP_LOGVV("core_hw_relays", " Relay 3: %s (%s)", - YESNO(sl_button_3_action->state != "${BUTTON_ACTION_NONE_TEXT}"), - sl_button_3_action->state.c_str()); - ESP_LOGVV("core_hw_relays", " Relay 4: %s (%s)", - YESNO(sl_button_4_action->state != "${BUTTON_ACTION_NONE_TEXT}"), - sl_button_4_action->state.c_str()); - switch (button) { - case ${BUTTON_1_ID}: - if (sl_button_1_action->state != "${BUTTON_ACTION_NONE_TEXT}") { - ESP_LOGV("core_hw_relays", "Toggle relay 1: (%s)", sl_button_1_action->state.c_str()); - sw_relay_1->toggle(); - } else { - ESP_LOGV("core_hw_relays", "Ignoring toggle for relay 1: action is '%s'", - sl_button_1_action->state.c_str()); - } - break; - case ${BUTTON_2_ID}: - if (sl_button_2_action->state != "${BUTTON_ACTION_NONE_TEXT}") { - ESP_LOGV("core_hw_relays", "Toggle relay 2: (%s)", sl_button_2_action->state.c_str()); - sw_relay_2->toggle(); - } else { - ESP_LOGV("core_hw_relays", "Ignoring toggle for relay 2: action is '%s'", - sl_button_2_action->state.c_str()); - } - break; - case ${BUTTON_3_ID}: - if (sl_button_3_action->state != "${BUTTON_ACTION_NONE_TEXT}") { - ESP_LOGV("core_hw_relays", "Toggle relay 3: (%s)", sl_button_3_action->state.c_str()); - sw_relay_3->toggle(); - } else { - ESP_LOGV("core_hw_relays", "Ignoring toggle for relay 3: action is '%s'", - sl_button_3_action->state.c_str()); - } - break; - case ${BUTTON_4_ID}: - if (sl_button_4_action->state != "${BUTTON_ACTION_NONE_TEXT}") { - ESP_LOGV("core_hw_relays", "Toggle relay 4: (%s)", sl_button_4_action->state.c_str()); - sw_relay_4->toggle(); - } else { - ESP_LOGV("core_hw_relays", "Ignoring toggle for relay 4: action is '%s'", - sl_button_4_action->state.c_str()); - } - break; - } - - - id: show_relay_status - mode: restart - then: - - script.wait: boot_initialize_relays - - wait_until: - condition: - - lambda: return id(boot_initialization_relays); - - lambda: |- - const bool is_model_us = sl_tx_model_format->active_index().has_value() and - sl_tx_model_format->active_index().value() == 1; - const uint8_t num_gangs = (sl_tx_model_gang->active_index().has_value()) - ? (sl_tx_model_gang->active_index().value() + 1) - : 0; - - if (num_gangs < 1 || num_gangs > 4) { - ESP_LOGE("core_hw_relays", "Invalid number of gangs: %" PRIu8, num_gangs); - return; - } - - for (uint8_t i = 0; i < num_gangs; i++) { - bool relay_state = false; - std::string light_mode; - const std::string light_mode_group_1 = is_model_us - ? "${LIGHT_MODE_LEFT_TEXT}" - : "${LIGHT_MODE_BOTTOM_TEXT}"; - const std::string light_mode_group_2 = is_model_us - ? "${LIGHT_MODE_RIGHT_TEXT}" - : "${LIGHT_MODE_TOP_TEXT}"; - - // Determine relay state and light mode - switch (i) { - case 0: - relay_state = id(sw_relay_1).state; - light_mode = is_model_us - ? id(sl_relay_1_light_mode_us)->state - : id(sl_relay_1_light_mode_eu)->state; - break; - case 1: - relay_state = id(sw_relay_2).state; - light_mode = is_model_us - ? id(sl_relay_2_light_mode_us)->state - : id(sl_relay_2_light_mode_eu)->state; - break; - case 2: - relay_state = id(sw_relay_3).state; - light_mode = is_model_us - ? id(sl_relay_3_light_mode_us)->state - : id(sl_relay_3_light_mode_eu)->state; - break; - case 3: - relay_state = id(sw_relay_4).state; - light_mode = is_model_us - ? id(sl_relay_4_light_mode_us)->state - : id(sl_relay_4_light_mode_eu)->state; - break; - } - - ESP_LOGV("core_hw_relays", "Relay %" PRIu8 " is %s", i + 1, relay_state ? "ON" : "OFF"); - ESP_LOGV("core_hw_relays", "Light Mode for Relay %" PRIu8 ": %s", i + 1, light_mode.c_str()); - - // Use light_set_state for light updates - if (relay_state) { - if (light_mode == light_mode_group_1 || light_mode == "${LIGHT_MODE_BOTH_TEXT}") { - light_set_state->execute(1, i, true); // Left/bottom light - } - if (light_mode == light_mode_group_2 || light_mode == "${LIGHT_MODE_BOTH_TEXT}") { - light_set_state->execute(2, i, true); // Right/top light - } - } else { - light_set_state->execute(1, i, false); // Turn off left/bottom light - light_set_state->execute(2, i, false); // Turn off right/top light - } - } - -select: - - &relay_select_mode_base - id: sl_relay_1_mode - name: Relay 1 display mode - platform: template - options: - - "${RELAY_MODE_TEXT_SWITCH}" - - "${RELAY_MODE_TEXT_LIGHT}" - - "${RELAY_MODE_TEXT_NOT_USED}" - initial_option: "${RELAY_MODE_TEXT_SWITCH}" - optimistic: true - restore_value: true - internal: true - entity_category: config - disabled_by_default: false - icon: mdi:dip-switch - - - id: sl_relay_2_mode - name: Relay 2 display mode - <<: *relay_select_mode_base - - - id: sl_relay_3_mode - name: Relay 3 display mode - <<: *relay_select_mode_base - - - id: sl_relay_4_mode - name: Relay 4 display mode - <<: *relay_select_mode_base - -switch: - - id: sw_relay_1 - name: Relay 1 - output: output_relay_1 - platform: output - restore_mode: ${RELAY_RESTORE_MODE} - internal: true - on_turn_on: - then: - - script.execute: show_relay_status - - if: - condition: - - light.is_off: light_output_1 - then: - light.turn_on: light_output_1 - on_turn_off: - then: - - script.execute: show_relay_status - - if: - condition: - - light.is_on: light_output_1 - then: - - light.turn_off: light_output_1 - - - id: sw_relay_2 - name: Relay 2 - output: output_relay_2 - platform: output - restore_mode: ${RELAY_RESTORE_MODE} - internal: true - on_turn_on: - then: - - script.execute: show_relay_status - - if: - condition: - - light.is_off: light_output_2 - then: - light.turn_on: light_output_2 - on_turn_off: - then: - - script.execute: show_relay_status - - if: - condition: - - light.is_on: light_output_2 - then: - - light.turn_off: light_output_2 - - - id: sw_relay_3 - name: Relay 3 - output: output_relay_3 - platform: output - restore_mode: ${RELAY_RESTORE_MODE} - internal: true - on_turn_on: - then: - - script.execute: show_relay_status - - if: - condition: - - light.is_off: light_output_3 - then: - - light.turn_on: light_output_3 - on_turn_off: - then: - - script.execute: show_relay_status - - if: - condition: - - light.is_on: light_output_3 - then: - - light.turn_off: light_output_3 - - - id: sw_relay_4 - name: Relay 4 - output: output_relay_4 - platform: output - restore_mode: ${RELAY_RESTORE_MODE} - internal: true - on_turn_on: - then: - - script.execute: show_relay_status - - if: - condition: - - light.is_off: light_output_4 - then: - - light.turn_on: light_output_4 - on_turn_off: - then: - - script.execute: show_relay_status - - if: - condition: - - light.is_on: light_output_4 - then: - - light.turn_off: light_output_4 -... diff --git a/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_touch.yaml b/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_touch.yaml index def7a97..45241a9 100644 --- a/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_touch.yaml +++ b/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_touch.yaml @@ -198,6 +198,11 @@ binary_sensor: id: bs_swipe_down state: OFF # yamllint disable-line rule:truthy +esphome: + platformio_options: + build_flags: + - -D TX_ULTIMATE_EASY_CORE_HW_TOUCH + external_components: - source: type: git @@ -256,13 +261,8 @@ script: - id: boot_initialize_touch_gang mode: restart then: - - wait_until: - condition: - - lambda: return sl_tx_model_gang->active_index().has_value(); - lambda: |- - const uint8_t num_gangs = (sl_tx_model_gang->active_index().has_value()) ? - (sl_tx_model_gang->active_index().value() + 1) : 0; - tx_ultimate->set_gang_count(num_gangs); + tx_ultimate->set_gang_count(id(gang_count)); bs_button_1_click_event->publish_state(false); bs_button_2_click_event->publish_state(false); bs_button_3_click_event->publish_state(false); @@ -275,18 +275,40 @@ script: bs_button_2_long_press_event->publish_state(false); bs_button_3_long_press_event->publish_state(false); bs_button_4_long_press_event->publish_state(false); - bs_button_1_click_event->set_internal(num_gangs < 1); - bs_button_2_click_event->set_internal(num_gangs < 2); - bs_button_3_click_event->set_internal(num_gangs < 3); - bs_button_4_click_event->set_internal(num_gangs < 4); - bs_button_1_double_click_event->set_internal(num_gangs < 1); - bs_button_2_double_click_event->set_internal(num_gangs < 2); - bs_button_3_double_click_event->set_internal(num_gangs < 3); - bs_button_4_double_click_event->set_internal(num_gangs < 4); - bs_button_1_long_press_event->set_internal(num_gangs < 1); - bs_button_2_long_press_event->set_internal(num_gangs < 2); - bs_button_3_long_press_event->set_internal(num_gangs < 3); - bs_button_4_long_press_event->set_internal(num_gangs < 4); + bs_button_1_click_event->set_internal(id(gang_count) < 1); + bs_button_2_click_event->set_internal(id(gang_count) < 2); + bs_button_3_click_event->set_internal(id(gang_count) < 3); + bs_button_4_click_event->set_internal(id(gang_count) < 4); + bs_button_1_double_click_event->set_internal(id(gang_count) < 1); + bs_button_2_double_click_event->set_internal(id(gang_count) < 2); + bs_button_3_double_click_event->set_internal(id(gang_count) < 3); + bs_button_4_double_click_event->set_internal(id(gang_count) < 4); + bs_button_1_long_press_event->set_internal(id(gang_count) < 1); + bs_button_2_long_press_event->set_internal(id(gang_count) < 2); + bs_button_3_long_press_event->set_internal(id(gang_count) < 3); + bs_button_4_long_press_event->set_internal(id(gang_count) < 4); + + - id: !extend dump_config + then: + - lambda: |- + // Touch panel's state + if (sw_touch_panel_power->state) + ESP_LOGCONFIG("core_hw_touch", "Touch panel - Power: On"); + else + ESP_LOGW("core_hw_touch", "Touch panel - Power: OFF"); + ESP_LOGCONFIG("core_hw_touch", "Touch event duration: %.0fms", nr_touch_duration->state); + + - id: !extend dump_config_list_packages + then: + - script.wait: dump_config + - lambda: |- + // Check for requirements + #if !defined(TX_ULTIMATE_EASY_CORE) + #error "The package TX-Ultimate-Easy-ESPHome_core.yaml is required." + #endif + + // Identify itself + ESP_LOGCONFIG(ESPHOME_PROJECT_NAME, " - Core - Hardware - Touchpad"); - id: touch_on_multi_touch_release mode: restart @@ -296,7 +318,7 @@ script: # - HW Vibration - binary_sensor.template.publish: id: bs_multi_touch - state: OFF # yamllint disable-line rule:truthy + state: ON # yamllint disable-line rule:truthy - id: touch_on_press mode: restart @@ -358,9 +380,9 @@ tx_ultimate_easy: - lambda: |- const uint8_t touch_position = static_cast(touch.x); if (touch_position > ${TOUCH_POSITION_MAX_VALUE}) { // Check for valid range - ESP_LOGE("tx_ultimate_easy", "Invalid long-touch position: %" PRIu8, touch_position); + ESP_LOGE("core_hw_touch", "Invalid long-touch position: %" PRIu8, touch_position); } else { - ESP_LOGI("tx_ultimate_easy", "Long-touch released at position %" PRIu8, touch_position); + ESP_LOGI("core_hw_touch", "Long-touch released at position %" PRIu8, touch_position); } on_multi_touch_release: @@ -373,21 +395,21 @@ tx_ultimate_easy: type: multi_touch action: release position: !lambda return touch.x; - - lambda: ESP_LOGI("tx_ultimate_easy", "Multi-touch released"); + - lambda: ESP_LOGI("core_hw_touch", "Multi-touch released"); - script.execute: touch_on_multi_touch_release on_press: - lambda: |- const uint8_t position = static_cast(touch.x); if (position > ${TOUCH_POSITION_MAX_VALUE}) { // Check for valid range - ESP_LOGE("tx_ultimate_easy", "Invalid touch position: %" PRIu8, position); + ESP_LOGE("core_hw_touch", "Invalid touch position: %" PRIu8, position); } else { - ESP_LOGI("tx_ultimate_easy", "Pressed at position %" PRIu8, position); + ESP_LOGI("core_hw_touch", "Pressed at position %" PRIu8, position); touch_on_press->execute(static_cast(touch.button), position); } on_release: - - lambda: ESP_LOGI("tx_ultimate_easy", "Released"); + - lambda: ESP_LOGI("core_hw_touch", "Released"); - script.execute: touch_on_release on_swipe_left: @@ -399,12 +421,12 @@ tx_ultimate_easy: domain: touch type: swipe action: !lambda |- - return sl_tx_model_format->state == "${TX_MODEL_FORMAT_US_TEXT}" ? "left" : "down"; + return sl_tx_model_format->state == "${TX_MODEL_FORMAT_EU_TEXT}" ? "left" : "down"; swipe-direction: !lambda |- - return sl_tx_model_format->state == "${TX_MODEL_FORMAT_US_TEXT}" ? "left" : "down"; + return sl_tx_model_format->state == "${TX_MODEL_FORMAT_EU_TEXT}" ? "left" : "down"; position: !lambda return touch.x; - lambda: |- - ESP_LOGI("tx_ultimate_easy", "Swipe %s", sl_tx_model_format->state == "${TX_MODEL_FORMAT_US_TEXT}" + ESP_LOGI("core_hw_touch", "Swipe %s", sl_tx_model_format->state == "${TX_MODEL_FORMAT_EU_TEXT}" ? "left" : "down"); - script.execute: touch_swipe_left @@ -418,21 +440,21 @@ tx_ultimate_easy: domain: touch type: swipe action: !lambda |- - return sl_tx_model_format->state == "${TX_MODEL_FORMAT_US_TEXT}" ? "right" : "up"; + return sl_tx_model_format->state == "${TX_MODEL_FORMAT_EU_TEXT}" ? "right" : "up"; swipe-direction: !lambda |- - return sl_tx_model_format->state == "${TX_MODEL_FORMAT_US_TEXT}" ? "right" : "up"; + return sl_tx_model_format->state == "${TX_MODEL_FORMAT_EU_TEXT}" ? "right" : "up"; position: !lambda return touch.x; - lambda: |- - ESP_LOGI("tx_ultimate_easy", "Swipe %s", sl_tx_model_format->state == "${TX_MODEL_FORMAT_US_TEXT}" + ESP_LOGI("core_hw_touch", "Swipe %s", sl_tx_model_format->state == "${TX_MODEL_FORMAT_EU_TEXT}" ? "right" : "up"); - script.execute: touch_swipe_right on_touch_event: - lambda: |- - ESP_LOGD("tx_ultimate_easy", "Touch event:"); - ESP_LOGD("tx_ultimate_easy", " State: %i (%s)", touch.state, touch.state_str.c_str()); - ESP_LOGD("tx_ultimate_easy", " Position: %i", touch.x); + ESP_LOGD("core_hw_touch", "Touch event:"); + ESP_LOGD("core_hw_touch", " State: %i (%s)", touch.state, touch.state_str.c_str()); + ESP_LOGD("core_hw_touch", " Position: %i", touch.x); uart: - id: uart_touch diff --git a/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_vibration.yaml b/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_vibration.yaml deleted file mode 100644 index 67655c1..0000000 --- a/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_vibration.yaml +++ /dev/null @@ -1,137 +0,0 @@ -#################################################################################################### -##### TX Ultimate Easy for ESPHome ##### -##### Repository: https://github.com/edwardtfn/TX-Ultimate-Easy ##### -#################################################################################################### -##### Purpose: ESPHome Core - Hardware - Vibration system ##### -#################################################################################################### -##### Author: edwardtfn - https://github.com/edwardtfn - https://buymeacoffee.com/edwardfirmo ##### -#################################################################################################### -##### NOTE: ##### -##### - Make changes ONLY if absolutely necessary and you have the required knowledge. ##### -##### - For normal system use, modifications to this file are NOT required. ##### -#################################################################################################### ---- -substitutions: - vibration_max_duration: 2s - -binary_sensor: - - id: bs_vibrating - name: Vibrating - icon: mdi:vibrate - internal: false - platform: template - lambda: return sw_vibration_motor->state; - -button: - - id: bt_vibrate - name: Vibrate - icon: mdi:vibrate - internal: false - platform: template - on_press: - then: - - script.execute: vibrate - -number: - - id: nr_vibrating_duration - name: Vibrate duration - icon: mdi:vibrate - unit_of_measurement: ms - internal: false - entity_category: config - platform: template - min_value: 1 - max_value: 500 - step: 1 - initial_value: 15 - optimistic: true - restore_value: true - -ota: - on_state_change: - then: - - switch.turn_off: sw_vibration_motor - -script: - - id: !extend touch_on_multi_touch_release - then: - - script.execute: touch_on_multi_touch_release_vibration - - - id: touch_on_multi_touch_release_vibration - mode: restart - then: - - lambda: |- - if (sl_touch_vibration_feedback->state != "Disabled") - vibrate->execute(); - - - id: !extend touch_on_press - then: - - script.execute: touch_on_press_vibration - - - id: touch_on_press_vibration - mode: restart - then: - - lambda: |- - if (sl_touch_vibration_feedback->state == "On press" or sl_touch_vibration_feedback->state == "Always") - vibrate->execute(); - - - id: !extend touch_on_release - then: - - script.execute: touch_on_release_vibration - - - id: touch_on_release_vibration - mode: restart - then: - - lambda: |- - if (sl_touch_vibration_feedback->state == "On release" or sl_touch_vibration_feedback->state == "Always") - vibrate->execute(); - - - id: vibrate - mode: restart - then: - - switch.turn_on: sw_vibration_motor - - delay: !lambda return nr_vibrating_duration->state; - - switch.turn_off: sw_vibration_motor - -select: - - id: sl_touch_vibration_feedback - name: Touch - Vibration feedback - platform: template - options: - - "Disabled" - - "On press" - - "On release" - - "Always" - initial_option: "Disabled" - optimistic: true - restore_value: true - internal: false - entity_category: config - disabled_by_default: false - icon: mdi:vibrate - -switch: - - id: sw_vibration_motor - name: Vibration motor - platform: gpio - pin: GPIO21 - restore_mode: ALWAYS_OFF - internal: true - on_turn_on: - then: - - binary_sensor.template.publish: - id: bs_vibrating - state: ON # yamllint disable-line rule:truthy - - delay: ${vibration_max_duration} - - if: - condition: - switch.is_on: sw_vibration_motor - then: - - switch.turn_off: sw_vibration_motor - on_turn_off: - then: - - binary_sensor.template.publish: - id: bs_vibrating - state: OFF # yamllint disable-line rule:truthy - -... diff --git a/README.md b/README.md index 4918684..c7f64d0 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,10 @@ [![Discord][discord-shield]](https://discord.gg/Db6WJWzWuf) [![Buy me an ice-cream][buymeacoffee-shield]](https://www.buymeacoffee.com/edwardfirmo) - -|  ![TX Ultimate Easy Logo](Assets/Logo.webp) | TX Ultimate Easy provides custom ESPHome firmware for Sonoff TX Ultimate devices. Our project focuses on user-friendly configuration through the Home Assistant UI, eliminating the need for manual YAML editing. Whether you're new to home automation or an experienced user, TX Ultimate Easy makes it simple to manage your device. | + +|  TX Ultimate Easy Logo | TX Ultimate Easy provides custom ESPHome firmware for Sonoff TX Ultimate devices. Our project focuses on user-friendly configuration through the Home Assistant UI, eliminating the need for manual YAML editing. Whether you're new to home automation or an experienced user, TX Ultimate Easy makes it simple to manage your device. | | --- | :-- | - + [version-shield]: https://img.shields.io/github/v/tag/edwardtfn/TX-Ultimate-Easy?label=version [version]: https://github.com/edwardtfn/TX-Ultimate-Easy/tags @@ -92,12 +92,210 @@ Before getting started, ensure you have: ## Installation -Detailed installation instructions coming soon. The process will include: +Follow these steps to get your TX Ultimate device up and running with ESPHome. -1. Initial ESPHome setup -2. Device flashing -3. Home Assistant integration -4. Basic configuration +### ESPHome Integration Setup + +1. Install the ESPHome add-on in Home Assistant if not already installed: + - Go to Settings → Add-ons → Add-on Store + - Search for "ESPHome" + - Click Install +2. Start the ESPHome add-on and verify it's running +3. Access ESPHome dashboard through Home Assistant + +### Setup Device + +1. In the ESPHome dashboard, click "+ New Device" +2. Name your device (e.g., "tx-ultimate-living-room") +3. Select ESP32 as your device type +4. Copy this basic configuration to your new device: + ```yaml + substitutions: + name: tx-ultimate-easy + friendly_name: TX Ultimate Easy + + wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password + + packages: + remote_package: + url: https://github.com/edwardtfn/TX-Ultimate-Easy + ref: stable # Or you can specify a version, like `ref: v2024.12.6` or `ref: latest` to the latest non-stable + refresh: 5min + files: + - ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml # Core (essential) packages + - ESPHome/TX-Ultimate-Easy-ESPHome_standard.yaml # Non-essential, but recommended packages + # - ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml # Adds BLE proxy support + ``` + You can also use a specific version tag for better control over updates: + ```yaml + ref: v2024.12.2 # Using specific version for controlled updates + ``` + **Notes:** + - [Click here](https://github.com/edwardtfn/TX-Ultimate-Easy/tags) for a full list of versions available. + - [Click here](TX-Ultimate-Easy-ESPHome.yaml) + for the latest version of this yaml. +5. Click "Save" and then "Install" + +> [!IMPORTANT] +> Starting from version 2025.1.0, non-essential components like `web_server`, `captive_portal`, and `wifi` +> are no longer included in the core package. If you need these components, +> you must add them manually to your local configuration file. +> For example: +> ```yaml +> # Add these to your configuration if needed +> web_server: +> captive_portal: +> wifi: +> ap: # Access point configuration +> ``` + +### Advanced Settings +For more granular control over components, +you can use our [advanced configuration template](TX-Ultimate-Easy-ESPHome_advanced.yaml). +This template allows you to selectively include specific packages, which can be useful for: + +- Troubleshooting specific components +- Reducing memory usage by excluding unused features +- Customizing functionality for specific use cases + +Here's an example of the advanced configuration: +```yaml +packages: + remote_package: + url: https://github.com/edwardtfn/TX-Ultimate-Easy + ref: stable # Or you can specify a version, like `ref: v2024.12.6` or `ref: latest` to the latest non-stable + refresh: 5min + files: + # Core (essential) packages + - ESPHome/TX-Ultimate-Easy-ESPHome_core_common.yaml # Basic shared settings + - ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_buttons.yaml # Button logic + - ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_leds.yaml # LED configuration + - ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_touch.yaml # Touch panel support + + # Optional but recommended packages + - ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_relays.yaml # Relay control + - ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_vibration.yaml # Haptic feedback + + # Audio options (use none or choose only one - using both will fail) + - ESPHome/TX-Ultimate-Easy-ESPHome_standard_media_player.yaml # Media player (Recommended for most users) + # - ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_speaker.yaml # Basic speaker +``` + +> [!NOTE] +> Use the advanced configuration with caution. Excluding core packages may cause instability or reduced functionality. + +### Device Flashing + +Initial flashing must be done via serial connection. +We recommend using [ESPHome Web](https://web.esphome.io) for the simplest experience. + + +> [!IMPORTANT] +> **SAFETY WARNINGS** +> - ALWAYS disconnect the device from mains power before opening +> - NEVER work on the device while connected to mains power +> - Ensure the device is completely powered off before making any connections +> - Keep your workspace clean, dry, and static-free +> - Use proper insulated tools when working with electronics +> - If unsure about any step, seek help from an experienced person + +> [!CAUTION] +>⚡ **CRITICAL: VOLTAGE WARNING** +> Using a UART adapter with voltage higher than 3.3V WILL DAMAGE YOUR DEVICE. +> Double-check your adapter's voltage before connecting - many common FTDI adapters +> default to 5V which will permanently damage the ESP32 chip. + + +#### Required Hardware +- USB-to-UART adapter: + - 3.3V logic level ONLY (DO NOT use 5V adapters) + - Must be capable of supplying at least 500mA + - Common adapters: CP2102, CH340, FTDI (ensure 3.3V setting) +- Small Phillips screwdriver +- 5 wires for connections (including one for BOOT to GND) + +#### Flashing Process +1. Open your TX Ultimate device carefully +2. Locate the programming header pins +3. Connect your USB-to-UART adapter: + + | Adapter | Device | + |---------|--------| + | GND | GND | + | 3.3V | 3.3V | + | TX | RX | + | RX | TX | + +4. Put device in flash mode: + - Temporarily connect the BOOT pin to GND using a jumper wire + - While holding BOOT to GND, power up the device + - After device powers up (wait a couple of seconds), remove the BOOT to GND connection +5. Visit [ESPHome Web](https://web.esphome.io) +6. Connect to your device and flash the firmware +7. After successful flash, device will restart and be ready for OTA updates + +#### Detailed Visual Guides + +For step-by-step visual instructions, you can reference these existing guides: +- 🇬🇧 [WirelessThings Guide](https://wirelessthings.io/index.php/2023/12/19/how-to-flash-sonoff-tx-ultimate-with-esphome/) - English guide with detailed photos +- 🇪🇸 [Un loco y su tecnología](https://youtu.be/58v8oqSQgXQ?t=143) - Spanish video tutorial +- 🇩🇪 [SmartHome yourself](https://youtu.be/naDLhX89enQ?t=465) - German video tutorial + + +Note: While these guides may use different firmware, the physical flashing process remains the same. + +#### Subsequent Updates +After initial flashing, all future updates can be done wirelessly (OTA) +through the ESPHome dashboard in your ESPHome add-on. + +### Home Assistant Integration + +After successful flashing: +1. Ensure your device and Home Assistant are on the same network +2. Device should be automatically discovered within 1–2 minutes +3. Accept the discovery notification in Home Assistant to add device + Note: If discovery takes longer than 5 minutes, proceed to troubleshooting steps +4. Device will appear in your Home Assistant Devices dashboard + +#### Troubleshooting Integration +If the device isn't discovered automatically: +1. Verify your device is powered and connected to your network: + - Look for the device in your router's client list + - Consider using [manual IP](https://esphome.io/components/wifi.html#manual-ips) in your device +2. If you missed the discovery notification: + - Go to Settings → Devices & Services + - Click "Add Integration" + - Search for "ESPHome" and enter your device's IP address +3. Still having issues? + - Check your network allows mDNS/discovery traffic + - Verify there are no VLANs or network isolation preventing communication + - Try rebooting both the device and Home Assistant + +### Initial Configuration + +1. In Home Assistant, navigate to: + - Settings → Devices & Services → ESPHome + - Click on your device to access its configuration page +2. Set basic device parameters: + - Model format (EU/US) + - Number of gangs (1-4) + - Relay modes (switch/light) + - Button actions +3. Optional: Configure advanced features + - LED behaviors + - Touch sensitivity + - Haptic feedback + - Audio feedback +4. Test your configuration: + - Verify each relay responds to controls + - Test configured button actions + - Confirm LED behavior matches settings + - Check haptic/audio feedback if enabled + +> [!NOTE] +> Some changes may require a device restart ## Usage @@ -154,8 +352,11 @@ Note: For proper tracking and resolution: This project builds upon the work of several amazing projects and contributors: + - [SmartHome yourself - SONOFF TX Ultimate for ESPHome](https://github.com/SmartHome-yourself/sonoff-tx-ultimate-for-esphome) - [Un loco y su tecnología - Sonoff TX Ultimate with ESPHome](https://www.youtube.com/watch?v=58v8oqSQgXQ) +- [@PxPert](https://github.com/PxPert) - [Sonoff TX Ultimate and Voice Assistant](https://community.home-assistant.io/t/sonoff-tx-ultimate-and-voice-assistant/682214?u=edwardtfn) + Special thanks to all contributors and community members who help make this project better. @@ -166,5 +367,9 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file --- -TX Ultimate Easy Logo + + + + TX Ultimate Easy Logo + diff --git a/TX-Ultimate-Easy-ESPHome.yaml b/TX-Ultimate-Easy-ESPHome.yaml index 9823def..6653f8e 100644 --- a/TX-Ultimate-Easy-ESPHome.yaml +++ b/TX-Ultimate-Easy-ESPHome.yaml @@ -16,9 +16,10 @@ wifi: packages: remote_package: url: https://github.com/edwardtfn/TX-Ultimate-Easy - ref: latest # Or you can specify a version, like `ref: v2024.12.6` + ref: stable # Or you can specify a version, like `ref: v2024.12.6` or `ref: latest` to the latest non-stable refresh: 5min files: - - ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml - # - ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml # Adds experimental BLE proxy support (limited) + - ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml # Core (essential) packages + - ESPHome/TX-Ultimate-Easy-ESPHome_standard.yaml # Non-essential, but recommended packages + # - ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml # Adds BLE proxy support ... diff --git a/components/tx_ultimate_easy/__init__.py b/components/tx_ultimate_easy/__init__.py index 7120ead..f8ec729 100644 --- a/components/tx_ultimate_easy/__init__.py +++ b/components/tx_ultimate_easy/__init__.py @@ -1,11 +1,12 @@ import esphome.codegen as cg import esphome.config_validation as cv +from esphome import automation from esphome.components import uart +from esphome.components.esp32 import add_idf_sdkconfig_option from esphome.const import ( CONF_ID, ) - -from esphome import automation +from esphome.core import CORE CODEOWNERS = ["@edwardtfn"] DEPENDENCIES = ['uart'] @@ -109,3 +110,17 @@ async def to_code(config): await cg.register_component(var, config) await uart.register_uart_device(var, config) await register_tx_ultimate_easy(var, config) + + if CORE.using_esp_idf: + add_idf_sdkconfig_option("CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST", True) + add_idf_sdkconfig_option("CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY", True) + add_idf_sdkconfig_option("CONFIG_ESP32_REV_MIN_3", True) + add_idf_sdkconfig_option("CONFIG_MBEDTLS_DYNAMIC_BUFFER", True) + add_idf_sdkconfig_option("CONFIG_MBEDTLS_DYNAMIC_FREE_CA_CERT", True) + add_idf_sdkconfig_option("CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA", True) + add_idf_sdkconfig_option("CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC", True) + add_idf_sdkconfig_option("CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY", True) + add_idf_sdkconfig_option("CONFIG_SPIRAM_RODATA", True) + add_idf_sdkconfig_option("CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP", True) + + cg.add_define("USE_TX_ULTIMATE_EASY") diff --git a/components/tx_ultimate_easy/tx_ultimate_easy.cpp b/components/tx_ultimate_easy/tx_ultimate_easy.cpp index 640f3db..d233abf 100644 --- a/components/tx_ultimate_easy/tx_ultimate_easy.cpp +++ b/components/tx_ultimate_easy/tx_ultimate_easy.cpp @@ -2,6 +2,7 @@ #include "esphome/core/log.h" #include "tx_ultimate_easy.h" +#include #include namespace esphome { @@ -68,9 +69,9 @@ namespace esphome { if (this->gang_count_ == 1) return 1; - // Calculate button number - const uint8_t width = (TOUCH_MAX_POSITION + 1) / this->gang_count_; // Width of each button region - if (width < 1 or width > this->gang_count_) // Invalid width - and prevents division by zero + //Calculate button number Change to round up insted of truncate (integer division) + const uint8_t width = (TOUCH_MAX_POSITION + gang_count_) / this->gang_count_; // Width of each button region + if (width < 1) // Invalid width - and prevents division by zero removed "width > gang_count_" issue with 2 gang return 0; const uint8_t button = std::min( static_cast((position / width) + 1), // Convert position to button index diff --git a/versioning/VERSION b/versioning/VERSION index a31cabd..98c8c87 100644 --- a/versioning/VERSION +++ b/versioning/VERSION @@ -1 +1 @@ -2024.12.12 +2025.3.1 diff --git a/versioning/VERSION_YAML b/versioning/VERSION_YAML index d4b581e..88f704d 100644 --- a/versioning/VERSION_YAML +++ b/versioning/VERSION_YAML @@ -1 +1 @@ -version: 2024.12.12 +version: 2025.3.1