1
0
mirror of https://github.com/esphome/esphome.git synced 2025-02-01 02:31:00 +00:00

implement set channel possiblity

remove peer_id over the use of globals.
This commit is contained in:
NP v/d Spek 2024-11-26 22:31:52 +01:00
parent 7534e39cc4
commit 3250125e21
6 changed files with 91 additions and 133 deletions

View File

@ -1,5 +1,6 @@
from esphome import automation, core from esphome import automation, core
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components.globals import GlobalsComponent
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_COMMAND, CONF_COMMAND,
@ -7,7 +8,9 @@ from esphome.const import (
CONF_MAC_ADDRESS, CONF_MAC_ADDRESS,
CONF_PAYLOAD, CONF_PAYLOAD,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_WIFI,
) )
import esphome.final_validate as fv
CODEOWNERS = ["@nielsnl68", "@jesserockz"] CODEOWNERS = ["@nielsnl68", "@jesserockz"]
@ -18,7 +21,7 @@ ESPNowProtocol = espnow_ns.class_("ESPNowProtocol")
ESPNowListener = espnow_ns.class_("ESPNowListener") ESPNowListener = espnow_ns.class_("ESPNowListener")
ESPNowPacket = espnow_ns.class_("ESPNowPacket") ESPNowPacket = espnow_ns.class_("ESPNowPacket")
ESPNowPeer = cg.uint64 ESPNowPeer = GlobalsComponent
ESPNowPacketConst = ESPNowPacket.operator("const") ESPNowPacketConst = ESPNowPacket.operator("const")
@ -41,7 +44,7 @@ SendAction = espnow_ns.class_("SendAction", automation.Action)
NewPeerAction = espnow_ns.class_("NewPeerAction", automation.Action) NewPeerAction = espnow_ns.class_("NewPeerAction", automation.Action)
DelPeerAction = espnow_ns.class_("DelPeerAction", automation.Action) DelPeerAction = espnow_ns.class_("DelPeerAction", automation.Action)
SetKeeperAction = espnow_ns.class_("SetKeeperAction", automation.Action) SetKeeperAction = espnow_ns.class_("SetKeeperAction", automation.Action)
SetStaticPeerAction = espnow_ns.class_("SetStaticPeerAction", automation.Action) SetChannelAction = espnow_ns.class_("SetChannelAction", automation.Action)
CONF_AUTO_ADD_PEER = "auto_add_peer" CONF_AUTO_ADD_PEER = "auto_add_peer"
CONF_CONFORMATION_TIMEOUT = "conformation_timeout" CONF_CONFORMATION_TIMEOUT = "conformation_timeout"
@ -59,6 +62,7 @@ CONF_WIFI_CHANNEL = "wifi_channel"
CONF_PROTOCOL_MODE = "protocol_mode" CONF_PROTOCOL_MODE = "protocol_mode"
validate_command = cv.Range(min=1, max=250) validate_command = cv.Range(min=1, max=250)
validate_channel = cv.int_range(1, 14)
ESPNowProtocolMode = espnow_ns.enum("ESPNowProtocolMode") ESPNowProtocolMode = espnow_ns.enum("ESPNowProtocolMode")
ENUM_MODE = { ENUM_MODE = {
@ -86,9 +90,8 @@ def espnow_hex(mac_address):
DEFINE_PEER_CONFIG = cv.maybe_simple_value( DEFINE_PEER_CONFIG = cv.maybe_simple_value(
{ {
cv.Optional(CONF_PEER_ID): cv.declare_id(ESPNowPeer),
cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
cv.Optional(CONF_WIFI_CHANNEL): cv.int_range(0, 14), cv.Optional(CONF_WIFI_CHANNEL): validate_channel,
}, },
key=CONF_MAC_ADDRESS, key=CONF_MAC_ADDRESS,
) )
@ -97,7 +100,7 @@ DEFINE_PEER_CONFIG = cv.maybe_simple_value(
CONFIG_SCHEMA = cv.Schema( CONFIG_SCHEMA = cv.Schema(
{ {
cv.GenerateID(): cv.declare_id(ESPNowComponent), cv.GenerateID(): cv.declare_id(ESPNowComponent),
cv.Optional(CONF_WIFI_CHANNEL): cv.int_range(0, 14), cv.Optional(CONF_WIFI_CHANNEL): validate_channel,
cv.Optional(CONF_AUTO_ADD_PEER, default=False): cv.boolean, cv.Optional(CONF_AUTO_ADD_PEER, default=False): cv.boolean,
cv.Optional(CONF_USE_SENT_CHECK, default=True): cv.boolean, cv.Optional(CONF_USE_SENT_CHECK, default=True): cv.boolean,
cv.Optional( cv.Optional(
@ -211,6 +214,25 @@ async def register_protocol(var, config):
cg.add(var.set_protocol_mode(config[CONF_PROTOCOL_MODE])) cg.add(var.set_protocol_mode(config[CONF_PROTOCOL_MODE]))
def _final_validate(config):
full_config = fv.full_config.get()
if CONF_WIFI_CHANNEL in config and CONF_WIFI in full_config:
raise cv.Invalid(
f"When you have {CONF_WIFI} configured, You can not set the {CONF_WIFI_CHANNEL} variable."
)
if CONF_WIFI_CHANNEL not in config and CONF_WIFI not in full_config:
raise cv.Invalid(
f"When you don't use the {CONF_WIFI} component, You need to set the {CONF_WIFI_CHANNEL} variable."
)
return config
FINAL_VALIDATE_SCHEMA = _final_validate
# ========================================== A C T I O N S ================================================
def validate_peer(value): def validate_peer(value):
if isinstance(value, cv.Lambda): if isinstance(value, cv.Lambda):
return cv.returning_lambda(value) return cv.returning_lambda(value)
@ -282,7 +304,7 @@ async def send_action(config, action_id, template_arg, args):
{ {
cv.GenerateID(): cv.use_id(ESPNowComponent), cv.GenerateID(): cv.use_id(ESPNowComponent),
cv.Required(CONF_MAC_ADDRESS): validate_peer, cv.Required(CONF_MAC_ADDRESS): validate_peer,
cv.Optional(CONF_WIFI_CHANNEL): cv.int_range(0, 14), cv.Optional(CONF_WIFI_CHANNEL): cv.templatable(validate_channel),
}, },
key=CONF_MAC_ADDRESS, key=CONF_MAC_ADDRESS,
), ),
@ -298,26 +320,32 @@ async def send_action(config, action_id, template_arg, args):
key=CONF_MAC_ADDRESS, key=CONF_MAC_ADDRESS,
), ),
) )
@automation.register_action(
"espnow.static.peer",
SetStaticPeerAction,
cv.Schema(
{
cv.GenerateID(): cv.use_id(ESPNowComponent),
cv.Required(CONF_PEER_ID): cv.use_id(ESPNowPeer),
cv.Required(CONF_MAC_ADDRESS): validate_peer,
}
),
)
async def peer_action(config, action_id, template_arg, args): async def peer_action(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg) var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID]) await cg.register_parented(var, config[CONF_ID])
if peer_id := config.get(CONF_PEER_ID):
peer = await cg.get_variable(peer_id)
cg.add(var.set_peer_id(peer))
if CONF_WIFI_CHANNEL in config: if CONF_WIFI_CHANNEL in config:
cg.add(var.set_wifi_channel(config[CONF_WIFI_CHANNEL])) template_ = await cg.templatable(config[CONF_WIFI_CHANNEL], args, cg.uint8)
cg.add(var.set_wifi_channel(template_))
await register_peer(var, config, args) await register_peer(var, config, args)
return var return var
@automation.register_action(
"espnow.channel.set",
SetChannelAction,
cv.maybe_simple_value(
{
cv.GenerateID(): cv.use_id(ESPNowComponent),
cv.Required(CONF_WIFI_CHANNEL): cv.templatable(validate_channel),
},
key=CONF_WIFI_CHANNEL,
),
)
async def channel_action(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
template_ = await cg.templatable(config[CONF_WIFI_CHANNEL], args, cg.uint8)
cg.add(var.set_channel(template_))
return var

View File

@ -266,8 +266,8 @@ void ESPNowComponent::set_wifi_channel(uint8_t channel) {
ESPNowPacket packet(ESPNOW_MASS_SEND_ADDR, &channel, 1, ESPNOW_MAIN_PROTOCOL_ID, 251); ESPNowPacket packet(ESPNOW_MASS_SEND_ADDR, &channel, 1, ESPNOW_MAIN_PROTOCOL_ID, 251);
this->send(packet); this->send(packet);
ESP_LOGD(TAG, "Wifi Channel is changed from %d to %d.", this->wifi_channel_, channel); ESP_LOGD(TAG, "Wifi Channel is changed from %d to %d.", this->wifi_channel_, channel);
this->wifi_channel_ = channel;
} }
this->wifi_channel_ = channel;
} }
esp_err_t ESPNowComponent::add_peer(uint64_t peer, int8_t channel) { esp_err_t ESPNowComponent::add_peer(uint64_t peer, int8_t channel) {
@ -276,6 +276,11 @@ esp_err_t ESPNowComponent::add_peer(uint64_t peer, int8_t channel) {
esp_now_peer_info_t peer_info = {}; esp_now_peer_info_t peer_info = {};
if (this->is_ready()) { if (this->is_ready()) {
if (peer == this->own_peer_address_) {
ESP_LOGE(TAG, "Tried to peer your self.");
this->mark_failed();
return ESP_ERR_INVALID_MAC;
}
if (esp_now_is_peer_exist((uint8_t *) &peer)) { if (esp_now_is_peer_exist((uint8_t *) &peer)) {
esp_now_get_peer((const uint8_t *) &peer, &peer_info); esp_now_get_peer((const uint8_t *) &peer, &peer_info);
old_channel = peer_info.channel; old_channel = peer_info.channel;
@ -444,8 +449,7 @@ void ESPNowComponent::handle_internal_commands(ESPNowPacket packet) {
case 251: case 251:
channel = (int8_t) *packet.get_payload(); channel = (int8_t) *packet.get_payload();
this->add_peer(packet.peer, channel); this->add_peer(packet.peer, channel);
ESP_LOGI(TAG, "The channel for peer %s. is changed toCommand not used: %d.", packet.get_peer_code().c_str(), ESP_LOGI(TAG, "The channel for peer %s is changed to: %d.", packet.get_peer_code().c_str(), channel);
channel);
break; break;
default: default:
ESP_LOGE(TAG, "Invalid internal ESP-NOW packet. Command not used: %d.", packet.get_command()); ESP_LOGE(TAG, "Invalid internal ESP-NOW packet. Command not used: %d.", packet.get_command());
@ -453,7 +457,9 @@ void ESPNowComponent::handle_internal_commands(ESPNowPacket packet) {
} }
bool ESPNowComponent::send(ESPNowPacket packet) { bool ESPNowComponent::send(ESPNowPacket packet) {
if (!this->is_ready()) { if (packet.peer == this->own_peer_address_) {
ESP_LOGE(TAG, "Tried to peer your self.");
} else if (!this->is_ready()) {
ESP_LOGE(TAG, "Cannot send espnow packet, espnow is not setup yet."); ESP_LOGE(TAG, "Cannot send espnow packet, espnow is not setup yet.");
} else if (this->is_failed()) { } else if (this->is_failed()) {
ESP_LOGE(TAG, "Cannot send espnow packet, espnow failed to setup"); ESP_LOGE(TAG, "Cannot send espnow packet, espnow failed to setup");
@ -482,7 +488,7 @@ bool ESPNowComponent::send(ESPNowPacket packet) {
this->call_on_sent_(packet, err == ESP_OK); this->call_on_sent_(packet, err == ESP_OK);
return true; return true;
} }
this->mark_failed();
return false; return false;
} }
@ -518,7 +524,7 @@ bool ESPNowProtocol::send(uint64_t peer, const uint8_t *data, uint8_t len, uint8
return this->parent_->send(packet); return this->parent_->send(packet);
} }
const char *const ChangeChannel::TAG = "espnow.changechannel"; const char *const SetChannel::TAG = "espnow.changechannel";
} // namespace espnow } // namespace espnow
} // namespace esphome } // namespace esphome

View File

@ -340,33 +340,18 @@ template<typename... Ts> class DelPeerAction : public Action<Ts...>, public Pare
} }
}; };
template<typename... Ts> class SetStaticPeerAction : public Action<Ts...>, public Parented<ESPNowComponent> { class SetChannel {
public:
TEMPLATABLE_VALUE(uint64_t, mac_address);
void set_peer_id(uint64_t &peer_id) { this->peer_id_ = &peer_id; }
void play(Ts... x) override {
uint64_t mac_address = this->mac_address_.value(x...);
*(this->peer_id_) = mac_address;
if (mac_address != 0)
parent_->add_peer(mac_address);
}
protected:
uint64_t *peer_id_;
};
class ChangeChannel {
public: public:
// could be made inline with C++17 // could be made inline with C++17
static const char *const TAG; static const char *const TAG;
}; };
template<typename... Ts> class ChangeChannelAction : public Action<Ts...>, public Parented<ESPNowComponent> { template<typename... Ts> class SetChannelAction : public Action<Ts...>, public Parented<ESPNowComponent> {
public: public:
TEMPLATABLE_VALUE(int8_t, channel); TEMPLATABLE_VALUE(int8_t, channel);
void play(Ts... x) override { void play(Ts... x) override {
#ifdef USE_WIFI #ifdef USE_WIFI
esph_log_e(ChangeChannel::TAG, "Manual changing the channel is not possible with WIFI enabled."); esph_log_e(SetChannel::TAG, "Manual changing the channel is not possible with WIFI enabled.");
#else #else
int8_t value = this->channel_.value(x...); int8_t value = this->channel_.value(x...);
parent_->set_wifi_channel(value); parent_->set_wifi_channel(value);
@ -374,7 +359,7 @@ template<typename... Ts> class ChangeChannelAction : public Action<Ts...>, publi
} }
}; };
/********************************* triggers **************************************/ /********************************* triggers **************************************/
class ESPNowSentTrigger : public Trigger<const ESPNowPacket, bool> { class ESPNowSentTrigger : public Trigger<const ESPNowPacket, bool> {
public: public:
explicit ESPNowSentTrigger(ESPNowComponent *parent) { explicit ESPNowSentTrigger(ESPNowComponent *parent) {

View File

@ -12,29 +12,19 @@ esp32:
esphome: esphome:
name: "${name}" name: "${name}"
# Friendly names are used where appropriate in Home Assistant
friendly_name: "${friendly_name}"
# Automatically add the mac address to the name
# so you can use a single firmware for all devices
name_add_mac_suffix: false
# This will allow for (future) project identification,
# configuration and updates.
project:
name: LumenSoft.espnow-test
version: "1.0"
# To be able to get logs from the device via serial and api. # To be able to get logs from the device via serial and api.
logger: logger:
level: verbose level: debug
espnow: espnow:
auto_add_peer: true auto_add_peer: true
wifi_channel: 1
predefined_peers: predefined_peers:
- mac_address: 11:22:33:44:55:66 - mac_address: E8:6B:EA:23:CD:98
on_receive: on_receive:
- logger.log: - logger.log:
format: "Received: '%s' from '%s' command: %d RSSI: %d" format: "Received from: %s = '%s' cmd: %d RSSI: %d"
args: args:
[ [
packet.get_payload(), packet.get_payload(),
@ -43,15 +33,11 @@ espnow:
packet.rssi, packet.rssi,
] ]
# this works only when esp_idf v5.1.5+ is being used. interval:
on_broadcast: - interval: 10sec
- command: 123 startup_delay: 20sec
then: then:
- logger.log: - espnow.send:
format: "Broadcast from: '%s' RSSI: %d: %s" mac_address: E8:6B:EA:23:CD:98
args: payload: "Test 1."
[ command: 222
packet.get_peer_code().c_str(),
packet.rssi,
packet.get_payload(),
]

View File

@ -26,23 +26,22 @@ esphome:
# To be able to get logs from the device via serial and api. # To be able to get logs from the device via serial and api.
logger: logger:
level: verbose level: debug
globals: globals:
- id: hub_address - id: hub_address
type: uint64_t type: uint64_t
initial_value: "0xE86BEA23CD98" initial_value: "0x0"
restore_value: yes restore_value: yes
espnow: espnow:
auto_add_peer: true auto_add_peer: true
wifi_channel: 1
predefined_peers: predefined_peers:
- peer_id: keeper - mac_address: e8:6b:ea:24:22:04
mac_address: E8:6B:EA:23:CD:98
on_receive: on_receive:
- logger.log: - logger.log:
format: "Received: '%s' from '%s' command: %d RSSI: %d" format: "Received from: %s = '%s' cmd: %d RSSI: %d"
args: args:
[ [
packet.get_payload(), packet.get_payload(),
@ -51,52 +50,15 @@ espnow:
packet.rssi, packet.rssi,
] ]
on_broadcast:
- command: 123
then:
- logger.log:
format: "Broadcast Received from: '%s' RSSI: %d: %s"
args:
[
packet.get_peer_code().c_str(),
packet.rssi,
packet.get_payload(),
]
interval: interval:
- interval: 30sec - interval: 30sec
startup_delay: 20sec startup_delay: 10sec
then: then:
- espnow.broadcast: - espnow.channel.set: 5
payload: "Broadcast message"
command: 123
- interval: 5sec - interval: 5sec
startup_delay: 10sec
then: then:
- espnow.send: - espnow.send:
mac_address: keeper mac_address: e8:6b:ea:24:22:04
payload: "Used static keeper value" payload: "Test 2."
command: 222
- espnow.send:
mac_address: E8:6B:EA:23:CD:98
payload: "used fixed mac address"
command: 123 command: 123
- espnow.send:
# dynamic peer address
mac_address: !lambda return keeper;
payload: "use keeper dynamicly "
command: 62
- espnow.send:
mac_address: !lambda return id(hub_address);
payload: "Using a global numberic value dynamicly"
command: 132
binary_sensor:
- platform: gpio
pin: GPIO39
name: Button
on_click:
- espnow.static.peer:
peer_id: keeper
mac_address: 80:6B:EA:23:CD:87
- espnow.peer.add: 80:6B:EA:23:AA:BB
- espnow.peer.del: 80:6B:EA:23:AA:BB

View File

@ -1,5 +1,5 @@
globals: globals:
- id: hub_address - id: keeper
type: uint64_t type: uint64_t
initial_value: "0xE86BEA23CD98" initial_value: "0xE86BEA23CD98"
restore_value: yes restore_value: yes
@ -8,8 +8,7 @@ espnow:
auto_add_peer: true auto_add_peer: true
predefined_peers: predefined_peers:
- FF:FF:FF:FF:FF:FF - FF:FF:FF:FF:FF:FF
- peer_id: keeper - mac_address: 11:22:33:44:55:66
mac_address: 11:22:33:44:55:66
wifi_channel: 2 wifi_channel: 2
on_receive: on_receive:
- logger.log: - logger.log:
@ -40,21 +39,13 @@ interval:
- espnow.broadcast: - espnow.broadcast:
payload: "hallo everyone" payload: "hallo everyone"
command: 123 command: 123
- espnow.send:
mac_address: keeper
payload: "hallo everyone"
command: 230
- espnow.send: - espnow.send:
mac_address: 44:55:66:77:88:33 mac_address: 44:55:66:77:88:33
payload: "hallo everyone" payload: "hallo everyone"
command: 230 command: 230
- espnow.send: - espnow.send:
# dynamic peer address mac_address: !lambda return id(keeper);
mac_address: !lambda return keeper;
payload: "use keeper dynamicly "
command: 62
- espnow.send:
mac_address: !lambda return id(hub_address);
payload: "Using a global numberic value dynamicly" payload: "Using a global numberic value dynamicly"
command: 132 command: 132