Merge pull request #35 from edwardtfn/0.0.4

Wrap-up
This commit is contained in:
Edward Firmo
2024-12-20 23:37:50 +01:00
committed by GitHub
7 changed files with 214 additions and 141 deletions

View File

@@ -78,7 +78,7 @@ improv_serial:
id: serial_improv id: serial_improv
logger: logger:
level: DEBUG level: INFO
ota: ota:
platform: esphome platform: esphome
@@ -89,22 +89,34 @@ script:
- id: boot_done - id: boot_done
mode: restart mode: restart
then: then:
- lambda: send_event_to_ha->execute("boot", "done"); - script.execute:
id: send_event_to_ha
component: boot
event: done
- id: boot_initialize - id: boot_initialize
mode: restart mode: restart
then: # There's nothing here so far then:
# Extended by: # Extended by:
# - HW Buttons # - HW Buttons
# - HW Relays # - HW Relays
# - HW Touch # - HW Touch
- script.execute:
id: send_event_to_ha
component: boot
event: start
- id: boot_sequence - id: boot_sequence
mode: restart
then:
- script.execute: publish_device_info
- id: publish_device_info
mode: restart mode: restart
then: then:
- lambda: |- - lambda: |-
tx_fw_version->publish_state("${version}"); tx_fw_version->publish_state("${version}");
tx_device_name->publish_state("${name}"); tx_device_name->publish_state(App.get_name().c_str());
select: select:
- id: sl_tx_model_format - id: sl_tx_model_format
@@ -137,34 +149,6 @@ select:
disabled_by_default: false disabled_by_default: false
icon: mdi:dip-switch icon: mdi:dip-switch
sensor:
- id: sun_elevation
name: Sun Elevation
platform: sun
type: elevation
internal: true
- id: zone_home_latitude
platform: homeassistant
entity_id: ${zone_home}
attribute: latitude
internal: false
on_value:
- lambda: if (!isnan(x)) sun_entity->set_latitude(x);
- id: zone_home_longitude
platform: homeassistant
entity_id: ${zone_home}
attribute: longitude
internal: false
on_value:
- lambda: if (!isnan(x)) sun_entity->set_longitude(x);
sun:
id: sun_entity
latitude: ${latitude}
longitude: ${longitude}
text_sensor: text_sensor:
- id: tx_fw_version - id: tx_fw_version
name: Firmware version name: Firmware version
@@ -183,6 +167,7 @@ text_sensor:
entity_category: diagnostic entity_category: diagnostic
internal: false internal: false
disabled_by_default: false disabled_by_default: false
update_interval: never
lambda: |- lambda: |-
return {"${name}"}; return {"${name}"};
filters: filters:

View File

@@ -13,23 +13,9 @@
--- ---
api: api:
id: api_server id: api_server
actions: on_client_connected:
- action: set_float then:
variables: - script.execute: publish_device_info
component: string
val: float
then:
- lambda: |-
ESP_LOGD("core_api", "Set float:");
ESP_LOGD("core_api", " Component: %s", component.c_str());
ESP_LOGD("core_api", " Value: %f", val);
if (!isnan(val)) {
if (component == "latitude" && val >= -90 && val <= 90) {
sun_entity->set_latitude(val);
} else if (component == "longitude" && val >= -180 && val <= 180) {
sun_entity->set_longitude(val);
}
}
script: script:
- id: !extend button_action - id: !extend button_action
@@ -45,14 +31,11 @@ script:
component: string component: string
event: string event: string
then: then:
- lambda: |- - homeassistant.event:
esphome::api::CustomAPIDevice ha_event; event: esphome.tx_ultimate_easy
ha_event.fire_homeassistant_event("esphome.tx_ultimate_easy", data:
{ device_name: !lambda return tx_device_name->state.c_str();
{"device_name", tx_device_name->state.c_str()}, firmware: ${version}
{"firmware", "${version}"}, component: !lambda return component.c_str();
{"component", component}, event: !lambda return event.c_str();
{"event", event},
});
... ...

View File

