From 5099d25965e426f77051781e835d08fec3918c03 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 12 Aug 2018 00:17:57 +0200 Subject: [PATCH 01/43] testing --- lib/BintrayClient/library.json | 24 +++ lib/BintrayClient/src/BintrayCertificates.h | 102 +++++++++ lib/BintrayClient/src/BintrayClient.cpp | 149 +++++++++++++ lib/BintrayClient/src/BintrayClient.h | 49 +++++ platformio.ini | 46 +++- src/SecureOTA.cpp | 225 ++++++++++++++++++++ src/SecureOTA.h | 25 +++ src/globals.h | 1 + src/main.cpp | 4 +- src/rcommand.cpp | 29 ++- src/rcommand.h | 3 + 11 files changed, 648 insertions(+), 9 deletions(-) create mode 100644 lib/BintrayClient/library.json create mode 100644 lib/BintrayClient/src/BintrayCertificates.h create mode 100644 lib/BintrayClient/src/BintrayClient.cpp create mode 100644 lib/BintrayClient/src/BintrayClient.h create mode 100644 src/SecureOTA.cpp create mode 100644 src/SecureOTA.h diff --git a/lib/BintrayClient/library.json b/lib/BintrayClient/library.json new file mode 100644 index 000000000..677cec5c8 --- /dev/null +++ b/lib/BintrayClient/library.json @@ -0,0 +1,24 @@ +{ + "name": "BintrayClient", + "keywords": "bintray, ota, cdn, storage", + "description": "A BintrayClient to connect to a JFrog Bintray.", + "authors": [ + { + "name": "PlatformIO", + "url": "https://platformio.org/" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/platformio/platformio-examples" + }, + "export": { + "include": "bintray-secure-ota/lib/BintrayClient" + }, + "dependencies": { + "ArduinoJson": "^5.13.1" + }, + "version": "1.0.0", + "frameworks": "arduino", + "platforms": "espressif32" +} diff --git a/lib/BintrayClient/src/BintrayCertificates.h b/lib/BintrayClient/src/BintrayCertificates.h new file mode 100644 index 000000000..ec5fdaa3c --- /dev/null +++ b/lib/BintrayClient/src/BintrayCertificates.h @@ -0,0 +1,102 @@ +/* + Copyright (c) 2014-present PlatformIO + + 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 BINTRAY_CERTIFICATES_H +#define BINTRAY_CERTIFICATES_H + +const char* BINTRAY_API_ROOT_CA = \ +"-----BEGIN CERTIFICATE-----\n" \ +"MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\n" \ +"MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i\n" \ +"YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG\n" \ +"EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg\n" \ +"R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9\n" \ +"9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq\n" \ +"fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv\n" \ +"iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU\n" \ +"1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+\n" \ +"bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW\n" \ +"MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA\n" \ +"ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l\n" \ +"uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn\n" \ +"Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS\n" \ +"tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF\n" \ +"PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un\n" \ +"hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV\n" \ +"5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==\n" \ +"-----END CERTIFICATE-----\n"; + +const char* BINTRAY_AKAMAI_ROOT_CA = \ +"-----BEGIN CERTIFICATE-----\n"\ +"MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBh\n"\ +"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"\ +"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n"\ +"QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJBgNVBAYTAlVT\n"\ +"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIg\n"\ +"U2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n"\ +"ANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83\n"\ +"nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bd\n"\ +"KpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f\n"\ +"/ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGX\n"\ +"kujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+guqw9ypzAO+sf0\n"\ +"/RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8C\n"\ +"AQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY\n"\ +"aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6\n"\ +"Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1\n"\ +"oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD\n"\ +"QS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v\n"\ +"d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHVLyjnjUY4tCzh\n"\ +"xtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEB\n"\ +"CwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHgl4+mUwnNqipl\n"\ +"5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZgTHbO7Djc1lGA\n"\ +"8MXW5dRNJ2Srm8c+cftIl7gzbckTB+6WohsYFfZcTEDts8Ls/3HB40f/1LkAtDdC\n"\ +"2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8ZDOo0rwAhaPit\n"\ +"c+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4d60tbvVS3bR0\n"\ +"j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz\n"\ +"-----END CERTIFICATE-----\n"; + +const char* CLOUDFRONT_API_ROOT_CA = \ +"-----BEGIN CERTIFICATE-----\n"\ +"MIIE3zCCA8egAwIBAgIQYxgNOPuAl3ip0DWjFhj4QDANBgkqhkiG9w0BAQsFADCB\n"\ +"yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\n"\ +"ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp\n"\ +"U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW\n"\ +"ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0\n"\ +"aG9yaXR5IC0gRzUwHhcNMTcxMTA2MDAwMDAwWhcNMjIxMTA1MjM1OTU5WjBhMQsw\n"\ +"CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu\n"\ +"ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjCC\n"\ +"ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALs3zTTce2vJsmiQrUp1/0a6\n"\ +"IQoIjfUZVMn7iNvzrvI6iZE8euarBhprz6wt6F4JJES6Ypp+1qOofuBUdSAFrFC3\n"\ +"nGMabDDc2h8Zsdce3v3X4MuUgzeu7B9DTt17LNK9LqUv5Km4rTrUmaS2JembawBg\n"\ +"kmD/TyFJGPdnkKthBpyP8rrptOmSMmu181foXRvNjB2rlQSVSfM1LZbjSW3dd+P7\n"\ +"SUu0rFUHqY+Vs7Qju0xtRfD2qbKVMLT9TFWMJ0pXFHyCnc1zktMWSgYMjFDRjx4J\n"\ +"vheh5iHK/YPlELyDpQrEZyj2cxQUPUZ2w4cUiSE0Ta8PRQymSaG6u5zFsTODKYUC\n"\ +"AwEAAaOCAScwggEjMB0GA1UdDgQWBBROIlQgGJXm427mD/r6uRLtBhePOTAPBgNV\n"\ +"HRMBAf8EBTADAQH/MF8GA1UdIARYMFYwVAYEVR0gADBMMCMGCCsGAQUFBwIBFhdo\n"\ +"dHRwczovL2Quc3ltY2IuY29tL2NwczAlBggrBgEFBQcCAjAZDBdodHRwczovL2Qu\n"\ +"c3ltY2IuY29tL3JwYTAvBgNVHR8EKDAmMCSgIqAghh5odHRwOi8vcy5zeW1jYi5j\n"\ +"b20vcGNhMy1nNS5jcmwwDgYDVR0PAQH/BAQDAgGGMC4GCCsGAQUFBwEBBCIwIDAe\n"\ +"BggrBgEFBQcwAYYSaHR0cDovL3Muc3ltY2QuY29tMB8GA1UdIwQYMBaAFH/TZafC\n"\ +"3ey78DAJ80M5+gKvMzEzMA0GCSqGSIb3DQEBCwUAA4IBAQBQ3dNWKSUBip6n5X1N\n"\ +"ua8bjKLSJzXlnescavPECMpFBlIIKH2mc6mL2Xr/wkSIBDrsqAO3sBcmoJN+n8V3\n"\ +"0O5JelrtEAFYSyRDXfu78ZlHn6kvV5/jPUFECEM/hdN0x8WdLpGjJMqfs0EG5qHj\n"\ +"+UaxpucWD445wea4zlK7hUR+MA8fq0Yd1HEKj4c8TcgaQIHMa4KHr448cQ69e3CP\n"\ +"ECRhRNg+RAKT2I7SlaVzLvaB/8yym2oMCEsoqiRT8dbXg35aKEYmmzn3O/mnB7bG\n"\ +"Ud/EUrkIf7FVamgYZd1fSzQeg1cHqf0ja6eHpvq2bTl+cWFHaq/84KlHe5Rh0Csm\n"\ +"pZzn\n"\ +"-----END CERTIFICATE-----\n"; + +#endif // BINTRAY_CERTIFICATES_H diff --git a/lib/BintrayClient/src/BintrayClient.cpp b/lib/BintrayClient/src/BintrayClient.cpp new file mode 100644 index 000000000..b0e7543f5 --- /dev/null +++ b/lib/BintrayClient/src/BintrayClient.cpp @@ -0,0 +1,149 @@ +/* + Copyright (c) 2014-present PlatformIO + + 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 +#include +#include + +#include "BintrayClient.h" +#include "BintrayCertificates.h" + +BintrayClient::BintrayClient(const String &user, const String &repository, const String &package) + : m_user(user), m_repo(repository), m_package(package), + m_storage_host("dl.bintray.com"), + m_api_host("api.bintray.com") +{ + m_certificates.emplace_back("cloudfront.net", CLOUDFRONT_API_ROOT_CA); + m_certificates.emplace_back("akamai.bintray.com", BINTRAY_AKAMAI_ROOT_CA); + m_certificates.emplace_back("bintray.com", BINTRAY_API_ROOT_CA); +} + +String BintrayClient::getUser() const +{ + return m_user; +} + +String BintrayClient::getRepository() const +{ + return m_repo; +} + +String BintrayClient::getPackage() const +{ + return m_package; +} + +String BintrayClient::getStorageHost() const +{ + return m_storage_host; +} + +String BintrayClient::getApiHost() const +{ + return m_api_host; +} + +String BintrayClient::getLatestVersionRequestUrl() const +{ + return String("https://") + getApiHost() + "/packages/" + getUser() + "/" + getRepository() + "/" + getPackage() + "/versions/_latest"; +} + +String BintrayClient::getBinaryRequestUrl(const String &version) const +{ + return String("https://") + getApiHost() + "/packages/" + getUser() + "/" + getRepository() + "/" + getPackage() + "/versions/" + version + "/files"; +} + +const char *BintrayClient::getCertificate(const String &url) const +{ + for(auto& cert: m_certificates) { + if(url.indexOf(cert.first) >= 0) { + return cert.second; + } + } + + // Return the certificate for *.bintray.com by default + return m_certificates.rbegin()->second; +} + +String BintrayClient::requestHTTPContent(const String &url) const +{ + String payload; + HTTPClient http; + http.begin(url, getCertificate(url)); + int httpCode = http.GET(); + + if (httpCode > 0) + { + if (httpCode == HTTP_CODE_OK) + { + payload = http.getString(); + } + } + else + { + Serial.printf("GET request failed, error: %s\n", http.errorToString(httpCode).c_str()); + } + + http.end(); + return payload; +} + +String BintrayClient::getLatestVersion() const +{ + String version; + const String url = getLatestVersionRequestUrl(); + String jsonResult = requestHTTPContent(url); + const size_t bufferSize = 1024; + if (jsonResult.length() > bufferSize) + { + Serial.println("Error: Could parse JSON. Input data is too big!"); + return version; + } + StaticJsonBuffer jsonBuffer; + + JsonObject &root = jsonBuffer.parseObject(jsonResult.c_str()); + // Check for errors in parsing + if (!root.success()) + { + Serial.println("Error: Could not parse JSON!"); + return version; + } + return root.get("name"); +} + +String BintrayClient::getBinaryPath(const String &version) const +{ + String path; + const String url = getBinaryRequestUrl(version); + String jsonResult = requestHTTPContent(url); + + const size_t bufferSize = 1024; + if (jsonResult.length() > bufferSize) + { + Serial.println("Error: Could parse JSON. Input data is too big!"); + return path; + } + StaticJsonBuffer jsonBuffer; + + JsonArray &root = jsonBuffer.parseArray(jsonResult.c_str()); + JsonObject &firstItem = root[0]; + if (!root.success()) + { //Check for errors in parsing + Serial.println("Error: Could not parse JSON!"); + return path; + } + return "/" + getUser() + "/" + getRepository() + "/" + firstItem.get("path"); +} diff --git a/lib/BintrayClient/src/BintrayClient.h b/lib/BintrayClient/src/BintrayClient.h new file mode 100644 index 000000000..9761c7c63 --- /dev/null +++ b/lib/BintrayClient/src/BintrayClient.h @@ -0,0 +1,49 @@ +/* + Copyright (c) 2014-present PlatformIO + + 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 BINTRAY_CLIENT_H +#define BINTRAY_CLIENT_H + +#include +#include +#include + +class BintrayClient { + +public: + BintrayClient(const String& user, const String& repository, const String& package); + String getUser() const; + String getRepository() const; + String getPackage() const; + String getStorageHost() const; + String getApiHost() const; + const char* getCertificate(const String& url) const; + String getLatestVersion() const; + String getBinaryPath(const String& version) const; + +private: + String requestHTTPContent(const String& url) const; + String getLatestVersionRequestUrl() const; + String getBinaryRequestUrl(const String& version) const; + String m_user; + String m_repo; + String m_package; + const String m_storage_host; + const String m_api_host; + std::vector> m_certificates; +}; + +#endif // BINTRAY_CLIENT_H diff --git a/platformio.ini b/platformio.ini index 982968726..91ee4e271 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,12 +11,12 @@ ; ---> SELECT TARGET PLATFORM HERE! <--- [platformio] -env_default = generic +;env_default = generic ;env_default = ebox ;env_default = heltec ;env_default = ttgov1 ;env_default = ttgov2 -;env_default = ttgov21 +env_default = ttgov21 ;env_default = ttgobeam ;env_default = lopy ;env_default = lopy4 @@ -27,10 +27,45 @@ env_default = generic ; description = Paxcounter is a proof-of-concept ESP32 device for metering passenger flows in realtime. It counts how many mobile devices are around. +[bintray] +user = cyberman54 +repository = paxcounter +package = esp32-paxcounter +api_token = 9f02e2a2374c278fd79d5bcf4b4442fca9752012 +;api_token = ${env.BINTRAY_API_TOKEN} + +; Wi-Fi network settings +[wifi] +ssid = PRENZLNET-G +password = 435Huse8!? +;ssid = ${env.PIO_WIFI_SSID} +;password = ${env.PIO_WIFI_PASSWORD} + +[common] +platform = https://github.com/platformio/platform-espressif32.git + +; firmware version, please modify it between releases +; positive integer value +release_version = 1 + +; build configuration based on Bintray and Wi-Fi settings +build_flags = + '-DWIFI_SSID="${wifi.ssid}"' + '-DWIFI_PASS="${wifi.password}"' + '-DBINTRAY_USER="${bintray.user}"' + '-DBINTRAY_REPO="${bintray.repository}"' + '-DBINTRAY_PACKAGE="${bintray.package}"' + '-DVERSION=0' + +; extra dependencies +lib_deps = ArduinoJson + + [common_env_data] platform_espressif32 = espressif32@1.2.0 ;platform_espressif32 = https://github.com/platformio/platform-espressif32.git#feature/stage -board_build.partitions = no_ota.csv +;board_build.partitions = no_ota.csv +board_build.partitions = min_spiffs.csv lib_deps_all = lib_deps_display = U8g2@>=2.23.12 @@ -48,9 +83,9 @@ build_flags = ; Error ; -DCORE_DEBUG_LEVEL=1 ; Warn - -DCORE_DEBUG_LEVEL=2 +; -DCORE_DEBUG_LEVEL=2 ; Info -; -DCORE_DEBUG_LEVEL=3 + -DCORE_DEBUG_LEVEL=3 ; Debug ; -DCORE_DEBUG_LEVEL=4 ; Verbose @@ -124,6 +159,7 @@ lib_deps = ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_display} build_flags = + ${common.build_flags} ${common_env_data.build_flags} [env:ttgobeam] diff --git a/src/SecureOTA.cpp b/src/SecureOTA.cpp new file mode 100644 index 000000000..7496c19c7 --- /dev/null +++ b/src/SecureOTA.cpp @@ -0,0 +1,225 @@ +/* + Copyright (c) 2014-present PlatformIO + + 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 +#include +#include +#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) + { + Serial.println("Could not load info about the latest firmware, so nothing to update. Continue ..."); + return; + } + else if (atoi(latest.c_str()) <= VERSION) + { + //Serial.println("The current firmware is up to date. Continue ..."); + return; + } + + Serial.println("There is a new version of firmware available: v." + 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")) + { + Serial.println("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)) + { + Serial.println("Cannot connect to " + currentHost); + return; + } + + bool redirect = true; + while (redirect) + { + if (currentHost != prevHost) + { + client.stop(); + client.setCACert(bintray.getCertificate(currentHost)); + if (!client.connect(currentHost.c_str(), port)) + { + Serial.println("Redirect detected! Cannot connect to " + currentHost + " for some reason!"); + return; + } + } + + //Serial.println("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) + { + Serial.println("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) + { + //Serial.println("Got 200 status code from server. Proceeding to firmware flashing"); + redirect = false; + } + else if (line.indexOf("302") > 0) + { + //Serial.println("Got 302 status code from server. Redirecting to the new address"); + redirect = true; + } + else + { + //Serial.println("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: "); + //Serial.println("Got new url: " + newUrl); + newUrl.remove(0, newUrl.indexOf("//") + 2); + currentHost = newUrl.substring(0, newUrl.indexOf('/')); + newUrl.remove(newUrl.indexOf(currentHost), currentHost.length()); + firmwarePath = newUrl; + //Serial.println("firmwarePath: " + firmwarePath); + continue; + } + + // Checking headers + if (line.startsWith("Content-Length: ")) + { + contentLength = atoi((getHeaderValue(line, "Content-Length: ")).c_str()); + Serial.println("Got " + String(contentLength) + " bytes from server"); + } + + if (line.startsWith("Content-Type: ")) + { + String contentType = getHeaderValue(line, "Content-Type: "); + //Serial.println("Got " + contentType + " payload."); + if (contentType == "application/octet-stream") + { + isValidContentType = true; + } + } + } + } + + // check whether we have everything for OTA update + if (contentLength && isValidContentType) + { + if (Update.begin(contentLength)) + { + Serial.println("Starting Over-The-Air update. This may take some time to complete ..."); + size_t written = Update.writeStream(client); + + if (written == contentLength) + { + Serial.println("Written : " + String(written) + " successfully"); + } + else + { + Serial.println("Written only : " + String(written) + "/" + String(contentLength) + ". Retry?"); + // Retry?? + } + + if (Update.end()) + { + if (Update.isFinished()) + { + Serial.println("OTA update has successfully completed. Rebooting ..."); + ESP.restart(); + } + else + { + Serial.println("Something went wrong! OTA update hasn't been finished properly."); + } + } + else + { + Serial.println("An error Occurred. Error #: " + String(Update.getError())); + } + } + else + { + Serial.println("There isn't enough space to start OTA update"); + client.flush(); + } + } + else + { + Serial.println("There was no valid content in the response from the OTA server!"); + client.flush(); + } +} \ No newline at end of file diff --git a/src/SecureOTA.h b/src/SecureOTA.h new file mode 100644 index 000000000..d8b17c3f8 --- /dev/null +++ b/src/SecureOTA.h @@ -0,0 +1,25 @@ +/* + Copyright (c) 2014-present PlatformIO + + 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 + +void checkFirmwareUpdates(); +void processOTAUpdate(const String &version); + +#endif // SECURE_OTA_H \ No newline at end of file diff --git a/src/globals.h b/src/globals.h index a34851a7e..1043b13ab 100644 --- a/src/globals.h +++ b/src/globals.h @@ -52,6 +52,7 @@ extern portMUX_TYPE timerMux; extern volatile int SendCycleTimerIRQ, HomeCycleIRQ, DisplayTimerIRQ, ChannelTimerIRQ, ButtonPressedIRQ; extern QueueHandle_t LoraSendQueue, SPISendQueue; +extern TaskHandle_t WifiLoopTask; extern std::array::iterator it; extern std::array beacons; diff --git a/src/main.cpp b/src/main.cpp index 1b258f14a..b3825cb62 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,6 +41,8 @@ hw_timer_t *channelSwitch = NULL, *displaytimer = NULL, *sendCycle = NULL, volatile int ButtonPressedIRQ = 0, ChannelTimerIRQ = 0, SendCycleTimerIRQ = 0, DisplayTimerIRQ = 0, HomeCycleIRQ = 0; +TaskHandle_t WifiLoopTask = NULL; + // RTos send queues for payload transmit #ifdef HAS_LORA QueueHandle_t LoraSendQueue; @@ -298,7 +300,7 @@ void setup() { // gets it's seed from RF noise reset_salt(); // get new 16bit for salting hashes xTaskCreatePinnedToCore(wifi_channel_loop, "wifiloop", 2048, (void *)1, 1, - NULL, 0); + &WifiLoopTask, 0); } // setup() /* end Arduino SETUP diff --git a/src/rcommand.cpp b/src/rcommand.cpp index 8899a8054..70ac4c8e6 100644 --- a/src/rcommand.cpp +++ b/src/rcommand.cpp @@ -138,7 +138,7 @@ void set_loraadr(uint8_t val[]) { ESP_LOGI(TAG, "Remote command: set LoRa ADR mode to %s", val[0] ? "on" : "off"); cfg.adrmode = val[0] ? 1 : 0; -LMIC_setAdrMode(cfg.adrmode); + LMIC_setAdrMode(cfg.adrmode); #else ESP_LOGW(TAG, "Remote command: LoRa not implemented"); #endif // HAS_LORA @@ -219,6 +219,29 @@ void get_gps(uint8_t val[]) { #endif }; +void set_update(uint8_t val[]) { + ESP_LOGI(TAG, "Remote command: get firmware update"); + + ESP_LOGI(TAG, "Stopping Wifi task on core 0"); + vTaskDelete(WifiLoopTask); + + ESP_LOGI(TAG, "Connecting to %s", WIFI_SSID); + ESP_ERROR_CHECK(esp_wifi_set_promiscuous(false)); // switch off monitor mode + //tcpipInit(); + tcpip_adapter_init(); + WiFi.mode(WIFI_STA); + + WiFi.begin(WIFI_SSID, WIFI_PASS); + + while (WiFi.status() != WL_CONNECTED) { + ESP_LOGI(TAG, "."); + delay(500); + } + + ESP_LOGI(TAG, "connected!"); + checkFirmwareUpdates(); +}; + // assign previously defined functions to set of numeric remote commands // format: opcode, function, #bytes params, // flag (1 = do make settings persistent / 0 = don't) @@ -233,8 +256,8 @@ cmd_t table[] = { {0x0d, set_vendorfilter, 1, false}, {0x0e, set_blescan, 1, true}, {0x0f, set_wifiant, 1, true}, {0x10, set_rgblum, 1, true}, {0x11, set_monitor, 1, true}, {0x12, set_beacon, 7, false}, - {0x80, get_config, 0, false}, {0x81, get_status, 0, false}, - {0x84, get_gps, 0, false}}; + {0x20, set_update, 0, false}, {0x80, get_config, 0, false}, + {0x81, get_status, 0, false}, {0x84, get_gps, 0, false}}; const uint8_t cmdtablesize = sizeof(table) / sizeof(table[0]); // number of commands in command table diff --git a/src/rcommand.h b/src/rcommand.h index 6afb905f5..2d1902a1f 100644 --- a/src/rcommand.h +++ b/src/rcommand.h @@ -6,6 +6,9 @@ #include "lorawan.h" #include "macsniff.h" +#include +#include "SecureOTA.h" + // table of remote commands and assigned functions typedef struct { const uint8_t opcode; From cc603d4ab8f5b8662633e4512a31a02aa6c53486 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 12 Aug 2018 15:42:58 +0200 Subject: [PATCH 02/43] testing --- README.md | 1 + lib/BintrayClient/src/BintrayClient.cpp | 8 ++--- platformio.ini | 39 ++++++++++----------- src/OTA.cpp | 30 ++++++++++++++++ src/OTA.h | 11 ++++++ src/SecureOTA.cpp | 46 ++++++++++++------------- src/TTN/packed_decoder.js | 3 +- src/globals.h | 8 ++++- src/main.cpp | 5 ++- src/paxcounter.conf | 2 +- src/payload.cpp | 16 +++++---- src/payload.h | 5 ++- src/rcommand.cpp | 21 ++++------- src/rcommand.h | 2 ++ src/wifiscan.cpp | 1 + 15 files changed, 123 insertions(+), 75 deletions(-) create mode 100644 src/OTA.cpp create mode 100644 src/OTA.h diff --git a/README.md b/README.md index 6d5b64d51..4d42fa2e5 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,7 @@ Hereafter described is the default *plain* format, which uses MSB bit numbering. byte 3-10: Uptime [seconds] bytes 11-14: CPU temperature [°C] bytes 15-18: Free RAM [bytes] + bytes 19-20: Last reset reasons core 0 / core 1 **Port #3:** Device configuration query result diff --git a/lib/BintrayClient/src/BintrayClient.cpp b/lib/BintrayClient/src/BintrayClient.cpp index b0e7543f5..4479f5391 100644 --- a/lib/BintrayClient/src/BintrayClient.cpp +++ b/lib/BintrayClient/src/BintrayClient.cpp @@ -109,7 +109,7 @@ String BintrayClient::getLatestVersion() const const size_t bufferSize = 1024; if (jsonResult.length() > bufferSize) { - Serial.println("Error: Could parse JSON. Input data is too big!"); + ESP_LOGI(TAG, "Error: Could not parse JSON. Input data is too big!"); return version; } StaticJsonBuffer jsonBuffer; @@ -118,7 +118,7 @@ String BintrayClient::getLatestVersion() const // Check for errors in parsing if (!root.success()) { - Serial.println("Error: Could not parse JSON!"); + ESP_LOGI(TAG, "Error: Could not parse JSON!"); return version; } return root.get("name"); @@ -133,7 +133,7 @@ String BintrayClient::getBinaryPath(const String &version) const const size_t bufferSize = 1024; if (jsonResult.length() > bufferSize) { - Serial.println("Error: Could parse JSON. Input data is too big!"); + ESP_LOGI(TAG, "Error: Could parse JSON. Input data is too big!"); return path; } StaticJsonBuffer jsonBuffer; @@ -142,7 +142,7 @@ String BintrayClient::getBinaryPath(const String &version) const JsonObject &firstItem = root[0]; if (!root.success()) { //Check for errors in parsing - Serial.println("Error: Could not parse JSON!"); + ESP_LOGI(TAG, "Error: Could not parse JSON!"); return path; } return "/" + getUser() + "/" + getRepository() + "/" + firstItem.get("path"); diff --git a/platformio.ini b/platformio.ini index 91ee4e271..b07f4d49d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -56,25 +56,7 @@ build_flags = '-DBINTRAY_REPO="${bintray.repository}"' '-DBINTRAY_PACKAGE="${bintray.package}"' '-DVERSION=0' - -; extra dependencies -lib_deps = ArduinoJson - - -[common_env_data] -platform_espressif32 = espressif32@1.2.0 -;platform_espressif32 = https://github.com/platformio/platform-espressif32.git#feature/stage -;board_build.partitions = no_ota.csv -board_build.partitions = min_spiffs.csv -lib_deps_all = -lib_deps_display = - U8g2@>=2.23.12 -lib_deps_rgbled = - SmartLeds@>=1.1.3 -lib_deps_gps = - TinyGPSPlus@>=1.0.2 - Time@>=1.5 -build_flags = +; ; ---> NOTE: For production run set DEBUG_LEVEL level to NONE! <--- ; otherwise device may leak RAM ; @@ -90,13 +72,28 @@ build_flags = ; -DCORE_DEBUG_LEVEL=4 ; Verbose ; -DCORE_DEBUG_LEVEL=5 -; + +[common_env_data] +platform_espressif32 = espressif32@1.2.0 +;platform_espressif32 = https://github.com/platformio/platform-espressif32.git#feature/stage +;board_build.partitions = no_ota.csv +board_build.partitions = min_spiffs.csv +lib_deps_all = + ArduinoJson +lib_deps_display = + U8g2@>=2.23.12 +lib_deps_rgbled = + SmartLeds@>=1.1.3 +lib_deps_gps = + TinyGPSPlus@>=1.0.2 + Time@>=1.5 +build_flags = ; override lora settings from LMiC library in lmic/config.h and use main.h instead -D_lmic_config_h_ -include "src/paxcounter.conf" -include "src/hal/${PIOENV}.h" -w - + [env:ebox] platform = ${common_env_data.platform_espressif32} framework = arduino diff --git a/src/OTA.cpp b/src/OTA.cpp new file mode 100644 index 000000000..7b9849cd2 --- /dev/null +++ b/src/OTA.cpp @@ -0,0 +1,30 @@ +#include "OTA.h" + +const BintrayClient bintray(BINTRAY_USER, BINTRAY_REPO, BINTRAY_PACKAGE); + +void ota_wifi_init(void) { + const int RESPONSE_TIMEOUT_MS = 5000; + unsigned long timeout = millis(); + + ESP_ERROR_CHECK(esp_wifi_set_promiscuous(false)); // switch off monitor mode + tcpip_adapter_init(); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_start()); + + WiFi.begin(WIFI_SSID, WIFI_PASS); + WiFi.setHostname(PROGNAME); + +/* + while (WiFi.status() != WL_CONNECTED) { + ESP_LOGI(TAG, "WiFi Status %d", WiFi.status()); + if (millis() - timeout > RESPONSE_TIMEOUT_MS) { + ESP_LOGE(TAG, "WiFi connection timeout. Please check your settings!"); + } + + delay(500); + } + + configASSERT(WiFi.isConnected() == true); +*/ + +} \ No newline at end of file diff --git a/src/OTA.h b/src/OTA.h new file mode 100644 index 000000000..5133a685a --- /dev/null +++ b/src/OTA.h @@ -0,0 +1,11 @@ +#ifndef OTA_H +#define OTA_H + +#include +#include "globals.h" +#include +#include + +void ota_wifi_init(void); + +#endif // OTA_H \ No newline at end of file diff --git a/src/SecureOTA.cpp b/src/SecureOTA.cpp index 7496c19c7..2ce69eca4 100644 --- a/src/SecureOTA.cpp +++ b/src/SecureOTA.cpp @@ -37,16 +37,16 @@ void checkFirmwareUpdates() const String latest = bintray.getLatestVersion(); if (latest.length() == 0) { - Serial.println("Could not load info about the latest firmware, so nothing to update. Continue ..."); + ESP_LOGI(TAG, "Could not load info about the latest firmware, so nothing to update. Continue ..."); return; } else if (atoi(latest.c_str()) <= VERSION) { - //Serial.println("The current firmware is up to date. Continue ..."); + //ESP_LOGI(TAG, "The current firmware is up to date. Continue ..."); return; } - Serial.println("There is a new version of firmware available: v." + latest); + ESP_LOGI(TAG, "There is a new version of firmware available: v.%s", latest); processOTAUpdate(latest); } @@ -64,7 +64,7 @@ void processOTAUpdate(const String &version) String firmwarePath = bintray.getBinaryPath(version); if (!firmwarePath.endsWith(".bin")) { - Serial.println("Unsupported binary format. OTA update cannot be performed!"); + ESP_LOGI(TAG, "Unsupported binary format. OTA update cannot be performed!"); return; } @@ -76,7 +76,7 @@ void processOTAUpdate(const String &version) if (!client.connect(currentHost.c_str(), port)) { - Serial.println("Cannot connect to " + currentHost); + ESP_LOGI(TAG, "Cannot connect to %s", currentHost); return; } @@ -89,12 +89,12 @@ void processOTAUpdate(const String &version) client.setCACert(bintray.getCertificate(currentHost)); if (!client.connect(currentHost.c_str(), port)) { - Serial.println("Redirect detected! Cannot connect to " + currentHost + " for some reason!"); + ESP_LOGI(TAG, "Redirect detected! Cannot connect to %s for some reason!", currentHost); return; } } - //Serial.println("Requesting: " + firmwarePath); + //ESP_LOGI(TAG, "Requesting: " + firmwarePath); client.print(String("GET ") + firmwarePath + " HTTP/1.1\r\n"); client.print(String("Host: ") + currentHost + "\r\n"); @@ -106,7 +106,7 @@ void processOTAUpdate(const String &version) { if (millis() - timeout > RESPONSE_TIMEOUT_MS) { - Serial.println("Client Timeout !"); + ESP_LOGI(TAG, "Client Timeout !"); client.stop(); return; } @@ -128,17 +128,17 @@ void processOTAUpdate(const String &version) { if (line.indexOf("200") > 0) { - //Serial.println("Got 200 status code from server. Proceeding to firmware flashing"); + ESP_LOGI(TAG, "Got 200 status code from server. Proceeding to firmware flashing"); redirect = false; } else if (line.indexOf("302") > 0) { - //Serial.println("Got 302 status code from server. Redirecting to the new address"); + ESP_LOGI(TAG, "Got 302 status code from server. Redirecting to the new address"); redirect = true; } else { - //Serial.println("Could not get a valid firmware url"); + ESP_LOGI(TAG, "Could not get a valid firmware url"); //Unexptected HTTP response. Retry or skip update? redirect = false; } @@ -148,12 +148,12 @@ void processOTAUpdate(const String &version) if (line.startsWith("Location: ")) { String newUrl = getHeaderValue(line, "Location: "); - //Serial.println("Got new url: " + newUrl); + 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; - //Serial.println("firmwarePath: " + firmwarePath); + ESP_LOGI(TAG, "firmwarePath: %s", firmwarePath); continue; } @@ -161,13 +161,13 @@ void processOTAUpdate(const String &version) if (line.startsWith("Content-Length: ")) { contentLength = atoi((getHeaderValue(line, "Content-Length: ")).c_str()); - Serial.println("Got " + String(contentLength) + " bytes from server"); + ESP_LOGI(TAG, "Got %s bytes from server", String(contentLength)); } if (line.startsWith("Content-Type: ")) { String contentType = getHeaderValue(line, "Content-Type: "); - //Serial.println("Got " + contentType + " payload."); + ESP_LOGI(TAG, "Got %s payload", contentType); if (contentType == "application/octet-stream") { isValidContentType = true; @@ -181,16 +181,16 @@ void processOTAUpdate(const String &version) { if (Update.begin(contentLength)) { - Serial.println("Starting Over-The-Air update. This may take some time to complete ..."); + ESP_LOGI(TAG, "Starting Over-The-Air update. This may take some time to complete ..."); size_t written = Update.writeStream(client); if (written == contentLength) { - Serial.println("Written : " + String(written) + " successfully"); + ESP_LOGI(TAG, "Written %s successfully", String(written)); } else { - Serial.println("Written only : " + String(written) + "/" + String(contentLength) + ". Retry?"); + ESP_LOGI(TAG, "Written only %s / %s Retry?", String(written), String(contentLength)); // Retry?? } @@ -198,28 +198,28 @@ void processOTAUpdate(const String &version) { if (Update.isFinished()) { - Serial.println("OTA update has successfully completed. Rebooting ..."); + ESP_LOGI(TAG, "OTA update has successfully completed. Rebooting ..."); ESP.restart(); } else { - Serial.println("Something went wrong! OTA update hasn't been finished properly."); + ESP_LOGI(TAG, "Something went wrong! OTA update hasn't been finished properly."); } } else { - Serial.println("An error Occurred. Error #: " + String(Update.getError())); + ESP_LOGI(TAG, "An error occurred. Error #: %s", String(Update.getError())); } } else { - Serial.println("There isn't enough space to start OTA update"); + ESP_LOGI(TAG, "There isn't enough space to start OTA update"); client.flush(); } } else { - Serial.println("There was no valid content in the response from the OTA server!"); + ESP_LOGI(TAG, "There was no valid content in the response from the OTA server!"); client.flush(); } } \ No newline at end of file diff --git a/src/TTN/packed_decoder.js b/src/TTN/packed_decoder.js index 6bf29f09d..32d6dc9f4 100644 --- a/src/TTN/packed_decoder.js +++ b/src/TTN/packed_decoder.js @@ -18,7 +18,7 @@ function Decoder(bytes, port) { if (port === 2) { // device status data - return decode(bytes, [uint16, uptime, temperature, uint32], ['voltage', 'uptime', 'cputemp', 'memory']); + return decode(bytes, [uint16, uptime, temperature, uint32, uint8, uint8], ['voltage', 'uptime', 'cputemp', 'memory', 'reset', 'reset']); } @@ -181,6 +181,7 @@ if (typeof module === 'object' && typeof module.exports !== 'undefined') { uint16: uint16, uint32: uint32, uptime: uptime, + reset: reset, temperature: temperature, humidity: humidity, latLng: latLng, diff --git a/src/globals.h b/src/globals.h index 1043b13ab..879a30e1f 100644 --- a/src/globals.h +++ b/src/globals.h @@ -51,7 +51,7 @@ extern hw_timer_t *channelSwitch, *sendCycle; extern portMUX_TYPE timerMux; extern volatile int SendCycleTimerIRQ, HomeCycleIRQ, DisplayTimerIRQ, ChannelTimerIRQ, ButtonPressedIRQ; -extern QueueHandle_t LoraSendQueue, SPISendQueue; +//extern QueueHandle_t LoraSendQueue, SPISendQueue; extern TaskHandle_t WifiLoopTask; extern std::array::iterator it; @@ -68,9 +68,15 @@ extern std::array beacons; #include "payload.h" #ifdef HAS_LORA +extern QueueHandle_t LoraSendQueue; +extern TaskHandle_t LoraTask; #include "lorawan.h" #endif +#ifdef HAS_SPI +extern QueueHandle_t SPISendQueue; +#endif + #ifdef HAS_DISPLAY #include "display.h" #endif diff --git a/src/main.cpp b/src/main.cpp index b3825cb62..fe5d57424 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,6 +46,7 @@ TaskHandle_t WifiLoopTask = NULL; // RTos send queues for payload transmit #ifdef HAS_LORA QueueHandle_t LoraSendQueue; +TaskHandle_t LoraTask = NULL; #endif #ifdef HAS_SPI @@ -271,7 +272,7 @@ void setup() { ESP_LOGI(TAG, "Starting Lora task on core 1"); xTaskCreatePinnedToCore(lorawan_loop, "loraloop", 2048, (void *)1, - (5 | portPRIVILEGE_BIT), NULL, 1); + (5 | portPRIVILEGE_BIT), &LoraTask, 1); #endif // if device has GPS and it is enabled, start GPS reader task on core 0 with @@ -332,6 +333,8 @@ void loop() { processSendBuffer(); // check send cycle and enqueue payload if cycle is expired sendPayload(); + // reset watchdog + vTaskDelay(1 / portTICK_PERIOD_MS); } // loop() } diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 7cf76677b..bcecc56d7 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -9,7 +9,7 @@ // Payload send cycle and encoding #define SEND_SECS 30 // payload send cycle [seconds/2] -> 60 sec. -#define PAYLOAD_ENCODER 1 // payload encoder: 1=Plain, 2=Packed, 3=CayenneLPP dynamic, 4=CayenneLPP packed +#define PAYLOAD_ENCODER 2 // payload encoder: 1=Plain, 2=Packed, 3=CayenneLPP dynamic, 4=CayenneLPP packed // Set this to include BLE counting and vendor filter functions #define VENDORFILTER 1 // comment out if you want to count things, not people diff --git a/src/payload.cpp b/src/payload.cpp index ab3d2c916..958d3fb31 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -52,8 +52,8 @@ void PayloadConvert::addConfig(configData_t value) { cursor += 10; } -void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, - float cputemp, uint32_t mem) { +void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, float cputemp, + uint32_t mem, uint8_t reset1, uint8_t reset2) { uint32_t temp = (uint32_t)cputemp; buffer[cursor++] = highByte(voltage); buffer[cursor++] = lowByte(voltage); @@ -73,6 +73,8 @@ void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, buffer[cursor++] = (byte)((mem & 0x00FF0000) >> 16); buffer[cursor++] = (byte)((mem & 0x0000FF00) >> 8); buffer[cursor++] = (byte)((mem & 0x000000FF)); + buffer[cursor++] = (byte)(reset1); + buffer[cursor++] = (byte)(reset2); } #ifdef HAS_GPS @@ -127,12 +129,14 @@ void PayloadConvert::addConfig(configData_t value) { value.vendorfilter ? true : false, value.gpsmode ? true : false); } -void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, - float cputemp, uint32_t mem) { +void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, float cputemp, + uint32_t mem, uint8_t reset1, uint8_t reset2) { writeUint16(voltage); writeUptime(uptime); writeTemperature(cputemp); writeUint32(mem); + writeUint8(reset1); + writeUint8(reset2); } #ifdef HAS_GPS @@ -245,8 +249,8 @@ void PayloadConvert::addConfig(configData_t value) { buffer[cursor++] = value.adrmode; } -void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, - float celsius, uint32_t mem) { +void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, float celsius, + uint32_t mem, uint8_t reset1, uint8_t reset2) { uint16_t temp = celsius * 10; uint16_t volt = voltage / 10; #ifdef HAS_BATTERY_PROBE diff --git a/src/payload.h b/src/payload.h index ba564ec7b..92f2d4ee6 100644 --- a/src/payload.h +++ b/src/payload.h @@ -35,7 +35,8 @@ class PayloadConvert { uint8_t *getBuffer(void); void addCount(uint16_t value1, uint16_t value2); void addConfig(configData_t value); - void addStatus(uint16_t voltage, uint64_t uptime, float cputemp, uint32_t mem); + void addStatus(uint16_t voltage, uint64_t uptime, float cputemp, uint32_t mem, + uint8_t reset1, uint8_t reset2); void addAlarm(int8_t rssi, uint8_t message); #ifdef HAS_GPS void addGPS(gpsStatus_t value); @@ -44,7 +45,6 @@ class PayloadConvert { void addButton(uint8_t value); #endif - #if PAYLOAD_ENCODER == 1 // format plain private: @@ -77,7 +77,6 @@ class PayloadConvert { #else #error "No valid payload converter defined" #endif - }; extern PayloadConvert payload; diff --git a/src/rcommand.cpp b/src/rcommand.cpp index 70ac4c8e6..63fcd690f 100644 --- a/src/rcommand.cpp +++ b/src/rcommand.cpp @@ -203,7 +203,8 @@ void get_status(uint8_t val[]) { #endif payload.reset(); payload.addStatus(voltage, uptime() / 1000, temperatureRead(), - ESP.getFreeHeap()); + ESP.getFreeHeap(), rtc_get_reset_reason(0), + rtc_get_reset_reason(1)); SendData(STATUSPORT); }; @@ -225,21 +226,13 @@ void set_update(uint8_t val[]) { ESP_LOGI(TAG, "Stopping Wifi task on core 0"); vTaskDelete(WifiLoopTask); - ESP_LOGI(TAG, "Connecting to %s", WIFI_SSID); - ESP_ERROR_CHECK(esp_wifi_set_promiscuous(false)); // switch off monitor mode - //tcpipInit(); - tcpip_adapter_init(); - WiFi.mode(WIFI_STA); - - WiFi.begin(WIFI_SSID, WIFI_PASS); - - while (WiFi.status() != WL_CONNECTED) { - ESP_LOGI(TAG, "."); - delay(500); - } + ESP_LOGI(TAG, "Stopping LORA task on core 1"); + vTaskDelete(LoraTask); - ESP_LOGI(TAG, "connected!"); + ESP_LOGI(TAG, "Connecting to %s", WIFI_SSID); + ota_wifi_init(); checkFirmwareUpdates(); + }; // assign previously defined functions to set of numeric remote commands diff --git a/src/rcommand.h b/src/rcommand.h index 2d1902a1f..880382ed7 100644 --- a/src/rcommand.h +++ b/src/rcommand.h @@ -5,6 +5,8 @@ #include "configmanager.h" #include "lorawan.h" #include "macsniff.h" +#include +#include "ota.h" #include #include "SecureOTA.h" diff --git a/src/wifiscan.cpp b/src/wifiscan.cpp index 4190e182b..9cb2ae989 100644 --- a/src/wifiscan.cpp +++ b/src/wifiscan.cpp @@ -36,6 +36,7 @@ void wifi_sniffer_init(void) { ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM)); // we don't need NVRAM ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL)); + ESP_ERROR_CHECK(esp_wifi_stop()); ESP_ERROR_CHECK( esp_wifi_set_promiscuous_filter(&filter)); // set MAC frame filter ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(&wifi_sniffer_packet_handler)); From 0ee138b02229357a8653d3ac637a926ec35d2e8e Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 12 Aug 2018 23:42:39 +0200 Subject: [PATCH 03/43] JFrog Bintray OTA (experimental, not working yet) --- platformio.ini | 8 ++----- src/OTA.cpp | 62 ++++++++++++++++++++++++++++++++++++------------ src/OTA.h | 4 +++- src/cyclic.cpp | 4 ++++ src/globals.h | 5 ++-- src/main.cpp | 11 ++++++--- src/rcommand.cpp | 12 +--------- src/rcommand.h | 4 ---- 8 files changed, 68 insertions(+), 42 deletions(-) diff --git a/platformio.ini b/platformio.ini index b07f4d49d..ddf0adc79 100644 --- a/platformio.ini +++ b/platformio.ini @@ -32,14 +32,10 @@ user = cyberman54 repository = paxcounter package = esp32-paxcounter api_token = 9f02e2a2374c278fd79d5bcf4b4442fca9752012 -;api_token = ${env.BINTRAY_API_TOKEN} -; Wi-Fi network settings [wifi] -ssid = PRENZLNET-G -password = 435Huse8!? -;ssid = ${env.PIO_WIFI_SSID} -;password = ${env.PIO_WIFI_PASSWORD} +ssid = *** +password = *** [common] platform = https://github.com/platformio/platform-espressif32.git diff --git a/src/OTA.cpp b/src/OTA.cpp index 7b9849cd2..23d64f5c8 100644 --- a/src/OTA.cpp +++ b/src/OTA.cpp @@ -2,29 +2,61 @@ const BintrayClient bintray(BINTRAY_USER, BINTRAY_REPO, BINTRAY_PACKAGE); +bool Wifi_Connected = false; + +static esp_err_t event_handler(void *ctx, system_event_t *event) { + switch (event->event_id) { + case SYSTEM_EVENT_STA_START: + esp_wifi_connect(); + break; + case SYSTEM_EVENT_STA_GOT_IP: + Wifi_Connected = true; + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + Wifi_Connected = false; + break; + default: + break; + } +} + void ota_wifi_init(void) { - const int RESPONSE_TIMEOUT_MS = 5000; - unsigned long timeout = millis(); - ESP_ERROR_CHECK(esp_wifi_set_promiscuous(false)); // switch off monitor mode + // initialize the tcp stack tcpip_adapter_init(); + + // initialize the wifi event handler + ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + wifi_config_t sta_config = {}; + + strcpy((char *)sta_config.sta.ssid, WIFI_SSID); + strcpy((char *)sta_config.sta.password, WIFI_PASS); + sta_config.sta.bssid_set = false; + + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); ESP_ERROR_CHECK(esp_wifi_start()); - WiFi.begin(WIFI_SSID, WIFI_PASS); - WiFi.setHostname(PROGNAME); + // 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)); -/* - while (WiFi.status() != WL_CONNECTED) { - ESP_LOGI(TAG, "WiFi Status %d", WiFi.status()); - if (millis() - timeout > RESPONSE_TIMEOUT_MS) { - ESP_LOGE(TAG, "WiFi connection timeout. Please check your settings!"); - } +} - delay(500); - } +void start_ota_update() { + ESP_LOGI(TAG, "Stopping Wifi task on core 0"); + vTaskDelete(WifiLoopTask); - configASSERT(WiFi.isConnected() == true); -*/ + ESP_LOGI(TAG, "Stopping LORA task on core 1"); + vTaskDelete(LoraTask); + ESP_LOGI(TAG, "Connecting to %s", WIFI_SSID); + ota_wifi_init(); + checkFirmwareUpdates(); + ESP.restart(); // reached if update was not successful } \ No newline at end of file diff --git a/src/OTA.h b/src/OTA.h index 5133a685a..8b6a27dfc 100644 --- a/src/OTA.h +++ b/src/OTA.h @@ -5,7 +5,9 @@ #include "globals.h" #include #include +#include "ota.h" +#include "SecureOTA.h" -void ota_wifi_init(void); +void start_ota_update(); #endif // OTA_H \ No newline at end of file diff --git a/src/cyclic.cpp b/src/cyclic.cpp index adbadda4a..45ce16cda 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -4,6 +4,7 @@ // Basic config #include "globals.h" #include "senddata.h" +#include "ota.h" // Local logging tag static const char TAG[] = "main"; @@ -14,6 +15,9 @@ void doHomework() { // update uptime counter uptime(); + if (ota_update) + start_ota_update(); + // read battery voltage into global variable #ifdef HAS_BATTERY_PROBE batt_voltage = read_voltage(); diff --git a/src/globals.h b/src/globals.h index 879a30e1f..53aad8203 100644 --- a/src/globals.h +++ b/src/globals.h @@ -42,7 +42,8 @@ typedef struct { } MessageBuffer_t; // global variables -extern configData_t cfg; // current device configuration +extern configData_t cfg; // current device configuration +extern bool ota_update; extern char display_line6[], display_line7[]; // screen buffers extern uint8_t channel; // wifi channel rotation counter extern uint16_t macs_total, macs_wifi, macs_ble, batt_voltage; // display values @@ -51,7 +52,7 @@ extern hw_timer_t *channelSwitch, *sendCycle; extern portMUX_TYPE timerMux; extern volatile int SendCycleTimerIRQ, HomeCycleIRQ, DisplayTimerIRQ, ChannelTimerIRQ, ButtonPressedIRQ; -//extern QueueHandle_t LoraSendQueue, SPISendQueue; +// extern QueueHandle_t LoraSendQueue, SPISendQueue; extern TaskHandle_t WifiLoopTask; extern std::array::iterator it; diff --git a/src/main.cpp b/src/main.cpp index fe5d57424..d52b4a7ac 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,7 +27,8 @@ licenses. Refer to LICENSE.txt file in repository for more details. #include "globals.h" #include "main.h" -configData_t cfg; // struct holds current device configuration +configData_t cfg; // struct holds current device configuration +bool ota_update = false; // triggers OTA update char display_line6[16], display_line7[16]; // display buffers uint8_t channel = 0; // channel rotation counter uint16_t macs_total = 0, macs_wifi = 0, macs_ble = 0, @@ -70,6 +71,9 @@ static const char TAG[] = "main"; void setup() { + // disable the default wifi logging + esp_log_level_set("wifi", ESP_LOG_NONE); + char features[100] = ""; // disable brownout detection @@ -92,7 +96,8 @@ void setup() { // initialize system event handler for wifi task, needed for // wifi_sniffer_init() - esp_event_loop_init(NULL, NULL); + // esp_event_loop_init(NULL, NULL); + //ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); // print chip information on startup if in verbose mode #ifdef VERBOSE @@ -333,7 +338,7 @@ void loop() { processSendBuffer(); // check send cycle and enqueue payload if cycle is expired sendPayload(); - // reset watchdog + // reset watchdog vTaskDelay(1 / portTICK_PERIOD_MS); } // loop() diff --git a/src/rcommand.cpp b/src/rcommand.cpp index 63fcd690f..a052c48ea 100644 --- a/src/rcommand.cpp +++ b/src/rcommand.cpp @@ -222,17 +222,7 @@ void get_gps(uint8_t val[]) { void set_update(uint8_t val[]) { ESP_LOGI(TAG, "Remote command: get firmware update"); - - ESP_LOGI(TAG, "Stopping Wifi task on core 0"); - vTaskDelete(WifiLoopTask); - - ESP_LOGI(TAG, "Stopping LORA task on core 1"); - vTaskDelete(LoraTask); - - ESP_LOGI(TAG, "Connecting to %s", WIFI_SSID); - ota_wifi_init(); - checkFirmwareUpdates(); - + ota_update = true; }; // assign previously defined functions to set of numeric remote commands diff --git a/src/rcommand.h b/src/rcommand.h index 880382ed7..c656c9fdb 100644 --- a/src/rcommand.h +++ b/src/rcommand.h @@ -6,10 +6,6 @@ #include "lorawan.h" #include "macsniff.h" #include -#include "ota.h" - -#include -#include "SecureOTA.h" // table of remote commands and assigned functions typedef struct { From 7a58c8dece3a8a3e0384b8c748633e82cc362314 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Thu, 16 Aug 2018 21:10:13 +0200 Subject: [PATCH 04/43] testing --- src/OTA.cpp | 47 ++++++++++++++++++++++++++++++++--------------- src/wifiscan.cpp | 2 +- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/OTA.cpp b/src/OTA.cpp index 23d64f5c8..1ec3be8ef 100644 --- a/src/OTA.cpp +++ b/src/OTA.cpp @@ -4,16 +4,23 @@ const BintrayClient bintray(BINTRAY_USER, BINTRAY_REPO, BINTRAY_PACKAGE); bool Wifi_Connected = false; -static esp_err_t event_handler(void *ctx, system_event_t *event) { +esp_err_t event_handler(void *ctx, system_event_t *event) { switch (event->event_id) { 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; @@ -22,30 +29,38 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { void ota_wifi_init(void) { + tcpip_adapter_if_t tcpip_if = TCPIP_ADAPTER_IF_STA; + // initialize the tcp stack + // nvs_flash_init(); tcpip_adapter_init(); + tcpip_adapter_set_hostname(tcpip_if, PROGNAME); + tcpip_adapter_dhcpc_start(tcpip_if); // initialize the wifi event handler ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - wifi_config_t sta_config = {}; + // switch off monitor more + ESP_ERROR_CHECK( + esp_wifi_set_promiscuous(false)); // now switch on monitor mode + ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(NULL)); - strcpy((char *)sta_config.sta.ssid, WIFI_SSID); - strcpy((char *)sta_config.sta.password, WIFI_PASS); - sta_config.sta.bssid_set = false; + wifi_sta_config_t cfg; + strcpy((char *)cfg.ssid, WIFI_SSID); + strcpy((char *)cfg.password, WIFI_PASS); + cfg.bssid_set = false; - ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); - ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); - ESP_ERROR_CHECK(esp_wifi_start()); + wifi_config_t sta_cfg; + sta_cfg.sta = cfg; - // 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)); + wifi_init_config_t wifi_cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&wifi_cfg)); + ESP_ERROR_CHECK( + esp_wifi_set_storage(WIFI_STORAGE_RAM)); // we don't need NVRAM + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_cfg)); + ESP_ERROR_CHECK(esp_wifi_start()); } void start_ota_update() { @@ -57,6 +72,8 @@ void start_ota_update() { ESP_LOGI(TAG, "Connecting to %s", WIFI_SSID); ota_wifi_init(); + delay(2000); + delay(2000); checkFirmwareUpdates(); ESP.restart(); // reached if update was not successful } \ No newline at end of file diff --git a/src/wifiscan.cpp b/src/wifiscan.cpp index 9cb2ae989..24d6504fd 100644 --- a/src/wifiscan.cpp +++ b/src/wifiscan.cpp @@ -6,7 +6,7 @@ static const char TAG[] = "wifi"; static wifi_country_t wifi_country = {WIFI_MY_COUNTRY, WIFI_CHANNEL_MIN, - WIFI_CHANNEL_MAX, 0, + WIFI_CHANNEL_MAX, 100, WIFI_COUNTRY_POLICY_MANUAL}; // using IRAM_:ATTR here to speed up callback function From 48734bca632350cd8a55af68a7eae49f8d982e5a Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Thu, 13 Sep 2018 21:50:45 +0200 Subject: [PATCH 05/43] lmic/radio.c: Fix RSSI and SNR calculation --- lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/radio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/radio.c b/lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/radio.c index 780226c2c..0fffaa4f3 100644 --- a/lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/radio.c +++ b/lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/radio.c @@ -790,8 +790,12 @@ void radio_irq_handler (u1_t dio) { // now read the FIFO readBuf(RegFifo, LMIC.frame, LMIC.dataLen); // read rx quality parameters - LMIC.snr = readReg(LORARegPktSnrValue); // SNR [dB] * 4 - LMIC.rssi = readReg(LORARegPktRssiValue) - 125 + 64; // RSSI [dBm] (-196...+63) + //LMIC.snr = readReg(LORARegPktSnrValue); // SNR [dB] * 4 + LMIC.snr = readReg(LORARegPktSnrValue) / 4; + //LMIC.rssi = readReg(LORARegPktRssiValue) - 125 + 64; // RSSI [dBm] (-196...+63) + LMIC.rssi = readReg(LORARegPktRssiValue) - 157; // RFI_HF for 868 and 915MHZ band + if (LMIC.snr < 0) + LMIC.rssi += LMIC.snr; } else if( flags & IRQ_LORA_RXTOUT_MASK ) { // indicate timeout LMIC.dataLen = 0; From 38dc2667abd921cfb529c06af5f492d2422e766a Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 15 Sep 2018 14:47:13 +0200 Subject: [PATCH 06/43] ota-test first push --- platformio.ini | 17 +++++++---- publish_firmware.py | 71 +++++++++++++++++++++++++++++++++++++++++++++ src/SecureOTA.cpp | 26 ++++++++++------- 3 files changed, 97 insertions(+), 17 deletions(-) create mode 100644 publish_firmware.py diff --git a/platformio.ini b/platformio.ini index ddf0adc79..65eb1107e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,6 +9,7 @@ ; http://docs.platformio.org/page/projectconf.html + ; ---> SELECT TARGET PLATFORM HERE! <--- [platformio] ;env_default = generic @@ -29,9 +30,9 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng [bintray] user = cyberman54 -repository = paxcounter -package = esp32-paxcounter -api_token = 9f02e2a2374c278fd79d5bcf4b4442fca9752012 +repository = paxcounter-firmware +package = ttgov21_old +api_token = *** [wifi] ssid = *** @@ -42,7 +43,8 @@ platform = https://github.com/platformio/platform-espressif32.git ; firmware version, please modify it between releases ; positive integer value -release_version = 1 +;release_version = 1.4.30 +release_version = 4 ; build configuration based on Bintray and Wi-Fi settings build_flags = @@ -51,7 +53,7 @@ build_flags = '-DBINTRAY_USER="${bintray.user}"' '-DBINTRAY_REPO="${bintray.repository}"' '-DBINTRAY_PACKAGE="${bintray.package}"' - '-DVERSION=0' + -DVERSION=${common.release_version} ; ; ---> NOTE: For production run set DEBUG_LEVEL level to NONE! <--- ; otherwise device may leak RAM @@ -70,7 +72,7 @@ build_flags = ; -DCORE_DEBUG_LEVEL=5 [common_env_data] -platform_espressif32 = espressif32@1.2.0 +platform_espressif32 = espressif32@1.3.0 ;platform_espressif32 = https://github.com/platformio/platform-espressif32.git#feature/stage ;board_build.partitions = no_ota.csv board_build.partitions = min_spiffs.csv @@ -142,6 +144,7 @@ build_flags = ${common_env_data.build_flags} [env:ttgov21] +bintraypackage = ttgov21_old platform = ${common_env_data.platform_espressif32} framework = arduino board = esp32dev @@ -154,6 +157,8 @@ lib_deps = build_flags = ${common.build_flags} ${common_env_data.build_flags} +upload_protocol = custom +extra_scripts = pre:publish_firmware.py [env:ttgobeam] platform = ${common_env_data.platform_espressif32} diff --git a/publish_firmware.py b/publish_firmware.py new file mode 100644 index 000000000..7086d0138 --- /dev/null +++ b/publish_firmware.py @@ -0,0 +1,71 @@ +# Copyright (c) 2014-present PlatformIO +# +# 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 +) \ No newline at end of file diff --git a/src/SecureOTA.cpp b/src/SecureOTA.cpp index 2ce69eca4..8b35c93bd 100644 --- a/src/SecureOTA.cpp +++ b/src/SecureOTA.cpp @@ -31,9 +31,13 @@ const uint32_t RESPONSE_TIMEOUT_MS = 5000; volatile int contentLength = 0; volatile bool isValidContentType = false; +// Local logging tag +static const char TAG[] = "main"; + void checkFirmwareUpdates() { // Fetch the latest firmware version + ESP_LOGI(TAG, "Checking latest firmware version..."); const String latest = bintray.getLatestVersion(); if (latest.length() == 0) { @@ -42,11 +46,11 @@ void checkFirmwareUpdates() } else if (atoi(latest.c_str()) <= VERSION) { - //ESP_LOGI(TAG, "The current firmware is up to date. Continue ..."); + 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); + ESP_LOGI(TAG, "There is a new version of firmware available: v.%s", latest.c_str()); processOTAUpdate(latest); } @@ -76,7 +80,7 @@ void processOTAUpdate(const String &version) if (!client.connect(currentHost.c_str(), port)) { - ESP_LOGI(TAG, "Cannot connect to %s", currentHost); + ESP_LOGI(TAG, "Cannot connect to %s", currentHost.c_str()); return; } @@ -89,7 +93,7 @@ void processOTAUpdate(const String &version) 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); + ESP_LOGI(TAG, "Redirect detected! Cannot connect to %s for some reason!", currentHost.c_str()); return; } } @@ -148,12 +152,12 @@ void processOTAUpdate(const String &version) if (line.startsWith("Location: ")) { String newUrl = getHeaderValue(line, "Location: "); - ESP_LOGI(TAG, "Got new url: %s", newUrl); + 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); + ESP_LOGI(TAG, "firmwarePath: %s", firmwarePath.c_str()); continue; } @@ -161,13 +165,13 @@ void processOTAUpdate(const String &version) if (line.startsWith("Content-Length: ")) { contentLength = atoi((getHeaderValue(line, "Content-Length: ")).c_str()); - ESP_LOGI(TAG, "Got %s bytes from server", String(contentLength)); + 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); + ESP_LOGI(TAG, "Got %s payload", contentType.c_str()); if (contentType == "application/octet-stream") { isValidContentType = true; @@ -186,11 +190,11 @@ void processOTAUpdate(const String &version) if (written == contentLength) { - ESP_LOGI(TAG, "Written %s successfully", String(written)); + ESP_LOGI(TAG, "Written %d successfully", written); } else { - ESP_LOGI(TAG, "Written only %s / %s Retry?", String(written), String(contentLength)); + ESP_LOGI(TAG, "Written only %d / %d Retry?", written, contentLength); // Retry?? } @@ -208,7 +212,7 @@ void processOTAUpdate(const String &version) } else { - ESP_LOGI(TAG, "An error occurred. Error #: %s", String(Update.getError())); + ESP_LOGI(TAG, "An error occurred. Error #: %d", Update.getError()); } } else From 460606f6a4354e80910f1ebdc6fe2b640236688c Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 15 Sep 2018 14:52:46 +0200 Subject: [PATCH 07/43] protect platformio.ini against github upload --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 030b6f3dd..f1f6d7549 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ .clang_complete .gcc-flags.json src/loraconf.h +platformio.ini \ No newline at end of file From ffd7260223eddb30cfdc73368c6ee9e1abd60113 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 15 Sep 2018 14:53:34 +0200 Subject: [PATCH 08/43] add keys to platformio.ini wifi section --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index d6e092c01..764dd17c9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -35,8 +35,8 @@ package = ttgov21_old api_token = *** [wifi] -ssid = *** -password = *** +ssid = testnet +password = test0815 [common] platform = https://github.com/platformio/platform-espressif32.git From 11e3ee8a8819a8d220f0eeaf7873e53ea955b4b8 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 15 Sep 2018 14:55:53 +0200 Subject: [PATCH 09/43] testing --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 764dd17c9..975578c69 100644 --- a/platformio.ini +++ b/platformio.ini @@ -32,7 +32,7 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng user = cyberman54 repository = paxcounter-firmware package = ttgov21_old -api_token = *** +api_token = **** [wifi] ssid = testnet From 7bd0d4d2c3c0ae30c026f50c2a324076b09323c7 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 15 Sep 2018 15:02:03 +0200 Subject: [PATCH 10/43] remove platformio.ini from git working tree --- platformio.ini | 271 ------------------------------------------------- 1 file changed, 271 deletions(-) delete mode 100644 platformio.ini diff --git a/platformio.ini b/platformio.ini deleted file mode 100644 index 975578c69..000000000 --- a/platformio.ini +++ /dev/null @@ -1,271 +0,0 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; http://docs.platformio.org/page/projectconf.html - - - -; ---> SELECT TARGET PLATFORM HERE! <--- -[platformio] -;env_default = generic -;env_default = ebox -;env_default = heltec -;env_default = ttgov1 -;env_default = ttgov2 -env_default = ttgov21 -;env_default = ttgobeam -;env_default = lopy -;env_default = lopy4 -;env_default = fipy -;env_default = lolin32litelora -;env_default = lolin32lora -;env_default = lolin32lite -; -description = Paxcounter is a proof-of-concept ESP32 device for metering passenger flows in realtime. It counts how many mobile devices are around. - -[bintray] -user = cyberman54 -repository = paxcounter-firmware -package = ttgov21_old -api_token = **** - -[wifi] -ssid = testnet -password = test0815 - -[common] -platform = https://github.com/platformio/platform-espressif32.git - -; firmware version, please modify it between releases -; positive integer value -;release_version = 1.4.30 -release_version = 4 - -; build configuration based on Bintray and Wi-Fi settings -build_flags = - '-DWIFI_SSID="${wifi.ssid}"' - '-DWIFI_PASS="${wifi.password}"' - '-DBINTRAY_USER="${bintray.user}"' - '-DBINTRAY_REPO="${bintray.repository}"' - '-DBINTRAY_PACKAGE="${bintray.package}"' - -DVERSION=${common.release_version} -; -; ---> NOTE: For production run set DEBUG_LEVEL level to NONE! <--- -; otherwise device may leak RAM -; -; None -; -DCORE_DEBUG_LEVEL=0 -; Error -; -DCORE_DEBUG_LEVEL=1 -; Warn -; -DCORE_DEBUG_LEVEL=2 -; Info - -DCORE_DEBUG_LEVEL=3 -; Debug -; -DCORE_DEBUG_LEVEL=4 -; Verbose -; -DCORE_DEBUG_LEVEL=5 - -[common_env_data] -platform_espressif32 = espressif32@1.3.0 -;platform_espressif32 = https://github.com/platformio/platform-espressif32.git#feature/stage -;board_build.partitions = no_ota.csv -board_build.partitions = min_spiffs.csv -lib_deps_all = - ArduinoJson -lib_deps_display = - U8g2@>=2.23.16 -lib_deps_rgbled = - SmartLeds@>=1.1.3 -lib_deps_gps = - TinyGPSPlus@>=1.0.2 - Time@>=1.5 -build_flags = -; override lora settings from LMiC library in lmic/config.h and use main.h instead - -D_lmic_config_h_ - -include "src/paxcounter.conf" - -include "src/hal/${PIOENV}.h" - -w - -[env:ebox] -platform = ${common_env_data.platform_espressif32} -framework = arduino -board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} -upload_speed = 115200 -monitor_speed = 115200 -lib_deps = - ${common_env_data.lib_deps_all} -build_flags = - ${common_env_data.build_flags} - -[env:heltec] -platform = ${common_env_data.platform_espressif32} -framework = arduino -board = heltec_wifi_lora_32 -board_build.partitions = ${common_env_data.board_build.partitions} -upload_speed = 115200 -monitor_speed = 115200 -lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_display} -build_flags = - ${common_env_data.build_flags} - -[env:ttgov1] -platform = ${common_env_data.platform_espressif32} -framework = arduino -board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} -upload_speed = 115200 -monitor_speed = 115200 -lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_display} -build_flags = - ${common_env_data.build_flags} - -[env:ttgov2] -platform = ${common_env_data.platform_espressif32} -framework = arduino -board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} -upload_speed = 921600 -monitor_speed = 115200 -lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_display} -build_flags = - ${common_env_data.build_flags} - -[env:ttgov21] -bintraypackage = ttgov21_old -platform = ${common_env_data.platform_espressif32} -framework = arduino -board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} -upload_speed = 921600 -monitor_speed = 115200 -lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_display} -build_flags = - ${common.build_flags} - ${common_env_data.build_flags} -upload_protocol = custom -extra_scripts = pre:publish_firmware.py - -[env:ttgobeam] -platform = ${common_env_data.platform_espressif32} -framework = arduino -board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} -upload_speed = 921600 -monitor_speed = 115200 -lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_gps} -build_flags = - ${common_env_data.build_flags} - -mfix-esp32-psram-cache-issue - -[env:fipy] -platform = ${common_env_data.platform_espressif32} -framework = arduino -board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} -upload_speed = 921600 -monitor_speed = 115200 -lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_rgbled} -build_flags = - ${common_env_data.build_flags} - -[env:lopy] -platform = ${common_env_data.platform_espressif32} -framework = arduino -board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} -upload_speed = 921600 -monitor_speed = 115200 -lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_rgbled} - ${common_env_data.lib_deps_gps} -build_flags = - ${common_env_data.build_flags} - -[env:lopy4] -platform = ${common_env_data.platform_espressif32} -framework = arduino -board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} -upload_speed = 921600 -monitor_speed = 115200 -lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_rgbled} - ${common_env_data.lib_deps_gps} -build_flags = - ${common_env_data.build_flags} - -mfix-esp32-psram-cache-issue - -[env:lolin32litelora] -platform = ${common_env_data.platform_espressif32} -framework = arduino -board = lolin32 -board_build.partitions = ${common_env_data.board_build.partitions} -upload_speed = 921600 -monitor_speed = 115200 -lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_rgbled} -build_flags = - ${common_env_data.build_flags} - -[env:lolin32lora] -platform = ${common_env_data.platform_espressif32} -framework = arduino -board = lolin32 -board_build.partitions = ${common_env_data.board_build.partitions} -upload_speed = 921600 -monitor_speed = 115200 -lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_rgbled} -build_flags = - ${common_env_data.build_flags} - -[env:lolin32lite] -platform = ${common_env_data.platform_espressif32} -framework = arduino -board = lolin32 -board_build.partitions = ${common_env_data.board_build.partitions} -upload_speed = 921600 -monitor_speed = 115200 -lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_rgbled} -build_flags = - ${common_env_data.build_flags} - -[env:generic] -platform = ${common_env_data.platform_espressif32} -framework = arduino -board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} -upload_speed = 921600 -monitor_speed = 115200 -lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_rgbled} - ${common_env_data.lib_deps_gps} - ${common_env_data.lib_deps_display} -build_flags = - ${common_env_data.build_flags} From 5139f7f8c76fc79be7dd866c4c23a25c92f4c169 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sat, 15 Sep 2018 15:20:41 +0200 Subject: [PATCH 11/43] clean platformio.ini uploaded --- platformio.ini | 270 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 platformio.ini diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 000000000..17ab99e0f --- /dev/null +++ b/platformio.ini @@ -0,0 +1,270 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; http://docs.platformio.org/page/projectconf.html + + + +; ---> SELECT TARGET PLATFORM HERE! <--- +[platformio] +;env_default = generic +;env_default = ebox +;env_default = heltec +;env_default = ttgov1 +;env_default = ttgov2 +env_default = ttgov21 +;env_default = ttgobeam +;env_default = lopy +;env_default = lopy4 +;env_default = fipy +;env_default = lolin32litelora +;env_default = lolin32lora +;env_default = lolin32lite +; +description = Paxcounter is a proof-of-concept ESP32 device for metering passenger flows in realtime. It counts how many mobile devices are around. + +[bintray] +user = cyberman54 +repository = paxcounter-firmware +package = ttgov21_old +api_token = *** + +[wifi] +ssid = *** +password = *** + +[common] +platform = https://github.com/platformio/platform-espressif32.git + +; firmware version, please modify it between releases +; positive integer value +;release_version = 1.4.30 +release_version = 3 + +; build configuration based on Bintray and Wi-Fi settings +build_flags = + '-DWIFI_SSID="${wifi.ssid}"' + '-DWIFI_PASS="${wifi.password}"' + '-DBINTRAY_USER="${bintray.user}"' + '-DBINTRAY_REPO="${bintray.repository}"' + '-DBINTRAY_PACKAGE="${bintray.package}"' + -DVERSION=${common.release_version} +; +; ---> NOTE: For production run set DEBUG_LEVEL level to NONE! <--- +; otherwise device may leak RAM +; +; None +; -DCORE_DEBUG_LEVEL=0 +; Error +; -DCORE_DEBUG_LEVEL=1 +; Warn +; -DCORE_DEBUG_LEVEL=2 +; Info + -DCORE_DEBUG_LEVEL=3 +; Debug +; -DCORE_DEBUG_LEVEL=4 +; Verbose +; -DCORE_DEBUG_LEVEL=5 + +[common_env_data] +platform_espressif32 = espressif32@1.3.0 +;platform_espressif32 = https://github.com/platformio/platform-espressif32.git#feature/stage +;board_build.partitions = no_ota.csv +board_build.partitions = min_spiffs.csv +lib_deps_all = + ArduinoJson +lib_deps_display = + U8g2@>=2.23.16 +lib_deps_rgbled = + SmartLeds@>=1.1.3 +lib_deps_gps = + TinyGPSPlus@>=1.0.2 + Time@>=1.5 +build_flags = +; override lora settings from LMiC library in lmic/config.h and use main.h instead + -D_lmic_config_h_ + -include "src/paxcounter.conf" + -include "src/hal/${PIOENV}.h" + -w + +[env:ebox] +platform = ${common_env_data.platform_espressif32} +framework = arduino +board = esp32dev +board_build.partitions = ${common_env_data.board_build.partitions} +upload_speed = 115200 +monitor_speed = 115200 +lib_deps = + ${common_env_data.lib_deps_all} +build_flags = + ${common_env_data.build_flags} + +[env:heltec] +platform = ${common_env_data.platform_espressif32} +framework = arduino +board = heltec_wifi_lora_32 +board_build.partitions = ${common_env_data.board_build.partitions} +upload_speed = 115200 +monitor_speed = 115200 +lib_deps = + ${common_env_data.lib_deps_all} + ${common_env_data.lib_deps_display} +build_flags = + ${common_env_data.build_flags} + +[env:ttgov1] +platform = ${common_env_data.platform_espressif32} +framework = arduino +board = esp32dev +board_build.partitions = ${common_env_data.board_build.partitions} +upload_speed = 115200 +monitor_speed = 115200 +lib_deps = + ${common_env_data.lib_deps_all} + ${common_env_data.lib_deps_display} +build_flags = + ${common_env_data.build_flags} + +[env:ttgov2] +platform = ${common_env_data.platform_espressif32} +framework = arduino +board = esp32dev +board_build.partitions = ${common_env_data.board_build.partitions} +upload_speed = 921600 +monitor_speed = 115200 +lib_deps = + ${common_env_data.lib_deps_all} + ${common_env_data.lib_deps_display} +build_flags = + ${common_env_data.build_flags} + +[env:ttgov21] +platform = ${common_env_data.platform_espressif32} +framework = arduino +board = esp32dev +board_build.partitions = ${common_env_data.board_build.partitions} +upload_speed = 921600 +monitor_speed = 115200 +lib_deps = + ${common_env_data.lib_deps_all} + ${common_env_data.lib_deps_display} +build_flags = + ${common.build_flags} + ${common_env_data.build_flags} +;upload_protocol = custom +;extra_scripts = pre:publish_firmware.py + +[env:ttgobeam] +platform = ${common_env_data.platform_espressif32} +framework = arduino +board = esp32dev +board_build.partitions = ${common_env_data.board_build.partitions} +upload_speed = 921600 +monitor_speed = 115200 +lib_deps = + ${common_env_data.lib_deps_all} + ${common_env_data.lib_deps_gps} +build_flags = + ${common_env_data.build_flags} + -mfix-esp32-psram-cache-issue + +[env:fipy] +platform = ${common_env_data.platform_espressif32} +framework = arduino +board = esp32dev +board_build.partitions = ${common_env_data.board_build.partitions} +upload_speed = 921600 +monitor_speed = 115200 +lib_deps = + ${common_env_data.lib_deps_all} + ${common_env_data.lib_deps_rgbled} +build_flags = + ${common_env_data.build_flags} + +[env:lopy] +platform = ${common_env_data.platform_espressif32} +framework = arduino +board = esp32dev +board_build.partitions = ${common_env_data.board_build.partitions} +upload_speed = 921600 +monitor_speed = 115200 +lib_deps = + ${common_env_data.lib_deps_all} + ${common_env_data.lib_deps_rgbled} + ${common_env_data.lib_deps_gps} +build_flags = + ${common_env_data.build_flags} + +[env:lopy4] +platform = ${common_env_data.platform_espressif32} +framework = arduino +board = esp32dev +board_build.partitions = ${common_env_data.board_build.partitions} +upload_speed = 921600 +monitor_speed = 115200 +lib_deps = + ${common_env_data.lib_deps_all} + ${common_env_data.lib_deps_rgbled} + ${common_env_data.lib_deps_gps} +build_flags = + ${common_env_data.build_flags} + -mfix-esp32-psram-cache-issue + +[env:lolin32litelora] +platform = ${common_env_data.platform_espressif32} +framework = arduino +board = lolin32 +board_build.partitions = ${common_env_data.board_build.partitions} +upload_speed = 921600 +monitor_speed = 115200 +lib_deps = + ${common_env_data.lib_deps_all} + ${common_env_data.lib_deps_rgbled} +build_flags = + ${common_env_data.build_flags} + +[env:lolin32lora] +platform = ${common_env_data.platform_espressif32} +framework = arduino +board = lolin32 +board_build.partitions = ${common_env_data.board_build.partitions} +upload_speed = 921600 +monitor_speed = 115200 +lib_deps = + ${common_env_data.lib_deps_all} + ${common_env_data.lib_deps_rgbled} +build_flags = + ${common_env_data.build_flags} + +[env:lolin32lite] +platform = ${common_env_data.platform_espressif32} +framework = arduino +board = lolin32 +board_build.partitions = ${common_env_data.board_build.partitions} +upload_speed = 921600 +monitor_speed = 115200 +lib_deps = + ${common_env_data.lib_deps_all} + ${common_env_data.lib_deps_rgbled} +build_flags = + ${common_env_data.build_flags} + +[env:generic] +platform = ${common_env_data.platform_espressif32} +framework = arduino +board = esp32dev +board_build.partitions = ${common_env_data.board_build.partitions} +upload_speed = 921600 +monitor_speed = 115200 +lib_deps = + ${common_env_data.lib_deps_all} + ${common_env_data.lib_deps_rgbled} + ${common_env_data.lib_deps_gps} + ${common_env_data.lib_deps_display} +build_flags = + ${common_env_data.build_flags} From 2c1dd22555bf52fabc2d600077399149cb63d592 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 15 Sep 2018 16:29:52 +0200 Subject: [PATCH 12/43] ota first test --- platformio.ini | 6 +- src/OTA.cpp | 263 ++++++++++++++++++++++++++++++++++++---------- src/OTA.h | 8 +- src/SecureOTA.cpp | 229 ---------------------------------------- src/SecureOTA.h | 25 ----- 5 files changed, 212 insertions(+), 319 deletions(-) delete mode 100644 src/SecureOTA.cpp delete mode 100644 src/SecureOTA.h diff --git a/platformio.ini b/platformio.ini index 17ab99e0f..121cca95a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -32,11 +32,11 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng user = cyberman54 repository = paxcounter-firmware package = ttgov21_old -api_token = *** +api_token = 2e10f923df5d47b9c7e25752510322a1d65ee997 [wifi] -ssid = *** -password = *** +ssid = testnet +password = test0815 [common] platform = https://github.com/platformio/platform-espressif32.git diff --git a/src/OTA.cpp b/src/OTA.cpp index 1ec3be8ef..888c28cdb 100644 --- a/src/OTA.cpp +++ b/src/OTA.cpp @@ -1,79 +1,226 @@ -#include "OTA.h" +/* + Parts of this code: + Copyright (c) 2014-present PlatformIO + + 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 +#include +#include +#include "ota.h" const BintrayClient bintray(BINTRAY_USER, BINTRAY_REPO, BINTRAY_PACKAGE); -bool Wifi_Connected = false; - -esp_err_t event_handler(void *ctx, system_event_t *event) { - switch (event->event_id) { - 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; - } -} +// Connection port (HTTPS) +const int port = 443; -void ota_wifi_init(void) { +// Connection timeout +const uint32_t RESPONSE_TIMEOUT_MS = 5000; - tcpip_adapter_if_t tcpip_if = TCPIP_ADAPTER_IF_STA; +// Variables to validate firmware content +volatile int contentLength = 0; +volatile bool isValidContentType = false; - // initialize the tcp stack - // nvs_flash_init(); - tcpip_adapter_init(); - tcpip_adapter_set_hostname(tcpip_if, PROGNAME); - tcpip_adapter_dhcpc_start(tcpip_if); +// Local logging tag +static const char TAG[] = "main"; - // initialize the wifi event handler - ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); +void start_ota_update() { + ota_update = false; // clear ota trigger switch + ESP_LOGI(TAG, "Stopping Wifi scanner"); + vTaskDelete(WifiLoopTask); + + ESP_LOGI(TAG, "Starting Wifi OTA update"); // switch off monitor more ESP_ERROR_CHECK( esp_wifi_set_promiscuous(false)); // now switch on monitor mode ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(NULL)); - wifi_sta_config_t cfg; - strcpy((char *)cfg.ssid, WIFI_SSID); - strcpy((char *)cfg.password, WIFI_PASS); - cfg.bssid_set = false; + WiFi.begin(WIFI_SSID, WIFI_PASS); - wifi_config_t sta_cfg; - sta_cfg.sta = cfg; + while (WiFi.status() != WL_CONNECTED) { + 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)); - ESP_ERROR_CHECK( - esp_wifi_set_storage(WIFI_STORAGE_RAM)); // we don't need NVRAM - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); - ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_cfg)); - ESP_ERROR_CHECK(esp_wifi_start()); + checkFirmwareUpdates(); + ESP.restart(); // reached only if update was not successful + +} // start_ota_update + +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() { - ESP_LOGI(TAG, "Stopping Wifi task on core 0"); - vTaskDelete(WifiLoopTask); +// A helper function to extract header value from header +inline String getHeaderValue(String header, String headerName) { + 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); - ota_wifi_init(); - delay(2000); - delay(2000); - checkFirmwareUpdates(); - ESP.restart(); // reached if update was not successful + 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.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(); + } } \ No newline at end of file diff --git a/src/OTA.h b/src/OTA.h index 8b6a27dfc..a20e54df1 100644 --- a/src/OTA.h +++ b/src/OTA.h @@ -2,12 +2,12 @@ #define OTA_H #include -#include "globals.h" -#include #include -#include "ota.h" -#include "SecureOTA.h" +#include "globals.h" +#include "wifiscan.h" +void checkFirmwareUpdates(); +void processOTAUpdate(const String &version); void start_ota_update(); #endif // OTA_H \ No newline at end of file diff --git a/src/SecureOTA.cpp b/src/SecureOTA.cpp deleted file mode 100644 index 8b35c93bd..000000000 --- a/src/SecureOTA.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - Copyright (c) 2014-present PlatformIO - - 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 -#include -#include -#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; - -// Local logging tag -static const char TAG[] = "main"; - -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); -} - -// 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.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(); - } -} \ No newline at end of file diff --git a/src/SecureOTA.h b/src/SecureOTA.h deleted file mode 100644 index d8b17c3f8..000000000 --- a/src/SecureOTA.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - Copyright (c) 2014-present PlatformIO - - 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 - -void checkFirmwareUpdates(); -void processOTAUpdate(const String &version); - -#endif // SECURE_OTA_H \ No newline at end of file From 01fa10e3fd7b9b82d09d994a87f0d0c2e8f5ccaa Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 15 Sep 2018 17:04:04 +0200 Subject: [PATCH 13/43] ota (experimental) --- .gitignore | 3 +-- platformio.ini | 68 +++++++++++++++++++++----------------------------- 2 files changed, 30 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index f1f6d7549..dbccbfe15 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,4 @@ .vscode/.browse.c_cpp.db* .clang_complete .gcc-flags.json -src/loraconf.h -platformio.ini \ No newline at end of file +src/loraconf.h \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 121cca95a..e42dbb317 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,15 +1,9 @@ ; PlatformIO Project Configuration File ; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; ; Please visit documentation for the other options and examples ; http://docs.platformio.org/page/projectconf.html - ; ---> SELECT TARGET PLATFORM HERE! <--- [platformio] ;env_default = generic @@ -17,8 +11,8 @@ ;env_default = heltec ;env_default = ttgov1 ;env_default = ttgov2 -env_default = ttgov21 -;env_default = ttgobeam +;env_default = ttgov21 +env_default = ttgobeam ;env_default = lopy ;env_default = lopy4 ;env_default = fipy @@ -34,42 +28,20 @@ repository = paxcounter-firmware package = ttgov21_old api_token = 2e10f923df5d47b9c7e25752510322a1d65ee997 -[wifi] -ssid = testnet -password = test0815 - [common] -platform = https://github.com/platformio/platform-espressif32.git - -; firmware version, please modify it between releases -; positive integer value -;release_version = 1.4.30 -release_version = 3 +release_version = 5 +[ota] ; build configuration based on Bintray and Wi-Fi settings +wifi_ssid = testnet +wifi_password = test0815 build_flags = - '-DWIFI_SSID="${wifi.ssid}"' - '-DWIFI_PASS="${wifi.password}"' + '-DWIFI_SSID="${ota.wifi_ssid}"' + '-DWIFI_PASS="${ota.wifi_password}"' '-DBINTRAY_USER="${bintray.user}"' '-DBINTRAY_REPO="${bintray.repository}"' '-DBINTRAY_PACKAGE="${bintray.package}"' -DVERSION=${common.release_version} -; -; ---> NOTE: For production run set DEBUG_LEVEL level to NONE! <--- -; otherwise device may leak RAM -; -; None -; -DCORE_DEBUG_LEVEL=0 -; Error -; -DCORE_DEBUG_LEVEL=1 -; Warn -; -DCORE_DEBUG_LEVEL=2 -; Info - -DCORE_DEBUG_LEVEL=3 -; Debug -; -DCORE_DEBUG_LEVEL=4 -; Verbose -; -DCORE_DEBUG_LEVEL=5 [common_env_data] platform_espressif32 = espressif32@1.3.0 @@ -91,6 +63,21 @@ build_flags = -include "src/paxcounter.conf" -include "src/hal/${PIOENV}.h" -w +; ---> NOTE: For production run set DEBUG_LEVEL level to NONE! <--- +; otherwise device may leak RAM +; +; None +; -DCORE_DEBUG_LEVEL=0 +; Error +; -DCORE_DEBUG_LEVEL=1 +; Warn +; -DCORE_DEBUG_LEVEL=2 +; Info + -DCORE_DEBUG_LEVEL=3 +; Debug +; -DCORE_DEBUG_LEVEL=4 +; Verbose +; -DCORE_DEBUG_LEVEL=5 [env:ebox] platform = ${common_env_data.platform_espressif32} @@ -102,6 +89,7 @@ monitor_speed = 115200 lib_deps = ${common_env_data.lib_deps_all} build_flags = + ${ota.build_flags} ${common_env_data.build_flags} [env:heltec] @@ -154,10 +142,7 @@ lib_deps = ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_display} build_flags = - ${common.build_flags} ${common_env_data.build_flags} -;upload_protocol = custom -;extra_scripts = pre:publish_firmware.py [env:ttgobeam] platform = ${common_env_data.platform_espressif32} @@ -170,8 +155,11 @@ lib_deps = ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_gps} build_flags = + ${ota.build_flags} ${common_env_data.build_flags} -mfix-esp32-psram-cache-issue +upload_protocol = custom +extra_scripts = pre:publish_firmware.py [env:fipy] platform = ${common_env_data.platform_espressif32} @@ -212,6 +200,7 @@ lib_deps = ${common_env_data.lib_deps_rgbled} ${common_env_data.lib_deps_gps} build_flags = + ${ota.build_flags} ${common_env_data.build_flags} -mfix-esp32-psram-cache-issue @@ -267,4 +256,5 @@ lib_deps = ${common_env_data.lib_deps_gps} ${common_env_data.lib_deps_display} build_flags = + ${ota.build_flags} ${common_env_data.build_flags} From b12ed126b7879ed377c9042b548dab7401bb49df Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 15 Sep 2018 18:59:20 +0200 Subject: [PATCH 14/43] OTA (experimental) --- README.md | 1 + platformio.ini | 18 +++++++++--------- src/OTA.cpp | 10 +--------- src/OTA.h | 1 - src/configmanager.cpp | 13 +++++++++++++ src/cyclic.cpp | 5 +++-- src/globals.h | 4 ++-- src/lorawan.cpp | 6 ++---- src/main.cpp | 19 +++++++++++++------ src/main.h | 1 + src/rcommand.cpp | 18 +++++++++--------- 11 files changed, 54 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 8c6400aad..0889b2b6b 100644 --- a/README.md +++ b/README.md @@ -278,6 +278,7 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts. 1 = reset MAC counter to zero 2 = reset device to factory settings 3 = flush send queues + 9 = OTA software update via Wifi 0x0A set LoRaWAN payload send cycle diff --git a/platformio.ini b/platformio.ini index e42dbb317..90c8fdb75 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,8 +11,8 @@ ;env_default = heltec ;env_default = ttgov1 ;env_default = ttgov2 -;env_default = ttgov21 -env_default = ttgobeam +env_default = ttgov21 +;env_default = ttgobeam ;env_default = lopy ;env_default = lopy4 ;env_default = fipy @@ -29,7 +29,7 @@ package = ttgov21_old api_token = 2e10f923df5d47b9c7e25752510322a1d65ee997 [common] -release_version = 5 +release_version = 6 [ota] ; build configuration based on Bintray and Wi-Fi settings @@ -62,6 +62,7 @@ build_flags = -D_lmic_config_h_ -include "src/paxcounter.conf" -include "src/hal/${PIOENV}.h" + ${ota.build_flags} -w ; ---> NOTE: For production run set DEBUG_LEVEL level to NONE! <--- ; otherwise device may leak RAM @@ -89,7 +90,6 @@ monitor_speed = 115200 lib_deps = ${common_env_data.lib_deps_all} build_flags = - ${ota.build_flags} ${common_env_data.build_flags} [env:heltec] @@ -143,6 +143,9 @@ lib_deps = ${common_env_data.lib_deps_display} build_flags = ${common_env_data.build_flags} +;upload_protocol = custom +;extra_scripts = pre:publish_firmware.py + [env:ttgobeam] platform = ${common_env_data.platform_espressif32} @@ -155,11 +158,10 @@ lib_deps = ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_gps} build_flags = - ${ota.build_flags} ${common_env_data.build_flags} -mfix-esp32-psram-cache-issue -upload_protocol = custom -extra_scripts = pre:publish_firmware.py +;upload_protocol = custom +;extra_scripts = pre:publish_firmware.py [env:fipy] platform = ${common_env_data.platform_espressif32} @@ -200,7 +202,6 @@ lib_deps = ${common_env_data.lib_deps_rgbled} ${common_env_data.lib_deps_gps} build_flags = - ${ota.build_flags} ${common_env_data.build_flags} -mfix-esp32-psram-cache-issue @@ -256,5 +257,4 @@ lib_deps = ${common_env_data.lib_deps_gps} ${common_env_data.lib_deps_display} build_flags = - ${ota.build_flags} ${common_env_data.build_flags} diff --git a/src/OTA.cpp b/src/OTA.cpp index 888c28cdb..702c8fcbf 100644 --- a/src/OTA.cpp +++ b/src/OTA.cpp @@ -36,16 +36,8 @@ volatile bool isValidContentType = false; static const char TAG[] = "main"; void start_ota_update() { - ota_update = false; // clear ota trigger switch - - ESP_LOGI(TAG, "Stopping Wifi scanner"); - vTaskDelete(WifiLoopTask); ESP_LOGI(TAG, "Starting Wifi OTA update"); - // switch off monitor more - ESP_ERROR_CHECK( - esp_wifi_set_promiscuous(false)); // now switch on monitor mode - ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(NULL)); WiFi.begin(WIFI_SSID, WIFI_PASS); @@ -56,7 +48,7 @@ void start_ota_update() { ESP_LOGI(TAG, "connected to %s", WIFI_SSID); - checkFirmwareUpdates(); + checkFirmwareUpdates(); // gets and flashes new firmware and restarts ESP.restart(); // reached only if update was not successful } // start_ota_update diff --git a/src/OTA.h b/src/OTA.h index a20e54df1..52698c391 100644 --- a/src/OTA.h +++ b/src/OTA.h @@ -4,7 +4,6 @@ #include #include #include "globals.h" -#include "wifiscan.h" void checkFirmwareUpdates(); void processOTAUpdate(const String &version); diff --git a/src/configmanager.cpp b/src/configmanager.cpp index 4ff40a843..8fa6b2f95 100644 --- a/src/configmanager.cpp +++ b/src/configmanager.cpp @@ -31,6 +31,7 @@ void defaultConfig() { cfg.rgblum = RGBLUMINOSITY; // RGB Led luminosity (0..100%) cfg.gpsmode = 1; // 0=disabled, 1=enabled cfg.monitormode = 0; // 0=disabled, 1=enabled + cfg.runmode = 0; // 0=normal, 1=update strncpy(cfg.version, PROGVERSION, sizeof(cfg.version) - 1); } @@ -143,6 +144,10 @@ void saveConfig() { flash8 != cfg.monitormode) nvs_set_i8(my_handle, "monitormode", cfg.monitormode); + if (nvs_get_i8(my_handle, "runmode", &flash8) != ESP_OK || + flash8 != cfg.runmode) + nvs_set_i8(my_handle, "runmode", cfg.runmode); + if (nvs_get_i16(my_handle, "rssilimit", &flash16) != ESP_OK || flash16 != cfg.rssilimit) nvs_set_i16(my_handle, "rssilimit", cfg.rssilimit); @@ -326,6 +331,14 @@ void loadConfig() { saveConfig(); } + if (nvs_get_i8(my_handle, "runmode", &flash8) == ESP_OK) { + cfg.runmode = flash8; + ESP_LOGI(TAG, "Run mode = %d", flash8); + } else { + ESP_LOGI(TAG, "Run mode set to default %d", cfg.runmode); + saveConfig(); + } + nvs_close(my_handle); ESP_LOGI(TAG, "Done"); } diff --git a/src/cyclic.cpp b/src/cyclic.cpp index 45ce16cda..ba7968bf4 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -15,8 +15,9 @@ void doHomework() { // update uptime counter uptime(); - if (ota_update) - start_ota_update(); + // check if update mode trigger switch was set + if (cfg.runmode == 1) + ESP.restart(); // read battery voltage into global variable #ifdef HAS_BATTERY_PROBE diff --git a/src/globals.h b/src/globals.h index 53aad8203..20acd5cb9 100644 --- a/src/globals.h +++ b/src/globals.h @@ -5,7 +5,7 @@ #include // attn: increment version after modifications to configData_t truct! -#define PROGVERSION "1.4.23" // use max 10 chars here! +#define PROGVERSION "1.4.30" // use max 10 chars here! #define PROGNAME "PAXCNT" // std::set for unified array functions @@ -31,6 +31,7 @@ typedef struct { uint8_t rgblum; // RGB Led luminosity (0..100%) uint8_t gpsmode; // 0=disabled, 1=enabled uint8_t monitormode; // 0=disabled, 1=enabled + uint8_t runmode; // 0=normal, 1=update char version[10]; // Firmware version } configData_t; @@ -43,7 +44,6 @@ typedef struct { // global variables extern configData_t cfg; // current device configuration -extern bool ota_update; extern char display_line6[], display_line7[]; // screen buffers extern uint8_t channel; // wifi channel rotation counter extern uint16_t macs_total, macs_wifi, macs_ble, batt_voltage; // display values diff --git a/src/lorawan.cpp b/src/lorawan.cpp index ea0709ff4..e3850847b 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -196,11 +196,9 @@ void onEvent(ev_t ev) { if (LMIC.dataLen) { ESP_LOGI(TAG, "Received %d bytes of payload, RSSI %d SNR %d", - LMIC.dataLen, LMIC.rssi, (signed char)LMIC.snr / 4); - // LMIC.snr = SNR twos compliment [dB] * 4 - // LMIC.rssi = RSSI [dBm] (-196...+63) + LMIC.dataLen, LMIC.rssi, (signed char)LMIC.snr); sprintf(display_line6, "RSSI %d SNR %d", LMIC.rssi, - (signed char)LMIC.snr / 4); + (signed char)LMIC.snr); // check if command is received on command port, then call interpreter if ((LMIC.txrxFlags & TXRX_PORT) && diff --git a/src/main.cpp b/src/main.cpp index d52b4a7ac..a49253f3b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,8 +27,7 @@ licenses. Refer to LICENSE.txt file in repository for more details. #include "globals.h" #include "main.h" -configData_t cfg; // struct holds current device configuration -bool ota_update = false; // triggers OTA update +configData_t cfg; // struct holds current device configuration char display_line6[16], display_line7[16]; // display buffers uint8_t channel = 0; // channel rotation counter uint16_t macs_total = 0, macs_wifi = 0, macs_ble = 0, @@ -97,7 +96,7 @@ void setup() { // initialize system event handler for wifi task, needed for // wifi_sniffer_init() // esp_event_loop_init(NULL, NULL); - //ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); + // ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); // print chip information on startup if in verbose mode #ifdef VERBOSE @@ -123,6 +122,13 @@ void setup() { // read settings from NVRAM loadConfig(); // includes initialize if necessary + // reboot to firmware update mode if ota trigger switch is set + if (cfg.runmode == 1) { + cfg.runmode = 0; + saveConfig(); + start_ota_update(); + } + #ifdef VENDORFILTER strcat_P(features, " OUIFLT"); #endif @@ -302,8 +308,8 @@ void setup() { ESP_LOGI(TAG, "Starting Wifi task on core 0"); wifi_sniffer_init(); // initialize salt value using esp_random() called by random() in - // arduino-esp32 core. Note: do this *after* wifi has started, since function - // gets it's seed from RF noise + // arduino-esp32 core. Note: do this *after* wifi has started, since + // function gets it's seed from RF noise reset_salt(); // get new 16bit for salting hashes xTaskCreatePinnedToCore(wifi_channel_loop, "wifiloop", 2048, (void *)1, 1, &WifiLoopTask, 0); @@ -318,7 +324,8 @@ void setup() { void loop() { while (1) { - // state machine for switching display, LED, button, housekeeping, senddata + // state machine for switching display, LED, button, housekeeping, + // senddata #if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED) led_loop(); diff --git a/src/main.h b/src/main.h index 89dc0be41..58919160a 100644 --- a/src/main.h +++ b/src/main.h @@ -8,6 +8,7 @@ #include "senddata.h" #include "cyclic.h" #include "beacon_array.h" +#include "ota.h" #include // needed for reading ESP32 chip attributes #include // needed for Wifi event handler diff --git a/src/rcommand.cpp b/src/rcommand.cpp index 2bae172ab..7f984cdbc 100644 --- a/src/rcommand.cpp +++ b/src/rcommand.cpp @@ -31,6 +31,11 @@ void set_reset(uint8_t val[]) { sprintf(display_line6, "Queue reset"); flushQueues(); break; + case 9: // reset and ask for software update via Wifi OTA + ESP_LOGI(TAG, "Remote command: software update via Wifi"); + sprintf(display_line6, "Software update"); + cfg.runmode = 1; + break; default: ESP_LOGW(TAG, "Remote command: reset called with invalid parameter(s)"); } @@ -220,27 +225,22 @@ void get_gps(uint8_t val[]) { #endif }; -void set_update(uint8_t val[]) { - ESP_LOGI(TAG, "Remote command: get firmware update"); - ota_update = true; -}; - // assign previously defined functions to set of numeric remote commands // format: opcode, function, #bytes params, -// flag (1 = do make settings persistent / 0 = don't) +// flag (true = do make settings persistent / false = don't) // cmd_t table[] = { {0x01, set_rssi, 1, true}, {0x02, set_countmode, 1, true}, {0x03, set_gps, 1, true}, {0x04, set_display, 1, true}, {0x05, set_lorasf, 1, true}, {0x06, set_lorapower, 1, true}, {0x07, set_loraadr, 1, true}, {0x08, set_screensaver, 1, true}, - {0x09, set_reset, 1, false}, {0x0a, set_sendcycle, 1, true}, + {0x09, set_reset, 1, true}, {0x0a, set_sendcycle, 1, true}, {0x0b, set_wifichancycle, 1, true}, {0x0c, set_blescantime, 1, true}, {0x0d, set_vendorfilter, 1, false}, {0x0e, set_blescan, 1, true}, {0x0f, set_wifiant, 1, true}, {0x10, set_rgblum, 1, true}, {0x11, set_monitor, 1, true}, {0x12, set_beacon, 7, false}, - {0x20, set_update, 0, false}, {0x80, get_config, 0, false}, - {0x81, get_status, 0, false}, {0x84, get_gps, 0, false}}; + {0x80, get_config, 0, false}, {0x81, get_status, 0, false}, + {0x84, get_gps, 0, false}}; const uint8_t cmdtablesize = sizeof(table) / sizeof(table[0]); // number of commands in command table From 0667ee57443e3026c383e71d0a21005d39d2273a Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 15 Sep 2018 21:10:11 +0200 Subject: [PATCH 15/43] OTA (experimental) --- src/OTA.cpp | 32 ++++++++++++++++---------------- src/main.cpp | 1 - src/main.h | 3 ++- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/OTA.cpp b/src/OTA.cpp index 702c8fcbf..7904eea31 100644 --- a/src/OTA.cpp +++ b/src/OTA.cpp @@ -49,24 +49,25 @@ void start_ota_update() { ESP_LOGI(TAG, "connected to %s", WIFI_SSID); checkFirmwareUpdates(); // gets and flashes new firmware and restarts - ESP.restart(); // reached only if update was not successful + ESP.restart(); // reached only if update was not successful } // start_ota_update void checkFirmwareUpdates() { // Fetch the latest firmware version - ESP_LOGI(TAG, "Checking latest firmware version..."); + ESP_LOGI(TAG, "OTA mode, checking latest firmware version on server..."); 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 ..."); + ESP_LOGI( + TAG, + "Could not load info about the latest firmware. Rebooting to runmode."); return; } else if (atoi(latest.c_str()) <= VERSION) { - ESP_LOGI(TAG, "The current firmware is up to date. Continue ..."); + ESP_LOGI(TAG, "Current firmware is up to date. Rebooting to runmode."); return; } - ESP_LOGI(TAG, "There is a new version of firmware available: v.%s", + ESP_LOGI(TAG, "New firmware version v%s available. Downloading...", latest.c_str()); processOTAUpdate(latest); } @@ -82,7 +83,7 @@ inline String getHeaderValue(String header, String headerName) { 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!"); + ESP_LOGI(TAG, "Unsupported binary format, OTA update cancelled."); return; } @@ -103,8 +104,7 @@ void processOTAUpdate(const String &version) { 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!", + ESP_LOGI(TAG, "Redirect detected, but cannot connect to %s", currentHost.c_str()); return; } @@ -120,7 +120,7 @@ void processOTAUpdate(const String &version) { unsigned long timeout = millis(); while (client.available() == 0) { if (millis() - timeout > RESPONSE_TIMEOUT_MS) { - ESP_LOGI(TAG, "Client Timeout !"); + ESP_LOGI(TAG, "Client Timeout."); client.stop(); return; } @@ -146,7 +146,7 @@ void processOTAUpdate(const String &version) { "new address"); redirect = true; } else { - ESP_LOGI(TAG, "Could not get a valid firmware url"); + ESP_LOGI(TAG, "Could not get a valid firmware url."); // Unexptected HTTP response. Retry or skip update? redirect = false; } @@ -184,20 +184,20 @@ void processOTAUpdate(const String &version) { // 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 ..."); + ESP_LOGI(TAG, "Starting OTA update. This will take some time to " + "complete..."); size_t written = Update.writeStream(client); if (written == contentLength) { - ESP_LOGI(TAG, "Written %d successfully", written); + ESP_LOGI(TAG, "Written %d bytes successfully", written); } else { - ESP_LOGI(TAG, "Written only %d / %d Retry?", written, contentLength); + ESP_LOGI(TAG, "Written only %d of %d bytes, OTA update cancelled.", written, contentLength); // Retry?? } if (Update.end()) { if (Update.isFinished()) { - ESP_LOGI(TAG, "OTA update has successfully completed. Rebooting ..."); + ESP_LOGI(TAG, "OTA update completed. Rebooting to runmode."); ESP.restart(); } else { ESP_LOGI(TAG, "Something went wrong! OTA update hasn't been finished " diff --git a/src/main.cpp b/src/main.cpp index a49253f3b..e659ea564 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,7 +24,6 @@ licenses. Refer to LICENSE.txt file in repository for more details. */ // Basic Config -#include "globals.h" #include "main.h" configData_t cfg; // struct holds current device configuration diff --git a/src/main.h b/src/main.h index 58919160a..cb0cb8e25 100644 --- a/src/main.h +++ b/src/main.h @@ -1,7 +1,8 @@ #ifndef _MAIN_H #define _MAIN_H -//#include "led.h" +#include "globals.h" +#include "led.h" #include "macsniff.h" #include "wifiscan.h" #include "configmanager.h" From fb7c32e5c88f7d09f1179e72670fba4f3f956fc2 Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Sun, 16 Sep 2018 12:18:11 +0200 Subject: [PATCH 16/43] OTA (experimental) --- lib/BintrayClient/src/BintrayClient.cpp | 8 ++++---- platformio.ini | 8 +++++--- src/OTA.cpp | 25 ++++++++++++++----------- src/OTA.h | 5 +++-- src/cyclic.cpp | 2 +- src/main.h | 2 +- src/paxcounter.conf | 3 +++ 7 files changed, 31 insertions(+), 22 deletions(-) diff --git a/lib/BintrayClient/src/BintrayClient.cpp b/lib/BintrayClient/src/BintrayClient.cpp index 4479f5391..b0e7543f5 100644 --- a/lib/BintrayClient/src/BintrayClient.cpp +++ b/lib/BintrayClient/src/BintrayClient.cpp @@ -109,7 +109,7 @@ String BintrayClient::getLatestVersion() const const size_t bufferSize = 1024; if (jsonResult.length() > bufferSize) { - ESP_LOGI(TAG, "Error: Could not parse JSON. Input data is too big!"); + Serial.println("Error: Could parse JSON. Input data is too big!"); return version; } StaticJsonBuffer jsonBuffer; @@ -118,7 +118,7 @@ String BintrayClient::getLatestVersion() const // Check for errors in parsing if (!root.success()) { - ESP_LOGI(TAG, "Error: Could not parse JSON!"); + Serial.println("Error: Could not parse JSON!"); return version; } return root.get("name"); @@ -133,7 +133,7 @@ String BintrayClient::getBinaryPath(const String &version) const const size_t bufferSize = 1024; if (jsonResult.length() > bufferSize) { - ESP_LOGI(TAG, "Error: Could parse JSON. Input data is too big!"); + Serial.println("Error: Could parse JSON. Input data is too big!"); return path; } StaticJsonBuffer jsonBuffer; @@ -142,7 +142,7 @@ String BintrayClient::getBinaryPath(const String &version) const JsonObject &firstItem = root[0]; if (!root.success()) { //Check for errors in parsing - ESP_LOGI(TAG, "Error: Could not parse JSON!"); + Serial.println("Error: Could not parse JSON!"); return path; } return "/" + getUser() + "/" + getRepository() + "/" + firstItem.get("path"); diff --git a/platformio.ini b/platformio.ini index 90c8fdb75..0bd773fe6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -29,7 +29,7 @@ package = ttgov21_old api_token = 2e10f923df5d47b9c7e25752510322a1d65ee997 [common] -release_version = 6 +release_version = 7 [ota] ; build configuration based on Bintray and Wi-Fi settings @@ -42,14 +42,16 @@ build_flags = '-DBINTRAY_REPO="${bintray.repository}"' '-DBINTRAY_PACKAGE="${bintray.package}"' -DVERSION=${common.release_version} +lib_deps_ota = + https://github.com/platformio/bintray-secure-ota.git [common_env_data] platform_espressif32 = espressif32@1.3.0 ;platform_espressif32 = https://github.com/platformio/platform-espressif32.git#feature/stage -;board_build.partitions = no_ota.csv board_build.partitions = min_spiffs.csv lib_deps_all = - ArduinoJson + ArduinoJson@^5.13.1 +; ArduinoJson${ota.lib_deps_ota} lib_deps_display = U8g2@>=2.23.16 lib_deps_rgbled = diff --git a/src/OTA.cpp b/src/OTA.cpp index 7904eea31..28a58f961 100644 --- a/src/OTA.cpp +++ b/src/OTA.cpp @@ -15,10 +15,7 @@ limitations under the License. */ -#include -#include -#include -#include "ota.h" +#include "OTA.h" const BintrayClient bintray(BINTRAY_USER, BINTRAY_REPO, BINTRAY_PACKAGE); @@ -41,15 +38,20 @@ void start_ota_update() { WiFi.begin(WIFI_SSID, WIFI_PASS); - while (WiFi.status() != WL_CONNECTED) { - delay(2000); + int i = WIFI_MAX_TRY; + while (i--) { ESP_LOGI(TAG, "trying to connect to %s", WIFI_SSID); + if (WiFi.status() == WL_CONNECTED) + break; + delay(5000); } + if (i >= 0) { + ESP_LOGI(TAG, "connected to %s", WIFI_SSID); + checkFirmwareUpdates(); // gets and flashes new firmware and restarts + } else + ESP_LOGI(TAG, "could not connect to %s, rebooting.", WIFI_SSID); - ESP_LOGI(TAG, "connected to %s", WIFI_SSID); - - checkFirmwareUpdates(); // gets and flashes new firmware and restarts - ESP.restart(); // reached only if update was not successful + ESP.restart(); // reached only if update was not successful or no wifi connect } // start_ota_update @@ -191,7 +193,8 @@ void processOTAUpdate(const String &version) { if (written == contentLength) { ESP_LOGI(TAG, "Written %d bytes successfully", written); } else { - ESP_LOGI(TAG, "Written only %d of %d bytes, OTA update cancelled.", written, contentLength); + ESP_LOGI(TAG, "Written only %d of %d bytes, OTA update cancelled.", + written, contentLength); // Retry?? } diff --git a/src/OTA.h b/src/OTA.h index 52698c391..fc66973c9 100644 --- a/src/OTA.h +++ b/src/OTA.h @@ -1,9 +1,10 @@ #ifndef OTA_H #define OTA_H -#include #include -#include "globals.h" +#include +#include +#include void checkFirmwareUpdates(); void processOTAUpdate(const String &version); diff --git a/src/cyclic.cpp b/src/cyclic.cpp index ba7968bf4..72b2284cb 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -4,7 +4,7 @@ // Basic config #include "globals.h" #include "senddata.h" -#include "ota.h" +#include "OTA.h" // Local logging tag static const char TAG[] = "main"; diff --git a/src/main.h b/src/main.h index cb0cb8e25..4b77439aa 100644 --- a/src/main.h +++ b/src/main.h @@ -9,7 +9,7 @@ #include "senddata.h" #include "cyclic.h" #include "beacon_array.h" -#include "ota.h" +#include "OTA.h" #include // needed for reading ESP32 chip attributes #include // needed for Wifi event handler diff --git a/src/paxcounter.conf b/src/paxcounter.conf index bcecc56d7..68681b9b9 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -63,6 +63,9 @@ #define DISPLAYREFRESH_MS 40 // OLED refresh cycle in ms [default = 40] -> 1000/40 = 25 frames per second #define HOMECYCLE 30 // house keeping cycle in seconds [default = 30 secs] +// OTA settings +#define WIFI_MAX_TRY 20 // maximum number of wifi connect attempts for OTA update [default = 20] + // LMIC settings // define hardware independent LMIC settings here, settings of standard library in /lmic/config.h will be ignored // define hardware specifics settings in platformio.ini as build_flag for hardware environment From 55e7d4b4e61c19871e9176431f88056ab41e89d6 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 16 Sep 2018 15:30:58 +0200 Subject: [PATCH 17/43] lmic radio.c snr/rssi fix --- lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/radio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/radio.c b/lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/radio.c index 0fffaa4f3..6c570545c 100644 --- a/lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/radio.c +++ b/lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/radio.c @@ -791,7 +791,7 @@ void radio_irq_handler (u1_t dio) { readBuf(RegFifo, LMIC.frame, LMIC.dataLen); // read rx quality parameters //LMIC.snr = readReg(LORARegPktSnrValue); // SNR [dB] * 4 - LMIC.snr = readReg(LORARegPktSnrValue) / 4; + LMIC.snr = ((s1_t)readReg(LORARegPktSnrValue)) / 4; //LMIC.rssi = readReg(LORARegPktRssiValue) - 125 + 64; // RSSI [dBm] (-196...+63) LMIC.rssi = readReg(LORARegPktRssiValue) - 157; // RFI_HF for 868 and 915MHZ band if (LMIC.snr < 0) From 6476dedc5bc2b5d6d6ac8ac9b0c65c89864d0c8b Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 16 Sep 2018 16:52:26 +0200 Subject: [PATCH 18/43] OTA: changed CA certficate for api.bintray.com --- lib/BintrayClient/src/BintrayCertificates.h | 40 +++++++++++---------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/lib/BintrayClient/src/BintrayCertificates.h b/lib/BintrayClient/src/BintrayCertificates.h index ec5fdaa3c..d85bb4e40 100644 --- a/lib/BintrayClient/src/BintrayCertificates.h +++ b/lib/BintrayClient/src/BintrayCertificates.h @@ -18,25 +18,27 @@ #define BINTRAY_CERTIFICATES_H const char* BINTRAY_API_ROOT_CA = \ -"-----BEGIN CERTIFICATE-----\n" \ -"MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\n" \ -"MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i\n" \ -"YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG\n" \ -"EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg\n" \ -"R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9\n" \ -"9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq\n" \ -"fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv\n" \ -"iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU\n" \ -"1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+\n" \ -"bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW\n" \ -"MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA\n" \ -"ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l\n" \ -"uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn\n" \ -"Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS\n" \ -"tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF\n" \ -"PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un\n" \ -"hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV\n" \ -"5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==\n" \ +"-----BEGIN CERTIFICATE-----\n" +"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" +"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" +"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" +"QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n" +"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" +"b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n" +"9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n" +"CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n" +"nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n" +"43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n" +"T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n" +"gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n" +"BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n" +"TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n" +"DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n" +"hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n" +"06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n" +"PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n" +"YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n" +"CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n" "-----END CERTIFICATE-----\n"; const char* BINTRAY_AKAMAI_ROOT_CA = \ From 49288182e973f27583e60dcbe931d1139665cdb2 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 16 Sep 2018 17:08:37 +0200 Subject: [PATCH 19/43] update readme.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0889b2b6b..9dbb980f5 100644 --- a/README.md +++ b/README.md @@ -229,7 +229,7 @@ function Converter(decoded, port) { The device listenes for remote control commands on LoRaWAN Port 2. Multiple commands per downlink are possible by concatenating them. -Note: all settings are stored in NVRAM and will be reloaded when device starts. To reset device to factory settings send remote command 09 02 09 00 unconfirmed(!) once. +Note: all settings are stored in NVRAM and will be reloaded when device starts. 0x01 set scan RSSI limit @@ -272,13 +272,13 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts. useful to clear pending commands from LoRaWAN server quere, or to check RSSI on device -0x09 reset functions +0x09 reset functions (send this command with confirmed ack only to avoid boot loops!) 0 = restart device 1 = reset MAC counter to zero 2 = reset device to factory settings 3 = flush send queues - 9 = OTA software update via Wifi + 9 = reboot device to OTA update via Wifi mode 0x0A set LoRaWAN payload send cycle From 21621e54d5d9990bcdc6c741818f97534759282e Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 16 Sep 2018 17:39:18 +0200 Subject: [PATCH 20/43] code sanitization (vTaskDelay) --- src/OTA.cpp | 2 +- src/display.cpp | 6 +++--- src/gps.cpp | 6 +++--- src/lorawan.cpp | 2 +- src/main.cpp | 2 +- src/wifiscan.cpp | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/OTA.cpp b/src/OTA.cpp index 28a58f961..876099491 100644 --- a/src/OTA.cpp +++ b/src/OTA.cpp @@ -43,7 +43,7 @@ void start_ota_update() { ESP_LOGI(TAG, "trying to connect to %s", WIFI_SSID); if (WiFi.status() == WL_CONNECTED) break; - delay(5000); + vTaskDelay(5000 / portTICK_PERIOD_MS); } if (i >= 0) { ESP_LOGI(TAG, "connected to %s", WIFI_SSID); diff --git a/src/display.cpp b/src/display.cpp index b2fecf099..bfc55f05b 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -36,14 +36,14 @@ void init_display(const char *Productname, const char *Version) { u8x8.draw2x2String(0, 0, Productname); u8x8.setInverseFont(0); u8x8.draw2x2String(2, 2, Productname); - delay(1500); + vTaskDelay(1500 / portTICK_PERIOD_MS); u8x8.clear(); u8x8.setFlipMode(1); u8x8.setInverseFont(1); u8x8.draw2x2String(0, 0, Productname); u8x8.setInverseFont(0); u8x8.draw2x2String(2, 2, Productname); - delay(1500); + vTaskDelay(1500 / portTICK_PERIOD_MS); u8x8.setFlipMode(0); u8x8.clear(); @@ -74,7 +74,7 @@ void init_display(const char *Productname, const char *Version) { DisplayKey(buf, 8, true); #endif // HAS_LORA - delay(5000); + vTaskDelay(3000 / portTICK_PERIOD_MS); u8x8.clear(); u8x8.setPowerSave(!cfg.screenon); // set display off if disabled u8x8.draw2x2String(0, 0, "PAX:0"); diff --git a/src/gps.cpp b/src/gps.cpp index ff0e0bae0..10d05c143 100644 --- a/src/gps.cpp +++ b/src/gps.cpp @@ -42,7 +42,7 @@ void gps_loop(void *pvParameters) { while (GPS_Serial.available()) { gps.encode(GPS_Serial.read()); } - vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog + vTaskDelay(2 / portTICK_PERIOD_MS); // reset watchdog } // after GPS function was disabled, close connect to GPS device GPS_Serial.end(); @@ -58,7 +58,7 @@ void gps_loop(void *pvParameters) { Wire.requestFrom(GPS_ADDR | 0x01, 32); while (Wire.available()) { gps.encode(Wire.read()); - vTaskDelay(1 / portTICK_PERIOD_MS); // polling mode: 500ms sleep + vTaskDelay(2 / portTICK_PERIOD_MS); // polling mode: 500ms sleep } } // after GPS function was disabled, close connect to GPS device @@ -67,7 +67,7 @@ void gps_loop(void *pvParameters) { #endif // GPS Type } - vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog + vTaskDelay(2 / portTICK_PERIOD_MS); // reset watchdog } // end of infinite loop diff --git a/src/lorawan.cpp b/src/lorawan.cpp index e3850847b..0ee8b6c08 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -227,7 +227,7 @@ void lorawan_loop(void *pvParameters) { while (1) { os_runloop_once(); // execute LMIC jobs - vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog + vTaskDelay(2 / portTICK_PERIOD_MS); // reset watchdog } } diff --git a/src/main.cpp b/src/main.cpp index e659ea564..6de8432cb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -345,7 +345,7 @@ void loop() { // check send cycle and enqueue payload if cycle is expired sendPayload(); // reset watchdog - vTaskDelay(1 / portTICK_PERIOD_MS); + vTaskDelay(2 / portTICK_PERIOD_MS); } // loop() } diff --git a/src/wifiscan.cpp b/src/wifiscan.cpp index 24d6504fd..ed3a84eee 100644 --- a/src/wifiscan.cpp +++ b/src/wifiscan.cpp @@ -59,7 +59,7 @@ void wifi_channel_loop(void *pvParameters) { esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE); ESP_LOGD(TAG, "Wifi set channel %d", channel); - vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog + vTaskDelay(2 / portTICK_PERIOD_MS); // reset watchdog } } // end of infinite wifi channel rotation loop From bd724557c1cdc22c4bd81479e9c9ec1ef43dea88 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 17 Sep 2018 17:23:02 +0200 Subject: [PATCH 21/43] v1.4.32 --- README.md | 1 + lib/BintrayClient/src/BintrayCertificates.h | 1 + lib/BintrayClient/src/BintrayClient.cpp | 11 +- lib/BintrayClient/src/BintrayClient.h | 1 + platformio.ini | 259 +++++++++++--------- publish_firmware.py | 16 +- src/OTA.cpp | 39 ++- src/OTA.h | 2 + src/globals.h | 4 - src/hal/ttgov21.h | 69 ------ src/hal/ttgov21new.h | 30 +++ src/hal/ttgov21old.h | 32 +++ src/main.cpp | 4 +- src/paxcounter.conf | 2 + src/payload.cpp | 10 +- src/payload.h | 1 + 16 files changed, 274 insertions(+), 208 deletions(-) delete mode 100644 src/hal/ttgov21.h create mode 100644 src/hal/ttgov21new.h create mode 100644 src/hal/ttgov21old.h diff --git a/README.md b/README.md index 9dbb980f5..870f3656b 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,7 @@ Hereafter described is the default *plain* format, which uses MSB bit numbering. byte 3-10: Uptime [seconds] byte 11: CPU temperature [°C] bytes 12-15: Free RAM [bytes] + bytes 16-17: Last CPU reset reason [core 0, core 1] **Port #3:** Device configuration query result diff --git a/lib/BintrayClient/src/BintrayCertificates.h b/lib/BintrayClient/src/BintrayCertificates.h index d85bb4e40..89854c84a 100644 --- a/lib/BintrayClient/src/BintrayCertificates.h +++ b/lib/BintrayClient/src/BintrayCertificates.h @@ -1,4 +1,5 @@ /* + Parts of this file Copyright (c) 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/BintrayClient/src/BintrayClient.cpp b/lib/BintrayClient/src/BintrayClient.cpp index b0e7543f5..955bca208 100644 --- a/lib/BintrayClient/src/BintrayClient.cpp +++ b/lib/BintrayClient/src/BintrayClient.cpp @@ -1,4 +1,5 @@ /* + Parts of this file Copyright (c) 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); @@ -94,7 +95,7 @@ String BintrayClient::requestHTTPContent(const String &url) const } else { - Serial.printf("GET request failed, error: %s\n", http.errorToString(httpCode).c_str()); + ESP_LOGE(TAG, "GET request failed, error: %s", http.errorToString(httpCode).c_str()); } http.end(); @@ -109,7 +110,7 @@ String BintrayClient::getLatestVersion() const const size_t bufferSize = 1024; if (jsonResult.length() > bufferSize) { - Serial.println("Error: Could parse JSON. Input data is too big!"); + ESP_LOGE(TAG, "Error: Firmware version data invalid."); return version; } StaticJsonBuffer jsonBuffer; @@ -118,7 +119,7 @@ String BintrayClient::getLatestVersion() const // Check for errors in parsing if (!root.success()) { - Serial.println("Error: Could not parse JSON!"); + ESP_LOGE(TAG, "Error: Firmware version data not found."); return version; } return root.get("name"); @@ -133,7 +134,7 @@ String BintrayClient::getBinaryPath(const String &version) const const size_t bufferSize = 1024; if (jsonResult.length() > bufferSize) { - Serial.println("Error: Could parse JSON. Input data is too big!"); + ESP_LOGE(TAG, "Error: Firmware download path data invalid."); return path; } StaticJsonBuffer jsonBuffer; @@ -142,7 +143,7 @@ String BintrayClient::getBinaryPath(const String &version) const JsonObject &firstItem = root[0]; if (!root.success()) { //Check for errors in parsing - Serial.println("Error: Could not parse JSON!"); + ESP_LOGE(TAG, "Error: Firmware download path not found."); return path; } return "/" + getUser() + "/" + getRepository() + "/" + firstItem.get("path"); diff --git a/lib/BintrayClient/src/BintrayClient.h b/lib/BintrayClient/src/BintrayClient.h index 9761c7c63..d0b7e67d4 100644 --- a/lib/BintrayClient/src/BintrayClient.h +++ b/lib/BintrayClient/src/BintrayClient.h @@ -1,4 +1,5 @@ /* + Parts of this file Copyright (c) 2014-present PlatformIO Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/platformio.ini b/platformio.ini index 0bd773fe6..97148ac3f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,8 +11,9 @@ ;env_default = heltec ;env_default = ttgov1 ;env_default = ttgov2 -env_default = ttgov21 -;env_default = ttgobeam +;env_default = ttgov21old +;env_default = ttgov21new +env_default = ttgobeam ;env_default = lopy ;env_default = lopy4 ;env_default = fipy @@ -25,14 +26,11 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng [bintray] user = cyberman54 repository = paxcounter-firmware -package = ttgov21_old api_token = 2e10f923df5d47b9c7e25752510322a1d65ee997 -[common] -release_version = 7 - [ota] -; build configuration based on Bintray and Wi-Fi settings +;release_version = max. 9 chars total, using decimal format "a.b.c" +release_version = 1.4.32 wifi_ssid = testnet wifi_password = test0815 build_flags = @@ -40,18 +38,24 @@ build_flags = '-DWIFI_PASS="${ota.wifi_password}"' '-DBINTRAY_USER="${bintray.user}"' '-DBINTRAY_REPO="${bintray.repository}"' - '-DBINTRAY_PACKAGE="${bintray.package}"' - -DVERSION=${common.release_version} -lib_deps_ota = - https://github.com/platformio/bintray-secure-ota.git + '-DBINTRAY_PACKAGE="${PIOENV}"' + '-DPROGVERSION="${ota.release_version}"' -[common_env_data] +[common] +; DEBUG LEVEL +; For production run setto 0, otherwise device will leak RAM while running! +; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose +debug_level = 0 +; UPLOAD MODE +; select esptool for USB/UART flashing, custom for OTA upload +upload_protocol = esptool +;upload_protocol = custom +extra_scripts = pre:publish_firmware.py platform_espressif32 = espressif32@1.3.0 -;platform_espressif32 = https://github.com/platformio/platform-espressif32.git#feature/stage board_build.partitions = min_spiffs.csv +monitor_speed = 115200 lib_deps_all = ArduinoJson@^5.13.1 -; ArduinoJson${ota.lib_deps_ota} lib_deps_display = U8g2@>=2.23.16 lib_deps_rgbled = @@ -59,204 +63,227 @@ lib_deps_rgbled = lib_deps_gps = TinyGPSPlus@>=1.0.2 Time@>=1.5 -build_flags = +build_flags = ; override lora settings from LMiC library in lmic/config.h and use main.h instead -D_lmic_config_h_ -include "src/paxcounter.conf" -include "src/hal/${PIOENV}.h" ${ota.build_flags} -w -; ---> NOTE: For production run set DEBUG_LEVEL level to NONE! <--- -; otherwise device may leak RAM -; -; None -; -DCORE_DEBUG_LEVEL=0 -; Error -; -DCORE_DEBUG_LEVEL=1 -; Warn -; -DCORE_DEBUG_LEVEL=2 -; Info - -DCORE_DEBUG_LEVEL=3 -; Debug -; -DCORE_DEBUG_LEVEL=4 -; Verbose -; -DCORE_DEBUG_LEVEL=5 + -DCORE_DEBUG_LEVEL=${common.debug_level} + [env:ebox] -platform = ${common_env_data.platform_espressif32} +platform = ${common.platform_espressif32} framework = arduino board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} +board_build.partitions = ${common.board_build.partitions} upload_speed = 115200 -monitor_speed = 115200 lib_deps = - ${common_env_data.lib_deps_all} + ${common.lib_deps_all} build_flags = - ${common_env_data.build_flags} + ${common.build_flags} +upload_protocol = ${common.upload_protocol} +extra_scripts = ${common.extra_scripts} +monitor_speed = ${common.monitor_speed} [env:heltec] -platform = ${common_env_data.platform_espressif32} +platform = ${common.platform_espressif32} framework = arduino board = heltec_wifi_lora_32 -board_build.partitions = ${common_env_data.board_build.partitions} +board_build.partitions = ${common.board_build.partitions} upload_speed = 115200 -monitor_speed = 115200 lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_display} + ${common.lib_deps_all} + ${common.lib_deps_display} build_flags = - ${common_env_data.build_flags} + ${common.build_flags} +upload_protocol = ${common.upload_protocol} +extra_scripts = ${common.extra_scripts} +monitor_speed = ${common.monitor_speed} [env:ttgov1] -platform = ${common_env_data.platform_espressif32} +platform = ${common.platform_espressif32} framework = arduino board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} +board_build.partitions = ${common.board_build.partitions} upload_speed = 115200 -monitor_speed = 115200 lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_display} + ${common.lib_deps_all} + ${common.lib_deps_display} build_flags = - ${common_env_data.build_flags} + ${common.build_flags} +upload_protocol = ${common.upload_protocol} +extra_scripts = ${common.extra_scripts} +monitor_speed = ${common.monitor_speed} [env:ttgov2] -platform = ${common_env_data.platform_espressif32} +platform = ${common.platform_espressif32} framework = arduino board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} +board_build.partitions = ${common.board_build.partitions} upload_speed = 921600 -monitor_speed = 115200 lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_display} + ${common.lib_deps_all} + ${common.lib_deps_display} build_flags = - ${common_env_data.build_flags} + ${common.build_flags} +upload_protocol = ${common.upload_protocol} +extra_scripts = ${common.extra_scripts} +monitor_speed = ${common.monitor_speed} -[env:ttgov21] -platform = ${common_env_data.platform_espressif32} +[env:ttgov21old] +platform = ${common.platform_espressif32} framework = arduino board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} +board_build.partitions = ${common.board_build.partitions} upload_speed = 921600 -monitor_speed = 115200 lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_display} + ${common.lib_deps_all} + ${common.lib_deps_display} build_flags = - ${common_env_data.build_flags} -;upload_protocol = custom -;extra_scripts = pre:publish_firmware.py + ${common.build_flags} +upload_protocol = ${common.upload_protocol} +extra_scripts = ${common.extra_scripts} +monitor_speed = ${common.monitor_speed} +[env:ttgov21new] +platform = ${common.platform_espressif32} +framework = arduino +board = esp32dev +board_build.partitions = ${common.board_build.partitions} +upload_speed = 921600 +lib_deps = + ${common.lib_deps_all} + ${common.lib_deps_display} +build_flags = + ${common.build_flags} +upload_protocol = ${common.upload_protocol} +extra_scripts = ${common.extra_scripts} +monitor_speed = ${common.monitor_speed} [env:ttgobeam] -platform = ${common_env_data.platform_espressif32} +platform = ${common.platform_espressif32} framework = arduino board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} +board_build.partitions = ${common.board_build.partitions} upload_speed = 921600 -monitor_speed = 115200 lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_gps} + ${common.lib_deps_all} + ${common.lib_deps_gps} build_flags = - ${common_env_data.build_flags} + ${common.build_flags} -mfix-esp32-psram-cache-issue -;upload_protocol = custom -;extra_scripts = pre:publish_firmware.py +upload_protocol = ${common.upload_protocol} +extra_scripts = ${common.extra_scripts} +monitor_speed = ${common.monitor_speed} [env:fipy] -platform = ${common_env_data.platform_espressif32} +platform = ${common.platform_espressif32} framework = arduino board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} +board_build.partitions = ${common.board_build.partitions} upload_speed = 921600 -monitor_speed = 115200 lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_rgbled} + ${common.lib_deps_all} + ${common.lib_deps_rgbled} build_flags = - ${common_env_data.build_flags} + ${common.build_flags} +upload_protocol = ${common.upload_protocol} +extra_scripts = ${common.extra_scripts} +monitor_speed = ${common.monitor_speed} [env:lopy] -platform = ${common_env_data.platform_espressif32} +platform = ${common.platform_espressif32} framework = arduino board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} +board_build.partitions = ${common.board_build.partitions} upload_speed = 921600 -monitor_speed = 115200 lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_rgbled} - ${common_env_data.lib_deps_gps} + ${common.lib_deps_all} + ${common.lib_deps_rgbled} + ${common.lib_deps_gps} build_flags = - ${common_env_data.build_flags} + ${common.build_flags} +upload_protocol = ${common.upload_protocol} +extra_scripts = ${common.extra_scripts} +monitor_speed = ${common.monitor_speed} [env:lopy4] -platform = ${common_env_data.platform_espressif32} +platform = ${common.platform_espressif32} framework = arduino board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} +board_build.partitions = ${common.board_build.partitions} upload_speed = 921600 -monitor_speed = 115200 lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_rgbled} - ${common_env_data.lib_deps_gps} + ${common.lib_deps_all} + ${common.lib_deps_rgbled} + ${common.lib_deps_gps} build_flags = - ${common_env_data.build_flags} + ${common.build_flags} -mfix-esp32-psram-cache-issue +upload_protocol = ${common.upload_protocol} +extra_scripts = ${common.extra_scripts} +monitor_speed = ${common.monitor_speed} [env:lolin32litelora] -platform = ${common_env_data.platform_espressif32} +platform = ${common.platform_espressif32} framework = arduino board = lolin32 -board_build.partitions = ${common_env_data.board_build.partitions} +board_build.partitions = ${common.board_build.partitions} upload_speed = 921600 -monitor_speed = 115200 lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_rgbled} + ${common.lib_deps_all} + ${common.lib_deps_rgbled} build_flags = - ${common_env_data.build_flags} + ${common.build_flags} +upload_protocol = ${common.upload_protocol} +extra_scripts = ${common.extra_scripts} +monitor_speed = ${common.monitor_speed} [env:lolin32lora] -platform = ${common_env_data.platform_espressif32} +platform = ${common.platform_espressif32} framework = arduino board = lolin32 -board_build.partitions = ${common_env_data.board_build.partitions} +board_build.partitions = ${common.board_build.partitions} upload_speed = 921600 -monitor_speed = 115200 lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_rgbled} + ${common.lib_deps_all} + ${common.lib_deps_rgbled} build_flags = - ${common_env_data.build_flags} + ${common.build_flags} +upload_protocol = ${common.upload_protocol} +extra_scripts = ${common.extra_scripts} +monitor_speed = ${common.monitor_speed} [env:lolin32lite] -platform = ${common_env_data.platform_espressif32} +platform = ${common.platform_espressif32} framework = arduino board = lolin32 -board_build.partitions = ${common_env_data.board_build.partitions} +board_build.partitions = ${common.board_build.partitions} upload_speed = 921600 -monitor_speed = 115200 lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_rgbled} + ${common.lib_deps_all} + ${common.lib_deps_rgbled} build_flags = - ${common_env_data.build_flags} + ${common.build_flags} +upload_protocol = ${common.upload_protocol} +extra_scripts = ${common.extra_scripts} +monitor_speed = ${common.monitor_speed} [env:generic] -platform = ${common_env_data.platform_espressif32} +platform = ${common.platform_espressif32} framework = arduino board = esp32dev -board_build.partitions = ${common_env_data.board_build.partitions} +board_build.partitions = ${common.board_build.partitions} upload_speed = 921600 -monitor_speed = 115200 lib_deps = - ${common_env_data.lib_deps_all} - ${common_env_data.lib_deps_rgbled} - ${common_env_data.lib_deps_gps} - ${common_env_data.lib_deps_display} + ${common.lib_deps_all} + ${common.lib_deps_rgbled} + ${common.lib_deps_gps} + ${common.lib_deps_display} build_flags = - ${common_env_data.build_flags} + ${common.build_flags} +upload_protocol = ${common.upload_protocol} +extra_scripts = ${common.extra_scripts} +monitor_speed = ${common.monitor_speed} diff --git a/publish_firmware.py b/publish_firmware.py index 7086d0138..b98487079 100644 --- a/publish_firmware.py +++ b/publish_firmware.py @@ -16,31 +16,30 @@ from os.path import basename from platformio import util -Import('env') +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") +version = project_config.get("ota", "release_version") +package = env.get("PIOENV") # # Push new firmware to the Bintray storage using API # -def publish_firmware(source, target, env): +def publish_bintray(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 + package, version, firmware_name ]) print(url) @@ -65,7 +64,8 @@ def publish_firmware(source, target, env): # Custom upload command and program name + env.Replace( - PROGNAME="firmware_v_%s" % version, - UPLOADCMD=publish_firmware + PROGNAME="firmware_" + package + "_v%s" % version, + UPLOADCMD=publish_bintray ) \ No newline at end of file diff --git a/src/OTA.cpp b/src/OTA.cpp index 876099491..7f46ea854 100644 --- a/src/OTA.cpp +++ b/src/OTA.cpp @@ -59,16 +59,16 @@ void checkFirmwareUpdates() { // Fetch the latest firmware version ESP_LOGI(TAG, "OTA mode, checking latest firmware version on server..."); const String latest = bintray.getLatestVersion(); + if (latest.length() == 0) { ESP_LOGI( TAG, "Could not load info about the latest firmware. Rebooting to runmode."); return; - } else if (atoi(latest.c_str()) <= VERSION) { + } else if (version_compare(latest, cfg.version) <= 0) { ESP_LOGI(TAG, "Current firmware is up to date. Rebooting to runmode."); return; } - ESP_LOGI(TAG, "New firmware version v%s available. Downloading...", latest.c_str()); processOTAUpdate(latest); @@ -218,4 +218,39 @@ void processOTAUpdate(const String &version) { "There was no valid content in the response from the OTA server!"); client.flush(); } +} + +// helper function to compare two versions. Returns 1 if v2 is +// smaller, -1 if v1 is smaller, 0 if equal + +int version_compare(const String v1, const String v2) { + // vnum stores each numeric part of version + int vnum1 = 0, vnum2 = 0; + + // loop untill both string are processed + for (int i = 0, j = 0; (i < v1.length() || j < v2.length());) { + // storing numeric part of version 1 in vnum1 + while (i < v1.length() && v1[i] != '.') { + vnum1 = vnum1 * 10 + (v1[i] - '0'); + i++; + } + + // storing numeric part of version 2 in vnum2 + while (j < v2.length() && v2[j] != '.') { + vnum2 = vnum2 * 10 + (v2[j] - '0'); + j++; + } + + if (vnum1 > vnum2) + return 1; + if (vnum2 > vnum1) + return -1; + + // if equal, reset variables and go for next numeric + // part + vnum1 = vnum2 = 0; + i++; + j++; + } + return 0; } \ No newline at end of file diff --git a/src/OTA.h b/src/OTA.h index fc66973c9..1a17fa24b 100644 --- a/src/OTA.h +++ b/src/OTA.h @@ -1,6 +1,7 @@ #ifndef OTA_H #define OTA_H +#include "globals.h" #include #include #include @@ -9,5 +10,6 @@ void checkFirmwareUpdates(); void processOTAUpdate(const String &version); void start_ota_update(); +int version_compare(const String v1, const String v2); #endif // OTA_H \ No newline at end of file diff --git a/src/globals.h b/src/globals.h index 20acd5cb9..fd057b5d9 100644 --- a/src/globals.h +++ b/src/globals.h @@ -4,10 +4,6 @@ // The mother of all embedded development... #include -// attn: increment version after modifications to configData_t truct! -#define PROGVERSION "1.4.30" // use max 10 chars here! -#define PROGNAME "PAXCNT" - // std::set for unified array functions #include #include diff --git a/src/hal/ttgov21.h b/src/hal/ttgov21.h deleted file mode 100644 index 6d59065d4..000000000 --- a/src/hal/ttgov21.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Hardware related definitions for TTGO V2.1 Board -/ ATTENTION: check your board version! -/ Different versions are on the market which need different settings in this file: -/ - without label -> use settings (2) -/ - labeled V1.5 on pcb -> use settings (2) -/ - labeled V1.6 on pcb -> use settings (1) -/ Choose the right configuration below -*/ - -/* -// (1) settings for board labeled "T3_V1.6" on pcb - -#define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI -#define CFG_sx1276_radio 1 // HPD13A LoRa SoC - -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C -#define HAS_LED GPIO_NUM_25 // green on board LED -#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // uses GPIO7 -#define BATT_FACTOR 2 // voltage divider 100k/100k on board - -// re-define pin definitions of pins_arduino.h -#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- HPD13A NSS/SEL (Pin4) SPI Chip Select Input -#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- HPD13A MOSI/DSI (Pin6) SPI Data Input -#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- HPD13A MISO/DSO (Pin7) SPI Data Output -#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- HPD13A SCK (Pin5) SPI Clock Input - -// non arduino pin definitions -#define RST GPIO_NUM_23 // ESP32 GPIO23 <-> HPD13A RESET -#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 <-> HPD13A IO0 -#define DIO1 GPIO_NUM_33 // ESP32 GPIO33 <-> HPDIO1 <-> HPD13A IO1 -#define DIO2 GPIO_NUM_32 // ESP32 GPIO32 <-> HPDIO2 <-> HPD13A IO2 - -// Hardware pin definitions for TTGO V2 Board with OLED SSD1306 0,96" I2C Display -#define OLED_RST U8X8_PIN_NONE // connected to CPU RST/EN -#define OLED_SDA GPIO_NUM_21 // ESP32 GPIO21 -- SD1306 D1+D2 -#define OLED_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0 - -*/ - -// (2) settings for boards without label on pcb, or labeled v1.5 on pcb - -#define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI -#define CFG_sx1276_radio 1 // HPD13A LoRa SoC -#define HAS_LED NOT_A_PIN // no usable LED on board - -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C -#define DISPLAY_FLIP 1 // rotated display -#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // uses GPIO7 -#define BATT_FACTOR 2 // voltage divider 100k/100k on board - -// re-define pin definitions of pins_arduino.h -#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- HPD13A NSS/SEL (Pin4) SPI Chip Select Input -#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- HPD13A MOSI/DSI (Pin6) SPI Data Input -#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- HPD13A MISO/DSO (Pin7) SPI Data Output -#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- HPD13A SCK (Pin5) SPI Clock Input - -// non arduino pin definitions -#define RST LMIC_UNUSED_PIN // connected to ESP32 RST/EN (old board) -//#define RST GPIO_NUM_12 // (boards labeled v1.5) -#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 <-> HPD13A IO0 -#define DIO1 GPIO_NUM_33 // ESP32 GPIO33 <-> HPDIO1 <-> HPD13A IO1 -#define DIO2 GPIO_NUM_32 // ESP32 GPIO32 <-> HPDIO2 <-> HPD13A IO2 - -// Hardware pin definitions for TTGO V2 Board with OLED SSD1306 0,96" I2C Display -#define OLED_RST U8X8_PIN_NONE // connected to CPU RST/EN -#define OLED_SDA GPIO_NUM_21 // ESP32 GPIO21 -- SD1306 D1+D2 -#define OLED_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0 diff --git a/src/hal/ttgov21new.h b/src/hal/ttgov21new.h new file mode 100644 index 000000000..ce64323f9 --- /dev/null +++ b/src/hal/ttgov21new.h @@ -0,0 +1,30 @@ +/* Hardware related definitions for TTGO V2.1 Board +// ATTENTION: check your board version! +// This settings are for boards labeled v1.6 on pcb, NOT for v1.5 or older +*/ + +#define HAS_LORA 1 // comment out if device shall not send data via LoRa +#define HAS_SPI 1 // comment out if device shall not send data via SPI +#define CFG_sx1276_radio 1 // HPD13A LoRa SoC + +#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C +#define HAS_LED GPIO_NUM_25 // green on board LED +#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // uses GPIO7 +#define BATT_FACTOR 2 // voltage divider 100k/100k on board + +// re-define pin definitions of pins_arduino.h +#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- HPD13A NSS/SEL (Pin4) SPI Chip Select Input +#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- HPD13A MOSI/DSI (Pin6) SPI Data Input +#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- HPD13A MISO/DSO (Pin7) SPI Data Output +#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- HPD13A SCK (Pin5) SPI Clock Input + +// non arduino pin definitions +#define RST GPIO_NUM_23 // ESP32 GPIO23 <-> HPD13A RESET +#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 <-> HPD13A IO0 +#define DIO1 GPIO_NUM_33 // ESP32 GPIO33 <-> HPDIO1 <-> HPD13A IO1 +#define DIO2 GPIO_NUM_32 // ESP32 GPIO32 <-> HPDIO2 <-> HPD13A IO2 + +// Hardware pin definitions for TTGO V2 Board with OLED SSD1306 0,96" I2C Display +#define OLED_RST U8X8_PIN_NONE // connected to CPU RST/EN +#define OLED_SDA GPIO_NUM_21 // ESP32 GPIO21 -- SD1306 D1+D2 +#define OLED_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0 \ No newline at end of file diff --git a/src/hal/ttgov21old.h b/src/hal/ttgov21old.h new file mode 100644 index 000000000..f6882187f --- /dev/null +++ b/src/hal/ttgov21old.h @@ -0,0 +1,32 @@ +/* Hardware related definitions for TTGO V2.1 Board +// ATTENTION: check your board version! +// This settings are for boards without label on pcb, or labeled v1.5 on pcb +*/ + +#define HAS_LORA 1 // comment out if device shall not send data via LoRa +#define HAS_SPI 1 // comment out if device shall not send data via SPI +#define CFG_sx1276_radio 1 // HPD13A LoRa SoC +#define HAS_LED NOT_A_PIN // no usable LED on board + +#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C +#define DISPLAY_FLIP 1 // rotated display +#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // uses GPIO7 +#define BATT_FACTOR 2 // voltage divider 100k/100k on board + +// re-define pin definitions of pins_arduino.h +#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- HPD13A NSS/SEL (Pin4) SPI Chip Select Input +#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- HPD13A MOSI/DSI (Pin6) SPI Data Input +#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- HPD13A MISO/DSO (Pin7) SPI Data Output +#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- HPD13A SCK (Pin5) SPI Clock Input + +// non arduino pin definitions +#define RST LMIC_UNUSED_PIN // connected to ESP32 RST/EN (old board) +//#define RST GPIO_NUM_12 // (boards labeled v1.5) +#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 <-> HPD13A IO0 +#define DIO1 GPIO_NUM_33 // ESP32 GPIO33 <-> HPDIO1 <-> HPD13A IO1 +#define DIO2 GPIO_NUM_32 // ESP32 GPIO32 <-> HPDIO2 <-> HPD13A IO2 + +// Hardware pin definitions for TTGO V2 Board with OLED SSD1306 0,96" I2C Display +#define OLED_RST U8X8_PIN_NONE // connected to CPU RST/EN +#define OLED_SDA GPIO_NUM_21 // ESP32 GPIO21 -- SD1306 D1+D2 +#define OLED_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0 diff --git a/src/main.cpp b/src/main.cpp index 6de8432cb..d84deb189 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -90,7 +90,7 @@ void setup() { esp_log_set_vprintf(redirect_log); #endif - ESP_LOGI(TAG, "Starting %s v%s", PROGNAME, PROGVERSION); + ESP_LOGI(TAG, "Starting %s v%s", PRODUCTNAME, PROGVERSION); // initialize system event handler for wifi task, needed for // wifi_sniffer_init() @@ -213,7 +213,7 @@ void setup() { #ifdef HAS_DISPLAY strcat_P(features, " OLED"); DisplayState = cfg.screenon; - init_display(PROGNAME, PROGVERSION); + init_display(PRODUCTNAME, PROGVERSION); // setup display refresh trigger IRQ using esp32 hardware timer // https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/ diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 68681b9b9..92380894e 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -4,6 +4,8 @@ // // Note: After editing, before "build", use "clean" button in PlatformIO! +#define PRODUCTNAME "PAXCNT" + // Verbose enables serial output #define VERBOSE 1 // comment out to silence the device, for mute use build option diff --git a/src/payload.cpp b/src/payload.cpp index 61514f949..38c2df76b 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -52,8 +52,8 @@ void PayloadConvert::addConfig(configData_t value) { cursor += 10; } -void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, - float cputemp, uint32_t mem) { +void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, float cputemp, + uint32_t mem, uint8_t reset1, uint8_t reset2) { buffer[cursor++] = highByte(voltage); buffer[cursor++] = lowByte(voltage); @@ -124,6 +124,7 @@ void PayloadConvert::addConfig(configData_t value) { value.screenon ? true : false, value.countermode ? true : false, value.blescan ? true : false, value.wifiant ? true : false, value.vendorfilter ? true : false, value.gpsmode ? true : false); + writeVersion(value.version); } void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, float cputemp, @@ -160,6 +161,11 @@ void PayloadConvert::writeUptime(uint64_t uptime) { intToBytes(cursor, uptime, 8); } +void PayloadConvert::writeVersion(char * version) { + memcpy(buffer + cursor, version, 10); + cursor += 10; +} + void PayloadConvert::writeLatLng(double latitude, double longitude) { intToBytes(cursor, latitude, 4); intToBytes(cursor, longitude, 4); diff --git a/src/payload.h b/src/payload.h index 6cf453e59..5973bdd90 100644 --- a/src/payload.h +++ b/src/payload.h @@ -64,6 +64,7 @@ class PayloadConvert { void writeUint8(uint8_t i); void writeHumidity(float humidity); void writeTemperature(float temperature); + void writeVersion(char * version); void writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, bool g, bool h); From 836572eeb241fc59756d482aece56fcf08d221af Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 17 Sep 2018 18:06:50 +0200 Subject: [PATCH 22/43] cleanup platformio.ini --- platformio.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platformio.ini b/platformio.ini index 97148ac3f..8d614480a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -6,20 +6,21 @@ ; ---> SELECT TARGET PLATFORM HERE! <--- [platformio] -;env_default = generic +env_default = generic ;env_default = ebox ;env_default = heltec ;env_default = ttgov1 ;env_default = ttgov2 ;env_default = ttgov21old ;env_default = ttgov21new -env_default = ttgobeam +;env_default = ttgobeam ;env_default = lopy ;env_default = lopy4 ;env_default = fipy ;env_default = lolin32litelora ;env_default = lolin32lora ;env_default = lolin32lite +;env_default = ebox, heltec, ttgobeam, lopy4, lopy, ttgov21old, ttgov21new ; description = Paxcounter is a proof-of-concept ESP32 device for metering passenger flows in realtime. It counts how many mobile devices are around. @@ -72,7 +73,6 @@ build_flags = -w -DCORE_DEBUG_LEVEL=${common.debug_level} - [env:ebox] platform = ${common.platform_espressif32} framework = arduino @@ -286,4 +286,4 @@ build_flags = ${common.build_flags} upload_protocol = ${common.upload_protocol} extra_scripts = ${common.extra_scripts} -monitor_speed = ${common.monitor_speed} +monitor_speed = ${common.monitor_speed} \ No newline at end of file From 52efcb7b019152e149aa49011ee39fc79eac31b4 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 17 Sep 2018 21:57:01 +0200 Subject: [PATCH 23/43] TTN decoders updated --- src/TTN/packed_decoder.js | 14 +++++++++++--- src/TTN/plain_decoder.js | 3 +++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/TTN/packed_decoder.js b/src/TTN/packed_decoder.js index 9aaf1cfc5..db04e5ab8 100644 --- a/src/TTN/packed_decoder.js +++ b/src/TTN/packed_decoder.js @@ -18,12 +18,12 @@ function Decoder(bytes, port) { if (port === 2) { // device status data - return decode(bytes, [uint16, uptime, uint8, uint32], ['voltage', 'uptime', 'cputemp', 'memory']); + return decode(bytes, [uint16, uptime, uint8, uint32, uint8, uint8], ['voltage', 'uptime', 'cputemp', 'memory', 'reset0', 'reset1']); } if (port === 3) { // device config data - return decode(bytes, [uint8, uint8, uint16, uint8, uint8, uint8, uint8, bitmap], ['lorasf', 'txpower', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags']); + return decode(bytes, [uint8, uint8, uint16, uint8, uint8, uint8, uint8, bitmap, version], ['lorasf', 'txpower', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags', 'version']); } if (port === 4) { @@ -55,6 +55,14 @@ var bytesToInt = function (bytes) { return i; }; +var version = function (bytes) { + if (bytes.length !== version.BYTES) { + throw new Error('version must have exactly 10 bytes'); + } + return String.fromCharCode.apply(null, bytes).split('\u0000')[0]; + }; +version.BYTES = 10; + var uint8 = function (bytes) { if (bytes.length !== uint8.BYTES) { throw new Error('uint8 must have exactly 1 byte'); @@ -180,12 +188,12 @@ if (typeof module === 'object' && typeof module.exports !== 'undefined') { uint16: uint16, uint32: uint32, uptime: uptime, - reset: reset, temperature: temperature, humidity: humidity, latLng: latLng, hdop: hdop, bitmap: bitmap, + version: version, decode: decode }; } \ No newline at end of file diff --git a/src/TTN/plain_decoder.js b/src/TTN/plain_decoder.js index ba674d35f..0de53fc28 100644 --- a/src/TTN/plain_decoder.js +++ b/src/TTN/plain_decoder.js @@ -25,6 +25,9 @@ function Decoder(bytes, port) { decoded.uptime = ((bytes[i++] << 56) | (bytes[i++] << 48) | (bytes[i++] << 40) | (bytes[i++] << 32) | (bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++]); decoded.temp = bytes[i++]; + decoded.memory = ((bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++]); + decoded.reset0 = bytes[i++]; + decoded.reset1 = bytes[i++]; } if (port === 5) { From 6052588af0b5545fcafd819b777cdde4f136be91 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 17 Sep 2018 22:03:03 +0200 Subject: [PATCH 24/43] TTN decoders updated --- src/TTN/packed_decoder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TTN/packed_decoder.js b/src/TTN/packed_decoder.js index db04e5ab8..fd9b955e9 100644 --- a/src/TTN/packed_decoder.js +++ b/src/TTN/packed_decoder.js @@ -60,7 +60,7 @@ var version = function (bytes) { throw new Error('version must have exactly 10 bytes'); } return String.fromCharCode.apply(null, bytes).split('\u0000')[0]; - }; +}; version.BYTES = 10; var uint8 = function (bytes) { From 2201e48800863cba8c3405bd68cd3da02bb19ffd Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Tue, 18 Sep 2018 17:23:56 +0200 Subject: [PATCH 25/43] build.py, ota.conf, platformio.ini --- .gitignore | 3 +- build.py | 77 +++++++++++++++++++++++++++++++++++++++++++++ platformio.ini | 34 ++++++-------------- publish_firmware.py | 71 ----------------------------------------- src/ota.sample.conf | 8 +++++ 5 files changed, 96 insertions(+), 97 deletions(-) create mode 100644 build.py delete mode 100644 publish_firmware.py create mode 100644 src/ota.sample.conf diff --git a/.gitignore b/.gitignore index dbccbfe15..875ecd9f1 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ .vscode/.browse.c_cpp.db* .clang_complete .gcc-flags.json -src/loraconf.h \ No newline at end of file +src/loraconf.h +src/ota.conf \ No newline at end of file diff --git a/build.py b/build.py new file mode 100644 index 000000000..f0fdc73ea --- /dev/null +++ b/build.py @@ -0,0 +1,77 @@ +# build.py +# pre-build script, setting up build environment + +import requests +from os.path import basename +from platformio import util + +Import("env") + +# get keyfile from platformio.ini and parse it +project_config = util.load_project_config() +keyfile = str(env.get("PROJECTSRC_DIR")) + "/" + project_config.get("common", "keyfile") +print "Parsing OTA keys from " + keyfile +mykeys = {} +with open(keyfile) as myfile: + for line in myfile: + key, value = line.partition("=")[::2] + mykeys[key.strip()] = str(value).strip() + +# get bintray credentials from keyfile +user = mykeys["BINTRAY_USER"] +repository = mykeys["BINTRAY_REPO"] +apitoken = mykeys["BINTRAY_API_TOKEN"] + +# get bintray parameters from platformio.ini +version = project_config.get("common", "release_version") +package = str(env.get("PIOENV")) + +# put bintray credentials to platformio environment +env.Replace(BINTRAY_USER=user) +env.Replace(BINTRAY_REPO=repository) +env.Replace(BINTRAY_API_TOKEN=apitoken) + +# get runtime credentials from keyfile and put them to compiler directive +env.Replace(CPPDEFINES=[ + ('WIFI_SSID', '\\"' + mykeys["OTA_WIFI_SSID"] + '\\"'), + ('WIFI_PASS', '\\"' + mykeys["OTA_WIFI_PASS"] + '\\"'), + ('BINTRAY_USER', '\\"' + mykeys["BINTRAY_USER"] + '\\"'), + ('BINTRAY_REPO', '\\"' + mykeys["BINTRAY_REPO"] + '\\"'), + ]) + +# function for pushing new firmware to bintray storage using API +def publish_bintray(source, target, env): + firmware_path = str(source[0]) + firmware_name = basename(firmware_path) + url = "/".join([ + "https://api.bintray.com", "content", + user, repository, package, version, firmware_name + ]) + + print("Uploading {0} to Bintray. Version: {1}".format( + firmware_name, version)) + 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=(user, apitoken)) + + 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!") + +# put build file name and upload command to platformio environment +env.Replace( + PROGNAME="firmware_" + package + "_v%s" % version, + UPLOADCMD=publish_bintray +) \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 8d614480a..5ca50241c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -24,34 +24,17 @@ env_default = generic ; description = Paxcounter is a proof-of-concept ESP32 device for metering passenger flows in realtime. It counts how many mobile devices are around. -[bintray] -user = cyberman54 -repository = paxcounter-firmware -api_token = 2e10f923df5d47b9c7e25752510322a1d65ee997 - -[ota] -;release_version = max. 9 chars total, using decimal format "a.b.c" -release_version = 1.4.32 -wifi_ssid = testnet -wifi_password = test0815 -build_flags = - '-DWIFI_SSID="${ota.wifi_ssid}"' - '-DWIFI_PASS="${ota.wifi_password}"' - '-DBINTRAY_USER="${bintray.user}"' - '-DBINTRAY_REPO="${bintray.repository}"' - '-DBINTRAY_PACKAGE="${PIOENV}"' - '-DPROGVERSION="${ota.release_version}"' - [common] -; DEBUG LEVEL -; For production run setto 0, otherwise device will leak RAM while running! +; for release_version use max.10 chars total, use any decimal format like "a.b.c" +release_version = 1.4.33 +; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running! ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose debug_level = 0 -; UPLOAD MODE -; select esptool for USB/UART flashing, custom for OTA upload +; UPLOAD MODE: select esptool to flash via USB/UART, select custom to upload to cloud for OTA upload_protocol = esptool ;upload_protocol = custom -extra_scripts = pre:publish_firmware.py +extra_scripts = pre:build.py +keyfile = ota.conf platform_espressif32 = espressif32@1.3.0 board_build.partitions = min_spiffs.csv monitor_speed = 115200 @@ -69,9 +52,10 @@ build_flags = -D_lmic_config_h_ -include "src/paxcounter.conf" -include "src/hal/${PIOENV}.h" - ${ota.build_flags} -w - -DCORE_DEBUG_LEVEL=${common.debug_level} + '-DCORE_DEBUG_LEVEL=${common.debug_level}' + '-DBINTRAY_PACKAGE="${PIOENV}"' + '-DPROGVERSION="${common.release_version}"' [env:ebox] platform = ${common.platform_espressif32} diff --git a/publish_firmware.py b/publish_firmware.py deleted file mode 100644 index b98487079..000000000 --- a/publish_firmware.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright (c) 2014-present PlatformIO -# -# 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("ota", "release_version") -package = env.get("PIOENV") - -# -# Push new firmware to the Bintray storage using API -# - - -def publish_bintray(source, target, env): - firmware_path = str(source[0]) - firmware_name = basename(firmware_path) - - print("Uploading {0} to Bintray. Version: {1}".format( - firmware_name, version)) - - url = "/".join([ - "https://api.bintray.com", "content", - bintray_config.get("user"), - bintray_config.get("repository"), - 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_" + package + "_v%s" % version, - UPLOADCMD=publish_bintray -) \ No newline at end of file diff --git a/src/ota.sample.conf b/src/ota.sample.conf new file mode 100644 index 000000000..f5aed2a73 --- /dev/null +++ b/src/ota.sample.conf @@ -0,0 +1,8 @@ +[ota] +OTA_WIFI_SSID = myhomewifi +OTA_WIFI_PASS = FooBar42! + +[bintray] +BINTRAY_USER = mybintrayuser +BINTRAY_REPO = mybintrayrepo +BINTRAY_API_TOKEN = 2e10f923df5d47b9c5423432322a1d4324783997 \ No newline at end of file From ce1b774d283a435e261c47c04277533f8fb06286 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Tue, 18 Sep 2018 17:25:18 +0200 Subject: [PATCH 26/43] Rename OTA.cpp to ota.cpp --- src/{OTA.cpp => ota.cpp} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/{OTA.cpp => ota.cpp} (99%) diff --git a/src/OTA.cpp b/src/ota.cpp similarity index 99% rename from src/OTA.cpp rename to src/ota.cpp index 7f46ea854..5d94bbed2 100644 --- a/src/OTA.cpp +++ b/src/ota.cpp @@ -253,4 +253,4 @@ int version_compare(const String v1, const String v2) { j++; } return 0; -} \ No newline at end of file +} From 14957bea9627de8a01822d1f621edd634471fa5c Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Tue, 18 Sep 2018 17:25:44 +0200 Subject: [PATCH 27/43] Rename OTA.h to ota.h --- src/{OTA.h => ota.h} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/{OTA.h => ota.h} (94%) diff --git a/src/OTA.h b/src/ota.h similarity index 94% rename from src/OTA.h rename to src/ota.h index 1a17fa24b..4b9e92d12 100644 --- a/src/OTA.h +++ b/src/ota.h @@ -12,4 +12,4 @@ void processOTAUpdate(const String &version); void start_ota_update(); int version_compare(const String v1, const String v2); -#endif // OTA_H \ No newline at end of file +#endif // OTA_H From aa9129abcad8fafc8e3d2095692ed00b8bed71d4 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Tue, 18 Sep 2018 18:01:56 +0200 Subject: [PATCH 28/43] Update README.md --- README.md | 52 +++++++--------------------------------------------- 1 file changed, 7 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 870f3656b..047b3ff35 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,13 @@ If you're using [TheThingsNetwork](https://www.thethingsnetwork.org/) (TTN) you To track a paxcounter device with on board GPS and at the same time contribute to TTN coverage mapping, you simply activate the [TTNmapper integration](https://www.thethingsnetwork.org/docs/applications/ttnmapper/) in TTN Console. The formats *plain* and *packed* generate the fields `latitude`, `longitude` and `hdop` required by ttnmapper. -Hereafter described is the default *plain* format, which uses MSB bit numbering. +Hereafter described is the default *plain* format, which uses MSB bit numbering. Under /TTN in this repository you find some ready-to-go decoders which you may copy to your TTN console: + +[**plain_decoder.js**](src/TTN/plain_decoder.js) | +[**plain_converter.js**](src/TTN/plain_converter.js) | +[**pdacked_decoder.js**](src/TTN/packed_decoder.js) | +[**packed_converter.js**](src/TTN/packed_converter.js) + **Port #1:** Paxcount data @@ -182,50 +188,6 @@ Hereafter described is the default *plain* format, which uses MSB bit numbering. byte 1: Beacon RSSI reception level byte 2: Beacon identifier (0..255) - -[**plain_decoder.js**](src/TTN/plain_decoder.js) - -```javascript -function Decoder(bytes, port) { - var decoded = {}; - - if (port === 1) { - var i = 0; - decoded.wifi = (bytes[i++] << 8) | bytes[i++]; - decoded.ble = (bytes[i++] << 8) | bytes[i++]; - if (bytes.length > 4) { - decoded.latitude = ( (bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++] ); - decoded.longitude = ( (bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++] ); - decoded.sats = ( bytes[i++] ); - decoded.hdop = ( bytes[i++] << 8) | (bytes[i++] ); - decoded.altitude = ( bytes[i++] << 8) | (bytes[i++] ); - } - } - - return decoded; -} -``` - -[**plain_converter.js**](src/TTN/plain_converter.js) - -```javascript -function Converter(decoded, port) { - - var converted = decoded; - - if (port === 1) { - converted.pax = converted.ble + converted.wifi; - if (converted.hdop) { - converted.hdop /= 100; - converted.latitude /= 1000000; - converted.longitude /= 1000000; - } - } - - return converted; -} -``` - # Remote control The device listenes for remote control commands on LoRaWAN Port 2. Multiple commands per downlink are possible by concatenating them. From f18c567adf7b15f1480a524b2d44cf0d3dede5e7 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Tue, 18 Sep 2018 18:03:06 +0200 Subject: [PATCH 29/43] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 047b3ff35..69a076edb 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ Hereafter described is the default *plain* format, which uses MSB bit numbering. [**plain_decoder.js**](src/TTN/plain_decoder.js) | [**plain_converter.js**](src/TTN/plain_converter.js) | -[**pdacked_decoder.js**](src/TTN/packed_decoder.js) | +[**packed_decoder.js**](src/TTN/packed_decoder.js) | [**packed_converter.js**](src/TTN/packed_converter.js) From ed50a79297d14404c440c1a943c9dec1ecad2eb0 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Tue, 18 Sep 2018 18:43:51 +0200 Subject: [PATCH 30/43] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 69a076edb..dfa9eafed 100644 --- a/README.md +++ b/README.md @@ -74,10 +74,14 @@ Use PlatformIO with your preferred IDE for # Uploading -To upload the code to your ESP32 board this needs to be switched from run to bootloader mode. Boards with USB bridge like Heltec and TTGO usually have an onboard logic which allows soft switching by the upload tool. In PlatformIO this happenes automatically.

+- **Initially, using USB/UART cable:** +To upload the code via cable to your ESP32 board this needs to be switched from run to bootloader mode. Boards with USB bridge like Heltec and TTGO usually have an onboard logic which allows soft switching by the upload tool. In PlatformIO this happenes automatically.

The LoPy/LoPy4/FiPy board needs to be set manually. See these instructions how to do it. Don't forget to press on board reset button after switching between run and bootloader mode.

The original Pycom firmware is not needed, so there is no need to update it before flashing Paxcounter. Just flash the compiled paxcounter binary (.elf file) on your LoPy/LoPy4/FiPy. If you later want to go back to the Pycom firmware, download the firmware from Pycom and flash it over. + +- **During runtime, using FOTA via WIFI:** +After the ESP32 board is initially flashed and has joined a LoRaWAN network, the firmware can update itself by FOTA. This process is kicked off by sending a remote control command (see below) via LoRaWAN to the board. The board then tries to connect via WIFI to a cloud service (JFrog Bintray), checks for update, and if available downloads the binary and reboots with it. If something goes wrong during this process, the board reboots back to the current version. Prerequisites for FOTA are: 1. You own a Bintray repository (free), 2. you pushed the update binary to the Bintray repository, 3. internet access via encrypted (WPA2) WIFI is present at the board's site, 4. WIFI credentials were set in ota.conf and initially flashed to the board. Step 2 runs automated, just enter the credentials in ota.conf and set `upload_protocol = custom` in platformio.ini. Then press build and lean back watching platformio doing build and upload. # Legal note From d80d1e24e9b1a278f7e94d894dfe6c0c4c80cd43 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Tue, 18 Sep 2018 22:58:02 +0200 Subject: [PATCH 31/43] ota.cpp: added a retry loop for write-to-flash --- platformio.ini | 2 +- src/ota.cpp | 34 ++++++++++++++++++++++++---------- src/paxcounter.conf | 1 + 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/platformio.ini b/platformio.ini index 5ca50241c..7cf588775 100644 --- a/platformio.ini +++ b/platformio.ini @@ -26,7 +26,7 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng [common] ; for release_version use max.10 chars total, use any decimal format like "a.b.c" -release_version = 1.4.33 +release_version = 1.4.34 ; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running! ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose debug_level = 0 diff --git a/src/ota.cpp b/src/ota.cpp index 5d94bbed2..34136f858 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -112,7 +112,7 @@ void processOTAUpdate(const String &version) { } } - // ESP_LOGI(TAG, "Requesting: " + firmwarePath); + ESP_LOGI(TAG, "Requesting %s", firmwarePath); client.print(String("GET ") + firmwarePath + " HTTP/1.1\r\n"); client.print(String("Host: ") + currentHost + "\r\n"); @@ -185,20 +185,33 @@ void processOTAUpdate(const String &version) { // check whether we have everything for OTA update if (contentLength && isValidContentType) { + + size_t written; + if (Update.begin(contentLength)) { - ESP_LOGI(TAG, "Starting OTA update. This will take some time to " - "complete..."); - size_t written = Update.writeStream(client); - if (written == contentLength) { - ESP_LOGI(TAG, "Written %d bytes successfully", written); - } else { - ESP_LOGI(TAG, "Written only %d of %d bytes, OTA update cancelled.", - written, contentLength); - // Retry?? + int i = FLASH_MAX_TRY; + while ((i--) && (written != contentLength)) { + + ESP_LOGI(TAG, + "Starting OTA update, attempt %d of %d. This will take some " + "time to complete...", + i, FLASH_MAX_TRY); + + written = Update.writeStream(client); + + if (written == contentLength) { + ESP_LOGI(TAG, "Written %d bytes successfully", written); + break; + } else { + ESP_LOGI(TAG, + "Written only %d of %d bytes, OTA update attempt cancelled.", + written, contentLength); + } } if (Update.end()) { + if (Update.isFinished()) { ESP_LOGI(TAG, "OTA update completed. Rebooting to runmode."); ESP.restart(); @@ -209,6 +222,7 @@ void processOTAUpdate(const String &version) { } 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(); diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 92380894e..1c6c6948f 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -67,6 +67,7 @@ // OTA settings #define WIFI_MAX_TRY 20 // maximum number of wifi connect attempts for OTA update [default = 20] +#define FLASH_MAX_TRY 3 // maximum number of attempts for writing update binary to flash [default = 3] // LMIC settings // define hardware independent LMIC settings here, settings of standard library in /lmic/config.h will be ignored From 7b6c2f1090abaa008de586153b2c94289e6fcbf7 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Wed, 19 Sep 2018 01:35:20 +0200 Subject: [PATCH 32/43] ota.cpp: bugfix --- platformio.ini | 4 ++-- src/ota.cpp | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/platformio.ini b/platformio.ini index 7cf588775..89b444006 100644 --- a/platformio.ini +++ b/platformio.ini @@ -25,8 +25,8 @@ env_default = generic description = Paxcounter is a proof-of-concept ESP32 device for metering passenger flows in realtime. It counts how many mobile devices are around. [common] -; for release_version use max.10 chars total, use any decimal format like "a.b.c" -release_version = 1.4.34 +; for release_version use max. 10 chars total, use any decimal format like "a.b.c" +release_version = 1.4.35 ; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running! ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose debug_level = 0 diff --git a/src/ota.cpp b/src/ota.cpp index 34136f858..c6e7c69bb 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -112,7 +112,7 @@ void processOTAUpdate(const String &version) { } } - ESP_LOGI(TAG, "Requesting %s", firmwarePath); + ESP_LOGI(TAG, "Requesting %s", firmwarePath.c_str()); client.print(String("GET ") + firmwarePath + " HTTP/1.1\r\n"); client.print(String("Host: ") + currentHost + "\r\n"); @@ -162,7 +162,6 @@ void processOTAUpdate(const String &version) { currentHost = newUrl.substring(0, newUrl.indexOf('/')); newUrl.remove(newUrl.indexOf(currentHost), currentHost.length()); firmwarePath = newUrl; - ESP_LOGI(TAG, "firmwarePath: %s", firmwarePath.c_str()); continue; } @@ -196,7 +195,7 @@ void processOTAUpdate(const String &version) { ESP_LOGI(TAG, "Starting OTA update, attempt %d of %d. This will take some " "time to complete...", - i, FLASH_MAX_TRY); + FLASH_MAX_TRY - i, FLASH_MAX_TRY); written = Update.writeStream(client); @@ -211,9 +210,12 @@ void processOTAUpdate(const String &version) { } if (Update.end()) { - + if (Update.isFinished()) { - ESP_LOGI(TAG, "OTA update completed. Rebooting to runmode."); + ESP_LOGI( + TAG, + "OTA update completed. Rebooting to runmode with new version."); + client.stop(); ESP.restart(); } else { ESP_LOGI(TAG, "Something went wrong! OTA update hasn't been finished " @@ -232,6 +234,10 @@ void processOTAUpdate(const String &version) { "There was no valid content in the response from the OTA server!"); client.flush(); } + ESP_LOGI(TAG, + "OTA update failed. Rebooting to runmode with current version."); + client.stop(); + ESP.restart(); } // helper function to compare two versions. Returns 1 if v2 is From 8b2e155576042daad5e8c1e5a42fa20d067bc54b Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Wed, 19 Sep 2018 11:04:23 +0200 Subject: [PATCH 33/43] Rename ota.sample.conf to ota.conf --- src/{ota.sample.conf => ota.conf} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/{ota.sample.conf => ota.conf} (67%) diff --git a/src/ota.sample.conf b/src/ota.conf similarity index 67% rename from src/ota.sample.conf rename to src/ota.conf index f5aed2a73..b27d90929 100644 --- a/src/ota.sample.conf +++ b/src/ota.conf @@ -5,4 +5,4 @@ OTA_WIFI_PASS = FooBar42! [bintray] BINTRAY_USER = mybintrayuser BINTRAY_REPO = mybintrayrepo -BINTRAY_API_TOKEN = 2e10f923df5d47b9c5423432322a1d4324783997 \ No newline at end of file +BINTRAY_API_TOKEN = 2e10f923df5d47b9c5423432322a1d4324783997 From c33112c3b455b4eede398986952bea9af9804e1e Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Wed, 19 Sep 2018 11:38:29 +0200 Subject: [PATCH 34/43] ota.cpp bugfix --- src/ota.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ota.cpp b/src/ota.cpp index c6e7c69bb..dbdcc30d1 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -216,7 +216,7 @@ void processOTAUpdate(const String &version) { TAG, "OTA update completed. Rebooting to runmode with new version."); client.stop(); - ESP.restart(); + return; } else { ESP_LOGI(TAG, "Something went wrong! OTA update hasn't been finished " "properly."); @@ -237,7 +237,6 @@ void processOTAUpdate(const String &version) { ESP_LOGI(TAG, "OTA update failed. Rebooting to runmode with current version."); client.stop(); - ESP.restart(); } // helper function to compare two versions. Returns 1 if v2 is From 8f36b313e33c57c860b76d5a163e3be08cfd3f76 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Wed, 19 Sep 2018 13:33:48 +0200 Subject: [PATCH 35/43] ignore ota.conf --- src/ota.conf | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 src/ota.conf diff --git a/src/ota.conf b/src/ota.conf deleted file mode 100644 index b27d90929..000000000 --- a/src/ota.conf +++ /dev/null @@ -1,8 +0,0 @@ -[ota] -OTA_WIFI_SSID = myhomewifi -OTA_WIFI_PASS = FooBar42! - -[bintray] -BINTRAY_USER = mybintrayuser -BINTRAY_REPO = mybintrayrepo -BINTRAY_API_TOKEN = 2e10f923df5d47b9c5423432322a1d4324783997 From 421b5786e3df4c7bb58ffb50d4e6aaf214c4912f Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Wed, 19 Sep 2018 13:48:33 +0200 Subject: [PATCH 36/43] Add files via upload --- src/ota.conf.txt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/ota.conf.txt diff --git a/src/ota.conf.txt b/src/ota.conf.txt new file mode 100644 index 000000000..5a525116f --- /dev/null +++ b/src/ota.conf.txt @@ -0,0 +1,8 @@ +[ota] +OTA_WIFI_SSID = MyHomeWifi +OTA_WIFI_PASS = FooBar42! + +[bintray] +BINTRAY_USER = MyBintrayUser +BINTRAY_REPO = MyBintrayRepo +BINTRAY_API_TOKEN = 3894a7a51d70c6523c1b7479261c34845ebf7878 \ No newline at end of file From 8026d4426beaf2d0724ccc84586c075e2f4305ec Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Wed, 19 Sep 2018 13:49:21 +0200 Subject: [PATCH 37/43] Rename ota.conf.txt to ota.conf --- src/{ota.conf.txt => ota.conf} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/{ota.conf.txt => ota.conf} (64%) diff --git a/src/ota.conf.txt b/src/ota.conf similarity index 64% rename from src/ota.conf.txt rename to src/ota.conf index 5a525116f..373d7af5f 100644 --- a/src/ota.conf.txt +++ b/src/ota.conf @@ -5,4 +5,4 @@ OTA_WIFI_PASS = FooBar42! [bintray] BINTRAY_USER = MyBintrayUser BINTRAY_REPO = MyBintrayRepo -BINTRAY_API_TOKEN = 3894a7a51d70c6523c1b7479261c34845ebf7878 \ No newline at end of file +BINTRAY_API_TOKEN = 3894a7a51d70c6523c1b7479261c34845ebf7878 From 8d65c84d1648b2faeef8dd01e8cb93fddf54d2b5 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Wed, 19 Sep 2018 13:52:14 +0200 Subject: [PATCH 38/43] ota.conf --- src/ota.conf | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 src/ota.conf diff --git a/src/ota.conf b/src/ota.conf deleted file mode 100644 index 373d7af5f..000000000 --- a/src/ota.conf +++ /dev/null @@ -1,8 +0,0 @@ -[ota] -OTA_WIFI_SSID = MyHomeWifi -OTA_WIFI_PASS = FooBar42! - -[bintray] -BINTRAY_USER = MyBintrayUser -BINTRAY_REPO = MyBintrayRepo -BINTRAY_API_TOKEN = 3894a7a51d70c6523c1b7479261c34845ebf7878 From 22aef4c9251fbbdcb95848564325feabf925b990 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Wed, 19 Sep 2018 13:54:14 +0200 Subject: [PATCH 39/43] sample_ota.conf --- src/sample_ota.conf | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/sample_ota.conf diff --git a/src/sample_ota.conf b/src/sample_ota.conf new file mode 100644 index 000000000..a10d79dc5 --- /dev/null +++ b/src/sample_ota.conf @@ -0,0 +1,8 @@ +[ota] +OTA_WIFI_SSID = MyHomeWifi +OTA_WIFI_PASS = FooBar42! + +[bintray] +BINTRAY_USER = MyBintrayUser +BINTRAY_REPO = MyBintrayRepo +BINTRAY_API_TOKEN = 3894a7a51d70c6523c1b7479261c34845ebf7878 \ No newline at end of file From adef8fc9ce353ebf925ebb903832ea0b8d0a3bc2 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Wed, 19 Sep 2018 13:54:51 +0200 Subject: [PATCH 40/43] ota.sample.conf --- src/{sample_ota.conf => ota.sample.conf} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{sample_ota.conf => ota.sample.conf} (100%) diff --git a/src/sample_ota.conf b/src/ota.sample.conf similarity index 100% rename from src/sample_ota.conf rename to src/ota.sample.conf From e5a4ada7d5cc022ff2112c5aa0416270c22a86df Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Wed, 19 Sep 2018 13:59:34 +0200 Subject: [PATCH 41/43] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index dfa9eafed..99e7cac94 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,8 @@ Before compiling the code, - **create file loraconf.h in your local /src directory** using the template [loraconf.sample.h](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/loraconf.sample.h) and populate it with your personal APPEUI und APPKEY for the LoRaWAN network. If you're using popular TheThingsNetwork you can copy&paste the keys from TTN console or output of ttnctl. +- **create file ota.conf in your local /src directory** using the template [ota.sample.conf](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/ota.sample.conf). Enter your WIFI network&key and your Bintray user account data in this file. If you do not want to use wireless firmware updates you don't need to touch the contents of the file, just rename ota.sample.conf to ota.conf. + To join the network only method OTAA is supported, not ABP. The DEVEUI for OTAA will be derived from the device's MAC adress during device startup and is shown as well on the device's display (if it has one) as on the serial console for copying it to your LoRaWAN network server settings. If your device has a fixed DEVEUI enter this in your local loraconf.h file. During compile time this DEVEUI will be grabbed from loraconf.h and inserted in the code. From 972cac75f16449ee4ac7d442b5342389e595c120 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Wed, 19 Sep 2018 14:20:52 +0200 Subject: [PATCH 42/43] build.py: errorhandling improved --- build.py | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/build.py b/build.py index f0fdc73ea..ed222a04a 100644 --- a/build.py +++ b/build.py @@ -1,37 +1,54 @@ # build.py # pre-build script, setting up build environment +import sys +import os +import os.path import requests from os.path import basename from platformio import util Import("env") -# get keyfile from platformio.ini and parse it +# get platformio environment variables project_config = util.load_project_config() + +# check if file loraconf.h is present in source directory +keyfile = str(env.get("PROJECTSRC_DIR")) + "/loraconf.h" +if os.path.isfile(keyfile) and os.access(keyfile, os.R_OK): + print "Parsing LORAWAN keys from " + keyfile +else: + sys.exit("Missing file loraconf.h, please create it using template loraconf.sample.h! Aborting.") + +# check if file ota.conf is present in source directory keyfile = str(env.get("PROJECTSRC_DIR")) + "/" + project_config.get("common", "keyfile") -print "Parsing OTA keys from " + keyfile +if os.path.isfile(keyfile) and os.access(keyfile, os.R_OK): + print "Parsing OTA keys from " + keyfile +else: + sys.exit("Missing file ota.conf, please create it using template ota.sample.conf! Aborting.") + +# parse file ota.conf mykeys = {} with open(keyfile) as myfile: for line in myfile: key, value = line.partition("=")[::2] mykeys[key.strip()] = str(value).strip() -# get bintray credentials from keyfile +# get bintray user credentials user = mykeys["BINTRAY_USER"] repository = mykeys["BINTRAY_REPO"] apitoken = mykeys["BINTRAY_API_TOKEN"] -# get bintray parameters from platformio.ini +# get bintray upload parameters version = project_config.get("common", "release_version") package = str(env.get("PIOENV")) -# put bintray credentials to platformio environment +# put bintray user credentials to platformio environment env.Replace(BINTRAY_USER=user) env.Replace(BINTRAY_REPO=repository) env.Replace(BINTRAY_API_TOKEN=apitoken) -# get runtime credentials from keyfile and put them to compiler directive +# get runtime credentials and put them to compiler directive env.Replace(CPPDEFINES=[ ('WIFI_SSID', '\\"' + mykeys["OTA_WIFI_SSID"] + '\\"'), ('WIFI_PASS', '\\"' + mykeys["OTA_WIFI_PASS"] + '\\"'), From 939d4b6a3b848876de761c3413384d6aa8165b16 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Wed, 19 Sep 2018 16:33:56 +0200 Subject: [PATCH 43/43] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 99e7cac94..2bcd48512 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ This can all be done with a single small and cheap ESP32 board for less than $20 - WeMos: LoLin32 + [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora), LoLin32lite + [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora) -*SPI only*: (coming soon) +*SPI only*: (code yet to come) - Pyom: WiPy - WeMos: LoLin32, LoLin32 Lite, WeMos D32 @@ -47,7 +47,7 @@ Depending on board hardware following features are supported: - GPS Target platform must be selected in [platformio.ini](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/platformio.ini).
-Hardware dependent settings (pinout etc.) are stored in board files in /hal directory.
+Hardware dependent settings (pinout etc.) are stored in board files in /hal directory. If you want to use a ESP32 board which is not yet supported, use hal file generic.h and tailor pin mappings to your needs. Pull requests for new boards welcome.
3D printable cases can be found (and, if wanted so, ordered) on Thingiverse, see Heltec, TTGOv2, TTGOv2.1, T-BEAM for example.
@@ -62,7 +62,7 @@ Before compiling the code, - **create file loraconf.h in your local /src directory** using the template [loraconf.sample.h](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/loraconf.sample.h) and populate it with your personal APPEUI und APPKEY for the LoRaWAN network. If you're using popular TheThingsNetwork you can copy&paste the keys from TTN console or output of ttnctl. -- **create file ota.conf in your local /src directory** using the template [ota.sample.conf](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/ota.sample.conf). Enter your WIFI network&key and your Bintray user account data in this file. If you do not want to use wireless firmware updates you don't need to touch the contents of the file, just rename ota.sample.conf to ota.conf. +- **create file ota.conf in your local /src directory** using the template [ota.sample.conf](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/ota.sample.conf) and enter your WIFI network&key. These settings are used for downloading updates. If you want to push own OTA updates you need a Bintray account. Enter your Bintray user account data in ota.conf. If you don't need wireless firmware updates just rename ota.sample.conf to ota.conf. To join the network only method OTAA is supported, not ABP. The DEVEUI for OTAA will be derived from the device's MAC adress during device startup and is shown as well on the device's display (if it has one) as on the serial console for copying it to your LoRaWAN network server settings. @@ -83,7 +83,7 @@ The LoPy/LoPy4/FiPy board needs to be set manually. See these The original Pycom firmware is not needed, so there is no need to update it before flashing Paxcounter. Just flash the compiled paxcounter binary (.elf file) on your LoPy/LoPy4/FiPy. If you later want to go back to the Pycom firmware, download the firmware from Pycom and flash it over. - **During runtime, using FOTA via WIFI:** -After the ESP32 board is initially flashed and has joined a LoRaWAN network, the firmware can update itself by FOTA. This process is kicked off by sending a remote control command (see below) via LoRaWAN to the board. The board then tries to connect via WIFI to a cloud service (JFrog Bintray), checks for update, and if available downloads the binary and reboots with it. If something goes wrong during this process, the board reboots back to the current version. Prerequisites for FOTA are: 1. You own a Bintray repository (free), 2. you pushed the update binary to the Bintray repository, 3. internet access via encrypted (WPA2) WIFI is present at the board's site, 4. WIFI credentials were set in ota.conf and initially flashed to the board. Step 2 runs automated, just enter the credentials in ota.conf and set `upload_protocol = custom` in platformio.ini. Then press build and lean back watching platformio doing build and upload. +After the ESP32 board is initially flashed and has joined a LoRaWAN network, the firmware can update itself by FOTA. This process is kicked off by sending a remote control command (see below) via LoRaWAN to the board. The board then tries to connect via WIFI to a cloud service (JFrog Bintray), checks for update, and if available downloads the binary and reboots with it. If something goes wrong during this process, the board reboots back to the current version. Prerequisites for FOTA are: 1. You own a Bintray repository, 2. you pushed the update binary to the Bintray repository, 3. internet access via encrypted (WPA2) WIFI is present at the board's site, 4. WIFI credentials were set in ota.conf and initially flashed to the board. Step 2 runs automated, just enter the credentials in ota.conf and set `upload_protocol = custom` in platformio.ini. Then press build and lean back watching platformio doing build and upload. # Legal note