This commit is contained in:
NP v/d Spek 2024-09-03 19:09:10 +02:00
parent 9e4b7f954d
commit 4be0ac2d65
6 changed files with 172 additions and 81 deletions

5
esphome/.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
# Gitignore settings for ESPHome
# This is an example and may include too much for your use-case.
# You can modify this file to suit your needs.
/.esphome/
/secrets.yaml

View file

@ -55,55 +55,46 @@ struct {
} __attribute__((packed)) espnow_frame_format_t; } __attribute__((packed)) espnow_frame_format_t;
#endif #endif
ESPNowPacket::ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size, uint32_t app_id) ESPNowPacket::ESPNowPacket(espnow_addr_t peer, const uint8_t *data, uint8_t size, uint32_t protocol) : ESPNowPacket() {
: mac64(mac64), size(size), app_id(app_id), retrys(0) { if (this->peer() == {0})
if (this->mac64 == 0) this->peer(ESPNOW_BROADCAST_ADDR);
this->mac64 = ESPNOW_BROADCAST_ADDR; this->is_broadcast = memcpr(&this->peer(), &ESPNOW_BROADCAST_ADDR, 6);
this->is_broadcast = this->mac64 == ESPNOW_BROADCAST_ADDR; this->protocol(protocol);
this->content_->get_data().std::memcpy(&this->data, (uint8_t *) data, this->size);
this->ref_id = 0;
this->size = std::min(MAX_ESPNOW_DATA_SIZE, size);
std::memcpy(&this->data, (uint8_t *) data, this->size);
this->data[this->size + 1] = 0; this->data[this->size + 1] = 0;
this->recalc(); this->recalc();
this->info("create");
} }
inline void ESPNowPacket::info(std::string place) { void ESPNowPacket::info(std::string place) {
ESP_LOGVV(TAG, "%s: M:%s A:0x%06x R:0x%02x C:0x%04x S:%02x", place.c_str(), this->to_str().c_str(), this->app_id, ESP_LOGVV(TAG, "%s: M:%s A:0x%06x R:0x%02x C:0x%04x S:%02x", place.c_str(), this->to_str().c_str(), this->app_id,
this->ref_id, this->random, this->size); this->ref_id, this->random, this->size);
} }
bool ESPNowPacket::is_valid() { bool ESPNowPacket::is_valid() {
uint16_t crc = this->crc16; uint16_t crc = this->crc();
recalc(); this->calc_crc();
bool valid = (std::memcmp(&header, &TRANSPORT_HEADER, 3) == 0); bool valid = (std::memcmp(this->header(), &TRANSPORT_HEADER, 3) == 0);
valid &= (this->app_id != 0); valid &= (this->protocol() != 0);
valid &= (this->crc16 == crc); valid &= (this->crc() == crc);
if (!valid) { if (!valid) {
ESP_LOGV("Packet", "Invalid H:%02x%02x%02x A:%06x R:%02x C:%04x ipv. %04x, %d&%d&%d=%d\n", this->header[0], ESP_LOGV("Packet", "Invalid H:%02x%02x%02x A:%06x R:%02x C:%04x ipv. %04x\n", this->header()[0], this->header()[1],
this->header[1], this->header[2], this->app_id, this->ref_id, crc, this->crc16, this->header()[2], this->protocol(), this->packet_id(), crc, this->crc());
std::memcmp(&header, &TRANSPORT_HEADER, 3) == 0, (this->app_id != 0), (this->crc16 == crc), valid);
} }
this->crc(crc);
this->crc16 = crc;
return valid; return valid;
} }
void ESPNowProtocol::setup() { parent_->register_protocol(this); }
bool ESPNowProtocol::write(uint64_t mac_address, const uint8_t *data, uint8_t len) { bool ESPNowProtocol::write(uint64_t mac_address, const uint8_t *data, uint8_t len) {
ESPNowPacket packet(mac_address, data, len, this->get_app_id()); ESPNowPacket packet(mac_address, data, len, this->get_protocol_id());
return this->parent_->write(packet); return this->parent_->write(packet);
} }
bool ESPNowProtocol::write(uint64_t mac_address, std::vector<uint8_t> &data) { bool ESPNowProtocol::write(uint64_t mac_address, std::vector<uint8_t> &data) {
ESPNowPacket packet(mac_address, (uint8_t *) data.data(), (uint8_t) data.size(), this->get_app_id()); ESPNowPacket packet(mac_address, (uint8_t *) data.data(), (uint8_t) data.size(), this->get_protocol_id());
return this->parent_->write(packet); return this->parent_->write(packet);
} }
bool ESPNowProtocol::write(ESPNowPacket packet) { bool ESPNowProtocol::write(ESPNowPacket packet) {
packet.app_id = this->get_app_id(); packet.protocol(this->get_protocol_id());
packet.ref_id = this->get_next_ref_id(); packet.ref_id = this->get_next_ref_id();
packet.recalc(); packet.recalc();
return this->parent_->write(packet); return this->parent_->write(packet);
@ -239,7 +230,6 @@ esp_err_t ESPNowComponent::del_peer(uint64_t addr) {
ESPNowDefaultProtocol *ESPNowComponent::get_default_protocol() { ESPNowDefaultProtocol *ESPNowComponent::get_default_protocol() {
if (this->protocols_[ESPNOW_DEFAULT_APP_ID] == nullptr) { if (this->protocols_[ESPNOW_DEFAULT_APP_ID] == nullptr) {
ESPNowDefaultProtocol *tmp = new ESPNowDefaultProtocol(); ESPNowDefaultProtocol *tmp = new ESPNowDefaultProtocol();
this->protocols_[ESPNOW_DEFAULT_APP_ID] = tmp;
this->register_protocol(tmp); this->register_protocol(tmp);
} }
return (ESPNowDefaultProtocol *) this->protocols_[ESPNOW_DEFAULT_APP_ID]; return (ESPNowDefaultProtocol *) this->protocols_[ESPNOW_DEFAULT_APP_ID];

View file

@ -22,7 +22,7 @@ namespace espnow {
typedef uint8_t espnow_addr_t[6]; typedef uint8_t espnow_addr_t[6];
static const uint64_t ESPNOW_BROADCAST_ADDR = 0xFFFFFFFFFFFF; static const espnow_addr_t ESPNOW_BROADCAST_ADDR = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static espnow_addr_t ESPNOW_ADDR_SELF = {0}; static espnow_addr_t ESPNOW_ADDR_SELF = {0};
static const uint8_t ESPNOW_DATA_HEADER = 0x00; static const uint8_t ESPNOW_DATA_HEADER = 0x00;
@ -62,70 +62,76 @@ class ESPNowPacket {
public: public:
ESPNowPacket() ESPHOME_ALWAYS_INLINE { this->content_.put_uint24(TRANSPORT_HEADER); } ESPNowPacket() ESPHOME_ALWAYS_INLINE { this->content_.put_uint24(TRANSPORT_HEADER); }
// Create packet to be send. // Create packet to be send.
ESPNowPacket(espnow_addr_t mac64, const uint8_t *data, uint8_t size, uint32_t app_id); ESPNowPacket(espnow_addr_t peer, const uint8_t *data, uint8_t size, uint32_t app_id);
// Load received packet's. // Load received packet's.
ESPNowPacket(espnow_addr_t mac64, const uint8_t *data, uint8_t size); ESPNowPacket(espnow_addr_t peer, const uint8_t *data, uint8_t size);
void info(std::string place); inline void info(std::string place);
uint8_T *peer() { return this->peer_; } uint8_T *peer() { return this->peer_; }
void peer(espnow_addr_t mac_addres) { std::memcpy(&this->peer_, &mac_addres, 6); } void peer(espnow_addr_t mac_addres) { std::memcpy(&this->peer_, &mac_addres, 6); }
uint8_T size() { return this->content_; } uint8_T size() {
if (this->content_->get_used() <= 10) {
return 0;
}
return this->content_->get_used();
}
}
bool broadcast(){return this->is_broadcast_}; bool broadcast(){return this->is_broadcast_};
void broadcast(bool state) { this->is_broadcast_ = state; } void broadcast(bool state) { this->is_broadcast_ = state; }
uint32_t timestamp() { return this->timestamp_; }; uint32_t timestamp() { return this->timestamp_; };
void timestamp(uint32_t timestamp) { this->timestamp_ = timestamp; }; void timestamp(uint32_t timestamp) { this->timestamp_ = timestamp; };
uint32_t protocol() { uint32_t protocol() {
this->content_->set_position(ESPNOW_DATA_PROTOCOL); this->content_->set_position(ESPNOW_DATA_PROTOCOL);
return this->content_->get_uint24(); return this->content_->get_uint24();
} }
void protocol(uint32_t protocol) { void protocol(uint32_t protocol) {
this->content_->set_position(ESPNOW_DATA_PROTOCOL); this->content_->set_position(ESPNOW_DATA_PROTOCOL);
this->content_->put_uint24(protocol); this->content_->put_uint24(protocol);
} }
uint8_t packet_id() { uint8_t packet_id() {
this->content_->set_position(ESPNOW_DATA_PACKET); this->content_->set_position(ESPNOW_DATA_PACKET);
return this->content_->get_uint8(); return this->content_->get_uint8();
} }
void packet_id(uint8_t packet_id) { void packet_id(uint8_t packet_id) {
this->content_->set_position(ESPNOW_DATA_PACKET); this->content_->set_position(ESPNOW_DATA_PACKET);
this->content_->put_uint8(packet_id); this->content_->put_uint8(packet_id);
} }
uint16_t crc() { uint16_t crc() {
this->content_->set_position(ESPNOW_DATA_CRC); this->content_->set_position(ESPNOW_DATA_CRC);
return this->content_->get_uint16(); return this->content_->get_uint16();
} }
void crc(uint16_t crc) { void crc(uint16_t crc) {
this->content_->set_position(ESPNOW_DATA_CRC); this->content_->set_position(ESPNOW_DATA_CRC);
this->content_->put_uint16(crc); this->content_->put_uint16(crc);
} }
ByteBuffer *content() { ByteBuffer *content() {
this->content_.set_position(ESPNOW_DATA_CONTENT + this->size_); this->content_.set_position(ESPNOW_DATA_CONTENT + this->size_);
return &this->content_; return &this->content_;
}
void retry() {
if (this->retrys_ < 7) {
this->retrys_ = this->retrys_ + 1;
} }
}
void retry() { void calc_crc() {
if (this->retrys_ < 7) { this->crc(0);
this->retrys_ = this->retrys_ + 1; this->crc(esp_crc16_le(this->packet(), this->dataptr(), 10 + size()));
} }
}
void calc_crc() { bool is_valid();
this->crc(0);
this->crc(esp_crc16_le(this->packet(), this->dataptr(), 10 + size()));
}
bool is_valid(); uint8_t *dataptr() { return this->content_->get_data()->data(); }
uint8_t *dataptr() { return this->content_->get_data()->data(); }
}; };
class ESPNowComponent; class ESPNowComponent;
@ -136,13 +142,11 @@ class ESPNowProtocol : public Parented<ESPNowComponent> {
public: public:
ESPNowProtocol(){}; ESPNowProtocol(){};
void setup();
virtual void on_receive(ESPNowPacket packet){}; virtual void on_receive(ESPNowPacket packet){};
virtual void on_sent(ESPNowPacket packet, bool status){}; virtual void on_sent(ESPNowPacket packet, bool status){};
virtual void on_new_peer(ESPNowPacket packet){}; virtual void on_new_peer(ESPNowPacket packet){};
virtual uint32_t get_app_id() = 0; virtual uint32_t get_protocol_id() = 0;
uint8_t get_next_ref_id() { return next_ref_id_++; } uint8_t get_next_ref_id() { return next_ref_id_++; }
bool write(uint64_t mac_address, const uint8_t *data, uint8_t len); bool write(uint64_t mac_address, const uint8_t *data, uint8_t len);
@ -159,7 +163,7 @@ class ESPNowDefaultProtocol : public ESPNowProtocol {
void on_sent(ESPNowPacket packet, bool status) override { this->on_sent_.call(packet, status); }; void on_sent(ESPNowPacket packet, bool status) override { this->on_sent_.call(packet, status); };
void on_new_peer(ESPNowPacket packet) override { this->on_new_peer_.call(packet); }; void on_new_peer(ESPNowPacket packet) override { this->on_new_peer_.call(packet); };
uint32_t get_app_id() override { return ESPNOW_DEFAULT_APP_ID; }; uint32_t get_protocol_id() override { return ESPNOW_DEFAULT_APP_ID; };
void add_on_sent_callback(std::function<void(ESPNowPacket, bool status)> &&callback) { void add_on_sent_callback(std::function<void(ESPNowPacket, bool status)> &&callback) {
this->on_sent_.add(std::move(callback)); this->on_sent_.add(std::move(callback));
@ -206,7 +210,7 @@ class ESPNowComponent : public Component {
void register_protocol(ESPNowProtocol *protocol) { void register_protocol(ESPNowProtocol *protocol) {
protocol->set_parent(this); protocol->set_parent(this);
this->protocols_[protocol->get_app_id()] = protocol; this->protocols_[protocol->get_protocol_id()] = protocol;
} }
esp_err_t add_peer(uint64_t addr); esp_err_t add_peer(uint64_t addr);

View file

@ -80,7 +80,9 @@ void ByteBuffer::flip() {
/// Getters /// Getters
uint8_t ByteBuffer::get_uint8() { uint8_t ByteBuffer::get_uint8() {
assert(this->get_remaining() >= 1); assert(this->get_remaining() >= 1);
return this->data_[this->position_++]; this->position_++;
this->update_used_();
return this->data_[this->position_];
} }
uint64_t ByteBuffer::get_uint(size_t length) { uint64_t ByteBuffer::get_uint(size_t length) {
assert(this->get_remaining() >= length); assert(this->get_remaining() >= length);
@ -98,6 +100,7 @@ uint64_t ByteBuffer::get_uint(size_t length) {
value |= this->data_[this->position_++]; value |= this->data_[this->position_++];
} }
} }
this->update_used_();
return value; return value;
} }
@ -126,13 +129,22 @@ std::vector<uint8_t> ByteBuffer::get_vector(size_t length) {
assert(this->get_remaining() >= length); assert(this->get_remaining() >= length);
auto start = this->data_.begin() + this->position_; auto start = this->data_.begin() + this->position_;
this->position_ += length; this->position_ += length;
this->update_used_();
return {start, start + length}; return {start, start + length};
} }
void ByteBuffer::get_data(const uint8_t *data, size_t length) {
assert(this->get_remaining() >= length);
auto start = this->data_.begin() + this->position_;
copy(start, start + length, data);
this->position_ += length;
this->update_used_();
}
/// Putters /// Putters
void ByteBuffer::put_uint8(uint8_t value) { void ByteBuffer::put_uint8(uint8_t value) {
assert(this->get_remaining() >= 1); assert(this->get_remaining() >= 1);
this->data_[this->position_++] = value; this->data_[this->position_++] = value;
this->update_used_();
} }
void ByteBuffer::put_uint(uint64_t value, size_t length) { void ByteBuffer::put_uint(uint64_t value, size_t length) {
@ -150,6 +162,7 @@ void ByteBuffer::put_uint(uint64_t value, size_t length) {
value >>= 8; value >>= 8;
} }
} }
this->update_used_();
} }
void ByteBuffer::put_float(float value) { void ByteBuffer::put_float(float value) {
static_assert(sizeof(float) == sizeof(uint32_t), "Float sizes other than 32 bit not supported"); static_assert(sizeof(float) == sizeof(uint32_t), "Float sizes other than 32 bit not supported");
@ -169,5 +182,13 @@ void ByteBuffer::put_vector(const std::vector<uint8_t> &value) {
assert(this->get_remaining() >= value.size()); assert(this->get_remaining() >= value.size());
std::copy(value.begin(), value.end(), this->data_.begin() + this->position_); std::copy(value.begin(), value.end(), this->data_.begin() + this->position_);
this->position_ += value.size(); this->position_ += value.size();
this->update_used_();
} }
void ByteBuffer::put_array(const uint8_t *data, size_t size) {
assert(this->get_remaining() >= size);
std::copy(data[0], data[size], this->data_.begin() + this->position_);
this->position_ += size;
this->update_used_();
}
} // namespace esphome } // namespace esphome

View file

@ -92,6 +92,7 @@ class ByteBuffer {
bool get_bool() { return this->get_uint8(); } bool get_bool() { return this->get_uint8(); }
// Get vector of bytes, increment by length // Get vector of bytes, increment by length
std::vector<uint8_t> get_vector(size_t length); std::vector<uint8_t> get_vector(size_t length);
void get_data(const uint8_t *data, size_t length);
// Put values into the buffer, increment the position accordingly // Put values into the buffer, increment the position accordingly
// put any integral value, length represents the number of bytes // put any integral value, length represents the number of bytes
@ -112,11 +113,13 @@ class ByteBuffer {
void put_double(double value); void put_double(double value);
void put_bool(bool value) { this->put_uint8(value); } void put_bool(bool value) { this->put_uint8(value); }
void put_vector(const std::vector<uint8_t> &value); void put_vector(const std::vector<uint8_t> &value);
void put_array(const uint8_t *data, size_t size);
inline size_t get_capacity() const { return this->data_.size(); } inline size_t get_capacity() const { return this->data_.size(); }
inline size_t get_position() const { return this->position_; } inline size_t get_position() const { return this->position_; }
inline size_t get_limit() const { return this->limit_; } inline size_t get_limit() const { return this->limit_; }
inline size_t get_remaining() const { return this->get_limit() - this->get_position(); } inline size_t get_remaining() const { return this->get_limit() - this->get_position(); }
inline size_t get_used() const { return this->used_; }
inline Endian get_endianness() const { return this->endianness_; } inline Endian get_endianness() const { return this->endianness_; }
inline void mark() { this->mark_ = this->position_; } inline void mark() { this->mark_ = this->position_; }
inline void big_endian() { this->endianness_ = BIG; } inline void big_endian() { this->endianness_ = BIG; }
@ -131,14 +134,21 @@ class ByteBuffer {
std::vector<uint8_t> get_data() { return this->data_; }; std::vector<uint8_t> get_data() { return this->data_; };
void rewind() { this->position_ = 0; } void rewind() { this->position_ = 0; }
void reset() { this->position_ = this->mark_; } void reset() { this->position_ = this->mark_; }
void resize() { this->used_ = this->position_; }
protected: protected:
ByteBuffer(std::vector<uint8_t> const &data) : data_(data), limit_(data.size()) {} ByteBuffer(std::vector<uint8_t> const &data) : data_(data), limit_(data.size()) {}
void update_used_() {
if (this->used_ < this->position_) {
this->resize();
}
}
std::vector<uint8_t> data_; std::vector<uint8_t> data_;
Endian endianness_{LITTLE}; Endian endianness_{LITTLE};
size_t position_{0}; size_t position_{0};
size_t mark_{0}; size_t mark_{0};
size_t limit_{0}; size_t limit_{0};
size_t used_{0};
}; };
} // namespace esphome } // namespace esphome

61
esphome/test.yaml Normal file
View file

@ -0,0 +1,61 @@
# These substitutions allow the end user to override certain values
substitutions:
name: "lum-iot-test"
friendly_name: "Project Template"
#xternal_components:
# - source: github://pr#7141
# components: [ espnow ]
# refresh: 1 sec
esp32:
board: esp32-s3-devkitc-1
framework:
type: esp-idf
wifi:
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: esphome.project-template
version: "1.0"
# To be able to get logs from the device via serial and api.
logger:
# API is a requirement of the dashboard import.
api:
# OTA is required for Over-the-Air updating
ota:
platform: esphome
# Sets up Bluetooth LE (Only on ESP32) to allow the user
# to provision wifi credentials to the device.
esp32_improv:
authorizer: none
espnow:
auto_add_peer: true
peers:
- FF:FF:FF:FF:FF:FF
on_receive:
- logger.log:
format: "Received: %s RSSI: %d"
args: [it->data().data(), it->rssi()]
binary_sensor:
- platform: gpio
pin: GPIO39
name: Button
on_click:
- espnow.send: "hallo everyone"