Compare commits

..

177 Commits

Author SHA1 Message Date
GitHub Actions
ffdb3a22b5 Bump version to 2025.7.1 [skip-versioning] 2025-07-09 22:42:27 +00:00
Edward Firmo
b426bdd5dc Merge pull request #111 from edwardtfn/remove-duplicated-names
Support to ESPHome 2025.7.0
2025-07-10 00:42:19 +02:00
Edward Firmo
3cdd9f87af Standardize std::to_string 2025-07-10 00:29:34 +02:00
Edward Firmo
ddb26cd833 Test with recommended IDF only 2025-07-10 00:13:56 +02:00
Edward Firmo
5ea4f2015b Support to ESPHome 2025.7.0
- Resolve duplicated names
- Rebuilt HA event calls
2025-07-09 23:36:54 +02:00
GitHub Actions
ddb5e0f783 Bump version to 2025.5.1 [skip-versioning] 2025-05-14 19:19:50 +00:00
Edward Firmo
ab078f597a Merge pull request #106 from edwardtfn/dev
Remove enforcing psram mode to octal
2025-05-14 21:19:39 +02:00
Edward Firmo
5eb42082db Remove rmt_channel
Not supported with IDF 5
2025-05-14 21:07:07 +02:00
Edward Firmo
b1a978b3f3 Remove rmt_channel
Not supported with IDF 5
2025-05-14 20:57:58 +02:00
Edward Firmo
4ec44e611f Merge branch 'main' into dev 2025-05-02 18:30:35 +02:00
Edward Firmo
4d7895a2e9 Remove enforcing psram mode to octal
Solves #105
2025-05-02 18:29:07 +02:00
GitHub Actions
be76ebd603 Bump version to 2025.3.1 [skip-versioning] 2025-03-21 19:08:53 +00:00
Edward Firmo
49a0f088e7 Merge pull request #101 from edwardtfn/edwardtfn-patch-1
Remove reference to tj-actions
2025-03-21 20:08:45 +01:00
Edward Firmo
ace945a4ea Update validate_yamllint.yml 2025-03-15 18:23:25 +01:00
Edward Firmo
e944cd2c21 Remove reference to tj-actions
Security reasons
2025-03-15 18:19:32 +01:00
GitHub Actions
1cf6f60c78 Bump version to 2025.1.4 [skip-versioning] 2025-01-07 07:49:22 +00:00
Edward Firmo
58ba5e0136 Merge pull request #92 from edwardtfn/fix-name-CORE-is-not-defined
Fix missing `add_idf_sdkconfig_option`
2025-01-07 08:49:12 +01:00
Edward Firmo
b0b19fee45 Fix missing add_idf_sdkconfig_option 2025-01-07 08:48:38 +01:00
GitHub Actions
fe222ffe32 Bump version to 2025.1.3 [skip-versioning] 2025-01-07 07:17:53 +00:00
Edward Firmo
bb09d7f7f7 Merge pull request #91 from edwardtfn/fix-name-CORE-is-not-defined
Fix `name 'CORE' is not defined`
2025-01-07 08:17:42 +01:00
Edward Firmo
b6e3f41952 Fix name 'CORE' is not defined 2025-01-07 08:15:27 +01:00
GitHub Actions
ba3fc89032 Bump version to 2025.1.2 [skip-versioning] 2025-01-06 16:01:26 +00:00
Edward Firmo
fcbc92aaec Merge pull request #88 from edwardtfn/revert-to-media-player-as-default
Revert to media player and neopixelbus as default
2025-01-06 17:01:15 +01:00
GitHub Actions
a59f667e7d Bump version to 2025.1.1 [skip-versioning] 2025-01-06 16:00:59 +00:00
Edward Firmo
ff3bf05ed1 Merge pull request #90 from Matthijs33/patch-1
Fix value for multi_touch event publishing
2025-01-06 17:00:46 +01:00
Edward Firmo
8a4009dd7e Move sdkconfig_options to component 2025-01-05 12:58:45 +01:00
Edward Firmo
6bdf6e97b7 Move sdkconfig to component 2025-01-05 12:51:22 +01:00
Edward Firmo
acb602c4ca Lint 2025-01-05 12:44:48 +01:00
Edward Firmo
9bae016573 Lint 2025-01-05 12:43:08 +01:00
Edward Firmo
e47726dc47 Advanced settings with granular package selection
Resolves #86
2025-01-05 12:40:52 +01:00
Edward Firmo
5988681132 Include common 2025-01-05 11:02:46 +01:00
Edward Firmo
5d80ce1117 Do not remove attributes twice 2025-01-05 01:34:18 +01:00
Edward Firmo
036e62b277 Remove check for framework type 2025-01-05 01:06:52 +01:00
Edward Firmo
56c613a70f Remove sw_speaker_amplifier when the media_player is removed 2025-01-05 00:54:48 +01:00
Edward Firmo
12fd2d3747 Lint 2025-01-05 00:38:30 +01:00
Edward Firmo
81f0420987 Lint 2025-01-05 00:37:05 +01:00
Edward Firmo
e89adca5cb Remove reference to esphome_fw_version 2025-01-05 00:34:40 +01:00
Edward Firmo
a64c45b37b Media Player is not compatible with IDF 2025-01-04 23:58:05 +01:00
Edward Firmo
95291c0381 Remove non-essential packages 2025-01-04 23:54:35 +01:00
Edward Firmo
39cf0f2b10 Do not remove media player from core 2025-01-04 22:58:09 +01:00
Edward Firmo
8d03105caf Reorg tests 2025-01-04 22:54:08 +01:00
Edward Firmo
e911482deb Lint 2025-01-04 22:39:31 +01:00
Edward Firmo
ef4f412223 Split extensions 2025-01-04 22:38:19 +01:00
Edward Firmo
9d64b099a4 Lint 2025-01-04 22:34:38 +01:00
Edward Firmo
037801e961 Revert to media player and neopixelbus 2025-01-04 22:31:14 +01:00
Edward Firmo
79b57304c7 Point users to stable tag. 2025-01-03 22:53:46 +01:00
Matthijs33
48ddfbf8b0 Update TX-Ultimate-Easy-ESPHome_core_hw_touch.yaml
fixes #74
Value was "OFF" instead of "ON"
2025-01-01 14:32:17 +01:00
GitHub Actions
2e43160acb Bump version to 2024.12.27 [skip-versioning] 2024-12-28 00:11:36 +00:00
Edward Firmo
8656d0c4ca Merge pull request #81 from skykingjwc/patch-1
Update README.md
2024-12-28 01:11:26 +01:00
Jordan W. Cobb
133d571874 Update README.md
Corrected path to TX-Ultimate-Easy-ESPHome.yaml
2024-12-27 17:39:05 -05:00
GitHub Actions
1489bc5237 Bump version to 2024.12.26 [skip-versioning] 2024-12-27 10:12:23 +00:00
Edward Firmo
11b21de8a9 Merge pull request #80 from edwardtfn/adaptative-logo
Adaptative logo
2024-12-27 11:12:12 +01:00
Edward Firmo
e8346e4436 Revert the new line thing
It broke the visual
2024-12-27 11:09:11 +01:00
Edward Firmo
e3abc6c6d5 Split table in lines 2024-12-27 11:07:31 +01:00
Edward Firmo
3e847bbd4a Allow for Inline HTML 2024-12-27 11:05:12 +01:00
Edward Firmo
ba69b43688 Adaptative logo 2024-12-27 11:02:25 +01:00
GitHub Actions
f84b9af1ee Bump version to 2024.12.25 [skip-versioning] 2024-12-27 09:42:29 +00:00
Edward Firmo
9fa79bbde6 Merge pull request #79 from edwardtfn/install-instructions
Add install instructions
2024-12-27 10:42:19 +01:00
Edward Firmo
8a343ab8fe CodeRabbitAI 2024-12-27 10:39:51 +01:00
Edward Firmo
b5a96387cb Update README.md 2024-12-27 10:35:10 +01:00
Edward Firmo
8b7fad76c1 Update README.md 2024-12-27 10:34:45 +01:00
Edward Firmo
a224cd5f86 Indentation on note 2024-12-27 10:33:24 +01:00
Edward Firmo
da9dfbf808 Remove duplicated section label 2024-12-27 10:31:57 +01:00
Edward Firmo
bd5091293e Remove numbered sections 2024-12-27 10:29:50 +01:00
Edward Firmo
05c40cf7b5 Pinout in a table and test instructions 2024-12-27 10:24:39 +01:00
Edward Firmo
ebd8a5432a Minor changes as suggested by CodeRabbitAI 2024-12-27 10:20:24 +01:00
Edward Firmo
0779279d44 Add dynamic version example 2024-12-27 10:10:26 +01:00
Edward Firmo
09514e1331 Disable markdown lint 2024-12-27 10:04:14 +01:00
Edward Firmo
b7a66b2e87 Adding warnings 2024-12-27 10:02:05 +01:00
Edward Firmo
4266a7cdd8 Add a bit more of details
As suggested by CodeRabbitAI
2024-12-27 09:48:52 +01:00
Edward Firmo
40f8165d5c Fix link to reference in English 2024-12-27 09:30:55 +01:00
Edward Firmo
d3d5c21d38 Add install instructions 2024-12-27 09:27:13 +01:00
GitHub Actions
4b1aed33ef Bump version to 2024.12.24 [skip-versioning] 2024-12-27 02:53:35 +00:00
Edward Firmo
72a666cd3c Merge pull request #78 from edwardtfn/test-any-folder
Match any file with the extensions in any directory
2024-12-27 03:53:25 +01:00
Edward Firmo
5255912fcf Match any file with the extensions in any directory 2024-12-27 03:49:39 +01:00
GitHub Actions
c50bd5ca16 Bump version to 2024.12.23 [skip-versioning] 2024-12-27 02:40:01 +00:00
Edward Firmo
6313709fd5 Merge pull request #77 from edwardtfn/expose-relays-lights
Set relays lights to not be disabled when exposed
2024-12-27 03:39:51 +01:00
Edward Firmo
b431041b15 Set relays lights to not be disabled when exposed
Resolves #75
2024-12-27 03:37:09 +01:00
GitHub Actions
9fad193892 Bump version to 2024.12.22 [skip-versioning] 2024-12-27 02:32:14 +00:00
Edward Firmo
e6bf60555d Merge pull request #73 from edwardtfn/reorg-add-ons
Reorganize project's files
2024-12-27 03:32:03 +01:00
Edward Firmo
6a12074b71 Merge branch 'main' into reorg-add-ons 2024-12-27 03:29:36 +01:00
Edward Firmo
fee446c5e2 Specify permissions and trigger's files types 2024-12-27 03:12:29 +01:00
Edward Firmo
088213137f Do not try media player and speaker together 2024-12-27 02:55:27 +01:00
Edward Firmo
02c7c1aff1 Remove media player test with idf 5.3 2024-12-27 02:47:00 +01:00
Edward Firmo
3401aaf4a3 Add tests with hw_vibration 2024-12-27 02:42:36 +01:00
Edward Firmo
f154a483cc Run tests when test script changes 2024-12-27 02:36:47 +01:00
Edward Firmo
b69bc6916b Comments only 2024-12-27 02:33:52 +01:00
Edward Firmo
9d0fcf6bfa Test Media Player with Arduino 2024-12-27 02:30:52 +01:00
Edward Firmo
fa516a66cc Add HW Speaker tests 2024-12-27 02:27:48 +01:00
Edward Firmo
2811eedffb Bump version 2024-12-27 02:23:24 +01:00
Edward Firmo
0c9a5ac65e Rebuild tone_volume_change play on volume change
IDF v5.3 compatibility
2024-12-27 02:19:59 +01:00
Edward Firmo
9828b6ff8a Add tests core+hw_relays 2024-12-27 02:15:51 +01:00
Edward Firmo
6221e109e8 Rename speaker file 2024-12-27 02:08:11 +01:00
Edward Firmo
3d21c2ebcb Add cinttypes 2024-12-27 02:02:01 +01:00
Edward Firmo
7d12ddb0e5 Add WiFi SSID 2024-12-27 01:56:39 +01:00
Edward Firmo
ea12c1d422 Lint 2024-12-27 01:48:58 +01:00
Edward Firmo
c73cb950eb lint 2024-12-27 01:48:04 +01:00
Edward Firmo
e69873cab5 Create standard package 2024-12-27 01:42:41 +01:00
Edward Firmo
d4a18dc595 Play sound at volume change 2024-12-26 23:57:21 +01:00
Edward Firmo
45b30d30fa Removed reference to experimental i2s format 2024-12-26 22:17:45 +01:00
Edward Firmo
d656f4b73f Lint 2024-12-26 22:13:27 +01:00
Edward Firmo
493dcb0abb Lint 2024-12-26 22:09:48 +01:00
Edward Firmo
f8fa9a2363 Lint 2024-12-26 22:08:10 +01:00
Edward Firmo
47744c7144 More changes covered by build test 2024-12-26 22:06:09 +01:00
Edward Firmo
fa2c5dcc29 Lint 2024-12-26 22:01:56 +01:00
Edward Firmo
3cf6a11bc7 Add Speaker amplifier switch and removed click sound from substitutions 2024-12-26 21:59:31 +01:00
GitHub Actions
0109771731 Bump version to 2024.12.20 [skip-versioning] 2024-12-26 20:36:19 +00:00
Edward Firmo
b7df1686b6 Merge pull request #76 from arnonh/main
Fix for 4 gang button position
2024-12-26 21:36:10 +01:00
arnonh
c22d8eb847 Update tx_ultimate_easy.cpp
Fix for 4 gang button position
calculation reflects better the old positions
2024-12-26 21:13:22 +02:00
Edward Firmo
f3b84e9d4e Fix calls to speaker_play_click 2024-12-26 00:27:48 +01:00
Edward Firmo
81c6620fbf Split files even more 2024-12-25 23:01:33 +01:00
GitHub Actions
4378952d97 Bump version to 2024.12.19 [skip-versioning] 2024-12-25 02:06:44 +00:00
Edward Firmo
876d03ace5 Merge pull request #72 from edwardtfn/dump-config
Add dump config
2024-12-25 03:06:35 +01:00
Edward Firmo
5ddf5388bd Handle unknown states 2024-12-25 03:00:56 +01:00
Edward Firmo
7aee88c38f CodeRabbitAI suggestions 2024-12-25 02:34:18 +01:00
Edward Firmo
e546fedf08 Add dump config
To help troubleshooting
2024-12-25 02:11:10 +01:00
GitHub Actions
cca59bbe2a Bump version to 2024.12.18 [skip-versioning] 2024-12-25 00:45:08 +00:00
Edward Firmo
aec1aa69d3 Merge pull request #71 from edwardtfn/expose-relay-indicator-leds
Expose relay-indicator LEDs
2024-12-25 01:44:54 +01:00
Edward Firmo
bcf4396c6f Split boot_initialize_relays script 2024-12-25 00:01:57 +01:00
Edward Firmo
403cdce2b5 Expose relay-indicator LEDs
The lights will be available on Home Assistant, so users will be able to set it's color and brightness, then this will be used when the relay turn on-off as the indicator for the relay status.
Resolves #57
2024-12-24 23:31:50 +01:00
GitHub Actions
44b3586a17 Bump version to 2024.12.17 [skip-versioning] 2024-12-24 13:46:33 +00:00
Edward Firmo
93990e78c1 Merge pull request #63 from edwardtfn/button-failsafe-action
Adds "Relay n (API failsafe only)" to button's actions
2024-12-24 14:46:21 +01:00
GitHub Actions
e8470f56e4 Bump version to 2024.12.16 [skip-versioning] 2024-12-24 11:02:55 +00:00
Edward Firmo
2429c9d616 Merge pull request #70 from edwardtfn/swipe-log-messages
Fix swipe log messages
2024-12-24 12:02:45 +01:00
Edward Firmo
7a5a537847 Fix swipe log messages 2024-12-24 11:57:03 +01:00
GitHub Actions
2aa036dc0e Bump version to 2024.12.15 [skip-versioning] 2024-12-24 10:42:07 +00:00
Edward Firmo
802acdc476 Merge pull request #69 from edwardtfn/esphome-version
Add ESPHome Version sensor
2024-12-24 11:41:57 +01:00
Edward Firmo
37b2e93896 Sensor is diagnostic 2024-12-24 11:17:35 +01:00
Edward Firmo
695cca07a0 Add ESPHome Version sensor
And renames the TX Firmware, which resolves #66
2024-12-24 10:32:31 +01:00
GitHub Actions
f258b8f783 Bump version to 2024.12.14 [skip-versioning] 2024-12-24 09:06:47 +00:00
Edward Firmo
7e055e7737 Merge pull request #68 from edwardtfn/new-led-mapping-us-3gang
New LED mapping for US 3&4-Gang
2024-12-24 10:06:36 +01:00
Edward Firmo
9fec812b66 New LED mapping for 4-Gang US model 2024-12-24 09:59:54 +01:00
Edward Firmo
269ba89bd3 New LED mapping for US 3-Gang
Partially solves #67
2024-12-24 09:49:14 +01:00
Edward Firmo
a44e486411 Add Id to Wi-Fi component 2024-12-24 01:23:29 +01:00
Edward Firmo
c4b2b8917f Consider disconnected if wifi is disconnected
Trying to detect a disconnection earlier.
2024-12-24 01:17:00 +01:00
GitHub Actions
ae87f025a3 Bump version to 2024.12.13 [skip-versioning] 2024-12-23 23:28:41 +00:00
Edward Firmo
303a3f1267 Merge pull request #64 from edwardtfn/speaker-with-ble-proxy
Add speaker to BLE Proxy add-on
2024-12-24 00:28:31 +01:00
Edward Firmo
a716e8e9cf Change media player fmt to msb 2024-12-24 00:22:52 +01:00
Edward Firmo
d77d761497 Add speaker to BLE Proxy add-on 2024-12-24 00:00:26 +01:00
Edward Firmo
60a3248c6b Adds "Relay n (API failsafe only)" to button's actions
Solves #23
2024-12-23 20:30:32 +01:00
GitHub Actions
ec528ec128 Bump version to 2024.12.12 [skip-versioning] 2024-12-23 17:52:46 +00:00
Edward Firmo
4ed98e533f Merge pull request #62 from edwardtfn/test-only-on-pull
Run test only on pull request or push to main
2024-12-23 18:52:35 +01:00
Edward Firmo
1ef73d5cd0 Remove paths-ignore 2024-12-23 18:49:50 +01:00
Edward Firmo
420225b6ba Run test only on pull request or push to main 2024-12-23 18:47:41 +01:00
GitHub Actions
8996cfbdf8 Bump version to 2024.12.11 [skip-versioning] 2024-12-23 17:39:57 +00:00
Edward Firmo
085250c471 Merge pull request #61 from edwardtfn/light-restore-state-on-boot
Restore light state on boot
2024-12-23 18:39:47 +01:00
Edward Firmo
6230e31323 Fix inconsistent restore mode variable usage
As suggested by CodeRabbitAI
2024-12-23 18:34:05 +01:00
Edward Firmo
248f7e9cd8 Use substitutions instead 2024-12-23 18:28:58 +01:00
Edward Firmo
6343e6eb4a Restore light state on boot
Trying to solve #47
2024-12-23 18:21:32 +01:00
GitHub Actions
226d5db7c8 Bump version to 2024.12.10 [skip-versioning] 2024-12-23 11:54:54 +00:00
Edward Firmo
dbde1da920 Merge pull request #60 from edwardtfn/buttons-action-fix-01
Fix relay toggle when button action is set to none
2024-12-23 12:54:43 +01:00
Edward Firmo
f2ff037c82 Add a bit more verbose logs 2024-12-23 11:59:26 +01:00
Edward Firmo
82af8b6687 Fix relay toggle when button action is set to none
Solves #59
2024-12-23 11:48:31 +01:00
GitHub Actions
73ecbba3b2 Bump version to 2024.12.9 [skip-versioning] 2024-12-23 03:43:28 +00:00
Edward Firmo
eb1a3954a9 Merge pull request #56 from edwardtfn/new-events
New event handler
2024-12-23 04:43:16 +01:00
Edward Firmo
5d5a3d3e77 Typo 2024-12-23 04:37:53 +01:00
Edward Firmo
f9e9243de5 Specify device when setting gang count 2024-12-23 04:31:16 +01:00
Edward Firmo
be6a4a51e2 Use set_gang_count 2024-12-23 04:24:50 +01:00
Edward Firmo
2a8255b788 Use long_press and not long_click 2024-12-23 04:16:28 +01:00
Edward Firmo
a00e15fa85 lint 2024-12-23 03:59:29 +01:00
Edward Firmo
4ea7f1ee57 New event handler
This rebuild the engine to send events to Home Assistant
2024-12-23 03:55:50 +01:00
GitHub Actions
bd4f6836c9 Bump version to 2024.12.8 [skip-versioning] 2024-12-23 00:14:23 +00:00
Edward Firmo
98ea8810f8 Merge pull request #55 from edwardtfn/relay-on-light-mode
Fix relay on display as light mode
2024-12-23 01:14:09 +01:00
Edward Firmo
552b83f065 Re-add button ids on substitutions 2024-12-23 01:03:51 +01:00
Edward Firmo
ee6f565447 Change refresh to 5min 2024-12-23 00:59:17 +01:00
Edward Firmo
aa4e27ec35 Merge branch 'relay-on-light-mode' of https://github.com/edwardtfn/TX-Ultimate-Easy into relay-on-light-mode 2024-12-23 00:53:37 +01:00
Edward Firmo
8a509cedc8 Point to latest 2024-12-23 00:52:59 +01:00
Edward Firmo
ddea93af6a Merge branch 'main' into relay-on-light-mode 2024-12-23 00:50:29 +01:00
Edward Firmo
dc99319397 Fix relay id on log 2024-12-23 00:46:06 +01:00
Edward Firmo
5ae45fff63 Fix relay on display as light mode
Solves #28
2024-12-23 00:41:51 +01:00
GitHub Actions
bbbaeeb0d4 Bump version to 2024.12.7 [skip-versioning] 2024-12-22 23:02:49 +00:00
Edward Firmo
a9f82d958f Merge pull request #54 from edwardtfn/event-based-automation-docs
Event based automation docs
2024-12-23 00:02:40 +01:00
Edward Firmo
c07e4f195a CodeRabbitAI 2024-12-22 23:55:18 +01:00
Edward Firmo
f1f545198b CodeRabbitAI 2024-12-22 23:47:03 +01:00
Edward Firmo
d87b86bfca CodeRabbitAI 2024-12-22 23:41:02 +01:00
Edward Firmo
f11840d2bc markdownlint 2024-12-22 23:23:22 +01:00
Edward Firmo
42afe71365 Add event based automation overview
Helps with #51
2024-12-22 23:20:39 +01:00
49 changed files with 3303 additions and 1148 deletions

