Compare commits

...

78 Commits

Author SHA1 Message Date
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
GitHub Actions
09e9d340fc Bump version to 2024.12.6 [skip-versioning] 2024-12-22 16:41:40 +00:00
Edward Firmo
7850d16aeb Push tag before setting latest and stable 2024-12-22 17:40:45 +01:00
Edward Firmo
1f2e60e7db Merge pull request #53 from edwardtfn/use-main-as-ref
Use `main` as reference for remote package
2024-12-22 17:23:39 +01:00
Edward Firmo
dd25e5dbba Use bump_version.sh from folder versioning 2024-12-22 17:19:59 +01:00
Edward Firmo
75f4245fe1 No need another versioning action 2024-12-22 17:16:09 +01:00
Edward Firmo
3b7f811876 Tag latest and stable only after versioning 2024-12-22 17:04:52 +01:00
Edward Firmo
d403bc2aa9 CodeRabbitAI - Remove duplicated badge reference 2024-12-22 16:41:21 +01:00
Edward Firmo
5d780f162e Add version badge 2024-12-22 16:37:05 +01:00
Edward Firmo
0e53dfd3cd CodeRabbitAI 2024-12-22 16:26:49 +01:00
Edward Firmo
23b633cdcb Run all tests in parallel
Let's see if this saves some time.
2024-12-22 16:20:51 +01:00
Edward Firmo
b1187332fb Ensure latest and stable tags are updated on push to main 2024-12-22 16:17:07 +01:00
Edward Firmo
669cc2f2c2 Use main as reference for remote package 2024-12-22 16:03:39 +01:00
18 changed files with 1780 additions and 711 deletions

View File

@@ -1,40 +0,0 @@
# This GitHub Actions workflow updates the "stable" and "latest" Git tags
# to point to the tag associated with a newly published release. It performs
# the following steps:
# 1. Checks out the repository code with full history.
# 2. Configures Git with a generic user for the action.
# 3. Moves and forcibly pushes the "stable" and "latest" tags to align with
# the tag of the newly published release.
# This ensures that "stable" and "latest" always point to the most recent release.
---
name: Update Tags
# yamllint disable-line rule:truthy
on:
release:
types: [published]
jobs:
update-tags:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@main
with:
fetch-depth: '0'
- name: Set up Git
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
- name: Move and push stable tag
run: |
git tag -f stable ${{ github.event.release.tag_name }}
git push -f origin stable
- name: Move and push latest tag
run: |
git tag -f latest ${{ github.event.release.tag_name }}
git push -f origin latest
...

View File

@@ -1,8 +1,7 @@
---
name: Validate ESPHome
name: Validate ESPHome (Latest)
# yamllint disable-line rule:truthy
on:
on: # yamllint disable-line rule:truthy
workflow_dispatch:
concurrency:
@@ -30,8 +29,6 @@ jobs:
build_basic:
name: Basic
needs:
- code_scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
@@ -39,10 +36,10 @@ jobs:
uses: esphome/build-action@main
with:
yaml-file: ".test/esphome_ard_basic.yaml"
version: latest
build_bluetooth_proxy_4:
name: Bluetooth Proxy (IDF)
needs: build_basic
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
@@ -50,10 +47,10 @@ jobs:
uses: esphome/build-action@main
with:
yaml-file: ".test/esphome_idf_bluetooth_proxy.yaml"
version: latest
build_bluetooth_proxy_53:
name: Bluetooth Proxy (IDF v5.3)
needs: build_basic
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
@@ -61,4 +58,5 @@ jobs:
uses: esphome/build-action@main
with:
yaml-file: ".test/esphome_idf53_bluetooth_proxy.yaml"
version: latest
...

View File

@@ -11,6 +11,8 @@ on: # yamllint disable-line rule:truthy
- "*.c"
- "*.cpp"
- "*.py"
branches:
- main
pull_request:
paths:
- "*.yaml"
@@ -47,8 +49,6 @@ jobs:
build_basic:
name: Basic
needs:
- code_scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
@@ -60,7 +60,6 @@ jobs:
build_bluetooth_proxy_4:
name: Bluetooth Proxy (IDF)
needs: build_basic
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
@@ -72,7 +71,6 @@ jobs:
build_bluetooth_proxy_53:
name: Bluetooth Proxy (IDF v5.3)
needs: build_basic
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main

