Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0d49f10
Move HA event handling to component
edwardtfn Nov 27, 2025
b980893
Bump to 2025.11.0-Dev
edwardtfn Nov 27, 2025
a2bfa99
Rename YAML files: drop core_ and standard_ prefixes
edwardtfn Nov 27, 2025
399eaeb
Update file dependancies
edwardtfn Nov 27, 2025
3f343b8
Use new format for `select`
edwardtfn Nov 27, 2025
10a5c1a
Standardize event call
edwardtfn Nov 27, 2025
9112901
Standardize header
edwardtfn Nov 27, 2025
b100126
Simplify `device_name` engine
edwardtfn Nov 27, 2025
5c39d54
Rename standard_hw_relays_package to hw_relays_package
edwardtfn Nov 27, 2025
83a0ccc
Rename standard_hw_speaker_package to hw_speaker_package
edwardtfn Nov 27, 2025
fa58eb1
Rename standard_hw_vibration_package to hw_vibration_package
edwardtfn Nov 27, 2025
ebbb629
Rename standard_hw_relays_package to hw_relays_package
edwardtfn Nov 27, 2025
8318444
Rename standard_hw_speaker_package to hw_speaker_package
edwardtfn Nov 27, 2025
d21a36a
Rename standard_hw_vibration_package to hw_vibration_package
edwardtfn Nov 27, 2025
170a8a3
yaml to c++
edwardtfn Nov 29, 2025
513f7d5
Increase `loop_task_stack_size` to 16Kb
edwardtfn Nov 29, 2025
50a88bb
Memory optimization - CONFIG_ESP32_REV_MIN_3
edwardtfn Nov 29, 2025
3f64d4e
Invert Up/Down swipe directions detection
edwardtfn Dec 9, 2025
6d09f75
Apply CodeRabit "nitpick comments"
edwardtfn Dec 9, 2025
845ba20
Move `initialize_cached_device_name` to component
edwardtfn Dec 9, 2025
9e85508
Use new file names
edwardtfn Dec 9, 2025
c531f02
Fix undefined behavior in character classification
edwardtfn Dec 9, 2025
e5348bb
Remove trailing underscore if present
edwardtfn Dec 9, 2025
5dddc7b
Add guard for uninitialized device name
edwardtfn Dec 9, 2025
2ec6053
include <cctype>
edwardtfn Dec 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .test/esphome_ard_hw_relays.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
packages:
common_arduino: !include common_ard.yaml
core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
standard_hw_relays_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_relays.yaml
hw_relays_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_hw_relays.yaml
...
2 changes: 1 addition & 1 deletion .test/esphome_ard_hw_speaker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
packages:
common_arduino: !include common_ard.yaml
core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
standard_hw_speaker_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_speaker.yaml
hw_speaker_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_hw_speaker.yaml
...
2 changes: 1 addition & 1 deletion .test/esphome_ard_hw_vibration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
packages:
common_arduino: !include common_ard.yaml
core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
standard_hw_vibration_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_vibration.yaml
hw_vibration_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_hw_vibration.yaml
...
2 changes: 1 addition & 1 deletion .test/esphome_idf_hw_relays.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
packages:
common_idf: !include common_idf.yaml
core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
standard_hw_relays_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_relays.yaml
hw_relays_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_hw_relays.yaml
...
2 changes: 1 addition & 1 deletion .test/esphome_idf_hw_speaker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
packages:
common_idf: !include common_idf.yaml
core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
standard_hw_speaker_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_speaker.yaml
hw_speaker_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_hw_speaker.yaml
...
2 changes: 1 addition & 1 deletion .test/esphome_idf_hw_vibration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
packages:
common_idf: !include common_idf.yaml
core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
standard_hw_vibration_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_vibration.yaml
hw_vibration_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_hw_vibration.yaml
...
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
##### TX Ultimate Easy for ESPHome #####
##### Repository: https://github.com/edwardtfn/TX-Ultimate-Easy #####
####################################################################################################
##### Purpose: ESPHome Core - Common #####
##### Purpose: ESPHome - Common #####
####################################################################################################
##### Author: edwardtfn - https://github.com/edwardtfn - https://buymeacoffee.com/edwardfirmo #####
####################################################################################################
Expand All @@ -29,14 +29,14 @@ substitutions:

