commit
ef6f9c3dd4
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,3 +10,4 @@
|
|||||||
.clang_complete
|
.clang_complete
|
||||||
.gcc-flags.json
|
.gcc-flags.json
|
||||||
src/loraconf.h
|
src/loraconf.h
|
||||||
|
platformio.ini
|
@ -9,6 +9,7 @@
|
|||||||
; http://docs.platformio.org/page/projectconf.html
|
; http://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
; ---> SELECT TARGET PLATFORM HERE! <---
|
; ---> SELECT TARGET PLATFORM HERE! <---
|
||||||
[platformio]
|
[platformio]
|
||||||
;env_default = generic
|
;env_default = generic
|
||||||
@ -29,20 +30,21 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng
|
|||||||
|
|
||||||
[bintray]
|
[bintray]
|
||||||
user = cyberman54
|
user = cyberman54
|
||||||
repository = paxcounter
|
repository = paxcounter-firmware
|
||||||
package = esp32-paxcounter
|
package = ttgov21_old
|
||||||
api_token = ***
|
api_token = 2e10f923df5d47b9c7e25752510322a1d65ee997
|
||||||
|
|
||||||
[wifi]
|
[wifi]
|
||||||
ssid = ***
|
ssid = testnet
|
||||||
password = ***
|
password = test0815
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
platform = https://github.com/platformio/platform-espressif32.git
|
platform = https://github.com/platformio/platform-espressif32.git
|
||||||
|
|
||||||
; firmware version, please modify it between releases
|
; firmware version, please modify it between releases
|
||||||
; positive integer value
|
; positive integer value
|
||||||
release_version = 4
|
;release_version = 1.4.30
|
||||||
|
release_version = 3
|
||||||
|
|
||||||
; build configuration based on Bintray and Wi-Fi settings
|
; build configuration based on Bintray and Wi-Fi settings
|
||||||
build_flags =
|
build_flags =
|
||||||
@ -154,6 +156,8 @@ lib_deps =
|
|||||||
build_flags =
|
build_flags =
|
||||||
${common.build_flags}
|
${common.build_flags}
|
||||||
${common_env_data.build_flags}
|
${common_env_data.build_flags}
|
||||||
|
;upload_protocol = custom
|
||||||
|
;extra_scripts = pre:publish_firmware.py
|
||||||
|
|
||||||
[env:ttgobeam]
|
[env:ttgobeam]
|
||||||
platform = ${common_env_data.platform_espressif32}
|
platform = ${common_env_data.platform_espressif32}
|
||||||
|
71
publish_firmware.py
Normal file
71
publish_firmware.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from os.path import basename
|
||||||
|
from platformio import util
|
||||||
|
|
||||||
|
Import('env')
|
||||||
|
|
||||||
|
project_config = util.load_project_config()
|
||||||
|
bintray_config = {k: v for k, v in project_config.items("bintray")}
|
||||||
|
version = project_config.get("common", "release_version")
|
||||||
|
|
||||||
|
#
|
||||||
|
# Push new firmware to the Bintray storage using API
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
def publish_firmware(source, target, env):
|
||||||
|
firmware_path = str(source[0])
|
||||||
|
firmware_name = basename(firmware_path)
|
||||||
|
|
||||||
|
print("Uploading {0} to Bintray. Version: {1}".format(
|
||||||
|
firmware_name, version))
|
||||||
|
|
||||||
|
print(firmware_path, firmware_name)
|
||||||
|
|
||||||
|
url = "/".join([
|
||||||
|
"https://api.bintray.com", "content",
|
||||||
|
bintray_config.get("user"),
|
||||||
|
bintray_config.get("repository"),
|
||||||
|
bintray_config.get("package"), version, firmware_name
|
||||||
|
])
|
||||||
|
|
||||||
|
print(url)
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Content-type": "application/octet-stream",
|
||||||
|
"X-Bintray-Publish": "1",
|
||||||
|
"X-Bintray-Override": "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
r = requests.put(
|
||||||
|
url,
|
||||||
|
data=open(firmware_path, "rb"),
|
||||||
|
headers=headers,
|
||||||
|
auth=(bintray_config.get("user"), bintray_config['api_token']))
|
||||||
|
|
||||||
|
if r.status_code != 201:
|
||||||
|
print("Failed to submit package: {0}\n{1}".format(
|
||||||
|
r.status_code, r.text))
|
||||||
|
else:
|
||||||
|
print("The firmware has been successfuly published at Bintray.com!")
|
||||||
|
|
||||||
|
|
||||||
|
# Custom upload command and program name
|
||||||
|
env.Replace(
|
||||||
|
PROGNAME="firmware_v_%s" % version,
|
||||||
|
UPLOADCMD=publish_firmware
|
||||||
|
)
|
261
src/OTA.cpp
261
src/OTA.cpp
@ -1,79 +1,226 @@
|
|||||||
#include "OTA.h"
|
/*
|
||||||
|
Parts of this code:
|
||||||
|
Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
#include <Update.h>
|
||||||
|
#include <BintrayClient.h>
|
||||||
|
#include "ota.h"
|
||||||
|
|
||||||
const BintrayClient bintray(BINTRAY_USER, BINTRAY_REPO, BINTRAY_PACKAGE);
|
const BintrayClient bintray(BINTRAY_USER, BINTRAY_REPO, BINTRAY_PACKAGE);
|
||||||
|
|
||||||
bool Wifi_Connected = false;
|
// Connection port (HTTPS)
|
||||||
|
const int port = 443;
|
||||||
|
|
||||||
esp_err_t event_handler(void *ctx, system_event_t *event) {
|
// Connection timeout
|
||||||
switch (event->event_id) {
|
const uint32_t RESPONSE_TIMEOUT_MS = 5000;
|
||||||
case SYSTEM_EVENT_STA_START:
|
|
||||||
esp_wifi_connect();
|
|
||||||
ESP_LOGI(TAG, "Event STA_START");
|
|
||||||
break;
|
|
||||||
case SYSTEM_EVENT_STA_GOT_IP:
|
|
||||||
Wifi_Connected = true;
|
|
||||||
ESP_LOGI(TAG, "Event STA_GOT_IP");
|
|
||||||
// print the local IP address
|
|
||||||
tcpip_adapter_ip_info_t ip_info;
|
|
||||||
ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info));
|
|
||||||
ESP_LOGI(TAG, "IP %s", ip4addr_ntoa(&ip_info.ip));
|
|
||||||
break;
|
|
||||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
|
||||||
Wifi_Connected = false;
|
|
||||||
ESP_LOGI(TAG, "Event STA_DISCONNECTED");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ota_wifi_init(void) {
|
// Variables to validate firmware content
|
||||||
|
volatile int contentLength = 0;
|
||||||
|
volatile bool isValidContentType = false;
|
||||||
|
|
||||||
tcpip_adapter_if_t tcpip_if = TCPIP_ADAPTER_IF_STA;
|
// Local logging tag
|
||||||
|
static const char TAG[] = "main";
|
||||||
|
|
||||||
// initialize the tcp stack
|
void start_ota_update() {
|
||||||
// nvs_flash_init();
|
ota_update = false; // clear ota trigger switch
|
||||||
tcpip_adapter_init();
|
|
||||||
tcpip_adapter_set_hostname(tcpip_if, PROGNAME);
|
|
||||||
tcpip_adapter_dhcpc_start(tcpip_if);
|
|
||||||
|
|
||||||
// initialize the wifi event handler
|
ESP_LOGI(TAG, "Stopping Wifi scanner");
|
||||||
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
|
vTaskDelete(WifiLoopTask);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Starting Wifi OTA update");
|
||||||
// switch off monitor more
|
// switch off monitor more
|
||||||
ESP_ERROR_CHECK(
|
ESP_ERROR_CHECK(
|
||||||
esp_wifi_set_promiscuous(false)); // now switch on monitor mode
|
esp_wifi_set_promiscuous(false)); // now switch on monitor mode
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(NULL));
|
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(NULL));
|
||||||
|
|
||||||
wifi_sta_config_t cfg;
|
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
||||||
strcpy((char *)cfg.ssid, WIFI_SSID);
|
|
||||||
strcpy((char *)cfg.password, WIFI_PASS);
|
|
||||||
cfg.bssid_set = false;
|
|
||||||
|
|
||||||
wifi_config_t sta_cfg;
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
sta_cfg.sta = cfg;
|
delay(2000);
|
||||||
|
ESP_LOGI(TAG, "trying to connect to %s", WIFI_SSID);
|
||||||
|
}
|
||||||
|
|
||||||
wifi_init_config_t wifi_cfg = WIFI_INIT_CONFIG_DEFAULT();
|
ESP_LOGI(TAG, "connected to %s", WIFI_SSID);
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_init(&wifi_cfg));
|
checkFirmwareUpdates();
|
||||||
ESP_ERROR_CHECK(
|
ESP.restart(); // reached only if update was not successful
|
||||||
esp_wifi_set_storage(WIFI_STORAGE_RAM)); // we don't need NVRAM
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
} // start_ota_update
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_cfg));
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_start());
|
void checkFirmwareUpdates() {
|
||||||
|
// Fetch the latest firmware version
|
||||||
|
ESP_LOGI(TAG, "Checking latest firmware version...");
|
||||||
|
const String latest = bintray.getLatestVersion();
|
||||||
|
if (latest.length() == 0) {
|
||||||
|
ESP_LOGI(TAG, "Could not load info about the latest firmware, so nothing "
|
||||||
|
"to update. Continue ...");
|
||||||
|
return;
|
||||||
|
} else if (atoi(latest.c_str()) <= VERSION) {
|
||||||
|
ESP_LOGI(TAG, "The current firmware is up to date. Continue ...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "There is a new version of firmware available: v.%s",
|
||||||
|
latest.c_str());
|
||||||
|
processOTAUpdate(latest);
|
||||||
}
|
}
|
||||||
|
|
||||||
void start_ota_update() {
|
// A helper function to extract header value from header
|
||||||
ESP_LOGI(TAG, "Stopping Wifi task on core 0");
|
inline String getHeaderValue(String header, String headerName) {
|
||||||
vTaskDelete(WifiLoopTask);
|
return header.substring(strlen(headerName.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Stopping LORA task on core 1");
|
/**
|
||||||
vTaskDelete(LoraTask);
|
* OTA update processing
|
||||||
|
*/
|
||||||
|
void processOTAUpdate(const String &version) {
|
||||||
|
String firmwarePath = bintray.getBinaryPath(version);
|
||||||
|
if (!firmwarePath.endsWith(".bin")) {
|
||||||
|
ESP_LOGI(TAG, "Unsupported binary format. OTA update cannot be performed!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Connecting to %s", WIFI_SSID);
|
String currentHost = bintray.getStorageHost();
|
||||||
ota_wifi_init();
|
String prevHost = currentHost;
|
||||||
delay(2000);
|
|
||||||
delay(2000);
|
WiFiClientSecure client;
|
||||||
checkFirmwareUpdates();
|
client.setCACert(bintray.getCertificate(currentHost));
|
||||||
ESP.restart(); // reached if update was not successful
|
|
||||||
|
if (!client.connect(currentHost.c_str(), port)) {
|
||||||
|
ESP_LOGI(TAG, "Cannot connect to %s", currentHost.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool redirect = true;
|
||||||
|
while (redirect) {
|
||||||
|
if (currentHost != prevHost) {
|
||||||
|
client.stop();
|
||||||
|
client.setCACert(bintray.getCertificate(currentHost));
|
||||||
|
if (!client.connect(currentHost.c_str(), port)) {
|
||||||
|
ESP_LOGI(TAG,
|
||||||
|
"Redirect detected! Cannot connect to %s for some reason!",
|
||||||
|
currentHost.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ESP_LOGI(TAG, "Requesting: " + firmwarePath);
|
||||||
|
|
||||||
|
client.print(String("GET ") + firmwarePath + " HTTP/1.1\r\n");
|
||||||
|
client.print(String("Host: ") + currentHost + "\r\n");
|
||||||
|
client.print("Cache-Control: no-cache\r\n");
|
||||||
|
client.print("Connection: close\r\n\r\n");
|
||||||
|
|
||||||
|
unsigned long timeout = millis();
|
||||||
|
while (client.available() == 0) {
|
||||||
|
if (millis() - timeout > RESPONSE_TIMEOUT_MS) {
|
||||||
|
ESP_LOGI(TAG, "Client Timeout !");
|
||||||
|
client.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (client.available()) {
|
||||||
|
String line = client.readStringUntil('\n');
|
||||||
|
// Check if the line is end of headers by removing space symbol
|
||||||
|
line.trim();
|
||||||
|
// if the the line is empty, this is the end of the headers
|
||||||
|
if (!line.length()) {
|
||||||
|
break; // proceed to OTA update
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check allowed HTTP responses
|
||||||
|
if (line.startsWith("HTTP/1.1")) {
|
||||||
|
if (line.indexOf("200") > 0) {
|
||||||
|
ESP_LOGI(TAG, "Got 200 status code from server. Proceeding to "
|
||||||
|
"firmware flashing");
|
||||||
|
redirect = false;
|
||||||
|
} else if (line.indexOf("302") > 0) {
|
||||||
|
ESP_LOGI(TAG, "Got 302 status code from server. Redirecting to the "
|
||||||
|
"new address");
|
||||||
|
redirect = true;
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "Could not get a valid firmware url");
|
||||||
|
// Unexptected HTTP response. Retry or skip update?
|
||||||
|
redirect = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extracting new redirect location
|
||||||
|
if (line.startsWith("Location: ")) {
|
||||||
|
String newUrl = getHeaderValue(line, "Location: ");
|
||||||
|
ESP_LOGI(TAG, "Got new url: %s", newUrl.c_str());
|
||||||
|
newUrl.remove(0, newUrl.indexOf("//") + 2);
|
||||||
|
currentHost = newUrl.substring(0, newUrl.indexOf('/'));
|
||||||
|
newUrl.remove(newUrl.indexOf(currentHost), currentHost.length());
|
||||||
|
firmwarePath = newUrl;
|
||||||
|
ESP_LOGI(TAG, "firmwarePath: %s", firmwarePath.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checking headers
|
||||||
|
if (line.startsWith("Content-Length: ")) {
|
||||||
|
contentLength =
|
||||||
|
atoi((getHeaderValue(line, "Content-Length: ")).c_str());
|
||||||
|
ESP_LOGI(TAG, "Got %d bytes from server", contentLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.startsWith("Content-Type: ")) {
|
||||||
|
String contentType = getHeaderValue(line, "Content-Type: ");
|
||||||
|
ESP_LOGI(TAG, "Got %s payload", contentType.c_str());
|
||||||
|
if (contentType == "application/octet-stream") {
|
||||||
|
isValidContentType = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check whether we have everything for OTA update
|
||||||
|
if (contentLength && isValidContentType) {
|
||||||
|
if (Update.begin(contentLength)) {
|
||||||
|
ESP_LOGI(TAG, "Starting Over-The-Air update. This may take some time to "
|
||||||
|
"complete ...");
|
||||||
|
size_t written = Update.writeStream(client);
|
||||||
|
|
||||||
|
if (written == contentLength) {
|
||||||
|
ESP_LOGI(TAG, "Written %d successfully", written);
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "Written only %d / %d Retry?", written, contentLength);
|
||||||
|
// Retry??
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Update.end()) {
|
||||||
|
if (Update.isFinished()) {
|
||||||
|
ESP_LOGI(TAG, "OTA update has successfully completed. Rebooting ...");
|
||||||
|
ESP.restart();
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "Something went wrong! OTA update hasn't been finished "
|
||||||
|
"properly.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "An error occurred. Error #: %d", Update.getError());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "There isn't enough space to start OTA update");
|
||||||
|
client.flush();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG,
|
||||||
|
"There was no valid content in the response from the OTA server!");
|
||||||
|
client.flush();
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,12 +2,12 @@
|
|||||||
#define OTA_H
|
#define OTA_H
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "globals.h"
|
|
||||||
#include <BintrayClient.h>
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include "ota.h"
|
#include "globals.h"
|
||||||
#include "SecureOTA.h"
|
#include "wifiscan.h"
|
||||||
|
|
||||||
|
void checkFirmwareUpdates();
|
||||||
|
void processOTAUpdate(const String &version);
|
||||||
void start_ota_update();
|
void start_ota_update();
|
||||||
|
|
||||||
#endif // OTA_H
|
#endif // OTA_H
|
@ -1,225 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <WiFiClientSecure.h>
|
|
||||||
#include <Update.h>
|
|
||||||
#include <BintrayClient.h>
|
|
||||||
#include "SecureOTA.h"
|
|
||||||
|
|
||||||
const BintrayClient bintray(BINTRAY_USER, BINTRAY_REPO, BINTRAY_PACKAGE);
|
|
||||||
|
|
||||||
// Connection port (HTTPS)
|
|
||||||
const int port = 443;
|
|
||||||
|
|
||||||
// Connection timeout
|
|
||||||
const uint32_t RESPONSE_TIMEOUT_MS = 5000;
|
|
||||||
|
|
||||||
// Variables to validate firmware content
|
|
||||||
volatile int contentLength = 0;
|
|
||||||
volatile bool isValidContentType = false;
|
|
||||||
|
|
||||||
void checkFirmwareUpdates()
|
|
||||||
{
|
|
||||||
// Fetch the latest firmware version
|
|
||||||
const String latest = bintray.getLatestVersion();
|
|
||||||
if (latest.length() == 0)
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "Could not load info about the latest firmware, so nothing to update. Continue ...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (atoi(latest.c_str()) <= VERSION)
|
|
||||||
{
|
|
||||||
//ESP_LOGI(TAG, "The current firmware is up to date. Continue ...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "There is a new version of firmware available: v.%s", latest);
|
|
||||||
processOTAUpdate(latest);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A helper function to extract header value from header
|
|
||||||
inline String getHeaderValue(String header, String headerName)
|
|
||||||
{
|
|
||||||
return header.substring(strlen(headerName.c_str()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OTA update processing
|
|
||||||
*/
|
|
||||||
void processOTAUpdate(const String &version)
|
|
||||||
{
|
|
||||||
String firmwarePath = bintray.getBinaryPath(version);
|
|
||||||
if (!firmwarePath.endsWith(".bin"))
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "Unsupported binary format. OTA update cannot be performed!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String currentHost = bintray.getStorageHost();
|
|
||||||
String prevHost = currentHost;
|
|
||||||
|
|
||||||
WiFiClientSecure client;
|
|
||||||
client.setCACert(bintray.getCertificate(currentHost));
|
|
||||||
|
|
||||||
if (!client.connect(currentHost.c_str(), port))
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "Cannot connect to %s", currentHost);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool redirect = true;
|
|
||||||
while (redirect)
|
|
||||||
{
|
|
||||||
if (currentHost != prevHost)
|
|
||||||
{
|
|
||||||
client.stop();
|
|
||||||
client.setCACert(bintray.getCertificate(currentHost));
|
|
||||||
if (!client.connect(currentHost.c_str(), port))
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "Redirect detected! Cannot connect to %s for some reason!", currentHost);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//ESP_LOGI(TAG, "Requesting: " + firmwarePath);
|
|
||||||
|
|
||||||
client.print(String("GET ") + firmwarePath + " HTTP/1.1\r\n");
|
|
||||||
client.print(String("Host: ") + currentHost + "\r\n");
|
|
||||||
client.print("Cache-Control: no-cache\r\n");
|
|
||||||
client.print("Connection: close\r\n\r\n");
|
|
||||||
|
|
||||||
unsigned long timeout = millis();
|
|
||||||
while (client.available() == 0)
|
|
||||||
{
|
|
||||||
if (millis() - timeout > RESPONSE_TIMEOUT_MS)
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "Client Timeout !");
|
|
||||||
client.stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (client.available())
|
|
||||||
{
|
|
||||||
String line = client.readStringUntil('\n');
|
|
||||||
// Check if the line is end of headers by removing space symbol
|
|
||||||
line.trim();
|
|
||||||
// if the the line is empty, this is the end of the headers
|
|
||||||
if (!line.length())
|
|
||||||
{
|
|
||||||
break; // proceed to OTA update
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check allowed HTTP responses
|
|
||||||
if (line.startsWith("HTTP/1.1"))
|
|
||||||
{
|
|
||||||
if (line.indexOf("200") > 0)
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "Got 200 status code from server. Proceeding to firmware flashing");
|
|
||||||
redirect = false;
|
|
||||||
}
|
|
||||||
else if (line.indexOf("302") > 0)
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "Got 302 status code from server. Redirecting to the new address");
|
|
||||||
redirect = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "Could not get a valid firmware url");
|
|
||||||
//Unexptected HTTP response. Retry or skip update?
|
|
||||||
redirect = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extracting new redirect location
|
|
||||||
if (line.startsWith("Location: "))
|
|
||||||
{
|
|
||||||
String newUrl = getHeaderValue(line, "Location: ");
|
|
||||||
ESP_LOGI(TAG, "Got new url: %s", newUrl);
|
|
||||||
newUrl.remove(0, newUrl.indexOf("//") + 2);
|
|
||||||
currentHost = newUrl.substring(0, newUrl.indexOf('/'));
|
|
||||||
newUrl.remove(newUrl.indexOf(currentHost), currentHost.length());
|
|
||||||
firmwarePath = newUrl;
|
|
||||||
ESP_LOGI(TAG, "firmwarePath: %s", firmwarePath);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checking headers
|
|
||||||
if (line.startsWith("Content-Length: "))
|
|
||||||
{
|
|
||||||
contentLength = atoi((getHeaderValue(line, "Content-Length: ")).c_str());
|
|
||||||
ESP_LOGI(TAG, "Got %s bytes from server", String(contentLength));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.startsWith("Content-Type: "))
|
|
||||||
{
|
|
||||||
String contentType = getHeaderValue(line, "Content-Type: ");
|
|
||||||
ESP_LOGI(TAG, "Got %s payload", contentType);
|
|
||||||
if (contentType == "application/octet-stream")
|
|
||||||
{
|
|
||||||
isValidContentType = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check whether we have everything for OTA update
|
|
||||||
if (contentLength && isValidContentType)
|
|
||||||
{
|
|
||||||
if (Update.begin(contentLength))
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "Starting Over-The-Air update. This may take some time to complete ...");
|
|
||||||
size_t written = Update.writeStream(client);
|
|
||||||
|
|
||||||
if (written == contentLength)
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "Written %s successfully", String(written));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "Written only %s / %s Retry?", String(written), String(contentLength));
|
|
||||||
// Retry??
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Update.end())
|
|
||||||
{
|
|
||||||
if (Update.isFinished())
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "OTA update has successfully completed. Rebooting ...");
|
|
||||||
ESP.restart();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "Something went wrong! OTA update hasn't been finished properly.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "An error occurred. Error #: %s", String(Update.getError()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "There isn't enough space to start OTA update");
|
|
||||||
client.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "There was no valid content in the response from the OTA server!");
|
|
||||||
client.flush();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#ifndef SECURE_OTA_H
|
|
||||||
#define SECURE_OTA_H
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
void checkFirmwareUpdates();
|
|
||||||
void processOTAUpdate(const String &version);
|
|
||||||
|
|
||||||
#endif // SECURE_OTA_H
|
|
Loading…
Reference in New Issue
Block a user