Merge branch 'ota-test' into development
This commit is contained in:
commit
8999c77579
24
lib/BintrayClient/library.json
Normal file
24
lib/BintrayClient/library.json
Normal file
@ -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"
|
||||||
|
}
|
102
lib/BintrayClient/src/BintrayCertificates.h
Normal file
102
lib/BintrayClient/src/BintrayCertificates.h
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef 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
|
149
lib/BintrayClient/src/BintrayClient.cpp
Normal file
149
lib/BintrayClient/src/BintrayClient.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Error: Could not parse JSON. Input data is too big!");
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
StaticJsonBuffer<bufferSize> jsonBuffer;
|
||||||
|
|
||||||
|
JsonObject &root = jsonBuffer.parseObject(jsonResult.c_str());
|
||||||
|
// Check for errors in parsing
|
||||||
|
if (!root.success())
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Error: Could not parse JSON!");
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
return root.get<String>("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)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Error: Could parse JSON. Input data is too big!");
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
StaticJsonBuffer<bufferSize> jsonBuffer;
|
||||||
|
|
||||||
|
JsonArray &root = jsonBuffer.parseArray(jsonResult.c_str());
|
||||||
|
JsonObject &firstItem = root[0];
|
||||||
|
if (!root.success())
|
||||||
|
{ //Check for errors in parsing
|
||||||
|
ESP_LOGI(TAG, "Error: Could not parse JSON!");
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
return "/" + getUser() + "/" + getRepository() + "/" + firstItem.get<String>("path");
|
||||||
|
}
|
49
lib/BintrayClient/src/BintrayClient.h
Normal file
49
lib/BintrayClient/src/BintrayClient.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef BINTRAY_CLIENT_H
|
||||||
|
#define BINTRAY_CLIENT_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
#include <WString.h>
|
||||||
|
|
||||||
|
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<std::pair<String, const char*>> m_certificates;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BINTRAY_CLIENT_H
|
@ -11,12 +11,12 @@
|
|||||||
|
|
||||||
; ---> SELECT TARGET PLATFORM HERE! <---
|
; ---> SELECT TARGET PLATFORM HERE! <---
|
||||||
[platformio]
|
[platformio]
|
||||||
env_default = generic
|
;env_default = generic
|
||||||
;env_default = ebox
|
;env_default = ebox
|
||||||
;env_default = heltec
|
;env_default = heltec
|
||||||
;env_default = ttgov1
|
;env_default = ttgov1
|
||||||
;env_default = ttgov2
|
;env_default = ttgov2
|
||||||
;env_default = ttgov21
|
env_default = ttgov21
|
||||||
;env_default = ttgobeam
|
;env_default = ttgobeam
|
||||||
;env_default = lopy
|
;env_default = lopy
|
||||||
;env_default = lopy4
|
;env_default = lopy4
|
||||||
@ -27,11 +27,55 @@ 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.
|
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 = ***
|
||||||
|
|
||||||
|
[wifi]
|
||||||
|
ssid = ***
|
||||||
|
password = ***
|
||||||
|
|
||||||
|
[common]
|
||||||
|
platform = https://github.com/platformio/platform-espressif32.git
|
||||||
|
|
||||||
|
; firmware version, please modify it between releases
|
||||||
|
; positive integer value
|
||||||
|
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]
|
[common_env_data]
|
||||||
platform_espressif32 = espressif32@1.3.0
|
platform_espressif32 = espressif32@1.3.0
|
||||||
;platform_espressif32 = https://github.com/platformio/platform-espressif32.git#feature/stage
|
;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_all =
|
||||||
|
ArduinoJson
|
||||||
lib_deps_display =
|
lib_deps_display =
|
||||||
U8g2@>=2.23.16
|
U8g2@>=2.23.16
|
||||||
lib_deps_rgbled =
|
lib_deps_rgbled =
|
||||||
@ -40,22 +84,6 @@ lib_deps_gps =
|
|||||||
TinyGPSPlus@>=1.0.2
|
TinyGPSPlus@>=1.0.2
|
||||||
Time@>=1.5
|
Time@>=1.5
|
||||||
build_flags =
|
build_flags =
|
||||||
; ---> 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
|
|
||||||
;
|
|
||||||
; override lora settings from LMiC library in lmic/config.h and use main.h instead
|
; override lora settings from LMiC library in lmic/config.h and use main.h instead
|
||||||
-D_lmic_config_h_
|
-D_lmic_config_h_
|
||||||
-include "src/paxcounter.conf"
|
-include "src/paxcounter.conf"
|
||||||
@ -124,6 +152,7 @@ lib_deps =
|
|||||||
${common_env_data.lib_deps_all}
|
${common_env_data.lib_deps_all}
|
||||||
${common_env_data.lib_deps_display}
|
${common_env_data.lib_deps_display}
|
||||||
build_flags =
|
build_flags =
|
||||||
|
${common.build_flags}
|
||||||
${common_env_data.build_flags}
|
${common_env_data.build_flags}
|
||||||
|
|
||||||
[env:ttgobeam]
|
[env:ttgobeam]
|
||||||
|
79
src/OTA.cpp
Normal file
79
src/OTA.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
// 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_config_t sta_cfg;
|
||||||
|
sta_cfg.sta = cfg;
|
||||||
|
|
||||||
|
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() {
|
||||||
|
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();
|
||||||
|
delay(2000);
|
||||||
|
delay(2000);
|
||||||
|
checkFirmwareUpdates();
|
||||||
|
ESP.restart(); // reached if update was not successful
|
||||||
|
}
|
13
src/OTA.h
Normal file
13
src/OTA.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef OTA_H
|
||||||
|
#define OTA_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "globals.h"
|
||||||
|
#include <BintrayClient.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include "ota.h"
|
||||||
|
#include "SecureOTA.h"
|
||||||
|
|
||||||
|
void start_ota_update();
|
||||||
|
|
||||||
|
#endif // OTA_H
|
225
src/SecureOTA.cpp
Normal file
225
src/SecureOTA.cpp
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
#include <Update.h>
|
||||||
|
#include <BintrayClient.h>
|
||||||
|
#include "SecureOTA.h"
|
||||||
|
|
||||||
|
const BintrayClient bintray(BINTRAY_USER, BINTRAY_REPO, BINTRAY_PACKAGE);
|
||||||
|
|
||||||
|
// Connection port (HTTPS)
|
||||||
|
const int port = 443;
|
||||||
|
|
||||||
|
// Connection timeout
|
||||||
|
const uint32_t RESPONSE_TIMEOUT_MS = 5000;
|
||||||
|
|
||||||
|
// Variables to validate firmware content
|
||||||
|
volatile int contentLength = 0;
|
||||||
|
volatile bool isValidContentType = false;
|
||||||
|
|
||||||
|
void checkFirmwareUpdates()
|
||||||
|
{
|
||||||
|
// Fetch the latest firmware version
|
||||||
|
const String latest = bintray.getLatestVersion();
|
||||||
|
if (latest.length() == 0)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Could not load info about the latest firmware, so nothing to update. Continue ...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (atoi(latest.c_str()) <= VERSION)
|
||||||
|
{
|
||||||
|
//ESP_LOGI(TAG, "The current firmware is up to date. Continue ...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "There is a new version of firmware available: v.%s", latest);
|
||||||
|
processOTAUpdate(latest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A helper function to extract header value from header
|
||||||
|
inline String getHeaderValue(String header, String headerName)
|
||||||
|
{
|
||||||
|
return header.substring(strlen(headerName.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OTA update processing
|
||||||
|
*/
|
||||||
|
void processOTAUpdate(const String &version)
|
||||||
|
{
|
||||||
|
String firmwarePath = bintray.getBinaryPath(version);
|
||||||
|
if (!firmwarePath.endsWith(".bin"))
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Unsupported binary format. OTA update cannot be performed!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String currentHost = bintray.getStorageHost();
|
||||||
|
String prevHost = currentHost;
|
||||||
|
|
||||||
|
WiFiClientSecure client;
|
||||||
|
client.setCACert(bintray.getCertificate(currentHost));
|
||||||
|
|
||||||
|
if (!client.connect(currentHost.c_str(), port))
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Cannot connect to %s", currentHost);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool redirect = true;
|
||||||
|
while (redirect)
|
||||||
|
{
|
||||||
|
if (currentHost != prevHost)
|
||||||
|
{
|
||||||
|
client.stop();
|
||||||
|
client.setCACert(bintray.getCertificate(currentHost));
|
||||||
|
if (!client.connect(currentHost.c_str(), port))
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Redirect detected! Cannot connect to %s for some reason!", currentHost);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//ESP_LOGI(TAG, "Requesting: " + firmwarePath);
|
||||||
|
|
||||||
|
client.print(String("GET ") + firmwarePath + " HTTP/1.1\r\n");
|
||||||
|
client.print(String("Host: ") + currentHost + "\r\n");
|
||||||
|
client.print("Cache-Control: no-cache\r\n");
|
||||||
|
client.print("Connection: close\r\n\r\n");
|
||||||
|
|
||||||
|
unsigned long timeout = millis();
|
||||||
|
while (client.available() == 0)
|
||||||
|
{
|
||||||
|
if (millis() - timeout > RESPONSE_TIMEOUT_MS)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Client Timeout !");
|
||||||
|
client.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (client.available())
|
||||||
|
{
|
||||||
|
String line = client.readStringUntil('\n');
|
||||||
|
// Check if the line is end of headers by removing space symbol
|
||||||
|
line.trim();
|
||||||
|
// if the the line is empty, this is the end of the headers
|
||||||
|
if (!line.length())
|
||||||
|
{
|
||||||
|
break; // proceed to OTA update
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check allowed HTTP responses
|
||||||
|
if (line.startsWith("HTTP/1.1"))
|
||||||
|
{
|
||||||
|
if (line.indexOf("200") > 0)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Got 200 status code from server. Proceeding to firmware flashing");
|
||||||
|
redirect = false;
|
||||||
|
}
|
||||||
|
else if (line.indexOf("302") > 0)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Got 302 status code from server. Redirecting to the new address");
|
||||||
|
redirect = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Could not get a valid firmware url");
|
||||||
|
//Unexptected HTTP response. Retry or skip update?
|
||||||
|
redirect = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extracting new redirect location
|
||||||
|
if (line.startsWith("Location: "))
|
||||||
|
{
|
||||||
|
String newUrl = getHeaderValue(line, "Location: ");
|
||||||
|
ESP_LOGI(TAG, "Got new url: %s", newUrl);
|
||||||
|
newUrl.remove(0, newUrl.indexOf("//") + 2);
|
||||||
|
currentHost = newUrl.substring(0, newUrl.indexOf('/'));
|
||||||
|
newUrl.remove(newUrl.indexOf(currentHost), currentHost.length());
|
||||||
|
firmwarePath = newUrl;
|
||||||
|
ESP_LOGI(TAG, "firmwarePath: %s", firmwarePath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checking headers
|
||||||
|
if (line.startsWith("Content-Length: "))
|
||||||
|
{
|
||||||
|
contentLength = atoi((getHeaderValue(line, "Content-Length: ")).c_str());
|
||||||
|
ESP_LOGI(TAG, "Got %s bytes from server", String(contentLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.startsWith("Content-Type: "))
|
||||||
|
{
|
||||||
|
String contentType = getHeaderValue(line, "Content-Type: ");
|
||||||
|
ESP_LOGI(TAG, "Got %s payload", contentType);
|
||||||
|
if (contentType == "application/octet-stream")
|
||||||
|
{
|
||||||
|
isValidContentType = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check whether we have everything for OTA update
|
||||||
|
if (contentLength && isValidContentType)
|
||||||
|
{
|
||||||
|
if (Update.begin(contentLength))
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Starting Over-The-Air update. This may take some time to complete ...");
|
||||||
|
size_t written = Update.writeStream(client);
|
||||||
|
|
||||||
|
if (written == contentLength)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Written %s successfully", String(written));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Written only %s / %s Retry?", String(written), String(contentLength));
|
||||||
|
// Retry??
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Update.end())
|
||||||
|
{
|
||||||
|
if (Update.isFinished())
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "OTA update has successfully completed. Rebooting ...");
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Something went wrong! OTA update hasn't been finished properly.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "An error occurred. Error #: %s", String(Update.getError()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "There isn't enough space to start OTA update");
|
||||||
|
client.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "There was no valid content in the response from the OTA server!");
|
||||||
|
client.flush();
|
||||||
|
}
|
||||||
|
}
|
25
src/SecureOTA.h
Normal file
25
src/SecureOTA.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef SECURE_OTA_H
|
||||||
|
#define SECURE_OTA_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
void checkFirmwareUpdates();
|
||||||
|
void processOTAUpdate(const String &version);
|
||||||
|
|
||||||
|
#endif // SECURE_OTA_H
|
@ -21,7 +21,6 @@ function Decoder(bytes, port) {
|
|||||||
return decode(bytes, [uint16, uptime, uint8, uint32], ['voltage', 'uptime', 'cputemp', 'memory']);
|
return decode(bytes, [uint16, uptime, uint8, uint32], ['voltage', 'uptime', 'cputemp', 'memory']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (port === 3) {
|
if (port === 3) {
|
||||||
// device config data
|
// 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], ['lorasf', 'txpower', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags']);
|
||||||
@ -181,6 +180,7 @@ if (typeof module === 'object' && typeof module.exports !== 'undefined') {
|
|||||||
uint16: uint16,
|
uint16: uint16,
|
||||||
uint32: uint32,
|
uint32: uint32,
|
||||||
uptime: uptime,
|
uptime: uptime,
|
||||||
|
reset: reset,
|
||||||
temperature: temperature,
|
temperature: temperature,
|
||||||
humidity: humidity,
|
humidity: humidity,
|
||||||
latLng: latLng,
|
latLng: latLng,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
// Basic config
|
// Basic config
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "senddata.h"
|
#include "senddata.h"
|
||||||
|
#include "ota.h"
|
||||||
|
|
||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char TAG[] = "main";
|
static const char TAG[] = "main";
|
||||||
@ -14,6 +15,9 @@ void doHomework() {
|
|||||||
// update uptime counter
|
// update uptime counter
|
||||||
uptime();
|
uptime();
|
||||||
|
|
||||||
|
if (ota_update)
|
||||||
|
start_ota_update();
|
||||||
|
|
||||||
// read battery voltage into global variable
|
// read battery voltage into global variable
|
||||||
#ifdef HAS_BATTERY_PROBE
|
#ifdef HAS_BATTERY_PROBE
|
||||||
batt_voltage = read_voltage();
|
batt_voltage = read_voltage();
|
||||||
|
@ -43,6 +43,7 @@ typedef struct {
|
|||||||
|
|
||||||
// global variables
|
// 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 char display_line6[], display_line7[]; // screen buffers
|
||||||
extern uint8_t channel; // wifi channel rotation counter
|
extern uint8_t channel; // wifi channel rotation counter
|
||||||
extern uint16_t macs_total, macs_wifi, macs_ble, batt_voltage; // display values
|
extern uint16_t macs_total, macs_wifi, macs_ble, batt_voltage; // display values
|
||||||
@ -51,7 +52,8 @@ extern hw_timer_t *channelSwitch, *sendCycle;
|
|||||||
extern portMUX_TYPE timerMux;
|
extern portMUX_TYPE timerMux;
|
||||||
extern volatile int SendCycleTimerIRQ, HomeCycleIRQ, DisplayTimerIRQ,
|
extern volatile int SendCycleTimerIRQ, HomeCycleIRQ, DisplayTimerIRQ,
|
||||||
ChannelTimerIRQ, ButtonPressedIRQ;
|
ChannelTimerIRQ, ButtonPressedIRQ;
|
||||||
extern QueueHandle_t LoraSendQueue, SPISendQueue;
|
// extern QueueHandle_t LoraSendQueue, SPISendQueue;
|
||||||
|
extern TaskHandle_t WifiLoopTask;
|
||||||
|
|
||||||
extern std::array<uint64_t, 0xff>::iterator it;
|
extern std::array<uint64_t, 0xff>::iterator it;
|
||||||
extern std::array<uint64_t, 0xff> beacons;
|
extern std::array<uint64_t, 0xff> beacons;
|
||||||
@ -67,9 +69,15 @@ extern std::array<uint64_t, 0xff> beacons;
|
|||||||
#include "payload.h"
|
#include "payload.h"
|
||||||
|
|
||||||
#ifdef HAS_LORA
|
#ifdef HAS_LORA
|
||||||
|
extern QueueHandle_t LoraSendQueue;
|
||||||
|
extern TaskHandle_t LoraTask;
|
||||||
#include "lorawan.h"
|
#include "lorawan.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_SPI
|
||||||
|
extern QueueHandle_t SPISendQueue;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_DISPLAY
|
#ifdef HAS_DISPLAY
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#endif
|
#endif
|
||||||
|
14
src/main.cpp
14
src/main.cpp
@ -28,6 +28,7 @@ licenses. Refer to LICENSE.txt file in repository for more details.
|
|||||||
#include "main.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
|
char display_line6[16], display_line7[16]; // display buffers
|
||||||
uint8_t channel = 0; // channel rotation counter
|
uint8_t channel = 0; // channel rotation counter
|
||||||
uint16_t macs_total = 0, macs_wifi = 0, macs_ble = 0,
|
uint16_t macs_total = 0, macs_wifi = 0, macs_ble = 0,
|
||||||
@ -41,9 +42,12 @@ hw_timer_t *channelSwitch = NULL, *displaytimer = NULL, *sendCycle = NULL,
|
|||||||
volatile int ButtonPressedIRQ = 0, ChannelTimerIRQ = 0, SendCycleTimerIRQ = 0,
|
volatile int ButtonPressedIRQ = 0, ChannelTimerIRQ = 0, SendCycleTimerIRQ = 0,
|
||||||
DisplayTimerIRQ = 0, HomeCycleIRQ = 0;
|
DisplayTimerIRQ = 0, HomeCycleIRQ = 0;
|
||||||
|
|
||||||
|
TaskHandle_t WifiLoopTask = NULL;
|
||||||
|
|
||||||
// RTos send queues for payload transmit
|
// RTos send queues for payload transmit
|
||||||
#ifdef HAS_LORA
|
#ifdef HAS_LORA
|
||||||
QueueHandle_t LoraSendQueue;
|
QueueHandle_t LoraSendQueue;
|
||||||
|
TaskHandle_t LoraTask = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_SPI
|
#ifdef HAS_SPI
|
||||||
@ -67,6 +71,9 @@ static const char TAG[] = "main";
|
|||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
|
|
||||||
|
// disable the default wifi logging
|
||||||
|
esp_log_level_set("wifi", ESP_LOG_NONE);
|
||||||
|
|
||||||
char features[100] = "";
|
char features[100] = "";
|
||||||
|
|
||||||
// disable brownout detection
|
// disable brownout detection
|
||||||
@ -89,7 +96,8 @@ void setup() {
|
|||||||
|
|
||||||
// initialize system event handler for wifi task, needed for
|
// initialize system event handler for wifi task, needed for
|
||||||
// wifi_sniffer_init()
|
// 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
|
// print chip information on startup if in verbose mode
|
||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
@ -269,7 +277,7 @@ void setup() {
|
|||||||
|
|
||||||
ESP_LOGI(TAG, "Starting Lora task on core 1");
|
ESP_LOGI(TAG, "Starting Lora task on core 1");
|
||||||
xTaskCreatePinnedToCore(lorawan_loop, "loraloop", 2048, (void *)1,
|
xTaskCreatePinnedToCore(lorawan_loop, "loraloop", 2048, (void *)1,
|
||||||
(5 | portPRIVILEGE_BIT), NULL, 1);
|
(5 | portPRIVILEGE_BIT), &LoraTask, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// if device has GPS and it is enabled, start GPS reader task on core 0 with
|
// if device has GPS and it is enabled, start GPS reader task on core 0 with
|
||||||
@ -298,7 +306,7 @@ void setup() {
|
|||||||
// gets it's seed from RF noise
|
// gets it's seed from RF noise
|
||||||
reset_salt(); // get new 16bit for salting hashes
|
reset_salt(); // get new 16bit for salting hashes
|
||||||
xTaskCreatePinnedToCore(wifi_channel_loop, "wifiloop", 2048, (void *)1, 1,
|
xTaskCreatePinnedToCore(wifi_channel_loop, "wifiloop", 2048, (void *)1, 1,
|
||||||
NULL, 0);
|
&WifiLoopTask, 0);
|
||||||
} // setup()
|
} // setup()
|
||||||
|
|
||||||
/* end Arduino SETUP
|
/* end Arduino SETUP
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
// Payload send cycle and encoding
|
// Payload send cycle and encoding
|
||||||
#define SEND_SECS 30 // payload send cycle [seconds/2] -> 60 sec.
|
#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
|
// Set this to include BLE counting and vendor filter functions
|
||||||
#define VENDORFILTER 1 // comment out if you want to count things, not people
|
#define VENDORFILTER 1 // comment out if you want to count things, not people
|
||||||
|
@ -54,6 +54,7 @@ void PayloadConvert::addConfig(configData_t value) {
|
|||||||
|
|
||||||
void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime,
|
void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime,
|
||||||
float cputemp, uint32_t mem) {
|
float cputemp, uint32_t mem) {
|
||||||
|
|
||||||
buffer[cursor++] = highByte(voltage);
|
buffer[cursor++] = highByte(voltage);
|
||||||
buffer[cursor++] = lowByte(voltage);
|
buffer[cursor++] = lowByte(voltage);
|
||||||
buffer[cursor++] = (byte)((uptime & 0xFF00000000000000) >> 56);
|
buffer[cursor++] = (byte)((uptime & 0xFF00000000000000) >> 56);
|
||||||
@ -69,6 +70,8 @@ void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime,
|
|||||||
buffer[cursor++] = (byte)((mem & 0x00FF0000) >> 16);
|
buffer[cursor++] = (byte)((mem & 0x00FF0000) >> 16);
|
||||||
buffer[cursor++] = (byte)((mem & 0x0000FF00) >> 8);
|
buffer[cursor++] = (byte)((mem & 0x0000FF00) >> 8);
|
||||||
buffer[cursor++] = (byte)((mem & 0x000000FF));
|
buffer[cursor++] = (byte)((mem & 0x000000FF));
|
||||||
|
buffer[cursor++] = (byte)(reset1);
|
||||||
|
buffer[cursor++] = (byte)(reset2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_GPS
|
#ifdef HAS_GPS
|
||||||
@ -123,12 +126,14 @@ void PayloadConvert::addConfig(configData_t value) {
|
|||||||
value.vendorfilter ? true : false, value.gpsmode ? true : false);
|
value.vendorfilter ? true : false, value.gpsmode ? true : false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime,
|
void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, float cputemp,
|
||||||
float cputemp, uint32_t mem) {
|
uint32_t mem, uint8_t reset1, uint8_t reset2) {
|
||||||
writeUint16(voltage);
|
writeUint16(voltage);
|
||||||
writeUptime(uptime);
|
writeUptime(uptime);
|
||||||
writeUint8((byte)cputemp);
|
writeUint8((byte)cputemp);
|
||||||
writeUint32(mem);
|
writeUint32(mem);
|
||||||
|
writeUint8(reset1);
|
||||||
|
writeUint8(reset2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_GPS
|
#ifdef HAS_GPS
|
||||||
@ -241,8 +246,8 @@ void PayloadConvert::addConfig(configData_t value) {
|
|||||||
buffer[cursor++] = value.adrmode;
|
buffer[cursor++] = value.adrmode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime,
|
void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, float celsius,
|
||||||
float celsius, uint32_t mem) {
|
uint32_t mem, uint8_t reset1, uint8_t reset2) {
|
||||||
uint16_t temp = celsius * 10;
|
uint16_t temp = celsius * 10;
|
||||||
uint16_t volt = voltage / 10;
|
uint16_t volt = voltage / 10;
|
||||||
#ifdef HAS_BATTERY_PROBE
|
#ifdef HAS_BATTERY_PROBE
|
||||||
|
@ -35,7 +35,8 @@ public:
|
|||||||
uint8_t *getBuffer(void);
|
uint8_t *getBuffer(void);
|
||||||
void addCount(uint16_t value1, uint16_t value2);
|
void addCount(uint16_t value1, uint16_t value2);
|
||||||
void addConfig(configData_t value);
|
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);
|
void addAlarm(int8_t rssi, uint8_t message);
|
||||||
#ifdef HAS_GPS
|
#ifdef HAS_GPS
|
||||||
void addGPS(gpsStatus_t value);
|
void addGPS(gpsStatus_t value);
|
||||||
@ -44,7 +45,6 @@ public:
|
|||||||
void addButton(uint8_t value);
|
void addButton(uint8_t value);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if PAYLOAD_ENCODER == 1 // format plain
|
#if PAYLOAD_ENCODER == 1 // format plain
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -77,7 +77,6 @@ private:
|
|||||||
#else
|
#else
|
||||||
#error "No valid payload converter defined"
|
#error "No valid payload converter defined"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern PayloadConvert payload;
|
extern PayloadConvert payload;
|
||||||
|
@ -203,7 +203,8 @@ void get_status(uint8_t val[]) {
|
|||||||
#endif
|
#endif
|
||||||
payload.reset();
|
payload.reset();
|
||||||
payload.addStatus(voltage, uptime() / 1000, temperatureRead(),
|
payload.addStatus(voltage, uptime() / 1000, temperatureRead(),
|
||||||
ESP.getFreeHeap());
|
ESP.getFreeHeap(), rtc_get_reset_reason(0),
|
||||||
|
rtc_get_reset_reason(1));
|
||||||
SendData(STATUSPORT);
|
SendData(STATUSPORT);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -219,6 +220,11 @@ void get_gps(uint8_t val[]) {
|
|||||||
#endif
|
#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
|
// assign previously defined functions to set of numeric remote commands
|
||||||
// format: opcode, function, #bytes params,
|
// format: opcode, function, #bytes params,
|
||||||
// flag (1 = do make settings persistent / 0 = don't)
|
// flag (1 = do make settings persistent / 0 = don't)
|
||||||
@ -233,8 +239,8 @@ cmd_t table[] = {
|
|||||||
{0x0d, set_vendorfilter, 1, false}, {0x0e, set_blescan, 1, true},
|
{0x0d, set_vendorfilter, 1, false}, {0x0e, set_blescan, 1, true},
|
||||||
{0x0f, set_wifiant, 1, true}, {0x10, set_rgblum, 1, true},
|
{0x0f, set_wifiant, 1, true}, {0x10, set_rgblum, 1, true},
|
||||||
{0x11, set_monitor, 1, true}, {0x12, set_beacon, 7, false},
|
{0x11, set_monitor, 1, true}, {0x12, set_beacon, 7, false},
|
||||||
{0x80, get_config, 0, false}, {0x81, get_status, 0, false},
|
{0x20, set_update, 0, false}, {0x80, get_config, 0, false},
|
||||||
{0x84, get_gps, 0, false}};
|
{0x81, get_status, 0, false}, {0x84, get_gps, 0, false}};
|
||||||
|
|
||||||
const uint8_t cmdtablesize =
|
const uint8_t cmdtablesize =
|
||||||
sizeof(table) / sizeof(table[0]); // number of commands in command table
|
sizeof(table) / sizeof(table[0]); // number of commands in command table
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "configmanager.h"
|
#include "configmanager.h"
|
||||||
#include "lorawan.h"
|
#include "lorawan.h"
|
||||||
#include "macsniff.h"
|
#include "macsniff.h"
|
||||||
|
#include <rom/rtc.h>
|
||||||
|
|
||||||
// table of remote commands and assigned functions
|
// table of remote commands and assigned functions
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
static const char TAG[] = "wifi";
|
static const char TAG[] = "wifi";
|
||||||
|
|
||||||
static wifi_country_t wifi_country = {WIFI_MY_COUNTRY, WIFI_CHANNEL_MIN,
|
static wifi_country_t wifi_country = {WIFI_MY_COUNTRY, WIFI_CHANNEL_MIN,
|
||||||
WIFI_CHANNEL_MAX, 0,
|
WIFI_CHANNEL_MAX, 100,
|
||||||
WIFI_COUNTRY_POLICY_MANUAL};
|
WIFI_COUNTRY_POLICY_MANUAL};
|
||||||
|
|
||||||
// using IRAM_:ATTR here to speed up callback function
|
// using IRAM_:ATTR here to speed up callback function
|
||||||
@ -36,6 +36,7 @@ void wifi_sniffer_init(void) {
|
|||||||
ESP_ERROR_CHECK(
|
ESP_ERROR_CHECK(
|
||||||
esp_wifi_set_storage(WIFI_STORAGE_RAM)); // we don't need NVRAM
|
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_set_mode(WIFI_MODE_NULL));
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_stop());
|
||||||
ESP_ERROR_CHECK(
|
ESP_ERROR_CHECK(
|
||||||
esp_wifi_set_promiscuous_filter(&filter)); // set MAC frame filter
|
esp_wifi_set_promiscuous_filter(&filter)); // set MAC frame filter
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(&wifi_sniffer_packet_handler));
|
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(&wifi_sniffer_packet_handler));
|
||||||
|
Loading…
Reference in New Issue
Block a user