mirror of
https://github.com/esphome/esphome.git
synced 2025-03-03 17:28:16 +00:00
full implement automaticly channel changing
This commit is contained in:
parent
5445451475
commit
bc9d065a79
@ -41,12 +41,51 @@ std::string peer_str(const uint64_t peer) {
|
||||
return "[Not Set]";
|
||||
if (peer == ESPNOW_BROADCAST_ADDR)
|
||||
return "[Broadcast]";
|
||||
if (peer == ESPNOW_MASS_SEND_ADDR)
|
||||
return "[Mass Send]";
|
||||
uint8_t *peer_ = (uint8_t *) &peer;
|
||||
snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X", peer_[0], peer_[1], peer_[2], peer_[3], peer_[4],
|
||||
peer_[5]);
|
||||
return mac;
|
||||
}
|
||||
|
||||
/* ESPNowPacket ********************************************************************** */
|
||||
|
||||
inline ESPNowPacket::ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size, uint32_t protocol,
|
||||
uint8_t command) {
|
||||
if (size > MAX_ESPNOW_DATA_SIZE) {
|
||||
ESP_LOGE(TAG, "Payload size is to large. It should be less then %d instead it is %d", MAX_ESPNOW_DATA_SIZE, size);
|
||||
return;
|
||||
}
|
||||
if (peer == 0ull) {
|
||||
ESP_LOGE(TAG, "No Peer defined.");
|
||||
return;
|
||||
}
|
||||
|
||||
this->peer = peer;
|
||||
this->is_broadcast = (peer == ESPNOW_BROADCAST_ADDR);
|
||||
|
||||
this->set_protocol(protocol);
|
||||
if (command != 0) {
|
||||
this->set_command(command);
|
||||
}
|
||||
this->size = size;
|
||||
std::memcpy(this->get_payload(), data, size);
|
||||
}
|
||||
|
||||
inline ESPNowPacket::ESPNowPacket(const uint8_t *peer, const uint8_t *data, uint8_t size) {
|
||||
if (size > MAX_ESPNOW_DATA_SIZE + this->prefix_size()) {
|
||||
ESP_LOGE(TAG, "Received Payload size is to large. It should be less then %d instead it is %d",
|
||||
MAX_ESPNOW_DATA_SIZE + this->prefix_size(), size);
|
||||
return;
|
||||
}
|
||||
|
||||
this->set_peer(peer);
|
||||
|
||||
this->size = size - this->prefix_size();
|
||||
std::memcpy(this->get_content(), data, size);
|
||||
}
|
||||
|
||||
/* ESPNowComponent ********************************************************************** */
|
||||
|
||||
ESPNowComponent::ESPNowComponent() { ESPNowComponent::static_ = this; } // NOLINT
|
||||
@ -94,7 +133,8 @@ void ESPNowComponent::setup() {
|
||||
esp_wifi_set_channel(this->wifi_channel_, WIFI_SECOND_CHAN_NONE);
|
||||
esp_wifi_set_promiscuous(false);
|
||||
#else
|
||||
// this->wifi_channel_ = wifi::global_wifi_component->
|
||||
if (wifi::global_wifi_component != nullptr)
|
||||
this->wifi_channel_ = wifi::global_wifi_component->get_wifi_channel();
|
||||
#endif
|
||||
|
||||
esp_err_t err = esp_now_init();
|
||||
@ -124,8 +164,8 @@ void ESPNowComponent::setup() {
|
||||
|
||||
esp_wifi_get_mac(WIFI_IF_STA, (uint8_t *) &this->own_peer_address_);
|
||||
|
||||
for (auto id : this->peers_) {
|
||||
this->add_peer(id & 0x00FFFFFFFFFFFF, (int8_t) id >> (64 - 8));
|
||||
for (const auto &kv : this->peers_) {
|
||||
this->add_peer(kv.first, kv.second.channel);
|
||||
}
|
||||
|
||||
this->send_queue_ = xQueueCreate(SEND_BUFFER_SIZE, sizeof(ESPNowPacket));
|
||||
@ -148,6 +188,22 @@ void ESPNowComponent::loop() {
|
||||
xTaskCreate(espnow_task, "espnow_task", 4096, this, tskIDLE_PRIORITY + 1, nullptr);
|
||||
this->task_running_ = true;
|
||||
}
|
||||
#ifdef USE_WIFI
|
||||
int32_t new_channel = wifi::global_wifi_component->get_wifi_channel();
|
||||
if (new_channel != this->wifi_channel_) {
|
||||
this->defer([this, new_channel]() { this->change_channel(new_channel); });
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ESPNowComponent::can_proceed() {
|
||||
#ifdef USE_WIFI
|
||||
if (wifi::global_wifi_component != nullptr)
|
||||
return wifi::global_wifi_component->is_ready();
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ESPNowComponent::espnow_task(void *param) {
|
||||
@ -206,10 +262,12 @@ void ESPNowComponent::espnow_task(void *param) {
|
||||
}
|
||||
|
||||
void ESPNowComponent::set_wifi_channel(uint8_t channel) {
|
||||
if (this->is_ready() && (this->wifi_channel_ == channel)) {
|
||||
if (this->is_ready() && (this->wifi_channel_ != channel)) {
|
||||
ESPNowPacket packet(ESPNOW_MASS_SEND_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);
|
||||
this->wifi_channel_ = channel;
|
||||
}
|
||||
this->wifi_channel_ = channel;
|
||||
}
|
||||
|
||||
esp_err_t ESPNowComponent::add_peer(uint64_t peer, int8_t channel) {
|
||||
@ -217,10 +275,7 @@ esp_err_t ESPNowComponent::add_peer(uint64_t peer, int8_t channel) {
|
||||
int8_t old_channel = this->wifi_channel_;
|
||||
esp_now_peer_info_t peer_info = {};
|
||||
|
||||
if (!this->is_ready()) {
|
||||
this->peers_.push_back((peer & 0x00FFFFFFFFFFFF) + (channel << (64 - 8)));
|
||||
return result;
|
||||
} else {
|
||||
if (this->is_ready()) {
|
||||
if (esp_now_is_peer_exist((uint8_t *) &peer)) {
|
||||
esp_now_get_peer((const uint8_t *) &peer, &peer_info);
|
||||
old_channel = peer_info.channel;
|
||||
@ -232,13 +287,20 @@ esp_err_t ESPNowComponent::add_peer(uint64_t peer, int8_t channel) {
|
||||
memset(&peer_info, 0, sizeof(esp_now_peer_info_t));
|
||||
peer_info.channel = (channel = -1) ? old_channel : channel;
|
||||
peer_info.encrypt = false;
|
||||
peer_info.ifidx = WIFI_IF_STA;
|
||||
memcpy((void *) peer_info.peer_addr, (void *) &peer, 6);
|
||||
esp_err_t result = esp_now_add_peer(&peer_info);
|
||||
if (result == ESP_OK) {
|
||||
this->call_on_add_peer_(peer);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (result == ESP_OK) {
|
||||
ESPNowPeer info;
|
||||
info.channel = channel;
|
||||
this->peers_[peer] = info;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
esp_err_t ESPNowComponent::del_peer(uint64_t peer) {
|
||||
@ -365,12 +427,31 @@ void ESPNowComponent::on_data_received(const uint8_t *addr, const uint8_t *data,
|
||||
show_packet("Receive", packet);
|
||||
|
||||
if (packet.is_valid()) {
|
||||
xQueueSendToBack(ESPNowComponent::static_->receive_queue_, (void *) &packet, 10);
|
||||
if (packet.get_protocol() == ESPNOW_MAIN_PROTOCOL_ID && packet.get_command() > 250) {
|
||||
ESPNowComponent *that = ESPNowComponent::static_;
|
||||
that->defer([that, packet]() { that->handle_internal_commands(packet); });
|
||||
} else {
|
||||
xQueueSendToBack(ESPNowComponent::static_->receive_queue_, (void *) &packet, 10);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid ESP-NOW packet received.");
|
||||
}
|
||||
}
|
||||
|
||||
void ESPNowComponent::handle_internal_commands(ESPNowPacket packet) {
|
||||
int8_t channel;
|
||||
switch (packet.get_command()) {
|
||||
case 251:
|
||||
channel = (int8_t) *packet.get_payload();
|
||||
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(),
|
||||
channel);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid internal ESP-NOW packet. Command not used: %d.", packet.get_command());
|
||||
}
|
||||
}
|
||||
|
||||
bool ESPNowComponent::send(ESPNowPacket packet) {
|
||||
if (!this->is_ready()) {
|
||||
ESP_LOGE(TAG, "Cannot send espnow packet, espnow is not setup yet.");
|
||||
@ -437,6 +518,8 @@ bool ESPNowProtocol::send(uint64_t peer, const uint8_t *data, uint8_t len, uint8
|
||||
return this->parent_->send(packet);
|
||||
}
|
||||
|
||||
const char *const ChangeChannel::TAG = "espnow.changechannel";
|
||||
|
||||
} // namespace espnow
|
||||
} // namespace esphome
|
||||
|
||||
|
@ -46,6 +46,10 @@ std::string peer_str(const uint64_t peer);
|
||||
|
||||
void show_packet(const std::string &title, const ESPNowPacket &packet);
|
||||
|
||||
struct ESPNowPeer {
|
||||
int8_t channel{-1};
|
||||
};
|
||||
|
||||
struct ESPNowPacket {
|
||||
uint64_t peer{0};
|
||||
uint8_t rssi{0};
|
||||
@ -66,40 +70,8 @@ struct ESPNowPacket {
|
||||
// Create packet to be send.
|
||||
|
||||
inline ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size, uint32_t protocol,
|
||||
uint8_t command = 0) ESPHOME_ALWAYS_INLINE {
|
||||
if (size > MAX_ESPNOW_DATA_SIZE) {
|
||||
ESP_LOGE("ESPNowPacket", "Payload size is to large. It should be less then %d instead it is %d",
|
||||
MAX_ESPNOW_DATA_SIZE, size); // nolint
|
||||
return;
|
||||
}
|
||||
if (peer == 0ull) {
|
||||
ESP_LOGE("ESPNowPacket", "No Peer defined.");
|
||||
return;
|
||||
}
|
||||
|
||||
this->peer = peer;
|
||||
this->is_broadcast = (peer == ESPNOW_BROADCAST_ADDR);
|
||||
|
||||
this->set_protocol(protocol);
|
||||
if (command != 0) {
|
||||
this->set_command(command);
|
||||
}
|
||||
this->size = size;
|
||||
std::memcpy(this->get_payload(), data, size);
|
||||
}
|
||||
|
||||
inline ESPNowPacket(const uint8_t *peer, const uint8_t *data, uint8_t size) ESPHOME_ALWAYS_INLINE {
|
||||
if (size > MAX_ESPNOW_DATA_SIZE + this->prefix_size()) {
|
||||
ESP_LOGE("ESPNowPacket", "Received Payload size is to large. It should be less then %d instead it is %d",
|
||||
MAX_ESPNOW_DATA_SIZE + this->prefix_size(), size); // nolint
|
||||
return;
|
||||
}
|
||||
|
||||
this->set_peer(peer);
|
||||
|
||||
this->size = size - this->prefix_size();
|
||||
std::memcpy(this->get_content(), data, size);
|
||||
}
|
||||
uint8_t command = 0) ESPHOME_ALWAYS_INLINE;
|
||||
inline ESPNowPacket(const uint8_t *peer, const uint8_t *data, uint8_t size) ESPHOME_ALWAYS_INLINE;
|
||||
|
||||
uint8_t prefix_size() const { return sizeof(this->content.prefix); }
|
||||
|
||||
@ -268,6 +240,7 @@ class ESPNowComponent : public Component {
|
||||
|
||||
void setup() override;
|
||||
void loop() override;
|
||||
bool can_proceed() override;
|
||||
|
||||
bool is_paired(uint64_t to_peer);
|
||||
|
||||
@ -295,6 +268,8 @@ class ESPNowComponent : public Component {
|
||||
|
||||
static void espnow_task(void *params);
|
||||
|
||||
void handle_internal_commands(ESPNowPacket packet);
|
||||
|
||||
protected:
|
||||
bool validate_channel_(uint8_t channel);
|
||||
ESPNowProtocol *get_protocol_(uint32_t protocol);
|
||||
@ -321,7 +296,8 @@ class ESPNowComponent : public Component {
|
||||
QueueHandle_t send_queue_{};
|
||||
|
||||
std::map<uint32_t, ESPNowProtocol *> protocols_{};
|
||||
std::vector<uint64_t> peers_{};
|
||||
std::map<uint64_t, ESPNowPeer> peers_{};
|
||||
|
||||
bool task_running_{false};
|
||||
static ESPNowComponent *static_; // NOLINT
|
||||
};
|
||||
@ -379,6 +355,25 @@ template<typename... Ts> class SetStaticPeerAction : public Action<Ts...>, publi
|
||||
uint64_t *peer_id_;
|
||||
};
|
||||
|
||||
class ChangeChannel {
|
||||
public:
|
||||
// could be made inline with C++17
|
||||
static const char *const TAG;
|
||||
};
|
||||
|
||||
template<typename... Ts> class ChangeChannelAction : public Action<Ts...>, public Parented<ESPNowComponent> {
|
||||
public:
|
||||
TEMPLATABLE_VALUE(int8_t, channel);
|
||||
void play(Ts... x) override {
|
||||
#ifdef USE_WIFI
|
||||
esph_log_e(ChangeChannel::TAG, "Manual changing the channel is not possible with WIFI enabled.");
|
||||
#else
|
||||
int8_t value = this->channel_.value(x...);
|
||||
parent_->set_wifi_channel(value);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/********************************* triggers **************************************/
|
||||
class ESPNowSentTrigger : public Trigger<const ESPNowPacket, bool> {
|
||||
public:
|
||||
|
Loading…
x
Reference in New Issue
Block a user