Add support for tile trackers and move to Nimble BLE

This commit is contained in:
DTTerastar 2021-03-07 09:07:34 -05:00
parent 75ad9e0af3
commit 4c8b84ab08
2 changed files with 546 additions and 468 deletions

View File

@ -14,7 +14,8 @@ src_dir = ./src
[env:esp32] [env:esp32]
platform = espressif32 platform = espressif32
framework = arduino framework = arduino
board = esp32dev board = m5stick-c
lib_deps = ArduinoJson@^6, ESP32 BLE Arduino@^1.0.1, AsyncMqttClient@^0.8.2, AsyncTCP lib_deps = ArduinoJson@^6, NimBLE-Arduino, AsyncMqttClient@^0.8.2, AsyncTCP
lib_ignore = ESPAsyncTCP lib_ignore = ESPAsyncTCP, ESP32 BLE Arduino
board_build.partitions = partitions_singleapp.csv board_build.partitions = partitions_singleapp.csv
monitor_speed = 115200

View File

@ -15,30 +15,32 @@
Ported to Arduino ESP32 by Evandro Copercini Ported to Arduino ESP32 by Evandro Copercini
*/ */
#include <WiFi.h> #include <WiFi.h>
extern "C" { extern "C"
#include "freertos/FreeRTOS.h" {
#include "freertos/timers.h" #include "freertos/FreeRTOS.h"
#include "freertos/timers.h"
} }
#include "soc/timer_group_struct.h" #include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h" #include "soc/timer_group_reg.h"
#include <AsyncTCP.h> #include <AsyncTCP.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include <AsyncMqttClient.h> #include <AsyncMqttClient.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <ArduinoOTA.h> #include <ArduinoOTA.h>
#include "BLEBeacon.h"
#include "BLEEddystoneTLM.h" #include <NimBLEDevice.h>
#include "BLEEddystoneURL.h" #include <NimBLEAdvertisedDevice.h>
#include "NimBLEEddystoneURL.h"
#include "NimBLEEddystoneTLM.h"
#include "NimBLEBeacon.h"
#include "Settings.h" #include "Settings.h"
#ifdef htuSensorTopic #ifdef htuSensorTopic
#define tempTopic htuSensorTopic "/temperature" #define tempTopic htuSensorTopic "/temperature"
#define humidityTopic htuSensorTopic "/humidity" #define humidityTopic htuSensorTopic "/humidity"
#include "sensors/sensor_htu21d.h" #include "sensors/sensor_htu21d.h"
#endif #endif
static const int scanTime = singleScanTime; static const int scanTime = singleScanTime;
@ -47,9 +49,9 @@ static const uint16_t beaconUUID = 0xFEAA;
#ifdef TxDefault #ifdef TxDefault
static const int defaultTxPower = TxDefault; static const int defaultTxPower = TxDefault;
#else #else
static const int defaultTxPower = -72; static const int defaultTxPower = -40;
#endif #endif
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8)) #define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8))
WiFiClient espClient; WiFiClient espClient;
AsyncMqttClient mqttClient; AsyncMqttClient mqttClient;
@ -59,21 +61,23 @@ bool updateInProgress = false;
String localIp; String localIp;
byte retryAttempts = 0; byte retryAttempts = 0;
unsigned long last = 0; unsigned long last = 0;
BLEScan* pBLEScan; BLEScan *pBLEScan;
TaskHandle_t BLEScan; TaskHandle_t BLEScan;
String getProximityUUIDString(BLEBeacon beacon) { String getProximityUUIDString(BLEBeacon beacon)
{
std::string serviceData = beacon.getProximityUUID().toString().c_str(); std::string serviceData = beacon.getProximityUUID().toString().c_str();
int serviceDataLength = serviceData.length(); int serviceDataLength = serviceData.length();
String returnedString = ""; String returnedString = "";
int i = serviceDataLength; int i = serviceDataLength;
while (i > 0) while (i > 0)
{ {
if (serviceData[i-1] == '-') { if (serviceData[i - 1] == '-')
{
i--; i--;
} }
char a = serviceData[i-1]; char a = serviceData[i - 1];
char b = serviceData[i-2]; char b = serviceData[i - 2];
returnedString += b; returnedString += b;
returnedString += a; returnedString += a;
@ -83,49 +87,46 @@ String getProximityUUIDString(BLEBeacon beacon) {
return returnedString; return returnedString;
} }
float calculateDistance(int rssi, int txPower) { float calcDistance(float rssi, float calRssi)
{
float distFl; if (rssi == 0)
if (rssi == 0) {
return -1.0; return -1.0;
} if (!calRssi)
calRssi = defaultTxPower;
if (!txPower) { float ratio = (calRssi - rssi) / 35;
// somewhat reasonable default value float distFl = pow(10, ratio);
txPower = defaultTxPower; float distance = round(distFl * 100) / 100;
}
if (txPower > 0) { Serial.print(", RSSI@1m: ");
txPower = txPower * -1; Serial.print(calRssi);
} Serial.print(", RSSI: ");
Serial.print(rssi);
const float ratio = rssi * 1.0 / txPower; Serial.print(", distance: ");
if (ratio < 1.0) { Serial.print(distance);
distFl = pow(ratio, 10);
} else {
distFl = (0.89976) * pow(ratio, 7.7095) + 0.111;
}
return round(distFl * 100) / 100;
return distance;
} }
#ifdef htuSensorTopic #ifdef htuSensorTopic
void reportSensorValues() { void reportSensorValues()
if (htuSensorIsConnected()) { {
if (htuSensorIsConnected())
{
char temp[8]; char temp[8];
char humidity[8]; char humidity[8];
dtostrf(getTemp(), 0, 1, temp); // convert float to string with one decimal place precision dtostrf(getTemp(), 0, 1, temp); // convert float to string with one decimal place precision
dtostrf(getHumidity(), 0, 1, humidity); // convert float to string with one decimal place precision dtostrf(getHumidity(), 0, 1, humidity); // convert float to string with one decimal place precision
if (mqttClient.publish(tempTopic, 0, 0, temp) == true) { if (mqttClient.publish(tempTopic, 0, 0, temp) == true)
{
Serial.printf("Temperature %s sent\t", temp); Serial.printf("Temperature %s sent\t", temp);
} }
if (mqttClient.publish(humidityTopic, 0, 0, humidity) == true) { if (mqttClient.publish(humidityTopic, 0, 0, humidity) == true)
{
Serial.printf("Humidity %s sent\n\r", humidity); Serial.printf("Humidity %s sent\n\r", humidity);
} }
} }
@ -133,8 +134,8 @@ void reportSensorValues() {
#endif #endif
bool sendTelemetry(int deviceCount = -1, int reportCount = -1)
bool sendTelemetry(int deviceCount = -1, int reportCount = -1) { {
StaticJsonDocument<256> tele; StaticJsonDocument<256> tele;
tele["room"] = room; tele["room"] = room;
tele["ip"] = localIp; tele["ip"] = localIp;
@ -143,109 +144,141 @@ bool sendTelemetry(int deviceCount = -1, int reportCount = -1) {
tele["wait_dur"] = waitTime; tele["wait_dur"] = waitTime;
tele["max_dist"] = maxDistance; tele["max_dist"] = maxDistance;
if (deviceCount > -1) { if (deviceCount > -1)
Serial.printf("devices_discovered: %d\n\r",deviceCount); {
Serial.printf("devices_discovered: %d\n\r", deviceCount);
tele["disc_ct"] = deviceCount; tele["disc_ct"] = deviceCount;
} }
if (reportCount > -1) { if (reportCount > -1)
Serial.printf("devices_reported: %d\n\r",reportCount); {
Serial.printf("devices_reported: %d\n\r", reportCount);
tele["rept_ct"] = reportCount; tele["rept_ct"] = reportCount;
} }
char teleMessageBuffer[258]; char teleMessageBuffer[258];
serializeJson(tele, teleMessageBuffer); serializeJson(tele, teleMessageBuffer);
#ifdef htuSensorTopic #ifdef htuSensorTopic
reportSensorValues(); reportSensorValues();
#endif #endif
if (mqttClient.publish(telemetryTopic, 0, 0, teleMessageBuffer) == true) { if (mqttClient.publish(telemetryTopic, 0, 0, teleMessageBuffer) == true)
{
Serial.println("Telemetry sent"); Serial.println("Telemetry sent");
return true; return true;
} else { }
else
{
Serial.println("Error sending telemetry"); Serial.println("Error sending telemetry");
return false; return false;
} }
} }
void connectToWifi() { void connectToWifi()
{
Serial.println("Connecting to WiFi..."); Serial.println("Connecting to WiFi...");
WiFi.begin(ssid, password); WiFi.begin(ssid, password);
WiFi.setHostname(hostname); WiFi.setHostname(hostname);
} }
void connectToMqtt() { void connectToMqtt()
{
Serial.println("Connecting to MQTT"); Serial.println("Connecting to MQTT");
if (WiFi.isConnected() && !updateInProgress) { if (WiFi.isConnected() && !updateInProgress)
{
mqttClient.setCredentials(mqttUser, mqttPassword); mqttClient.setCredentials(mqttUser, mqttPassword);
mqttClient.setClientId(hostname); mqttClient.setClientId(hostname);
mqttClient.connect(); mqttClient.connect();
} else { }
else
{
Serial.println("Cannot reconnect MQTT - WiFi error"); Serial.println("Cannot reconnect MQTT - WiFi error");
handleWifiDisconnect(); handleWifiDisconnect();
} }
} }
bool handleMqttDisconnect() { bool handleMqttDisconnect()
if (updateInProgress) { {
if (updateInProgress)
{
Serial.println("Not retrying MQTT connection - OTA update in progress"); Serial.println("Not retrying MQTT connection - OTA update in progress");
return true; return true;
} }
if (retryAttempts > 10) { if (retryAttempts > 10)
{
Serial.println("Too many retries. Restarting"); Serial.println("Too many retries. Restarting");
ESP.restart(); ESP.restart();
} else { }
else
{
retryAttempts++; retryAttempts++;
} }
if (WiFi.isConnected() && !updateInProgress) { if (WiFi.isConnected() && !updateInProgress)
{
Serial.println("Starting MQTT reconnect timer"); Serial.println("Starting MQTT reconnect timer");
if (xTimerReset(mqttReconnectTimer, 0) == pdFAIL) { if (xTimerReset(mqttReconnectTimer, 0) == pdFAIL)
{
Serial.println("failed to restart"); Serial.println("failed to restart");
xTimerStart(mqttReconnectTimer, 0); xTimerStart(mqttReconnectTimer, 0);
} else { }
else
{
Serial.println("restarted"); Serial.println("restarted");
} }
} else { }
else
{
Serial.print("Disconnected from WiFi; starting WiFi reconnect timiler\t"); Serial.print("Disconnected from WiFi; starting WiFi reconnect timiler\t");
handleWifiDisconnect(); handleWifiDisconnect();
} }
return false;
} }
bool handleWifiDisconnect() { bool handleWifiDisconnect()
if (WiFi.isConnected()) { {
if (WiFi.isConnected())
{
Serial.println("WiFi appears to be connected. Not retrying."); Serial.println("WiFi appears to be connected. Not retrying.");
return true; return true;
} }
if (retryAttempts > 10) { if (retryAttempts > 10)
{
Serial.println("Too many retries. Restarting"); Serial.println("Too many retries. Restarting");
ESP.restart(); ESP.restart();
} else { }
else
{
retryAttempts++; retryAttempts++;
} }
if (mqttClient.connected()) { if (mqttClient.connected())
{
mqttClient.disconnect(); mqttClient.disconnect();
} }
if (xTimerIsTimerActive(mqttReconnectTimer) != pdFALSE) { if (xTimerIsTimerActive(mqttReconnectTimer) != pdFALSE)
{
xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
} }
if (xTimerReset(wifiReconnectTimer, 0) == pdFAIL) { if (xTimerReset(wifiReconnectTimer, 0) == pdFAIL)
{
Serial.println("failed to restart"); Serial.println("failed to restart");
xTimerStart(wifiReconnectTimer, 0); xTimerStart(wifiReconnectTimer, 0);
return false; return false;
} else { }
else
{
Serial.println("restarted"); Serial.println("restarted");
return true; return true;
} }
} }
void WiFiEvent(WiFiEvent_t event) { void WiFiEvent(WiFiEvent_t event)
{
Serial.printf("[WiFi-event] event: %x\n\r", event); Serial.printf("[WiFi-event] event: %x\n\r", event);
switch(event) { switch (event)
{
case SYSTEM_EVENT_STA_GOT_IP: case SYSTEM_EVENT_STA_GOT_IP:
digitalWrite(LED_BUILTIN, !LED_ON); digitalWrite(LED_BUILTIN, !LED_ON);
Serial.print("IP address: \t"); Serial.print("IP address: \t");
@ -254,7 +287,8 @@ void WiFiEvent(WiFiEvent_t event) {
Serial.print("Hostname: \t"); Serial.print("Hostname: \t");
Serial.println(WiFi.getHostname()); Serial.println(WiFi.getHostname());
connectToMqtt(); connectToMqtt();
if (xTimerIsTimerActive(wifiReconnectTimer) != pdFALSE) { if (xTimerIsTimerActive(wifiReconnectTimer) != pdFALSE)
{
Serial.println("Stopping wifi reconnect timer"); Serial.println("Stopping wifi reconnect timer");
xTimerStop(wifiReconnectTimer, 0); xTimerStop(wifiReconnectTimer, 0);
} }
@ -272,12 +306,15 @@ void WiFiEvent(WiFiEvent_t event) {
case SYSTEM_EVENT_STA_START: case SYSTEM_EVENT_STA_START:
Serial.println("STA Start"); Serial.println("STA Start");
tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, hostname); tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, hostname);
if (xTimerIsTimerActive(wifiReconnectTimer) != pdFALSE) { if (xTimerIsTimerActive(wifiReconnectTimer) != pdFALSE)
TickType_t xRemainingTime = xTimerGetExpiryTime( wifiReconnectTimer ) - xTaskGetTickCount(); {
TickType_t xRemainingTime = xTimerGetExpiryTime(wifiReconnectTimer) - xTaskGetTickCount();
Serial.print("WiFi Time remaining: "); Serial.print("WiFi Time remaining: ");
Serial.println(xRemainingTime); Serial.println(xRemainingTime);
} else { }
Serial.println("WiFi Timer is inactive; resetting\t"); else
{
Serial.println("WiFi Timer is inactive; resetting");
handleWifiDisconnect(); handleWifiDisconnect();
} }
break; break;
@ -285,251 +322,275 @@ void WiFiEvent(WiFiEvent_t event) {
Serial.println("STA Stop"); Serial.println("STA Stop");
handleWifiDisconnect(); handleWifiDisconnect();
break; break;
default:
break;
} }
} }
void onMqttConnect(bool sessionPresent) { void onMqttConnect(bool sessionPresent)
Serial.println("Connected to MQTT."); {
Serial.println("Connected to MQTT");
retryAttempts = 0; retryAttempts = 0;
if (mqttClient.publish(availabilityTopic, 0, 1, "CONNECTED") == true) { if (mqttClient.publish(availabilityTopic, 0, 1, "CONNECTED") == true)
{
Serial.print("Success sending message to topic:\t"); Serial.print("Success sending message to topic:\t");
Serial.println(availabilityTopic); Serial.println(availabilityTopic);
} else { }
else
{
Serial.println("Error sending message"); Serial.println("Error sending message");
} }
sendTelemetry(); sendTelemetry();
} }
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) { void onMqttDisconnect(AsyncMqttClientDisconnectReason reason)
{
Serial.println("Disconnected from MQTT."); Serial.println("Disconnected from MQTT.");
handleMqttDisconnect(); handleMqttDisconnect();
} }
bool reportDevice(BLEAdvertisedDevice advertisedDevice) { bool reportDevice(BLEAdvertisedDevice advertisedDevice)
{
// Serial.printf("\n\n");
StaticJsonDocument<500> doc; StaticJsonDocument<500> doc;
String mac_address = advertisedDevice.getAddress().toString().c_str(); String mac_address = advertisedDevice.getAddress().toString().c_str();
mac_address.replace(":",""); mac_address.replace(":", "");
mac_address.toLowerCase(); mac_address.toLowerCase();
//Check scanned MAC Address against a list of allowed MAC Addresses //Check scanned MAC Address against a list of allowed MAC Addresses
if (allowedListCheck) { if (allowedListCheck)
{
bool allowedListFound = false; bool allowedListFound = false;
for (uint32_t x = 0; x < allowedListNumberOfItems; x++) { for (uint32_t x = 0; x < allowedListNumberOfItems; x++)
if (mac_address == allowedList[x]) { {
if (mac_address == allowedList[x])
{
allowedListFound = true; allowedListFound = true;
} }
} }
if (allowedListFound == false) { if (allowedListFound == false)
{
return false; return false;
} }
} }
// -------------- // --------------
Serial.print("MAC: ");
// Serial.print("mac:\t"); Serial.print(mac_address);
// Serial.println(mac_address);
int rssi = advertisedDevice.getRSSI(); int rssi = advertisedDevice.getRSSI();
float distance;
doc["id"] = mac_address; if (advertisedDevice.haveName())
doc["uuid"] = mac_address; {
doc["rssi"] = rssi;
if (advertisedDevice.haveName()){
String nameBLE = String(advertisedDevice.getName().c_str()); String nameBLE = String(advertisedDevice.getName().c_str());
// Serial.print("Name: "); Serial.print(", Name: ");
// Serial.println(nameBLE); Serial.print(nameBLE);
doc["name"] = nameBLE; doc["name"] = nameBLE;
}
} else { else
// doc["name"] = "unknown"; {
// Serial.println("Device name unknown"); doc["name"] = mac_address;
} }
// Serial.printf("\n\r"); doc["id"] = mac_address;
// Serial.printf("Advertised Device: %s \n\r", advertisedDevice.toString().c_str()); doc["mac"] = mac_address;
doc["rssi"] = rssi;
std::string strServiceData = advertisedDevice.getServiceData(); std::string strServiceData = advertisedDevice.getServiceData();
uint8_t cServiceData[100]; uint8_t cServiceData[100];
strServiceData.copy((char *)cServiceData, strServiceData.length(), 0); strServiceData.copy((char *)cServiceData, strServiceData.length(), 0);
if (advertisedDevice.getServiceDataUUID().equals(BLEUUID(beaconUUID))==true) { // found Eddystone UUID if (advertisedDevice.haveServiceUUID())
// Serial.printf("is Eddystone: %d %s length %d\n", advertisedDevice.getServiceDataUUID().bitSize(), advertisedDevice.getServiceDataUUID().toString().c_str(),strServiceData.length()); {
for (int i = 0; i < advertisedDevice.getServiceUUIDCount(); i++)
{
Serial.printf(", sID: %s", advertisedDevice.getServiceUUID(i).toString().c_str());
}
}
if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceDataUUID().equals(BLEUUID("0xFEED")) == true)
{
Serial.print(", Tile");
doc["name"] = "Tile";
if (advertisedDevice.haveTXPower())
doc["txPower"] = advertisedDevice.getTXPower();
doc["distance"] = calcDistance(rssi, advertisedDevice.haveTXPower() ? -advertisedDevice.getTXPower() - 41 : 0);
}
else if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceDataUUID().equals(BLEUUID(beaconUUID)) == true)
{ // found Eddystone UUID
Serial.print(", Eddystone");
// Update distance variable for Eddystone BLE devices // Update distance variable for Eddystone BLE devices
BLEBeacon oBeacon = BLEBeacon(); if (cServiceData[0] == 0x10)
distance = calculateDistance(rssi, oBeacon.getSignalPower()); {
doc["distance"] = distance;
if (cServiceData[0]==0x10) {
BLEEddystoneURL oBeacon = BLEEddystoneURL(); BLEEddystoneURL oBeacon = BLEEddystoneURL();
oBeacon.setData(strServiceData); oBeacon.setData(strServiceData);
// Serial.printf("Eddystone Frame Type (Eddystone-URL) "); // Serial.printf("Eddystone Frame Type (Eddystone-URL) ");
// Serial.printf(oBeacon.getDecodedURL().c_str()); // Serial.printf(oBeacon.getDecodedURL().c_str());
doc["url"] = oBeacon.getDecodedURL().c_str(); doc["url"] = oBeacon.getDecodedURL().c_str();
Serial.print(" URL: ");
} else if (cServiceData[0]==0x20) { Serial.print(oBeacon.getDecodedURL().c_str());
doc["txPower"] = oBeacon.getPower();
doc["distance"] = calcDistance(rssi, oBeacon.getPower());
}
else if (cServiceData[0] == 0x20)
{
BLEEddystoneTLM oBeacon = BLEEddystoneTLM(); BLEEddystoneTLM oBeacon = BLEEddystoneTLM();
oBeacon.setData(strServiceData); oBeacon.setData(strServiceData);
// Serial.printf("Eddystone Frame Type (Unencrypted Eddystone-TLM) \n"); Serial.printf(" TLM: ");
// Serial.printf(oBeacon.toString().c_str()); Serial.printf(oBeacon.toString().c_str());
} else {
// Serial.println("service data");
for (int i=0;i<strServiceData.length();i++) {
// Serial.printf("[%X]",cServiceData[i]);
} }
} }
// Serial.printf("\n"); else
} else { {
if (advertisedDevice.haveManufacturerData()==true) { if (advertisedDevice.haveManufacturerData() == true)
{
std::string strManufacturerData = advertisedDevice.getManufacturerData(); std::string strManufacturerData = advertisedDevice.getManufacturerData();
uint8_t cManufacturerData[100]; uint8_t cManufacturerData[100];
strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0); strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
if (strManufacturerData.length()==25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00 ) { if (strManufacturerData.length() == 25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00)
{
BLEBeacon oBeacon = BLEBeacon(); BLEBeacon oBeacon = BLEBeacon();
oBeacon.setData(strManufacturerData); oBeacon.setData(strManufacturerData);
String proximityUUID = getProximityUUIDString(oBeacon); String proximityUUID = getProximityUUIDString(oBeacon);
distance = calculateDistance(rssi, oBeacon.getSignalPower());
// Serial.print("RSSI: ");
// Serial.print(rssi);
// Serial.print("\ttxPower: ");
// Serial.print(oBeacon.getSignalPower());
// Serial.print("\tDistance: ");
// Serial.println(distance);
int major = ENDIAN_CHANGE_U16(oBeacon.getMajor()); int major = ENDIAN_CHANGE_U16(oBeacon.getMajor());
int minor = ENDIAN_CHANGE_U16(oBeacon.getMinor()); int minor = ENDIAN_CHANGE_U16(oBeacon.getMinor());
Serial.print(", iBeacon: ");
Serial.print(proximityUUID);
Serial.printf("-%d-%d", major, minor);
doc["major"] = major; doc["major"] = major;
doc["minor"] = minor; doc["minor"] = minor;
doc["uuid"] = proximityUUID;
doc["id"] = proximityUUID + "-" + String(major) + "-" + String(minor); doc["id"] = proximityUUID + "-" + String(major) + "-" + String(minor);
doc["txPower"] = oBeacon.getSignalPower(); doc["txPower"] = oBeacon.getSignalPower();
doc["distance"] = distance; doc["distance"] = calcDistance(rssi, oBeacon.getSignalPower());
}
} else { else
{
if (advertisedDevice.haveTXPower()) { if (advertisedDevice.haveTXPower())
distance = calculateDistance(rssi, advertisedDevice.getTXPower());
doc["txPower"] = advertisedDevice.getTXPower(); doc["txPower"] = advertisedDevice.getTXPower();
} else { doc["distance"] = calcDistance(rssi, advertisedDevice.haveTXPower() ? advertisedDevice.getTXPower() - 41 : 0);
distance = calculateDistance(rssi, defaultTxPower);
Serial.print(", MD: ");
for (int x = 0; x < strManufacturerData.length(); x++)
Serial.print(strManufacturerData[x], HEX);
} }
doc["distance"] = distance;
// Serial.printf("strManufacturerData: %d \n\r",strManufacturerData.length());
// TODO: parse manufacturer data
} }
} else { else
{
if (advertisedDevice.haveTXPower()) { if (advertisedDevice.haveTXPower())
distance = calculateDistance(rssi, advertisedDevice.getTXPower());
doc["txPower"] = advertisedDevice.getTXPower(); doc["txPower"] = advertisedDevice.getTXPower();
doc["distance"] = distance; doc["distance"] = calcDistance(rssi, advertisedDevice.haveTXPower() ? -advertisedDevice.getTXPower() - 41 : 0);
} else { }
distance = calculateDistance(rssi, defaultTxPower);
doc["distance"] = distance;
} }
// Serial.printf("no Beacon Advertised ServiceDataUUID: %d %s \n\r", advertisedDevice.getServiceDataUUID().bitSize(), advertisedDevice.getServiceDataUUID().toString().c_str()); Serial.println();
}
}
char JSONmessageBuffer[512]; char JSONmessageBuffer[512];
serializeJson(doc, JSONmessageBuffer); serializeJson(doc, JSONmessageBuffer);
String id = doc["id"];
String publishTopic = String(channel) + "/" + room; String publishTopic = String(channel) + "/" + room;
String publishTopic2 = (String(channel) + "/" + room + "/") + id;
if (mqttClient.connected()) { if (mqttClient.connected())
if (maxDistance == 0 || doc["distance"] < maxDistance) { {
if (mqttClient.publish((char *)publishTopic.c_str(), 0, 0, JSONmessageBuffer) == true) { if (maxDistance == 0 || doc["distance"] < maxDistance)
{
// Serial.print("Success sending message to topic: "); Serial.println(publishTopic); if (mqttClient.publish((char *)publishTopic.c_str(), 0, 0, JSONmessageBuffer) == true)
return true; {
return (mqttClient.publish((char *)publishTopic2.c_str(), 0, 0, JSONmessageBuffer) == true);
} else { }
else
{
Serial.print("Error sending message: "); Serial.print("Error sending message: ");
Serial.println(publishTopic); Serial.println(publishTopic);
Serial.print("Message: "); Serial.print("Message: ");
Serial.println(JSONmessageBuffer); Serial.println(JSONmessageBuffer);
return false; return false;
} }
} else { }
Serial.printf("%s exceeded distance threshold %.2f\n\r", mac_address.c_str(), distance); else
{
//Serial.printf("%s exceeded distance threshold %.2f\n\r", mac_address.c_str(), distance);
return false; return false;
} }
}
} else { else
{
Serial.println("MQTT disconnected."); Serial.println("MQTT disconnected.");
if (xTimerIsTimerActive(mqttReconnectTimer) != pdFALSE) { if (xTimerIsTimerActive(mqttReconnectTimer) != pdFALSE)
TickType_t xRemainingTime = xTimerGetExpiryTime( mqttReconnectTimer ) - xTaskGetTickCount(); {
TickType_t xRemainingTime = xTimerGetExpiryTime(mqttReconnectTimer) - xTaskGetTickCount();
Serial.print("Time remaining: "); Serial.print("Time remaining: ");
Serial.println(xRemainingTime); Serial.println(xRemainingTime);
} else { }
else
{
handleMqttDisconnect(); handleMqttDisconnect();
} }
} }
return false; return false;
} }
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
{
void onResult(BLEAdvertisedDevice advertisedDevice) { void onResult(BLEAdvertisedDevice advertisedDevice)
{
Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
digitalWrite(LED_BUILTIN, LED_ON); digitalWrite(LED_BUILTIN, LED_ON);
vTaskDelay(10 / portTICK_PERIOD_MS); vTaskDelay(10 / portTICK_PERIOD_MS);
digitalWrite(LED_BUILTIN, !LED_ON); digitalWrite(LED_BUILTIN, !LED_ON);
} }
}; };
void scanForDevices(void * parameter) { void scanForDevices(void *parameter)
while(1) { {
if (!updateInProgress && WiFi.isConnected() && (millis() - last > (waitTime * 1000) || last == 0)) { while (1)
{
if (!updateInProgress && WiFi.isConnected() && (millis() - last > (waitTime * 1000) || last == 0))
{
Serial.print("Scanning...\t"); Serial.print("Scanning...\t");
BLEScanResults foundDevices = pBLEScan->start(scanTime); BLEScanResults foundDevices = pBLEScan->start(scanTime);
int devicesCount = foundDevices.getCount(); int devicesCount = foundDevices.getCount();
Serial.printf("Scan done! Devices found: %d\n\r",devicesCount); Serial.printf("Scan done! Devices found: %d\n\r", devicesCount);
int devicesReported = 0; int devicesReported = 0;
if (mqttClient.connected()) { if (mqttClient.connected())
for (uint32_t i = 0; i < devicesCount; i++) { {
for (uint32_t i = 0; i < devicesCount; i++)
{
bool included = reportDevice(foundDevices.getDevice(i)); bool included = reportDevice(foundDevices.getDevice(i));
if (included) { if (included)
{
devicesReported++; devicesReported++;
} }
} }
sendTelemetry(devicesCount, devicesReported); sendTelemetry(devicesCount, devicesReported);
pBLEScan->clearResults(); pBLEScan->clearResults();
} else { }
else
{
Serial.println("Cannot report; mqtt disconnected"); Serial.println("Cannot report; mqtt disconnected");
if (xTimerIsTimerActive(mqttReconnectTimer) != pdFALSE) { if (xTimerIsTimerActive(mqttReconnectTimer) != pdFALSE)
TickType_t xRemainingTime = xTimerGetExpiryTime( mqttReconnectTimer ) - xTaskGetTickCount(); {
TickType_t xRemainingTime = xTimerGetExpiryTime(mqttReconnectTimer) - xTaskGetTickCount();
Serial.print("Time remaining: "); Serial.print("Time remaining: ");
Serial.println(xRemainingTime); Serial.println(xRemainingTime);
} else { }
else
{
handleMqttDisconnect(); handleMqttDisconnect();
} }
} }
@ -538,7 +599,8 @@ void scanForDevices(void * parameter) {
} }
} }
void configureOTA() { void configureOTA()
{
ArduinoOTA ArduinoOTA
.onStart([]() { .onStart([]() {
Serial.println("OTA Start"); Serial.println("OTA Start");
@ -554,16 +616,21 @@ void configureOTA() {
}) })
.onProgress([](unsigned int progress, unsigned int total) { .onProgress([](unsigned int progress, unsigned int total) {
byte percent = (progress / (total / 100)); byte percent = (progress / (total / 100));
Serial.printf("Progress: %u% \n\r", percent); Serial.printf("Progress: %u\r\n", percent);
digitalWrite(LED_BUILTIN, percent % 2); digitalWrite(LED_BUILTIN, percent % 2);
}) })
.onError([](ota_error_t error) { .onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error); Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); if (error == OTA_AUTH_ERROR)
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); Serial.println("Auth Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); else if (error == OTA_BEGIN_ERROR)
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); Serial.println("Begin Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed"); else if (error == OTA_CONNECT_ERROR)
Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR)
Serial.println("Receive Failed");
else if (error == OTA_END_ERROR)
Serial.println("End Failed");
ESP.restart(); ESP.restart();
}); });
ArduinoOTA.setHostname(hostname); ArduinoOTA.setHostname(hostname);
@ -571,19 +638,20 @@ void configureOTA() {
ArduinoOTA.begin(); ArduinoOTA.begin();
} }
void setup() { void setup()
{
Serial.begin(115200); Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LED_ON); digitalWrite(LED_BUILTIN, LED_ON);
mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt)); mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void *)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
wifiReconnectTimer = xTimerCreate("wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToWifi)); wifiReconnectTimer = xTimerCreate("wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void *)0, reinterpret_cast<TimerCallbackFunction_t>(connectToWifi));
#ifdef htuSensorTopic #ifdef htuSensorTopic
sensor_setup(); sensor_setup();
#endif #endif
WiFi.onEvent(WiFiEvent); WiFi.onEvent(WiFiEvent);
@ -600,7 +668,7 @@ void setup() {
BLEDevice::init(""); BLEDevice::init("");
pBLEScan = BLEDevice::getScan(); //create new scan pBLEScan = BLEDevice::getScan(); //create new scan
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); //pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks(), true, true);
pBLEScan->setActiveScan(activeScan); pBLEScan->setActiveScan(activeScan);
pBLEScan->setInterval(bleScanInterval); pBLEScan->setInterval(bleScanInterval);
pBLEScan->setWindow(bleScanWindow); pBLEScan->setWindow(bleScanWindow);
@ -613,12 +681,21 @@ void setup() {
1, 1,
&BLEScan, &BLEScan,
1); 1);
} }
void loop() { void loop()
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; {
TIMERG0.wdt_feed=1; TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
TIMERG0.wdt_wprotect=0; TIMERG0.wdt_feed = 1;
TIMERG0.wdt_wprotect = 0;
ArduinoOTA.handle(); ArduinoOTA.handle();
} }
typedef struct
{
uint8_t frameType; // UID
int8_t txpower;
uint8_t namespaceID[10];
uint8_t instanceID[6];
uint8_t reserved[2];
} eddystoneUID_t;