mirror of
https://github.com/esphome/esphome.git
synced 2024-11-23 23:48:11 +01:00
added the web server option
This commit is contained in:
parent
c05ac32352
commit
cace9706be
5 changed files with 82 additions and 5 deletions
|
@ -4,12 +4,16 @@ import esphome.config_validation as cv
|
||||||
from esphome import automation, yaml_util
|
from esphome import automation, yaml_util
|
||||||
from esphome.core import CORE
|
from esphome.core import CORE
|
||||||
from esphome.config import strip_default_ids
|
from esphome.config import strip_default_ids
|
||||||
|
from esphome.components import web_server_base
|
||||||
|
from esphome.components.web_server_base import CONF_WEB_SERVER_BASE_ID
|
||||||
|
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
|
CONF_URL,
|
||||||
)
|
)
|
||||||
|
|
||||||
CODEOWNERS = ["@gabest11"]
|
CODEOWNERS = ["@gabest11"]
|
||||||
|
AUTO_LOAD = ["web_server_base"]
|
||||||
CONF_SHOW_IN_DUMP_CONFIG = "show_in_dump_config"
|
CONF_SHOW_IN_DUMP_CONFIG = "show_in_dump_config"
|
||||||
CONF_SHOW_SECRETS = "show_secrets"
|
CONF_SHOW_SECRETS = "show_secrets"
|
||||||
|
|
||||||
|
@ -21,6 +25,10 @@ CONFIG_SCHEMA = cv.Schema(
|
||||||
cv.GenerateID(): cv.declare_id(StoreYamlComponent),
|
cv.GenerateID(): cv.declare_id(StoreYamlComponent),
|
||||||
cv.Optional(CONF_SHOW_IN_DUMP_CONFIG, default=False): cv.boolean,
|
cv.Optional(CONF_SHOW_IN_DUMP_CONFIG, default=False): cv.boolean,
|
||||||
cv.Optional(CONF_SHOW_SECRETS, default=False): cv.boolean,
|
cv.Optional(CONF_SHOW_SECRETS, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_URL): cv.string_strict,
|
||||||
|
cv.GenerateID(CONF_WEB_SERVER_BASE_ID): cv.use_id(
|
||||||
|
web_server_base.WebServerBase
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -88,6 +96,9 @@ async def to_code(config):
|
||||||
size_t = f"const size_t ESPHOME_YAML_SIZE = {size}"
|
size_t = f"const size_t ESPHOME_YAML_SIZE = {size}"
|
||||||
cg.add_global(cg.RawExpression(uint8_t))
|
cg.add_global(cg.RawExpression(uint8_t))
|
||||||
cg.add_global(cg.RawExpression(size_t))
|
cg.add_global(cg.RawExpression(size_t))
|
||||||
|
if CONF_URL in config:
|
||||||
|
webserver = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID])
|
||||||
|
cg.add(var.set_web_server(webserver, config[CONF_URL]))
|
||||||
|
|
||||||
|
|
||||||
LogAction = store_yaml_ns.class_("LogAction", automation.Action)
|
LogAction = store_yaml_ns.class_("LogAction", automation.Action)
|
||||||
|
|
|
@ -19,7 +19,7 @@ void Decompressor::reset() {
|
||||||
this->buff_ = 0;
|
this->buff_ = 0;
|
||||||
this->codes_.clear();
|
this->codes_.clear();
|
||||||
for (uint32_t i = 0; i < 256; i++) {
|
for (uint32_t i = 0; i < 256; i++) {
|
||||||
this->codes_.push_back(Entry{.p = 0, .c = i});
|
this->codes_.push_back(Entry{.p = 0, .c = (uint8_t) i});
|
||||||
}
|
}
|
||||||
this->code_width_ = 9; // log2next + 1
|
this->code_width_ = 9; // log2next + 1
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,10 @@ std::string Decompressor::get_next() {
|
||||||
this->prev_.c = s[0];
|
this->prev_.c = s[0];
|
||||||
this->codes_.push_back(this->prev_);
|
this->codes_.push_back(this->prev_);
|
||||||
this->prev_.p = code;
|
this->prev_.p = code;
|
||||||
|
if (this->is_eof()) {
|
||||||
|
// free code table, no longer needed
|
||||||
|
this->codes_.clear();
|
||||||
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,11 @@ namespace esphome {
|
||||||
namespace store_yaml {
|
namespace store_yaml {
|
||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
uint32_t p : 24;
|
// uint32_t p : 24;
|
||||||
uint32_t c : 8;
|
// uint32_t c : 8;
|
||||||
};
|
uint16_t p; // save 1 byte, this reduces the number of code words to 65536, more than enough for configs
|
||||||
|
uint8_t c;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
class Decompressor {
|
class Decompressor {
|
||||||
const uint8_t *data_ptr_;
|
const uint8_t *data_ptr_;
|
||||||
|
|
|
@ -18,6 +18,13 @@ void StoreYamlComponent::dump_config() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StoreYamlComponent::setup() {
|
||||||
|
if (this->web_server_ != nullptr) {
|
||||||
|
this->web_server_->init();
|
||||||
|
this->web_server_->add_handler(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void StoreYamlComponent::loop() {
|
void StoreYamlComponent::loop() {
|
||||||
if (this->dec_) {
|
if (this->dec_) {
|
||||||
std::string row;
|
std::string row;
|
||||||
|
@ -34,5 +41,48 @@ void StoreYamlComponent::log() {
|
||||||
this->dec_ = make_unique<RowDecompressor>(ESPHOME_YAML, ESPHOME_YAML_SIZE);
|
this->dec_ = make_unique<RowDecompressor>(ESPHOME_YAML, ESPHOME_YAML_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StoreYamlComponent::set_web_server(web_server_base::WebServerBase *web_server, const std::string &url) {
|
||||||
|
this->web_server_ = web_server;
|
||||||
|
this->web_server_url_ = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StoreYamlComponent::canHandle(AsyncWebServerRequest *request) {
|
||||||
|
return request->method() == HTTP_GET && request->url() == this->web_server_url_.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StoreYamlComponent::handleRequest(AsyncWebServerRequest *request) {
|
||||||
|
#ifdef USE_ARDUINO
|
||||||
|
auto cb = [this](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
|
||||||
|
uint8_t *ptr = buffer;
|
||||||
|
// 5KB+ config file with a single character repeating will result in a 100 byte long word, not likely
|
||||||
|
while (maxLen > 100 && !(this->web_dec_ && this->web_dec_->is_eof())) {
|
||||||
|
std::string s;
|
||||||
|
if (!this->web_dec_) {
|
||||||
|
this->web_dec_ = make_unique<Decompressor>(ESPHOME_YAML, ESPHOME_YAML_SIZE);
|
||||||
|
s = this->web_dec_->get_first();
|
||||||
|
} else {
|
||||||
|
s = this->web_dec_->get_next();
|
||||||
|
}
|
||||||
|
size_t len = std::min(maxLen, s.size());
|
||||||
|
memcpy(ptr, s.c_str(), len);
|
||||||
|
ptr += len;
|
||||||
|
maxLen -= len;
|
||||||
|
}
|
||||||
|
return ptr - buffer;
|
||||||
|
};
|
||||||
|
AsyncWebServerResponse *response = request->beginChunkedResponse("text/plain;charset=UTF-8", cb);
|
||||||
|
#else
|
||||||
|
AsyncResponseStream *response = request->beginResponseStream("text/plain;charset=UTF-8");
|
||||||
|
auto dec = make_unique<Decompressor>(ESPHOME_YAML, ESPHOME_YAML_SIZE);
|
||||||
|
response->print(dec->get_first().c_str());
|
||||||
|
while (!dec->is_eof()) {
|
||||||
|
response->print(dec->get_next().c_str());
|
||||||
|
}
|
||||||
|
dec = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace store_yaml
|
} // namespace store_yaml
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/automation.h"
|
#include "esphome/core/automation.h"
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/components/web_server_base/web_server_base.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "decompressor.h"
|
#include "decompressor.h"
|
||||||
|
|
||||||
|
@ -12,15 +13,24 @@ extern const size_t ESPHOME_YAML_SIZE;
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace store_yaml {
|
namespace store_yaml {
|
||||||
|
|
||||||
class StoreYamlComponent : public Component {
|
class StoreYamlComponent : public Component, public AsyncWebHandler {
|
||||||
std::unique_ptr<RowDecompressor> dec_;
|
std::unique_ptr<RowDecompressor> dec_;
|
||||||
bool show_in_dump_config_{false};
|
bool show_in_dump_config_{false};
|
||||||
|
|
||||||
|
web_server_base::WebServerBase *web_server_;
|
||||||
|
std::string web_server_url_;
|
||||||
|
std::unique_ptr<Decompressor> web_dec_;
|
||||||
|
bool canHandle(AsyncWebServerRequest *request) override;
|
||||||
|
void handleRequest(AsyncWebServerRequest *request) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::WIFI - 1.0f; }
|
||||||
|
void setup() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
void log();
|
void log();
|
||||||
void set_show_in_dump_config(bool show) { this->show_in_dump_config_ = show; }
|
void set_show_in_dump_config(bool show) { this->show_in_dump_config_ = show; }
|
||||||
|
void set_web_server(web_server_base::WebServerBase *web_server, const std::string &url);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class LogAction : public Action<Ts...>, public Parented<StoreYamlComponent> {
|
template<typename... Ts> class LogAction : public Action<Ts...>, public Parented<StoreYamlComponent> {
|
||||||
|
|
Loading…
Reference in a new issue