Add component tx_ultimate_easy
Based on https://github.com/SmartHome-yourself/sonoff-tx-ultimate-for-esphome
This commit is contained in:
@@ -2,7 +2,11 @@ substitutions:
|
|||||||
name: tx-ultimate-easy
|
name: tx-ultimate-easy
|
||||||
friendly_name: TX Ultimate Easy
|
friendly_name: TX Ultimate Easy
|
||||||
|
|
||||||
version: 0.0.1
|
latitude: '0'
|
||||||
|
longitude: '0'
|
||||||
|
zone_home: 'zone.home'
|
||||||
|
|
||||||
|
version: '0.0.1'
|
||||||
|
|
||||||
api:
|
api:
|
||||||
id: api_server
|
id: api_server
|
||||||
@@ -93,9 +97,20 @@ esphome:
|
|||||||
sw_relay_3->set_internal(index.value() < 2);
|
sw_relay_3->set_internal(index.value() < 2);
|
||||||
sw_relay_4->set_internal(index.value() < 3);
|
sw_relay_4->set_internal(index.value() < 3);
|
||||||
}
|
}
|
||||||
- priority: -100
|
- priority: 600 # This is where most sensors are set up.
|
||||||
then:
|
then:
|
||||||
- lambda: tx_fw_version->publish_state("${version}");
|
- lambda: |-
|
||||||
|
tx_fw_version->publish_state("${version}");
|
||||||
|
tx_device_name->publish_state("${name}");
|
||||||
|
|
||||||
|
external_components:
|
||||||
|
- source:
|
||||||
|
type: git
|
||||||
|
url: https://github.com/edwardtfn/TX-Ultimate-Easy/
|
||||||
|
ref: dev
|
||||||
|
path: ESPHome/components
|
||||||
|
components:
|
||||||
|
- tx_ultimate_easy
|
||||||
|
|
||||||
i2s_audio:
|
i2s_audio:
|
||||||
id: if_i2s_audio
|
id: if_i2s_audio
|
||||||
@@ -226,7 +241,7 @@ sensor:
|
|||||||
|
|
||||||
- id: zone_home_latitude
|
- id: zone_home_latitude
|
||||||
platform: homeassistant
|
platform: homeassistant
|
||||||
entity_id: zone.home
|
entity_id: ${zone_home}
|
||||||
attribute: latitude
|
attribute: latitude
|
||||||
internal: false
|
internal: false
|
||||||
on_value:
|
on_value:
|
||||||
@@ -234,7 +249,7 @@ sensor:
|
|||||||
|
|
||||||
- id: zone_home_longitude
|
- id: zone_home_longitude
|
||||||
platform: homeassistant
|
platform: homeassistant
|
||||||
entity_id: zone.home
|
entity_id: ${zone_home}
|
||||||
attribute: longitude
|
attribute: longitude
|
||||||
internal: false
|
internal: false
|
||||||
on_value:
|
on_value:
|
||||||
@@ -242,8 +257,8 @@ sensor:
|
|||||||
|
|
||||||
sun:
|
sun:
|
||||||
id: sun_entity
|
id: sun_entity
|
||||||
latitude: 90
|
latitude: ${latitude}
|
||||||
longitude: 180
|
longitude: ${longitude}
|
||||||
|
|
||||||
switch:
|
switch:
|
||||||
- id: sw_speaker_aplifier
|
- id: sw_speaker_aplifier
|
||||||
@@ -317,10 +332,37 @@ text_sensor:
|
|||||||
lambda: |-
|
lambda: |-
|
||||||
return {"${version}"};
|
return {"${version}"};
|
||||||
|
|
||||||
|
- id: tx_device_name
|
||||||
|
name: Device Name
|
||||||
|
platform: template
|
||||||
|
icon: mdi:identifier
|
||||||
|
entity_category: diagnostic
|
||||||
|
internal: false
|
||||||
|
disabled_by_default: false
|
||||||
|
lambda: |-
|
||||||
|
return {"${name}"};
|
||||||
|
filters:
|
||||||
|
- lambda: |-
|
||||||
|
const std::string raw_name = x;
|
||||||
|
std::string result;
|
||||||
|
bool last_was_underscore = false;
|
||||||
|
for (const char& c : raw_name) {
|
||||||
|
if (isalnum(c)) {
|
||||||
|
result += tolower(c); // Add alphanumeric characters as lowercase
|
||||||
|
last_was_underscore = false;
|
||||||
|
} else if (!last_was_underscore) { // Replace non-alphanumeric with '_' but avoid consecutive '_'
|
||||||
|
result += '_';
|
||||||
|
last_was_underscore = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
time:
|
time:
|
||||||
- id: time_source
|
- id: time_source
|
||||||
platform: homeassistant
|
platform: homeassistant
|
||||||
|
|
||||||
|
tx_ultimate_easy:
|
||||||
|
|
||||||
uart:
|
uart:
|
||||||
id: if_uart_touch
|
id: if_uart_touch
|
||||||
tx_pin: GPIO19
|
tx_pin: GPIO19
|
||||||
|
|||||||
99
ESPHome/components/tx_ultimate_easy/__init__.py
Normal file
99
ESPHome/components/tx_ultimate_easy/__init__.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
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_PRESS = "on_press"
|
||||||
|
CONF_ON_RELEASE = "on_release"
|
||||||
|
|
||||||
|
CONF_ON_SWIPE_LEFT = "on_swipe_left"
|
||||||
|
CONF_ON_SWIPE_RIGHT = "on_swipe_right"
|
||||||
|
|
||||||
|
CONF_ON_FULL_TOUCH_RELEASE = "on_full_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_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_FULL_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_PRESS in config:
|
||||||
|
await automation.build_automation(
|
||||||
|
var.get_touch_trigger(),
|
||||||
|
[(TouchPoint, "touch")],
|
||||||
|
config[CONF_ON_PRESS],
|
||||||
|
)
|
||||||
|
|
||||||
|
if CONF_ON_RELEASE in config:
|
||||||
|
await automation.build_automation(
|
||||||
|
var.get_release_trigger(),
|
||||||
|
[(TouchPoint, "touch")],
|
||||||
|
config[CONF_ON_RELEASE],
|
||||||
|
)
|
||||||
|
|
||||||
|
if CONF_ON_SWIPE_LEFT in config:
|
||||||
|
await automation.build_automation(
|
||||||
|
var.get_swipe_left_trigger(),
|
||||||
|
[(TouchPoint, "touch")],
|
||||||
|
config[CONF_ON_SWIPE_LEFT],
|
||||||
|
)
|
||||||
|
|
||||||
|
if CONF_ON_SWIPE_RIGHT in config:
|
||||||
|
await automation.build_automation(
|
||||||
|
var.get_swipe_right_trigger(),
|
||||||
|
[(TouchPoint, "touch")],
|
||||||
|
config[CONF_ON_SWIPE_RIGHT],
|
||||||
|
)
|
||||||
|
|
||||||
|
if CONF_ON_FULL_TOUCH_RELEASE in config:
|
||||||
|
await automation.build_automation(
|
||||||
|
var.get_full_touch_release_trigger(),
|
||||||
|
[(TouchPoint, "touch")],
|
||||||
|
config[CONF_ON_FULL_TOUCH_RELEASE],
|
||||||
|
)
|
||||||
|
|
||||||
|
if CONF_ON_LONG_TOUCH_RELEASE in config:
|
||||||
|
await automation.build_automation(
|
||||||
|
var.get_long_touch_release_trigger(),
|
||||||
|
[(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)
|
||||||
204
ESPHome/components/tx_ultimate_easy/tx_ultimate_easy.cpp
Normal file
204
ESPHome/components/tx_ultimate_easy/tx_ultimate_easy.cpp
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
#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 Touch is initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TxUltimateEasy::loop()
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
int bytes[15] = {};
|
||||||
|
int byte = -1;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (this->available())
|
||||||
|
{
|
||||||
|
byte = this->read();
|
||||||
|
if (byte == 170)
|
||||||
|
{
|
||||||
|
handle_touch(bytes);
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes[i] = byte;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (byte != 0)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
handle_touch(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TxUltimateEasy::handle_touch(int bytes[])
|
||||||
|
{
|
||||||
|
ESP_LOGV("UART-Log", "------------");
|
||||||
|
for (int i = 0; i < 15; i++)
|
||||||
|
{
|
||||||
|
ESP_LOGV("UART-Log", "%i", bytes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_valid_data(bytes))
|
||||||
|
{
|
||||||
|
send_touch_(get_touch_point(bytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TxUltimateEasy::dump_config()
|
||||||
|
{
|
||||||
|
ESP_LOGCONFIG(TAG, "Tx Ultimate Touch");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TxUltimateEasy::send_touch_(TouchPoint tp)
|
||||||
|
{
|
||||||
|
switch (tp.state)
|
||||||
|
{
|
||||||
|
case TOUCH_STATE_RELEASE:
|
||||||
|
if (tp.x >= 17)
|
||||||
|
{
|
||||||
|
tp.x = tp.x - 16;
|
||||||
|
ESP_LOGD(TAG, "Long Press Release (x=%d)", tp.x);
|
||||||
|
this->long_touch_release_trigger_.trigger(tp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGD(TAG, "Release (x=%d)", tp.x);
|
||||||
|
this->release_trigger_.trigger(tp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOUCH_STATE_PRESS:
|
||||||
|
ESP_LOGD(TAG, "Press (x=%d)", tp.x);
|
||||||
|
this->touch_trigger_.trigger(tp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOUCH_STATE_SWIPE_LEFT:
|
||||||
|
ESP_LOGD(TAG, "Swipe Left (x=%d)", tp.x);
|
||||||
|
this->swipe_trigger_left_.trigger(tp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOUCH_STATE_SWIPE_RIGHT:
|
||||||
|
ESP_LOGD(TAG, "Swipe Right (x=%d)", tp.x);
|
||||||
|
this->swipe_trigger_right_.trigger(tp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOUCH_STATE_ALL_FIELDS:
|
||||||
|
ESP_LOGD(TAG, "Full Touch Release");
|
||||||
|
this->full_touch_release_trigger_.trigger(tp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TxUltimateEasy::is_valid_data(int bytes[])
|
||||||
|
{
|
||||||
|
bool valid = true;
|
||||||
|
|
||||||
|
if (!(bytes[0] == 170 && bytes[1] == 85 && bytes[2] == 1 && bytes[3] == 2))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int state = get_touch_state(bytes);
|
||||||
|
if (state != TOUCH_STATE_PRESS &&
|
||||||
|
state != TOUCH_STATE_RELEASE &&
|
||||||
|
state != TOUCH_STATE_SWIPE_LEFT &&
|
||||||
|
state != TOUCH_STATE_SWIPE_RIGHT &&
|
||||||
|
state != TOUCH_STATE_ALL_FIELDS)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes[6] < 0 && state != TOUCH_STATE_ALL_FIELDS)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TxUltimateEasy::get_x_touch_position(int bytes[])
|
||||||
|
{
|
||||||
|
int state = bytes[4];
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case TOUCH_STATE_RELEASE:
|
||||||
|
return bytes[5];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOUCH_STATE_ALL_FIELDS:
|
||||||
|
return bytes[5];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOUCH_STATE_SWIPE_LEFT:
|
||||||
|
return bytes[5];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOUCH_STATE_SWIPE_RIGHT:
|
||||||
|
return bytes[5];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return bytes[6];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int TxUltimateEasy::get_touch_state(int bytes[])
|
||||||
|
{
|
||||||
|
int state = bytes[4];
|
||||||
|
|
||||||
|
if (state == TOUCH_STATE_PRESS && bytes[5] != 0)
|
||||||
|
{
|
||||||
|
state = TOUCH_STATE_RELEASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == TOUCH_STATE_RELEASE && bytes[5] == TOUCH_STATE_ALL_FIELDS)
|
||||||
|
{
|
||||||
|
state = TOUCH_STATE_ALL_FIELDS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == TOUCH_STATE_SWIPE)
|
||||||
|
{
|
||||||
|
if (bytes[5] == TOUCH_STATE_SWIPE_RIGHT)
|
||||||
|
{
|
||||||
|
state = TOUCH_STATE_SWIPE_RIGHT;
|
||||||
|
}
|
||||||
|
else if (bytes[5] == TOUCH_STATE_SWIPE_LEFT)
|
||||||
|
{
|
||||||
|
state = TOUCH_STATE_SWIPE_LEFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
TouchPoint TxUltimateEasy::get_touch_point(int bytes[])
|
||||||
|
{
|
||||||
|
TouchPoint tp;
|
||||||
|
|
||||||
|
tp.x = get_x_touch_position(bytes);
|
||||||
|
tp.state = get_touch_state(bytes);
|
||||||
|
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace tx_ultimate_easy
|
||||||
|
} // namespace esphome
|
||||||
68
ESPHome/components/tx_ultimate_easy/tx_ultimate_easy.h
Normal file
68
ESPHome/components/tx_ultimate_easy/tx_ultimate_easy.h
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#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_ALL_FIELDS = 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TxUltimateEasy : public uart::UARTDevice, public Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Trigger<TouchPoint> *get_touch_trigger() { return &this->touch_trigger_; }
|
||||||
|
Trigger<TouchPoint> *get_release_trigger() { return &this->release_trigger_; }
|
||||||
|
Trigger<TouchPoint> *get_swipe_left_trigger() { return &this->swipe_trigger_left_; }
|
||||||
|
Trigger<TouchPoint> *get_swipe_right_trigger() { return &this->swipe_trigger_right_; }
|
||||||
|
Trigger<TouchPoint> *get_full_touch_release_trigger() { return &this->full_touch_release_trigger_; }
|
||||||
|
Trigger<TouchPoint> *get_long_touch_release_trigger() { return &this->long_touch_release_trigger_; }
|
||||||
|
|
||||||
|
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_x_touch_position(int bytes[]);
|
||||||
|
int get_touch_state(int bytes[]);
|
||||||
|
|
||||||
|
Trigger<TouchPoint> touch_trigger_;
|
||||||
|
Trigger<TouchPoint> release_trigger_;
|
||||||
|
Trigger<TouchPoint> swipe_trigger_left_;
|
||||||
|
Trigger<TouchPoint> swipe_trigger_right_;
|
||||||
|
Trigger<TouchPoint> full_touch_release_trigger_;
|
||||||
|
Trigger<TouchPoint> long_touch_release_trigger_;
|
||||||
|
|
||||||
|
}; // class TxUltimateEasy
|
||||||
|
|
||||||
|
} // namespace tx_ultimate_easy
|
||||||
|
} // namespace esphome
|
||||||
Reference in New Issue
Block a user