Skip to content

Instantly share code, notes, and snippets.

@wolph
Last active November 18, 2024 18:06
Show Gist options
  • Save wolph/42024a983e4dfb0bc1dcbe6882979d21 to your computer and use it in GitHub Desktop.
Save wolph/42024a983e4dfb0bc1dcbe6882979d21 to your computer and use it in GitHub Desktop.
ESPHome Sonoff TX Ultimate T5-3C-86 Custom button component
light:
- platform: neopixelbus
type: GRB
variant: WS2812
pin: GPIO1
num_leds: 1
name: "NeoPixel 1"
internal: true
- platform: neopixelbus
type: GRB
variant: WS2812
pin: GPIO3
num_leds: 1
name: "NeoPixel 3"
internal: true
- platform: neopixelbus
type: GRB
variant: WS2812
pin: GPIO5
num_leds: 1
name: "NeoPixel 5"
internal: true
- platform: neopixelbus
type: GRB
variant: WS2812
pin: GPIO13
num_leds: 1
name: "NeoPixel 13"
internal: true
- platform: neopixelbus
type: GRB
variant: WS2812
pin: GPIO32
num_leds: 1
name: "NeoPixel 32"
internal: true
- platform: neopixelbus
type: GRB
variant: WS2812
# pin: GPIO20
pin: GPIO33
num_leds: 28
name: "Ambience Nightlight"
id: rgb_light
effects:
- addressable_twinkle:
- addressable_random_twinkle:
- addressable_rainbow:
name: 'rainbow slow'
speed: 5
- addressable_rainbow:
name: 'rainbow fast'
speed: 50
- addressable_rainbow:
name: 'rainbow superfast'
speed: 100
restore_mode: RESTORE_DEFAULT_OFF
# - platform: partition
# id: light_left_top
# name: "light left top"
# segments:
# - id: rgb_light
# from: 20
# to: 20
# - platform: partition
# id: light_middle_top
# name: "light middle top"
# segments:
# - id: rgb_light
# from: 23
# to: 23
# - platform: partition
# id: light_right_top
# name: "light right top"
# segments:
# - id: rgb_light
# from: 26
# to: 27
# - platform: partition
# id: light_left_bottom
# name: "light left bottom"
# segments:
# - id: rgb_light
# from: 6
# to: 7
# - platform: partition
# id: light_middle_bottom
# name: "light middle bottom"
# segments:
# - id: rgb_light
# from: 8
# to: 10
# - platform: partition
# id: light_right_bottom
# name: "light right bottom"
# segments:
# - id: rgb_light
# from: 11
# to: 12
- platform: partition
restore_mode: RESTORE_DEFAULT_OFF
id: light_left_both
name: "light left both"
segments:
- id: rgb_light
from: 11
to: 21
effects:
- addressable_twinkle:
- addressable_random_twinkle:
- addressable_rainbow:
speed: 5
- platform: partition
restore_mode: RESTORE_DEFAULT_OFF
id: light_middle_both
name: "light middle both"
segments:
- id: rgb_light
from: 22
to: 24
- id: rgb_light
from: 8
to: 10
effects:
- addressable_twinkle:
- addressable_random_twinkle:
- addressable_rainbow:
speed: 5
- platform: partition
restore_mode: RESTORE_DEFAULT_OFF
id: light_right_both
name: "light right both"
segments:
- id: rgb_light
from: 0
to: 7
- id: rgb_light
from: 25
to: 27
effects:
- addressable_twinkle:
- addressable_random_twinkle:
- addressable_rainbow:
speed: 5
- platform: partition
restore_mode: RESTORE_DEFAULT_OFF
id: light_right
name: "light right"
segments:
- id: rgb_light
from: 0
to: 5
# - platform: partition
# id: light_bottom
# name: "light bottom"
# segments:
# - id: rgb_light
# from: 6
# to: 12
- platform: partition
restore_mode: RESTORE_DEFAULT_OFF
id: light_left
name: "light left"
segments:
- id: rgb_light
from: 13
to: 19
# - platform: partition
# id: light_top
# name: "light top"
# segments:
# - id: rgb_light
# from: 20
# to: 26
condition:
switch.is_on: ${switch}
then:
- light.turn_on:
id: ${light}
brightness: ${on_brightness}
red: ${on_red}
green: ${on_green}
blue: ${on_blue}
transition_length: 500ms
else:
- if:
condition:
and:
- lambda: |-
return id(htime).now().hour < ${nightlight_on_hour};
- lambda: |-
return id(htime).now().hour > ${nightlight_off_hour};
then:
- light.turn_off:
id: ${light}
transition_length: 500ms
else:
- light.turn_on:
id: ${light}
brightness: ${nightlight_brightness}
red: ${nightlight_red}
green: ${nightlight_green}
blue: ${nightlight_blue}
transition_length: 500ms
substitutions:
name: 'sonoff_tx_ultimate_00'
on_brightness: 50%
on_red: 100%
on_green: 40%
on_blue: 0%
nightlight_brightness: 20%
nightlight_red: 100%
nightlight_green: 40%
nightlight_blue: 0%
nightlight_on_hour: '19' # turn on at 7 in the evening
nightlight_off_hour: '9' # turn off at 9 in the morning
esphome:
name: $name
platform: ESP32
board: esp32dev
on_boot:
priority: -100.0
then:
- script.execute: light_relays
includes:
- touch_panel.hpp
- touch_panel.cpp
uart:
id: uart_bus
tx_pin: GPIO19
rx_pin: GPIO22
baud_rate: 115200
script:
- id: light_relays
then:
- if: !include
file: relays_light.yaml
vars:
switch: relay1
light: light_left_both
- if: !include
file: relays_light.yaml
vars:
switch: relay2
light: light_middle_both
- if: !include
file: relays_light.yaml
vars:
switch: relay3
light: light_right_both
binary_sensor:
- platform: custom
lambda: |-
auto touch_panel = new touch_panel::TouchPanel(id(uart_bus));
App.register_component(touch_panel);
return {
touch_panel->left,
touch_panel->middle,
touch_panel->right,
touch_panel->two_finger,
touch_panel->dragged_ltr,
touch_panel->dragged_rtl,
};
binary_sensors:
- id: button_left
name: "Left Button"
on_press:
- switch.toggle: relay1
- switch.turn_on: haptics
- id: button_middle
name: "Middle Button"
on_press:
- switch.toggle: relay2
- switch.turn_on: haptics
- id: button_right
name: "Right Button"
on_press:
- switch.toggle: relay3
- switch.turn_on: haptics
- id: button_two_finger
name: "Two Fingers"
- id: button_dragged_ltr
name: "Dragged Left to Right"
- id: button_dragged_rtl
name: "Dragged Right to Left"
switch:
- platform: gpio
name: "relay left"
pin: GPIO18
id: relay1
on_turn_on:
script.execute: light_relays
on_turn_off:
script.execute: light_relays
- platform: gpio
name: "relay middle"
pin: GPIO17
id: relay2
on_turn_on:
script.execute: light_relays
on_turn_off:
script.execute: light_relays
- platform: gpio
name: "relay right"
pin: GPIO27
id: relay3
on_turn_on:
script.execute: light_relays
on_turn_off:
script.execute: light_relays
- platform: gpio
name: "relay right"
pin: GPIO23
id: relay4
on_turn_on:
script.execute: light_relays
on_turn_off:
script.execute: light_relays
- platform: gpio
name: "sound amplifier power"
pin: GPIO26
id: pa_sw
- platform: gpio
name: "touch panel power"
pin:
number: GPIO5
inverted: true
id: ca51_pow
restore_mode: ALWAYS_ON
- platform: gpio
pin: GPIO21
name: "Haptics"
id: "haptics"
restore_mode: ALWAYS_OFF
on_turn_on:
- delay: 300ms
- switch.turn_off: haptics
#include "touch_panel.hpp"
#include <stdio.h>
namespace esphome
{
namespace touch_panel
{
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
const uint8_t PREFIX[] = {0xAA, 0x55, 0x01, 0x02};
const unsigned int PREFIX_LENGTH = sizeof(PREFIX) / sizeof(PREFIX[0]);
// Messages consist of a prefix, a type of action and a position.
// There's probably other stuff but that's not relevant for us
const unsigned int MESSAGE_SIZE = PREFIX_LENGTH + 4;
const unsigned int BUFFER_SIZE = 32;
TouchPanel::TouchPanel(uart::UARTComponent *parent) : uart::UARTDevice(parent) {}
void TouchPanel::setup()
{
for (int i = 0; i < button_map.size(); i++)
button_map[i]->publish_state(i < TwoFinger);
}
void TouchPanel::loop()
{
static uint8_t buffer[BUFFER_SIZE];
while (available() >= MESSAGE_SIZE)
{
read_array(buffer, MIN(available(), BUFFER_SIZE));
bool match = true;
if (memcmp(buffer, PREFIX, PREFIX_LENGTH) != 0)
{
continue;
}
if (match)
{
TouchEvent event = static_cast<TouchEvent>(buffer[4]);
uint8_t released_position = buffer[5];
uint8_t pressed_position = buffer[6];
if (event == Pressed)
{
// ESP_LOGD("custom", "Pressed: %d", pressed_position);
button_map[pressed_position]->publish_state(true);
// Always trigger the two-fingered and drag events since we can only detect when they are released
two_finger->publish_state(true);
dragged_ltr->publish_state(true);
dragged_rtl->publish_state(true);
}
else if (event == Released || event == Dragged)
{
// Make sure to reset all buttons
for (int i = 0; i < TwoFinger; i++)
button_map[i]->publish_state(false);
button_map[released_position]->publish_state(false);
}
else
{
ESP_LOGD("custom", "Unknown event: %d", event);
}
}
}
}
} // namespace touch_panel
} // namespace esphome
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/uart/uart.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
#include <vector>
namespace esphome
{
namespace touch_panel
{
enum TouchEvent
{
Released = 1,
Pressed = 2,
Dragged = 3
};
enum TouchPosition
{
Left = 1,
Middle = 4,
Right = 7,
TwoFinger = 11,
DraggedLTR = 12,
DraggedRTL = 13
};
class TouchPanel : public Component, public uart::UARTDevice
{
public:
TouchPanel(uart::UARTComponent *parent);
void setup() override;
void loop() override;
float get_setup_priority() const override { return esphome::setup_priority::BUS; }
binary_sensor::BinarySensor *left = new binary_sensor::BinarySensor();
binary_sensor::BinarySensor *middle = new binary_sensor::BinarySensor();
binary_sensor::BinarySensor *right = new binary_sensor::BinarySensor();
binary_sensor::BinarySensor *two_finger = new binary_sensor::BinarySensor();
binary_sensor::BinarySensor *dragged_ltr = new binary_sensor::BinarySensor();
binary_sensor::BinarySensor *dragged_rtl = new binary_sensor::BinarySensor();
protected:
// For positional tracking
std::vector<binary_sensor::BinarySensor *> button_map = {
left, // 0 never occurs but is here for completeness
left, // 1-3 is left
left,
left,
middle, // 4-6 is middle
middle,
middle,
right, // 7-10 is right
right,
right,
right,
two_finger, // 11 is two fingers (released only)
dragged_ltr, // 12 is drag left to right
dragged_rtl, // 13 is drag right to left
};
};
} // namespace adalight
} // namespace esphome
@0xAhmed
Copy link

0xAhmed commented Nov 16, 2024

Thank you so much @wolph. I completed overlooked the fact that the baud rate might be the problem. I just tried with an ESP32-WROOM chip (was getting the same error message on it) and it worked fine. Shall try with another TX Ultimate switch later.

@xHirscHx
Copy link

xHirscHx commented Nov 18, 2024

Anybody ever get the sound to be as loud as the stock firmware. mine works but its very , very low.
media_player:

  • platform: i2s_audio
    id: media_out
    name: ${friendly_name} Player
    dac_type: external
    i2s_dout_pin: ${audio_sdata_pin}
    i2s_audio_id: audio_i2s
    i2s_comm_fmt: lsb
    mode: mono

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment