#include "PresenceDetection.h" #include "PreferencesKeys.h" #include "Logger.h" #include "CharBuffer.h" #include #include #include "NimBLEBeacon.h" #include "NukiUtils.h" PresenceDetection::PresenceDetection(Preferences* preferences, BleScanner::Scanner *bleScanner, Network* network, char* buffer, size_t bufferSize) : _preferences(preferences), _bleScanner(bleScanner), _network(network), _csv(buffer), _bufferSize(bufferSize) { _timeout = _preferences->getInt(preference_presence_detection_timeout) * 1000; if(_timeout == 0) { _timeout = 60000; _preferences->putInt(preference_presence_detection_timeout, 60); } Log->print(F("Presence detection timeout (ms): ")); Log->println(_timeout); } PresenceDetection::~PresenceDetection() { _bleScanner->unsubscribe(this); _bleScanner = nullptr; _network = nullptr; delete _csv; _csv = nullptr; } void PresenceDetection::initialize() { _bleScanner->subscribe(this); } void PresenceDetection::update() { delay(3000); if(_timeout < 0) return; memset(_csv, 0, _bufferSize); if(_devices.size() == 0) { strcpy(_csv, ";;"); _network->publishPresenceDetection(_csv); return; } _csvIndex = 0; long ts = millis(); for(auto it : _devices) { if(ts - _timeout < it.second.timestamp) { buildCsv(it.second); } // Prevent csv buffer overflow if(_csvIndex > _bufferSize - (sizeof(it.second.name) + sizeof(it.second.address) + 10)) { break; } } _csv[_csvIndex-1] = 0x00; // Log->print("Devices found: "); // Log->println(_devices.size()); _network->publishPresenceDetection(_csv); } void PresenceDetection::buildCsv(const PdDevice &device) { for(int i = 0; i < 17; i++) { _csv[_csvIndex] = device.address[i]; ++_csvIndex; } _csv[_csvIndex] = ';'; ++_csvIndex; int i=0; while(device.name[i] != 0x00 && i < sizeof(device.name)) { _csv[_csvIndex] = device.name[i]; ++_csvIndex; ++i; } _csv[_csvIndex] = ';'; ++_csvIndex; if(device.hasRssi) { char rssiStr[20] = {0}; itoa(device.rssi, rssiStr, 10); int i=0; while(rssiStr[i] != 0x00 && i < 20) { _csv[_csvIndex] = rssiStr[i]; ++_csvIndex; ++i; } } _csv[_csvIndex] = '\n'; _csvIndex++; } void PresenceDetection::onResult(NimBLEAdvertisedDevice *device) { std::string addressStr = device->getAddress().toString(); char addrArrComp[13] = {0}; // Log->println(addressStr.c_str()); addrArrComp[0] = addressStr.at(0); addrArrComp[1] = addressStr.at(1); addrArrComp[2] = addressStr.at(3); addrArrComp[3] = addressStr.at(4); addrArrComp[4] = addressStr.at(6); addrArrComp[5] = addressStr.at(7); addrArrComp[6] = addressStr.at(9); addrArrComp[7] = addressStr.at(10); addrArrComp[8] = addressStr.at(12); addrArrComp[9] = addressStr.at(13); addrArrComp[10] = addressStr.at(15); addrArrComp[11] = addressStr.at(16); long long addr = strtoll(addrArrComp, nullptr, 16); auto it = _devices.find(addr); if(it == _devices.end()) { PdDevice pdDevice; int i=0; size_t len = addressStr.length(); while(i < len) { pdDevice.address[i] = addressStr.at(i); ++i; } if(device->haveRSSI()) { pdDevice.hasRssi = true; pdDevice.rssi = device->getRSSI(); } std::string nameStr = "-"; if(device->haveName()) { std::string nameStr = device->getName(); i=0; len = nameStr.length(); while(i < len && i < sizeof(pdDevice.name)-1) { pdDevice.name[i] = nameStr.at(i); ++i; } pdDevice.timestamp = millis(); _devices[addr] = pdDevice; } else if (device->haveManufacturerData()) { std::string strManufacturerData = device->getManufacturerData(); uint8_t cManufacturerData[100]; strManufacturerData.copy((char *)cManufacturerData, std::min(strManufacturerData.length(), sizeof(cManufacturerData)), 0); if (strManufacturerData.length() == 25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00) { BLEBeacon oBeacon = BLEBeacon(); oBeacon.setData(strManufacturerData); if(ENDIAN_CHANGE_U16(oBeacon.getMinor()) == 40004) { pdDevice.timestamp = millis(); strcpy(pdDevice.name, oBeacon.getProximityUUID().toString().c_str()); _devices[addr] = pdDevice; } } } } else { it->second.timestamp = millis(); if(device->haveRSSI()) { it->second.hasRssi = true; it->second.rssi = device->getRSSI(); } } // if(device->haveName()) // { // Log->print(" | "); // Log->print(device->getName().c_str()); // if(device->haveRSSI()) // { // Log->print(" | "); // Log->print(device->getRSSI()); // } // } // Log->println(); }