mirror of
https://github.com/IoTManagerProject/IoTManager.git
synced 2026-03-26 22:22:16 +03:00
240 lines
8.4 KiB
C++
240 lines
8.4 KiB
C++
|
|
//
|
||
|
|
//
|
||
|
|
//
|
||
|
|
|
||
|
|
#include "WifiLocation.h"
|
||
|
|
#include "time.h"
|
||
|
|
|
||
|
|
const char* googleApisHost = "www.googleapis.com";
|
||
|
|
const char* googleApiUrl = "/geolocation/v1/geolocate";
|
||
|
|
|
||
|
|
// GlobalSign CA certificate valid until 15th december 2021
|
||
|
|
#if defined ARDUINO_ARCH_ESP32 || defined ARDUINO_ARCH_ESP8266
|
||
|
|
static const char GlobalSignCA[] PROGMEM = R"EOF(
|
||
|
|
-----BEGIN CERTIFICATE-----
|
||
|
|
MIIESjCCAzKgAwIBAgINAeO0mqGNiqmBJWlQuDANBgkqhkiG9w0BAQsFADBMMSAw
|
||
|
|
HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFs
|
||
|
|
U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xNzA2MTUwMDAwNDJaFw0yMTEy
|
||
|
|
MTUwMDAwNDJaMEIxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVHb29nbGUgVHJ1c3Qg
|
||
|
|
U2VydmljZXMxEzARBgNVBAMTCkdUUyBDQSAxTzEwggEiMA0GCSqGSIb3DQEBAQUA
|
||
|
|
A4IBDwAwggEKAoIBAQDQGM9F1IvN05zkQO9+tN1pIRvJzzyOTHW5DzEZhD2ePCnv
|
||
|
|
UA0Qk28FgICfKqC9EksC4T2fWBYk/jCfC3R3VZMdS/dN4ZKCEPZRrAzDsiKUDzRr
|
||
|
|
mBBJ5wudgzndIMYcLe/RGGFl5yODIKgjEv/SJH/UL+dEaltN11BmsK+eQmMF++Ac
|
||
|
|
xGNhr59qM/9il71I2dN8FGfcddwuaej4bXhp0LcQBbjxMcI7JP0aM3T4I+DsaxmK
|
||
|
|
FsbjzaTNC9uzpFlgOIg7rR25xoynUxv8vNmkq7zdPGHXkxWY7oG9j+JkRyBABk7X
|
||
|
|
rJfoucBZEqFJJSPk7XA0LKW0Y3z5oz2D0c1tJKwHAgMBAAGjggEzMIIBLzAOBgNV
|
||
|
|
HQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1Ud
|
||
|
|
EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJjR+G4Q68+b7GCfGJAboOt9Cf0rMB8G
|
||
|
|
A1UdIwQYMBaAFJviB1dnHB7AagbeWbSaLd/cGYYuMDUGCCsGAQUFBwEBBCkwJzAl
|
||
|
|
BggrBgEFBQcwAYYZaHR0cDovL29jc3AucGtpLmdvb2cvZ3NyMjAyBgNVHR8EKzAp
|
||
|
|
MCegJaAjhiFodHRwOi8vY3JsLnBraS5nb29nL2dzcjIvZ3NyMi5jcmwwPwYDVR0g
|
||
|
|
BDgwNjA0BgZngQwBAgIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly9wa2kuZ29vZy9y
|
||
|
|
ZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAGoA+Nnn78y6pRjd9XlQWNa7H
|
||
|
|
TgiZ/r3RNGkmUmYHPQq6Scti9PEajvwRT2iWTHQr02fesqOqBY2ETUwgZQ+lltoN
|
||
|
|
FvhsO9tvBCOIazpswWC9aJ9xju4tWDQH8NVU6YZZ/XteDSGU9YzJqPjY8q3MDxrz
|
||
|
|
mqepBCf5o8mw/wJ4a2G6xzUr6Fb6T8McDO22PLRL6u3M4Tzs3A2M1j6bykJYi8wW
|
||
|
|
IRdAvKLWZu/axBVbzYmqmwkm5zLSDW5nIAJbELCQCZwMH56t2Dvqofxs6BBcCFIZ
|
||
|
|
USpxu6x6td0V7SvJCCosirSmIatj/9dSSVDQibet8q/7UK4v4ZUN80atnZz1yg==
|
||
|
|
-----END CERTIFICATE-----
|
||
|
|
)EOF";
|
||
|
|
#endif
|
||
|
|
|
||
|
|
String WifiLocation::MACtoString(uint8_t* macAddress) {
|
||
|
|
uint8_t mac[6];
|
||
|
|
char macStr[18] = { 0 };
|
||
|
|
#ifdef ARDUINO_ARCH_SAMD
|
||
|
|
sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", macAddress[5], macAddress[4], macAddress[3], macAddress[2], macAddress[1], macAddress[0]);
|
||
|
|
#elif defined ARDUINO_ARCH_ESP8266 || defined ARDUINO_ARCH_ESP32
|
||
|
|
sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", macAddress[0], macAddress[1], macAddress[2], macAddress[3], macAddress[4], macAddress[5]);
|
||
|
|
#endif
|
||
|
|
return String(macStr);
|
||
|
|
}
|
||
|
|
|
||
|
|
WifiLocation::WifiLocation(String googleKey) {
|
||
|
|
_googleApiKey = googleKey;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Function to get a list of surrounding WiFi signals in JSON format to get location via Google Location API
|
||
|
|
String WifiLocation::getSurroundingWiFiJson() {
|
||
|
|
String wifiArray = "[\n";
|
||
|
|
|
||
|
|
int8_t numWifi = WiFi.scanNetworks();
|
||
|
|
if(numWifi > MAX_WIFI_SCAN) {
|
||
|
|
numWifi = MAX_WIFI_SCAN;
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.println(String(numWifi) + " WiFi networks found");
|
||
|
|
#endif // DEBUG_WIFI_LOCATION
|
||
|
|
for (uint8_t i = 0; i < numWifi; i++) {//numWifi; i++) {
|
||
|
|
//Serial.print("WiFi.BSSID(i) = ");
|
||
|
|
//Serial.println((char *)WiFi.BSSID(i));
|
||
|
|
#ifdef ARDUINO_ARCH_SAMD
|
||
|
|
byte bssid[6];
|
||
|
|
|
||
|
|
wifiArray += "{\"macAddress\":\"" + MACtoString(WiFi.BSSID(i,bssid)) + "\",";
|
||
|
|
#elif defined ARDUINO_ARCH_ESP8266 || defined ARDUINO_ARCH_ESP32
|
||
|
|
wifiArray += "{\"macAddress\":\"" + MACtoString(WiFi.BSSID(i)) + "\",";
|
||
|
|
#else
|
||
|
|
#error Only ESP8266 and SAMD platforms are supported
|
||
|
|
#endif
|
||
|
|
wifiArray += "\"signalStrength\":" + String(WiFi.RSSI(i)) + ",";
|
||
|
|
wifiArray += "\"channel\":" + String(WiFi.channel(i)) + "}";
|
||
|
|
if (i < (numWifi - 1)) {
|
||
|
|
wifiArray += ",\n";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#if defined ARDUINO_ARCH_ESP8266 || defined ARDUINO_ARCH_ESP32
|
||
|
|
WiFi.scanDelete();
|
||
|
|
#endif
|
||
|
|
wifiArray += "]";
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.println("WiFi list :\n" + wifiArray);
|
||
|
|
#endif // DEBUG_WIFI_LOCATION
|
||
|
|
return wifiArray;
|
||
|
|
}
|
||
|
|
|
||
|
|
#if defined ARDUINO_ARCH_ESP32 || defined ARDUINO_ARCH_ESP8266
|
||
|
|
// Set time via NTP, as required for x.509 validation
|
||
|
|
void setClock () {
|
||
|
|
configTime (3600, 0, "pool.ntp.org", "time.nist.gov");
|
||
|
|
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.print ("Waiting for NTP time sync: ");
|
||
|
|
#endif
|
||
|
|
time_t now = time (nullptr);
|
||
|
|
while (now < 8 * 3600 * 2) {
|
||
|
|
delay (500);
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.print (".");
|
||
|
|
#endif
|
||
|
|
now = time (nullptr);
|
||
|
|
}
|
||
|
|
struct tm timeinfo;
|
||
|
|
gmtime_r (&now, &timeinfo);
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.println ();
|
||
|
|
Serial.print ("Current time: ");
|
||
|
|
Serial.print (asctime (&timeinfo));
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
#endif //ARDUINO_ARCH_ESP32 || ARDUINO_ARCH_ESP8266
|
||
|
|
|
||
|
|
// Calls Google Location API to get current location using surrounding WiFi signals inf
|
||
|
|
location_t WifiLocation::getGeoFromWiFi() {
|
||
|
|
|
||
|
|
location_t location;
|
||
|
|
String response = "";
|
||
|
|
#if defined ARDUINO_ARCH_ESP8266 || defined ARDUINO_ARCH_ESP32
|
||
|
|
setClock ();
|
||
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
||
|
|
#if (defined BR_BEARSSL_H__ && not defined USE_CORE_PRE_2_5_0)
|
||
|
|
BearSSL::X509List cert (GlobalSignCA);
|
||
|
|
_client.setTrustAnchors (&cert);
|
||
|
|
#else
|
||
|
|
_client.setCACert (reinterpret_cast<const uint8_t*>(GlobalSignCA), sizeof (GlobalSignCA));
|
||
|
|
#endif
|
||
|
|
#endif // ARDUINO_ARCH_ESP8266
|
||
|
|
#endif
|
||
|
|
#ifdef ARDUINO_ARCH_ESP32
|
||
|
|
_client.setCACert(GlobalSignCA);
|
||
|
|
#endif
|
||
|
|
if (_client.connect(googleApisHost, 443)) {
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.println("Connected to API endpoint");
|
||
|
|
#endif // DEBUG_WIFI_LOCATION
|
||
|
|
} else {
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.println("HTTPS error");
|
||
|
|
#endif // DEBUG_WIFI_LOCATION
|
||
|
|
return location;
|
||
|
|
}
|
||
|
|
|
||
|
|
String body = "{\"wifiAccessPoints\":" + getSurroundingWiFiJson() + "}";
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.println("requesting URL: " + String(googleApiUrl) + "?key=" + _googleApiKey);
|
||
|
|
#endif // DEBUG_WIFI_LOCATION
|
||
|
|
String request = String("POST ") + String(googleApiUrl);
|
||
|
|
if (_googleApiKey != "")
|
||
|
|
request += "?key=" + _googleApiKey;
|
||
|
|
request += " HTTP/1.1\r\n";
|
||
|
|
request += "Host: " + String(googleApisHost) + "\r\n";
|
||
|
|
request += "User-Agent: ESP8266\r\n";
|
||
|
|
request += "Content-Type:application/json\r\n";
|
||
|
|
request += "Content-Length:" + String(body.length()) + "\r\n";
|
||
|
|
request += "Connection: close\r\n\r\n";
|
||
|
|
request += body;
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.println("request: \n" + request);
|
||
|
|
#endif // DEBUG_WIFI_LOCATION
|
||
|
|
|
||
|
|
_client.println(request);
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.println("request sent");
|
||
|
|
Serial.print("Free heap: ");
|
||
|
|
Serial.println(ESP.getFreeHeap());
|
||
|
|
#endif // DEBUG_WIFI_LOCATION
|
||
|
|
int timer = millis();
|
||
|
|
|
||
|
|
// Wait for response
|
||
|
|
while (millis() - timer < MAX_CONNECTION_TIMEOUT) {
|
||
|
|
if (_client.available())
|
||
|
|
break;
|
||
|
|
yield ();
|
||
|
|
}
|
||
|
|
while (_client.available()) {
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.print(".");
|
||
|
|
#endif // DEBUG_WIFI_LOCATION
|
||
|
|
response += _client.readString();
|
||
|
|
yield ();
|
||
|
|
}
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.println();
|
||
|
|
#endif // DEBUG_WIFI_LOCATION
|
||
|
|
if (response != "") {
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.println("Got response:");
|
||
|
|
Serial.println(response);
|
||
|
|
#endif // DEBUG_WIFI_LOCATION
|
||
|
|
|
||
|
|
int index = response.indexOf("\"lat\":");
|
||
|
|
if (index != -1) {
|
||
|
|
String tempStr = response.substring(index);
|
||
|
|
//Serial.println(tempStr);
|
||
|
|
tempStr = tempStr.substring(tempStr.indexOf(":") + 1, tempStr.indexOf(","));
|
||
|
|
//Serial.println(tempStr);
|
||
|
|
location.lat = tempStr.toFloat();
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.println("\nLat: " + String(location.lat, 7));
|
||
|
|
#endif // DEBUG_WIFI_LOCATION
|
||
|
|
}
|
||
|
|
|
||
|
|
index = response.indexOf("\"lng\":");
|
||
|
|
if (index != -1) {
|
||
|
|
String tempStr = response.substring(index);
|
||
|
|
//Serial.println(tempStr);
|
||
|
|
tempStr = tempStr.substring(tempStr.indexOf(":") + 1, tempStr.indexOf(","));
|
||
|
|
//Serial.println(tempStr);
|
||
|
|
location.lon = tempStr.toFloat();
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.println("Lon: " + String(location.lon, 7));
|
||
|
|
#endif // DEBUG_WIFI_LOCATION
|
||
|
|
}
|
||
|
|
|
||
|
|
index = response.indexOf("\"accuracy\":");
|
||
|
|
if (index != -1) {
|
||
|
|
String tempStr = response.substring(index);
|
||
|
|
//Serial.println(tempStr);
|
||
|
|
tempStr = tempStr.substring(tempStr.indexOf(":") + 1, tempStr.indexOf("\n"));
|
||
|
|
//Serial.println(tempStr);
|
||
|
|
location.accuracy = tempStr.toFloat();
|
||
|
|
#ifdef DEBUG_WIFI_LOCATION
|
||
|
|
Serial.println("Accuracy: " + String(location.accuracy) + "\n");
|
||
|
|
#endif // DEBUG_WIFI_LOCATION
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return location;
|
||
|
|
}
|