mirror of
https://github.com/esphome/esphome.git
synced 2025-07-29 22:56:37 +00:00
[update, http_request_update] Implement update available trigger (#9174)
This commit is contained in:
parent
b6fade7339
commit
1368139f4d
@ -50,7 +50,8 @@ void HttpRequestUpdate::update_task(void *params) {
|
|||||||
|
|
||||||
if (container == nullptr || container->status_code != HTTP_STATUS_OK) {
|
if (container == nullptr || container->status_code != HTTP_STATUS_OK) {
|
||||||
std::string msg = str_sprintf("Failed to fetch manifest from %s", this_update->source_url_.c_str());
|
std::string msg = str_sprintf("Failed to fetch manifest from %s", this_update->source_url_.c_str());
|
||||||
this_update->status_set_error(msg.c_str());
|
// Defer to main loop to avoid race condition on component_state_ read-modify-write
|
||||||
|
this_update->defer([this_update, msg]() { this_update->status_set_error(msg.c_str()); });
|
||||||
UPDATE_RETURN;
|
UPDATE_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +59,8 @@ void HttpRequestUpdate::update_task(void *params) {
|
|||||||
uint8_t *data = allocator.allocate(container->content_length);
|
uint8_t *data = allocator.allocate(container->content_length);
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
std::string msg = str_sprintf("Failed to allocate %zu bytes for manifest", container->content_length);
|
std::string msg = str_sprintf("Failed to allocate %zu bytes for manifest", container->content_length);
|
||||||
this_update->status_set_error(msg.c_str());
|
// Defer to main loop to avoid race condition on component_state_ read-modify-write
|
||||||
|
this_update->defer([this_update, msg]() { this_update->status_set_error(msg.c_str()); });
|
||||||
container->end();
|
container->end();
|
||||||
UPDATE_RETURN;
|
UPDATE_RETURN;
|
||||||
}
|
}
|
||||||
@ -120,7 +122,8 @@ void HttpRequestUpdate::update_task(void *params) {
|
|||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
std::string msg = str_sprintf("Failed to parse JSON from %s", this_update->source_url_.c_str());
|
std::string msg = str_sprintf("Failed to parse JSON from %s", this_update->source_url_.c_str());
|
||||||
this_update->status_set_error(msg.c_str());
|
// Defer to main loop to avoid race condition on component_state_ read-modify-write
|
||||||
|
this_update->defer([this_update, msg]() { this_update->status_set_error(msg.c_str()); });
|
||||||
UPDATE_RETURN;
|
UPDATE_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,19 +150,35 @@ void HttpRequestUpdate::update_task(void *params) {
|
|||||||
this_update->update_info_.current_version = current_version;
|
this_update->update_info_.current_version = current_version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool trigger_update_available = false;
|
||||||
|
|
||||||
if (this_update->update_info_.latest_version.empty() ||
|
if (this_update->update_info_.latest_version.empty() ||
|
||||||
this_update->update_info_.latest_version == this_update->update_info_.current_version) {
|
this_update->update_info_.latest_version == this_update->update_info_.current_version) {
|
||||||
this_update->state_ = update::UPDATE_STATE_NO_UPDATE;
|
this_update->state_ = update::UPDATE_STATE_NO_UPDATE;
|
||||||
} else {
|
} else {
|
||||||
|
if (this_update->state_ != update::UPDATE_STATE_AVAILABLE) {
|
||||||
|
trigger_update_available = true;
|
||||||
|
}
|
||||||
this_update->state_ = update::UPDATE_STATE_AVAILABLE;
|
this_update->state_ = update::UPDATE_STATE_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Defer to main loop to ensure thread-safe execution of:
|
||||||
|
// - status_clear_error() performs non-atomic read-modify-write on component_state_
|
||||||
|
// - publish_state() triggers API callbacks that write to the shared protobuf buffer
|
||||||
|
// which can be corrupted if accessed concurrently from task and main loop threads
|
||||||
|
// - update_available trigger to ensure consistent state when the trigger fires
|
||||||
|
this_update->defer([this_update, trigger_update_available]() {
|
||||||
this_update->update_info_.has_progress = false;
|
this_update->update_info_.has_progress = false;
|
||||||
this_update->update_info_.progress = 0.0f;
|
this_update->update_info_.progress = 0.0f;
|
||||||
|
|
||||||
this_update->status_clear_error();
|
this_update->status_clear_error();
|
||||||
this_update->publish_state();
|
this_update->publish_state();
|
||||||
|
|
||||||
|
if (trigger_update_available) {
|
||||||
|
this_update->get_update_available_trigger()->trigger(this_update->update_info_);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
UPDATE_RETURN;
|
UPDATE_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include "esphome/core/automation.h"
|
#include "esphome/core/automation.h"
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/entity_base.h"
|
#include "esphome/core/entity_base.h"
|
||||||
@ -38,12 +39,19 @@ class UpdateEntity : public EntityBase, public EntityBase_DeviceClass {
|
|||||||
const UpdateState &state = state_;
|
const UpdateState &state = state_;
|
||||||
|
|
||||||
void add_on_state_callback(std::function<void()> &&callback) { this->state_callback_.add(std::move(callback)); }
|
void add_on_state_callback(std::function<void()> &&callback) { this->state_callback_.add(std::move(callback)); }
|
||||||
|
Trigger<const UpdateInfo &> *get_update_available_trigger() {
|
||||||
|
if (!update_available_trigger_) {
|
||||||
|
update_available_trigger_ = std::make_unique<Trigger<const UpdateInfo &>>();
|
||||||
|
}
|
||||||
|
return update_available_trigger_.get();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
UpdateState state_{UPDATE_STATE_UNKNOWN};
|
UpdateState state_{UPDATE_STATE_UNKNOWN};
|
||||||
UpdateInfo update_info_;
|
UpdateInfo update_info_;
|
||||||
|
|
||||||
CallbackManager<void()> state_callback_{};
|
CallbackManager<void()> state_callback_{};
|
||||||
|
std::unique_ptr<Trigger<const UpdateInfo &>> update_available_trigger_{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace update
|
} // namespace update
|
||||||
|
@ -91,3 +91,5 @@ update:
|
|||||||
name: OTA Update
|
name: OTA Update
|
||||||
id: ota_update
|
id: ota_update
|
||||||
source: http://my.ha.net:8123/local/esphome/manifest.json
|
source: http://my.ha.net:8123/local/esphome/manifest.json
|
||||||
|
on_update_available:
|
||||||
|
- logger.log: "A new update is available"
|
||||||
|
@ -26,3 +26,5 @@ update:
|
|||||||
- platform: http_request
|
- platform: http_request
|
||||||
name: Firmware Update
|
name: Firmware Update
|
||||||
source: http://example.com/manifest.json
|
source: http://example.com/manifest.json
|
||||||
|
on_update_available:
|
||||||
|
- logger.log: "A new update is available"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user