Compare commits
47 Commits
v2024.12.0
...
v2024.12.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09e9d340fc | ||
|
|
7850d16aeb | ||
|
|
1f2e60e7db | ||
|
|
dd25e5dbba | ||
|
|
75f4245fe1 | ||
|
|
3b7f811876 | ||
|
|
d403bc2aa9 | ||
|
|
5d780f162e | ||
|
|
0e53dfd3cd | ||
|
|
23b633cdcb | ||
|
|
b1187332fb | ||
|
|
669cc2f2c2 | ||
|
|
e5d941c460 | ||
|
|
9b134a786a | ||
|
|
be0fc353f6 | ||
|
|
fbc5cb79cc | ||
|
|
c65acc3298 | ||
|
|
4d8107faf2 | ||
|
|
65bbd901b1 | ||
|
|
8c610a406a | ||
|
|
696e3bf28d | ||
|
|
5ae4564e6a | ||
|
|
857c43940d | ||
|
|
8668fe8dc9 | ||
|
|
976a903118 | ||
|
|
35cc0c4a8e | ||
|
|
5c4581563e | ||
|
|
7f1c362a50 | ||
|
|
cf3018c95c | ||
|
|
360ae3123a | ||
|
|
6767b5e765 | ||
|
|
d5e5ebb3d6 | ||
|
|
46c04eb992 | ||
|
|
8558bc3650 | ||
|
|
f32e2eee4f | ||
|
|
5a993165cd | ||
|
|
d04c2aff2f | ||
|
|
2d79ee42c7 | ||
|
|
3f4fc7a505 | ||
|
|
be23a5a0fd | ||
|
|
a23a2db352 | ||
|
|
4e73a11528 | ||
|
|
3c98d81bb7 | ||
|
|
e63447984d | ||
|
|
1f1a8049e6 | ||
|
|
0dddc0747b | ||
|
|
86d1513c6a |
32
.github/workflows/release_tag.yml
vendored
32
.github/workflows/release_tag.yml
vendored
@@ -1,32 +0,0 @@
|
|||||||
---
|
|
||||||
name: Update Tags
|
|
||||||
|
|
||||||
# yamllint disable-line rule:truthy
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update-tags:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@main
|
|
||||||
with:
|
|
||||||
fetch-depth: '0'
|
|
||||||
|
|
||||||
- name: Set up Git
|
|
||||||
run: |
|
|
||||||
git config --local user.email "action@github.com"
|
|
||||||
git config --local user.name "GitHub Action"
|
|
||||||
|
|
||||||
- name: Move and push stable tag
|
|
||||||
run: |
|
|
||||||
git tag -f stable ${{ github.event.release.tag_name }}
|
|
||||||
git push -f origin stable
|
|
||||||
|
|
||||||
- name: Move and push latest tag
|
|
||||||
run: |
|
|
||||||
git tag -f latest ${{ github.event.release.tag_name }}
|
|
||||||
git push -f origin latest
|
|
||||||
...
|
|
||||||
4
.github/workflows/validate_esphome.yml
vendored
4
.github/workflows/validate_esphome.yml
vendored
@@ -30,8 +30,6 @@ jobs:
|
|||||||
|
|
||||||
build_basic:
|
build_basic:
|
||||||
name: Basic
|
name: Basic
|
||||||
needs:
|
|
||||||
- code_scan
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@main
|
- uses: actions/checkout@main
|
||||||
@@ -42,7 +40,6 @@ jobs:
|
|||||||
|
|
||||||
build_bluetooth_proxy_4:
|
build_bluetooth_proxy_4:
|
||||||
name: Bluetooth Proxy (IDF)
|
name: Bluetooth Proxy (IDF)
|
||||||
needs: build_basic
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@main
|
- uses: actions/checkout@main
|
||||||
@@ -53,7 +50,6 @@ jobs:
|
|||||||
|
|
||||||
build_bluetooth_proxy_53:
|
build_bluetooth_proxy_53:
|
||||||
name: Bluetooth Proxy (IDF v5.3)
|
name: Bluetooth Proxy (IDF v5.3)
|
||||||
needs: build_basic
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@main
|
- uses: actions/checkout@main
|
||||||
|
|||||||
4
.github/workflows/validate_esphome_beta.yml
vendored
4
.github/workflows/validate_esphome_beta.yml
vendored
@@ -47,8 +47,6 @@ jobs:
|
|||||||
|
|
||||||
build_basic:
|
build_basic:
|
||||||
name: Basic
|
name: Basic
|
||||||
needs:
|
|
||||||
- code_scan
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@main
|
- uses: actions/checkout@main
|
||||||
@@ -60,7 +58,6 @@ jobs:
|
|||||||
|
|
||||||
build_bluetooth_proxy_4:
|
build_bluetooth_proxy_4:
|
||||||
name: Bluetooth Proxy (IDF)
|
name: Bluetooth Proxy (IDF)
|
||||||
needs: build_basic
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@main
|
- uses: actions/checkout@main
|
||||||
@@ -72,7 +69,6 @@ jobs:
|
|||||||
|
|
||||||
build_bluetooth_proxy_53:
|
build_bluetooth_proxy_53:
|
||||||
name: Bluetooth Proxy (IDF v5.3)
|
name: Bluetooth Proxy (IDF v5.3)
|
||||||
needs: build_basic
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@main
|
- uses: actions/checkout@main
|
||||||
|
|||||||
87
.github/workflows/versioning.yml
vendored
87
.github/workflows/versioning.yml
vendored
@@ -1,31 +1,48 @@
|
|||||||
# Workflow for managing versioning, tagging, and conditional updates
|
# This GitHub Actions workflow handles version bumping and tag updates.
|
||||||
|
# It can be triggered either by:
|
||||||
|
# 1. Pushing to main branch - automatically bumps version and updates tags
|
||||||
|
# 2. Manual dispatch - allows independent control over stable and latest tags
|
||||||
|
|
||||||
---
|
---
|
||||||
name: Bump Version and Tag
|
|
||||||
|
name: Version and Tags
|
||||||
|
|
||||||
on: # yamllint disable-line rule:truthy
|
on: # yamllint disable-line rule:truthy
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
paths-ignore:
|
||||||
|
- '**/VERSION'
|
||||||
|
- '**/VERSION_YAML'
|
||||||
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
update_stable:
|
update_stable:
|
||||||
description: "Update stable tag?"
|
description: "Update stable tag?"
|
||||||
required: true
|
required: true
|
||||||
default: "false"
|
default: false
|
||||||
|
type: boolean
|
||||||
|
update_latest:
|
||||||
|
description: "Update latest tag?"
|
||||||
|
required: true
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
versioning:
|
version-and-tag:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Git
|
- name: Set up Git
|
||||||
run: |
|
run: |
|
||||||
git config user.name "GitHub Actions"
|
git config user.name "GitHub Actions"
|
||||||
git config user.email "actions@github.com"
|
git config user.email "actions@github.com"
|
||||||
|
|
||||||
- name: Bump Version
|
- name: Bump version
|
||||||
run: |
|
run: |
|
||||||
chmod +x ./versioning/bump_version.sh
|
chmod +x ./versioning/bump_version.sh
|
||||||
./versioning/bump_version.sh
|
./versioning/bump_version.sh
|
||||||
@@ -34,12 +51,56 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
git push https://x-access-token:${GITHUB_TOKEN}@github.com/edwardtfn/TX-Ultimate-Easy.git main
|
git push origin main
|
||||||
git push https://x-access-token:${GITHUB_TOKEN}@github.com/edwardtfn/TX-Ultimate-Easy.git --tags
|
git push origin --tags --force
|
||||||
|
|
||||||
- name: Conditionally Update Stable Tag
|
- name: Update stable tag
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.update_stable == 'true' }}
|
if: |
|
||||||
|
success() && (
|
||||||
|
github.event_name == 'workflow_dispatch' && inputs.update_stable ||
|
||||||
|
github.event_name == 'push'
|
||||||
|
)
|
||||||
run: |
|
run: |
|
||||||
git tag -f stable
|
# Verify version bump was successful
|
||||||
git push https://x-access-token:${GITHUB_TOKEN}@github.com/edwardtfn/TX-Ultimate-Easy.git stable --force
|
if [ ! -f "./versioning/VERSION" ]; then
|
||||||
|
echo "Error: VERSION file not found. Version bump may have failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Backup existing tag
|
||||||
|
if git rev-parse --verify stable >/dev/null 2>&1; then
|
||||||
|
OLD_STABLE=$(git rev-parse stable)
|
||||||
|
echo "Backing up current stable tag ($OLD_STABLE)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update tag
|
||||||
|
NEW_VERSION=$(cat ./versioning/VERSION)
|
||||||
|
echo "Updating stable tag to $NEW_VERSION"
|
||||||
|
git tag -fa stable -m "Update stable tag"
|
||||||
|
git push origin stable --force
|
||||||
|
|
||||||
|
- name: Update latest tag
|
||||||
|
if: |
|
||||||
|
success() && (
|
||||||
|
github.event_name == 'workflow_dispatch' && inputs.update_latest ||
|
||||||
|
github.event_name == 'push'
|
||||||
|
)
|
||||||
|
run: |
|
||||||
|
# Verify version bump was successful
|
||||||
|
if [ ! -f "./versioning/VERSION" ]; then
|
||||||
|
echo "Error: VERSION file not found. Version bump may have failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Backup existing tag
|
||||||
|
if git rev-parse --verify latest >/dev/null 2>&1; then
|
||||||
|
OLD_LATEST=$(git rev-parse latest)
|
||||||
|
echo "Backing up current latest tag ($OLD_LATEST)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update tag
|
||||||
|
NEW_VERSION=$(cat ./versioning/VERSION)
|
||||||
|
echo "Updating latest tag to $NEW_VERSION"
|
||||||
|
git tag -fa latest -m "Update latest tag"
|
||||||
|
git push origin latest --force
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
packages:
|
packages:
|
||||||
basic_package: !include ../TX-Ultimate-Easy-ESPHome.yaml # Basic package
|
basic_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml # Basic package
|
||||||
|
|
||||||
esp32:
|
esp32:
|
||||||
framework:
|
framework:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
packages:
|
packages:
|
||||||
basic_package: !include ../TX-Ultimate-Easy-ESPHome.yaml # Core package
|
core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
|
||||||
addon_bluetooth_proxy: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml
|
addon_bluetooth_proxy: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml
|
||||||
|
|
||||||
esp32:
|
esp32:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
packages:
|
packages:
|
||||||
basic_package: !include ../TX-Ultimate-Easy-ESPHome.yaml # Core package
|
core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
|
||||||
addon_bluetooth_proxy: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml
|
addon_bluetooth_proxy: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ improv_serial:
|
|||||||
id: serial_improv
|
id: serial_improv
|
||||||
|
|
||||||
logger:
|
logger:
|
||||||
level: INFO
|
level: DEBUG
|
||||||
|
|
||||||
ota:
|
ota:
|
||||||
platform: esphome
|
platform: esphome
|
||||||
|
|||||||
@@ -20,111 +20,53 @@ substitutions:
|
|||||||
BUTTON_3_ACTION_TEXT: "Relay 3 (toggle)"
|
BUTTON_3_ACTION_TEXT: "Relay 3 (toggle)"
|
||||||
BUTTON_4_ACTION_TEXT: "Relay 4 (toggle)"
|
BUTTON_4_ACTION_TEXT: "Relay 4 (toggle)"
|
||||||
|
|
||||||
binary_sensor:
|
BUTTON_CLICK_MIN_LENGTH: '50' # The minimum duration the click should last, in msec
|
||||||
- id: bs_button_1
|
BUTTON_CLICK_MAX_LENGTH: '350' # The maximum duration the click should last, in msec
|
||||||
name: Button 1
|
BUTTON_MULTI_CLICK_DELAY: '250' # The time to wait for another click, in msec
|
||||||
icon: mdi:gesture-tap-box
|
BUTTON_PRESS_TIMEOUT: '10000' # Ignore if button is pressed for longer than this time, in msec
|
||||||
internal: false
|
BUTTON_LONG_PRESS_DELAY: '800' # The time to wait to consider a long press, in msec
|
||||||
platform: template
|
|
||||||
on_click:
|
|
||||||
then:
|
|
||||||
- script.execute:
|
|
||||||
id: button_action
|
|
||||||
component: bs_button_1
|
|
||||||
event: click
|
|
||||||
on_double_click:
|
|
||||||
then:
|
|
||||||
- script.execute:
|
|
||||||
id: button_action
|
|
||||||
component: bs_button_1
|
|
||||||
event: double_click
|
|
||||||
on_multi_click:
|
|
||||||
- timing: &long_click-timing
|
|
||||||
- ON for at least 0.8s
|
|
||||||
invalid_cooldown: ${invalid_cooldown}
|
|
||||||
then:
|
|
||||||
- script.execute:
|
|
||||||
id: button_action
|
|
||||||
component: bs_button_1
|
|
||||||
event: long_click
|
|
||||||
|
|
||||||
- id: bs_button_2
|
binary_sensor:
|
||||||
|
- &binary_sensor_button_base
|
||||||
|
id: bs_button_2
|
||||||
name: Button 2
|
name: Button 2
|
||||||
icon: mdi:gesture-tap-box
|
icon: mdi:gesture-tap-box
|
||||||
internal: true
|
|
||||||
platform: template
|
platform: template
|
||||||
on_click:
|
internal: true
|
||||||
then:
|
|
||||||
- script.execute:
|
|
||||||
id: button_action
|
|
||||||
component: bs_button_2
|
|
||||||
event: click
|
|
||||||
on_double_click:
|
|
||||||
then:
|
|
||||||
- script.execute:
|
|
||||||
id: button_action
|
|
||||||
component: bs_button_2
|
|
||||||
event: double_click
|
|
||||||
on_multi_click:
|
|
||||||
- timing: *long_click-timing
|
|
||||||
invalid_cooldown: ${invalid_cooldown}
|
|
||||||
then:
|
|
||||||
- script.execute:
|
|
||||||
id: button_action
|
|
||||||
component: bs_button_2
|
|
||||||
event: long_click
|
|
||||||
|
|
||||||
- id: bs_button_3
|
- id: bs_button_3
|
||||||
name: Button 3
|
name: Button 3
|
||||||
icon: mdi:gesture-tap-box
|
<<: *binary_sensor_button_base
|
||||||
internal: true
|
|
||||||
platform: template
|
|
||||||
on_click:
|
|
||||||
then:
|
|
||||||
- script.execute:
|
|
||||||
id: button_action
|
|
||||||
component: bs_button_3
|
|
||||||
event: click
|
|
||||||
on_double_click:
|
|
||||||
then:
|
|
||||||
- script.execute:
|
|
||||||
id: button_action
|
|
||||||
component: bs_button_3
|
|
||||||
event: double_click
|
|
||||||
on_multi_click:
|
|
||||||
- timing: *long_click-timing
|
|
||||||
invalid_cooldown: ${invalid_cooldown}
|
|
||||||
then:
|
|
||||||
- script.execute:
|
|
||||||
id: button_action
|
|
||||||
component: bs_button_3
|
|
||||||
event: long_click
|
|
||||||
|
|
||||||
- id: bs_button_4
|
- id: bs_button_4
|
||||||
name: Button 4
|
name: Button 4
|
||||||
icon: mdi:gesture-tap-box
|
<<: *binary_sensor_button_base
|
||||||
internal: true
|
|
||||||
platform: template
|
- id: bs_button_1
|
||||||
on_click:
|
name: Button 1
|
||||||
then:
|
internal: false
|
||||||
- script.execute:
|
<<: *binary_sensor_button_base
|
||||||
id: button_action
|
|
||||||
component: bs_button_4
|
globals:
|
||||||
event: click
|
- id: button_press_button
|
||||||
on_double_click:
|
type: uint8_t
|
||||||
then:
|
restore_value: false
|
||||||
- script.execute:
|
initial_value: '0'
|
||||||
id: button_action
|
|
||||||
component: bs_button_4
|
- id: button_press_position
|
||||||
event: double_click
|
type: uint8_t
|
||||||
on_multi_click:
|
restore_value: false
|
||||||
- timing: *long_click-timing
|
initial_value: '0'
|
||||||
invalid_cooldown: ${invalid_cooldown}
|
|
||||||
then:
|
- id: button_press_start_time
|
||||||
- script.execute:
|
type: uint32_t
|
||||||
id: button_action
|
restore_value: false
|
||||||
component: bs_button_4
|
initial_value: '0'
|
||||||
event: long_click
|
|
||||||
|
- id: click_counter
|
||||||
|
type: uint8_t
|
||||||
|
restore_value: false
|
||||||
|
initial_value: '0'
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- id: !extend boot_initialize
|
- id: !extend boot_initialize
|
||||||
@@ -162,9 +104,31 @@ script:
|
|||||||
parameters:
|
parameters:
|
||||||
component: string
|
component: string
|
||||||
event: string
|
event: string
|
||||||
then: # There's nothing here so far
|
then:
|
||||||
# Extended by:
|
# Extended by:
|
||||||
# - core_api
|
# - core_api
|
||||||
|
- lambda: |-
|
||||||
|
ESP_LOGI("core_hw_buttons", "Button '%s' action: '%s'", component.c_str(), event.c_str());
|
||||||
|
id(button_press_button) = 0;
|
||||||
|
id(click_counter) = 0;
|
||||||
|
id(button_press_start_time) = 0;
|
||||||
|
buttons_release->execute();
|
||||||
|
|
||||||
|
- id: button_click_event
|
||||||
|
mode: restart
|
||||||
|
parameters:
|
||||||
|
button_id: uint8_t
|
||||||
|
click_count: uint8_t
|
||||||
|
then:
|
||||||
|
- delay:
|
||||||
|
milliseconds: ${BUTTON_MULTI_CLICK_DELAY}
|
||||||
|
- lambda: |-
|
||||||
|
const std::string button_name = "bs_button_" + std::to_string(button_id);
|
||||||
|
std::string event_name;
|
||||||
|
if (click_count == 1) event_name = "click";
|
||||||
|
else if (click_count == 2) event_name = "double_click";
|
||||||
|
else event_name = std::to_string(click_count) + "_click";
|
||||||
|
button_action->execute(button_name.c_str(), event_name.c_str());
|
||||||
|
|
||||||
- id: buttons_release
|
- id: buttons_release
|
||||||
mode: restart
|
mode: restart
|
||||||
@@ -187,42 +151,78 @@ script:
|
|||||||
then:
|
then:
|
||||||
- script.execute:
|
- script.execute:
|
||||||
id: touch_on_press_buttons
|
id: touch_on_press_buttons
|
||||||
touch_x: !lambda return touch_x;
|
touch_position: !lambda return touch_position;
|
||||||
|
|
||||||
- id: touch_on_press_buttons
|
- id: touch_on_press_buttons
|
||||||
mode: restart
|
mode: restart
|
||||||
parameters:
|
parameters:
|
||||||
touch_x: uint8_t
|
touch_position: uint8_t
|
||||||
then:
|
then:
|
||||||
- lambda: |-
|
- lambda: |-
|
||||||
|
id(button_press_start_time) = millis();
|
||||||
|
id(button_press_position) = touch_position;
|
||||||
|
uint8_t button = 0;
|
||||||
auto model_index = sl_tx_model_gang->active_index();
|
auto model_index = sl_tx_model_gang->active_index();
|
||||||
if (model_index.has_value()) {
|
if (model_index.has_value()) {
|
||||||
uint8_t model_idx = model_index.value() + 1;
|
const uint8_t model_idx = model_index.value() + 1; // Increment for 1-based indexing
|
||||||
switch (model_idx) {
|
if (model_idx == 1) {
|
||||||
case 1: // 1 Gang
|
button = 1; // Single button, always 1
|
||||||
bs_button_1->publish_state(true);
|
} else {
|
||||||
break;
|
const uint8_t width = ${TOUCH_POSITION_MAX_VALUE} / model_idx; // Width of each button region
|
||||||
case 2: // 2 Gang
|
ESP_LOGV("core_hw_buttons", "Button regions: width=%" PRIu8 ", touch_position=%" PRIu8,
|
||||||
if (touch_x <= 5) bs_button_1->publish_state(true);
|
width, touch_position);
|
||||||
else bs_button_2->publish_state(true);
|
button = (touch_position / width) + 1; // Determine button region
|
||||||
break;
|
if (button > model_idx)
|
||||||
case 3: // 3 Gang
|
button = model_idx; // Clamp to max button count
|
||||||
if (touch_x <= 3) bs_button_1->publish_state(true);
|
}
|
||||||
else if (touch_x <= 7) bs_button_2->publish_state(true);
|
}
|
||||||
else bs_button_3->publish_state(true);
|
// Update binary sensor
|
||||||
break;
|
switch (button) {
|
||||||
case 4: // 4 Gang
|
case 1:
|
||||||
if (touch_x <= 2) bs_button_1->publish_state(true);
|
bs_button_1->publish_state(true);
|
||||||
else if (touch_x <= 5) bs_button_2->publish_state(true);
|
break;
|
||||||
else if (touch_x <= 8) bs_button_3->publish_state(true);
|
case 2:
|
||||||
else bs_button_4->publish_state(true);
|
bs_button_2->publish_state(true);
|
||||||
break;
|
break;
|
||||||
}
|
case 3:
|
||||||
|
bs_button_3->publish_state(true);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
bs_button_4->publish_state(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Update counters
|
||||||
|
if (id(button_press_button) == button) {
|
||||||
|
id(click_counter)++;
|
||||||
|
} else {
|
||||||
|
id(click_counter) = 1;
|
||||||
|
id(button_press_button) = button;
|
||||||
}
|
}
|
||||||
|
|
||||||
- id: !extend touch_on_release
|
- id: !extend touch_on_release
|
||||||
then:
|
then:
|
||||||
- script.execute: buttons_release
|
- lambda: |-
|
||||||
|
uint32_t current_time = millis();
|
||||||
|
buttons_release->execute();
|
||||||
|
if (id(button_press_start_time) > 0 and
|
||||||
|
id(button_press_start_time) < current_time) {
|
||||||
|
uint32_t press_duration = current_time - id(button_press_start_time);
|
||||||
|
// Handle overflow (optional, since it's unlikely to happen here)
|
||||||
|
ESP_LOGI("core_hw_buttons", "Button press duration: %" PRIu32 " ms", press_duration);
|
||||||
|
if (press_duration < ${BUTTON_CLICK_MIN_LENGTH}) {
|
||||||
|
ESP_LOGW("core_hw_buttons", "Ignoring button press (too short)");
|
||||||
|
} else if (press_duration >= ${BUTTON_CLICK_MIN_LENGTH} and
|
||||||
|
press_duration <= ${BUTTON_CLICK_MAX_LENGTH}) { // Short/normal click
|
||||||
|
button_click_event->execute(id(button_press_button), id(click_counter));
|
||||||
|
} else if (press_duration >= ${BUTTON_LONG_PRESS_DELAY} and press_duration <= ${BUTTON_PRESS_TIMEOUT}) {
|
||||||
|
button_action->execute(("bs_button_" + std::to_string(id(button_press_button))).c_str(), "long_click");
|
||||||
|
} else if (press_duration > ${BUTTON_PRESS_TIMEOUT}) { // Timeout or invalid
|
||||||
|
ESP_LOGW("core_hw_buttons", "Button press cancelled or timed out after ${BUTTON_PRESS_TIMEOUT} ms");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ESP_LOGW("core_hw_buttons", "Press event timestamp not recorded yet");
|
||||||
|
}
|
||||||
|
id(button_press_start_time) = 0;
|
||||||
|
|
||||||
- id: !extend touch_swipe_left
|
- id: !extend touch_swipe_left
|
||||||
then:
|
then:
|
||||||
|
|||||||
@@ -11,55 +11,6 @@
|
|||||||
##### - For normal system use, modifications to this file are NOT required. #####
|
##### - For normal system use, modifications to this file are NOT required. #####
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
---
|
---
|
||||||
binary_sensor:
|
|
||||||
- id: !extend bs_button_1
|
|
||||||
on_click:
|
|
||||||
then:
|
|
||||||
- if:
|
|
||||||
condition:
|
|
||||||
- lambda: return sl_button_1_action->active_index().has_value();
|
|
||||||
- lambda: return sl_button_1_action->active_index().value() == 1;
|
|
||||||
- and: &button_click_no_other_click
|
|
||||||
- lambda: return not bs_multi_touch->state;
|
|
||||||
- lambda: return not bs_swipe_left->state;
|
|
||||||
- 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
|
|
||||||
on_click:
|
|
||||||
then:
|
|
||||||
- if:
|
|
||||||
condition:
|
|
||||||
- lambda: return sl_button_2_action->active_index().has_value();
|
|
||||||
- lambda: return sl_button_2_action->active_index().value() == 1;
|
|
||||||
- and: *button_click_no_other_click
|
|
||||||
then:
|
|
||||||
- switch.toggle: sw_relay_2
|
|
||||||
|
|
||||||
- id: !extend bs_button_3
|
|
||||||
on_click:
|
|
||||||
then:
|
|
||||||
- if:
|
|
||||||
condition:
|
|
||||||
- lambda: return sl_button_3_action->active_index().has_value();
|
|
||||||
- lambda: return sl_button_3_action->active_index().value() == 1;
|
|
||||||
- and: *button_click_no_other_click
|
|
||||||
then:
|
|
||||||
- switch.toggle: sw_relay_3
|
|
||||||
|
|
||||||
- id: !extend bs_button_4
|
|
||||||
on_click:
|
|
||||||
then:
|
|
||||||
- if:
|
|
||||||
condition:
|
|
||||||
- lambda: return sl_button_4_action->active_index().has_value();
|
|
||||||
- lambda: return sl_button_4_action->active_index().value() == 1;
|
|
||||||
- and: *button_click_no_other_click
|
|
||||||
then:
|
|
||||||
- switch.toggle: sw_relay_4
|
|
||||||
|
|
||||||
globals:
|
globals:
|
||||||
- id: boot_initialization_relays
|
- id: boot_initialization_relays
|
||||||
type: bool
|
type: bool
|
||||||
@@ -159,6 +110,45 @@ script:
|
|||||||
}
|
}
|
||||||
id(boot_initialization_relays) = true;
|
id(boot_initialization_relays) = true;
|
||||||
|
|
||||||
|
- id: !extend button_click_event
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
// Handle only single clicks
|
||||||
|
if (click_count != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Ignore if other touch events are active
|
||||||
|
if (bs_multi_touch->state ||
|
||||||
|
bs_swipe_left->state ||
|
||||||
|
bs_swipe_down->state ||
|
||||||
|
bs_swipe_right->state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle relay if corresponding button action is enabled
|
||||||
|
switch (button_id) {
|
||||||
|
case 1:
|
||||||
|
if (sl_button_1_action->active_index().has_value() and
|
||||||
|
sl_button_1_action->active_index().value() == 1)
|
||||||
|
sw_relay_1->toggle();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (sl_button_2_action->active_index().has_value() and
|
||||||
|
sl_button_2_action->active_index().value() == 1)
|
||||||
|
sw_relay_2->toggle();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (sl_button_3_action->active_index().has_value() and
|
||||||
|
sl_button_3_action->active_index().value() == 1)
|
||||||
|
sw_relay_3->toggle();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (sl_button_4_action->active_index().has_value() and
|
||||||
|
sl_button_4_action->active_index().value() == 1)
|
||||||
|
sw_relay_4->toggle();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
- id: show_relay_status
|
- id: show_relay_status
|
||||||
mode: restart
|
mode: restart
|
||||||
then:
|
then:
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
##### - For normal system use, modifications to this file are NOT required. #####
|
##### - For normal system use, modifications to this file are NOT required. #####
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
---
|
---
|
||||||
|
substitutions:
|
||||||
|
TOUCH_POSITION_MAX_VALUE: '10' # Maximum touch position value returned by the touch pad via uart
|
||||||
|
|
||||||
binary_sensor:
|
binary_sensor:
|
||||||
- id: bs_multi_touch
|
- id: bs_multi_touch
|
||||||
name: Multi-touch
|
name: Multi-touch
|
||||||
@@ -61,7 +64,7 @@ external_components:
|
|||||||
- source:
|
- source:
|
||||||
type: git
|
type: git
|
||||||
url: https://github.com/edwardtfn/TX-Ultimate-Easy
|
url: https://github.com/edwardtfn/TX-Ultimate-Easy
|
||||||
ref: ${version}
|
ref: v${version}
|
||||||
refresh: 1h
|
refresh: 1h
|
||||||
components:
|
components:
|
||||||
- tx_ultimate_easy
|
- tx_ultimate_easy
|
||||||
@@ -124,7 +127,7 @@ script:
|
|||||||
- id: touch_on_press
|
- id: touch_on_press
|
||||||
mode: restart
|
mode: restart
|
||||||
parameters:
|
parameters:
|
||||||
touch_x: uint8_t
|
touch_position: uint8_t
|
||||||
then:
|
then:
|
||||||
# Extended by:
|
# Extended by:
|
||||||
# - HW Buttons
|
# - HW Buttons
|
||||||
@@ -203,16 +206,28 @@ tx_ultimate_easy:
|
|||||||
id: tx_ultimate
|
id: tx_ultimate
|
||||||
uart: uart_touch
|
uart: uart_touch
|
||||||
|
|
||||||
|
on_long_touch_release:
|
||||||
|
- lambda: |-
|
||||||
|
const uint8_t touch_position = static_cast<uint8_t>(touch.x);
|
||||||
|
if (touch_position > ${TOUCH_POSITION_MAX_VALUE}) { // Check for valid range
|
||||||
|
ESP_LOGE("tx_ultimate_easy", "Invalid long-touch position: %" PRIu8, touch_position);
|
||||||
|
} else {
|
||||||
|
ESP_LOGI("tx_ultimate_easy", "Long-touch released at position %" PRIu8, touch_position);
|
||||||
|
}
|
||||||
|
|
||||||
on_multi_touch_release:
|
on_multi_touch_release:
|
||||||
- lambda: ESP_LOGI("tx_ultimate_easy", "Multi-touch released");
|
- lambda: ESP_LOGI("tx_ultimate_easy", "Multi-touch released");
|
||||||
- script.execute: touch_on_multi_touch_release
|
- script.execute: touch_on_multi_touch_release
|
||||||
|
|
||||||
on_press:
|
on_press:
|
||||||
- lambda: |-
|
- lambda: |-
|
||||||
ESP_LOGI("tx_ultimate_easy", "Pressed at position %" PRIu8, static_cast<uint8_t>(touch.x));
|
const uint8_t touch_position = static_cast<uint8_t>(touch.x);
|
||||||
- script.execute:
|
if (touch_position > ${TOUCH_POSITION_MAX_VALUE}) { // Check for valid range
|
||||||
id: touch_on_press
|
ESP_LOGE("tx_ultimate_easy", "Invalid touch position: %" PRIu8, touch_position);
|
||||||
touch_x: !lambda return static_cast<uint8_t>(touch.x);
|
} else {
|
||||||
|
ESP_LOGI("tx_ultimate_easy", "Pressed at position %" PRIu8, touch_position);
|
||||||
|
touch_on_press->execute(touch_position);
|
||||||
|
}
|
||||||
|
|
||||||
on_release:
|
on_release:
|
||||||
- lambda: ESP_LOGI("tx_ultimate_easy", "Released");
|
- lambda: ESP_LOGI("tx_ultimate_easy", "Released");
|
||||||
@@ -233,8 +248,8 @@ tx_ultimate_easy:
|
|||||||
ESP_LOGD("tx_ultimate_easy", " Position: %i", touch.x);
|
ESP_LOGD("tx_ultimate_easy", " Position: %i", touch.x);
|
||||||
|
|
||||||
uart:
|
uart:
|
||||||
id: uart_touch
|
- id: uart_touch
|
||||||
tx_pin: GPIO19
|
tx_pin: GPIO19
|
||||||
rx_pin: GPIO22
|
rx_pin: GPIO22
|
||||||
baud_rate: 115200
|
baud_rate: 115200
|
||||||
...
|
...
|
||||||
|
|||||||
17
README.md
17
README.md
@@ -1,19 +1,20 @@
|
|||||||
# TX Ultimate Easy
|
# TX Ultimate Easy
|
||||||
|
|
||||||
<!-- markdownlint-disable MD033 -->
|
[![Version][version-shield]](https://github.com/edwardtfn/TX-Ultimate-Easy/tags)
|
||||||
<a href="https://github.com/edwardtfn/TX-Ultimate-Easy/commits/main" target="_blank">![GitHub Activity][commits-shield]</a>
|
[![GitHub Activity][commits-shield]](https://github.com/edwardtfn/TX-Ultimate-Easy/commits/main)
|
||||||
<a href="LICENSE" target="_blank">![License][license-shield]</a>
|
[![License][license-shield]](LICENSE)
|
||||||
<a href="https://github.com/edwardtfn/TX-Ultimate-Easy/commits/main" target="_blank">![GitHub Last Commit][last-commit-shield]</a>
|
[![GitHub Last Commit][last-commit-shield]](https://github.com/edwardtfn/TX-Ultimate-Easy/commits/main)
|
||||||
<a href="https://esphome.io/" target="_blank">![ESPHome][esphome-shield]</a>
|
[![ESPHome][esphome-shield]](https://esphome.io/)
|
||||||
<a href="https://discord.gg/Db6WJWzWuf" target="_blank">![Discord][discord-shield]</a>
|
[![Discord][discord-shield]](https://discord.gg/Db6WJWzWuf)
|
||||||
<a href="https://www.buymeacoffee.com/edwardfirmo" target="_blank">![Buy me an ice-cream][buymeacoffee-shield]</a>
|
[![Buy me an ice-cream][buymeacoffee-shield]](https://www.buymeacoffee.com/edwardfirmo)
|
||||||
<!-- markdownlint-enable MD033 -->
|
|
||||||
|
|
||||||
<!-- markdownlint-disable MD013 -->
|
<!-- markdownlint-disable MD013 -->
|
||||||
|  | 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. |
|
|  | 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 -->
|
||||||
|
|
||||||
|
[version-shield]: https://img.shields.io/github/v/tag/edwardtfn/TX-Ultimate-Easy?label=version
|
||||||
|
[version]: https://github.com/edwardtfn/TX-Ultimate-Easy/tags
|
||||||
[commits-shield]: https://img.shields.io/github/commit-activity/y/edwardtfn/TX-Ultimate-Easy
|
[commits-shield]: https://img.shields.io/github/commit-activity/y/edwardtfn/TX-Ultimate-Easy
|
||||||
[commits]: https://github.com/edwardtfn/TX-Ultimate-Easy/commits/main
|
[commits]: https://github.com/edwardtfn/TX-Ultimate-Easy/commits/main
|
||||||
[license-shield]: https://img.shields.io/github/license/edwardtfn/TX-Ultimate-Easy
|
[license-shield]: https://img.shields.io/github/license/edwardtfn/TX-Ultimate-Easy
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ wifi:
|
|||||||
packages:
|
packages:
|
||||||
remote_package:
|
remote_package:
|
||||||
url: https://github.com/edwardtfn/TX-Ultimate-Easy
|
url: https://github.com/edwardtfn/TX-Ultimate-Easy
|
||||||
ref: dev
|
ref: main
|
||||||
refresh: 30s
|
refresh: 30s
|
||||||
files:
|
files:
|
||||||
- ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
|
- ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ DEPENDENCIES = ['uart']
|
|||||||
CONF_TX_ULTIMATE_EASY = "tx_ultimate_easy"
|
CONF_TX_ULTIMATE_EASY = "tx_ultimate_easy"
|
||||||
|
|
||||||
CONF_UART = "uart"
|
CONF_UART = "uart"
|
||||||
|
CONF_GANG_COUNT = "gang_count"
|
||||||
|
|
||||||
CONF_ON_TOUCH_EVENT = "on_touch_event"
|
CONF_ON_TOUCH_EVENT = "on_touch_event"
|
||||||
CONF_ON_PRESS = "on_press"
|
CONF_ON_PRESS = "on_press"
|
||||||
@@ -33,6 +34,7 @@ CONFIG_SCHEMA = cv.Schema({
|
|||||||
cv.GenerateID(): cv.declare_id(TxUltimateTouch),
|
cv.GenerateID(): cv.declare_id(TxUltimateTouch),
|
||||||
|
|
||||||
cv.Required(CONF_UART): cv.use_id(uart),
|
cv.Required(CONF_UART): cv.use_id(uart),
|
||||||
|
cv.Optional(CONF_GANG_COUNT, default=1): cv.int_range(min=1, max=4),
|
||||||
|
|
||||||
cv.Optional(CONF_ON_TOUCH_EVENT): automation.validate_automation(single=True),
|
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_PRESS): automation.validate_automation(single=True),
|
||||||
@@ -49,6 +51,9 @@ async def register_tx_ultimate_easy(var, config):
|
|||||||
uart_component = await cg.get_variable(config[CONF_UART])
|
uart_component = await cg.get_variable(config[CONF_UART])
|
||||||
cg.add(var.set_uart_component(uart_component))
|
cg.add(var.set_uart_component(uart_component))
|
||||||
|
|
||||||
|
if CONF_GANG_COUNT in config:
|
||||||
|
cg.add(var.set_gang_count(config[CONF_GANG_COUNT]))
|
||||||
|
|
||||||
if CONF_ON_TOUCH_EVENT in config:
|
if CONF_ON_TOUCH_EVENT in config:
|
||||||
await automation.build_automation(
|
await automation.build_automation(
|
||||||
var.get_trigger_touch_event(),
|
var.get_trigger_touch_event(),
|
||||||
|
|||||||
@@ -48,6 +48,35 @@ namespace esphome {
|
|||||||
|
|
||||||
void TxUltimateEasy::dump_config() {
|
void TxUltimateEasy::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "TX Ultimate Easy");
|
ESP_LOGCONFIG(TAG, "TX Ultimate Easy");
|
||||||
|
ESP_LOGCONFIG(TAG, " Gang count: %" PRIu8, this->gang_count_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TxUltimateEasy::set_gang_count(const uint8_t gang_count) {
|
||||||
|
// Hardware supports maximum of 4 touch-sensitive buttons
|
||||||
|
if (gang_count < 1 or gang_count > 4)
|
||||||
|
return false;
|
||||||
|
this->gang_count_ = gang_count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TxUltimateEasy::get_button_from_position(const uint8_t position) {
|
||||||
|
// Validate position bounds
|
||||||
|
if (position > TOUCH_MAX_POSITION)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Special case for single gang (only one button exists)
|
||||||
|
if (this->gang_count_ == 1)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// Calculate button number
|
||||||
|
const uint8_t width = (TOUCH_MAX_POSITION + 1) / this->gang_count_; // Width of each button region
|
||||||
|
if (width < 1 or width > this->gang_count_) // Invalid width - and prevents division by zero
|
||||||
|
return 0;
|
||||||
|
const uint8_t button = std::min(
|
||||||
|
static_cast<uint8_t>((position / width) + 1), // Convert position to button index
|
||||||
|
this->gang_count_ // Clamp to max gang count
|
||||||
|
);
|
||||||
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TxUltimateEasy::send_touch_(TouchPoint tp) {
|
void TxUltimateEasy::send_touch_(TouchPoint tp) {
|
||||||
@@ -103,7 +132,8 @@ namespace esphome {
|
|||||||
state == TOUCH_STATE_SWIPE_LEFT ||
|
state == TOUCH_STATE_SWIPE_LEFT ||
|
||||||
state == TOUCH_STATE_SWIPE_RIGHT ||
|
state == TOUCH_STATE_SWIPE_RIGHT ||
|
||||||
state == TOUCH_STATE_MULTI_TOUCH) &&
|
state == TOUCH_STATE_MULTI_TOUCH) &&
|
||||||
(uart_received_bytes[6] >= 0 || state == TOUCH_STATE_MULTI_TOUCH);
|
// Multi-touch events may have x < 0, all other events require valid x position
|
||||||
|
(uart_received_bytes[6] >= 0 || state == TOUCH_STATE_MULTI_TOUCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
int TxUltimateEasy::get_touch_position_x(const std::array<int, UART_RECEIVED_BYTES_SIZE> &uart_received_bytes) {
|
int TxUltimateEasy::get_touch_position_x(const std::array<int, UART_RECEIVED_BYTES_SIZE> &uart_received_bytes) {
|
||||||
@@ -133,6 +163,8 @@ namespace esphome {
|
|||||||
TouchPoint TxUltimateEasy::get_touch_point(const std::array<int, UART_RECEIVED_BYTES_SIZE> &uart_received_bytes) {
|
TouchPoint TxUltimateEasy::get_touch_point(const std::array<int, UART_RECEIVED_BYTES_SIZE> &uart_received_bytes) {
|
||||||
TouchPoint tp;
|
TouchPoint tp;
|
||||||
tp.x = this->get_touch_position_x(uart_received_bytes);
|
tp.x = this->get_touch_position_x(uart_received_bytes);
|
||||||
|
if (tp.x >= 0)
|
||||||
|
tp.button = this->get_button_from_position(static_cast<uint8_t>(tp.x));
|
||||||
tp.state = this->get_touch_state(uart_received_bytes);
|
tp.state = this->get_touch_state(uart_received_bytes);
|
||||||
switch (tp.state) {
|
switch (tp.state) {
|
||||||
case TOUCH_STATE_RELEASE:
|
case TOUCH_STATE_RELEASE:
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace tx_ultimate_easy {
|
namespace tx_ultimate_easy {
|
||||||
|
// Touch Max Position
|
||||||
|
constexpr uint8_t TOUCH_MAX_POSITION = 10;
|
||||||
|
|
||||||
// Touch State Constants
|
// Touch State Constants
|
||||||
constexpr uint8_t TOUCH_STATE_RELEASE = 0x01;
|
constexpr uint8_t TOUCH_STATE_RELEASE = 0x01;
|
||||||
constexpr uint8_t TOUCH_STATE_PRESS = 0x02;
|
constexpr uint8_t TOUCH_STATE_PRESS = 0x02;
|
||||||
@@ -32,6 +35,7 @@ namespace esphome {
|
|||||||
static const char *TAG = "tx_ultimate_easy";
|
static const char *TAG = "tx_ultimate_easy";
|
||||||
|
|
||||||
struct TouchPoint {
|
struct TouchPoint {
|
||||||
|
uint8_t button = 0;
|
||||||
int8_t x = -1;
|
int8_t x = -1;
|
||||||
int8_t state = -1;
|
int8_t state = -1;
|
||||||
std::string state_str = "Unknown";
|
std::string state_str = "Unknown";
|
||||||
@@ -53,6 +57,10 @@ namespace esphome {
|
|||||||
void loop() override;
|
void loop() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|
||||||
|
uint8_t get_gang_count() { return this->gang_count_; }
|
||||||
|
bool set_gang_count(const uint8_t gang_count);
|
||||||
|
uint8_t get_button_from_position(const uint8_t position);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void send_touch_(TouchPoint tp);
|
void send_touch_(TouchPoint tp);
|
||||||
void handle_touch(const std::array<int, UART_RECEIVED_BYTES_SIZE> &bytes);
|
void handle_touch(const std::array<int, UART_RECEIVED_BYTES_SIZE> &bytes);
|
||||||
@@ -70,6 +78,8 @@ namespace esphome {
|
|||||||
Trigger<TouchPoint> trigger_multi_touch_release_;
|
Trigger<TouchPoint> trigger_multi_touch_release_;
|
||||||
Trigger<TouchPoint> trigger_long_touch_release_;
|
Trigger<TouchPoint> trigger_long_touch_release_;
|
||||||
|
|
||||||
|
uint8_t gang_count_ = 1;
|
||||||
|
|
||||||
}; // class TxUltimateEasy
|
}; // class TxUltimateEasy
|
||||||
|
|
||||||
} // namespace tx_ultimate_easy
|
} // namespace tx_ultimate_easy
|
||||||
|
|||||||
@@ -1,35 +1,29 @@
|
|||||||
# Versioning
|
# Versioning
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
This project uses a time-based versioning scheme: `year.month.sequential_number`.
|
This project uses a time-based versioning scheme: `year.month.sequential_number`.
|
||||||
This scheme makes it easy to identify when a version was released and provides a clear order for releases within a given month.
|
The system automates version updates and tagging to ensure consistent, conflict-free management of releases.
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
- `2024.12.01` – First release of December 2024.
|
- `2024.1.1` – First release of January 2024.
|
||||||
- `2024.12.02` – Second release of December 2024.
|
- `2024.12.2` – Second release of December 2024.
|
||||||
- `2025.01.01` – First release of January 2025.
|
|
||||||
|
|
||||||
## Files
|
## How It Works
|
||||||
- **`VERSION`**: Contains the current version of the project as plain text.
|
1. **Temporary Branch Creation**: A unique branch is created for each workflow run.
|
||||||
- **`bump_version.sh`**: A script to increment the version based on the current date and release sequence.
|
2. **Version Update**: The workflow updates the `VERSION` and `VERSION_YAML` files using the current date and release sequence.
|
||||||
- **`README.md`**: Documentation for the versioning process.
|
3. **Commit with Marker**: Changes are committed with a `[skip-versioning]` marker to prevent triggering the workflow again.
|
||||||
|
4. **Merge into Main**: The temporary branch is merged into `main`.
|
||||||
## Versioning Rules
|
5. **Branch Cleanup**: The temporary branch is deleted after merging.
|
||||||
1. The version format is `YYYY.MM.NN`, where:
|
|
||||||
- `YYYY` is the current year.
|
|
||||||
- `MM` is the current month (two digits).
|
|
||||||
- `NN` is the sequential release number within the month (starting at `01`).
|
|
||||||
2. On each new merge to the `main` branch:
|
|
||||||
- If the month hasn’t changed, the sequential number (`NN`) is incremented.
|
|
||||||
- If the month has changed, the sequential number resets to `01`.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Automatically Managed
|
### Automated Workflow
|
||||||
The versioning process is fully integrated into the workflow. Developers do not need to manually increment or manage versions.
|
The versioning process is fully automated:
|
||||||
Simply push your changes, and the system will handle version updates and tagging automatically.
|
- Developers submit their changes as usual.
|
||||||
|
- The workflow handles version updates, tagging, and integration into `main`.
|
||||||
|
- No manual intervention is needed for versioning.
|
||||||
|
|
||||||
### Access Version in Code
|
### Accessing the Version in Code
|
||||||
The version is accessible in the ESPHome YAML configuration file (`TX-Ultimate-Easy-ESPHome_core.yaml`) using the following syntax:
|
The version is accessible in the ESPHome YAML configuration file (`TX-Ultimate-Easy-ESPHome_core.yaml`) using the following syntax:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -37,30 +31,46 @@ substitutions:
|
|||||||
version: <<: !include ../versioning/VERSION
|
version: <<: !include ../versioning/VERSION
|
||||||
```
|
```
|
||||||
|
|
||||||
This ensures the correct version is used directly in the ESPHome setup without requiring manual updates.
|
This ensures the correct version is dynamically included in the ESPHome setup.
|
||||||
|
|
||||||
## Benefits of this Versioning Approach
|
## Benefits
|
||||||
1. **Clarity**: Each version is tied to a specific point in time, making it easy to track releases.
|
- **Clarity**: Easily track when a release occurred with meaningful version numbers.
|
||||||
2. **Automation**: The process is seamless and reduces manual effort.
|
- **Automation**: Eliminates manual version management.
|
||||||
3. **Scalability**: Supports frequent releases while keeping the versioning system organized.
|
- **Scalability**: Supports frequent updates and concurrent workflows.
|
||||||
4. **Traceability**: Git tags and the `VERSION` file ensure releases are well-documented and easily accessible.
|
- **Traceability**: Maintains a clear history of changes through Git tags and version files.
|
||||||
|
|
||||||
|
## System Details
|
||||||
|
|
||||||
|
### Version Format
|
||||||
|
The format `year.month.sequential_number` includes:
|
||||||
|
- `year` (YYYY): A 4-digit number representing the year.
|
||||||
|
- `month` (M): A number from 1 to 12 (no leading zeros).
|
||||||
|
- `sequential_number`: A positive number incremented with each release in the same month.
|
||||||
|
|
||||||
|
### Validation Rules
|
||||||
|
The `bump_version.sh` script enforces strict validation:
|
||||||
|
- Year must be a 4-digit number.
|
||||||
|
- Month must be 1–12 without leading zeros.
|
||||||
|
- Sequence must be a positive number without leading zeros.
|
||||||
|
|
||||||
|
If validation fails, the workflow stops and provides an error message.
|
||||||
|
|
||||||
|
### GitHub Workflow
|
||||||
|
The workflow is triggered automatically when:
|
||||||
|
- Changes are pushed to `main`.
|
||||||
|
- Developers trigger it manually using the `workflow_dispatch` event.
|
||||||
|
|
||||||
|
The workflow avoids infinite loops by committing changes with the `[skip-versioning]` marker.
|
||||||
|
|
||||||
## Extending the System
|
## Extending the System
|
||||||
- Add more scripts to handle additional automation tasks, such as generating changelogs or notifying stakeholders of new releases.
|
Consider extending the system to:
|
||||||
- Enhance the `bump_version.sh` script to support different versioning schemes if needed.
|
- Automatically generate release notes or changelogs.
|
||||||
- Integrate versioning information into your deployment pipelines to label builds with their corresponding version.
|
- Notify stakeholders when a new version is released.
|
||||||
|
- Integrate versioning information into deployment pipelines.
|
||||||
|
|
||||||
## Version Validation
|
## FAQ
|
||||||
|
**Q: What happens if two workflows run concurrently?**
|
||||||
|
A: Each workflow operates in its own temporary branch, avoiding conflicts.
|
||||||
|
|
||||||
The versioning system enforces strict format validation:
|
**Q: Can I manually update the version?**
|
||||||
- Year must be a 4-digit number (YYYY)
|
A: Manual updates are not needed. The workflow ensures accurate, automated versioning.
|
||||||
- Month must be a 2-digit number (01-12)
|
|
||||||
- Sequence must be a 2-digit number (01-99)
|
|
||||||
|
|
||||||
The `bump_version.sh` script includes validation checks and will fail if:
|
|
||||||
- The version format is invalid
|
|
||||||
- The sequence number would exceed 99 in a month
|
|
||||||
|
|
||||||
### GitHub Actions Workflow Adjustment
|
|
||||||
The GitHub Actions workflow for versioning runs only when changes are merged into the `main` branch, ensuring no premature version updates during PR creation.
|
|
||||||
This behavior is automatically handled by the integrated workflow.
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2024.12.01
|
2024.12.6
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
version: 2024.12.01
|
version: 2024.12.6
|
||||||
|
|||||||
@@ -5,18 +5,20 @@ VERSION_YAML_FILE="./versioning/VERSION_YAML"
|
|||||||
|
|
||||||
# Read the current version
|
# Read the current version
|
||||||
if [ -f "$VERSION_FILE" ]; then
|
if [ -f "$VERSION_FILE" ]; then
|
||||||
CURRENT_VERSION=$(cat $VERSION_FILE)
|
CURRENT_VERSION=$(cat "$VERSION_FILE")
|
||||||
else
|
else
|
||||||
CURRENT_VERSION="0.0.0" # Default if file doesn't exist
|
CURRENT_VERSION="0.0.0" # Default if file doesn't exist
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Extract components
|
# Validate the current version format
|
||||||
CURRENT_YEAR=$(date +%Y)
|
if ! [[ "$CURRENT_VERSION" =~ ^[0-9]{4}\.[0-9]{1,2}\.[0-9]+$ ]]; then
|
||||||
CURRENT_MONTH=$(date +%m)
|
|
||||||
if ! [[ "$CURRENT_VERSION" =~ ^[0-9]{4}\.[0-9]{2}\.[0-9]{2}$ ]]; then
|
|
||||||
echo "Error: Invalid version format in $VERSION_FILE"
|
echo "Error: Invalid version format in $VERSION_FILE"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Extract components
|
||||||
|
CURRENT_YEAR=$(date +%Y)
|
||||||
|
CURRENT_MONTH=$(date +%-m) # Avoid leading zero for the month
|
||||||
CURRENT_SEQ=$(echo "$CURRENT_VERSION" | awk -F. '{print $3}')
|
CURRENT_SEQ=$(echo "$CURRENT_VERSION" | awk -F. '{print $3}')
|
||||||
|
|
||||||
VERSION_YEAR=$(echo "$CURRENT_VERSION" | awk -F. '{print $1}')
|
VERSION_YEAR=$(echo "$CURRENT_VERSION" | awk -F. '{print $1}')
|
||||||
@@ -24,17 +26,12 @@ VERSION_MONTH=$(echo "$CURRENT_VERSION" | awk -F. '{print $2}')
|
|||||||
|
|
||||||
# Determine new version
|
# Determine new version
|
||||||
if [[ "$CURRENT_YEAR" == "$VERSION_YEAR" && "$CURRENT_MONTH" == "$VERSION_MONTH" ]]; then
|
if [[ "$CURRENT_YEAR" == "$VERSION_YEAR" && "$CURRENT_MONTH" == "$VERSION_MONTH" ]]; then
|
||||||
NEXT_SEQ=$((10#$CURRENT_SEQ + 1))
|
NEXT_SEQ=$((CURRENT_SEQ + 1))
|
||||||
if [ $NEXT_SEQ -gt 99 ]; then
|
|
||||||
echo "Error: Sequence number would exceed 99"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
NEW_SEQ=$(printf "%02d" $NEXT_SEQ)
|
|
||||||
else
|
else
|
||||||
NEW_SEQ="01" # Reset sequence for a new month
|
NEXT_SEQ=1 # Reset sequence for a new month
|
||||||
fi
|
fi
|
||||||
|
|
||||||
NEW_VERSION="${CURRENT_YEAR}.${CURRENT_MONTH}.${NEW_SEQ}"
|
NEW_VERSION="${CURRENT_YEAR}.${CURRENT_MONTH}.${NEXT_SEQ}"
|
||||||
|
|
||||||
# Update the plain text VERSION file
|
# Update the plain text VERSION file
|
||||||
echo "$NEW_VERSION" > "$VERSION_FILE"
|
echo "$NEW_VERSION" > "$VERSION_FILE"
|
||||||
@@ -47,7 +44,7 @@ if ! git add "$VERSION_FILE" "$VERSION_YAML_FILE"; then
|
|||||||
echo "Error: Failed to stage version files"
|
echo "Error: Failed to stage version files"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if ! git commit -m "Bump version to $NEW_VERSION"; then
|
if ! git commit -m "Bump version to $NEW_VERSION [skip-versioning]"; then
|
||||||
echo "Error: Failed to commit version bump"
|
echo "Error: Failed to commit version bump"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user