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_, {});
|
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
|
void
|
||||||
Light::loop() {
|
Light::loop() {
|
||||||
disable_loop();
|
disable_loop();
|
||||||
|
|
@ -247,7 +265,7 @@ Light::write_state(light::LightState *state) {
|
||||||
count_ = 0;
|
count_ = 0;
|
||||||
//ESP_LOGD(TAG, "%c%02hhX: state: %s", id_.kind(), id_.value(),
|
//ESP_LOGD(TAG, "%c%02hhX: state: %s", id_.kind(), id_.value(),
|
||||||
// format_hex_pretty(&payload[0], payload.size()).c_str());
|
// format_hex_pretty(&payload[0], payload.size()).c_str());
|
||||||
enable_loop();
|
//enable_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace brmesh
|
} // namespace brmesh
|
||||||
|
|
|
||||||
|
|
@ -23,26 +23,24 @@ public:
|
||||||
class Id : public std::variant<Single, Group> {
|
class Id : public std::variant<Single, Group> {
|
||||||
public:
|
public:
|
||||||
using variant::variant;
|
using variant::variant;
|
||||||
|
constexpr Id(uint8_t value) : variant(Single{value}) {}
|
||||||
|
|
||||||
static constexpr char kind(Single) { return 'L'; }
|
static constexpr char kind(Single) { return 'L'; }
|
||||||
static constexpr char kind(Group) { return 'G'; }
|
static constexpr char kind(Group) { return 'G'; }
|
||||||
constexpr char kind() {
|
constexpr char kind() const {
|
||||||
return std::visit([](auto &&value) { return Id::kind(value); }, *this);
|
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(Single value) { return static_cast<uint8_t>(value); }
|
||||||
static constexpr uint8_t value(Group 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);
|
return std::visit([](auto &&value) { return Id::value(value); }, *this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Light(Id id, Network *network) : id_(id), network_(*network) {}
|
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
|
// interface: Component
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
float get_setup_priority() const override {
|
float get_setup_priority() const override {
|
||||||
|
|
@ -59,31 +57,16 @@ public:
|
||||||
|
|
||||||
// callback
|
// callback
|
||||||
void advertise(bool advertise);
|
void advertise(bool advertise);
|
||||||
|
|
||||||
|
std::span<uint8_t> command(const std::span<uint8_t> &output) const;
|
||||||
private:
|
private:
|
||||||
Id id_;
|
Id id_;
|
||||||
Network &network_;
|
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;
|
uint8_t count_ = 0;
|
||||||
bool advertising_ = false;
|
bool advertising_ = false;
|
||||||
|
|
||||||
std::array<uint8_t, 6> payload_ = {};
|
std::array<uint8_t, 6> payload_ = {};
|
||||||
size_t payload_length_ = 0;
|
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
|
} // namespace brmesh
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.cpp_generator import LambdaExpression
|
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.core import HexInt
|
||||||
from esphome.components import light, esp32_ble
|
from esphome.components import light, esp32_ble
|
||||||
|
|
||||||
|
|
@ -15,14 +15,14 @@ AUTO_LOAD = ["light"]
|
||||||
CONF_NETWORK_ID = "network"
|
CONF_NETWORK_ID = "network"
|
||||||
|
|
||||||
Light = brmesh_ns.class_("Light", light.LightOutput, cg.Component)
|
Light = brmesh_ns.class_("Light", light.LightOutput, cg.Component)
|
||||||
Single = Light.enum("Single", True)
|
Single = Light.enum('Single', is_class=True)
|
||||||
Group = Light.enum("Group", True);
|
|
||||||
|
|
||||||
CONFIG_SCHEMA = light.light_schema(Light, light.LightType.RGB).extend({
|
CONFIG_SCHEMA = light.light_schema(Light, light.LightType.RGB).extend({
|
||||||
cv.Required(CONF_NETWORK_ID): cv.use_id(Network),
|
cv.Required(CONF_NETWORK_ID): cv.use_id(Network),
|
||||||
cv.Required(CONF_LIGHT_ID): cv.int_range(min=1, max=255),
|
cv.Required(CONF_LIGHT_ID): cv.int_range(min=1, max=255),
|
||||||
# TODO: use CONF_BLE_ID from CONF_NETWORK_ID...
|
# TODO: use CONF_BLE_ID from CONF_NETWORK_ID...
|
||||||
cv.GenerateID(esp32_ble.CONF_BLE_ID): cv.use_id(esp32_ble.ESP32BLE),
|
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 "network.h"
|
||||||
|
|
||||||
|
#include "address.h"
|
||||||
#include "light.h"
|
#include "light.h"
|
||||||
#include "whitening.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) {
|
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 Address ADDRESS = { 0xC1, 0xC2, 0xC3 };
|
||||||
constexpr std::array<uint8_t, 3> PREFIX = { 0x71, 0x0F, 0x55 };
|
//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());
|
const auto prefix = subspan(buffer, 0, PREFIX.size());
|
||||||
if (prefix.empty())
|
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(),
|
//ESP_LOGV(TAG, "%c%02hhX: raw: %s", id.kind(), id.value(),
|
||||||
// format_hex_pretty(&result[0], result.size()).c_str());
|
// format_hex_pretty(&result[0], result.size()).c_str());
|
||||||
|
|
||||||
for (auto &byte:prefix)
|
//for (auto &byte:prefix)
|
||||||
byte = reverse_bits(byte);
|
// byte = reverse_bits(byte);
|
||||||
|
|
||||||
//ESP_LOGV(TAG, "%c%02hhX: reverse: %s", id.kind(), id.value(),
|
//ESP_LOGV(TAG, "%c%02hhX: reverse: %s", id.kind(), id.value(),
|
||||||
// format_hex_pretty(&result[0], result.size()).c_str());
|
// 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;
|
return;
|
||||||
|
|
||||||
auto err = ESP_OK;
|
auto err = ESP_OK;
|
||||||
#if 0
|
|
||||||
err = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, tx_power_);
|
err = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, tx_power_);
|
||||||
if (err != ESP_OK)
|
if (err != ESP_OK)
|
||||||
ESP_LOGW(TAG, "%c%02hhX: tx power set: %s", id.kind(), id.value(), esp_err_to_name(err));
|
ESP_LOGW(TAG, "%c%02hhX: tx power set: %s", id.kind(), id.value(), esp_err_to_name(err));
|
||||||
#endif
|
|
||||||
|
|
||||||
advertise_ = true;
|
advertise_ = true;
|
||||||
err = esp_ble_gap_config_adv_data_raw(&data.front(), data.size());
|
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