mirror of
https://github.com/esphome/esphome.git
synced 2025-07-29 06:36:45 +00:00
[online_image] Last-Modified-Date and ETag response caching (#8782)
This commit is contained in:
parent
04ee1a87e9
commit
1911269dc9
@ -213,7 +213,7 @@ async def to_code(config):
|
|||||||
|
|
||||||
for conf in config.get(CONF_ON_DOWNLOAD_FINISHED, []):
|
for conf in config.get(CONF_ON_DOWNLOAD_FINISHED, []):
|
||||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
await automation.build_automation(trigger, [], conf)
|
await automation.build_automation(trigger, [(bool, "cached")], conf)
|
||||||
|
|
||||||
for conf in config.get(CONF_ON_ERROR, []):
|
for conf in config.get(CONF_ON_ERROR, []):
|
||||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
static const char *const TAG = "online_image";
|
static const char *const TAG = "online_image";
|
||||||
|
static const char *const ETAG_HEADER_NAME = "etag";
|
||||||
|
static const char *const IF_NONE_MATCH_HEADER_NAME = "if-none-match";
|
||||||
|
static const char *const LAST_MODIFIED_HEADER_NAME = "last-modified";
|
||||||
|
static const char *const IF_MODIFIED_SINCE_HEADER_NAME = "if-modified-since";
|
||||||
|
|
||||||
#include "image_decoder.h"
|
#include "image_decoder.h"
|
||||||
|
|
||||||
@ -60,6 +64,8 @@ void OnlineImage::release() {
|
|||||||
this->height_ = 0;
|
this->height_ = 0;
|
||||||
this->buffer_width_ = 0;
|
this->buffer_width_ = 0;
|
||||||
this->buffer_height_ = 0;
|
this->buffer_height_ = 0;
|
||||||
|
this->last_modified_ = "";
|
||||||
|
this->etag_ = "";
|
||||||
this->end_connection_();
|
this->end_connection_();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,9 +133,17 @@ void OnlineImage::update() {
|
|||||||
}
|
}
|
||||||
accept_header.value = accept_mime_type + ",*/*;q=0.8";
|
accept_header.value = accept_mime_type + ",*/*;q=0.8";
|
||||||
|
|
||||||
|
if (!this->etag_.empty()) {
|
||||||
|
headers.push_back(http_request::Header{IF_NONE_MATCH_HEADER_NAME, this->etag_});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->last_modified_.empty()) {
|
||||||
|
headers.push_back(http_request::Header{IF_MODIFIED_SINCE_HEADER_NAME, this->last_modified_});
|
||||||
|
}
|
||||||
|
|
||||||
headers.push_back(accept_header);
|
headers.push_back(accept_header);
|
||||||
|
|
||||||
this->downloader_ = this->parent_->get(this->url_, headers);
|
this->downloader_ = this->parent_->get(this->url_, headers, {ETAG_HEADER_NAME, LAST_MODIFIED_HEADER_NAME});
|
||||||
|
|
||||||
if (this->downloader_ == nullptr) {
|
if (this->downloader_ == nullptr) {
|
||||||
ESP_LOGE(TAG, "Download failed.");
|
ESP_LOGE(TAG, "Download failed.");
|
||||||
@ -141,7 +155,9 @@ void OnlineImage::update() {
|
|||||||
int http_code = this->downloader_->status_code;
|
int http_code = this->downloader_->status_code;
|
||||||
if (http_code == HTTP_CODE_NOT_MODIFIED) {
|
if (http_code == HTTP_CODE_NOT_MODIFIED) {
|
||||||
// Image hasn't changed on server. Skip download.
|
// Image hasn't changed on server. Skip download.
|
||||||
|
ESP_LOGI(TAG, "Server returned HTTP 304 (Not Modified). Download skipped.");
|
||||||
this->end_connection_();
|
this->end_connection_();
|
||||||
|
this->download_finished_callback_.call(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (http_code != HTTP_CODE_OK) {
|
if (http_code != HTTP_CODE_OK) {
|
||||||
@ -201,8 +217,10 @@ void OnlineImage::loop() {
|
|||||||
ESP_LOGD(TAG, "Image fully downloaded, read %zu bytes, width/height = %d/%d", this->downloader_->get_bytes_read(),
|
ESP_LOGD(TAG, "Image fully downloaded, read %zu bytes, width/height = %d/%d", this->downloader_->get_bytes_read(),
|
||||||
this->width_, this->height_);
|
this->width_, this->height_);
|
||||||
ESP_LOGD(TAG, "Total time: %lds", ::time(nullptr) - this->start_time_);
|
ESP_LOGD(TAG, "Total time: %lds", ::time(nullptr) - this->start_time_);
|
||||||
|
this->etag_ = this->downloader_->get_response_header(ETAG_HEADER_NAME);
|
||||||
|
this->last_modified_ = this->downloader_->get_response_header(LAST_MODIFIED_HEADER_NAME);
|
||||||
|
this->download_finished_callback_.call(false);
|
||||||
this->end_connection_();
|
this->end_connection_();
|
||||||
this->download_finished_callback_.call();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this->downloader_ == nullptr) {
|
if (this->downloader_ == nullptr) {
|
||||||
@ -325,7 +343,7 @@ bool OnlineImage::validate_url_(const std::string &url) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnlineImage::add_on_finished_callback(std::function<void()> &&callback) {
|
void OnlineImage::add_on_finished_callback(std::function<void(bool)> &&callback) {
|
||||||
this->download_finished_callback_.add(std::move(callback));
|
this->download_finished_callback_.add(std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +63,8 @@ class OnlineImage : public PollingComponent,
|
|||||||
if (this->validate_url_(url)) {
|
if (this->validate_url_(url)) {
|
||||||
this->url_ = url;
|
this->url_ = url;
|
||||||
}
|
}
|
||||||
|
this->etag_ = "";
|
||||||
|
this->last_modified_ = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,7 +88,7 @@ class OnlineImage : public PollingComponent,
|
|||||||
*/
|
*/
|
||||||
size_t resize_download_buffer(size_t size) { return this->download_buffer_.resize(size); }
|
size_t resize_download_buffer(size_t size) { return this->download_buffer_.resize(size); }
|
||||||
|
|
||||||
void add_on_finished_callback(std::function<void()> &&callback);
|
void add_on_finished_callback(std::function<void(bool)> &&callback);
|
||||||
void add_on_error_callback(std::function<void()> &&callback);
|
void add_on_error_callback(std::function<void()> &&callback);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -131,7 +133,7 @@ class OnlineImage : public PollingComponent,
|
|||||||
|
|
||||||
void end_connection_();
|
void end_connection_();
|
||||||
|
|
||||||
CallbackManager<void()> download_finished_callback_{};
|
CallbackManager<void(bool)> download_finished_callback_{};
|
||||||
CallbackManager<void()> download_error_callback_{};
|
CallbackManager<void()> download_error_callback_{};
|
||||||
|
|
||||||
std::shared_ptr<http_request::HttpContainer> downloader_{nullptr};
|
std::shared_ptr<http_request::HttpContainer> downloader_{nullptr};
|
||||||
@ -173,6 +175,14 @@ class OnlineImage : public PollingComponent,
|
|||||||
* decoded images).
|
* decoded images).
|
||||||
*/
|
*/
|
||||||
int buffer_height_;
|
int buffer_height_;
|
||||||
|
/**
|
||||||
|
* The value of the ETag HTTP header provided in the last response.
|
||||||
|
*/
|
||||||
|
std::string etag_ = "";
|
||||||
|
/**
|
||||||
|
* The value of the Last-Modified HTTP header provided in the last response.
|
||||||
|
*/
|
||||||
|
std::string last_modified_ = "";
|
||||||
|
|
||||||
time_t start_time_;
|
time_t start_time_;
|
||||||
|
|
||||||
@ -202,10 +212,10 @@ template<typename... Ts> class OnlineImageReleaseAction : public Action<Ts...> {
|
|||||||
OnlineImage *parent_;
|
OnlineImage *parent_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DownloadFinishedTrigger : public Trigger<> {
|
class DownloadFinishedTrigger : public Trigger<bool> {
|
||||||
public:
|
public:
|
||||||
explicit DownloadFinishedTrigger(OnlineImage *parent) {
|
explicit DownloadFinishedTrigger(OnlineImage *parent) {
|
||||||
parent->add_on_finished_callback([this]() { this->trigger(); });
|
parent->add_on_finished_callback([this](bool cached) { this->trigger(cached); });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,6 +11,13 @@ online_image:
|
|||||||
format: PNG
|
format: PNG
|
||||||
type: BINARY
|
type: BINARY
|
||||||
resize: 50x50
|
resize: 50x50
|
||||||
|
on_download_finished:
|
||||||
|
lambda: |-
|
||||||
|
if (cached) {
|
||||||
|
ESP_LOGD("online_image", "Cache hit: using cached image");
|
||||||
|
} else {
|
||||||
|
ESP_LOGD("online_image", "Cache miss: fresh download");
|
||||||
|
}
|
||||||
- id: online_binary_transparent_image
|
- id: online_binary_transparent_image
|
||||||
url: http://www.libpng.org/pub/png/img_png/pnglogo-blk-tiny.png
|
url: http://www.libpng.org/pub/png/img_png/pnglogo-blk-tiny.png
|
||||||
type: BINARY
|
type: BINARY
|
||||||
|
Loading…
x
Reference in New Issue
Block a user