2022-10-31 10:45:00 +03:00
|
|
|
|
#include "Global.h"
|
|
|
|
|
|
#include "classes/IoTItem.h"
|
|
|
|
|
|
#include <Arduino.h>
|
|
|
|
|
|
#include <NimBLEDevice.h>
|
2023-11-15 21:54:02 +03:00
|
|
|
|
#define BLE_PART1
|
|
|
|
|
|
#define BLE_PART2
|
2022-10-31 10:45:00 +03:00
|
|
|
|
#include <decoder.h>
|
2023-10-28 19:58:45 +03:00
|
|
|
|
#include <vector>
|
2022-10-31 10:45:00 +03:00
|
|
|
|
|
|
|
|
|
|
// Создаем переменную для хранения данных с датчиков bluetooth
|
2023-10-28 19:58:45 +03:00
|
|
|
|
// StaticJsonDocument<JSON_BUFFER_SIZE * 4> BLEbuffer;
|
|
|
|
|
|
// DynamicJsonDocument extBLEdata(JSON_BUFFER_SIZE * 4);
|
|
|
|
|
|
// JsonObject extBLEdata = BLEbuffer.to<JsonObject>();
|
|
|
|
|
|
class BleSens;
|
|
|
|
|
|
std::vector<BleSens *> BleSensArray;
|
2022-10-31 10:45:00 +03:00
|
|
|
|
|
2023-10-28 19:58:45 +03:00
|
|
|
|
class BleSens : public IoTItem
|
|
|
|
|
|
{
|
|
|
|
|
|
private:
|
|
|
|
|
|
// описание параметров передаваемых из настроек датчика из веба
|
|
|
|
|
|
String _MAC;
|
|
|
|
|
|
String _sensor;
|
2023-10-31 22:03:33 +03:00
|
|
|
|
int timeRecv = 0;
|
|
|
|
|
|
int _minutesPassed = 0;
|
|
|
|
|
|
String json = "{}";
|
|
|
|
|
|
int orange = 0;
|
|
|
|
|
|
int red = 0;
|
|
|
|
|
|
int offline = 0;
|
|
|
|
|
|
int _int;
|
|
|
|
|
|
bool dataFromNode = false;
|
|
|
|
|
|
|
2023-10-28 19:58:45 +03:00
|
|
|
|
public:
|
|
|
|
|
|
String whoIAm(/*String &mac, String &sens*/)
|
|
|
|
|
|
{
|
|
|
|
|
|
// mac = _MAC;
|
|
|
|
|
|
// sens = _sensor;
|
|
|
|
|
|
return _MAC;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void setBLEdata(JsonObject extBLEdata)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_sensor == "last")
|
|
|
|
|
|
{
|
2023-10-28 22:12:15 +03:00
|
|
|
|
timeRecv = extBLEdata[_sensor].as<int>();
|
2023-10-28 19:58:45 +03:00
|
|
|
|
char *s;
|
2023-10-28 22:12:15 +03:00
|
|
|
|
s = TimeToString(millis() / 1000 - timeRecv / 1000);
|
2023-10-28 19:58:45 +03:00
|
|
|
|
value.isDecimal = 0;
|
2023-10-28 22:12:15 +03:00
|
|
|
|
if (timeRecv > 0)
|
2023-10-28 19:58:45 +03:00
|
|
|
|
{
|
|
|
|
|
|
value.valS = s;
|
2023-10-31 22:03:33 +03:00
|
|
|
|
dataFromNode = true;
|
|
|
|
|
|
_minutesPassed = 0;
|
|
|
|
|
|
setNewWidgetAttributes();
|
2023-10-28 19:58:45 +03:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
value.valS = "";
|
|
|
|
|
|
}
|
|
|
|
|
|
regEvent(value.valS, _id);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
String valStr = extBLEdata[_sensor].as<String>();
|
|
|
|
|
|
if (valStr != "null")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (value.isDecimal == isDigitDotCommaStr(valStr))
|
|
|
|
|
|
{
|
|
|
|
|
|
value.isDecimal = 1;
|
|
|
|
|
|
value.valD = valStr.toFloat();
|
|
|
|
|
|
regEvent(value.valD, _id);
|
2023-10-31 22:03:33 +03:00
|
|
|
|
dataFromNode = true;
|
|
|
|
|
|
_minutesPassed = 0;
|
|
|
|
|
|
setNewWidgetAttributes();
|
2023-10-28 19:58:45 +03:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
value.isDecimal = 0;
|
|
|
|
|
|
value.valS = valStr;
|
|
|
|
|
|
regEvent(value.valS, _id);
|
2023-10-31 22:03:33 +03:00
|
|
|
|
dataFromNode = true;
|
|
|
|
|
|
_minutesPassed = 0;
|
|
|
|
|
|
setNewWidgetAttributes();
|
2023-10-28 19:58:45 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
char *TimeToString(unsigned long t)
|
|
|
|
|
|
{
|
|
|
|
|
|
static char str[12];
|
|
|
|
|
|
long h = t / 3600;
|
|
|
|
|
|
t = t % 3600;
|
|
|
|
|
|
int m = t / 60;
|
|
|
|
|
|
int s = t % 60;
|
|
|
|
|
|
sprintf(str, "%02ld:%02d:%02d", h, m, s);
|
|
|
|
|
|
return str;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-10-28 22:12:15 +03:00
|
|
|
|
void doByInterval()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_sensor == "last")
|
|
|
|
|
|
{
|
|
|
|
|
|
char *s;
|
|
|
|
|
|
s = TimeToString(millis() / 1000 - timeRecv / 1000);
|
|
|
|
|
|
value.isDecimal = 0;
|
|
|
|
|
|
if (timeRecv > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
value.valS = s;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
value.valS = "";
|
|
|
|
|
|
}
|
|
|
|
|
|
regEvent(value.valS, _id);
|
|
|
|
|
|
}
|
2023-10-31 22:03:33 +03:00
|
|
|
|
_minutesPassed++;
|
|
|
|
|
|
setNewWidgetAttributes();
|
|
|
|
|
|
}
|
|
|
|
|
|
void onMqttWsAppConnectEvent()
|
|
|
|
|
|
{
|
|
|
|
|
|
setNewWidgetAttributes();
|
|
|
|
|
|
}
|
|
|
|
|
|
void setNewWidgetAttributes()
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
int minutes_ = _minutesPassed * _int / 60;
|
|
|
|
|
|
jsonWriteStr(json, F("info"), prettyMinutsTimeout(minutes_));
|
|
|
|
|
|
if (dataFromNode)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (orange != 0 && red != 0 && offline != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (minutes_ < orange)
|
|
|
|
|
|
{
|
|
|
|
|
|
jsonWriteStr(json, F("color"), "");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (minutes_ >= orange && minutes_ < red)
|
|
|
|
|
|
{
|
|
|
|
|
|
jsonWriteStr(json, F("color"), F("orange")); // сделаем виджет оранжевым
|
|
|
|
|
|
}
|
|
|
|
|
|
if (minutes_ >= red && minutes_ < offline)
|
|
|
|
|
|
{
|
|
|
|
|
|
jsonWriteStr(json, F("color"), F("red")); // сделаем виджет красным
|
|
|
|
|
|
}
|
|
|
|
|
|
if (minutes_ >= offline)
|
|
|
|
|
|
{
|
|
|
|
|
|
jsonWriteStr(json, F("info"), F("offline"));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
jsonWriteStr(json, F("info"), F("awaiting"));
|
|
|
|
|
|
}
|
|
|
|
|
|
sendSubWidgetsValues(_id, json);
|
2023-10-28 22:12:15 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-10-28 19:58:45 +03:00
|
|
|
|
BleSens(String parameters) : IoTItem(parameters)
|
|
|
|
|
|
{
|
|
|
|
|
|
_MAC = jsonReadStr(parameters, "MAC");
|
|
|
|
|
|
_sensor = jsonReadStr(parameters, "sensor");
|
2023-10-31 22:03:33 +03:00
|
|
|
|
jsonRead(parameters, F("orange"), orange);
|
|
|
|
|
|
jsonRead(parameters, F("red"), red);
|
|
|
|
|
|
jsonRead(parameters, F("offline"), offline);
|
|
|
|
|
|
jsonRead(parameters, F("int"), _int);
|
|
|
|
|
|
dataFromNode = false;
|
2023-10-28 19:58:45 +03:00
|
|
|
|
BleSensArray.push_back(this);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
~BleSens(){};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//=======================================================================================================
|
|
|
|
|
|
|
|
|
|
|
|
/** Callback to process the results of the last scan or restart it */
|
|
|
|
|
|
void scanEndedCB(NimBLEScanResults results)
|
|
|
|
|
|
{
|
|
|
|
|
|
int count = results.getCount();
|
|
|
|
|
|
SerialPrint("i", F("BLE"), "Scan done! "); // +"Devices found: " + String(count));
|
|
|
|
|
|
// pBLEScan->clearResults();
|
|
|
|
|
|
}
|
2022-10-31 10:45:00 +03:00
|
|
|
|
|
|
|
|
|
|
class BleScan : public IoTItem, BLEAdvertisedDeviceCallbacks
|
|
|
|
|
|
{
|
|
|
|
|
|
private:
|
2023-10-28 19:58:45 +03:00
|
|
|
|
// описание параметров передаваемых из настроек датчика из веба
|
2022-10-31 10:45:00 +03:00
|
|
|
|
int _scanDuration;
|
|
|
|
|
|
String _filter;
|
2023-10-28 19:58:45 +03:00
|
|
|
|
bool _debug;
|
|
|
|
|
|
|
|
|
|
|
|
StaticJsonDocument<512> doc;
|
|
|
|
|
|
BLEScan *pBLEScan;
|
|
|
|
|
|
TheengsDecoder decoder;
|
2022-10-31 10:45:00 +03:00
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
std::string convertServiceData(std::string deviceServiceData)
|
|
|
|
|
|
{
|
|
|
|
|
|
int serviceDataLength = (int)deviceServiceData.length();
|
|
|
|
|
|
char spr[2 * serviceDataLength + 1];
|
|
|
|
|
|
for (int i = 0; i < serviceDataLength; i++)
|
|
|
|
|
|
sprintf(spr + 2 * i, "%.2x", (unsigned char)deviceServiceData[i]);
|
|
|
|
|
|
spr[2 * serviceDataLength] = 0;
|
|
|
|
|
|
return spr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void onResult(BLEAdvertisedDevice *advertisedDevice)
|
|
|
|
|
|
{
|
|
|
|
|
|
JsonObject BLEdata = doc.to<JsonObject>();
|
|
|
|
|
|
String mac_adress_ = advertisedDevice->getAddress().toString().c_str();
|
|
|
|
|
|
mac_adress_.toUpperCase();
|
|
|
|
|
|
BLEdata["id"] = (char *)mac_adress_.c_str();
|
|
|
|
|
|
|
|
|
|
|
|
if (advertisedDevice->haveName())
|
|
|
|
|
|
{
|
|
|
|
|
|
BLEdata["name"] = (char *)advertisedDevice->getName().c_str();
|
|
|
|
|
|
}
|
|
|
|
|
|
if (advertisedDevice->haveManufacturerData())
|
|
|
|
|
|
{
|
|
|
|
|
|
char *manufacturerdata = BLEUtils::buildHexData(NULL, (uint8_t *)advertisedDevice->getManufacturerData().data(), advertisedDevice->getManufacturerData().length());
|
|
|
|
|
|
BLEdata["manufacturerdata"] = manufacturerdata;
|
|
|
|
|
|
free(manufacturerdata);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (advertisedDevice->haveRSSI())
|
|
|
|
|
|
BLEdata["rssi"] = (int)advertisedDevice->getRSSI();
|
|
|
|
|
|
if (advertisedDevice->haveTXPower())
|
|
|
|
|
|
BLEdata["txpower"] = (int8_t)advertisedDevice->getTXPower();
|
|
|
|
|
|
if (advertisedDevice->haveServiceData())
|
|
|
|
|
|
{
|
|
|
|
|
|
int serviceDataCount = advertisedDevice->getServiceDataCount();
|
|
|
|
|
|
for (int j = 0; j < serviceDataCount; j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
std::string service_data = convertServiceData(advertisedDevice->getServiceData(j));
|
|
|
|
|
|
BLEdata["servicedata"] = (char *)service_data.c_str();
|
|
|
|
|
|
std::string serviceDatauuid = advertisedDevice->getServiceDataUUID(j).toString();
|
|
|
|
|
|
BLEdata["servicedatauuid"] = (char *)serviceDatauuid.c_str();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (decoder.decodeBLEJson(BLEdata))
|
|
|
|
|
|
{
|
2023-11-15 21:54:02 +03:00
|
|
|
|
String mac_address = BLEdata["mac"].as<const char *>();
|
2023-11-13 23:36:40 +03:00
|
|
|
|
if (mac_address == "")
|
|
|
|
|
|
{
|
2023-11-15 21:54:02 +03:00
|
|
|
|
BLEdata["mac"] = BLEdata["id"];
|
2023-11-13 23:36:40 +03:00
|
|
|
|
mac_address = BLEdata["id"].as<const char *>();
|
|
|
|
|
|
}
|
|
|
|
|
|
mac_address.replace(":", "");
|
|
|
|
|
|
|
2023-11-15 21:54:02 +03:00
|
|
|
|
if (_debug < 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
BLEdata.remove("manufacturerdata");
|
|
|
|
|
|
BLEdata.remove("servicedata");
|
|
|
|
|
|
BLEdata.remove("type");
|
|
|
|
|
|
BLEdata.remove("cidc");
|
|
|
|
|
|
BLEdata.remove("acts");
|
|
|
|
|
|
BLEdata.remove("cont");
|
|
|
|
|
|
BLEdata.remove("track");
|
|
|
|
|
|
BLEdata.remove("id");
|
|
|
|
|
|
}
|
2023-10-28 19:58:45 +03:00
|
|
|
|
// дописываем время прихода пакета данных
|
|
|
|
|
|
BLEdata["last"] = millis();
|
|
|
|
|
|
if (_debug)
|
2022-10-31 10:45:00 +03:00
|
|
|
|
{
|
2023-10-28 19:58:45 +03:00
|
|
|
|
if ((_filter != "" && BLEdata[_filter]) || _filter == "")
|
2022-10-31 10:45:00 +03:00
|
|
|
|
{
|
2023-10-28 19:58:45 +03:00
|
|
|
|
// for (JsonPair kv : BLEdata)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// String val = BLEdata.as<String>();
|
|
|
|
|
|
String output;
|
2023-11-15 21:54:02 +03:00
|
|
|
|
if (_debug < 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
BLEdata.remove("servicedatauuid");
|
|
|
|
|
|
}
|
2023-10-28 19:58:45 +03:00
|
|
|
|
serializeJson(BLEdata, output);
|
2023-10-31 22:03:33 +03:00
|
|
|
|
SerialPrint("i", F("BLE"), mac_address + " " + output);
|
2023-10-28 19:58:45 +03:00
|
|
|
|
//}
|
2022-10-31 10:45:00 +03:00
|
|
|
|
}
|
2023-10-31 22:03:33 +03:00
|
|
|
|
|
2023-11-15 21:54:02 +03:00
|
|
|
|
SerialPrint("i", F("BLE"), "found: " + String(BLEdata["mac"].as<const char *>()));
|
2022-10-31 10:45:00 +03:00
|
|
|
|
}
|
2023-10-31 22:03:33 +03:00
|
|
|
|
|
2023-10-28 19:58:45 +03:00
|
|
|
|
// Перебираем все зарегистрированные сенсоры BleSens
|
|
|
|
|
|
for (std::vector<BleSens *>::iterator it = BleSensArray.begin();
|
|
|
|
|
|
it != BleSensArray.end(); ++it)
|
2022-10-31 10:45:00 +03:00
|
|
|
|
{
|
2023-10-28 19:58:45 +03:00
|
|
|
|
// Если это данные для нужного сенсора (по его МАКУ)
|
|
|
|
|
|
if ((*it)->whoIAm() == mac_address)
|
|
|
|
|
|
// то передаем ему json, дальше он сам разберется
|
|
|
|
|
|
(*it)->setBLEdata(BLEdata);
|
2022-10-31 10:45:00 +03:00
|
|
|
|
}
|
2023-10-28 19:58:45 +03:00
|
|
|
|
}
|
2022-10-31 10:45:00 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BleScan(String parameters) : IoTItem(parameters)
|
|
|
|
|
|
{
|
|
|
|
|
|
_scanDuration = jsonReadInt(parameters, "scanDuration");
|
|
|
|
|
|
_filter = jsonReadStr(parameters, "filter");
|
2023-10-28 19:58:45 +03:00
|
|
|
|
jsonRead(parameters, "debug", _debug);
|
|
|
|
|
|
|
|
|
|
|
|
BLEDevice::init("");
|
|
|
|
|
|
pBLEScan = BLEDevice::getScan(); // create new scan
|
|
|
|
|
|
pBLEScan->setAdvertisedDeviceCallbacks(this);
|
|
|
|
|
|
pBLEScan->setActiveScan(false); // active scan uses more power, but get results faster
|
|
|
|
|
|
pBLEScan->setInterval(100);
|
|
|
|
|
|
pBLEScan->setWindow(99); // less or equal setInterval value
|
|
|
|
|
|
pBLEScan->setMaxResults(0); // do not store the scan results, use callback only.
|
2022-10-31 10:45:00 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// doByInterval()
|
|
|
|
|
|
void doByInterval()
|
|
|
|
|
|
{
|
2023-10-28 19:58:45 +03:00
|
|
|
|
if (pBLEScan->isScanning() == false)
|
2022-10-31 10:45:00 +03:00
|
|
|
|
{
|
2023-10-28 19:58:45 +03:00
|
|
|
|
if (_scanDuration > 0)
|
2022-10-31 10:45:00 +03:00
|
|
|
|
{
|
2023-10-28 19:58:45 +03:00
|
|
|
|
SerialPrint("i", F("BLE"), "Start Scanning...");
|
|
|
|
|
|
pBLEScan->start(_scanDuration, scanEndedCB, false);
|
2022-10-31 10:45:00 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-10-28 19:58:45 +03:00
|
|
|
|
}
|
2022-10-31 10:45:00 +03:00
|
|
|
|
|
2023-10-31 22:03:33 +03:00
|
|
|
|
~BleScan() { BleSensArray.clear(); };
|
2022-10-31 10:45:00 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
2023-10-28 19:58:45 +03:00
|
|
|
|
//=======================================================================================================
|
2022-10-31 10:45:00 +03:00
|
|
|
|
|
|
|
|
|
|
void *getAPI_Ble(String subtype, String param)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (subtype == F("BleScan"))
|
|
|
|
|
|
{
|
|
|
|
|
|
return new BleScan(param);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (subtype == F("BleSens"))
|
|
|
|
|
|
{
|
|
|
|
|
|
return new BleSens(param);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
2023-10-31 22:03:33 +03:00
|
|
|
|
}
|