mirror of
https://github.com/esphome/esphome.git
synced 2024-11-30 10:44:13 +01:00
-add option to set a global keeper to be used withe the espnow.send action. peer= keeper
- the keeper is templatable. - introduce protocol modes Keeper, drudge and universal - revert back event call's - add get)iwb_peer_address() - prepare for pairing protocol
This commit is contained in:
parent
342a20a48e
commit
535c8dd70f
5 changed files with 356 additions and 126 deletions
|
@ -8,6 +8,8 @@ CODEOWNERS = ["@nielsnl68", "@jesserockz"]
|
|||
|
||||
espnow_ns = cg.esphome_ns.namespace("espnow")
|
||||
ESPNowComponent = espnow_ns.class_("ESPNowComponent", cg.Component)
|
||||
ESPNowProtocol = espnow_ns.class_("ESPNowProtocol")
|
||||
|
||||
ESPNowListener = espnow_ns.class_("ESPNowListener")
|
||||
|
||||
ESPNowPacket = espnow_ns.class_("ESPNowPacket")
|
||||
|
@ -46,10 +48,20 @@ CONF_PEER = "peer"
|
|||
CONF_PEERS = "peers"
|
||||
CONF_USE_SENT_CHECK = "use_sent_check"
|
||||
CONF_WIFI_CHANNEL = "wifi_channel"
|
||||
|
||||
CONF_PROTOCOL_MODE = "protocol_mode"
|
||||
CONF_KEEPER = "keeper"
|
||||
|
||||
CONF_MAC_CHARS = "0123456789-AbCdEfGhIjKlMnOpQrStUvWxYz+aBcDeFgHiJkLmNoPqRsTuVwXyZ"
|
||||
|
||||
validate_command = cv.Range(min=1, max=250)
|
||||
|
||||
ESPNowProtocol_mode = espnow_ns.enum("ESPNowProtocol_mode")
|
||||
ENUM_MODE = {
|
||||
"universal": ESPNowProtocol_mode.universal,
|
||||
"keeper": ESPNowProtocol_mode.keeper,
|
||||
"drudge": ESPNowProtocol_mode.drudge,
|
||||
}
|
||||
|
||||
|
||||
def validate_raw_data(value):
|
||||
if isinstance(value, str):
|
||||
|
@ -83,15 +95,18 @@ def validate_peer(value):
|
|||
if isinstance(value, (int)):
|
||||
return value
|
||||
|
||||
value = cv.string_strict(value)
|
||||
|
||||
if value.lower() == CONF_KEEPER:
|
||||
return 0x0
|
||||
|
||||
if value.find(":") != -1:
|
||||
return convert_mac_address(value)
|
||||
|
||||
if len(value) == 8:
|
||||
value = cv.string_strict(value)
|
||||
|
||||
mac = 0
|
||||
for x in value:
|
||||
n = CONF_MAC_CHARS.find(x)
|
||||
for x in range(8, 0, -1):
|
||||
n = CONF_MAC_CHARS.find(value[x - 1])
|
||||
if n == -1:
|
||||
raise cv.Invalid(f"peer code is invalid. ({value}|{x})")
|
||||
mac = (mac << 6) + n
|
||||
|
@ -112,28 +127,29 @@ CONFIG_SCHEMA = cv.Schema(
|
|||
CONF_CONFORMATION_TIMEOUT, default="5000ms"
|
||||
): cv.positive_time_period_milliseconds,
|
||||
cv.Optional(CONF_RETRIES, default=5): cv.int_range(min=1, max=10),
|
||||
cv.Optional(CONF_KEEPER): cv.templatable(validate_peer),
|
||||
cv.Optional(CONF_ON_RECEIVE): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowReceiveTrigger),
|
||||
cv.Optional(CONF_COMMAND): cv.Range(min=16, max=255),
|
||||
cv.Optional(CONF_COMMAND): validate_command,
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_BROADCAST): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowBroadcaseTrigger),
|
||||
cv.Optional(CONF_COMMAND): cv.Range(min=0, max=255),
|
||||
cv.Optional(CONF_COMMAND): validate_command,
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_SENT): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowSentTrigger),
|
||||
cv.Optional(CONF_COMMAND): cv.Range(min=0, max=255),
|
||||
cv.Optional(CONF_COMMAND): validate_command,
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_NEW_PEER): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowNewPeerTrigger),
|
||||
cv.Optional(CONF_COMMAND): cv.Range(min=16, max=255),
|
||||
cv.Optional(CONF_COMMAND): validate_command,
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_PEERS): cv.ensure_list(validate_peer),
|
||||
|
@ -157,6 +173,10 @@ async def to_code(config):
|
|||
cg.add(var.set_conformation_timeout(config[CONF_CONFORMATION_TIMEOUT]))
|
||||
cg.add(var.set_retries(config[CONF_RETRIES]))
|
||||
|
||||
if CONF_KEEPER in config:
|
||||
template_ = await cg.templatable(config[CONF_KEEPER], [], cg.uint64)
|
||||
cg.add(var.set_keeper(template_))
|
||||
|
||||
for conf in config.get(CONF_PEERS, []):
|
||||
cg.add(var.add_peer(conf))
|
||||
|
||||
|
@ -198,24 +218,27 @@ async def to_code(config):
|
|||
PROTOCOL_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_ESPNOW): cv.use_id(ESPNowComponent),
|
||||
cv.Optional(CONF_PROTOCOL_MODE): cv.enum(ENUM_MODE, string=True),
|
||||
},
|
||||
cv.only_on_esp32,
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
)
|
||||
|
||||
|
||||
async def register_protocol(var, config):
|
||||
now = await cg.get_variable(config[CONF_ESPNOW])
|
||||
cg.add(now.register_protocol(var))
|
||||
if config[CONF_PROTOCOL_MODE]:
|
||||
cg.add(var.set_protocol_mode(config[CONF_PROTOCOL_MODE]))
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"espnow.broatcast",
|
||||
"espnow.broadcast",
|
||||
SendAction,
|
||||
cv.maybe_simple_value(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(ESPNowComponent),
|
||||
cv.Required(CONF_PAYLOAD): cv.templatable(validate_raw_data),
|
||||
cv.Optional(CONF_COMMAND): cv.templatable(cv.Range(min=16, max=255)),
|
||||
cv.Optional(CONF_COMMAND): cv.templatable(validate_command),
|
||||
},
|
||||
key=CONF_PAYLOAD,
|
||||
),
|
||||
|
@ -228,9 +251,7 @@ async def register_protocol(var, config):
|
|||
cv.GenerateID(): cv.use_id(ESPNowComponent),
|
||||
cv.Required(CONF_PEER): cv.templatable(validate_peer),
|
||||
cv.Required(CONF_PAYLOAD): cv.templatable(validate_raw_data),
|
||||
cv.Optional(CONF_COMMAND, default=0): cv.templatable(
|
||||
cv.Range(min=0, max=255)
|
||||
),
|
||||
cv.Optional(CONF_COMMAND): cv.templatable(validate_command),
|
||||
}
|
||||
),
|
||||
)
|
||||
|
|
|
@ -30,11 +30,13 @@ static const size_t SEND_BUFFER_SIZE = 200;
|
|||
ESPNowComponent *ESPNowComponent::static_{nullptr}; // NOLINT
|
||||
|
||||
std::string espnow_encode_peer(uint64_t peer) {
|
||||
std::string str1 = "";
|
||||
if (peer == FAILED) {
|
||||
return "[Not Set]";
|
||||
} else if (peer == ESPNOW_BROADCAST_ADDR)
|
||||
return "[BroadCast]";
|
||||
|
||||
std::string str1 = "";
|
||||
str1.reserve(8);
|
||||
do {
|
||||
str1.push_back(chars[peer & 63]); // Add on the left
|
||||
peer = peer >> 6;
|
||||
|
@ -63,10 +65,10 @@ ESPNowComponent::ESPNowComponent() { ESPNowComponent::static_ = this; } // NOLI
|
|||
void ESPNowComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "esp_now:");
|
||||
|
||||
ESP_LOGCONFIG(TAG, " Own Peer Address: %s.", espnow_encode_peer(this->own_peer_address_).c_str());
|
||||
ESP_LOGCONFIG(TAG, " Own Peer code: %s.", espnow_encode_peer(this->own_peer_address_).c_str());
|
||||
ESP_LOGCONFIG(TAG, " Keeper Peer code: %s.", espnow_encode_peer(this->get_keeper()).c_str());
|
||||
ESP_LOGCONFIG(TAG, " Wifi channel: %d.", this->wifi_channel_);
|
||||
ESP_LOGCONFIG(TAG, " Auto add new peers: %s.", this->auto_add_peer_ ? "Yes" : "No");
|
||||
|
||||
ESP_LOGCONFIG(TAG, " Use sent status: %s.", this->use_sent_check_ ? "Yes" : "No");
|
||||
ESP_LOGCONFIG(TAG, " Convermation timeout: %" PRIx32 "ms.", this->conformation_timeout_);
|
||||
ESP_LOGCONFIG(TAG, " Send retries: %d.", this->retries_);
|
||||
|
@ -142,7 +144,10 @@ void ESPNowComponent::setup() {
|
|||
esp_wifi_get_mac(WIFI_IF_STA, (uint8_t *) &this->own_peer_address_);
|
||||
|
||||
for (auto id : this->peers_) {
|
||||
add_peer(id);
|
||||
this->add_peer(id);
|
||||
}
|
||||
if (this->get_keeper() != 0) {
|
||||
this->add_peer(this->get_keeper());
|
||||
}
|
||||
|
||||
this->send_queue_ = xQueueCreate(SEND_BUFFER_SIZE, sizeof(ESPNowPacket));
|
||||
|
@ -172,16 +177,16 @@ void ESPNowComponent::espnow_task(void *param) {
|
|||
ESPNowPacket packet; // NOLINT
|
||||
for (;;) {
|
||||
if (xQueueReceive(this_espnow->receive_queue_, (void *) &packet, (TickType_t) 1) == pdTRUE) {
|
||||
uint8_t *mac = packet.get_peer();
|
||||
if (!packet.is_broadcast || !this_espnow->call_on_broadcast_(packet)) {
|
||||
if (!esp_now_is_peer_exist(mac) && !this_espnow->call_on_new_peer_(packet)) {
|
||||
if (this_espnow->auto_add_peer_) {
|
||||
this_espnow->add_peer(packet.peer);
|
||||
if (packet.is_broadcast) {
|
||||
this_espnow->call_on_broadcast_(packet);
|
||||
continue;
|
||||
} else if (!this_espnow->is_paired(packet.peer)) {
|
||||
this_espnow->call_on_new_peer_(packet);
|
||||
}
|
||||
}
|
||||
if (esp_now_is_peer_exist(mac)) {
|
||||
if (this_espnow->is_paired(packet.peer)) {
|
||||
this_espnow->call_on_receive_(packet);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGI(TAG, "message skipt, not paired.");
|
||||
}
|
||||
}
|
||||
if (xQueueReceive(this_espnow->send_queue_, (void *) &packet, (TickType_t) 1) == pdTRUE) {
|
||||
|
@ -218,26 +223,39 @@ void ESPNowComponent::espnow_task(void *param) {
|
|||
}
|
||||
|
||||
esp_err_t ESPNowComponent::add_peer(uint64_t peer) {
|
||||
esp_err_t result = ESP_OK;
|
||||
if (!this->is_ready()) {
|
||||
this->peers_.push_back(peer);
|
||||
return ESP_OK;
|
||||
return result;
|
||||
} else {
|
||||
this->del_peer(peer);
|
||||
if (esp_now_is_peer_exist((uint8_t *) &peer)) {
|
||||
result = esp_now_del_peer((uint8_t *) &peer);
|
||||
if (result != ESP_OK)
|
||||
return result;
|
||||
}
|
||||
|
||||
esp_now_peer_info_t peer_info = {};
|
||||
memset(&peer_info, 0, sizeof(esp_now_peer_info_t));
|
||||
peer_info.channel = this->wifi_channel_;
|
||||
peer_info.encrypt = false;
|
||||
memcpy((void *) peer_info.peer_addr, (void *) &peer, 6);
|
||||
|
||||
return esp_now_add_peer(&peer_info);
|
||||
esp_err_t result = esp_now_add_peer(&peer_info);
|
||||
if (result == ESP_OK) {
|
||||
this->call_on_add_peer_(peer);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t ESPNowComponent::del_peer(uint64_t peer) {
|
||||
if (esp_now_is_peer_exist((uint8_t *) &peer))
|
||||
return esp_now_del_peer((uint8_t *) &peer);
|
||||
return ESP_OK;
|
||||
esp_err_t result = ESP_OK;
|
||||
if (esp_now_is_peer_exist((uint8_t *) &peer)) {
|
||||
esp_err_t result = esp_now_del_peer((uint8_t *) &peer);
|
||||
if (result == ESP_OK) {
|
||||
this->call_on_del_peer_(peer);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ESPNowDefaultProtocol *ESPNowComponent::get_default_protocol() {
|
||||
|
@ -255,36 +273,61 @@ ESPNowProtocol *ESPNowComponent::get_protocol_(uint32_t protocol) {
|
|||
return this->protocols_[protocol];
|
||||
}
|
||||
|
||||
bool ESPNowComponent::call_on_receive_(ESPNowPacket &packet) {
|
||||
void ESPNowComponent::call_on_receive_(ESPNowPacket &packet) {
|
||||
ESPNowProtocol *protocol = this->get_protocol_(packet.get_protocol());
|
||||
if (protocol != nullptr) {
|
||||
return protocol->on_receive(packet);
|
||||
this->defer([protocol, packet]() { protocol->on_receive(packet); });
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ESPNowComponent::call_on_broadcast_(ESPNowPacket &packet) {
|
||||
void ESPNowComponent::call_on_broadcast_(ESPNowPacket &packet) {
|
||||
ESPNowProtocol *protocol = this->get_protocol_(packet.get_protocol());
|
||||
if (protocol != nullptr) {
|
||||
return protocol->on_broadcast(packet);
|
||||
this->defer([protocol, packet]() { protocol->on_broadcast(packet); });
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ESPNowComponent::call_on_sent_(ESPNowPacket &packet, bool status) {
|
||||
void ESPNowComponent::call_on_sent_(ESPNowPacket &packet, bool status) {
|
||||
ESPNowProtocol *protocol = this->get_protocol_(packet.get_protocol());
|
||||
if (protocol != nullptr) {
|
||||
return protocol->on_sent(packet, status);
|
||||
this->defer([protocol, packet, status]() { protocol->on_sent(packet, status); });
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ESPNowComponent::call_on_new_peer_(ESPNowPacket &packet) {
|
||||
void ESPNowComponent::call_on_new_peer_(ESPNowPacket &packet) {
|
||||
ESPNowProtocol *protocol = this->get_protocol_(packet.get_protocol());
|
||||
if (protocol != nullptr) {
|
||||
return protocol->on_new_peer(packet);
|
||||
this->defer([protocol, packet]() { protocol->on_new_peer(packet); });
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ESPNowComponent::call_on_add_peer_(uint64_t peer) {
|
||||
this->defer([this, peer]() {
|
||||
for (const auto &kv : this->protocols_) {
|
||||
kv.second->on_add_peer(peer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ESPNowComponent::call_on_del_peer_(uint64_t peer) {
|
||||
this->defer([this, peer]() {
|
||||
for (const auto &kv : this->protocols_) {
|
||||
kv.second->on_del_peer(peer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool ESPNowComponent::is_paired(uint64_t peer) {
|
||||
bool result = false;
|
||||
if (this->pairing_protocol_ != nullptr) {
|
||||
result = this->pairing_protocol_->is_paired(peer);
|
||||
} else {
|
||||
result = (esp_now_is_peer_exist((uint8_t *) &peer));
|
||||
}
|
||||
if (!result && this->auto_add_peer_) {
|
||||
result = (this->add_peer(peer) == ESP_OK);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**< callback function of receiving ESPNOW data */
|
||||
|
@ -335,7 +378,7 @@ bool ESPNowComponent::send(ESPNowPacket packet) {
|
|||
ESP_LOGE(TAG, "Cannot send espnow packet, espnow failed to setup");
|
||||
} else if (this->send_queue_full()) {
|
||||
ESP_LOGE(TAG, "Send Buffer Out of Memory.");
|
||||
} else if (!esp_now_is_peer_exist(packet.get_peer())) {
|
||||
} else if (!this->is_paired(packet.peer)) {
|
||||
ESP_LOGE(TAG, "Peer not registered: %s.", packet.get_peer_code().c_str());
|
||||
} else if (!packet.is_valid()) {
|
||||
ESP_LOGE(TAG, "This Packet is invalid: %s (%d.%d)", packet.get_peer_code().c_str(), packet.get_sequents(),
|
||||
|
@ -382,6 +425,10 @@ void ESPNowComponent::on_data_sent(const uint8_t *mac_addr, esp_now_send_status_
|
|||
/* ESPNowProtocol ********************************************************************** */
|
||||
|
||||
bool ESPNowProtocol::send(uint64_t peer, const uint8_t *data, uint8_t len, uint8_t command) {
|
||||
if (peer == 0x0) {
|
||||
peer = this->get_keeper();
|
||||
}
|
||||
|
||||
ESPNowPacket packet(peer, data, len, this->get_protocol_id(), command); // NOLINT
|
||||
packet.set_sequents(this->get_next_sequents(packet.peer));
|
||||
return this->parent_->send(packet);
|
||||
|
|
|
@ -15,13 +15,15 @@
|
|||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
#include <random>
|
||||
#include <string>
|
||||
|
||||
namespace esphome {
|
||||
namespace espnow {
|
||||
|
||||
static const uint64_t ESPNOW_BROADCAST_ADDR = 0xFFFFFFFFFFFF;
|
||||
|
||||
static const uint8_t MAX_ESPNOW_DATA_SIZE = 241;
|
||||
static const uint8_t MAX_ESPNOW_DATA_SIZE = 240;
|
||||
|
||||
static const uint8_t TRANSPORT_HEADER[3] = {'N', '0', 'w'};
|
||||
static const uint32_t ESPNOW_MAIN_PROTOCOL_ID = 0x447453; // = StD
|
||||
|
@ -33,6 +35,10 @@ static const uint8_t ESPNOW_COMMAND_RESEND = 0x05;
|
|||
static const char chars[] = "0123456789-AbCdEfGhIjKlMnOpQrStUvWxYz+aBcDeFgHiJkLmNoPqRsTuVwXyZ";
|
||||
static const uint64_t FAILED = 0;
|
||||
|
||||
template<typename T> std::string espnow_i2h(T i) { return sprintf("%04x", i); }
|
||||
|
||||
std::string espnow_rdm(std::string::size_type length);
|
||||
|
||||
std::string espnow_encode_peer(uint64_t peer);
|
||||
uint64_t espnow_decode_peer(std::string peer);
|
||||
|
||||
|
@ -96,9 +102,6 @@ struct ESPNowPacket {
|
|||
uint8_t content_size() const { return (this->prefix_size() + this->size); }
|
||||
|
||||
inline void set_peer(const uint8_t *peer) ESPHOME_ALWAYS_INLINE {
|
||||
if (*peer == 0) {
|
||||
peer = (uint8_t *) &ESPNOW_BROADCAST_ADDR;
|
||||
}
|
||||
memcpy((void *) this->get_peer(), (const void *) peer, 6);
|
||||
};
|
||||
inline bool is_peer(const uint8_t *peer) const { return memcmp(peer, this->get_peer(), 6) == 0; }
|
||||
|
@ -137,33 +140,45 @@ struct ESPNowPacket {
|
|||
|
||||
class ESPNowComponent;
|
||||
|
||||
enum ESPNowProtocol_mode { universal, keeper, drudge };
|
||||
|
||||
class ESPNowProtocol : public Parented<ESPNowComponent> {
|
||||
public:
|
||||
ESPNowProtocol(){};
|
||||
void set_protocol_mode(ESPNowProtocol_mode mode) { this->protocol_mode_ = mode; }
|
||||
ESPNowProtocol_mode get_protocol_mode() { return this->protocol_mode_; }
|
||||
|
||||
virtual bool on_receive(const ESPNowPacket &packet) { return false; };
|
||||
virtual bool on_broadcast(const ESPNowPacket &packet) { return false; };
|
||||
|
||||
virtual bool on_sent(const ESPNowPacket &packet, bool status) { return false; };
|
||||
virtual bool on_new_peer(const ESPNowPacket &packet) { return false; };
|
||||
protected:
|
||||
ESPNowProtocol_mode protocol_mode_{universal};
|
||||
|
||||
public:
|
||||
virtual uint32_t get_protocol_id() = 0;
|
||||
virtual std::string get_protocol_name() = 0;
|
||||
virtual void init_protocol() {}
|
||||
|
||||
uint8_t get_next_sequents() { return this->get_next_sequents(0); }
|
||||
virtual uint8_t get_next_sequents(uint64_t peer) {
|
||||
if (this->next_sequents_ == 255) {
|
||||
this->next_sequents_ = 0;
|
||||
virtual void on_receive(const ESPNowPacket &packet){};
|
||||
virtual void on_broadcast(const ESPNowPacket &packet) { this->on_receive(packet); };
|
||||
|
||||
virtual void on_sent(const ESPNowPacket &packet, bool status){};
|
||||
virtual void on_new_peer(const ESPNowPacket &packet){};
|
||||
|
||||
virtual void on_add_peer(uint64_t peer){};
|
||||
virtual void on_del_peer(uint64_t peer){};
|
||||
|
||||
virtual bool is_paired(uint64_t to_peer) { return true; }
|
||||
|
||||
uint8_t get_next_sequents(uint64_t peer) {
|
||||
if (this->next_sequents_[peer] == 255) {
|
||||
this->next_sequents_[peer] = 0;
|
||||
} else {
|
||||
this->next_sequents_++;
|
||||
this->next_sequents_[peer]++;
|
||||
}
|
||||
return this->next_sequents_;
|
||||
return this->next_sequents_[peer];
|
||||
}
|
||||
|
||||
bool is_valid_squence(uint8_t received_sequence) {
|
||||
bool valid = this->next_sequents_ + 1 == received_sequence;
|
||||
bool is_valid_squence(uint64_t peer, uint8_t received_sequence) {
|
||||
bool valid = this->next_sequents_[peer] + 1 == received_sequence;
|
||||
if (valid) {
|
||||
this->next_sequents_ = received_sequence;
|
||||
this->next_sequents_[peer] = received_sequence;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
@ -171,7 +186,17 @@ class ESPNowProtocol : public Parented<ESPNowComponent> {
|
|||
bool send(uint64_t peer, const uint8_t *data, uint8_t len, uint8_t command = 0);
|
||||
|
||||
protected:
|
||||
uint8_t next_sequents_{255};
|
||||
std::map<uint64_t, uint8_t> next_sequents_{};
|
||||
std::string get_mode_name_() {
|
||||
switch (this->protocol_mode_) {
|
||||
case universal:
|
||||
return "Universal";
|
||||
case keeper:
|
||||
return "Keeper";
|
||||
case drudge:
|
||||
return "Drudge";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ESPNowDefaultProtocol : public ESPNowProtocol {
|
||||
|
@ -182,35 +207,28 @@ class ESPNowDefaultProtocol : public ESPNowProtocol {
|
|||
void add_on_receive_callback(std::function<void(const ESPNowPacket)> &&callback) {
|
||||
this->on_receive_.add(std::move(callback));
|
||||
}
|
||||
bool on_receive(const ESPNowPacket &packet) override {
|
||||
this->on_receive_.call(packet);
|
||||
return this->on_receive_.size() > 0;
|
||||
};
|
||||
void on_receive(const ESPNowPacket &packet) override { this->on_receive_.call(packet); };
|
||||
|
||||
void add_on_broadcast_callback(std::function<void(const ESPNowPacket)> &&callback) {
|
||||
this->on_broadcast_.add(std::move(callback));
|
||||
}
|
||||
|
||||
bool on_broadcast(const ESPNowPacket &packet) override {
|
||||
void on_broadcast(const ESPNowPacket &packet) override {
|
||||
if (this->on_broadcast_.size() > 0) {
|
||||
this->on_broadcast_.call(packet);
|
||||
return this->on_broadcast_.size() > 0;
|
||||
} else {
|
||||
this->on_receive(packet);
|
||||
}
|
||||
};
|
||||
|
||||
void add_on_sent_callback(std::function<void(const ESPNowPacket, bool status)> &&callback) {
|
||||
this->on_sent_.add(std::move(callback));
|
||||
}
|
||||
bool on_sent(const ESPNowPacket &packet, bool status) override {
|
||||
this->on_sent_.call(packet, status);
|
||||
return this->on_sent_.size() > 0;
|
||||
};
|
||||
void on_sent(const ESPNowPacket &packet, bool status) override { this->on_sent_.call(packet, status); };
|
||||
|
||||
void add_on_peer_callback(std::function<void(const ESPNowPacket)> &&callback) {
|
||||
void add_on_new_peer_callback(std::function<void(const ESPNowPacket)> &&callback) {
|
||||
this->on_new_peer_.add(std::move(callback));
|
||||
}
|
||||
bool on_new_peer(const ESPNowPacket &packet) override {
|
||||
this->on_new_peer_.call(packet);
|
||||
return this->on_new_peer_.size() > 0;
|
||||
};
|
||||
void on_new_peer(const ESPNowPacket &packet) override { this->on_new_peer_.call(packet); };
|
||||
|
||||
protected:
|
||||
CallbackManager<void(const ESPNowPacket, bool)> on_sent_;
|
||||
|
@ -240,62 +258,73 @@ class ESPNowComponent : public Component {
|
|||
void set_use_sent_check(bool value) { this->use_sent_check_ = value; }
|
||||
void set_conformation_timeout(uint32_t timeout) { this->conformation_timeout_ = timeout; }
|
||||
void set_retries(uint8_t value) { this->retries_ = value; }
|
||||
void set_pairing_protocol(ESPNowProtocol *pairing_protocol) { this->pairing_protocol_ = pairing_protocol; }
|
||||
void set_keeper(uint64_t keeper) { this->keeper_ = keeper; }
|
||||
} uint64_t get_keeper() {
|
||||
return this->keeper_;
|
||||
}
|
||||
uint64_t get_own_peer_address() { return this->own_peer_address_; }
|
||||
|
||||
void setup() override;
|
||||
void loop() override;
|
||||
void setup() override;
|
||||
void loop() override;
|
||||
|
||||
bool send(ESPNowPacket packet);
|
||||
bool is_paired(uint64_t to_peer);
|
||||
|
||||
void register_protocol(ESPNowProtocol *protocol) {
|
||||
bool send(ESPNowPacket packet);
|
||||
|
||||
void register_protocol(ESPNowProtocol *protocol) {
|
||||
protocol->set_parent(this);
|
||||
this->protocols_[protocol->get_protocol_id()] = protocol;
|
||||
}
|
||||
protocol->init_protocol();
|
||||
}
|
||||
|
||||
esp_err_t add_peer(uint64_t peer);
|
||||
esp_err_t del_peer(uint64_t peer);
|
||||
esp_err_t add_peer(uint64_t peer);
|
||||
esp_err_t del_peer(uint64_t peer);
|
||||
|
||||
bool send_queue_empty() { return uxQueueMessagesWaiting(this->send_queue_) == 0; }
|
||||
bool send_queue_full() { return uxQueueSpacesAvailable(this->send_queue_) == 0; }
|
||||
size_t send_queue_used() { return uxQueueMessagesWaiting(this->send_queue_); }
|
||||
size_t send_queue_free() { return uxQueueSpacesAvailable(this->send_queue_); }
|
||||
bool send_queue_empty() { return uxQueueMessagesWaiting(this->send_queue_) == 0; }
|
||||
bool send_queue_full() { return uxQueueSpacesAvailable(this->send_queue_) == 0; }
|
||||
size_t send_queue_used() { return uxQueueMessagesWaiting(this->send_queue_); }
|
||||
size_t send_queue_free() { return uxQueueSpacesAvailable(this->send_queue_); }
|
||||
|
||||
void lock() { this->lock_ = true; }
|
||||
bool is_locked() { return this->lock_; }
|
||||
void unlock() { this->lock_ = false; }
|
||||
void lock() { this->lock_ = true; }
|
||||
bool is_locked() { return this->lock_; }
|
||||
void unlock() { this->lock_ = false; }
|
||||
|
||||
ESPNowDefaultProtocol *get_default_protocol();
|
||||
ESPNowDefaultProtocol *get_default_protocol();
|
||||
|
||||
void show_packet(const std::string &title, const ESPNowPacket &packet);
|
||||
void show_packet(const std::string &title, const ESPNowPacket &packet);
|
||||
|
||||
static void espnow_task(void *params);
|
||||
static void espnow_task(void *params);
|
||||
|
||||
protected:
|
||||
bool validate_channel_(uint8_t channel);
|
||||
ESPNowProtocol *get_protocol_(uint32_t protocol);
|
||||
protected:
|
||||
bool validate_channel_(uint8_t channel);
|
||||
ESPNowProtocol *get_protocol_(uint32_t protocol);
|
||||
ESPNowProtocol *pairing_protocol_{nullptr};
|
||||
uint64_t own_peer_address_{0};
|
||||
uint8_t wifi_channel_{0};
|
||||
uint32_t conformation_timeout_{5000};
|
||||
uint8_t retries_{5};
|
||||
|
||||
uint64_t own_peer_address_{0};
|
||||
uint8_t wifi_channel_{0};
|
||||
bool auto_add_peer_{false};
|
||||
bool use_sent_check_{true};
|
||||
|
||||
uint32_t conformation_timeout_{5000};
|
||||
uint8_t retries_{5};
|
||||
bool lock_{false};
|
||||
|
||||
bool auto_add_peer_{false};
|
||||
bool use_sent_check_{true};
|
||||
void call_on_receive_(ESPNowPacket &packet);
|
||||
void call_on_broadcast_(ESPNowPacket &packet);
|
||||
void call_on_sent_(ESPNowPacket &packet, bool status);
|
||||
void call_on_new_peer_(ESPNowPacket &packet);
|
||||
|
||||
bool lock_{false};
|
||||
void call_on_add_peer_(uint64_t peer);
|
||||
void call_on_del_peer_(uint64_t peer);
|
||||
|
||||
bool call_on_receive_(ESPNowPacket &packet);
|
||||
bool call_on_broadcast_(ESPNowPacket &packet);
|
||||
bool call_on_sent_(ESPNowPacket &packet, bool status);
|
||||
bool call_on_new_peer_(ESPNowPacket &packet);
|
||||
QueueHandle_t receive_queue_{};
|
||||
QueueHandle_t send_queue_{};
|
||||
|
||||
QueueHandle_t receive_queue_{};
|
||||
QueueHandle_t send_queue_{};
|
||||
|
||||
std::map<uint32_t, ESPNowProtocol *> protocols_{};
|
||||
std::vector<uint64_t> peers_{};
|
||||
bool task_running_{false};
|
||||
static ESPNowComponent *static_; // NOLINT
|
||||
std::map<uint32_t, ESPNowProtocol *> protocols_{};
|
||||
std::vector<uint64_t> peers_{};
|
||||
bool task_running_{false};
|
||||
static ESPNowComponent *static_; // NOLINT
|
||||
};
|
||||
|
||||
template<typename... Ts> class SendAction : public Action<Ts...>, public Parented<ESPNowComponent> {
|
||||
|
@ -380,7 +409,7 @@ class ESPNowBroadcaseTrigger : public Trigger<const ESPNowPacket> {
|
|||
class ESPNowNewPeerTrigger : public Trigger<const ESPNowPacket> {
|
||||
public:
|
||||
explicit ESPNowNewPeerTrigger(ESPNowComponent *parent) {
|
||||
parent->get_default_protocol()->add_on_peer_callback([this](const ESPNowPacket packet) {
|
||||
parent->get_default_protocol()->add_on_new_peer_callback([this](const ESPNowPacket packet) {
|
||||
if ((this->command_ == 0) || this->command_ == packet.get_command()) {
|
||||
this->trigger(packet);
|
||||
}
|
||||
|
|
57
esphome/components/espnow/test1.yaml
Normal file
57
esphome/components/espnow/test1.yaml
Normal file
|
@ -0,0 +1,57 @@
|
|||
# These substitutions allow the end user to override certain values
|
||||
substitutions:
|
||||
name: "lum-iot-test1"
|
||||
friendly_name: "Project Template"
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
# version: 5.1.5
|
||||
|
||||
esphome:
|
||||
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.
|
||||
logger:
|
||||
level: verbose
|
||||
|
||||
espnow:
|
||||
auto_add_peer: false
|
||||
peers:
|
||||
- FF:FF:FF:FF:FF:FF
|
||||
- flW1QA3k
|
||||
|
||||
on_receive:
|
||||
- logger.log:
|
||||
format: "Received: '%s' from '%s' command: %d RSSI: %d"
|
||||
args:
|
||||
[
|
||||
packet.get_payload(),
|
||||
packet.get_peer_code().c_str(),
|
||||
packet.get_command(),
|
||||
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(),
|
||||
]
|
76
esphome/components/espnow/test2.yaml
Normal file
76
esphome/components/espnow/test2.yaml
Normal file
|
@ -0,0 +1,76 @@
|
|||
# These substitutions allow the end user to override certain values
|
||||
substitutions:
|
||||
name: "lum-iot-test2"
|
||||
friendly_name: "Project Template"
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
# version: 5.1.5
|
||||
|
||||
esphome:
|
||||
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.
|
||||
logger:
|
||||
level: verbose
|
||||
|
||||
espnow:
|
||||
auto_add_peer: true
|
||||
peers:
|
||||
- FF:FF:FF:FF:FF:FF
|
||||
keeper: rmT7YF9o
|
||||
on_receive:
|
||||
- logger.log:
|
||||
format: "Received: '%s' from '%s' command: %d RSSI: %d"
|
||||
args:
|
||||
[
|
||||
packet.get_payload(),
|
||||
packet.get_peer_code().c_str(),
|
||||
packet.get_command(),
|
||||
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: 30sec
|
||||
startup_delay: 20sec
|
||||
then:
|
||||
- espnow.broadcast:
|
||||
payload: "Broadcast message"
|
||||
command: 123
|
||||
- interval: 5sec
|
||||
then:
|
||||
- espnow.send:
|
||||
peer: keeper
|
||||
payload: "tesing the test"
|
||||
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
pin: GPIO39
|
||||
name: Button
|
||||
on_click:
|
||||
- espnow.peer.del: rmT7YF9o
|
Loading…
Reference in a new issue