Merge pull request #11 from edwardtfn/dev

First workable version
This commit is contained in:
Edward Firmo
2024-05-29 22:23:15 +02:00
committed by GitHub
8 changed files with 2288 additions and 2 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.cmd
*.bat

BIN
Assets/Logo.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +1,59 @@
# TX-Ultimate-Easy # TX Ultimate Easy
ESPHome based custom firmware for Sonoff TX Ultimate. Easy to setup.
|  ![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 or via blueprints, eliminating the need to edit YAML files manually. |
| --- | :-- |
## Features
- **Simple Setup:** Configure your Sonoff TX Ultimate through Home Assistant UI.
- **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
### Prerequisites
- Sonoff TX Ultimate device
- Home Assistant installed
- ESPHome add-on installed in Home Assistant
### Installation
To be written.
### Configuration
- **Via Home Assistant UI:**
All device settings can be managed through the Home Assistant interface. No need to edit YAML files directly.
- **Using Blueprints:**
Import and use blueprints to quickly configure your device for common use cases.
## Documentation
To be written.
## 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.
## License
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)
<img src="Assets/Logo.webp" alt="TX Ultimate Easy Logo" width="100"/>

View File

@@ -0,0 +1,19 @@
substitutions:
name: tx-ultimate-easy
friendly_name: TX Ultimate Easy
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
packages:
remote_package:
url: https://github.com/edwardtfn/TX-Ultimate-Easy
ref: dev
refresh: 1h
files:
- ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
### Uncomment the lines bellow if you have issues with OTA and cannot flash via serial at this moment. ###
#esp32:
# flash_size: 4MB

View File