View File

@@ -1,8 +1,11 @@
---
name: Validate ESPHome
name: Validate ESPHome (Latest)
# yamllint disable-line rule:truthy
on:
permissions:
contents: read
pull-requests: read
on: # yamllint disable-line rule:truthy
workflow_dispatch:
concurrency:
@@ -28,33 +31,162 @@ 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_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:
build_idf_basic:
name: Basic (IDF)
needs: build_idf_core
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
- name: Build Basic (IDF)
uses: esphome/build-action@main
with:
yaml-file: ".test/esphome_idf_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_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_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_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 core
- name: Build BLE Proxy (IDF)
uses: esphome/build-action@main
with:
yaml-file: ".test/esphome_idf_bluetooth_proxy.yaml"
yaml-file: ".test/esphome_idf_ble_proxy.yaml"
version: latest
build_bluetooth_proxy_53:
name: Bluetooth Proxy (IDF v5.3)
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 core
- name: Build Media Player (Ard)
uses: esphome/build-action@main
with:
yaml-file: ".test/esphome_idf53_bluetooth_proxy.yaml"
yaml-file: ".test/esphome_ard_media_player.yaml"
version: latest
...

View File

@@ -1,25 +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"
- "**/*.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:
@@ -45,36 +49,162 @@ 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_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_ard_hw_relays:
name: HW Relays (Arduino)
needs: build_ard_core
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
- name: Build core
- name: Build HW Relays (Arduino)
uses: esphome/build-action@main
with:
yaml-file: ".test/esphome_idf53_bluetooth_proxy.yaml"
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_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_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_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_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
...

View File

@@ -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'

View File

@@ -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

View File

@@ -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

5
.test/common.yaml Normal file
View File

@@ -0,0 +1,5 @@
---
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
...

8
.test/common_ard.yaml Normal file
View File

@@ -0,0 +1,8 @@
---
packages:
common: !include common.yaml
esp32:
framework:
type: arduino
...