View File

@@ -1,6 +1,11 @@
# Workflow for managing versioning and tagging
# This GitHub Actions workflow handles version bumping and tag updates.
# It can be triggered either by:
# 1. Pushing to main branch - automatically bumps version and updates tags
# 2. Manual dispatch - allows independent control over stable and latest tags
---
name: Version Bump and Tag
name: Version and Tags
on: # yamllint disable-line rule:truthy
push:
@@ -9,34 +14,93 @@ on: # yamllint disable-line rule:truthy
paths-ignore:
- '**/VERSION'
- '**/VERSION_YAML'
workflow_dispatch:
inputs:
update_stable:
description: "Update stable tag?"
required: true
default: "false"
default: false
type: boolean
update_latest:
description: "Update latest tag?"
required: true
default: false
type: boolean
jobs:
versioning:
version-and-tag:
runs-on: ubuntu-latest
steps:
- uses: "actions/checkout@v4"
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Git
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
- name: Bump Version
- name: Bump version
run: |
chmod +x "./versioning/bump_version.sh"
"./versioning/bump_version.sh"
chmod +x ./versioning/bump_version.sh
./versioning/bump_version.sh
- name: Push Changes and Tags
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git push "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" main
git push "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" --tags
git push origin main
git push origin --tags --force
- name: Update stable tag
if: |
success() && (
github.event_name == 'workflow_dispatch' && inputs.update_stable ||
github.event_name == 'push'
)
run: |
# Verify version bump was successful
if [ ! -f "./versioning/VERSION" ]; then
echo "Error: VERSION file not found. Version bump may have failed."
exit 1
fi
# Backup existing tag
if git rev-parse --verify stable >/dev/null 2>&1; then
OLD_STABLE=$(git rev-parse stable)
echo "Backing up current stable tag ($OLD_STABLE)"
fi
# Update tag
NEW_VERSION=$(cat ./versioning/VERSION)
echo "Updating stable tag to $NEW_VERSION"
git tag -fa stable -m "Update stable tag"
git push origin stable --force
- name: Update latest tag
if: |
success() && (
github.event_name == 'workflow_dispatch' && inputs.update_latest ||
github.event_name == 'push'
)
run: |
# Verify version bump was successful
if [ ! -f "./versioning/VERSION" ]; then
echo "Error: VERSION file not found. Version bump may have failed."
exit 1
fi
# Backup existing tag
if git rev-parse --verify latest >/dev/null 2>&1; then
OLD_LATEST=$(git rev-parse latest)
echo "Backing up current latest tag ($OLD_LATEST)"
fi
# Update tag
NEW_VERSION=$(cat ./versioning/VERSION)
echo "Updating latest tag to $NEW_VERSION"
git tag -fa latest -m "Update latest tag"
git push origin latest --force
...

View File

@@ -11,6 +11,27 @@
##### - 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
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 (rtttl_speaker_gain->state > 0) {
ESP_LOGI("api", "Play tone: '%s'", tone.c_str());
rtttl_speaker->play(tone.c_str());
}
bluetooth_proxy:
esp32:
@@ -33,17 +54,60 @@ esphome:
build_flags:
- -D TX_ULTIMATE_EASY_ADDON_BLE_PROXY
i2s_audio: !remove
light:
- id: !extend light_full
platform: esp32_rmt_led_strip
rgb_order: GRB
rmt_channel: 0
rmt_channel: 1
chipset: ws2812
type: !remove
variant: !remove
max_refresh_rate: 33ms
use_psram: true
media_player: !remove
number:
- id: rtttl_speaker_gain
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:
- lambda: |-
rtttl_speaker->set_gain((100-(x/10.0f))/100.0f);
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_speaker->dump_config();
rtttl:
- id: rtttl_speaker
speaker: mp_speaker
script:
- id: !extend dump_config
then:
- lambda: |-
ESP_LOGCONFIG("addon_ble_proxy", "Add-on BLE Proxy installed");
speaker:
- id: mp_speaker
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

