1
0
mirror of https://github.com/esphome/esphome.git synced 2025-03-03 17:28:16 +00:00

you can now send multicast messages.

multicast is used for changing channels
This commit is contained in:
NP v/d Spek 2024-11-28 01:02:54 +01:00
parent 3250125e21
commit 32b9be9548
5 changed files with 103 additions and 30 deletions

View File

@ -258,6 +258,20 @@ async def register_peer(var, config, args):
cv.maybe_simple_value(
{
cv.GenerateID(): cv.use_id(ESPNowComponent),
cv.Optional(CONF_MAC_ADDRESS, default=0xFFFFFFFFFFFF): cv.uint64_t,
cv.Required(CONF_PAYLOAD): cv.templatable(validate_raw_data),
cv.Optional(CONF_COMMAND): cv.templatable(validate_command),
},
key=CONF_PAYLOAD,
),
)
@automation.register_action(
"espnow.multicast",
SendAction,
cv.maybe_simple_value(
{
cv.GenerateID(): cv.use_id(ESPNowComponent),
cv.Optional(CONF_MAC_ADDRESS, default=0xFFFFFFFFFFFE): cv.uint64_t,
cv.Required(CONF_PAYLOAD): cv.templatable(validate_raw_data),
cv.Optional(CONF_COMMAND): cv.templatable(validate_command),
},

View File

@ -41,8 +41,8 @@ std::string peer_str(uint64_t peer) {
return "[Not Set]";
if (peer == ESPNOW_BROADCAST_ADDR)
return "[Broadcast]";
if (peer == ESPNOW_MASS_SEND_ADDR)
return "[Mass Send]";
if (peer == ESPNOW_MULTICAST_ADDR)
return "[Multicast]";
uint8_t *ppeer = (uint8_t *) &peer;
snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X", ppeer[0], ppeer[1], ppeer[2], ppeer[3], ppeer[4],
ppeer[5]);
@ -199,7 +199,7 @@ void ESPNowComponent::loop() {
bool ESPNowComponent::can_proceed() {
#ifdef USE_WIFI
if (wifi::global_wifi_component != nullptr)
return wifi::global_wifi_component->is_ready();
return wifi::global_wifi_component->is_connected();
return false;
#else
return true;
@ -225,14 +225,13 @@ void ESPNowComponent::espnow_task(void *param) {
}
if (xQueueReceive(this_espnow->send_queue_, (void *) &packet, (TickType_t) 1) == pdTRUE) {
if (packet.attempts > this_espnow->retries_) {
ESP_LOGE(TAG, "Dropped '%s' (%d.%d). To many retries.", packet.get_peer_code().c_str(), packet.get_sequents(),
ESP_LOGE(TAG, "Dropped %s (%d.%d). To many retries.", packet.get_peer_code().c_str(), packet.get_sequents(),
packet.attempts);
this_espnow->unlock();
continue;
} else if (this_espnow->is_locked()) {
if (packet.timestamp + this_espnow->conformation_timeout_ < millis()) {
ESP_LOGW(TAG, "TimeOut '%s' (%d.%d).", packet.get_peer_code().c_str(), packet.get_sequents(),
packet.attempts);
ESP_LOGW(TAG, "TimeOut %s (%d.%d).", packet.get_peer_code().c_str(), packet.get_sequents(), packet.attempts);
this_espnow->unlock();
}
} else {
@ -241,17 +240,18 @@ void ESPNowComponent::espnow_task(void *param) {
packet.timestamp = millis();
esp_err_t err;
if (packet.peer == ESPNOW_MASS_SEND_ADDR) {
if (packet.peer == ESPNOW_MULTICAST_ADDR) {
this_espnow->start_multi_cast_();
err = esp_now_send(nullptr, packet.get_content(), packet.content_size());
} else {
err = esp_now_send(packet.get_peer(), packet.get_content(), packet.content_size());
}
if (err == ESP_OK) {
ESP_LOGD(TAG, "Sended '%s' (%d.%d) from buffer. Wait for conformation.", packet.get_peer_code().c_str(),
ESP_LOGD(TAG, "Sended %s (%d.%d) from buffer. Wait for conformation.", packet.get_peer_code().c_str(),
packet.get_sequents(), packet.attempts);
} else {
ESP_LOGE(TAG, "Sending '%s' (%d.%d) FAILED. B: %d.", packet.get_peer_code().c_str(), packet.get_sequents(),
ESP_LOGE(TAG, "Sending %s (%d.%d) FAILED. B: %d.", packet.get_peer_code().c_str(), packet.get_sequents(),
packet.attempts, this_espnow->send_queue_used());
this_espnow->unlock();
}
@ -263,7 +263,7 @@ void ESPNowComponent::espnow_task(void *param) {
void ESPNowComponent::set_wifi_channel(uint8_t channel) {
if (this->is_ready() && (this->wifi_channel_ != channel)) {
ESPNowPacket packet(ESPNOW_MASS_SEND_ADDR, &channel, 1, ESPNOW_MAIN_PROTOCOL_ID, 251);
ESPNowPacket packet(ESPNOW_MULTICAST_ADDR, &channel, 1, ESPNOW_MAIN_PROTOCOL_ID, 251);
this->send(packet);
ESP_LOGD(TAG, "Wifi Channel is changed from %d to %d.", this->wifi_channel_, channel);
}
@ -380,7 +380,7 @@ void ESPNowComponent::call_on_del_peer_(uint64_t peer) {
bool ESPNowComponent::is_paired(uint64_t peer) {
bool result = false;
if (peer == ESPNOW_MASS_SEND_ADDR) {
if (peer == ESPNOW_MULTICAST_ADDR) {
return true;
} else if (peer == ESPNOW_BROADCAST_ADDR) {
this->add_peer(ESPNOW_BROADCAST_ADDR);
@ -456,6 +456,11 @@ void ESPNowComponent::handle_internal_commands(ESPNowPacket packet) {
}
}
void ESPNowComponent::handle_internal_sent(ESPNowPacket packet, bool status) {
ESP_LOGW(TAG, "Internal packet sent to %s (%d.%d) %sreceived.", packet.get_peer_code().c_str(), packet.get_sequents(),
packet.attempts, status ? "" : "NOT ");
}
bool ESPNowComponent::send(ESPNowPacket packet) {
if (packet.peer == this->own_peer_address_) {
ESP_LOGE(TAG, "Tried to peer your self.");
@ -477,7 +482,7 @@ bool ESPNowComponent::send(ESPNowPacket packet) {
return true;
} else {
esp_err_t err;
if (packet.peer == ESPNOW_MASS_SEND_ADDR) {
if (packet.peer == ESPNOW_MULTICAST_ADDR) {
err = esp_now_send(nullptr, packet.get_content(), packet.content_size());
} else {
err = esp_now_send(packet.get_peer(), packet.get_content(), packet.content_size());
@ -493,11 +498,19 @@ bool ESPNowComponent::send(ESPNowPacket packet) {
}
void ESPNowComponent::on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) {
ESPNowComponent *that = ESPNowComponent::static_;
bool unlock = true;
ESPNowPacket packet; // NOLINT
uint64_t peer = 0;
memcpy((void *) &peer, mac_addr, 6);
if (xQueuePeek(ESPNowComponent::static_->send_queue_, (void *) &packet, 10 / portTICK_PERIOD_MS) == pdTRUE) {
if (packet.peer != peer) {
if (xQueuePeek(that->send_queue_, (void *) &packet, 10 / portTICK_PERIOD_MS) == pdTRUE) {
if (packet.peer == ESPNOW_MULTICAST_ADDR) {
packet.peer = peer;
auto it = std::find(that->multicast_.begin(), that->multicast_.end(), peer);
that->multicast_.erase(it);
unlock = that->multicast_.empty();
} else if (packet.peer != peer) {
ESP_LOGE(TAG, " Invalid mac address. Expected: %s (%d.%d); got: %s", packet.get_peer_code().c_str(),
packet.get_sequents(), packet.attempts, peer_str(peer).c_str());
return;
@ -507,10 +520,32 @@ void ESPNowComponent::on_data_sent(const uint8_t *mac_addr, esp_now_send_status_
} else {
ESP_LOGV(TAG, "Confirm packet sent %s (%d.%d)", packet.get_peer_code().c_str(), packet.get_sequents(),
packet.attempts);
xQueueReceive(ESPNowComponent::static_->send_queue_, (void *) &packet, 10 / portTICK_PERIOD_MS);
}
ESPNowComponent::static_->call_on_sent_(packet, status == ESP_OK);
ESPNowComponent::static_->unlock();
if (packet.get_protocol() == ESPNOW_MAIN_PROTOCOL_ID && packet.get_command() > 250) {
that->defer([that, packet, status]() { that->handle_internal_sent(packet, status == ESP_OK); });
} else if (status == ESP_OK) {
that->call_on_sent_(packet, true);
}
if (unlock) {
if (status == ESP_OK) {
xQueueReceive(that->send_queue_, (void *) &packet, 10 / portTICK_PERIOD_MS);
}
that->unlock();
}
}
}
uint8_t ESPNowComponent::get_channel_for_(uint64_t peer) { return 0; }
void ESPNowComponent::update_channel_scan_(ESPNowPacket &packet) {}
void ESPNowComponent::start_multi_cast_() {
esp_now_peer_info_t peer;
memset(&peer, 0, sizeof(esp_now_peer_info_t));
multicast_.clear();
for (esp_err_t e = esp_now_fetch_peer(true, &peer); e == ESP_OK; e = esp_now_fetch_peer(false, &peer)) {
uint64_t mac = 0;
memcpy((void *) &mac, peer.peer_addr, 6);
multicast_.push_back(mac);
}
}

View File

@ -23,7 +23,7 @@ namespace esphome {
namespace espnow {
static const uint64_t ESPNOW_BROADCAST_ADDR = 0xFFFFFFFFFFFF;
static const uint64_t ESPNOW_MASS_SEND_ADDR = 0xFFFFFFFFFFFE;
static const uint64_t ESPNOW_MULTICAST_ADDR = 0xFFFFFFFFFFFE;
static const uint8_t MAX_ESPNOW_DATA_SIZE = 240;
@ -55,6 +55,8 @@ struct ESPNowPacket {
uint8_t rssi{0};
int8_t attempts{0};
bool is_broadcast{false};
bool is_multicast{false};
uint8_t scan_start{0};
uint32_t timestamp{0};
uint8_t size{0};
struct {
@ -232,6 +234,8 @@ class ESPNowComponent : public Component {
void set_wifi_channel(uint8_t channel);
void set_auto_add_peer(bool value) { this->auto_add_peer_ = value; }
void set_use_sent_check(bool value) { this->use_sent_check_ = value; }
void set_auto_channel_scan(bool value) { this->auto_channel_scan_ = 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; }
@ -269,11 +273,14 @@ class ESPNowComponent : public Component {
static void espnow_task(void *params);
void handle_internal_commands(ESPNowPacket packet);
void handle_internal_sent(ESPNowPacket packet, bool status);
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};
@ -281,6 +288,7 @@ class ESPNowComponent : public Component {
bool auto_add_peer_{false};
bool use_sent_check_{true};
bool auto_channel_scan_{false};
bool lock_{false};
@ -292,11 +300,16 @@ class ESPNowComponent : public Component {
void call_on_add_peer_(uint64_t peer);
void call_on_del_peer_(uint64_t peer);
uint8_t get_channel_for_(uint64_t peer);
void update_channel_scan_(ESPNowPacket &packet);
void start_multi_cast_();
QueueHandle_t receive_queue_{};
QueueHandle_t send_queue_{};
std::map<uint32_t, ESPNowProtocol *> protocols_{};
std::map<uint64_t, ESPNowPeer> peers_{};
std::vector<uint64_t> multicast_{};
bool task_running_{false};
static ESPNowComponent *static_; // NOLINT

View File

@ -17,11 +17,18 @@ esphome:
logger:
level: debug
#wifi:
# fast_connect: true
# networks:
# - ssid: !secret wifi_ssid
# password: !secret wifi_password
espnow:
auto_add_peer: true
wifi_channel: 1
predefined_peers:
- mac_address: E8:6B:EA:23:CD:98
wifi_channel: 2
on_receive:
- logger.log:
format: "Received from: %s = '%s' cmd: %d RSSI: %d"
@ -34,7 +41,7 @@ espnow:
]
interval:
- interval: 10sec
- interval: 30sec
startup_delay: 20sec
then:
- espnow.send:

View File

@ -26,19 +26,26 @@ esphome:
# To be able to get logs from the device via serial and api.
logger:
level: debug
level: verbose
globals:
- id: hub_address
type: uint64_t
initial_value: "0x0"
restore_value: yes
- id: channel
type: uint8_t
initial_value: "3"
restore_value: false
espnow:
auto_add_peer: true
wifi_channel: 1
wifi_channel: 2
predefined_peers:
- mac_address: e8:6b:ea:24:22:04
wifi_channel: 1
- mac_address: e8:6b:ea:24:22:03
- mac_address: e8:6b:ea:24:22:02
on_receive:
- logger.log:
format: "Received from: %s = '%s' cmd: %d RSSI: %d"
@ -52,13 +59,10 @@ espnow:
interval:
- interval: 30sec
startup_delay: 10sec
then:
- espnow.channel.set: 5
- interval: 5sec
startup_delay: 10sec
then:
- espnow.send:
mac_address: e8:6b:ea:24:22:04
payload: "Test 2."
command: 123
- espnow.channel.set: !lambda return id(channel);
- lambda: |-
id(channel) = id(channel)+1;
if (id(channel) > 10) {
id(channel) = 1;
}