wip
This commit is contained in:
parent
b83f7b8e16
commit
e797cdb349
6 changed files with 104 additions and 33 deletions
35
components/brmesh/address.h
Normal file
35
components/brmesh/address.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <span>
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace brmesh {
|
||||
|
||||
class Address : public std::array<uint8_t, 3> {
|
||||
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 <size_t size>
|
||||
std::span<uint8_t> set(const std::span<uint8_t, size> &dst) const {
|
||||
return set(std::span<uint8_t>(dst));
|
||||
}
|
||||
|
||||
std::span<uint8_t> set(const std::span<uint8_t> &dst) const {
|
||||
if (dst.size() < size())
|
||||
return {};
|
||||
std::copy(cbegin(), cend(), &dst[0]);
|
||||
return dst.subspan(0, size());
|
||||
}
|
||||
};
|
||||
} // namespace brmesh
|
||||
} // namespace esphome
|
||||
|
|
@ -188,6 +188,24 @@ Light::advertise(bool advertise) {
|
|||
network_.advertise(id_, {});
|
||||
}
|
||||
|
||||
std::span<uint8_t>
|
||||
Light::command(const std::span<uint8_t> &output) const
|
||||
{
|
||||
const auto hdr = output.subspan(0, 2);
|
||||
const auto dst = output.subspan(hdr.size());
|
||||
const auto src = std::span<const uint8_t>(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
|
||||
|
|
|
|||
|
|
@ -23,26 +23,24 @@ public:
|
|||
class Id : public std::variant<Single, Group> {
|
||||
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<uint8_t>(value); }
|
||||
static constexpr uint8_t value(Group value) { return static_cast<uint8_t>(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<uint8_t> command(const std::span<uint8_t> &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<uint8_t, 6> 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<uint8_t> adv_data_(const std::span<uint8_t, 31> &, uint8_t seq, light::LightState &);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
} // namespace brmesh
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
})
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "network.h"
|
||||
|
||||
#include "address.h"
|
||||
#include "light.h"
|
||||
#include "whitening.h"
|
||||
|
||||
|
|
@ -132,8 +133,9 @@ std::span<uint8_t> command(const std::span<uint8_t> &buffer, const Key &key, Lig
|
|||
}
|
||||
|
||||
std::span<uint8_t> payload(const std::span<uint8_t> &buffer, const Key &key, Light::Id id, uint8_t seq, const std::span<uint8_t> &light_data) {
|
||||
constexpr std::array<uint8_t, 3> ADDRESS = { 0xC3, 0x43, 0x83 };
|
||||
constexpr std::array<uint8_t, 3> PREFIX = { 0x71, 0x0F, 0x55 };
|
||||
constexpr Address ADDRESS = { 0xC1, 0xC2, 0xC3 };
|
||||
//constexpr std::array<uint8_t, 3> PREFIX = { 0x71, 0x0F, 0x55 };
|
||||
constexpr std::array<uint8_t, 3> PREFIX = { 0x8E, 0xF0, 0xAA };
|
||||
|
||||
const auto prefix = subspan(buffer, 0, PREFIX.size());
|
||||
if (prefix.empty())
|
||||
|
|
@ -175,8 +177,8 @@ std::span<uint8_t> payload(const std::span<uint8_t> &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<uint8_t> &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());
|
||||
|
|
|
|||
35
components/brmesh/output.h
Normal file
35
components/brmesh/output.h
Normal file
|
|
@ -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<uint8_t> command(const std::span<uint8_t> &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
|
||||
Loading…
Add table
Add a link
Reference in a new issue