125 auto *result =
static_cast<TaskResult *
>(params);
127 auto *info = &result->info;
128 const char *source_url = result->source_url;
132 if (container ==
nullptr || container->status_code !=
HTTP_STATUS_OK) {
133 ESP_LOGE(TAG,
"Failed to fetch manifest from %s", source_url);
134 if (container !=
nullptr)
136 result->error_str = LOG_STR(
"Failed to fetch manifest");
142 uint8_t *data = allocator.
allocate(container->content_length);
143 if (data ==
nullptr) {
144 ESP_LOGE(TAG,
"Failed to allocate %zu bytes for manifest", container->content_length);
146 result->error_str = LOG_STR(
"Failed to allocate memory for manifest");
150 auto read_result =
http_read_fully(container.get(), data, container->content_length, MAX_READ_SIZE,
154 ESP_LOGE(TAG,
"Timeout reading manifest");
156 ESP_LOGE(TAG,
"Error reading manifest: %d", read_result.error_code);
158 allocator.
deallocate(data, container->content_length);
160 result->error_str = LOG_STR(
"Failed to read manifest");
163 size_t read_index = container->get_bytes_read();
164 size_t content_length = container->content_length;
172 if (!root[ESPHOME_F(
"name")].is<const char *>() || !root[ESPHOME_F(
"version")].is<const char *>() ||
173 !root[ESPHOME_F(
"builds")].is<JsonArray>()) {
174 ESP_LOGE(TAG,
"Manifest does not contain required fields");
177 info->title = root[ESPHOME_F(
"name")].as<std::string>();
178 info->latest_version = root[ESPHOME_F(
"version")].as<std::string>();
180 auto builds_array = root[ESPHOME_F(
"builds")].as<JsonArray>();
181 for (
auto build : builds_array) {
182 if (!build[ESPHOME_F(
"chipFamily")].is<const char *>()) {
183 ESP_LOGE(TAG,
"Manifest does not contain required fields");
186 if (build[ESPHOME_F(
"chipFamily")] == ESPHOME_VARIANT) {
187 if (!build[ESPHOME_F(
"ota")].is<JsonObject>()) {
188 ESP_LOGE(TAG,
"Manifest does not contain required fields");
191 JsonObject ota = build[ESPHOME_F(
"ota")].as<JsonObject>();
192 if (!ota[ESPHOME_F(
"path")].is<const char *>() || !ota[ESPHOME_F(
"md5")].is<const char *>()) {
193 ESP_LOGE(TAG,
"Manifest does not contain required fields");
196 info->firmware_url = ota[ESPHOME_F(
"path")].as<std::string>();
197 info->md5 = ota[ESPHOME_F(
"md5")].as<std::string>();
199 if (ota[ESPHOME_F(
"summary")].is<const char *>())
200 info->summary = ota[ESPHOME_F(
"summary")].as<std::string>();
201 if (ota[ESPHOME_F(
"release_url")].is<const char *>())
202 info->release_url = ota[ESPHOME_F(
"release_url")].as<std::string>();
213 ESP_LOGE(TAG,
"Failed to parse JSON from %s", source_url);
214 result->error_str = LOG_STR(
"Failed to parse manifest JSON");
219 if (!info->firmware_url.empty() && info->firmware_url.find(
"http") == std::string::npos) {
220 const char *source = source_url;
221 const size_t source_len = strlen(source);
223 if (info->firmware_url[0] ==
'/') {
225 const char *host_end = source_len > 8 ? strchr(source + 8,
'/') :
nullptr;
226 prefix_len = host_end !=
nullptr ? host_end - source : source_len;
229 const char *dir_end = strrchr(source,
'/');
230 prefix_len = dir_end !=
nullptr ? dir_end - source + 1 : 0;
232 info->firmware_url.insert(0, source, prefix_len);
235#ifdef ESPHOME_PROJECT_VERSION
236 info->current_version = ESPHOME_PROJECT_VERSION;
238 info->current_version = ESPHOME_VERSION;
250 this_update->
defer([this_update, result]() {
253 this_update->end_check_(result);
255 if (result->error_str !=
nullptr) {
262 bool trigger_update_available =
false;
264 if (result->info.latest_version.empty() || result->info.latest_version == result->info.current_version) {
269 trigger_update_available =
true;
274 this_update->
state_ = new_state;
280 if (trigger_update_available) {
HttpReadResult http_read_fully(HttpContainer *container, uint8_t *buffer, size_t total_size, size_t chunk_size, uint32_t timeout_ms)
Read data from HTTP container into buffer with timeout handling Handles feed_wdt, yield,...