@@ -25,17 +25,42 @@ substitutions:
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
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_media_player: !include TX-Ultimate-Easy-ESPHome_core_hw_media_player.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
# yamllint enable rule:colons
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
@@ -70,6 +95,23 @@ esphome:
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
# initial_value: "''"
improv_serial:
id: serial_improv
@@ -80,15 +122,29 @@ ota:
platform: esphome
psram:
mode: octal
speed: 80MHz
script:
- id: api_send_ha_event_boot
mode: queued
parameters:
type: string
then:
- homeassistant.event:
event: esphome.tx_ultimate_easy
data:
device_name: !lambda return tx_device_name->state.c_str();
firmware: ${version}
domain: boot
type: !lambda return type.c_str();
- id: boot_done
mode: restart
then:
- script.execute:
id: send_event_to_ha
component: boot
event: done
id: api_send_ha_event_boot
type: done
- id: boot_initialize
mode: restart
@@ -98,14 +154,69 @@ script:
# - HW Relays
# - HW Touch
- script.execute:
id: send_event_to_ha
component: boot
event: start
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());
// Version information
ESP_LOGCONFIG("core", "ESPHome builder: %s", esphome_fw_version->state.c_str());
ESP_LOGCONFIG("core", "TX Ultimate firmware version: ${version}");
// Framework detection
#ifdef 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
- id: publish_device_info
mode: restart
@@ -128,6 +239,14 @@ select:
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)
@@ -144,10 +263,25 @@ select:
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: esphome_fw_version
name: ESPHome Version
platform: version
entity_category: diagnostic
internal: false
- id: tx_fw_version
name: Firmware version
name: TX Ultimate Easy Firmware Version
platform: template
entity_category: diagnostic
icon: mdi:tag-text-outline
@@ -189,5 +323,6 @@ time:
web_server:
wifi:
id: wifi_component
ap:
...

View File

@@ -1,41 +0,0 @@
####################################################################################################
##### TX Ultimate Easy for ESPHome #####
##### Repository: https://github.com/edwardtfn/TX-Ultimate-Easy #####
####################################################################################################
##### Purpose: ESPHome Core - API #####
####################################################################################################
##### 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. #####
####################################################################################################
---
api:
id: api_server
on_client_connected:
then:
- script.execute: publish_device_info
script:
- id: !extend button_action
then:
- script.execute:
id: send_event_to_ha
component: !lambda return component.c_str();
event: !lambda return event.c_str();
- 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();
...

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
@@ -76,59 +86,106 @@ 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
- homeassistant.event:
event: esphome.tx_ultimate_easy
data:
device_name: !lambda return tx_device_name->state.c_str();
firmware: ${version}
domain: touch
type: button
action: !lambda return action.c_str();
button_id: !lambda return button;
count: !lambda return count;
position: !lambda return id(button_press_position);
- lambda: |-
ESP_LOGI("core_hw_buttons", "Button '%s' action: '%s'", component.c_str(), event.c_str());
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 +200,28 @@ script:
}
}
- id: !extend dump_config
then:
- lambda: |-
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 touch_on_multi_touch_release
then:
- script.execute: buttons_release
@@ -151,30 +230,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
id(button_press_button) = button;
// Update counters
if (id(button_press_position) == position) {
id(click_counter)++;
} 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(click_counter) = 1;
id(button_press_position) = position;
}
// Update binary sensor
switch (button) {
@@ -191,13 +264,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 +281,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 +306,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 +321,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 +331,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 +341,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,10 @@ 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
globals:
- id: gb_lights_1
type: std::vector<light::LightState*>
@@ -44,6 +48,7 @@ light:
# method: esp32_rmt
num_leds: 32
pin: GPIO13
restore_mode: ${LIGHT_FULL_RESTORE_MODE}
# Those lights are available based on the model selections
- &light_partition_with_effects
@@ -52,6 +57,7 @@ light:
platform: partition
default_transition_length: ${default_transition_length}
internal: true
restore_mode: ${LIGHT_SIDES_RESTORE_MODE}
effects:
- addressable_rainbow:
name: "Rainbow"
@@ -184,6 +190,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,330 +417,32 @@ 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) {
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));
// 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 (is_model_us) {
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 {
@@ -742,7 +451,7 @@ script:
}
break;
case 2: // 2 Gang
if (is_model_us) {
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 {
@@ -751,7 +460,7 @@ script:
}
break;
case 3: // 3 Gang
if (is_model_us) {
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 {
@@ -760,7 +469,7 @@ script:
}
break;
case 4: // 4 Gang
if (is_model_us) {
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,
@@ -772,8 +481,52 @@ script:
light_eu_rl_3_4_top, light_eu_rl_4_4_top };
}
break;
default:
ESP_LOGE("core_hw_leds", "Invalid gang count: %" PRIu8, id(gang_count));
break;
}
- 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: light_set_state
mode: parallel
parameters:
@@ -786,21 +539,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 +564,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 +574,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 +588,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
@@ -860,15 +615,12 @@ select:
entity_category: config
disabled_by_default: false
icon: mdi:dots-square
- id: sl_relay_2_light_mode_eu
name: Relay 2 light mode
<<: *relay_light_mode_eu
- id: sl_relay_3_light_mode_eu
name: Relay 3 light mode
<<: *relay_light_mode_eu
- id: sl_relay_4_light_mode_eu
name: Relay 4 light mode
<<: *relay_light_mode_eu
@@ -890,15 +642,12 @@ select:
entity_category: config
disabled_by_default: false
icon: mdi:dots-square
- id: sl_relay_2_light_mode_us
name: Relay 2 light mode
<<: *relay_light_mode_us
- id: sl_relay_3_light_mode_us
name: Relay 3 light mode
<<: *relay_light_mode_us
- id: sl_relay_4_light_mode_us
name: Relay 4 light mode
<<: *relay_light_mode_us

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