DUMP_CONFIG_CALLER_DELAY: 5s # Delay to dump config after requested

TAG_CORE_COMMON: core.common
TAG_COMMON: tx_ultimate_easy.common

api:
id: api_server
homeassistant_services: true
on_client_connected:
then:
- script.execute: dump_config_caller
- script.execute: publish_device_info

binary_sensor:
- id: bs_pending_restart
Expand Down Expand Up @@ -73,18 +73,23 @@ esp32:
flash_size: 8MB
framework:
type: esp-idf
advanced:
loop_task_stack_size: 16384
sdkconfig_options:
CONFIG_ESP32_REV_MIN_3: y

esphome:
name: ${name}
friendly_name: ${friendly_name}
comment: TX Ultimate Easy
min_version: 2025.8.0
min_version: 2025.11.0
project:
name: "edwardtfn.tx_ultimate_easy"
version: ${version}
platformio_options:
build_flags:
- -D TX_ULTIMATE_EASY_CORE_COMMON
- -D TX_ULTIMATE_EASY_COMMON
- -D TX_ULTIMATE_EASY_FIRMWARE_VERSION="${version}"

on_boot:
- priority: 1000 # Very early in boot process
Expand Down Expand Up @@ -145,13 +150,7 @@ script:
then:
- lambda: |-
// Send event to Home Assistant
esphome::api::CustomAPIDevice ha_event;
ha_event.fire_homeassistant_event("${EVENT_NAME}", {
{"device_name", id(tx_device_name).state.c_str()},
{"firmware", "${version}"},
{"domain", "boot"},
{"type", type.c_str()}
});
esphome::tx_ultimate_easy::fire_ha_event("boot", type.c_str(), {});

- id: boot_done
mode: restart
Expand All @@ -174,6 +173,7 @@ script:
# - HW Buttons
# - HW Relays
# - HW Touch
- script.execute: update_device_name
- script.execute:
id: api_send_ha_event_boot
type: start
Expand All @@ -182,16 +182,15 @@ script:
- 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(is_us_model) = strcmp(sl_tx_model_format->current_option(), "${TX_MODEL_FORMAT_US_TEXT}") == 0;
id(gang_count) = sl_tx_model_gang->active_index().value() + 1;
if (id(gang_count) < 1 || id(gang_count) > 4) {
ESP_LOGE("${TAG_CORE_COMMON}", "Invalid number of gangs: %" PRIu8, id(gang_count));
ESP_LOGE("${TAG_COMMON}", "Invalid number of gangs: %" PRIu8, id(gang_count));
}

- id: boot_sequence
mode: restart
then:
- script.execute: publish_device_info
- binary_sensor.template.publish:
id: bs_pending_restart
state: false
Expand All @@ -202,43 +201,43 @@ script:
# Extended by all modules
- lambda: |-
// Device identification
ESP_LOGCONFIG("${TAG_CORE_COMMON}", "Device friendly name: ${friendly_name}");
ESP_LOGCONFIG("${TAG_CORE_COMMON}", "Device name: ${name}");
ESP_LOGCONFIG("${TAG_CORE_COMMON}", "Device name (HA): %s", tx_device_name->state.c_str());
ESP_LOGCONFIG("${TAG_CORE_COMMON}", "Device hostname: %s", App.get_name().c_str());
ESP_LOGCONFIG("${TAG_COMMON}", "Device friendly name: ${friendly_name}");
ESP_LOGCONFIG("${TAG_COMMON}", "Device name: ${name}");
ESP_LOGCONFIG("${TAG_COMMON}", "Device name (HA): %s", esphome::tx_ultimate_easy::cached_device_name.c_str());
ESP_LOGCONFIG("${TAG_COMMON}", "Device hostname: %s", App.get_name().c_str());

dump_config_versions->execute();

// Framework detection
#ifdef USE_ARDUINO
ESP_LOGCONFIG("${TAG_CORE_COMMON}", "Framework: Arduino");
ESP_LOGCONFIG("${TAG_COMMON}", "Framework: Arduino");
#elif defined(USE_ESP_IDF)
ESP_LOGCONFIG("${TAG_CORE_COMMON}", "Framework: ESP-IDF");
ESP_LOGCONFIG("${TAG_COMMON}", "Framework: ESP-IDF");
#else
ESP_LOGW("${TAG_CORE_COMMON}", "Framework: UNKNOWN");
ESP_LOGW("${TAG_COMMON}", "Framework: UNKNOWN");
#endif

