Add espnow switch

This commit is contained in:
Aiden
2026-07-25 17:36:28 +08:00
parent 8fc4eb3bc4
commit e565e29288
2 changed files with 264 additions and 76 deletions
+132 -38
View File
@@ -10,7 +10,7 @@ substitutions:
# Project Name # Project Name
project_name: "China Athom Technology.Athom RGBCW Bulb" project_name: "China Athom Technology.Athom RGBCW Bulb"
# Projection version denotes the release version of the yaml file, allowing checking of deployed vs latest version # Projection version denotes the release version of the yaml file, allowing checking of deployed vs latest version
project_version: "v3.2.4" project_version: "v3.2.5"
# Restore the light (GPO switch) upon reboot to state: # Restore the light (GPO switch) upon reboot to state:
light_restore_mode: RESTORE_DEFAULT_ON light_restore_mode: RESTORE_DEFAULT_ON
# Define a domain for this device to use. i.e. iot.home.lan (so device will appear as athom-smart-plug-v2.iot.home.lan in DNS/DHCP logs) # Define a domain for this device to use. i.e. iot.home.lan (so device will appear as athom-smart-plug-v2.iot.home.lan in DNS/DHCP logs)
@@ -77,6 +77,11 @@ globals:
restore_value: yes restore_value: yes
initial_value: "false" initial_value: "false"
- id: espnow_enabled
type: bool
restore_value: yes
initial_value: "true"
select: select:
- platform: template - platform: template
name: "Power On State" name: "Power On State"
@@ -134,24 +139,48 @@ esphome:
then: then:
- if: - if:
condition: condition:
lambda: 'return id(remote_paired);' lambda: 'return id(espnow_enabled);'
then: then:
- espnow.peer.add: # ESP-NOW is configured with enable_on_boot: false so that the saved
id: espnow_component # switch state decides whether the stack comes up at all. enable()
address: !lambda |- # must run before any peer.add - add_peer() returns ESP_ERR_ESPNOW_NOT_INIT
return id(remote_mac); # while the component is disabled.
- lambda: |- - lambda: 'id(espnow_component)->enable();'
char mac[18]; - if:
snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X", condition:
id(remote_mac)[0], id(remote_mac)[1], lambda: 'return id(remote_paired);'
id(remote_mac)[2], id(remote_mac)[3], then:
id(remote_mac)[4], id(remote_mac)[5]); - espnow.peer.add:
id(remote_paired_text).publish_state(mac); id: espnow_component
id(remote_pairing_status).publish_state("Paired"); address: !lambda |-
return id(remote_mac);
- lambda: |-
char mac[18];
snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
id(remote_mac)[0], id(remote_mac)[1],
id(remote_mac)[2], id(remote_mac)[3],
id(remote_mac)[4], id(remote_mac)[5]);
id(remote_paired_text).publish_state(mac);
id(remote_pairing_status).publish_state("Paired");
else:
- lambda: |-
id(remote_paired_text).publish_state("None");
id(remote_pairing_status).publish_state("Idle");
else: else:
# ESP-NOW switched off: leave the stack down, but still surface the
# retained pairing so the user can see it is remembered.
- lambda: |- - lambda: |-
id(remote_paired_text).publish_state("None"); if (id(remote_paired)) {
id(remote_pairing_status).publish_state("Idle"); char mac[18];
snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
id(remote_mac)[0], id(remote_mac)[1],
id(remote_mac)[2], id(remote_mac)[3],
id(remote_mac)[4], id(remote_mac)[5]);
id(remote_paired_text).publish_state(mac);
} else {
id(remote_paired_text).publish_state("None");
}
id(remote_pairing_status).publish_state("Disabled");
- if: - if:
condition: condition:
and: and:
@@ -255,7 +284,9 @@ esp32_improv:
espnow: espnow:
id: espnow_component id: espnow_component
auto_add_peer: false auto_add_peer: false
enable_on_boot: true # Startup is driven by the "ESP-NOW" switch via the on_boot automation above,
# so the stack is never brought up only to be torn down again.
enable_on_boot: false
on_unknown_peer: on_unknown_peer:
- lambda: |- - lambda: |-
const char *const TAG = "espnow_remote"; const char *const TAG = "espnow_remote";
@@ -410,6 +441,53 @@ switch:
- esp32_ble_tracker.stop_scan: - esp32_ble_tracker.stop_scan:
- lambda: 'ESP_LOGI("bluetooth_proxy_switch", "Bluetooth proxy scanning disabled");' - lambda: 'ESP_LOGI("bluetooth_proxy_switch", "Bluetooth proxy scanning disabled");'
- platform: template
name: "ESP-NOW"
id: espnow_switch
icon: mdi:remote
entity_category: config
restore_mode: DISABLED
lambda: 'return id(espnow_enabled);'
turn_on_action:
- globals.set:
id: espnow_enabled
value: "true"
# enable() first: add_peer() is rejected with ESP_ERR_ESPNOW_NOT_INIT while disabled.
- lambda: 'id(espnow_component)->enable();'
- if:
condition:
lambda: 'return id(remote_paired);'
then:
- espnow.peer.add:
id: espnow_component
address: !lambda |-
return id(remote_mac);
- lambda: 'id(remote_pairing_status).publish_state("Paired");'
else:
- lambda: 'id(remote_pairing_status).publish_state("Idle");'
- lambda: 'ESP_LOGI("espnow_remote", "ESP-NOW enabled");'
turn_off_action:
- globals.set:
id: espnow_enabled
value: "false"
# Close any open pairing window so it cannot fire once ESP-NOW comes back.
- lambda: 'id(remote_pairing) = false;'
# Drop the peer while the stack is still up (del_peer() is rejected once disabled).
# The pairing itself lives in remote_mac/remote_paired and is retained, so turning
# the switch back on re-adds the same remote without re-pairing.
- if:
condition:
lambda: 'return id(remote_paired);'
then:
- espnow.peer.delete:
id: espnow_component
address: !lambda |-
return id(remote_mac);
- lambda: |-
id(espnow_component)->disable();
id(remote_pairing_status).publish_state("Disabled");
ESP_LOGI("espnow_remote", "ESP-NOW disabled");
binary_sensor: binary_sensor:
- platform: status - platform: status
name: "Status" name: "Status"
@@ -468,12 +546,20 @@ button:
entity_category: config entity_category: config
on_press: on_press:
then: then:
- lambda: |- - if:
id(remote_pairing) = true; condition:
id(remote_pair_deadline) = millis() + 60000; lambda: 'return !id(espnow_enabled);'
id(remote_pairing_status).publish_state("Pairing for 60 seconds"); then:
ESP_LOGI("espnow_remote", "Pairing enabled for 60 seconds; press a ESP-NOW remote button"); - lambda: |-
- script.execute: remote_pairing_timeout id(remote_pairing_status).publish_state("Disabled");
ESP_LOGW("espnow_remote", "ESP-NOW is disabled; turn on the ESP-NOW switch before pairing");
else:
- lambda: |-
id(remote_pairing) = true;
id(remote_pair_deadline) = millis() + 60000;
id(remote_pairing_status).publish_state("Pairing for 60 seconds");
ESP_LOGI("espnow_remote", "Pairing enabled for 60 seconds; press a ESP-NOW remote button");
- script.execute: remote_pairing_timeout
- platform: template - platform: template
name: "Clear ESP-NOW Remote" name: "Clear ESP-NOW Remote"
@@ -483,20 +569,28 @@ button:
then: then:
- if: - if:
condition: condition:
lambda: 'return id(remote_paired);' lambda: 'return !id(espnow_enabled);'
then: then:
- espnow.peer.delete: - lambda: |-
id: espnow_component id(remote_pairing_status).publish_state("Disabled");
address: !lambda |- ESP_LOGW("espnow_remote", "ESP-NOW is disabled; turn on the ESP-NOW switch before clearing the remote");
return id(remote_mac); else:
- lambda: |- - if:
id(remote_mac) = std::array<uint8_t, 6>{0, 0, 0, 0, 0, 0}; condition:
id(remote_paired) = false; lambda: 'return id(remote_paired);'
id(remote_pairing) = false; then:
id(remote_last_seq) = 0xFFFFFFFF; - espnow.peer.delete:
id(remote_paired_text).publish_state("None"); id: espnow_component
id(remote_pairing_status).publish_state("Idle"); address: !lambda |-
ESP_LOGI("espnow_remote", "Cleared paired ESP-NOW remote"); return id(remote_mac);
- lambda: |-
id(remote_mac) = std::array<uint8_t, 6>{0, 0, 0, 0, 0, 0};
id(remote_paired) = false;
id(remote_pairing) = false;
id(remote_last_seq) = 0xFFFFFFFF;
id(remote_paired_text).publish_state("None");
id(remote_pairing_status).publish_state("Idle");
ESP_LOGI("espnow_remote", "Cleared paired ESP-NOW remote");
output: output:
- platform: ledc - platform: ledc
@@ -522,13 +616,13 @@ output:
frequency: 9765 frequency: 9765
pin: GPIO6 pin: GPIO6
min_power: 0 min_power: 0
max_power: 0.9 max_power: 0.95
- platform: ledc - platform: ledc
id: warm_white_output id: warm_white_output
frequency: 9765 frequency: 9765
pin: GPIO7 pin: GPIO7
min_power: 0 min_power: 0
max_power: 0.9 max_power: 0.95
light: light:
- platform: rgbww - platform: rgbww
+132 -38
View File
@@ -10,7 +10,7 @@ substitutions:
# Project Name # Project Name
project_name: "China Athom Technology.Athom 12W RGBCW Bulb" project_name: "China Athom Technology.Athom 12W RGBCW Bulb"
# Projection version denotes the release version of the yaml file, allowing checking of deployed vs latest version # Projection version denotes the release version of the yaml file, allowing checking of deployed vs latest version
project_version: "v3.1.6" project_version: "v3.1.7"
# Restore the light (GPO switch) upon reboot to state: # Restore the light (GPO switch) upon reboot to state:
light_restore_mode: RESTORE_DEFAULT_ON light_restore_mode: RESTORE_DEFAULT_ON
# Define a domain for this device to use. i.e. iot.home.lan (so device will appear as athom-smart-plug-v2.iot.home.lan in DNS/DHCP logs) # Define a domain for this device to use. i.e. iot.home.lan (so device will appear as athom-smart-plug-v2.iot.home.lan in DNS/DHCP logs)
@@ -77,6 +77,11 @@ globals:
restore_value: yes restore_value: yes
initial_value: "false" initial_value: "false"
- id: espnow_enabled
type: bool
restore_value: yes
initial_value: "true"
select: select:
- platform: template - platform: template
name: "Power On State" name: "Power On State"
@@ -134,24 +139,48 @@ esphome:
then: then:
- if: - if:
condition: condition:
lambda: 'return id(remote_paired);' lambda: 'return id(espnow_enabled);'
then: then:
- espnow.peer.add: # ESP-NOW is configured with enable_on_boot: false so that the saved
id: espnow_component # switch state decides whether the stack comes up at all. enable()
address: !lambda |- # must run before any peer.add - add_peer() returns ESP_ERR_ESPNOW_NOT_INIT
return id(remote_mac); # while the component is disabled.
- lambda: |- - lambda: 'id(espnow_component)->enable();'
char mac[18]; - if:
snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X", condition:
id(remote_mac)[0], id(remote_mac)[1], lambda: 'return id(remote_paired);'
id(remote_mac)[2], id(remote_mac)[3], then:
id(remote_mac)[4], id(remote_mac)[5]); - espnow.peer.add:
id(remote_paired_text).publish_state(mac); id: espnow_component
id(remote_pairing_status).publish_state("Paired"); address: !lambda |-
return id(remote_mac);
- lambda: |-
char mac[18];
snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
id(remote_mac)[0], id(remote_mac)[1],
id(remote_mac)[2], id(remote_mac)[3],
id(remote_mac)[4], id(remote_mac)[5]);
id(remote_paired_text).publish_state(mac);
id(remote_pairing_status).publish_state("Paired");
else:
- lambda: |-
id(remote_paired_text).publish_state("None");
id(remote_pairing_status).publish_state("Idle");
else: else:
# ESP-NOW switched off: leave the stack down, but still surface the
# retained pairing so the user can see it is remembered.
- lambda: |- - lambda: |-
id(remote_paired_text).publish_state("None"); if (id(remote_paired)) {
id(remote_pairing_status).publish_state("Idle"); char mac[18];
snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
id(remote_mac)[0], id(remote_mac)[1],
id(remote_mac)[2], id(remote_mac)[3],
id(remote_mac)[4], id(remote_mac)[5]);
id(remote_paired_text).publish_state(mac);
} else {
id(remote_paired_text).publish_state("None");
}
id(remote_pairing_status).publish_state("Disabled");
- if: - if:
condition: condition:
and: and:
@@ -255,7 +284,9 @@ esp32_improv:
espnow: espnow:
id: espnow_component id: espnow_component
auto_add_peer: false auto_add_peer: false
enable_on_boot: true # Startup is driven by the "ESP-NOW" switch via the on_boot automation above,
# so the stack is never brought up only to be torn down again.
enable_on_boot: false
on_unknown_peer: on_unknown_peer:
- lambda: |- - lambda: |-
const char *const TAG = "espnow_remote"; const char *const TAG = "espnow_remote";
@@ -410,6 +441,53 @@ switch:
- esp32_ble_tracker.stop_scan: - esp32_ble_tracker.stop_scan:
- lambda: 'ESP_LOGI("bluetooth_proxy_switch", "Bluetooth proxy scanning disabled");' - lambda: 'ESP_LOGI("bluetooth_proxy_switch", "Bluetooth proxy scanning disabled");'
- platform: template
name: "ESP-NOW"
id: espnow_switch
icon: mdi:remote
entity_category: config
restore_mode: DISABLED
lambda: 'return id(espnow_enabled);'
turn_on_action:
- globals.set:
id: espnow_enabled
value: "true"
# enable() first: add_peer() is rejected with ESP_ERR_ESPNOW_NOT_INIT while disabled.
- lambda: 'id(espnow_component)->enable();'
- if:
condition:
lambda: 'return id(remote_paired);'
then:
- espnow.peer.add:
id: espnow_component
address: !lambda |-
return id(remote_mac);
- lambda: 'id(remote_pairing_status).publish_state("Paired");'
else:
- lambda: 'id(remote_pairing_status).publish_state("Idle");'
- lambda: 'ESP_LOGI("espnow_remote", "ESP-NOW enabled");'
turn_off_action:
- globals.set:
id: espnow_enabled
value: "false"
# Close any open pairing window so it cannot fire once ESP-NOW comes back.
- lambda: 'id(remote_pairing) = false;'
# Drop the peer while the stack is still up (del_peer() is rejected once disabled).
# The pairing itself lives in remote_mac/remote_paired and is retained, so turning
# the switch back on re-adds the same remote without re-pairing.
- if:
condition:
lambda: 'return id(remote_paired);'
then:
- espnow.peer.delete:
id: espnow_component
address: !lambda |-
return id(remote_mac);
- lambda: |-
id(espnow_component)->disable();
id(remote_pairing_status).publish_state("Disabled");
ESP_LOGI("espnow_remote", "ESP-NOW disabled");
binary_sensor: binary_sensor:
- platform: status - platform: status
name: "Status" name: "Status"
@@ -468,12 +546,20 @@ button:
entity_category: config entity_category: config
on_press: on_press:
then: then:
- lambda: |- - if:
id(remote_pairing) = true; condition:
id(remote_pair_deadline) = millis() + 60000; lambda: 'return !id(espnow_enabled);'
id(remote_pairing_status).publish_state("Pairing for 60 seconds"); then:
ESP_LOGI("espnow_remote", "Pairing enabled for 60 seconds; press a ESP-NOW remote button"); - lambda: |-
- script.execute: remote_pairing_timeout id(remote_pairing_status).publish_state("Disabled");
ESP_LOGW("espnow_remote", "ESP-NOW is disabled; turn on the ESP-NOW switch before pairing");
else:
- lambda: |-
id(remote_pairing) = true;
id(remote_pair_deadline) = millis() + 60000;
id(remote_pairing_status).publish_state("Pairing for 60 seconds");
ESP_LOGI("espnow_remote", "Pairing enabled for 60 seconds; press a ESP-NOW remote button");
- script.execute: remote_pairing_timeout
- platform: template - platform: template
name: "Clear ESP-NOW Remote" name: "Clear ESP-NOW Remote"
@@ -483,20 +569,28 @@ button:
then: then:
- if: - if:
condition: condition:
lambda: 'return id(remote_paired);' lambda: 'return !id(espnow_enabled);'
then: then:
- espnow.peer.delete: - lambda: |-
id: espnow_component id(remote_pairing_status).publish_state("Disabled");
address: !lambda |- ESP_LOGW("espnow_remote", "ESP-NOW is disabled; turn on the ESP-NOW switch before clearing the remote");
return id(remote_mac); else:
- lambda: |- - if:
id(remote_mac) = std::array<uint8_t, 6>{0, 0, 0, 0, 0, 0}; condition:
id(remote_paired) = false; lambda: 'return id(remote_paired);'
id(remote_pairing) = false; then:
id(remote_last_seq) = 0xFFFFFFFF; - espnow.peer.delete:
id(remote_paired_text).publish_state("None"); id: espnow_component
id(remote_pairing_status).publish_state("Idle"); address: !lambda |-
ESP_LOGI("espnow_remote", "Cleared paired ESP-NOW remote"); return id(remote_mac);
- lambda: |-
id(remote_mac) = std::array<uint8_t, 6>{0, 0, 0, 0, 0, 0};
id(remote_paired) = false;
id(remote_pairing) = false;
id(remote_last_seq) = 0xFFFFFFFF;
id(remote_paired_text).publish_state("None");
id(remote_pairing_status).publish_state("Idle");
ESP_LOGI("espnow_remote", "Cleared paired ESP-NOW remote");
output: output:
- platform: ledc - platform: ledc
@@ -522,13 +616,13 @@ output:
frequency: 9765 frequency: 9765
pin: GPIO3 pin: GPIO3
min_power: 0 min_power: 0
max_power: 0.9 max_power: 0.95
- platform: ledc - platform: ledc
id: warm_white_output id: warm_white_output
frequency: 9765 frequency: 9765
pin: GPIO4 pin: GPIO4
min_power: 0 min_power: 0
max_power: 0.9 max_power: 0.95
light: light:
- platform: rgbww - platform: rgbww