This commit is contained in:
Dmitry Borisenko
2020-09-06 23:00:33 +03:00
parent 799118d763
commit e505eb9b6e
21 changed files with 819 additions and 49 deletions

6
lib/WifiLocation/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
*.bak
examples/googleLocation/googleLocation.sln
**vcxproj**
examples/googleLocation/.vs/
examples/googleLocation/__vm/
examples/googleLocation/Release/

View File

@@ -0,0 +1,13 @@
#### Copyright 2016 [German Martin](mailto:gmag11@gmail.com). All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met :
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and / or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those of the
authors and should not be interpreted as representing official policies, either expressed
or implied, of [German Martin](mailto:gmag11@gmail.com) [(mailto:gmag11@gmail.com)](mailto:gmag11@gmail.com)

139
lib/WifiLocation/README.md Normal file
View File

@@ -0,0 +1,139 @@
# WiFi Location
> ## Important notice:
> Since July 2018, Google's conditions for Maps APIs have changed. You have to assign a billing method to it so that you are able to use it. Check more information here: https://cloud.google.com/maps-platform/pricing/. Be careful about number of request you make using this library. There is a free tier but you know this can change in any moment. I am not responsible of billing cost caused by use of Google API.
> ## Platform compatibility:
> Support of SAMD microcontrollers have been deprecated. If you use MKR series boards from Arduino you can keep using version 1.2.5.
> Newer developments will be done for ESP8266 and ESP32.
## Introduction
When location information is needed in an electronic project, we normally think about a GPS module. But we know that mobile phones can get approximate location listening WiFi signals, when GPS is disabled or not usable because we are inside a building.
If your project needs approximate location or you are indoors, and it is connected to the Internet, you can use same mechanism to get latitude and longitude. So, you don't need additional hardware.
This code uses access to Google Maps GeoLocation API. Please check [Google Policies](https://developers.google.com/maps/documentation/geolocation/policies).
## Description
This is a library that sends Google Maps GeoLocaion API a request with a list of all WiFi AP's BSSID that your microcontroller listens to. Google, then answer with location and accuracy in JSON format.
Request body has this form:
```
{
"wifiAccessPoints": [
{"macAddress":"XX:XX:XX:XX:XX:XX","signalStrength":-58,"channel":11},
{"macAddress":"XX:XX:XX:XX:XX:XX","signalStrength":-85,"channel":11},
{"macAddress":"XX:XX:XX:XX:XX:XX","signalStrength":-82,"channel":1},
{"macAddress":"XX:XX:XX:XX:XX:XX","signalStrength":-89,"channel":6},
{"macAddress":"XX:XX:XX:XX:XX:XX","signalStrength":-86,"channel":13},
{"macAddress":"XX:XX:XX:XX:XX:XX","signalStrength":-89,"channel":4},
{"macAddress":"XX:XX:XX:XX:XX:XX","signalStrength":-42,"channel":5}
]
}
```
If information is correct, Google GeoLocation API response will be like this:
```
{
"location": {
"lat": 37.3689919,
"lng": -122.1054095
},
"accuracy": 39.0
}
```
You need a google API key to validate with Google API. Navigate to [Google Developers Console](https://console.developers.google.com/apis) to enable GeoLocation API. Without this API key you will get an error as response.
Go to https://developers.google.com/maps/documentation/geolocation/intro to learn how to create an API key.
That API key has to be provided to WifiLocation class constructor like a String.
Once WifiLocation object is created, you can get location calling `getGeoFromWiFi()`.
Google requires using secure TLS connection in order to use GeoLocation API. `WifiLocation.cpp` includes GoogleCA certificate to check server chain. This certificate may expire.
You may get current certificate using this command (if you are using Linux)
``` bash
openssl s_client -servername www.googleapis.com -showcerts \
-connect www.googleapis.com:443 < /dev/null \
| awk '/^-----BEGIN CERTIFICATE-----/,/^-----END CERTIFICATE-----/{if(++m==1)n++;if(n==2)print;if(/^-----END CERTIFICATE-----/)m=0}' \
> googleCA.cer
```
Then, you can copy file content and overwrite [this part](https://github.com/gmag11/WifiLocation/blob/dev/src/WifiLocation.cpp#L14-L38) of `WifiLocation.cpp`, from line 14.
## Required libraries
Using this code on ESP8266 or ESP32 platform does not require any external library.
In order to compile this on MRK1000, WiFi101 library is needed.
## Limitations
Notice that in order to get location this library has to scan for all surrounding Wi-Fi networks and make the request to Google API. Don't expect to get this immediately. All needed steps may take up to 20 seconds.
So, if your project is powered with batteries, you need to drastically limit the frequency of position updates or use a GPS instead.
Current version uses synchronous programming. This means that main code will be blocked while location is being resolved. As this can be quite long you need to take it into account while programming your project.
In future versions, I'll try to add non blocking options. I think I can keep back compatibility so that anyone can get updated versions without using new features.
## Code example
Valid for ESP32, ESP8266 and MKR1000 (SAMD architecture)
```Arduino
#ifdef ARDUINO_ARCH_SAMD
#include <WiFi101.h>
#elif defined ARDUINO_ARCH_ESP8266
#include <ESP8266WiFi.h>
#elif defined ARDUINO_ARCH_ESP32
#include <WiFi.h>
#else
#error Wrong platform
#endif
#include <WifiLocation.h>
const char* googleApiKey = "YOUR_GOOGLE_API_KEY";
const char* ssid = "SSID";
const char* passwd = "PASSWD";
WifiLocation location(googleApiKey);
void setup() {
Serial.begin(115200);
// Connect to WPA/WPA2 network
#ifdef ARDUINO_ARCH_ESP32
WiFi.mode(WIFI_MODE_STA);
#endif
#ifdef ARDUINO_ARCH_ESP8266
WiFi.mode(WIFI_STA);
#endif
WiFi.begin(ssid, passwd);
while (WiFi.status() != WL_CONNECTED) {
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
// wait 5 seconds for connection:
Serial.print("Status = ");
Serial.println(WiFi.status());
delay(500);
}
location_t loc = location.getGeoFromWiFi();
Serial.println("Location request data");
Serial.println(location.getSurroundingWiFiJson());
Serial.println("Latitude: " + String(loc.lat, 7));
Serial.println("Longitude: " + String(loc.lon, 7));
Serial.println("Accuracy: " + String(loc.accuracy));
}
void loop() {
}
```

View File

@@ -0,0 +1,52 @@
#include <Arduino.h>
#ifdef ARDUINO_ARCH_SAMD
#include <WiFi101.h>
#elif defined ARDUINO_ARCH_ESP8266
#include <ESP8266WiFi.h>
#elif defined ARDUINO_ARCH_ESP32
#include <WiFi.h>
#else
#error Wrong platform
#endif
#include <WifiLocation.h>
const char* googleApiKey = "YOUR_GOOGLE_API_KEY";
const char* ssid = "SSID";
const char* passwd = "PASSWD";
WifiLocation location(googleApiKey);
void setup() {
Serial.begin(115200);
// Connect to WPA/WPA2 network
#ifdef ARDUINO_ARCH_ESP32
WiFi.mode(WIFI_MODE_STA);
#endif
#ifdef ARDUINO_ARCH_ESP8266
WiFi.mode(WIFI_STA);
#endif
WiFi.begin(ssid, passwd);
while (WiFi.status() != WL_CONNECTED) {
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
// wait 5 seconds for connection:
Serial.print("Status = ");
Serial.println(WiFi.status());
delay(500);
}
location_t loc = location.getGeoFromWiFi();
Serial.println("Location request data");
Serial.println(location.getSurroundingWiFiJson());
Serial.println("Latitude: " + String(loc.lat, 7));
Serial.println("Longitude: " + String(loc.lon, 7));
Serial.println("Accuracy: " + String(loc.accuracy));
}
void loop() {
}

View File

@@ -0,0 +1,24 @@
#######################################
# Syntax Coloring Map For WifiLocation
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
location_t KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
WifiLocation KEYWORD2
getGeoFromWiFi KEYWORD2
getSurroundingWiFiJson KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
googleApisHost LITERAL1
googleApiUrl LITERAL1

View File

@@ -0,0 +1,21 @@
{
"name": "WifiLocation",
"frameworks": "arduino",
"version": "1.2.6",
"keywords": "GPS, location, wifi, google",
"platforms": ["atmelsam", "espressif32", "espressif8266"],
"description": "Library to get geographic position (lat, lon, accuracy) listening surrounding WiFi networks (Works with ESP8266 and WiFi101 boards, including MKR1000). This library implements call to Google Maps GeoLocation API to get location from surrounding WiFi networks. It is not needed to know WiFi password of all of them. Internet connection is required. You need an API key from Google Maps. Check https://developers.google.com/maps/documentation/geolocation/intro to learn how to get your own key.",
"url": "https://github.com/gmag11/WifiLocation",
"authors":
{
"name": "Germán Martín",
"email": "gmag11@gmail.com"
},
"repository":
{
"type": "git",
"url": "https://github.com/gmag11/WifiLocation.git"
},
"examples": "examples/*/*.ino"
}

View File

@@ -0,0 +1,10 @@
name=WifiLocation
version=1.2.6
author=Germán Martín
maintainer=Germán Martín <gmag11@gmail.com>
sentence=Library to get geographic position (lat, lon, accuracy), without GPS, by listening surrounding WiFi networks (Works with ESP8266 and WiFi101 boards, including MKR1000)
paragraph=This library implements call to Google Maps GeoLocation API to get location from surrounding WiFi networks without the need to use a GPS receiver. It is not needed to know WiFi password of all of them. Internet connection is required. You need an API key from Google Maps. Check https://developers.google.com/maps/documentation/geolocation/intro to learn how to get your own key.
category=Other
url=https://github.com/gmag11/WifiLocation
architectures=esp8266, samd, esp32

View File

@@ -0,0 +1,239 @@
//
//
//
#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;
}

View File

@@ -0,0 +1,54 @@
// WifiLocation.h
#ifndef _WIFILOCATION_h
#define _WIFILOCATION_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
//#define DEBUG_WIFI_LOCATION
//#define USE_CORE_PRE_2_5_0 // Uncomment this if you are using Arduino Core < 2.5.0
#ifdef ARDUINO_ARCH_SAMD
#include <WiFi101.h>
#elif defined ARDUINO_ARCH_ESP8266
#include <ESP8266WiFi.h>
#elif defined ARDUINO_ARCH_ESP32
#include <WiFi.h>
#include <WiFiClientSecure.h>
#else
#error Wrong platform
#endif
#define MAX_CONNECTION_TIMEOUT 5000
#define MAX_WIFI_SCAN 127
typedef struct {
float lat = 0;
float lon = 0;
int accuracy = 40000;
} location_t;
class WifiLocation {
public:
WifiLocation(String googleKey = "");
location_t getGeoFromWiFi();
static String getSurroundingWiFiJson();
protected:
String _googleApiKey;
//String _googleApiFingerprint = "2c 86 e4 67 e7 b5 ca df 11 9e bd 2e 41 c2 4b e8 b6 7e cd aa";
//IPAddress _googleApiIP = IPAddress(216, 58, 214, 170);
#if defined ESP8266 || defined ARDUINO_ARCH_ESP32
WiFiClientSecure _client;
#elif defined ARDUINO_ARCH_SAMD
WiFiSSLClient _client;
#endif
static String MACtoString(uint8_t* macAddress);
};
#endif

View File

@@ -0,0 +1,25 @@
-----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-----