Merge branch 'dev' into dev

This commit is contained in:
Jesse Hills 2024-10-14 09:01:24 +13:00 committed by GitHub
commit 5db3078199
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 96 additions and 35 deletions

View File

@ -315,7 +315,9 @@ jobs:
key: platformio-${{ matrix.pio_cache_key }}
- name: Install clang-tidy
run: sudo apt-get install clang-tidy-14
run: |
sudo apt-get update
sudo apt-get install clang-tidy-14
- name: Register problem matchers
run: |
@ -397,7 +399,9 @@ jobs:
file: ${{ fromJson(needs.list-components.outputs.components) }}
steps:
- name: Install dependencies
run: sudo apt-get install libsdl2-dev
run: |
sudo apt-get update
sudo apt-get install libsdl2-dev
- name: Check out code from GitHub
uses: actions/checkout@v4.1.7
@ -451,7 +455,9 @@ jobs:
run: echo ${{ matrix.components }}
- name: Install dependencies
run: sudo apt-get install libsdl2-dev
run: |
sudo apt-get update
sudo apt-get install libsdl2-dev
- name: Check out code from GitHub
uses: actions/checkout@v4.1.7

View File

@ -22,7 +22,7 @@ void ESP32RMTLEDStripLightOutput::setup() {
size_t buffer_size = this->get_buffer_size_();
ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
RAMAllocator<uint8_t> allocator(this->use_psram_ ? 0 : RAMAllocator<uint8_t>::ALLOC_INTERNAL);
this->buf_ = allocator.allocate(buffer_size);
if (this->buf_ == nullptr) {
ESP_LOGE(TAG, "Cannot allocate LED buffer!");
@ -37,7 +37,7 @@ void ESP32RMTLEDStripLightOutput::setup() {
return;
}
ExternalRAMAllocator<rmt_item32_t> rmt_allocator(ExternalRAMAllocator<rmt_item32_t>::ALLOW_FAILURE);
RAMAllocator<rmt_item32_t> rmt_allocator(this->use_psram_ ? 0 : RAMAllocator<rmt_item32_t>::ALLOC_INTERNAL);
this->rmt_buf_ = rmt_allocator.allocate(buffer_size * 8 +
1); // 8 bits per byte, 1 rmt_item32_t per bit + 1 rmt_item32_t for reset

View File

@ -45,6 +45,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight {
void set_num_leds(uint16_t num_leds) { this->num_leds_ = num_leds; }
void set_is_rgbw(bool is_rgbw) { this->is_rgbw_ = is_rgbw; }
void set_is_wrgb(bool is_wrgb) { this->is_wrgb_ = is_wrgb; }
void set_use_psram(bool use_psram) { this->use_psram_ = use_psram; }
/// Set a maximum refresh rate in µs as some lights do not like being updated too often.
void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; }
@ -75,6 +76,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight {
uint16_t num_leds_;
bool is_rgbw_;
bool is_wrgb_;
bool use_psram_;
rmt_item32_t bit0_, bit1_, reset_;
RGBOrder rgb_order_;

View File

@ -55,7 +55,7 @@ CHIPSETS = {
"SM16703": LEDStripTimings(300, 900, 900, 300, 0, 0),
}
CONF_USE_PSRAM = "use_psram"
CONF_IS_WRGB = "is_wrgb"
CONF_BIT0_HIGH = "bit0_high"
CONF_BIT0_LOW = "bit0_low"
@ -77,6 +77,7 @@ CONFIG_SCHEMA = cv.All(
cv.Optional(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True),
cv.Optional(CONF_IS_RGBW, default=False): cv.boolean,
cv.Optional(CONF_IS_WRGB, default=False): cv.boolean,
cv.Optional(CONF_USE_PSRAM, default=True): cv.boolean,
cv.Inclusive(
CONF_BIT0_HIGH,
"custom",
@ -145,6 +146,7 @@ async def to_code(config):
cg.add(var.set_rgb_order(config[CONF_RGB_ORDER]))
cg.add(var.set_is_rgbw(config[CONF_IS_RGBW]))
cg.add(var.set_is_wrgb(config[CONF_IS_WRGB]))
cg.add(var.set_use_psram(config[CONF_USE_PSRAM]))
cg.add(
var.set_rmt_channel(

View File

@ -1,6 +1,6 @@
from esphome import automation
import esphome.codegen as cg
from esphome.components import mqtt
from esphome.components import mqtt, web_server
import esphome.config_validation as cv
from esphome.const import (
CONF_DEVICE_CLASS,
@ -11,6 +11,7 @@ from esphome.const import (
CONF_MQTT_ID,
CONF_ON_EVENT,
CONF_TRIGGER_ID,
CONF_WEB_SERVER,
DEVICE_CLASS_BUTTON,
DEVICE_CLASS_DOORBELL,
DEVICE_CLASS_EMPTY,
@ -40,17 +41,21 @@ EventTrigger = event_ns.class_("EventTrigger", automation.Trigger.template())
validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
EVENT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
{
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTEventComponent),
cv.GenerateID(): cv.declare_id(Event),
cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
cv.Optional(CONF_ON_EVENT): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(EventTrigger),
}
),
}
EVENT_SCHEMA = (
cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
.extend(cv.MQTT_COMPONENT_SCHEMA)
.extend(
{
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTEventComponent),
cv.GenerateID(): cv.declare_id(Event),
cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
cv.Optional(CONF_ON_EVENT): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(EventTrigger),
}
),
}
)
)
_UNDEF = object()
@ -97,6 +102,9 @@ async def setup_event_core_(var, config, *, event_types: list[str]):
mqtt_ = cg.new_Pvariable(mqtt_id, var)
await mqtt.register_mqtt_component(mqtt_, config)
if web_server_config := config.get(CONF_WEB_SERVER):
await web_server.add_entity_config(var, web_server_config)
async def register_event(var, config, *, event_types: list[str]):
if not CORE.has_id(config[CONF_ID]):

View File

@ -1441,9 +1441,26 @@ std::string WebServer::alarm_control_panel_json(alarm_control_panel::AlarmContro
void WebServer::on_event(event::Event *obj, const std::string &event_type) {
this->events_.send(this->event_json(obj, event_type, DETAIL_STATE).c_str(), "state");
}
void WebServer::handle_event_request(AsyncWebServerRequest *request, const UrlMatch &match) {
for (event::Event *obj : App.get_events()) {
if (obj->get_object_id() != match.id)
continue;
if (request->method() == HTTP_GET && match.method.empty()) {
auto detail = DETAIL_STATE;
auto *param = request->getParam("detail");
if (param && param->value() == "all") {
detail = DETAIL_ALL;
}
std::string data = this->event_json(obj, "", detail);
request->send(200, "application/json", data.c_str());
return;
}
}
request->send(404);
}
std::string WebServer::event_json(event::Event *obj, const std::string &event_type, JsonDetail start_config) {
return json::build_json([obj, event_type, start_config](JsonObject root) {
return json::build_json([this, obj, event_type, start_config](JsonObject root) {
set_json_id(root, obj, "event-" + obj->get_object_id(), start_config);
if (!event_type.empty()) {
root["event_type"] = event_type;
@ -1454,6 +1471,12 @@ std::string WebServer::event_json(event::Event *obj, const std::string &event_ty
event_types.add(event_type);
}
root["device_class"] = obj->get_device_class();
if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
root["sorting_weight"] = this->sorting_entitys_[obj].weight;
if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
}
}
}
});
}
@ -1645,6 +1668,11 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) {
return true;
#endif
#ifdef USE_EVENT
if (request->method() == HTTP_GET && match.domain == "event")
return true;
#endif
#ifdef USE_UPDATE
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "update")
return true;

View File

@ -322,6 +322,9 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
#ifdef USE_EVENT
void on_event(event::Event *obj, const std::string &event_type) override;
/// Handle a event request under '/event<id>'.
void handle_event_request(AsyncWebServerRequest *request, const UrlMatch &match);
/// Dump the event details with its value as a JSON string.
std::string event_json(event::Event *obj, const std::string &event_type, JsonDetail start_config);
#endif

View File

@ -651,35 +651,45 @@ void delay_microseconds_safe(uint32_t us);
/// @name Memory management
///@{
/** An STL allocator that uses SPI RAM.
/** An STL allocator that uses SPI or internal RAM.
* Returns `nullptr` in case no memory is available.
*
* By setting flags, it can be configured to don't try main memory if SPI RAM is full or unavailable, and to return
* `nulllptr` instead of aborting when no memory is available.
* By setting flags, it can be configured to:
* - perform external allocation falling back to main memory if SPI RAM is full or unavailable
* - perform external allocation only
* - perform internal allocation only
*/
template<class T> class ExternalRAMAllocator {
template<class T> class RAMAllocator {
public:
using value_type = T;
enum Flags {
NONE = 0,
REFUSE_INTERNAL = 1 << 0, ///< Refuse falling back to internal memory when external RAM is full or unavailable.
ALLOW_FAILURE = 1 << 1, ///< Don't abort when memory allocation fails.
NONE = 0, // Perform external allocation and fall back to internal memory
ALLOC_EXTERNAL = 1 << 0, // Perform external allocation only.
ALLOC_INTERNAL = 1 << 1, // Perform internal allocation only.
ALLOW_FAILURE = 1 << 2, // Does nothing. Kept for compatibility.
};
ExternalRAMAllocator() = default;
ExternalRAMAllocator(Flags flags) : flags_{flags} {}
template<class U> constexpr ExternalRAMAllocator(const ExternalRAMAllocator<U> &other) : flags_{other.flags_} {}
RAMAllocator() = default;
RAMAllocator(uint8_t flags) : flags_{flags} {}
template<class U> constexpr RAMAllocator(const RAMAllocator<U> &other) : flags_{other.flags_} {}
T *allocate(size_t n) {
size_t size = n * sizeof(T);
T *ptr = nullptr;
#ifdef USE_ESP32
ptr = static_cast<T *>(heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
#endif
if (ptr == nullptr && (this->flags_ & Flags::REFUSE_INTERNAL) == 0)
// External allocation by default or if explicitely requested
if ((this->flags_ & Flags::ALLOC_EXTERNAL) || ((this->flags_ & Flags::ALLOC_INTERNAL) == 0)) {
ptr = static_cast<T *>(heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
}
// Fallback to internal allocation if explicitely requested or no flag is specified
if (ptr == nullptr && ((this->flags_ & Flags::ALLOC_INTERNAL) || (this->flags_ & Flags::ALLOC_EXTERNAL) == 0)) {
ptr = static_cast<T *>(malloc(size)); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
if (ptr == nullptr && (this->flags_ & Flags::ALLOW_FAILURE) == 0)
abort();
}
#else
// Ignore ALLOC_EXTERNAL/ALLOC_INTERNAL flags if external allocation is not supported
ptr = static_cast<T *>(malloc(size)); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
#endif
return ptr;
}
@ -688,9 +698,11 @@ template<class T> class ExternalRAMAllocator {
}
private:
Flags flags_{Flags::ALLOW_FAILURE};
uint8_t flags_{Flags::ALLOW_FAILURE};
};
template<class T> using ExternalRAMAllocator = RAMAllocator<T>;
/// @}
/// @name Internal functions