@@ -14,6 +14,12 @@
substitutions: substitutions:
invalid_cooldown: 100ms invalid_cooldown: 100ms
BUTTON_ACTION_NONE_TEXT: "None"
BUTTON_1_ACTION_TEXT: "Relay 1 (toggle)"
BUTTON_2_ACTION_TEXT: "Relay 2 (toggle)"
BUTTON_3_ACTION_TEXT: "Relay 3 (toggle)"
BUTTON_4_ACTION_TEXT: "Relay 4 (toggle)"
binary_sensor: binary_sensor:
- id: bs_button_1 - id: bs_button_1
name: Button 1 name: Button 1
@@ -232,8 +238,9 @@ select:
name: Button 1 action name: Button 1 action
platform: template platform: template
options: options:
- "None" - "${BUTTON_ACTION_NONE_TEXT}"
- "Relay 1 (toggle)" - "${BUTTON_1_ACTION_TEXT}"
initial_option: "${BUTTON_1_ACTION_TEXT}"
optimistic: true optimistic: true
restore_value: true restore_value: true
internal: true internal: true
@@ -245,23 +252,26 @@ select:
name: Button 2 action name: Button 2 action
platform: template platform: template
options: options:
- "None" - "${BUTTON_ACTION_NONE_TEXT}"
- "Relay 2 (toggle)" - "${BUTTON_2_ACTION_TEXT}"
initial_option: "${BUTTON_2_ACTION_TEXT}"
<<: *button_select_action_base <<: *button_select_action_base
- id: sl_button_3_action - id: sl_button_3_action
name: Button 3 action name: Button 3 action
platform: template platform: template
options: options:
- "None" - "${BUTTON_ACTION_NONE_TEXT}"
- "Relay 3 (toggle)" - "${BUTTON_3_ACTION_TEXT}"
initial_option: "${BUTTON_3_ACTION_TEXT}"
<<: *button_select_action_base <<: *button_select_action_base
- id: sl_button_4_action - id: sl_button_4_action
name: Button 4 action name: Button 4 action
platform: template platform: template
options: options:
- "None" - "${BUTTON_ACTION_NONE_TEXT}"
- "Relay 4 (toggle)" - "${BUTTON_4_ACTION_TEXT}"
initial_option: "${BUTTON_4_ACTION_TEXT}"
<<: *button_select_action_base <<: *button_select_action_base
... ...

View File