18
.test/common_idf.yaml Normal file
View File

@@ -0,0 +1,18 @@
---
packages:
common: !include common.yaml
esp32:
framework:
type: esp-idf
light:
- id: !extend light_full
platform: esp32_rmt_led_strip
rgb_order: GRB
chipset: ws2812
max_refresh_rate: 33ms
use_psram: false
type: !remove
variant: !remove
...

10
.test/common_idf53.yaml Normal file
View File

@@ -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
...

View File

@@ -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
...

View File

@@ -1,5 +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
...

View File

@@ -0,0 +1,5 @@
---
packages:
common_arduino: !include common_ard.yaml
core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
...

View File

@@ -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
...

View File

@@ -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
...

View File

@@ -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
...

View File

@@ -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
...

View File

@@ -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
...

View File

@@ -1,11 +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
esp32:
framework:
type: esp-idf
version: 5.3.1
platform_version: 6.9.0
...

View File

@@ -0,0 +1,5 @@
---
packages:
common_idf: !include common_idf.yaml
core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
...

View File

@@ -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
...

View File

@@ -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
...

View File

@@ -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
...

BIN
Assets/Logo_dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

BIN
Assets/Logo_dark.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

BIN
Assets/Logo_light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@@ -0,0 +1,19 @@
####################################################################################################
##### TX Ultimate Easy for ESPHome #####
##### Repository: https://github.com/edwardtfn/TX-Ultimate-Easy #####
####################################################################################################
##### Purpose: ESPHome Basic (includes core plus non-essential, but recommended packages) #####
####################################################################################################
##### 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:
# yamllint disable rule:colons
core: !include TX-Ultimate-Easy-ESPHome_core.yaml
standard: !include TX-Ultimate-Easy-ESPHome_standard.yaml
# yamllint enable rule:colons
...

View File

@@ -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 # Not supported with IDF 5
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
...

View File

@@ -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
...

View File

@@ -11,183 +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_api: !include TX-Ultimate-Easy-ESPHome_core_api.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_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
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: boot_done
mode: restart
then:
- script.execute:
id: send_event_to_ha
component: boot
event: done
- id: boot_initialize
mode: restart
then:
# Extended by:
# - HW Buttons
# - HW Relays
# - HW Touch
- script.execute:
id: send_event_to_ha
component: boot
event: 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
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:
...

View File

@@ -0,0 +1,324 @@
####################################################################################################
##### TX Ultimate Easy for ESPHome #####
##### Repository: https://github.com/edwardtfn/TX-Ultimate-Easy #####
####################################################################################################
##### Purpose: ESPHome Core - Common #####
####################################################################################################
##### 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:
name: tx-ultimate-easy
friendly_name: TX Ultimate Easy
<<: !include ../versioning/VERSION_YAML
EVENT_NAME: esphome.tx_ultimate_easy
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"
DUMP_CONFIG_CALLER_DELAY: 10s # Delay to dump config after requested
api:
id: api_server
on_client_connected:
then:
- script.execute: dump_config_caller
- script.execute: publish_device_info
binary_sensor:
- id: bs_pending_restart
name: Pending Restart Status
internal: false
disabled_by_default: false
platform: template
entity_category: diagnostic
device_class: problem
on_state:
then:
- lambda: |-
if (x)
ESP_LOGW("core", "Pending restart: YES");
else
ESP_LOGCONFIG("core", "Pending restart: No");
- script.execute: dump_config_caller
button:
- id: bt_restart
name: Restart
internal: false
platform: restart
esp32:
board: esp32dev
flash_size: 8MB
esphome:
name: ${name}
friendly_name: ${friendly_name}
comment: TX Ultimate Easy
project:
name: "edwardtfn.tx_ultimate_easy"
version: ${version}
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
globals:
- id: is_us_model
type: bool
restore_value: true
initial_value: 'false'
- id: gang_count
type: uint8_t
restore_value: true
initial_value: '0'
- id: gang_count_plural_suffix
type: std::string
restore_value: true
max_restore_data_length: 3
logger:
level: DEBUG
ota:
platform: esphome
psram:
script:
- id: api_send_ha_event_boot
mode: queued
parameters:
type: string
then:
- lambda: |-
// Send event to Home Assistant
esphome::api::CustomAPIDevice ha_event;
ha_event.fire_homeassistant_event("${EVENT_NAME}", {
{"device_name", id(tx_device_name).state.c_str()},
{"firmware", "${version}"},
{"domain", "boot"},
{"type", 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
- wait_until:
condition:
- lambda: return sl_tx_model_format->active_index().has_value();
- lambda: return sl_tx_model_gang->active_index().has_value();
- lambda: |-
id(is_us_model) = (sl_tx_model_format->state == "${TX_MODEL_FORMAT_US_TEXT}");
id(gang_count) = sl_tx_model_gang->active_index().value() + 1;
if (id(gang_count) < 1 || id(gang_count) > 4) {
ESP_LOGE("core_hw_leds", "Invalid number of gangs: %" PRIu8, id(gang_count));
}
id(gang_count_plural_suffix) = id(gang_count) > 1 ? "s" : "";
- id: boot_sequence
mode: restart
then:
- script.execute: publish_device_info
- binary_sensor.template.publish:
id: bs_pending_restart
state: false
- id: dump_config
mode: restart
then:
# Extended by all modules
- lambda: |-
// Device identification
ESP_LOGCONFIG("core", "Device friendly name: ${friendly_name}");
ESP_LOGCONFIG("core", "Device name: ${name}");
ESP_LOGCONFIG("core", "Device name (HA): %s", tx_device_name->state.c_str());
ESP_LOGCONFIG("core", "Device hostname: %s", App.get_name().c_str());
dump_config_versions->execute();
// Framework detection
#ifdef USE_ARDUINO
ESP_LOGCONFIG("core", "Framework: Arduino");
#elif defined(USE_ESP_IDF)
ESP_LOGCONFIG("core", "Framework: ESP-IDF");
#else
ESP_LOGW("core", "Framework: UNKNOWN");
#endif
// Model configuration
ESP_LOGCONFIG("core", "Model format (selected): %s", sl_tx_model_format->state.c_str());
ESP_LOGCONFIG("core", "Model format (detected): %s", id(is_us_model) ? "US" : "EU");
ESP_LOGCONFIG("core", "Gangs (selected): %s", sl_tx_model_gang->state.c_str());
ESP_LOGCONFIG("core", "Gangs (detected): %" PRIu8 "-Gang%s", id(gang_count), id(gang_count_plural_suffix).c_str());
// System state
if (bs_pending_restart->state)
ESP_LOGW("core", "Pending restart: YES");
else
ESP_LOGCONFIG("core", "Pending restart: No");
- id: dump_config_caller
mode: restart
then:
- delay: ${DUMP_CONFIG_CALLER_DELAY}
- script.execute: dump_config
- script.wait: dump_config
- script.execute: dump_config_list_packages
- id: dump_config_list_packages
mode: restart
then:
- script.wait: dump_config
- lambda: |-
ESP_LOGCONFIG(ESPHOME_PROJECT_NAME, "Installed packages:");
// Identify itself
ESP_LOGCONFIG(ESPHOME_PROJECT_NAME, " - Core");
- id: dump_config_versions
mode: restart
then:
- lambda: |-
// Version information
ESP_LOGCONFIG("core", "TX Ultimate firmware version: ${version}");
// ESPHome builder information
ESP_LOGCONFIG("core", "ESPHome builder: " ESPHOME_VERSION);
ESP_LOGCONFIG("core", "ESPHome build timestamp: %s", App.get_compilation_time().c_str());
- 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
on_value:
then:
- binary_sensor.template.publish:
id: bs_pending_restart
state: true
- lambda: |-
id(is_us_model) = (x == "${TX_MODEL_FORMAT_US_TEXT}");
ESP_LOGI("core", "New model selected: %s", id(is_us_model) ? "US" : "EU");
- 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:
- binary_sensor.template.publish:
id: bs_pending_restart
state: true
- lambda: |-
id(gang_count) = static_cast<uint8_t>(i) + 1;
ESP_LOGI("core", "New model selected: %" PRIu8 "-%s", id(gang_count), id(gang_count) > 1 ? "Gangs" : "Gang");
tx_ultimate->set_gang_count(id(gang_count));
text_sensor:
- id: tx_fw_version
name: TX Ultimate Easy 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;
wifi:
id: wifi_component
...

View File

@@ -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
@@ -26,6 +30,12 @@ substitutions:
BUTTON_PRESS_TIMEOUT: '10000' # Ignore if button is pressed for longer than this time, in msec
BUTTON_LONG_PRESS_DELAY: '800' # The time to wait to consider a long press, in msec
# Button numbers constants
BUTTON_1_ID: '1'
BUTTON_2_ID: '2'
BUTTON_3_ID: '3'
BUTTON_4_ID: '4'
binary_sensor:
- &binary_sensor_button_base
id: bs_button_2
@@ -47,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
@@ -76,59 +91,107 @@ 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
parameters:
component: string
event: string
button: uint8_t
action: string
count: uint8_t
then:
# Extended by:
# - core_api
- lambda: |-
ESP_LOGI("core_hw_buttons", "Button '%s' action: '%s'", component.c_str(), event.c_str());
// Send event to Home Assistant
esphome::api::CustomAPIDevice ha_event;
ha_event.fire_homeassistant_event("${EVENT_NAME}", {
{"device_name", id(tx_device_name).state.c_str()},
{"firmware", "${version}"},
{"domain", "touch"},
{"type", "button"},
{"action", action.c_str()},
{"button_id", std::to_string(button)},
{"count", std::to_string(count)},
{"position", std::to_string(id(button_press_position))}
});
ESP_LOGI("core_hw_buttons", "Button %" PRIu8 " action: '%s'", button, action.c_str());
if (action == "click") {
switch (button) {
case ${BUTTON_1_ID}:
bs_button_1_click_event->publish_state(true);
break;
case ${BUTTON_2_ID}:
bs_button_2_click_event->publish_state(true);
break;
case ${BUTTON_3_ID}:
bs_button_3_click_event->publish_state(true);
break;
case ${BUTTON_4_ID}:
bs_button_4_click_event->publish_state(true);
break;
}
} else if (action == "double_click") {
switch (button) {
case ${BUTTON_1_ID}:
bs_button_1_double_click_event->publish_state(true);
break;
case ${BUTTON_2_ID}:
bs_button_2_double_click_event->publish_state(true);
break;
case ${BUTTON_3_ID}:
bs_button_3_double_click_event->publish_state(true);
break;
case ${BUTTON_4_ID}:
bs_button_4_double_click_event->publish_state(true);
break;
}
} else if (action == "long_press") {
switch (button) {
case ${BUTTON_1_ID}:
bs_button_1_long_press_event->publish_state(true);
break;
case ${BUTTON_2_ID}:
bs_button_2_long_press_event->publish_state(true);
break;
case ${BUTTON_3_ID}:
bs_button_3_long_press_event->publish_state(true);
break;
case ${BUTTON_4_ID}:
bs_button_4_long_press_event->publish_state(true);
break;
}
}
id(button_press_button) = 0;
id(click_counter) = 0;
id(button_press_position) = 0;
id(button_press_start_time) = 0;
id(click_counter) = 0;
buttons_release->execute();
- id: button_click_event
mode: restart
parameters:
button_id: uint8_t
button: uint8_t
click_count: uint8_t
then:
- delay:
milliseconds: ${BUTTON_MULTI_CLICK_DELAY}
- lambda: |-
const std::string button_name = "bs_button_" + std::to_string(button_id);
std::string event_name;
if (click_count == 1) event_name = "click";
else if (click_count == 2) event_name = "double_click";
else event_name = std::to_string(click_count) + "_click";
button_action->execute(button_name.c_str(), event_name.c_str());
else event_name = "multiple_click";
button_action->execute(button, event_name.c_str(), click_count);
- id: buttons_release
mode: restart
@@ -143,6 +206,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
@@ -151,30 +249,24 @@ script:
then:
- script.execute:
id: touch_on_press_buttons
touch_position: !lambda return touch_position;
button: !lambda return button;
position: !lambda return position;
- id: touch_on_press_buttons
mode: restart
parameters:
touch_position: uint8_t
button: uint8_t
position: uint8_t
then:
- lambda: |-
id(button_press_start_time) = millis();
id(button_press_position) = touch_position;
uint8_t button = 0;
auto model_index = sl_tx_model_gang->active_index();
if (model_index.has_value()) {
const uint8_t model_idx = model_index.value() + 1; // Increment for 1-based indexing
if (model_idx == 1) {
button = 1; // Single button, always 1
} else {
const uint8_t width = ${TOUCH_POSITION_MAX_VALUE} / model_idx; // Width of each button region
ESP_LOGV("core_hw_buttons", "Button regions: width=%" PRIu8 ", touch_position=%" PRIu8,
width, touch_position);
button = (touch_position / width) + 1; // Determine button region
if (button > model_idx)
button = model_idx; // Clamp to max button count
}
id(button_press_button) = button;
// Update counters
if (id(button_press_position) == position) {
id(click_counter)++;
} else {
id(click_counter) = 1;
id(button_press_position) = position;
}
// Update binary sensor
switch (button) {
@@ -191,13 +283,6 @@ script:
bs_button_4->publish_state(true);
break;
}
// Update counters
if (id(button_press_button) == button) {
id(click_counter)++;
} else {
id(click_counter) = 1;
id(button_press_button) = button;
}
- id: !extend touch_on_release
then:
@@ -215,7 +300,7 @@ script:
press_duration <= ${BUTTON_CLICK_MAX_LENGTH}) { // Short/normal click
button_click_event->execute(id(button_press_button), id(click_counter));
} else if (press_duration >= ${BUTTON_LONG_PRESS_DELAY} and press_duration <= ${BUTTON_PRESS_TIMEOUT}) {
button_action->execute(("bs_button_" + std::to_string(id(button_press_button))).c_str(), "long_click");
button_action->execute(id(button_press_button), "long_press", 1);
} else if (press_duration > ${BUTTON_PRESS_TIMEOUT}) { // Timeout or invalid
ESP_LOGW("core_hw_buttons", "Button press cancelled or timed out after ${BUTTON_PRESS_TIMEOUT} ms");
}
@@ -240,6 +325,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
@@ -254,6 +340,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
@@ -263,6 +350,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
@@ -272,6 +360,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
...

View File

@@ -25,6 +25,15 @@ substitutions:
LIGHT_TRANSITION_TURN_OFF: '0' # Transition time in msec
LIGHT_BRIGHTNESS_TURN_ON: '0' # Brightness (1 to 100%, 0 to not set it)
LIGHT_FULL_RESTORE_MODE: RESTORE_DEFAULT_OFF
LIGHT_SIDES_RESTORE_MODE: RESTORE_DEFAULT_OFF
LIGHT_INDIVIDUAL_RESTORE_MODE: RESTORE_DEFAULT_OFF
esphome:
platformio_options:
build_flags:
- -D TX_ULTIMATE_EASY_CORE_HW_LEDS
globals:
- id: gb_lights_1
type: std::vector<light::LightState*>
@@ -38,20 +47,21 @@ light:
- id: light_full
name: Light - All
internal: true
num_leds: 32
pin: GPIO13
restore_mode: ${LIGHT_FULL_RESTORE_MODE}
platform: neopixelbus
type: GRB
variant: WS2811
# method: esp32_rmt
num_leds: 32
pin: GPIO13
# Those lights are available based on the model selections
- &light_partition_with_effects
id: light_eu
name: Light
name: Light EU
platform: partition
default_transition_length: ${default_transition_length}
internal: true
restore_mode: ${LIGHT_SIDES_RESTORE_MODE}
effects:
- addressable_rainbow:
name: "Rainbow"
@@ -96,7 +106,7 @@ light:
to: 27
- id: light_us
name: Light
name: Light US
<<: *light_partition_with_effects
segments:
- id: light_full
@@ -105,7 +115,7 @@ light:
- &light_partition_with_effects_disabled
id: light_eu_bottom
name: Light - Bottom
name: Light - Bottom EU
disabled_by_default: true
<<: *light_partition_with_effects
segments:
@@ -114,7 +124,7 @@ light:
to: 12
reversed: true
- id: light_eu_left
name: Light - Left
name: Light - Left EU
<<: *light_partition_with_effects_disabled
segments:
- id: light_full
@@ -122,7 +132,7 @@ light:
to: 19
reversed: true
- id: light_eu_right
name: Light - Right
name: Light - Right EU
<<: *light_partition_with_effects_disabled
segments:
- id: light_full
@@ -134,7 +144,7 @@ light:
to: 5
reversed: false
- id: light_eu_top
name: Light - Top
name: Light - Top EU
<<: *light_partition_with_effects_disabled
segments:
- id: light_full
@@ -142,7 +152,7 @@ light:
to: 26
reversed: false
- id: light_us_bottom
name: Light - Bottom
name: Light - Bottom US
<<: *light_partition_with_effects_disabled
segments:
- id: light_full
@@ -150,7 +160,7 @@ light:
to: 14
reversed: true
- id: light_us_left
name: Light - Left
name: Light - Left US
<<: *light_partition_with_effects_disabled
segments:
- id: light_full
@@ -158,7 +168,7 @@ light:
to: 24
reversed: true
- id: light_us_right
name: Light - Right
name: Light - Right US
<<: *light_partition_with_effects_disabled
segments:
- id: light_full
@@ -170,7 +180,7 @@ light:
to: 8
reversed: false
- id: light_us_top
name: Light - Top
name: Light - Top US
<<: *light_partition_with_effects_disabled
segments:
- id: light_full
@@ -184,6 +194,7 @@ light:
platform: partition
disabled_by_default: true
default_transition_length: ${default_transition_length}
restore_mode: ${LIGHT_INDIVIDUAL_RESTORE_MODE}
segments:
- id: light_full
from: 0
@@ -410,369 +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}
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
@@ -786,21 +505,23 @@ 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:
if (light_index >= id(gb_lights_1).size()) {
ESP_LOGE("core_hw_leds", "Invalid set with %s light for Relay %" PRIu8,
light_mode_group_1.c_str(), light_index);
light_mode_group_1.c_str(), light_index+1);
return;
}
if (state and !id(gb_lights_1)[light_index]->current_values.is_on()) {
ESP_LOGI("core_hw_leds", "Turn-on %s light for Relay %" PRIu8,
light_mode_group_1.c_str(), light_index);
light_mode_group_1.c_str(), light_index+1);
auto call = id(gb_lights_1)[light_index]->turn_on();
if (LIGHT_TRANSITION_TURN_ON > 0)
call.set_transition_length(LIGHT_TRANSITION_TURN_ON); // in ms
@@ -809,7 +530,7 @@ script:
call.perform();
} else if (!state and id(gb_lights_1)[light_index]->current_values.is_on()) {
ESP_LOGI("core_hw_leds", "Turn-off %s light for Relay %" PRIu8,
light_mode_group_1.c_str(), light_index);
light_mode_group_1.c_str(), light_index+1);
auto call = id(gb_lights_1)[light_index]->turn_off();
if (LIGHT_TRANSITION_TURN_OFF > 0)
call.set_transition_length(LIGHT_TRANSITION_TURN_OFF); // in ms
@@ -819,12 +540,12 @@ script:
case 2:
if (light_index >= id(gb_lights_2).size()) {
ESP_LOGE("core_hw_leds", "Invalid set with %s light for Relay %" PRIu8,
light_mode_group_2.c_str(), light_index);
light_mode_group_2.c_str(), light_index+1);
return;
}
if (state and !id(gb_lights_2)[light_index]->current_values.is_on()) {
ESP_LOGI("core_hw_leds", "Turn-on %s light for Relay %" PRIu8,
light_mode_group_2.c_str(), light_index);
light_mode_group_2.c_str(), light_index+1);
auto call = id(gb_lights_2)[light_index]->turn_on();
if (LIGHT_TRANSITION_TURN_ON > 0)
call.set_transition_length(LIGHT_TRANSITION_TURN_ON); // in ms
@@ -833,7 +554,7 @@ script:
call.perform();
} else if (!state and id(gb_lights_2)[light_index]->current_values.is_on()) {
ESP_LOGI("core_hw_leds", "Turn-off %s light for Relay %" PRIu8,
light_mode_group_2.c_str(), light_index);
light_mode_group_2.c_str(), light_index+1);
auto call = id(gb_lights_2)[light_index]->turn_off();
if (LIGHT_TRANSITION_TURN_OFF > 0)
call.set_transition_length(LIGHT_TRANSITION_TURN_OFF); // in ms
@@ -846,7 +567,7 @@ select:
# EU relay light mode template
- &relay_light_mode_eu
id: sl_relay_1_light_mode_eu
name: Relay 1 light mode
name: Relay 1 light mode EU
platform: template
options:
- "${LIGHT_MODE_DISABLED_TEXT}"
@@ -860,23 +581,20 @@ select:
entity_category: config
disabled_by_default: false
icon: mdi:dots-square
- id: sl_relay_2_light_mode_eu
name: Relay 2 light mode
name: Relay 2 light mode EU
<<: *relay_light_mode_eu
- id: sl_relay_3_light_mode_eu
name: Relay 3 light mode
name: Relay 3 light mode EU
<<: *relay_light_mode_eu
- id: sl_relay_4_light_mode_eu
name: Relay 4 light mode
name: Relay 4 light mode EU
<<: *relay_light_mode_eu
# US relay light mode template
- &relay_light_mode_us
id: sl_relay_1_light_mode_us
name: Relay 1 light mode
name: Relay 1 light mode US
platform: template
options:
- "${LIGHT_MODE_DISABLED_TEXT}"
@@ -890,16 +608,13 @@ select:
entity_category: config
disabled_by_default: false
icon: mdi:dots-square
- id: sl_relay_2_light_mode_us
name: Relay 2 light mode
name: Relay 2 light mode US
<<: *relay_light_mode_us
- id: sl_relay_3_light_mode_us
name: Relay 3 light mode
name: Relay 3 light mode US
<<: *relay_light_mode_us
- id: sl_relay_4_light_mode_us
name: Relay 4 light mode
name: Relay 4 light mode US
<<: *relay_light_mode_us
...