// Model configuration
ESP_LOGCONFIG("${TAG_CORE_COMMON}", "Model format (selected): %s",
sl_tx_model_format->state.c_str());
ESP_LOGCONFIG("${TAG_CORE_COMMON}", "Model format (detected): %s",
ESP_LOGCONFIG("${TAG_COMMON}", "Model format (selected): %s",
sl_tx_model_format->current_option());
ESP_LOGCONFIG("${TAG_COMMON}", "Model format (detected): %s",
id(is_us_model) ? "US" : "EU");
ESP_LOGCONFIG("${TAG_CORE_COMMON}", "Gangs (selected): %s",
sl_tx_model_gang->state.c_str());
ESP_LOGCONFIG("${TAG_CORE_COMMON}", "Gangs (detected): %" PRIu8 "-Gang%s",
ESP_LOGCONFIG("${TAG_COMMON}", "Gangs (selected): %s",
sl_tx_model_gang->current_option());
ESP_LOGCONFIG("${TAG_COMMON}", "Gangs (detected): %" PRIu8 "-Gang%s",
id(gang_count), id(gang_count) > 1 ? "s" : "");

// Boot completion status
if (bs_boot_completed->state)
ESP_LOGCONFIG("${TAG_CORE_COMMON}", "Boot completed: Yes");
ESP_LOGCONFIG("${TAG_COMMON}", "Boot completed: Yes");
else
ESP_LOGW("${TAG_CORE_COMMON}", "Boot completed: NO");
ESP_LOGW("${TAG_COMMON}", "Boot completed: NO");

// System state
if (bs_pending_restart->state)
ESP_LOGW("${TAG_CORE_COMMON}", "Pending restart: YES");
ESP_LOGW("${TAG_COMMON}", "Pending restart: YES");
else
ESP_LOGCONFIG("${TAG_CORE_COMMON}", "Pending restart: No");
ESP_LOGCONFIG("${TAG_COMMON}", "Pending restart: No");

- id: dump_config_caller
mode: restart
Expand All @@ -263,17 +262,10 @@ script:
then:
- lambda: |-
// Version information
ESP_LOGCONFIG("${TAG_CORE_COMMON}", "TX Ultimate firmware version: ${version}");
ESP_LOGCONFIG("${TAG_COMMON}", "TX Ultimate firmware version: ${version}");
// ESPHome builder information
ESP_LOGCONFIG("${TAG_CORE_COMMON}", "ESPHome builder: " ESPHOME_VERSION);
ESP_LOGCONFIG("${TAG_CORE_COMMON}", "ESPHome build timestamp: %s", App.get_compilation_time().c_str());

- id: publish_device_info
mode: restart
then:
- lambda: |-
tx_fw_version->publish_state("${version}");
tx_device_name->publish_state(App.get_name().c_str());
ESP_LOGCONFIG("${TAG_COMMON}", "ESPHome builder: " ESPHOME_VERSION);
ESP_LOGCONFIG("${TAG_COMMON}", "ESPHome build timestamp: %s", App.get_compilation_time().c_str());

- id: restore_from_nvs
mode: single
Expand All @@ -287,6 +279,16 @@ script:
if (id(gang_count) < 1 || id(gang_count) > 4) return 0; // default to 1-Gang
return static_cast<uint8_t>(id(gang_count)) - 1;

- id: update_device_name
mode: single
then:
- lambda: |-
if (esphome::tx_ultimate_easy::cached_device_name.empty()) {
esphome::tx_ultimate_easy::initialize_cached_device_name(App.get_name());
ESP_LOGI("${TAG_COMMON}", "Device name: %s", esphome::tx_ultimate_easy::cached_device_name.c_str());
tx_device_name->publish_state(esphome::tx_ultimate_easy::cached_device_name);
}

select:
- id: sl_tx_model_format
name: Model (Format)
Expand All @@ -303,10 +305,8 @@ select:
icon: mdi:tablet-cellphone
on_value:
then:
- binary_sensor.template.publish:
id: bs_pending_restart
state: true
- lambda: |-
bs_pending_restart->publish_state(true);
id(is_us_model) = (x == "${TX_MODEL_FORMAT_US_TEXT}");

- id: sl_tx_model_gang
Expand All @@ -326,10 +326,8 @@ select:
icon: mdi:dip-switch
on_value:
then:
- binary_sensor.template.publish:
id: bs_pending_restart
state: true
- lambda: |-
bs_pending_restart->publish_state(true);
id(gang_count) = static_cast<uint8_t>(i) + 1;
tx_ultimate->set_gang_count(id(gang_count));

Expand All @@ -353,26 +351,18 @@ text_sensor:
disabled_by_default: false
update_interval: never
lambda: |-
return {"${name}"};
filters:
- lambda: |-
const std::string raw_name = x;
std::string result;
bool last_was_underscore = false;
for (const char& c : raw_name) {
if (isalnum(c)) {
result += tolower(c); // Add alphanumeric characters as lowercase
last_was_underscore = false;
} else if (!last_was_underscore) { // Replace non-alphanumeric with '_' but avoid consecutive '_'
result += '_';
last_was_underscore = true;
}
}
return result;
return { esphome::tx_ultimate_easy::cached_device_name };

tx_ultimate_easy:
id: tx_ultimate

wifi:
id: wifi_component
use_psram: true

on_connect:
then:
- lambda: |-
tx_fw_version->publish_state("${version}");
update_device_name->execute();
...
8 changes: 4 additions & 4 deletions ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
---
packages:
# yamllint disable rule:colons
core_common: !include TX-Ultimate-Easy-ESPHome_core_common.yaml
core_hw_buttons: !include TX-Ultimate-Easy-ESPHome_core_hw_buttons.yaml
core_hw_leds: !include TX-Ultimate-Easy-ESPHome_core_hw_leds.yaml
core_hw_touch: !include TX-Ultimate-Easy-ESPHome_core_hw_touch.yaml
common: !include TX-Ultimate-Easy-ESPHome_common.yaml
hw_buttons: !include TX-Ultimate-Easy-ESPHome_hw_buttons.yaml
hw_leds: !include TX-Ultimate-Easy-ESPHome_hw_leds.yaml
hw_touch: !include TX-Ultimate-Easy-ESPHome_hw_touch.yaml
# yamllint enable rule:colons
...
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
##### TX Ultimate Easy for ESPHome #####
##### Repository: https://github.com/edwardtfn/TX-Ultimate-Easy #####
####################################################################################################
##### Purpose: ESPHome - Standard - I2S Audio #####
##### Purpose: ESPHome - Hardward - I2S Audio #####
####################################################################################################
##### Author: edwardtfn - https://github.com/edwardtfn - https://buymeacoffee.com/edwardfirmo #####
####################################################################################################
Expand All @@ -14,12 +14,12 @@
substitutions:
SWITCH_AUDIO_AMPLIFIER_RESTORE_MODE: RESTORE_DEFAULT_ON

TAG_STD_HW_AUDIO: std.hw.audio
TAG_HW_AUDIO: tx_ultimate_easy.hw.audio

esphome:
platformio_options:
build_flags:
- -D TX_ULTIMATE_EASY_STANDARD_HW_AUDIO
- -D TX_ULTIMATE_EASY_HW_AUDIO

i2s_audio:
- id: if_i2s_audio
Expand All @@ -32,12 +32,12 @@ script:
- script.wait: dump_config
- lambda: |-
// Check for requirements
#if !defined(TX_ULTIMATE_EASY_CORE_COMMON)
#error "The package TX-Ultimate-Easy-ESPHome_core_common.yaml is required."
#if !defined(TX_ULTIMATE_EASY_COMMON)
#error "The package TX-Ultimate-Easy-ESPHome_common.yaml is required."
#endif

// Identify itself
ESP_LOGCONFIG(ESPHOME_PROJECT_NAME, " - Standard - Hardware - Audio");
ESP_LOGCONFIG(ESPHOME_PROJECT_NAME, " - Hardware - Audio");

switch:
- id: sw_audio_amplifier
Expand Down
Loading
Loading