@@ -844,16 +844,21 @@ script:
static const uint32_t LIGHT_TRANSITION_TURN_OFF = ${LIGHT_TRANSITION_TURN_OFF}; static const uint32_t LIGHT_TRANSITION_TURN_OFF = ${LIGHT_TRANSITION_TURN_OFF};
static const uint8_t LIGHT_BRIGHTNESS_TURN_ON = ${LIGHT_BRIGHTNESS_TURN_ON}; static const uint8_t LIGHT_BRIGHTNESS_TURN_ON = ${LIGHT_BRIGHTNESS_TURN_ON};
ESP_LOGI("core_hw_leds.light_set_state", "Setting light group %d, index %d to state %s", const bool is_model_us = sl_tx_model_format->active_index().has_value() and
light_group, light_index, state ? "ON" : "OFF"); 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}";
switch (light_group) { switch (light_group) {
case 1: case 1:
if (light_index >= id(gb_lights_1).size()) { if (light_index >= id(gb_lights_1).size()) {
ESP_LOGE("light_set_state", "Invalid light_index %d for group 1", light_index); ESP_LOGE("core_hw_leds", "Invalid set with %s light for Relay %" PRIu8,
light_mode_group_1.c_str(), light_index);
return; return;
} }
if (state and !id(gb_lights_1)[light_index]->current_values.is_on()) { 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);
auto call = id(gb_lights_1)[light_index]->turn_on(); auto call = id(gb_lights_1)[light_index]->turn_on();
if (LIGHT_TRANSITION_TURN_ON > 0) if (LIGHT_TRANSITION_TURN_ON > 0)
call.set_transition_length(LIGHT_TRANSITION_TURN_ON); // in ms call.set_transition_length(LIGHT_TRANSITION_TURN_ON); // in ms
@@ -861,6 +866,8 @@ script:
call.set_brightness(LIGHT_TRANSITION_TURN_ON / 100.0f); call.set_brightness(LIGHT_TRANSITION_TURN_ON / 100.0f);
call.perform(); call.perform();
} else if (!state and id(gb_lights_1)[light_index]->current_values.is_on()) { } 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);
auto call = id(gb_lights_1)[light_index]->turn_off(); auto call = id(gb_lights_1)[light_index]->turn_off();
if (LIGHT_TRANSITION_TURN_OFF > 0) if (LIGHT_TRANSITION_TURN_OFF > 0)
call.set_transition_length(LIGHT_TRANSITION_TURN_OFF); // in ms call.set_transition_length(LIGHT_TRANSITION_TURN_OFF); // in ms
@@ -869,10 +876,13 @@ script:
break; break;
case 2: case 2:
if (light_index >= id(gb_lights_2).size()) { if (light_index >= id(gb_lights_2).size()) {
ESP_LOGE("light_set_state", "Invalid light_index %d for group 2", light_index); ESP_LOGE("core_hw_leds", "Invalid set with %s light for Relay %" PRIu8,
light_mode_group_2.c_str(), light_index);
return; return;
} }
if (state and !id(gb_lights_2)[light_index]->current_values.is_on()) { 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);
auto call = id(gb_lights_2)[light_index]->turn_on(); auto call = id(gb_lights_2)[light_index]->turn_on();
if (LIGHT_TRANSITION_TURN_ON > 0) if (LIGHT_TRANSITION_TURN_ON > 0)
call.set_transition_length(LIGHT_TRANSITION_TURN_ON); // in ms call.set_transition_length(LIGHT_TRANSITION_TURN_ON); // in ms
@@ -880,6 +890,8 @@ script:
call.set_brightness(LIGHT_TRANSITION_TURN_ON / 100.0f); call.set_brightness(LIGHT_TRANSITION_TURN_ON / 100.0f);
call.perform(); call.perform();
} else if (!state and id(gb_lights_2)[light_index]->current_values.is_on()) { } 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);
auto call = id(gb_lights_2)[light_index]->turn_off(); auto call = id(gb_lights_2)[light_index]->turn_off();
if (LIGHT_TRANSITION_TURN_OFF > 0) if (LIGHT_TRANSITION_TURN_OFF > 0)
call.set_transition_length(LIGHT_TRANSITION_TURN_OFF); // in ms call.set_transition_length(LIGHT_TRANSITION_TURN_OFF); // in ms

View File

@@ -15,50 +15,50 @@ binary_sensor:
- id: !extend bs_button_1 - id: !extend bs_button_1
on_click: on_click:
then: then:
- lambda: |- - if:
if (sl_button_1_action->active_index().has_value() and condition:
sl_button_1_action->active_index().value() == 1 and - lambda: return sl_button_1_action->active_index().has_value();
!bs_multi_touch->state and - lambda: return sl_button_1_action->active_index().value() == 1;
!bs_swipe_left->state and - and: &button_click_no_other_click
!bs_swipe_down->state and - lambda: return not bs_multi_touch->state;
!bs_swipe_right->state) - lambda: return not bs_swipe_left->state;
sw_relay_1->toggle(); - lambda: return not bs_swipe_down->state;
- lambda: return not bs_swipe_right->state;
then:
- switch.toggle: sw_relay_1
- id: !extend bs_button_2 - id: !extend bs_button_2
on_click: on_click:
then: then:
- lambda: |- - if:
if (sl_button_2_action->active_index().has_value() and condition:
sl_button_2_action->active_index().value() == 1 and - lambda: return sl_button_2_action->active_index().has_value();
!bs_multi_touch->state and - lambda: return sl_button_2_action->active_index().value() == 1;
!bs_swipe_left->state and - and: *button_click_no_other_click
!bs_swipe_down->state and then:
!bs_swipe_right->state) - switch.toggle: sw_relay_2
sw_relay_2->toggle();
- id: !extend bs_button_3 - id: !extend bs_button_3
on_click: on_click:
then: then:
- lambda: |- - if:
if (sl_button_3_action->active_index().has_value() and condition:
sl_button_3_action->active_index().value() == 1 and - lambda: return sl_button_3_action->active_index().has_value();
!bs_multi_touch->state and - lambda: return sl_button_3_action->active_index().value() == 1;
!bs_swipe_left->state and - and: *button_click_no_other_click
!bs_swipe_down->state and then:
!bs_swipe_right->state) - switch.toggle: sw_relay_3
sw_relay_3->toggle();
- id: !extend bs_button_4 - id: !extend bs_button_4
on_click: on_click:
then: then:
- lambda: |- - if:
if (sl_button_4_action->active_index().has_value() and condition:
sl_button_4_action->active_index().value() == 1 and - lambda: return sl_button_4_action->active_index().has_value();
!bs_multi_touch->state and - lambda: return sl_button_4_action->active_index().value() == 1;
!bs_swipe_left->state and - and: *button_click_no_other_click
!bs_swipe_down->state and then:
!bs_swipe_right->state) - switch.toggle: sw_relay_4
sw_relay_4->toggle();
globals: globals:
- id: boot_initialization_relays - id: boot_initialization_relays