View File

@@ -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
...

View File

@@ -1,283 +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. #####
####################################################################################################
---
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
- &light_binary_base
id: light_output_1
name: Light output 1
output: output_relay_1
platform: binary
internal: true
- id: light_output_2
name: Light output 2
output: output_relay_2
<<: *light_binary_base
- id: light_output_3
name: Light output 3
output: output_relay_3
<<: *light_binary_base
- id: light_output_4
name: Light output 4
output: output_relay_4
<<: *light_binary_base
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
switch (button_id) {
case 1:
if (sl_button_1_action->active_index().has_value() and
sl_button_1_action->active_index().value() == 1)
sw_relay_1->toggle();
break;
case 2:
if (sl_button_2_action->active_index().has_value() and
sl_button_2_action->active_index().value() == 1)
sw_relay_2->toggle();
break;
case 3:
if (sl_button_3_action->active_index().has_value() and
sl_button_3_action->active_index().value() == 1)
sw_relay_3->toggle();
break;
case 4:
if (sl_button_4_action->active_index().has_value() and
sl_button_4_action->active_index().value() == 1)
sw_relay_4->toggle();
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 mode
platform: template
options:
- "Relay"
- "Light"
- "Not in use"
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 mode
<<: *relay_select_mode_base
- id: sl_relay_3_mode
name: Relay 3 mode
<<: *relay_select_mode_base
- id: sl_relay_4_mode
name: Relay 4 mode
<<: *relay_select_mode_base
switch:
- &relay_switch_base
id: sw_relay_1
name: Relay 1
platform: output
output: output_relay_1
restore_mode: RESTORE_DEFAULT_OFF
internal: true
on_turn_on:
then:
- script.execute: show_relay_status
on_turn_off:
then:
- script.execute: show_relay_status
- id: sw_relay_2
name: Relay 2
output: output_relay_2
<<: *relay_switch_base
- id: sw_relay_3
name: Relay 3
output: output_relay_3
<<: *relay_switch_base
- id: sw_relay_4
name: Relay 4
output: output_relay_4
<<: *relay_switch_base
...

View File

@@ -15,50 +15,193 @@ substitutions:
TOUCH_POSITION_MAX_VALUE: '10' # Maximum touch position value returned by the touch pad via uart
binary_sensor:
- &bs_button_event_template
id: bs_button_event_template
icon: mdi:gesture-tap-box
internal: true
disabled_by_default: true
platform: template
- id: bs_button_1_click_event
name: Button 1 - Click event
internal: false
<<: *bs_button_event_template
on_press:
then:
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_button_1_click_event
state: OFF # yamllint disable-line rule:truthy
- id: bs_button_2_click_event
name: Button 2 - Click event
internal: false
<<: *bs_button_event_template
on_press:
then:
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_button_2_click_event
state: OFF # yamllint disable-line rule:truthy
- id: bs_button_3_click_event
name: Button 3 - Click event
internal: false
<<: *bs_button_event_template
on_press:
then:
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_button_3_click_event
state: OFF # yamllint disable-line rule:truthy
- id: bs_button_4_click_event
name: Button 4 - Click event
internal: false
<<: *bs_button_event_template
on_press:
then:
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_button_4_click_event
state: OFF # yamllint disable-line rule:truthy
- id: bs_button_1_double_click_event
name: Button 1 - Double-click event
internal: false
<<: *bs_button_event_template
on_press:
then:
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_button_1_double_click_event
state: OFF # yamllint disable-line rule:truthy
- id: bs_button_2_double_click_event
name: Button 2 - Double-click event
internal: false
<<: *bs_button_event_template
on_press:
then:
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_button_2_double_click_event
state: OFF # yamllint disable-line rule:truthy
- id: bs_button_3_double_click_event
name: Button 3 - Double-click event
internal: false
<<: *bs_button_event_template
on_press:
then:
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_button_3_double_click_event
state: OFF # yamllint disable-line rule:truthy
- id: bs_button_4_double_click_event
name: Button 4 - Double-click event
internal: false
<<: *bs_button_event_template
on_press:
then:
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_button_4_double_click_event
state: OFF # yamllint disable-line rule:truthy
- id: bs_button_1_long_press_event
name: Button 1 - Long-press event
internal: false
<<: *bs_button_event_template
on_press:
then:
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_button_1_long_press_event
state: OFF # yamllint disable-line rule:truthy
- id: bs_button_2_long_press_event
name: Button 2 - Long-press event
internal: false
<<: *bs_button_event_template
on_press:
then:
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_button_2_long_press_event
state: OFF # yamllint disable-line rule:truthy
- id: bs_button_3_long_press_event
name: Button 3 - Long-press event
internal: false
<<: *bs_button_event_template
on_press:
then:
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_button_3_long_press_event
state: OFF # yamllint disable-line rule:truthy
- id: bs_button_4_long_press_event
name: Button 4 - Long-press event
internal: false
<<: *bs_button_event_template
on_press:
then:
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_button_4_long_press_event
state: OFF # yamllint disable-line rule:truthy
- id: bs_multi_touch
name: Multi-touch
name: Multi-touch event
icon: mdi:gesture-two-tap
internal: false
platform: template
on_click:
<<: *bs_button_event_template
on_press:
then:
- lambda: send_event_to_ha->execute("multi_touch", "multi_touch");
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_multi_touch
state: OFF # yamllint disable-line rule:truthy
- id: bs_swipe_left
name: Swipe left
name: Swipe left event
icon: mdi:gesture-swipe-left
internal: true
platform: template
on_click:
<<: *bs_button_event_template
on_press:
then:
- lambda: send_event_to_ha->execute("swipe", "left");
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_swipe_left
state: OFF # yamllint disable-line rule:truthy
- id: bs_swipe_right
name: Swipe right
name: Swipe right event
icon: mdi:gesture-swipe-right
internal: true
platform: template
on_click:
<<: *bs_button_event_template
on_press:
then:
- lambda: send_event_to_ha->execute("swipe", "right");
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_swipe_right
state: OFF # yamllint disable-line rule:truthy
- id: bs_swipe_up
name: Swipe up
name: Swipe up event
icon: mdi:gesture-swipe-up
internal: true
platform: template
on_click:
<<: *bs_button_event_template
on_press:
then:
- lambda: send_event_to_ha->execute("swipe", "up");
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
id: bs_swipe_up
state: OFF # yamllint disable-line rule:truthy
- id: bs_swipe_down
name: Swipe down
name: Swipe down event
icon: mdi:gesture-swipe-down
internal: true
platform: template
on_click:
<<: *bs_button_event_template
on_press:
then:
- lambda: send_event_to_ha->execute("swipe", "down");
- delay: !lambda return nr_touch_duration->state;
- binary_sensor.template.publish:
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:
@@ -71,7 +214,7 @@ external_components:
number:
- id: nr_touch_duration
name: Touch duration
name: Touch event duration
icon: mdi:timer-cog-outline
unit_of_measurement: ms
# mode: box
@@ -91,6 +234,12 @@ script:
- script.execute: boot_initialize_touch
- id: boot_initialize_touch
mode: restart
then:
- script.execute: boot_initialize_touch_format
- script.execute: boot_initialize_touch_gang
- id: boot_initialize_touch_format
mode: restart
then:
- wait_until:
@@ -109,25 +258,73 @@ script:
bs_swipe_up->publish_state(false);
bs_swipe_up->set_internal(!is_model_us);
- id: boot_initialize_touch_gang
mode: restart
then:
- lambda: |-
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);
bs_button_4_click_event->publish_state(false);
bs_button_1_double_click_event->publish_state(false);
bs_button_2_double_click_event->publish_state(false);
bs_button_3_double_click_event->publish_state(false);
bs_button_4_double_click_event->publish_state(false);
bs_button_1_long_press_event->publish_state(false);
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(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
then:
# Extended by:
# - HW Buttons
# - HW Vibration
- script.execute: touch_on_multi_touch_release_touch
- id: touch_on_multi_touch_release_touch
mode: restart
then:
- lambda: bs_multi_touch->publish_state(true);
- delay: !lambda return nr_touch_duration->state;
- lambda: bs_multi_touch->publish_state(false);
- binary_sensor.template.publish:
id: bs_multi_touch
state: ON # yamllint disable-line rule:truthy
- id: touch_on_press
mode: restart
parameters:
touch_position: uint8_t
button: uint8_t
position: uint8_t
then:
# Extended by:
# - HW Buttons
@@ -136,60 +333,33 @@ script:
- id: touch_on_release
mode: restart
then:
# Extended by:
# - HW Buttons
# - HW Vibration
- script.execute: touch_swipe_turn_off_binary_sensor
# Extended by:
# - HW Buttons
# - HW Vibration
- id: touch_swipe_left
mode: restart
then:
# Extended by:
# - HW Buttons
- script.execute: touch_swipe_left_touch
- id: touch_swipe_left_touch
mode: restart
then:
- binary_sensor.template.publish:
id: bs_swipe_left
state: ON # yamllint disable-line rule:truthy
- delay: !lambda return nr_touch_duration->state;
- script.execute: touch_swipe_turn_off_binary_sensor
- binary_sensor.template.publish:
id: bs_swipe_down
state: ON # yamllint disable-line rule:truthy
- id: touch_swipe_right
mode: restart
then:
# Extended by:
# - HW Buttons
- script.execute: touch_swipe_right_touch
- id: touch_swipe_right_touch
mode: restart
then:
- binary_sensor.template.publish:
id: bs_swipe_right
state: ON # yamllint disable-line rule:truthy
- delay: !lambda return nr_touch_duration->state;
- script.execute: touch_swipe_turn_off_binary_sensor
- id: touch_swipe_turn_off_binary_sensor
mode: restart
then:
- if:
condition:
binary_sensor.is_on: bs_swipe_left
then:
- binary_sensor.template.publish:
id: bs_swipe_left
state: OFF # yamllint disable-line rule:truthy
- if:
condition:
binary_sensor.is_on: bs_swipe_right
then:
- binary_sensor.template.publish:
id: bs_swipe_right
state: OFF # yamllint disable-line rule:truthy
- binary_sensor.template.publish:
id: bs_swipe_up
state: ON # yamllint disable-line rule:truthy
switch:
- id: sw_touch_panel_power
@@ -210,42 +380,86 @@ tx_ultimate_easy:
- lambda: |-
const uint8_t touch_position = static_cast<uint8_t>(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:
- lambda: ESP_LOGI("tx_ultimate_easy", "Multi-touch released");
- script.execute: touch_on_multi_touch_release
then:
- lambda: |-
// Send event to Home Assistant
esphome::api::CustomAPIDevice ha_event;
ha_event.fire_homeassistant_event("${EVENT_NAME}", {
{"device_name", id(tx_device_name).state.c_str()},
{"firmware", "${version}"},
{"domain", "touch"},
{"type", "multi_touch"},
{"action", "release"},
{"position", std::to_string(touch.x)}
});
ESP_LOGI("core_hw_touch", "Multi-touch released");
touch_on_multi_touch_release->execute();
on_press:
- lambda: |-
const uint8_t touch_position = static_cast<uint8_t>(touch.x);
if (touch_position > ${TOUCH_POSITION_MAX_VALUE}) { // Check for valid range
ESP_LOGE("tx_ultimate_easy", "Invalid touch position: %" PRIu8, touch_position);
} else {
ESP_LOGI("tx_ultimate_easy", "Pressed at position %" PRIu8, touch_position);
touch_on_press->execute(touch_position);
}
then:
- lambda: |-
const uint8_t position = static_cast<uint8_t>(touch.x);
if (position > ${TOUCH_POSITION_MAX_VALUE}) { // Check for valid range
ESP_LOGE("core_hw_touch", "Invalid touch position: %" PRIu8, position);
} else {
ESP_LOGI("core_hw_touch", "Pressed at position %" PRIu8, position);
touch_on_press->execute(static_cast<uint8_t>(touch.button), position);
}
on_release:
- lambda: ESP_LOGI("tx_ultimate_easy", "Released");
- script.execute: touch_on_release
then:
- lambda: ESP_LOGI("core_hw_touch", "Released");
- script.execute: touch_on_release
on_swipe_left:
- lambda: ESP_LOGI("tx_ultimate_easy", "Swipe left");
- script.execute: touch_swipe_left
then:
- lambda: |-
std::string swipe_direction = (sl_tx_model_format->state == "${TX_MODEL_FORMAT_EU_TEXT}") ? "left" : "down";
// Send event to Home Assistant
esphome::api::CustomAPIDevice ha_event;
ha_event.fire_homeassistant_event("${EVENT_NAME}", {
{"device_name", id(tx_device_name).state.c_str()},
{"firmware", "${version}"},
{"domain", "touch"},
{"type", "swipe"},
{"action", swipe_direction.c_str()},
{"swipe-direction", swipe_direction.c_str()},
{"position", std::to_string(touch.x)}
});
ESP_LOGI("core_hw_touch", "Multi-touch released");
touch_on_multi_touch_release->execute();
ESP_LOGI("core_hw_touch", "Swipe %s", swipe_direction.c_str());
touch_swipe_left->execute();
on_swipe_right:
- lambda: ESP_LOGI("tx_ultimate_easy", "Swipe right");
- script.execute: touch_swipe_right
then:
- lambda: |-
std::string swipe_direction = (sl_tx_model_format->state == "${TX_MODEL_FORMAT_EU_TEXT}") ? "right" : "up";
// Send event to Home Assistant
esphome::api::CustomAPIDevice ha_event;
ha_event.fire_homeassistant_event("${EVENT_NAME}", {
{"device_name", id(tx_device_name).state.c_str()},
{"firmware", "${version}"},
{"domain", "touch"},
{"type", "swipe"},
{"action", swipe_direction.c_str()},
{"swipe-direction", swipe_direction.c_str()},
{"position", std::to_string(touch.x)}
});
ESP_LOGI("core_hw_touch", "Swipe %s", swipe_direction.c_str());
touch_swipe_right->execute();
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

View File

@@ -0,0 +1,20 @@
####################################################################################################
##### TX Ultimate Easy for ESPHome #####
##### Repository: https://github.com/edwardtfn/TX-Ultimate-Easy #####
####################################################################################################
##### Purpose: ESPHome Standard (non-essential, but recommended packages) #####
####################################################################################################
##### 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:
# yamllint disable rule:colons
standard_hw_relays: !include TX-Ultimate-Easy-ESPHome_standard_hw_relays.yaml
standard_hw_vibration: !include TX-Ultimate-Easy-ESPHome_standard_hw_vibration.yaml
standard_media_player: !include TX-Ultimate-Easy-ESPHome_standard_media_player.yaml
# yamllint enable rule:colons
...

View File

@@ -2,7 +2,7 @@
##### TX Ultimate Easy for ESPHome #####
##### Repository: https://github.com/edwardtfn/TX-Ultimate-Easy #####
####################################################################################################
##### Purpose: ESPHome Core - API #####
##### Purpose: ESPHome - Standard - I2S Audio #####
####################################################################################################
##### Author: edwardtfn - https://github.com/edwardtfn - https://buymeacoffee.com/edwardfirmo #####
####################################################################################################
@@ -11,31 +11,26 @@
##### - For normal system use, modifications to this file are NOT required. #####
####################################################################################################
---
api:
id: api_server
on_client_connected:
then:
- script.execute: publish_device_info
esphome:
platformio_options:
build_flags:
- -D TX_ULTIMATE_EASY_STANDARD_HW_AUDIO
i2s_audio:
id: if_i2s_audio
i2s_bclk_pin: GPIO2
i2s_lrclk_pin: GPIO4
script:
- id: !extend button_action
- id: !extend dump_config_list_packages
then:
- script.execute:
id: send_event_to_ha
component: !lambda return component.c_str();
event: !lambda return event.c_str();
- 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
- id: send_event_to_ha
mode: queued
parameters:
component: string
event: string
then:
- homeassistant.event:
event: esphome.tx_ultimate_easy
data:
device_name: !lambda return tx_device_name->state.c_str();
firmware: ${version}
component: !lambda return component.c_str();
event: !lambda return event.c_str();
// Identify itself
ESP_LOGCONFIG(ESPHOME_PROJECT_NAME, " - Standard - Hardware - Audio");
...

View File

@@ -0,0 +1,970 @@
####################################################################################################
##### TX Ultimate Easy for ESPHome #####
##### Repository: https://github.com/edwardtfn/TX-Ultimate-Easy #####
####################################################################################################
##### Purpose: ESPHome - Standard - 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
LIGHT_RELAYS_RESTORE_MODE: RESTORE_DEFAULT_OFF
esphome:
platformio_options:
build_flags:
- -D TX_ULTIMATE_EASY_STANDARD_HW_RELAYS
globals:
- id: boot_initialization_relays
type: bool
restore_value: false
initial_value: 'false'
- id: boot_initialization_relays_group_assignments
type: bool
restore_value: false
initial_value: 'false'
- id: boot_initialization_relays_light_modes
type: bool
restore_value: false
initial_value: 'false'
- id: boot_initialization_relays_relay_leds
type: bool
restore_value: false
initial_value: 'false'
- id: boot_initialization_relays_relay_modes
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
# 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
disabled_by_default: false
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: 16
to: 17
- 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: 23
to: 24
- 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_full
from: 0
to: 0
- id: light_us_rl_2_4_left
name: Light - Relay 2 of 4 (left)
<<: *light_partition_relays
segments:
- id: light_full
from: 21
to: 22
- id: light_us_rl_2_4_right
name: Light - Relay 2 of 4 (right)
<<: *light_partition_relays
segments:
- id: light_full
from: 1
to: 2
- id: light_us_rl_3_4_left
name: Light - Relay 3 of 4 (left)
<<: *light_partition_relays
segments:
- id: light_full
from: 17
to: 18
- id: light_us_rl_3_4_right
name: Light - Relay 3 of 4 (right)
<<: *light_partition_relays
segments:
- id: light_full
from: 5
to: 6
- id: light_us_rl_4_4_left
name: Light - Relay 4 of 4 (left)
<<: *light_partition_relays
segments:
- id: light_full
from: 15
to: 16
- id: light_us_rl_4_4_right
name: Light - Relay 4 of 4 (right)
<<: *light_partition_relays
segments:
- id: light_full
from: 7
to: 8
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:
- script.execute: boot_initialize_relays_group_assignments
- script.execute: boot_initialize_relays_light_modes
- script.execute: boot_initialize_relays_relay_leds
- script.execute: boot_initialize_relays_relay_modes
- script.wait: boot_initialize_relays_group_assignments
- script.wait: boot_initialize_relays_light_modes
- script.wait: boot_initialize_relays_relay_leds
- script.wait: boot_initialize_relays_relay_modes
- wait_until:
condition:
- lambda: return id(boot_initialization_relays_group_assignments);
- lambda: return id(boot_initialization_relays_light_modes);
- lambda: return id(boot_initialization_relays_relay_leds);
- lambda: return id(boot_initialization_relays_relay_modes);
- globals.set:
id: boot_initialization_relays
value: 'true'
- id: boot_initialize_relays_group_assignments
mode: restart
then:
- lambda: |-
// LED Group Assignment:
// - For US model: gb_lights_1 = left side LEDs, gb_lights_2 = right side LEDs
// - For EU model: gb_lights_1 = bottom LEDs, gb_lights_2 = top LEDs
// Gang configurations determine which LED segments are active
switch (id(gang_count)) {
case 1: // 1 Gang
if (id(is_us_model)) {
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 (id(is_us_model)) {
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 (id(is_us_model)) {
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 (id(is_us_model)) {
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;
default:
ESP_LOGE("standard_hw_relays", "Invalid gang count: %" PRIu8, id(gang_count));
break;
}
id(boot_initialization_relays_group_assignments) = true;
- id: boot_initialize_relays_light_modes
mode: restart
then:
- lambda: |-
// EU light modes
sl_relay_1_light_mode_eu->set_internal(id(is_us_model) or id(gang_count) < 1);
sl_relay_2_light_mode_eu->set_internal(id(is_us_model) or id(gang_count) < 2);
sl_relay_3_light_mode_eu->set_internal(id(is_us_model) or id(gang_count) < 3);
sl_relay_4_light_mode_eu->set_internal(id(is_us_model) or id(gang_count) < 4);
// US light modes
sl_relay_1_light_mode_us->set_internal(!id(is_us_model) or id(gang_count) < 1);
sl_relay_2_light_mode_us->set_internal(!id(is_us_model) or id(gang_count) < 2);
sl_relay_3_light_mode_us->set_internal(!id(is_us_model) or id(gang_count) < 3);
sl_relay_4_light_mode_us->set_internal(!id(is_us_model) or id(gang_count) < 4);
// Set this section of initialization as completed
id(boot_initialization_relays_light_modes) = true;
- id: boot_initialize_relays_relay_leds
mode: restart
then:
- lambda: |-
const bool set_internal = not sw_expose_relays_leds_to_ha->state;
// EU model LEDs
// EU model - 1 Gang
light_eu_rl_1_1_bottom->set_internal(set_internal or id(is_us_model) or id(gang_count) != 1);
light_eu_rl_1_1_top->set_internal(set_internal or id(is_us_model) or id(gang_count) != 1);
// EU model - 2 Gang
light_eu_rl_1_2_bottom->set_internal(set_internal or id(is_us_model) or id(gang_count) != 2);
light_eu_rl_1_2_top->set_internal(set_internal or id(is_us_model) or id(gang_count) != 2);
light_eu_rl_2_2_bottom->set_internal(set_internal or id(is_us_model) or id(gang_count) != 2);
light_eu_rl_2_2_top->set_internal(set_internal or id(is_us_model) or id(gang_count) != 2);
// EU model - 3 Gang
light_eu_rl_1_3_bottom->set_internal(set_internal or id(is_us_model) or id(gang_count) != 3);
light_eu_rl_1_3_top->set_internal(set_internal or id(is_us_model) or id(gang_count) != 3);
light_eu_rl_2_3_bottom->set_internal(set_internal or id(is_us_model) or id(gang_count) != 3);
light_eu_rl_2_3_top->set_internal(set_internal or id(is_us_model) or id(gang_count) != 3);
light_eu_rl_3_3_bottom->set_internal(set_internal or id(is_us_model) or id(gang_count) != 3);
light_eu_rl_3_3_top->set_internal(set_internal or id(is_us_model) or id(gang_count) != 3);
// EU model - 4 Gang
light_eu_rl_1_4_bottom->set_internal(set_internal or id(is_us_model) or id(gang_count) != 4);
light_eu_rl_1_4_top->set_internal(set_internal or id(is_us_model) or id(gang_count) != 4);
light_eu_rl_2_4_bottom->set_internal(set_internal or id(is_us_model) or id(gang_count) != 4);
light_eu_rl_2_4_top->set_internal(set_internal or id(is_us_model) or id(gang_count) != 4);
light_eu_rl_3_4_bottom->set_internal(set_internal or id(is_us_model) or id(gang_count) != 4);
light_eu_rl_3_4_top->set_internal(set_internal or id(is_us_model) or id(gang_count) != 4);
light_eu_rl_4_4_bottom->set_internal(set_internal or id(is_us_model) or id(gang_count) != 4);
light_eu_rl_4_4_top->set_internal(set_internal or id(is_us_model) or id(gang_count) != 4);
// US model LEDs
// US model - 1 Gang
light_us_rl_1_1_left->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 1);
light_us_rl_1_1_right->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 1);
// US model - 2 Gang
light_us_rl_1_2_left->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 2);
light_us_rl_1_2_right->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 2);
light_us_rl_2_2_left->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 2);
light_us_rl_2_2_right->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 2);
// US model - 3 Gang
light_us_rl_1_3_left->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 3);
light_us_rl_1_3_right->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 3);
light_us_rl_2_3_left->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 3);
light_us_rl_2_3_right->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 3);
light_us_rl_3_3_left->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 3);
light_us_rl_3_3_right->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 3);
// US model - 4 Gang
light_us_rl_1_4_left->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 4);
light_us_rl_1_4_right->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 4);
light_us_rl_2_4_left->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 4);
light_us_rl_2_4_right->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 4);
light_us_rl_3_4_left->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 4);
light_us_rl_3_4_right->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 4);
light_us_rl_4_4_left->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 4);
light_us_rl_4_4_right->set_internal(set_internal or !id(is_us_model) or id(gang_count) != 4);
// Set this section of initialization as completed
id(boot_initialization_relays_relay_leds) = true;
- id: boot_initialize_relays_relay_modes
mode: restart
then:
- lambda: |-
// Set selector internal based on the model (num of relays)
sl_relay_1_mode->set_internal(id(gang_count) < 1);
sl_relay_2_mode->set_internal(id(gang_count) < 2);
sl_relay_3_mode->set_internal(id(gang_count) < 3);
sl_relay_4_mode->set_internal(id(gang_count) < 4);
// Set indicator (either switch or light) visible on Home Assistant
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(id(gang_count) < 2 or relay_mode_index.value() != 1);
sw_relay_2->set_internal(id(gang_count) < 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(id(gang_count) < 3 or relay_mode_index.value() != 1);
sw_relay_3->set_internal(id(gang_count) < 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(id(gang_count) < 4 or relay_mode_index.value() != 1);
sw_relay_4->set_internal(id(gang_count) < 4 or relay_mode_index.value() != 0);
}
// Set this section of initialization as completed
id(boot_initialization_relays_relay_modes) = 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
const bool api_disconnected = !global_api_server->is_connected() or
!wifi_component->is_connected();
std::string select_state;
bool toggle_relay = false;
if (api_disconnected) {
ESP_LOGW("standard_hw_relays", "Toggle relays:");
ESP_LOGW("standard_hw_relays", " API state: DISCONNECTED");
ESP_LOGW("standard_hw_relays", " Button: %" PRIu8, button);
} else {
ESP_LOGVV("standard_hw_relays", "Toggle relays:");
ESP_LOGVV("standard_hw_relays", " API state: Connected");
ESP_LOGVV("standard_hw_relays", " Button: %" PRIu8, button);
}
switch (button) {
case ${BUTTON_1_ID}:
select_state = sl_button_1_action->state;
toggle_relay = (select_state == "${BUTTON_1_ACTION_TEXT}" or
(api_disconnected and select_state == "${BUTTON_1_ACTION_FAILSAFE_TEXT}"));
if (toggle_relay)
sw_relay_1->toggle();
break;
case ${BUTTON_2_ID}:
select_state = sl_button_2_action->state;
toggle_relay = (select_state == "${BUTTON_2_ACTION_TEXT}" or
(api_disconnected and select_state == "${BUTTON_2_ACTION_FAILSAFE_TEXT}"));
if (toggle_relay)
sw_relay_2->toggle();
break;
case ${BUTTON_3_ID}:
select_state = sl_button_3_action->state;
toggle_relay = (select_state == "${BUTTON_3_ACTION_TEXT}" or
(api_disconnected and select_state == "${BUTTON_3_ACTION_FAILSAFE_TEXT}"));
if (toggle_relay)
sw_relay_3->toggle();
break;
case ${BUTTON_4_ID}:
select_state = sl_button_4_action->state;
toggle_relay = (select_state == "${BUTTON_4_ACTION_TEXT}" or
(api_disconnected and select_state == "${BUTTON_4_ACTION_FAILSAFE_TEXT}"));
if (toggle_relay)
sw_relay_4->toggle();
break;
}
if (toggle_relay) {
ESP_LOGI("standard_hw_relays", "Toggle relay %" PRIu8 ": (%s)", button, select_state.c_str());
} else if (not select_state.empty()) {
ESP_LOGV("standard_hw_relays", "Ignoring toggle for relay %" PRIu8 ": action is '%s'",
button, select_state.c_str());
} else {
ESP_LOGE("standard_hw_relays", "No button action selected for button %" PRIu8, button);
}
- id: !extend dump_config
then:
- lambda: |-
// Relay's modes
ESP_LOGCONFIG("standard_hw_relays", "Relay%s mode%s:",
id(gang_count_plural_suffix).c_str(),
id(gang_count_plural_suffix).c_str());
ESP_LOGCONFIG("standard_hw_relays", " Relay 1: %s", sl_relay_1_mode->has_state()
? sl_relay_1_mode->state.c_str()
: "Unknown");
if (id(gang_count) >= 2)
ESP_LOGCONFIG("standard_hw_relays", " Relay 2: %s", sl_relay_2_mode->has_state()
? sl_relay_2_mode->state.c_str()
: "Unknown");
if (id(gang_count) >= 3)
ESP_LOGCONFIG("standard_hw_relays", " Relay 3: %s", sl_relay_3_mode->has_state()
? sl_relay_3_mode->state.c_str()
: "Unknown");
if (id(gang_count) >= 4)
ESP_LOGCONFIG("standard_hw_relays", " Relay 4: %s", sl_relay_4_mode->has_state()
? sl_relay_4_mode->state.c_str()
: "Unknown");
// Relay's states
ESP_LOGCONFIG("standard_hw_relays", "Relay%s state%s:",
id(gang_count_plural_suffix).c_str(),
id(gang_count_plural_suffix).c_str());
ESP_LOGCONFIG("standard_hw_relays", " Relay 1: %s", sw_relay_1->state ? "ON" : "OFF");
if (id(gang_count) >= 2)
ESP_LOGCONFIG("standard_hw_relays", " Relay 2: %s", sw_relay_2->state ? "ON" : "OFF");
if (id(gang_count) >= 3)
ESP_LOGCONFIG("standard_hw_relays", " Relay 3: %s", sw_relay_3->state ? "ON" : "OFF");
if (id(gang_count) >= 4)
ESP_LOGCONFIG("standard_hw_relays", " Relay 4: %s", sw_relay_4->state ? "ON" : "OFF");
ESP_LOGCONFIG("standard_hw_relays", "Expose Relay's LEDs to Home Assistant: %s",
YESNO(sw_expose_relays_leds_to_ha->state));
// Boot initialization statuses
ESP_LOGCONFIG("standard_hw_relays", "Boot initialization flags:");
ESP_LOGCONFIG("standard_hw_relays", " Overall: %s", YESNO(id(boot_initialization_relays)));
ESP_LOGCONFIG("standard_hw_relays", " Groups: %s",
YESNO(id(boot_initialization_relays_group_assignments)));
ESP_LOGCONFIG("standard_hw_relays", " Light modes: %s", YESNO(id(boot_initialization_relays_light_modes)));
ESP_LOGCONFIG("standard_hw_relays", " Relay modes: %s", YESNO(id(boot_initialization_relays_relay_modes)));
ESP_LOGCONFIG("standard_hw_relays", " Status LEDs: %s", YESNO(id(boot_initialization_relays_relay_leds)));
// Substitutions
ESP_LOGCONFIG("standard_hw_relays", "Restore modes:");
ESP_LOGCONFIG("standard_hw_relays", " Relays: ${RELAY_RESTORE_MODE}");
ESP_LOGCONFIG("standard_hw_relays", " Status LEDs: ${LIGHT_RELAYS_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, " - Standard - Hardware - Relays");
- id: show_relay_status
mode: restart
then:
- script.wait: boot_initialize_relays
- lambda: |-
if (not id(boot_initialization_relays)) {
ESP_LOGW("standard_hw_relays", "Relays not initialized yet");
if (not boot_initialize_relays->is_running())
boot_initialize_relays->execute();
return;
}
for (uint8_t i = 0; i < id(gang_count); i++) {
bool relay_state = false;
std::string light_mode;
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}";
// Determine relay state and light mode
switch (i) {
case 0:
relay_state = id(sw_relay_1).state;
light_mode = id(is_us_model)
? 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 = id(is_us_model)
? 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 = id(is_us_model)
? 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 = id(is_us_model)
? id(sl_relay_4_light_mode_us)->state
: id(sl_relay_4_light_mode_eu)->state;
break;
}
ESP_LOGV("standard_hw_relays", "Relay %" PRIu8 " is %s", i + 1, relay_state ? "ON" : "OFF");
ESP_LOGV("standard_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
on_value:
then:
- binary_sensor.template.publish:
id: bs_pending_restart
state: true
- 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_expose_relays_leds_to_ha
name: Expose Relay's LEDs to Home Assistant
platform: template
restore_mode: RESTORE_DEFAULT_OFF
optimistic: true
internal: false
entity_category: config
on_turn_on:
then:
- binary_sensor.template.publish:
id: bs_pending_restart
state: true
on_turn_off:
then:
- binary_sensor.template.publish:
id: bs_pending_restart
state: true
- 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
...

View File

@@ -0,0 +1,182 @@
####################################################################################################
##### TX Ultimate Easy for ESPHome #####
##### Repository: https://github.com/edwardtfn/TX-Ultimate-Easy #####
####################################################################################################
##### Purpose: ESPHome - Standard - Hardware - Speaker #####
####################################################################################################
##### 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:
# RTTTL format: name:d=duration,o=octave,b=tempo:notes
# d=32 (32nd note), o=5 (octave 5), b=100 (tempo 100)
tone_volume_change: "scale_up:d=32,o=5,b=100:c,c#,d#,e,f#,g#,a#,b" # Use "none" to disable sound
packages:
standard_hw_audio: !include TX-Ultimate-Easy-ESPHome_standard_hw_audio.yaml
api:
actions:
- action: rtttl_play
variables:
# The RTTTL string for the melody to be played.
# It should follow the RTTTL format, including the melody's name,
# default settings, and a sequence of notes.
tone: string
then:
- lambda: |-
rtttl_speaker->stop();
if (speaker_volume->state > 0) {
ESP_LOGI("standard_speaker", "Play tone: '%s'", tone.c_str());
rtttl_speaker->play(tone.c_str());
}
esphome:
platformio_options:
build_flags:
- -D TX_ULTIMATE_EASY_STANDARD_SPEAKER
number:
- id: speaker_volume
name: Sound - Volume
platform: template
max_value: 100
min_value: 0
step: 1
initial_value: 100
unit_of_measurement: "%"
internal: false
disabled_by_default: true
entity_category: config
device_class: sound_pressure
restore_value: true
optimistic: true
set_action:
then:
- speaker.volume_set:
id: speaker_embedded
volume: !lambda return x/100.0f;
- lambda: |-
static const std::string tone_volume_change = "${tone_volume_change}";
// Play sound if tone_volume_change is not "none"
if (x > 0 and !tone_volume_change.empty() and tone_volume_change != "none")
rtttl_speaker->play(tone_volume_change);
rtttl:
- id: rtttl_speaker
speaker: speaker_embedded
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, " - Standard - Hardware - Speaker");
- id: speaker_play_click
then:
- if:
condition:
not:
- speaker.is_playing: speaker_embedded
then:
- speaker.play:
id: speaker_embedded
data: [
0x01, 0x02, 0x04, 0x06, 0x07, 0x08, 0x08, 0x06, 0x01, 0xFA, 0xF4,
0xEF, 0xEE, 0xF1, 0xF7, 0xFF, 0x07, 0x0E, 0x11, 0x11, 0x10, 0x0C,
0x06, 0xFF, 0xF8, 0xF1, 0xEC, 0xEA, 0xEC, 0xF2, 0xF9, 0xFF, 0x05,
0x0A, 0x10, 0x14, 0x17, 0x17, 0x14, 0x0B, 0xFD, 0xED, 0xE0, 0xD9,
0xDB, 0xE6, 0xF7, 0x0A, 0x19, 0x20, 0x1E, 0x14, 0x05, 0xF4, 0xE5,
0xDF, 0xE4, 0xF4, 0x0C, 0x24, 0x36, 0x3D, 0x35, 0x20, 0xFF, 0xDD,
0xC0, 0xAE, 0xA9, 0xB0, 0xC4, 0xE0, 0x03, 0x26, 0x48, 0x62, 0x70,
0x6D, 0x59, 0x35, 0x08, 0xD8, 0xAC, 0x8D, 0x80, 0x85, 0x9C, 0xC1,
0xF0, 0x21, 0x4E, 0x6F, 0x7F, 0x7A, 0x63, 0x3D, 0x0F, 0xE0, 0xB7,
0x9B, 0x90, 0x96, 0xAC, 0xCE, 0xF6, 0x1D, 0x3C, 0x50, 0x55, 0x4D,
0x3A, 0x20, 0x04, 0xEC, 0xD8, 0xCC, 0xC9, 0xCD, 0xD8, 0xE8, 0xF9,
0x0A, 0x17, 0x1F, 0x20, 0x1C, 0x12, 0x07, 0xFC, 0xF2, 0xEC, 0xEB,
0xED, 0xF3, 0xFA, 0x02, 0x0A, 0x10, 0x12, 0x12, 0x0E, 0x07, 0xFE,
0xF5, 0xED, 0xEA, 0xEB, 0xEF, 0xF7, 0x00, 0x0A, 0x10, 0x13, 0x12,
0x0F, 0x09, 0x02, 0xFB, 0xF5, 0xF3, 0xF2, 0xF3, 0xF6, 0xFB, 0xFF,
0x03, 0x05, 0x07, 0x08, 0x07, 0x05, 0x03, 0x01, 0xFF, 0xFE, 0xFC,
0xFB, 0xFB, 0xFC, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x02,
0x01]
- wait_until:
condition:
not:
- speaker.is_playing: speaker_embedded
- speaker.stop: speaker_embedded
- id: !extend touch_on_multi_touch_release
then:
- script.execute: touch_on_multi_touch_release_speaker
- id: touch_on_multi_touch_release_speaker
mode: restart
then:
- lambda: |-
if (sl_touch_speaker_feedback->state != "Disabled")
speaker_play_click->execute();
- id: !extend touch_on_press
then:
- script.execute: touch_on_press_speaker
- id: touch_on_press_speaker
mode: restart
then:
- lambda: |-
if (sl_touch_speaker_feedback->state == "On press" or sl_touch_speaker_feedback->state == "Always")
speaker_play_click->execute();
- id: !extend touch_on_release
then:
- script.execute: touch_on_release_speaker
- id: touch_on_release_speaker
mode: restart
then:
- lambda: |-
if (sl_touch_speaker_feedback->state == "On release" or sl_touch_speaker_feedback->state == "Always")
speaker_play_click->execute();
select:
- id: sl_touch_speaker_feedback
name: Touch - Speaker 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
speaker:
- id: speaker_embedded
platform: i2s_audio
dac_type: external
i2s_dout_pin: GPIO15
i2s_audio_id: if_i2s_audio
i2s_comm_fmt: stand_msb
channel: mono
...

View File

@@ -2,7 +2,7 @@
##### TX Ultimate Easy for ESPHome #####
##### Repository: https://github.com/edwardtfn/TX-Ultimate-Easy #####
####################################################################################################
##### Purpose: ESPHome Core - Hardware - Vibration system #####
##### Purpose: ESPHome - Standard - Hardware - Vibration system #####
####################################################################################################
##### Author: edwardtfn - https://github.com/edwardtfn - https://buymeacoffee.com/edwardfirmo #####
####################################################################################################
@@ -32,6 +32,11 @@ button:
then:
- script.execute: vibrate
esphome:
platformio_options:
build_flags:
- -D TX_ULTIMATE_EASY_STANDARD_HW_VIBRATION
number:
- id: nr_vibrating_duration
name: Vibrate duration
@@ -53,6 +58,33 @@ ota:
- switch.turn_off: sw_vibration_motor
script:
- id: !extend dump_config
then:
- lambda: |-
// Configuration
ESP_LOGCONFIG("standard_hw_vibration", "Touch - Vibration feedback: %s",
sl_touch_vibration_feedback->state.c_str());
ESP_LOGCONFIG("standard_hw_vibration", "Vibrate duration: %.0fms", nr_vibrating_duration->state);
ESP_LOGCONFIG("standard_hw_vibration", "Vibrate max duration: ${vibration_max_duration}");
// State
if (bs_vibrating->state)
ESP_LOGW("standard_hw_vibration", "Vibrating now: YES");
else
ESP_LOGCONFIG("standard_hw_vibration", "Vibrating now: No");
- 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, " - Standard - Hardware - Vibration");
- id: !extend touch_on_multi_touch_release
then:
- script.execute: touch_on_multi_touch_release_vibration
@@ -133,5 +165,4 @@ switch:
- binary_sensor.template.publish:
id: bs_vibrating
state: OFF # yamllint disable-line rule:truthy
...

View File

@@ -0,0 +1,64 @@
####################################################################################################
##### 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
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
...

263
README.md
View File

@@ -8,10 +8,10 @@
[![Discord][discord-shield]](https://discord.gg/Db6WJWzWuf)
[![Buy me an ice-cream][buymeacoffee-shield]](https://www.buymeacoffee.com/edwardfirmo)
<!-- markdownlint-disable MD013 -->
| &nbsp;![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. |
<!-- markdownlint-disable MD013 MD033 -->
| &nbsp;<picture><source media="(prefers-color-scheme: dark)" srcset="Assets/Logo_dark.png"><source media="(prefers-color-scheme: light)" srcset="Assets/Logo_light.png"><img alt="TX Ultimate Easy Logo" src="Assets/Logo_light.png"></picture> | 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. |
| --- | :-- |
<!-- markdownlint-enable MD013 -->
<!-- markdownlint-enable MD013 MD033 -->
[version-shield]: https://img.shields.io/github/v/tag/edwardtfn/TX-Ultimate-Easy?label=version
[version]: https://github.com/edwardtfn/TX-Ultimate-Easy/tags
@@ -29,14 +29,39 @@
## Integration with Home Assistant
TX Ultimate Easy exposes your device's components (sensors, touch panel, relays, etc.) to Home Assistant, allowing you to:
TX Ultimate Easy exposes your device's components (sensors, touch panel, relays, etc.) to Home Assistant,
allowing you to:
- Monitor sensor states and values
- Control device components through the Home Assistant UI
- Use device triggers and states in your Home Assistant automations and scripts
- Configure device behavior through Home Assistant's service calls
All automation capabilities are handled through Home Assistant's native automation system - this project focuses on providing reliable device integration rather than implementing its own automation tools.
All automation capabilities are handled through Home Assistant's
native automation system - this project focuses on providing reliable
device integration rather than implementing its own automation tools.
### Event-Based Automation
TX Ultimate Easy uses Home Assistant's native Events system for reliable automation triggers.
While sensors show the current state (e.g., button pressed/not pressed),
events capture-specific actions like clicks, swipes, and long presses.
For more details, please refer to our **[Events docs](docs/events.md)**.
### Device Configuration
#### Relay Modes
- **Light Mode**: Exposes the relay as a light entity with brightness controls (if supported)
- **Switch Mode**: Exposes the relay as a simple on/off switch entity
#### Button Actions
- **None**: Allows using button events for custom automations
Example: Trigger scenes or complex automations through Home Assistant
- **Relay Toggle**: Direct control of the associated relay
Example: Toggle relay state with each press, independent of Home Assistant
#### Automation
All device behaviors can be customized through Home Assistant automations without relying on local device triggers.
## Key Features
@@ -67,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.
<!-- markdownlint-disable MD028 -->
> [!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.
<!-- markdownlint-enable MD028 -->
#### 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
<!-- markdownlint-disable MD013 -->
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
<!-- markdownlint-enable MD013 -->
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 12 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
@@ -104,6 +327,7 @@ We welcome contributions from the community! Here's how you can help:
4. Submit a pull request targeting the `main` branch
Please ensure your code follows our standards:
- Passes all lint checks (YAML, C++, Markdown)
- Includes appropriate documentation
- Follows existing code style
@@ -112,11 +336,15 @@ Please ensure your code follows our standards:
Need help? Here are your options:
- **Bug Reports & Feature Requests**: Use [GitHub Issues](https://github.com/edwardtfn/TX-Ultimate-Easy/issues) for all bug reports and feature requests
- **Community Chat**: Join our [Discord Server](https://discord.gg/Db6WJWzWuf) for discussions and community interaction
- **Bug Reports & Feature Requests**: Use [GitHub Issues](https://github.com/edwardtfn/TX-Ultimate-Easy/issues)
for all bug reports and feature requests
- **Community Chat**: Join our [Discord Server](https://discord.gg/Db6WJWzWuf)
for discussions and community interaction
- **Support the Project**: Consider supporting through Buy Me a Coffee
Note: For proper tracking and resolution, all bug reports and feature requests must be submitted through GitHub Issues, not Discord. The Issues page can be found at: [Issues · edwardtfn/TX-Ultimate-Easy](https://github.com/edwardtfn/TX-Ultimate-Easy/issues)
Note: For proper tracking and resolution:
- All bug reports and feature requests must be submitted through GitHub Issues, not Discord
- Submit issues here: [Issues · edwardtfn/TX-Ultimate-Easy](https://github.com/edwardtfn/TX-Ultimate-Easy/issues)
[![Buy Me a Coffee](https://www.buymeacoffee.com/assets/img/custom_images/yellow_img.png)](https://www.buymeacoffee.com/edwardfirmo)
@@ -124,8 +352,11 @@ Note: For proper tracking and resolution, all bug reports and feature requests m
This project builds upon the work of several amazing projects and contributors:
<!-- markdownlint-disable MD013 -->
- [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)
<!-- markdownlint-enable MD013 -->
Special thanks to all contributors and community members who help make this project better.
@@ -136,5 +367,9 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
---
<!-- markdownlint-disable MD033 -->
<img src="Assets/Logo.webp" alt="TX Ultimate Easy Logo" width="100"/>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="Assets/Logo_dark.png">
<source media="(prefers-color-scheme: light)" srcset="Assets/Logo_light.png">
<img alt="TX Ultimate Easy Logo" src="Assets/Logo_light.png" width="100">
</picture>
<!-- markdownlint-enable MD033 -->

View File

@@ -16,9 +16,10 @@ wifi:
packages:
remote_package:
url: https://github.com/edwardtfn/TX-Ultimate-Easy
ref: main
refresh: 30s
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
...

View File

@@ -0,0 +1,38 @@
####################################################################################################
##### TX Ultimate Easy for ESPHome #####
##### Repository: https://github.com/edwardtfn/TX-Ultimate-Easy #####
####################################################################################################
##### Author: edwardtfn - https://github.com/edwardtfn - https://buymeacoffee.com/edwardfirmo #####
####################################################################################################
##### WARNING: This is an advanced configuration template. Use with caution as improper #####
##### configuration may lead to reduced functionality or system instability. #####
####################################################################################################
---
substitutions:
name: tx-ultimate-easy-adv
friendly_name: TX Ultimate Easy Advanced
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:
# Core (essential) packages - Do not disable these unless you know what you're doing
- 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 functionality - Can be enabled/disabled as needed
- 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
...

View File

@@ -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")

View File

@@ -2,6 +2,7 @@
#include "esphome/core/log.h"
#include "tx_ultimate_easy.h"
#include <cinttypes>
#include <string>
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<uint8_t>((position / width) + 1), // Convert position to button index

236
docs/events.md Normal file
View File

@@ -0,0 +1,236 @@
# Updating the Event Engine in TX Ultimate Easy
## Overview of the Event System
The TX Ultimate Easy firmware introduces a powerful
and flexible event system designed to handle various types of interactions,
such as touch gestures and device states.
This system leverages Home Assistant's native event structure,
ensuring seamless integration and enabling users to create advanced automations.
### Event Structure
All events emitted by the device are categorized under the `esphome.tx_ultimate_easy` event type in Home Assistant.
The `data` field within the event payload provides details about the specific interaction.
Below is a detailed description of the keys used:
#### Example Event Payload
```yaml
event:
event_type: esphome.tx_ultimate_easy
data:
device_id: "abc123"
device_name: "living_room_panel"
firmware: "2024.12.1"
domain: touch
type: button
action: click
button_id: 2
count: 1
position: 3
```
### Key Definitions
#### `device_id`
- **Description**: A unique identifier for the device emitting the event.
- **Example**: `device_id: "abc123"`
#### `device_name`
- **Description**: A Home Assistant-compatible version of the hostname, with blanks and invalid characters replaced by `_`.
- **Example**: `device_name: "living_room_panel"`
#### `firmware`
- **Description**: The firmware version of the device, formatted as `YYYY.M.S`.
- **Example**: `firmware: "2024.12.1"`
#### `domain`
- **Description**: The high-level category of the event.
- **Examples**:
- `boot`
- `touch`
#### `type`
- **Description**: Specifies the subcategory within the `domain`.
- **Examples**:
- For `domain: boot`: `start`, `done`
- For `domain: touch`: `button`, `swipe`, `multi_touch`
#### `action`
- **Description**: Indicates the specific action or interaction.
- **Examples**:
- For `type: button`: `click`, `double-click`, `long-press`, `multiple-click`
- For `type: swipe`: `left`, `right`, `up`, `down`
#### `button_id`
- **Description**: Identifies the button involved in the event (specific to `type: button`).
- **Example**: `button_id: 2`
#### `count`
- **Description**: Indicates the number of clicks or interactions (used with `action: multiple-click`).
- **Example**: `count: 3`
#### `swipe-direction`
- **Description**: Specifies the direction of a swipe (used with `type: swipe`).
- **Examples**: `left`, `right`, `up`, `down`
#### `position`
- **Description**: An integer from 1 to 10 indicating the touch position (available on all touch events).
- **Example**: `position: 3`
### Supported Event Types
#### Boot Events
```yaml
event:
device_id: "abc123"
device_name: "living_room_panel"
firmware: "2024.12.1"
domain: boot
type: start
action: null
```
```yaml
event:
device_id: "abc123"
device_name: "living_room_panel"
firmware: "2024.12.1"
domain: boot
type: done
action: null
```
#### Touch Events
##### Button Event
```yaml
event:
device_id: "abc123"
device_name: "living_room_panel"
firmware: "2024.12.1"
domain: touch
type: button
action: click
button_id: 1
count: 1
position: 3
```
```yaml
event:
device_id: "abc123"
device_name: "living_room_panel"
firmware: "2024.12.1"
domain: touch
type: button
action: multiple-click
button_id: 1
count: 5
position: 3
```
##### Swipe Event
```yaml
event:
device_id: "abc123"
device_name: "living_room_panel"
firmware: "2024.12.1"
domain: touch
type: swipe
action: left
swipe-direction: left
position: 3
```
```yaml
event:
device_id: "abc123"
device_name: "living_room_panel"
firmware: "2024.12.1"
domain: touch
type: swipe
action: up
swipe-direction: up
position: 3
```
##### Multi-Touch Event
```yaml
event:
device_id: "abc123"
device_name: "living_room_panel"
firmware: "2024.12.1"
domain: touch
type: multi_touch
action: release
position: 3
```
### Integration in Automations
#### Listening to Events
To utilize these events in Home Assistant, follow these steps:
1. Open the **Developer Tools** in Home Assistant.
2. Navigate to the **Events** tab.
3. Enter `esphome.tx_ultimate_easy` in the "Event to subscribe to" field.
4. Click "Start listening."
5. Trigger interactions on your TX Ultimate Easy device to see the events in real-time.
#### Example Automation YAML
##### Automation for a Single Click
```yaml
trigger:
- platform: event
event_type: esphome.tx_ultimate_easy
event_data:
domain: touch
type: button
action: click
button_id: 1
position: 3
action:
- service: light.toggle
target:
entity_id: light.living_room
```
##### Automation for a Swipe Gesture
```yaml
trigger:
- platform: event
event_type: esphome.tx_ultimate_easy
event_data:
domain: touch
type: swipe
action: left
swipe-direction: left
position: 3
action:
- service: script.activate_scene
target:
entity_id: scene.relax_mode
```
This event engine provides a robust and extensible framework for handling device interactions,
allowing users to implement highly customized automations with ease.

View File

@@ -1 +1 @@
2024.12.6
2025.7.1

View File

@@ -1 +1 @@
version: 2024.12.6
version: 2025.7.1