Browse Source

add OTA

split_files
Hendrik Langer 5 years ago
parent
commit
0d4cc1f418
  1. 3
      .gitignore
  2. 5
      .gitlab-ci.yml
  3. 2
      platformio.ini
  4. 13
      script/autoversioning.py
  5. 132
      src/XD0OTA.cpp
  6. 84
      src/XD0OTA.h

3
.gitignore

@ -12,3 +12,6 @@ include/
lib/
local/
share/
# custom
version.txt

5
.gitlab-ci.yml

@ -10,12 +10,12 @@ build:
- platformio update
script:
- platformio ci --project-conf platformio.ini --board=lolin_d32_pro --build-dir build --keep-build-dir
# - cp ~/.platformio/packages/framework-arduinoespressif32/tools/sdk/bin/bootloader_dio_40m.bin build/.pio/build/lolin_d32_pro/
# - cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/default.bin build/.pio/build/lolin_d32_pro/
# - date +%s > build/.pio/build/lolin_d32_pro/build.version
variables: {PLATFORMIO_CI_SRC: "src"}
artifacts:
paths:
- build/.pio/build/lolin_d32_pro/*.bin
- version.txt
deploy:
stage: deploy
@ -31,6 +31,7 @@ deploy:
- chmod 644 ~/.ssh/known_hosts
script:
- scp build/.pio/build/lolin_d32_pro/firmware.bin "${SSH_USER_HOST}:${DEPLOY_PATH}"
- scp version.txt "${SSH_USER_HOST}:${DEPLOY_PATH}".version
dependencies:
- build
when: manual

2
platformio.ini

@ -21,3 +21,5 @@ build_flags =
; ArduinoJSON
monitor_speed = 115200
extra_scripts = pre:script/autoversioning.py

13
script/autoversioning.py

@ -0,0 +1,13 @@
Import("env")
import time
ver = time.time()
f = open("version.txt", "w")
f.write(str(ver))
f.close()
env.Append(CPPDEFINES=[
("FW_VERSION", ver)
])

132
src/XD0OTA.cpp

@ -0,0 +1,132 @@
#include "XD0OTA.h"
#include <WiFi.h>
#include <WiFiClient.h>
#include <HTTPClient.h>
#include <HTTPUpdate.h>
#include <time.h>
static const char* TAG = "OTA";
XD0OTA::XD0OTA(String deviceName) : deviceName{deviceName} {}
// Set time via NTP, as required for x.509 validation
void XD0OTA::setClock() {
configTime(0, 0, "pool.ntp.org", "time.nist.gov"); // UTC
Serial.print(F("Waiting for NTP time sync: "));
time_t now = time(nullptr);
while (now < 8 * 3600 * 2) {
yield();
delay(500);
Serial.print(F("."));
now = time(nullptr);
}
Serial.println(F(""));
struct tm timeinfo;
gmtime_r(&now, &timeinfo);
Serial.print(F("Current time: "));
Serial.print(asctime(&timeinfo));
}
String XD0OTA::getMAC() {
uint8_t mac[6];
char result[14];
WiFi.macAddress( mac );
snprintf( result, sizeof( result ), "%02x%02x%02x%02x%02x%02x", mac[ 0 ], mac[ 1 ], mac[ 2 ], mac[ 3 ], mac[ 4 ], mac[ 5 ] );
return String( result );
}
String XD0OTA::getUpdateURL(String file, String extension) {
String updateURL = String(fwUrlBase);
updateURL.concat(file);
updateURL.concat(extension);
return updateURL;
}
void XD0OTA::update(void) {
setClock();
// try device specific image first
String fwURL = getUpdateURL(getMAC(), ".bin");
int newVersion = checkForUpdates(fwURL + ".version");
if (newVersion < 1) {
ESP_LOGW(TAG, "[update] no device specific update found..\n");
fwURL = getUpdateURL(deviceName, ".bin");
newVersion = checkForUpdates(fwURL + ".version");
// try project specific image
if (newVersion < 1) {
ESP_LOGW(TAG, "[update] Error while looking for updates..\n");
return;
}
}
if( newVersion > FW_VERSION ) {
ESP_LOGW(TAG, "Preparing to update.\n" );
ESP_LOGW(TAG, "Firmware image URL: " );
ESP_LOGW(TAG, "%s\n", fwURL.c_str() );
WiFiClientSecure client;
client.setCACert(rootCACertificate);
client.setTimeout(12); // seconds
httpUpdate.setLedPin(LED_BUILTIN, HIGH);
t_httpUpdate_return ret = httpUpdate.update( client, fwURL );
switch(ret) {
case HTTP_UPDATE_FAILED:
ESP_LOGW(TAG, "HTTP_UPDATE_FAILED Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES:
ESP_LOGW(TAG, "HTTP_UPDATE_NO_UPDATES\n");
break;
case HTTP_UPDATE_OK:
ESP_LOGW(TAG, "[update] Update ok.\n"); // may not called we reboot the ESP
break;
}
} else {
ESP_LOGW(TAG, "[update] Already on latest version\n" );
}
}
int XD0OTA::checkForUpdates(String url) {
int newVersion = -1;
ESP_LOGW(TAG, "Checking for firmware updates.\n" );
ESP_LOGW(TAG, "Firmware version URL: " );
ESP_LOGW(TAG, "%s\n", url.c_str() );
WiFiClientSecure client;
client.setCACert(rootCACertificate);
client.setTimeout(5); // seconds
HTTPClient httpClient;
httpClient.begin( client, url );
int httpCode = httpClient.GET();
if( httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY ) {
String newFWVersion = httpClient.getString();
ESP_LOGW(TAG, "Current firmware version: " );
ESP_LOGW(TAG, "%s\n", String(FW_VERSION).c_str() );
ESP_LOGW(TAG, "Available firmware version: " );
ESP_LOGW(TAG, "%s\n", newFWVersion.c_str() );
newVersion = newFWVersion.toInt();
} else {
ESP_LOGW(TAG, "Firmware version check failed, got HTTP response code " );
ESP_LOGW(TAG, "%d\n", httpCode );
newVersion = -1;
}
httpClient.end();
return newVersion;
}

84
src/XD0OTA.h

@ -0,0 +1,84 @@
#ifndef _XD0OTA_H
#define _XD0OTA_H
#include <Arduino.h>
class XD0OTA {
public:
XD0OTA(String deviceName);
void update(void);
int checkForUpdates(String url);
private:
String deviceName;
const char* fwUrlBase = "https://fwupdate.xd0.de:444/fota/";
const char* httpsFingerprint = "37 42 61 B9 E6 EE 22 36 D1 59 67 7D 55 53 6E A4 C7 AA 60 26";
const char* rootCACertificate = \
"-----BEGIN CERTIFICATE-----\n" \
"MIID8DCCAtigAwIBAgIJAPSONy8RRejRMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD\n" \
"VQQGEwJERTEeMBwGA1UECAwVTm9ydGhyaGluZS1XZXN0cGhhbGlhMQ4wDAYDVQQH\n" \
"DAVFc3NlbjEPMA0GA1UECgwGeGQwLmRlMRgwFgYDVQQDDA9md3VwZGF0ZS54ZDAu\n" \
"ZGUxITAfBgkqhkiG9w0BCQEWEmhlbmRyaWsrZGV2QHhkMC5kZTAgFw0xODA2MTYx\n" \
"MTAzMTVaGA8yMDY4MDYxNjExMDMxNVowgYsxCzAJBgNVBAYTAkRFMR4wHAYDVQQI\n" \
"DBVOb3J0aHJoaW5lLVdlc3RwaGFsaWExDjAMBgNVBAcMBUVzc2VuMQ8wDQYDVQQK\n" \
"DAZ4ZDAuZGUxGDAWBgNVBAMMD2Z3dXBkYXRlLnhkMC5kZTEhMB8GCSqGSIb3DQEJ\n" \
"ARYSaGVuZHJpaytkZXZAeGQwLmRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" \
"CgKCAQEAx37S1YgaG74IhTysaaZQMFI50TDeGkxxdpNoIBX0UBeVtKI/3u3MAqBz\n" \
"kKTDHFu4IQDj0PvBdlqPFGdSinFgrIvr49uAr+alNKUtkuSTT7nXI0fzqAxv1taj\n" \
"0mNhigVvYikX2BUU/rNLnQclyBdPNVsOf9cv0t5+UcOHRt6oEwk5nFtG7s7k4+wu\n" \
"wRdGlLy2LwLihYFon4LHAs05JW3qs0IQI4etc8E2JWjF2YwBg3+ooyzUFFIGjPSl\n" \
"Lpi7WvAAR19HITbt5FJXQkFZnFxnfbQv/5f7n8vWfFmzYsEgvldwMZv+Eg6wPb2h\n" \
"rgH7T6RSb55JrZE/JUY5C6pKvTJ3AwIDAQABo1MwUTAdBgNVHQ4EFgQUCnZywNj+\n" \
"djz6n0sIARPx8dp+7bQwHwYDVR0jBBgwFoAUCnZywNj+djz6n0sIARPx8dp+7bQw\n" \
"DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAto7IGXpNYTiPUgnA\n" \
"DE6osdgSV1yVYJj75v+Y8aUGgQ93Ipl/0+PQL99wbGgjDhfxGADLtljwoEAz/fep\n" \
"RqCh8swjL34XV9XjMzfhEMDCybSO6mK7ZmCKwhz9yBaK/Qjdj0YUoLhJ9Huzb70m\n" \
"lGzbOhY4JJKFVaA5AcZhYHqjCmzHCVJ/H0zeuPGyKutbvSx23a24LmebfY4q2D62\n" \
"U85ox3Ojek6Mc8J4V+RjORygDGAO4gZClEhAza4koAg7lCO/kSSk5PrXdlz2dqtA\n" \
"D5Npv9M5363apnO1VlVR+OuO1NEJusRK1aWk9RLZsTPxzwOWwdkifXxUEJ+f8mGn\n" \
"o+6SCw==\n" \
"-----END CERTIFICATE-----\n";
String getMAC(void);
String getUpdateURL(String file, String extension);
void setClock(void);
};
#endif /* _XD0OTA_H */
/*
MAKE SURE TO RESET THE ESP8266 ONCE AFTER NORMAL FLASHING! OTHERWISE OTA WON'T WORK!
openssl req -x509 -nodes -days 18263 -newkey rsa:2048 -keyout /etc/ssl/private/xd0-fwupdate-selfsigned.key -out /etc/ssl/certs/xd0-fwupdate-selfsigned.crt
openssl x509 -noout -fingerprint -sha1 -inform pem -in /etc/ssl/certs/xd0-fwupdate-selfsigned.crt
scp .pioenvs/nodemcuv2/firmware.bin user@webserver:/var/www/fwupdate/fota/macaddress.bin
and change macaddress.version
server {
listen 444 ssl;
listen [::]:444 ssl;
server_name fwupdate.xd0.de;
# SSL configuration
ssl_certificate /etc/ssl/certs/xd0-fwupdate-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/xd0-fwupdate-selfsigned.key;
ssl_buffer_size 4k;
root /var/www/fwupdate;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
access_log /var/log/nginx/fwupdate_access.log;
error_log /var/log/nginx/fwupdate_error.log;
}
*/
Loading…
Cancel
Save