arduino-sketches

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 1  →  ?path2? @ 2
/espFindClient.ino
@@ -0,0 +1,351 @@
/*
This file is part of esp-find3-client by Sylwester aka DatanoiseTV.
The original source can be found at https://github.com/DatanoiseTV/esp-find3-client.
 
26/04/2020: Adjustments by Wizardry and Steamworks.
 
esp-find3-client is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
esp-find3-client is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with esp-find3-client. If not, see <http://www.gnu.org/licenses/>.
*/
 
///////////////////////////////////////////////////////////////////////////
// CONFIGURATION //
///////////////////////////////////////////////////////////////////////////
 
// Set to the WiFi AP name.
#define WIFI_SSID ""
// Set to the WiFi AP password.
#define WIFI_PSK ""
 
// Set to 1 for learning mode.
#define MODE_LEARNING 1
#define LOCATION ""
 
// Family name.
#define FAMILY_NAME ""
 
// BLE requires large app partition or the sketch will not fit.
// Please choose:
// * Tools -> Partition scheme -> Minimal SPIFFS (1.9MB APP / 190KB SPIFFS)
// and set to 1 to enable BLE.
#define USE_BLE 1
#define BLE_SCANTIME 5
 
// Official server: cloud.internalpositioning.com
#define FIND_HOST "cloud.internalpositioning.com"
// Official port: 443 and SSL set to 1
#define FIND_PORT 443
// Whether to use SSL for the HTTP connection.
// Set to 1 for official cloud server.
#define USE_HTTP_SSL 1
// Timeout connecting to find3 server expressed in milliseconds.
#define HTTP_TIMEOUT 2500
 
// The NTP server to use for time updates.
#define NTP_HOST "pool.ntp.org"
// The offset in seconds from UTC, ie: 3600 for +1 Hour.
#define UTC_OFFSET 2 * 3600
 
// The password to use for OTA updates.
#define OTA_PASSWORD ""
 
// Set to 1 to enable. Used for verbose debugging.
#define DEBUG 1
 
///////////////////////////////////////////////////////////////////////////
// INTERNALS //
///////////////////////////////////////////////////////////////////////////
 
#ifdef ARDUINO_ARCH_ESP32
#include <WiFiClientSecure.h>
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <ArduinoOTA.h>
 
#if defined(ARDUINO_ARCH_ESP8266)
#define GET_CHIP_ID() String(ESP.getChipId(), HEX)
#elif defined(ARDUINO_ARCH_ESP32)
#define GET_CHIP_ID() String(((uint16_t)(ESP.getEfuseMac()>>32)), HEX)
#endif
 
#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
 
#define ARDUINOJSON_USE_LONG_LONG 1
#include <ArduinoJson.h>
 
// Automagically disable BLE on ESP8266
#if defined(ARDUINO_ARCH_ESP8266) && !defined(ARDUINO_ARCH_ESP32)
#define USE_BLE 0
#endif
 
#if defined(ARDUINO_ARCH_ESP32) && (USE_BLE == 1)
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
 
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
// Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
}
};
#endif
 
#ifdef ARDUINO_ARCH_ESP32
RTC_DATA_ATTR int bootCount = 0;
#endif
 
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_HOST, UTC_OFFSET, 60000);
 
// Retrieves the WiFi MAC address.
String getWiFiMAC() {
String result;
byte mac[6];
WiFi.macAddress(mac);
for (int i = 5; i > -1; --i) {
result += String(mac[i], HEX);
if (i != 0) {
result += ":";
}
}
return result;
}
 
void SubmitWiFi(void)
{
Serial.println("[ INFO ]\tWiFi MAC: " + getWiFiMAC());
 
String request;
 
StaticJsonDocument<256> jsonBuffer;
JsonObject root = jsonBuffer.to<JsonObject>();
 
root["d"] = "esp-" + GET_CHIP_ID();
root["f"] = FAMILY_NAME;
root["t"] = timeClient.getEpochTime();
#if (MODE_LEARNING == 1)
Serial.println("[ iNFO ]\tLearning enabled, sending learning data.");
root["l"] = LOCATION;
#endif
 
JsonObject data = root.createNestedObject("s");
 
Serial.println("[ INFO ]\tWiFi scan starting..");
int n = WiFi.scanNetworks(false, true);
Serial.println("[ INFO ]\tWiFi Scan finished.");
if (n == 0) {
Serial.println("[ ERROR ]\tNo networks found");
} else {
Serial.print("[ INFO ]\t");
Serial.print(n);
Serial.println(" WiFi networks found.");
JsonObject wifi_network = data.createNestedObject("wifi");
for (int i = 0; i < n; ++i) {
wifi_network[WiFi.BSSIDstr(i)] = WiFi.RSSI(i);
}
 
#if (USE_BLE == 1)
Serial.println("[ INFO ]\tBLE scan starting..");
BLEDevice::init("");
BLEAddress btMAC = BLEDevice::getAddress();
Serial.println("[ INFO ]\tBT MAC: " + String(btMAC.toString().c_str()));
BLEScan* pBLEScan = BLEDevice::getScan(); // create new scan
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true); // active scan uses more power, but get results faster
BLEScanResults foundDevices = pBLEScan->start(BLE_SCANTIME);
 
Serial.print("[ INFO ]\t");
Serial.print(foundDevices.getCount());
Serial.println(" BLE devices found.");
 
JsonObject bt_network = data.createNestedObject("bluetooth");
for (int i = 0; i < foundDevices.getCount(); i++)
{
std::string mac = foundDevices.getDevice(i).getAddress().toString();
bt_network[(String)mac.c_str()] = (int)foundDevices.getDevice(i).getRSSI();
}
#else
Serial.println("[ INFO ]\tBLE scan skipped (BLE disabled)..");
#endif // USE_BLE
 
serializeJson(root, request);
 
#if (DEBUG == 1)
Serial.println("[ DEBUG ]\t" + request);
#endif
 
#if (USE_HTTP_SSL == 1)
WiFiClientSecure client;
#else
WiFiClient client;
#endif
if (!client.connect(FIND_HOST, FIND_PORT)) {
Serial.println("[ WARN ]\tConnection to server failed, restarting in 5s...");
delay(5000);
ESP.restart();
}
 
// We now create a URI for the request
String url = "/data";
 
Serial.print("[ INFO ]\tRequesting URL: ");
Serial.println(url);
 
// This will send the request to the server
client.print(String("POST ") + url + " HTTP/1.1\r\n" +
"Host: " + FIND_HOST + "\r\n" +
"Content-Type: application/json\r\n" +
"Content-Length: " + request.length() + "\r\n\r\n" +
request +
"\r\n\r\n"
);
client.flush();
 
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > HTTP_TIMEOUT) {
Serial.println("[ ERROR ]\tHTTP Client Timeout!");
client.stop();
return;
}
}
 