@@ -0,0 +1,105 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import uart
from esphome.const import (
CONF_ID,
)
from esphome import automation
CODEOWNERS = ["@edwardtfn"]
DEPENDENCIES = ['uart']
CONF_TX_ULTIMATE_EASY = "tx_ultimate_easy"
CONF_UART = "uart"
CONF_ON_TOUCH_EVENT = "on_touch_event"
CONF_ON_PRESS = "on_press"
CONF_ON_RELEASE = "on_release"
CONF_ON_SWIPE_LEFT = "on_swipe_left"
CONF_ON_SWIPE_RIGHT = "on_swipe_right"
CONF_ON_MULTI_TOUCH_RELEASE = "on_multi_touch_release"
CONF_ON_LONG_TOUCH_RELEASE = "on_long_touch_release"
tx_ultimate_easy_ns = cg.esphome_ns.namespace('tx_ultimate_easy')
TouchPoint = tx_ultimate_easy_ns.struct("TouchPoint")
TxUltimateTouch = tx_ultimate_easy_ns.class_(
'TxUltimateEasy', cg.Component, uart.UARTDevice)
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(TxUltimateTouch),
cv.Required(CONF_UART): cv.use_id(uart),
cv.Optional(CONF_ON_TOUCH_EVENT): automation.validate_automation(single=True),
cv.Optional(CONF_ON_PRESS): automation.validate_automation(single=True),
cv.Optional(CONF_ON_RELEASE): automation.validate_automation(single=True),
cv.Optional(CONF_ON_SWIPE_LEFT): automation.validate_automation(single=True),
cv.Optional(CONF_ON_SWIPE_RIGHT): automation.validate_automation(single=True),
cv.Optional(CONF_ON_MULTI_TOUCH_RELEASE): automation.validate_automation(single=True),
cv.Optional(CONF_ON_LONG_TOUCH_RELEASE): automation.validate_automation(single=True),
}).extend(cv.COMPONENT_SCHEMA).extend(uart.UART_DEVICE_SCHEMA)
async def register_tx_ultimate_easy(var, config):
uart_component = await cg.get_variable(config[CONF_UART])
cg.add(var.set_uart_component(uart_component))
if CONF_ON_TOUCH_EVENT in config:
await automation.build_automation(
var.get_trigger_touch_event(),
[(TouchPoint, "touch")],
config[CONF_ON_TOUCH_EVENT],
)
if CONF_ON_PRESS in config:
await automation.build_automation(
var.get_trigger_touch(),
[(TouchPoint, "touch")],
config[CONF_ON_PRESS],
)
if CONF_ON_RELEASE in config:
await automation.build_automation(
var.get_trigger_release(),
[(TouchPoint, "touch")],
config[CONF_ON_RELEASE],
)
if CONF_ON_SWIPE_LEFT in config:
await automation.build_automation(
var.get_trigger_swipe_left(),
[(TouchPoint, "touch")],
config[CONF_ON_SWIPE_LEFT],
)
if CONF_ON_SWIPE_RIGHT in config:
await automation.build_automation(
var.get_trigger_swipe_right(),
[(TouchPoint, "touch")],
config[CONF_ON_SWIPE_RIGHT],
)
if CONF_ON_MULTI_TOUCH_RELEASE in config:
await automation.build_automation(
var.get_trigger_multi_touch_release(),
[(TouchPoint, "touch")],
config[CONF_ON_MULTI_TOUCH_RELEASE],
)
if CONF_ON_LONG_TOUCH_RELEASE in config:
await automation.build_automation(
var.get_trigger_long_touch_release(),
[(TouchPoint, "touch")],
config[CONF_ON_LONG_TOUCH_RELEASE],
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await uart.register_uart_device(var, config)
await register_tx_ultimate_easy(var, config)

View File

@@ -0,0 +1,154 @@
#include "esphome/core/log.h"
#include "tx_ultimate_easy.h"
namespace esphome {
namespace tx_ultimate_easy {
static const char *TAG = "tx_ultimate_easy";
void TxUltimateEasy::setup() {
ESP_LOGI("log", "%s", "Tx Ultimate Easy is initialized");
}
void TxUltimateEasy::loop() {
bool found = false;
int uart_received_bytes[15] = {};
int byte = -1;
int i = 0;
while (this->available()) {
byte = this->read();
if (byte == 170) {
handle_touch(uart_received_bytes);
i = 0;
}
uart_received_bytes[i] = byte;
i++;
if (byte != 0) {
found = true;
}
};
if (found) handle_touch(uart_received_bytes);
}
void TxUltimateEasy::handle_touch(int uart_received_bytes[]) {
ESP_LOGVV(TAG, "------------");
ESP_LOGVV(TAG, "- UART-Log -");
ESP_LOGVV(TAG, "------------");
for (int i = 0; i < 15; i++) ESP_LOGVV(TAG, "UART - Log - Byte[%i]: %i", i, uart_received_bytes[i]);
if (is_valid_data(uart_received_bytes)) send_touch_(get_touch_point(uart_received_bytes));
}
void TxUltimateEasy::dump_config() { ESP_LOGCONFIG(TAG, "Tx Ultimate Easy"); }
void TxUltimateEasy::send_touch_(TouchPoint tp) {
this->trigger_touch_event_.trigger(tp);
switch (tp.state) {
case TOUCH_STATE_RELEASE:
if (tp.x >= 17) {
tp.x = tp.x - 16;
ESP_LOGV(TAG, "Long touch - Released (x=%d)", tp.x);
this->trigger_long_touch_release_.trigger(tp);
} else {
ESP_LOGV(TAG, "Touch - Released (x=%d)", tp.x);
this->trigger_release_.trigger(tp);
}
break;
case TOUCH_STATE_PRESS:
ESP_LOGV(TAG, "Touch - Pressed (x=%d)", tp.x);
this->trigger_touch_.trigger(tp);
break;
case TOUCH_STATE_SWIPE_LEFT:
ESP_LOGV(TAG, "Swipe - Left (x=%d)", tp.x);
this->trigger_swipe_left_.trigger(tp);
break;
case TOUCH_STATE_SWIPE_RIGHT:
ESP_LOGV(TAG, "Swipe - Right (x=%d)", tp.x);
this->trigger_swipe_right_.trigger(tp);
break;
case TOUCH_STATE_MULTI_TOUCH:
ESP_LOGV(TAG, "Multi touch - Released");
this->trigger_multi_touch_release_.trigger(tp);
break;
default:
break;
}
}
bool TxUltimateEasy::is_valid_data(int uart_received_bytes[]) {
bool valid = true;
if (!(uart_received_bytes[0] == 170 && uart_received_bytes[1] == 85 && uart_received_bytes[2] == 1 && uart_received_bytes[3] == 2)) return false;
int state = get_touch_state(uart_received_bytes);
if (state != TOUCH_STATE_PRESS &&
state != TOUCH_STATE_RELEASE &&
state != TOUCH_STATE_SWIPE_LEFT &&
state != TOUCH_STATE_SWIPE_RIGHT &&
state != TOUCH_STATE_MULTI_TOUCH)
return false;
if (uart_received_bytes[6] < 0 && state != TOUCH_STATE_MULTI_TOUCH) return false;
return true;
}
int TxUltimateEasy::get_touch_position_x(int uart_received_bytes[]) {
int state = uart_received_bytes[4];
switch (state) {
case TOUCH_STATE_RELEASE:
case TOUCH_STATE_MULTI_TOUCH:
case TOUCH_STATE_SWIPE_LEFT:
case TOUCH_STATE_SWIPE_RIGHT:
return uart_received_bytes[5];
break;
default:
return uart_received_bytes[6];
break;
}
}
int TxUltimateEasy::get_touch_state(int uart_received_bytes[]) {
int state = uart_received_bytes[4];
if (state == TOUCH_STATE_PRESS && uart_received_bytes[5] != 0) state = TOUCH_STATE_RELEASE;
if (state == TOUCH_STATE_RELEASE && uart_received_bytes[5] == TOUCH_STATE_MULTI_TOUCH) state = TOUCH_STATE_MULTI_TOUCH;
if (state == TOUCH_STATE_SWIPE) {
if (uart_received_bytes[5] == TOUCH_STATE_SWIPE_RIGHT) state = TOUCH_STATE_SWIPE_RIGHT;
else if (uart_received_bytes[5] == TOUCH_STATE_SWIPE_LEFT) state = TOUCH_STATE_SWIPE_LEFT;
}
return state;
}
TouchPoint TxUltimateEasy::get_touch_point(int uart_received_bytes[]) {
TouchPoint tp;
tp.x = get_touch_position_x(uart_received_bytes);
tp.state = get_touch_state(uart_received_bytes);
tp.state_str = "Unknown";
switch (tp.state) {
case TOUCH_STATE_RELEASE:
tp.state_str = "RELEASE";
break;
case TOUCH_STATE_PRESS:
tp.state_str = "PRESS";
break;
case TOUCH_STATE_SWIPE:
tp.state_str = "SWIPE";
break;
case TOUCH_STATE_MULTI_TOUCH:
tp.state_str = "MULTI_TOUCH";
break;
case TOUCH_STATE_SWIPE_RIGHT:
tp.state_str = "SWIPE_RIGHT";
break;
case TOUCH_STATE_SWIPE_LEFT:
tp.state_str = "SWIPE_LEFT";
break;
}
return tp;
}
} // namespace tx_ultimate_easy
} // namespace esphome

View File

@@ -0,0 +1,62 @@
#pragma once
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/components/uart/uart.h"
#include "esphome/components/uart/uart_component.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/components/switch/switch.h"
#include "esphome/components/light/addressable_light.h"
namespace esphome {
namespace tx_ultimate_easy {
const static uint8_t TOUCH_STATE_RELEASE = 1;
const static uint8_t TOUCH_STATE_PRESS = 2;
const static uint8_t TOUCH_STATE_SWIPE = 3;
const static uint8_t TOUCH_STATE_MULTI_TOUCH = 11;
const static uint8_t TOUCH_STATE_SWIPE_RIGHT = 12;
const static uint8_t TOUCH_STATE_SWIPE_LEFT = 13;
struct TouchPoint {
int8_t x = -1;
int8_t state = -1;
std::string state_str = "Unknown";
};
class TxUltimateEasy : public uart::UARTDevice, public Component {
public:
Trigger<TouchPoint> *get_trigger_touch_event() { return &this->trigger_touch_event_; }
Trigger<TouchPoint> *get_trigger_touch() { return &this->trigger_touch_; }
Trigger<TouchPoint> *get_trigger_release() { return &this->trigger_release_; }
Trigger<TouchPoint> *get_trigger_swipe_left() { return &this->trigger_swipe_left_; }
Trigger<TouchPoint> *get_trigger_swipe_right() { return &this->trigger_swipe_right_; }
Trigger<TouchPoint> *get_trigger_multi_touch_release() { return &this->trigger_multi_touch_release_; }
Trigger<TouchPoint> *get_trigger_long_touch_release() { return &this->trigger_long_touch_release_; }
void set_uart_component(esphome::uart::UARTComponent *uart_component) { this->set_uart_parent(uart_component); }
void setup() override;
void loop() override;
void dump_config() override;
protected:
void send_touch_(TouchPoint tp);
void handle_touch(int bytes[]);
TouchPoint get_touch_point(int bytes[]);
bool is_valid_data(int bytes[]);
int get_touch_position_x(int bytes[]);
int get_touch_state(int bytes[]);
Trigger<TouchPoint> trigger_touch_event_;
Trigger<TouchPoint> trigger_touch_;
Trigger<TouchPoint> trigger_release_;
Trigger<TouchPoint> trigger_swipe_left_;
Trigger<TouchPoint> trigger_swipe_right_;
Trigger<TouchPoint> trigger_multi_touch_release_;
Trigger<TouchPoint> trigger_long_touch_release_;
}; // class TxUltimateEasy
} // namespace tx_ultimate_easy
} // namespace esphome