From e797cdb34970edd8bf9d17205414a38b85babec5 Mon Sep 17 00:00:00 2001 From: Jonas Rabenstein Date: Sun, 4 Jan 2026 19:19:00 +0100 Subject: [PATCH] wip --- components/brmesh/address.h | 35 +++++++++++++++++++++++++++++++++++ components/brmesh/light.cpp | 20 +++++++++++++++++++- components/brmesh/light.h | 29 ++++++----------------------- components/brmesh/light.py | 6 +++--- components/brmesh/network.cpp | 12 ++++++------ components/brmesh/output.h | 35 +++++++++++++++++++++++++++++++++++ 6 files changed, 104 insertions(+), 33 deletions(-) create mode 100644 components/brmesh/address.h create mode 100644 components/brmesh/output.h diff --git a/components/brmesh/address.h b/components/brmesh/address.h new file mode 100644 index 0000000..ba3a1b0 --- /dev/null +++ b/components/brmesh/address.h @@ -0,0 +1,35 @@ +#pragma once +#include +#include +#include + +#include "esphome/core/helpers.h" + +namespace esphome { +namespace brmesh { + +class Address : public std::array { + static constexpr uint8_t reverse(uint8_t x) { + x = ((x & 0xAA) >> 1) | ((x & 0x55) << 1); + x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2); + x = ((x & 0xF0) >> 4) | ((x & 0x0F) << 4); + return x; + } +public: + constexpr Address(const uint8_t a, const uint8_t b, const uint8_t c) + : array{reverse(c), reverse(b), reverse(a)} {} + + template + std::span set(const std::span &dst) const { + return set(std::span(dst)); + } + + std::span set(const std::span &dst) const { + if (dst.size() < size()) + return {}; + std::copy(cbegin(), cend(), &dst[0]); + return dst.subspan(0, size()); + } +}; +} // namespace brmesh +} // namespace esphome diff --git a/components/brmesh/light.cpp b/components/brmesh/light.cpp index 1dbf674..0f0bb8a 100644 --- a/components/brmesh/light.cpp +++ b/components/brmesh/light.cpp @@ -188,6 +188,24 @@ Light::advertise(bool advertise) { network_.advertise(id_, {}); } +std::span +Light::command(const std::span &output) const +{ + const auto hdr = output.subspan(0, 2); + const auto dst = output.subspan(hdr.size()); + const auto src = std::span(payload_.cbegin(), payload_length_); + + if (output.size() < hdr.size() + src.size()) + return {}; + + hdr[0] = 2 | (((0xfffffff & (src.size() + 1)) << 4)); + hdr[1] = id_.value(); + std::copy(src.begin(), src.end(), dst.begin()); + std::ranges::fill(dst.subspan(src.size()), 0); + + return output; +} + void Light::loop() { disable_loop(); @@ -247,7 +265,7 @@ Light::write_state(light::LightState *state) { count_ = 0; //ESP_LOGD(TAG, "%c%02hhX: state: %s", id_.kind(), id_.value(), // format_hex_pretty(&payload[0], payload.size()).c_str()); - enable_loop(); + //enable_loop(); } } // namespace brmesh diff --git a/components/brmesh/light.h b/components/brmesh/light.h index cb20922..dda261d 100644 --- a/components/brmesh/light.h +++ b/components/brmesh/light.h @@ -23,26 +23,24 @@ public: class Id : public std::variant { public: using variant::variant; + constexpr Id(uint8_t value) : variant(Single{value}) {} static constexpr char kind(Single) { return 'L'; } static constexpr char kind(Group) { return 'G'; } - constexpr char kind() { + constexpr char kind() const { return std::visit([](auto &&value) { return Id::kind(value); }, *this); } static constexpr uint8_t value(Single value) { return static_cast(value); } static constexpr uint8_t value(Group value) { return static_cast(value); } - constexpr uint8_t value() { + constexpr uint8_t value() const { return std::visit([](auto &&value) { return Id::value(value); }, *this); } }; Light(Id id, Network *network) : id_(id), network_(*network) {} + Light(Single id, Network *network) : Light(Id{id}, network) {} -// Light(Id id, const Key &key, uint16_t adv_interval_min, uint16_t adv_interval_max) -// : id_(id), key_(key), -// adv_interval_min_(adv_interval_min / 0.625f), adv_interval_max_(adv_interval_max / 0.625f) {} -// // interface: Component void dump_config() override; float get_setup_priority() const override { @@ -59,31 +57,16 @@ public: // callback void advertise(bool advertise); + + std::span command(const std::span &output) const; private: Id id_; Network &network_; -#if 0 - light::LightState *state_ = nullptr; - const Key key_; - const uint16_t adv_interval_min_; - const uint16_t adv_interval_max_; - static constexpr esp_power_level_t tx_power_{}; - uint8_t seq_ = 0; -#endif uint8_t count_ = 0; bool advertising_ = false; std::array payload_ = {}; size_t payload_length_ = 0; - -#if 0 - void adv_event_(esp_ble_gap_cb_param_t::ble_adv_data_raw_cmpl_evt_param &); - void adv_event_(esp_ble_gap_cb_param_t::ble_adv_start_cmpl_evt_param &); - void adv_event_(esp_ble_gap_cb_param_t::ble_adv_stop_cmpl_evt_param &); - - static std::span adv_data_(const std::span &, uint8_t seq, light::LightState &); -#endif - }; } // namespace brmesh diff --git a/components/brmesh/light.py b/components/brmesh/light.py index f9954b2..03f9a38 100644 --- a/components/brmesh/light.py +++ b/components/brmesh/light.py @@ -3,7 +3,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.cpp_generator import LambdaExpression -from esphome.const import CONF_LIGHT_ID, CONF_OUTPUT_ID +from esphome.const import CONF_LIGHT_ID, CONF_OUTPUT_ID, CONF_REPEAT from esphome.core import HexInt from esphome.components import light, esp32_ble @@ -15,14 +15,14 @@ AUTO_LOAD = ["light"] CONF_NETWORK_ID = "network" Light = brmesh_ns.class_("Light", light.LightOutput, cg.Component) -Single = Light.enum("Single", True) -Group = Light.enum("Group", True); +Single = Light.enum('Single', is_class=True) CONFIG_SCHEMA = light.light_schema(Light, light.LightType.RGB).extend({ cv.Required(CONF_NETWORK_ID): cv.use_id(Network), cv.Required(CONF_LIGHT_ID): cv.int_range(min=1, max=255), # TODO: use CONF_BLE_ID from CONF_NETWORK_ID... cv.GenerateID(esp32_ble.CONF_BLE_ID): cv.use_id(esp32_ble.ESP32BLE), + cv.Optional(CONF_REPEAT, default=5): cv.positive_not_null_int, }) diff --git a/components/brmesh/network.cpp b/components/brmesh/network.cpp index 9f39e33..a67c981 100644 --- a/components/brmesh/network.cpp +++ b/components/brmesh/network.cpp @@ -1,5 +1,6 @@ #include "network.h" +#include "address.h" #include "light.h" #include "whitening.h" @@ -132,8 +133,9 @@ std::span command(const std::span &buffer, const Key &key, Lig } std::span payload(const std::span &buffer, const Key &key, Light::Id id, uint8_t seq, const std::span &light_data) { - constexpr std::array ADDRESS = { 0xC3, 0x43, 0x83 }; - constexpr std::array PREFIX = { 0x71, 0x0F, 0x55 }; + constexpr Address ADDRESS = { 0xC1, 0xC2, 0xC3 }; + //constexpr std::array PREFIX = { 0x71, 0x0F, 0x55 }; + constexpr std::array PREFIX = { 0x8E, 0xF0, 0xAA }; const auto prefix = subspan(buffer, 0, PREFIX.size()); if (prefix.empty()) @@ -175,8 +177,8 @@ std::span payload(const std::span &buffer, const Key &key, Lig //ESP_LOGV(TAG, "%c%02hhX: raw: %s", id.kind(), id.value(), // format_hex_pretty(&result[0], result.size()).c_str()); - for (auto &byte:prefix) - byte = reverse_bits(byte); + //for (auto &byte:prefix) + // byte = reverse_bits(byte); //ESP_LOGV(TAG, "%c%02hhX: reverse: %s", id.kind(), id.value(), // format_hex_pretty(&result[0], result.size()).c_str()); @@ -254,11 +256,9 @@ Network::advertise(Light::Id id, const std::span &payload) { return; auto err = ESP_OK; -#if 0 err = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, tx_power_); if (err != ESP_OK) ESP_LOGW(TAG, "%c%02hhX: tx power set: %s", id.kind(), id.value(), esp_err_to_name(err)); -#endif advertise_ = true; err = esp_ble_gap_config_adv_data_raw(&data.front(), data.size()); diff --git a/components/brmesh/output.h b/components/brmesh/output.h new file mode 100644 index 0000000..51c8e31 --- /dev/null +++ b/components/brmesh/output.h @@ -0,0 +1,35 @@ +#pragma once + +namespace esphome { +namespace brmesh { + +class Output : public Component, public light::LightOutput +{ +public: + virtual const char *kind() const = 0; + virtual uint8_t id() const = 0; + + virtual std::span command(const std::span &output) const = 0; + + virtual void advertise(bool advertise) const; + + // interface: Component + void dump_config() override; + float get_setup_priority() const override { + return setup_priority::AFTER_BLUETOOTH; + } + void setup() override; + void loop() override; + + // interface: LightOutput + light::LightTraits get_traits() override; + void setup_state(light::LightState *state) override; + void update_state(light::LightState *state) override; + void write_state(light::LightState *state) override; + +private: + Network &network_; +}; + +} // namespace brmesh +} // namespace esphome