@@ -11,46 +11,419 @@
##### - 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
globals:
- id: boot_initialization_relays
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
- &light_binary_base
id: light_output_1
- 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
<<: *light_binary_base
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
<<: *light_binary_base
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
<<: *light_binary_base
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: true
default_transition_length: ${default_transition_length}
restore_mode: ${LIGHT_RELAYS_RESTORE_MODE}
segments:
- id: light_full
from: 9
to: 9
- id: light_eu_rl_1_1_top
name: Light - Relay 1 of 1 (top)
<<: *light_partition_relays
segments:
- id: light_full
from: 23
to: 23
- id: light_eu_rl_1_2_bottom
name: Light - Relay 1 of 2 (bottom)
<<: *light_partition_relays
segments:
- id: light_full
from: 11
to: 11
- id: light_eu_rl_1_2_top
name: Light - Relay 1 of 2 (top)
<<: *light_partition_relays
segments:
- id: light_full
from: 21
to: 21
- id: light_eu_rl_2_2_bottom
name: Light - Relay 2 of 2 (bottom)
<<: *light_partition_relays
segments:
- id: light_full
from: 7
to: 7
- id: light_eu_rl_2_2_top
name: Light - Relay 2 of 2 (top)
<<: *light_partition_relays
segments:
- id: light_full
from: 25
to: 25
- id: light_eu_rl_1_3_bottom
name: Light - Relay 1 of 3 (bottom)
<<: *light_partition_relays
segments:
- id: light_full
from: 12
to: 12
- id: light_eu_rl_1_3_top
name: Light - Relay 1 of 3 (top)
<<: *light_partition_relays
segments:
- id: light_full
from: 20
to: 20
- id: light_eu_rl_2_3_bottom
name: Light - Relay 2 of 3 (bottom)
<<: *light_partition_relays
segments:
- id: light_full
from: 9
to: 9
- id: light_eu_rl_2_3_top
name: Light - Relay 2 of 3 (top)
<<: *light_partition_relays
segments:
- id: light_full
from: 23
to: 23
- id: light_eu_rl_3_3_bottom
name: Light - Relay 3 of 3 (bottom)
<<: *light_partition_relays
segments:
- id: light_full
from: 6
to: 6
- id: light_eu_rl_3_3_top
name: Light - Relay 3 of 3 (top)
<<: *light_partition_relays
segments:
- id: light_full
from: 26
to: 26
- id: light_eu_rl_1_4_bottom
name: Light - Relay 1 of 4 (bottom)
<<: *light_partition_relays
segments:
- id: light_full
from: 12
to: 12
- id: light_eu_rl_1_4_top
name: Light - Relay 1 of 4 (top)
<<: *light_partition_relays
segments:
- id: light_full
from: 20
to: 20
- id: light_eu_rl_2_4_bottom
name: Light - Relay 2 of 4 (bottom)
<<: *light_partition_relays
segments:
- id: light_full
from: 10
to: 10
- id: light_eu_rl_2_4_top
name: Light - Relay 2 of 4 (top)
<<: *light_partition_relays
segments:
- id: light_full
from: 22
to: 22
- id: light_eu_rl_3_4_bottom
name: Light - Relay 3 of 4 (bottom)
<<: *light_partition_relays
segments:
- id: light_full
from: 8
to: 8
- id: light_eu_rl_3_4_top
name: Light - Relay 3 of 4 (top)
<<: *light_partition_relays
segments:
- id: light_full
from: 24
to: 24
- id: light_eu_rl_4_4_bottom
name: Light - Relay 4 of 4 (bottom)
<<: *light_partition_relays
segments:
- id: light_full
from: 6
to: 6
- id: light_eu_rl_4_4_top
name: Light - Relay 4 of 4 (top)
<<: *light_partition_relays
segments:
- id: light_full
from: 26
to: 26
- id: light_us_rl_1_1_left
name: Light - Relay 1 of 1 (left)
<<: *light_partition_relays
segments:
- id: light_full
from: 15
to: 24
- id: light_us_rl_1_1_right
name: Light - Relay 1 of 1 (right)
<<: *light_partition_relays
segments:
- id: light_full
from: 31
to: 31
- id: light_full
from: 0
to: 8
- id: light_us_rl_1_2_left
name: Light - Relay 1 of 2 (left)
<<: *light_partition_relays
segments:
- id: light_full
from: 20
to: 24
- id: light_us_rl_1_2_right
name: Light - Relay 1 of 2 (right)
<<: *light_partition_relays
segments:
- id: light_full
from: 31
to: 31
- id: light_full
from: 0
to: 3
- id: light_us_rl_2_2_left
name: Light - Relay 2 of 2 (left)
<<: *light_partition_relays
segments:
- id: light_full
from: 15
to: 19
- id: light_us_rl_2_2_right
name: Light - Relay 2 of 2 (right)
<<: *light_partition_relays
segments:
- id: light_full
from: 4
to: 8
- id: light_us_rl_1_3_left
name: Light - Relay 1 of 3 (left)
<<: *light_partition_relays
segments:
- id: light_full
from: 22
to: 23
- id: light_us_rl_1_3_right
name: Light - Relay 1 of 3 (right)
<<: *light_partition_relays
segments:
- id: light_full
from: 0
to: 1
- id: light_us_rl_2_3_left
name: Light - Relay 2 of 3 (left)
<<: *light_partition_relays
segments:
- id: light_full
from: 19
to: 20
- id: light_us_rl_2_3_right
name: Light - Relay 2 of 3 (right)
<<: *light_partition_relays
segments:
- id: light_full
from: 3
to: 4
- id: light_us_rl_3_3_left
name: Light - Relay 3 of 3 (left)
<<: *light_partition_relays
segments:
- id: light_full
from: 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
@@ -63,31 +436,112 @@ script:
- id: boot_initialize_relays
mode: restart
then:
- 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_light_modes
- script.wait: boot_initialize_relays_relay_leds
- script.wait: boot_initialize_relays_relay_modes
- wait_until:
condition:
- lambda: return sl_tx_model_format->active_index().has_value();
- lambda: return sl_tx_model_gang->active_index().has_value();
- 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_light_modes
mode: restart
then:
- 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);
// 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);
@@ -95,20 +549,22 @@ script:
}
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);
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(num_gangs < 3 or relay_mode_index.value() != 1);
sw_relay_3->set_internal(num_gangs < 3 or relay_mode_index.value() != 0);
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(num_gangs < 4 or relay_mode_index.value() != 1);
sw_relay_4->set_internal(num_gangs < 4 or relay_mode_index.value() != 0);
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);
}
id(boot_initialization_relays) = true;
// Set this section of initialization as completed
id(boot_initialization_relays_relay_modes) = true;
- id: !extend button_click_event
then:
@@ -126,55 +582,118 @@ script:
}
// 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)
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("core_hw_relays", "Toggle relays:");
ESP_LOGW("core_hw_relays", " API state: DISCONNECTED");
ESP_LOGW("core_hw_relays", " Button: %" PRIu8, button);
} else {
ESP_LOGVV("core_hw_relays", "Toggle relays:");
ESP_LOGVV("core_hw_relays", " API state: Connected");
ESP_LOGVV("core_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 2:
if (sl_button_2_action->active_index().has_value() and
sl_button_2_action->active_index().value() == 1)
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 3:
if (sl_button_3_action->active_index().has_value() and
sl_button_3_action->active_index().value() == 1)
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 4:
if (sl_button_4_action->active_index().has_value() and
sl_button_4_action->active_index().value() == 1)
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("core_hw_relays", "Toggle relay %" PRIu8 ": (%s)", button, select_state.c_str());
} else if (not select_state.empty()) {
ESP_LOGV("core_hw_relays", "Ignoring toggle for relay %" PRIu8 ": action is '%s'",
button, select_state.c_str());
} else {
ESP_LOGE("core_hw_relays", "No button action selected for button %" PRIu8, button);
}
- id: !extend dump_config
then:
- lambda: |-
ESP_LOGCONFIG("core_hw_relays", "Relay%s mode%s:",
id(gang_count_plural_suffix).c_str(),
id(gang_count_plural_suffix).c_str());
ESP_LOGCONFIG("core_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("core_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("core_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("core_hw_relays", " Relay 4: %s", sl_relay_4_mode->has_state()
? sl_relay_4_mode->state.c_str()
: "Unknown");
ESP_LOGCONFIG("core_hw_relays", "Relay%s state%s:",
id(gang_count_plural_suffix).c_str(),
id(gang_count_plural_suffix).c_str());
ESP_LOGCONFIG("core_hw_relays", " Relay 1: %s", sw_relay_1->state ? "ON" : "OFF");
if (id(gang_count) >= 2)
ESP_LOGCONFIG("core_hw_relays", " Relay 2: %s", sw_relay_2->state ? "ON" : "OFF");
if (id(gang_count) >= 3)
ESP_LOGCONFIG("core_hw_relays", " Relay 3: %s", sw_relay_3->state ? "ON" : "OFF");
if (id(gang_count) >= 4)
ESP_LOGCONFIG("core_hw_relays", " Relay 4: %s", sw_relay_4->state ? "ON" : "OFF");
ESP_LOGCONFIG("core_hw_relays", "Expose Relay's LEDs to Home Assistant: %s",
YESNO(sw_expose_relays_leds_to_ha->state));
ESP_LOGCONFIG("core_hw_relays", "Boot initialization flags:");
ESP_LOGCONFIG("core_hw_relays", " Overall: %s", YESNO(id(boot_initialization_relays)));
ESP_LOGCONFIG("core_hw_relays", " Light modes: %s", YESNO(id(boot_initialization_relays_light_modes)));
ESP_LOGCONFIG("core_hw_relays", " Relay modes: %s", YESNO(id(boot_initialization_relays_relay_modes)));
ESP_LOGCONFIG("core_hw_relays", " Status LEDs: %s", YESNO(id(boot_initialization_relays_relay_leds)));
ESP_LOGCONFIG("core_hw_relays", "Restore modes:");
ESP_LOGCONFIG("core_hw_relays", " Relays: ${RELAY_RESTORE_MODE}");
ESP_LOGCONFIG("core_hw_relays", " Status LEDs: ${LIGHT_RELAYS_RESTORE_MODE}");
- 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);
if (not id(boot_initialization_relays)) {
ESP_LOGW("core_hw_relays", "Relays not initialized yet");
if (not boot_initialize_relays->is_running())
boot_initialize_relays->execute();
return;
}
for (uint8_t i = 0; i < num_gangs; i++) {
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 = is_model_us
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 = is_model_us
const std::string light_mode_group_2 = id(is_us_model)
? "${LIGHT_MODE_RIGHT_TEXT}"
: "${LIGHT_MODE_TOP_TEXT}";
@@ -182,25 +701,25 @@ script:
switch (i) {
case 0:
relay_state = id(sw_relay_1).state;
light_mode = is_model_us
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 = is_model_us
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 = is_model_us
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 = is_model_us
light_mode = id(is_us_model)
? id(sl_relay_4_light_mode_us)->state
: id(sl_relay_4_light_mode_eu)->state;
break;
@@ -226,58 +745,139 @@ script:
select:
- &relay_select_mode_base
id: sl_relay_1_mode
name: Relay 1 mode
name: Relay 1 display mode
platform: template
options:
- "Relay"
- "Light"
- "Not in use"
- "${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 mode
name: Relay 2 display mode
<<: *relay_select_mode_base
- id: sl_relay_3_mode
name: Relay 3 mode
name: Relay 3 display mode
<<: *relay_select_mode_base
- id: sl_relay_4_mode
name: Relay 4 mode
name: Relay 4 display mode
<<: *relay_select_mode_base
switch:
- &relay_switch_base
id: sw_relay_1
name: Relay 1
platform: output
output: output_relay_1
- 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
<<: *relay_switch_base
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
<<: *relay_switch_base
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
<<: *relay_switch_base
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

@@ -15,50 +15,188 @@ 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
external_components:
- source:
@@ -71,7 +209,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 +229,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 +253,60 @@ 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: |-
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: 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: OFF # 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
@@ -139,57 +318,30 @@ script:
# Extended by:
# - HW Buttons
# - HW Vibration
- script.execute: touch_swipe_turn_off_binary_sensor
- 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
id: bs_swipe_up
state: ON # yamllint disable-line rule:truthy
switch:
- id: sw_touch_panel_power
@@ -210,42 +362,81 @@ 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");
- homeassistant.event:
event: esphome.tx_ultimate_easy
data:
device_name: !lambda return tx_device_name->state.c_str();
firmware: ${version}
domain: touch
type: multi_touch
action: release
position: !lambda return touch.x;
- lambda: ESP_LOGI("core_hw_touch", "Multi-touch released");
- script.execute: touch_on_multi_touch_release
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);
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("tx_ultimate_easy", "Pressed at position %" PRIu8, touch_position);
touch_on_press->execute(touch_position);
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");
- lambda: ESP_LOGI("core_hw_touch", "Released");
- script.execute: touch_on_release
on_swipe_left:
- lambda: ESP_LOGI("tx_ultimate_easy", "Swipe left");
- homeassistant.event:
event: esphome.tx_ultimate_easy
data:
device_name: !lambda return tx_device_name->state.c_str();
firmware: ${version}
domain: touch
type: swipe
action: !lambda |-
return sl_tx_model_format->state == "${TX_MODEL_FORMAT_EU_TEXT}" ? "left" : "down";
swipe-direction: !lambda |-
return sl_tx_model_format->state == "${TX_MODEL_FORMAT_EU_TEXT}" ? "left" : "down";
position: !lambda return touch.x;
- lambda: |-
ESP_LOGI("core_hw_touch", "Swipe %s", sl_tx_model_format->state == "${TX_MODEL_FORMAT_EU_TEXT}"
? "left"
: "down");
- script.execute: touch_swipe_left
on_swipe_right:
- lambda: ESP_LOGI("tx_ultimate_easy", "Swipe right");
- homeassistant.event:
event: esphome.tx_ultimate_easy
data:
device_name: !lambda return tx_device_name->state.c_str();
firmware: ${version}
domain: touch
type: swipe
action: !lambda |-
return sl_tx_model_format->state == "${TX_MODEL_FORMAT_EU_TEXT}" ? "right" : "up";
swipe-direction: !lambda |-
return sl_tx_model_format->state == "${TX_MODEL_FORMAT_EU_TEXT}" ? "right" : "up";
position: !lambda return touch.x;
- lambda: |-
ESP_LOGI("core_hw_touch", "Swipe %s", sl_tx_model_format->state == "${TX_MODEL_FORMAT_EU_TEXT}"
? "right"
: "up");
- script.execute: touch_swipe_right
on_touch_event:
- lambda: |-
ESP_LOGD("tx_ultimate_easy", "Touch event:");
ESP_LOGD("tx_ultimate_easy", " State: %i (%s)", touch.state, touch.state_str.c_str());
ESP_LOGD("tx_ultimate_easy", " Position: %i", touch.x);
ESP_LOGD("core_hw_touch", "Touch event:");
ESP_LOGD("core_hw_touch", " State: %i (%s)", touch.state, touch.state_str.c_str());
ESP_LOGD("core_hw_touch", " Position: %i", touch.x);
uart:
- id: uart_touch

View File

@@ -53,6 +53,21 @@ ota:
- switch.turn_off: sw_vibration_motor
script:
- id: !extend dump_config
then:
- lambda: |-
// Configuration
ESP_LOGCONFIG("core_hw_vibration", "Touch - Vibration feedback: %s",
sl_touch_vibration_feedback->state.c_str());
ESP_LOGCONFIG("core_hw_vibration", "Vibrate duration: %.0fms", nr_vibrating_duration->state);
ESP_LOGCONFIG("core_hw_vibration", "Vibrate max duration: ${vibration_max_duration}");
// State
if (bs_vibrating->state)
ESP_LOGW("core_hw_vibration", "Vibrating now: YES");
else
ESP_LOGCONFIG("core_hw_vibration", "Vibrating now: No");
- id: !extend touch_on_multi_touch_release
then:
- script.execute: touch_on_multi_touch_release_vibration
@@ -133,5 +148,4 @@ switch:
- binary_sensor.template.publish:
id: bs_vibrating
state: OFF # yamllint disable-line rule:truthy
...

View File

@@ -1,19 +1,20 @@
# TX Ultimate Easy
<!-- markdownlint-disable MD033 -->
<a href="https://github.com/edwardtfn/TX-Ultimate-Easy/commits/main" target="_blank">![GitHub Activity][commits-shield]</a>
<a href="LICENSE" target="_blank">![License][license-shield]</a>
<a href="https://github.com/edwardtfn/TX-Ultimate-Easy/commits/main" target="_blank">![GitHub Last Commit][last-commit-shield]</a>
<a href="https://esphome.io/" target="_blank">![ESPHome][esphome-shield]</a>
<a href="https://discord.gg/Db6WJWzWuf" target="_blank">![Discord][discord-shield]</a>
<a href="https://www.buymeacoffee.com/edwardfirmo" target="_blank">![Buy me an ice-cream][buymeacoffee-shield]</a>
<!-- markdownlint-enable MD033 -->
[![Version][version-shield]](https://github.com/edwardtfn/TX-Ultimate-Easy/tags)
[![GitHub Activity][commits-shield]](https://github.com/edwardtfn/TX-Ultimate-Easy/commits/main)
[![License][license-shield]](LICENSE)
[![GitHub Last Commit][last-commit-shield]](https://github.com/edwardtfn/TX-Ultimate-Easy/commits/main)
[![ESPHome][esphome-shield]](https://esphome.io/)
[![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-enable MD013 -->
[version-shield]: https://img.shields.io/github/v/tag/edwardtfn/TX-Ultimate-Easy?label=version
[version]: https://github.com/edwardtfn/TX-Ultimate-Easy/tags
[commits-shield]: https://img.shields.io/github/commit-activity/y/edwardtfn/TX-Ultimate-Easy
[commits]: https://github.com/edwardtfn/TX-Ultimate-Easy/commits/main
[license-shield]: https://img.shields.io/github/license/edwardtfn/TX-Ultimate-Easy
@@ -28,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
@@ -103,6 +129,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
@@ -111,11 +138,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)

View File

@@ -16,8 +16,8 @@ wifi:
packages:
remote_package:
url: https://github.com/edwardtfn/TX-Ultimate-Easy
ref: latest
refresh: 30s
ref: latest # Or you can specify a version, like `ref: v2024.12.6`
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)

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.4
2024.12.19

View File

@@ -1 +1 @@
version: 2024.12.4
version: 2024.12.19