View File

@@ -208,7 +208,8 @@ tx_ultimate_easy:
- script.execute: touch_on_multi_touch_release - script.execute: touch_on_multi_touch_release
on_press: on_press:
- lambda: ESP_LOGI("tx_ultimate_easy", "Pressed"); - lambda: |-
ESP_LOGI("tx_ultimate_easy", "Pressed at position %" PRIu8, static_cast<uint8_t>(touch.x));
- script.execute: - script.execute:
id: touch_on_press id: touch_on_press
touch_x: !lambda return static_cast<uint8_t>(touch.x); touch_x: !lambda return static_cast<uint8_t>(touch.x);

148
README.md
View File

@@ -1,58 +1,140 @@
# TX Ultimate Easy # 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 -->
<!-- markdownlint-disable MD013 --> <!-- markdownlint-disable MD013 -->
| &nbsp;![TX Ultimate Easy Logo](Assets/Logo.webp) | Welcome to TX Ultimate Easy! This project aims to provide custom firmware for Sonoff TX Ultimate devices based on ESPHome, making it easy for even the least tech-savvy users to configure and use. Our goal is to have all the configurations manageable directly through the Home Assistant UI, eliminating the need to edit YAML files manually. | | &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 --> <!-- markdownlint-enable MD013 -->
## Features [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
[license]: LICENSE
[last-commit-shield]: https://img.shields.io/github/last-commit/edwardtfn/TX-Ultimate-Easy
[esphome-shield]: https://img.shields.io/badge/powered%20by-ESPHome-blue
[esphome]: https://esphome.io/
[discord-shield]: https://img.shields.io/discord/1243652421692031016?logo=discord
[discord]: https://discord.gg/Db6WJWzWuf
[buymeacoffee-shield]: https://img.shields.io/static/v1?label=Buy%20me%20an%20ice%20cream&message=❄&color=blue
[buymeacoffee]: https://www.buymeacoffee.com/edwardfirmo
- **Simple Setup:** Configure your Sonoff TX Ultimate through Home Assistant UI. ## Integration with Home Assistant
- **No YAML Editing:** All settings are adjustable without touching YAML files after the initial setup.
- **User-Friendly:** Designed for users of all technical levels.
- **Customizable:** Flexibility to adapt the firmware to your needs.
- **Seamless Integration:** Works flawlessly with Home Assistant.
## Getting Started TX Ultimate Easy exposes your device's components (sensors, touch panel, relays, etc.) to Home Assistant, allowing you to:
### Prerequisites - 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
- Sonoff TX Ultimate device 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.
- Home Assistant installed
- ESPHome add-on installed in Home Assistant
### Installation ## Key Features
To be written.
### Configuration - **Home Assistant UI Configuration**: Manage all device settings directly through the Home Assistant interface
- **Zero YAML Knowledge Required**: After initial setup, no manual YAML editing needed
- **Flexible Light Control**: Customize LED behavior and effects
- **Touch Panel Support**: Full support for touch gestures and multi-touch capabilities
- **Advanced Automations**: Create complex automations using Home Assistant's powerful automation engine
- **BLE Proxy Support**: Optional Bluetooth Low Energy proxy functionality
- **Audio Feedback**: Built-in speaker support for audible feedback
- **Haptic Feedback**: Vibration motor support for tactile feedback
- **Via Home Assistant UI:** ## Hardware Support
All device settings can be managed through the Home Assistant interface. No need to edit YAML files directly.
## Documentation - Compatible with all Sonoff TX Ultimate variants:
To be written. - EU format (Square, T5-xC-86)
- US format (Rectangle, T5-xC-120)
- 1/2/3/4 gang versions
## Prerequisites
Before getting started, ensure you have:
1. A Sonoff TX Ultimate device
2. Home Assistant installation
3. ESPHome add-on installed in Home Assistant
4. Basic knowledge of Home Assistant
## Installation
Detailed installation instructions coming soon. The process will include:
1. Initial ESPHome setup
2. Device flashing
3. Home Assistant integration
4. Basic configuration
## Usage
After installation, you can:
1. Configure your device through Home Assistant UI
2. Customize touch behaviors
3. Set up LED patterns and effects
4. Create automations
5. Enable optional features like BLE proxy
## Configuration Options
TX Ultimate Easy offers extensive configuration options:
- Touch panel sensitivity and gestures
- LED colors, patterns, and behaviors
- Relay modes and functions
- Audio and haptic feedback settings
- Network and connectivity options
## Contributing ## Contributing
We welcome contributions from the community. If you have ideas for new features, improvements, or bug fixes, please open an issue or submit a pull request. We welcome contributions from the community! Here's how you can help:
1. Fork the repository
2. Create a feature branch from `dev`
3. Make your changes
4. Submit a pull request targeting the `dev` branch
Please ensure your code follows our standards:
- Passes all lint checks (YAML, C++, Markdown)
- Includes appropriate documentation
- Follows existing code style
All pull requests should be made against the `dev` branch. We don't accept pull requests directly to `main` as it's reserved for stable releases.
## Support and Community
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
- **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)
[![Buy Me a Coffee](https://www.buymeacoffee.com/assets/img/custom_images/yellow_img.png)](https://www.buymeacoffee.com/edwardfirmo)
## Acknowledgments
This project builds upon the work of several amazing projects and contributors:
- [SmartHome yourself - SONOFF TX Ultimate for ESPHome](https://github.com/SmartHome-yourself/sonoff-tx-ultimate-for-esphome)
- [Un loco y su tecnología - Sonoff TX Ultimate with ESPHome](https://www.youtube.com/watch?v=58v8oqSQgXQ)
Special thanks to all contributors and community members who help make this project better.
## License ## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Acknowledgments ---
This project is highly inspired by these other projects:
- [SmartHome yourself - SONOFF TX Ultimate for ESPHome (Custom Component)](https://github.com/SmartHome-yourself/sonoff-tx-ultimate-for-esphome)
- [Un loco y su tecnología - Sonoff TX Ultimate with ESPHome | Absolute power](https://www.youtube.com/watch?v=58v8oqSQgXQ)
Thanks a lot for sharing all your discoveries and ideas.
## Support
If you find this project helpful, consider supporting us through Buy Me a Coffee:
[![Buy Me a Coffee](https://www.buymeacoffee.com/assets/img/custom_images/yellow_img.png)](https://www.buymeacoffee.com/edwardfirmo)
<!-- markdownlint-disable MD033 --> <!-- markdownlint-disable MD033 -->
<img src="Assets/Logo.webp" alt="TX Ultimate Easy Logo" width="100"/> <img src="Assets/Logo.webp" alt="TX Ultimate Easy Logo" width="100"/>