// Check HTTP status
char status[60] = {0};
client.readBytesUntil('\r', status, sizeof(status));
if (strcmp(status, "HTTP/1.1 200 OK") != 0) {
Serial.print(F("[ ERROR ]\tUnexpected Response: "));
Serial.println(status);
return;
}
else
{
Serial.println(F("[ INFO ]\tGot a 200 OK."));
}
 
char endOfHeaders[] = "\r\n\r\n";
if (!client.find(endOfHeaders)) {
Serial.println(F("[ ERROR ]\t Invalid Response"));
return;
}
else
{
Serial.println("[ INFO ]\tLooks like a valid response.");
}
 
Serial.println("[ INFO ]\tClosing connection.");
Serial.println("=============================================================");
}
}
 
void setup() {
Serial.begin(115200);
delay(1000);
 
#if defined(ARDUINO_ARCH_ESP32) && (USE_BLE == 1)
Serial.println("Find3 ESP client by DatanoiseTV (WiFi + BLE support.)");
#else
Serial.println("Find3 ESP client by DatanoiseTV (WiFi support WITHOUT BLE.)");
#endif
 
Serial.print("[ INFO ]\tESP ID is: ");
Serial.println("esp-" + GET_CHIP_ID());
 
// Hostname defaults to esp8266-[ChipID]
ArduinoOTA.setHostname(String("esp-" + GET_CHIP_ID()).c_str());
// Set the OTA password
ArduinoOTA.setPassword(OTA_PASSWORD);
ArduinoOTA.onStart([]() {
Serial.println("=============================================================");
switch (ArduinoOTA.getCommand()) {
case U_FLASH: // Sketch
Serial.println("[ INFO ]\tOTA start updating sketch.");
break;
#if defined(ARDUINO_ARCH_ESP8266)
case U_FS:
#elif defined(ARDUINO_ARCH_ESP32)
case U_SPIFFS:
#endif
Serial.println("[ INFO ]\tOTA start updating filesystem.");
break;
default:
Serial.println("[ WARN ]\tUnknown OTA update type.");
break;
}
});
ArduinoOTA.onEnd([]() {
Serial.println("[ INFO ]\tOTA update complete.");
Serial.println("=============================================================");
ESP.restart();
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("[ INFO ]\tOTA update progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("[ ERROR ]\tOTA update error [%u]: ", error);
switch (error) {
case OTA_AUTH_ERROR:
Serial.println("OTA authentication failed");
break;
case OTA_BEGIN_ERROR:
Serial.println("OTA begin failed");
break;
case OTA_CONNECT_ERROR:
Serial.println("OTA connect failed");
break;
case OTA_RECEIVE_ERROR:
Serial.println("OTA receive failed");
break;
case OTA_END_ERROR:
Serial.println("OTA end failed");
break;
default:
Serial.println("Unknown OTA failure");
break;
}
ESP.restart();
});
}
 
void loop() {
// If WiFi is not connected, attempt to reconnect and if that fails then restart.
if (WiFi.status() != WL_CONNECTED) {
Serial.println("[ WARN ]\tWiFi not connected, retrying...");
WiFi.disconnect();
#if defined(ARDUINO_ARCH_ESP32)
WiFi.setHostname(String("esp-" + GET_CHIP_ID()).c_str());
#elif defined(ARDUINO_ARCH_ESP8266)
WiFi.hostname(String("esp-" + GET_CHIP_ID()).c_str());
#endif
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PSK);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("[ ERROR ]\tFailed to connect to Wifi, rebooting in 5s...");
delay(5000);
ESP.restart();
}
Serial.println("[ INFO ]\tStarting OTA...");
ArduinoOTA.begin();
 
Serial.println("[ INFO ]\tStarting NTP...");
timeClient.begin();
}
ArduinoOTA.handle();
timeClient.update();
SubmitWiFi();
}