diff --git a/CHANGELOG.md b/CHANGELOG.md index 91ed6220..30d50fc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added blocking for shifts above or below min/max set points. - Added power scaler for new board. - Added Main Index link to develop.html. +- Added feature to automatically reconnect BLE devices if both are specified. ### Changed - PowerTable values are now adjusted to 90 RPM cad on input. diff --git a/data/bluetoothscanner.html b/data/bluetoothscanner.html index f80cfb6b..403f4c48 100644 --- a/data/bluetoothscanner.html +++ b/data/bluetoothscanner.html @@ -123,7 +123,7 @@

var t_obj = JSON.parse(data.foundDevices) { for (var key in t_obj) { - if (t_obj[key].UUID == '0x1818' || t_obj[key].UUID == '0x1826') { + if (t_obj[key].UUID == '0x1818' || t_obj[key].UUID == '0x1826' || t_obj[key].UUID == '6e400001-b5a3-f393-e0a9-e50e24dcca9e' || t_obj[key].UUID == '0bf669f0-45f2-11e7-9598-0800200c9a66') { optionPM = document.createElement('option'); if (t_obj[key].name) { optionPM.text = t_obj[key].name; @@ -152,18 +152,24 @@

} } - optionPM = document.createElement('option'); - optionPM.text = 'none'; - PMDropdown.add(optionPM); - optionHR = document.createElement('option'); - optionHR.text = 'none'; - HRDropdown.add(optionHR); - let defaultOptionPM = document.createElement('option'); - defaultOptionPM.text = 'any'; - let defaultOptionHR = document.createElement('option'); - defaultOptionHR.text = 'any'; - PMDropdown.add(defaultOptionPM); - HRDropdown.add(defaultOptionHR); + let connectedOptionPM = document.createElement('option'); + connectedOptionPM.text = data.connectedPowerMeter; + let connectedOptionHR = document.createElement('option'); + connectedOptionHR.text = data.connectedHeartMonitor; + PMDropdown.add(connectedOptionPM); + HRDropdown.add(connectedOptionHR); + let anyOptionPM = document.createElement('option'); + anyOptionPM.text = 'any'; + let anyOptionHR = document.createElement('option'); + anyOptionHR.text = 'any'; + PMDropdown.add(anyOptionPM); + HRDropdown.add(anyOptionHR); + let noneOptionPM = document.createElement('option'); + noneOptionPM.text = 'none'; + let noneOptionHR = document.createElement('option'); + noneOptionHR.text = 'none'; + PMDropdown.add(noneOptionPM); + HRDropdown.add(noneOptionHR); document.getElementById("connectedPowerMeter").innerHTML = data.connectedPowerMeter; document.getElementById("connectedHeartMonitor").innerHTML = data.connectedHeartMonitor; document.getElementById("powerCorrectionFactorValue").innerHTML = data.powerCorrectionFactor; diff --git a/include/BLE_Common.h b/include/BLE_Common.h index 175075ce..b48b590e 100644 --- a/include/BLE_Common.h +++ b/include/BLE_Common.h @@ -212,7 +212,7 @@ class SpinBLEClient { void start(); void serverScan(bool connectRequest); bool connectToServer(); - void scanProcess(); + void scanProcess(int duration = DEFAULT_SCAN_DURATION); void disconnect(); // Check for duplicate services of BLEClient and remove the previously // connected one. diff --git a/include/Main.h b/include/Main.h index 4c171b50..3e9919db 100644 --- a/include/Main.h +++ b/include/Main.h @@ -51,6 +51,7 @@ class SS2K { void checkDriverTemperature(); void motorStop(bool releaseTension = false); void checkSerial(); + void checkBLEReconnect(); SS2K() { targetPosition = 0; diff --git a/include/SmartSpin_parameters.h b/include/SmartSpin_parameters.h index c5cb6924..941e265d 100644 --- a/include/SmartSpin_parameters.h +++ b/include/SmartSpin_parameters.h @@ -126,8 +126,8 @@ class userParameters { bool getAutoUpdate() { return autoUpdate; } const char* getSsid() { return ssid.c_str(); } const char* getPassword() { return password.c_str(); } - const char* getconnectedPowerMeter() { return connectedPowerMeter.c_str(); } - const char* getconnectedHeartMonitor() { return connectedHeartMonitor.c_str(); } + const char* getConnectedPowerMeter() { return connectedPowerMeter.c_str(); } + const char* getConnectedHeartMonitor() { return connectedHeartMonitor.c_str(); } int getStepperPower() { return stepperPower; } int getMaxWatts() { return maxWatts; } int getMinWatts() { return minWatts; } diff --git a/include/settings.h b/include/settings.h index 9353e080..a096fa18 100644 --- a/include/settings.h +++ b/include/settings.h @@ -245,6 +245,15 @@ // If not receiving Peleton Messages, how long to wait before next TX attempt is #define TX_CHECK_INTERVAL 20 +// If ble devices are both setup, how often to attempt a reconnect. +#define BLE_RECONNECT_INTERVAL 40 + +// Initial and web scan duration. +#define DEFAULT_SCAN_DURATION 10 + +// BLE automatic reconnect duration. Set this low to avoid interruption. +#define BLE_RECONNECT_SCAN_DURATION 3 + // Uncomment to enable sending Telegram debug messages back to the chat // specified in telegram_token.h // #define USE_TELEGRAM @@ -253,8 +262,11 @@ //#define DEBUG_STACK // Uncomment to enable HR->PWR debugging info. Always displays HR->PWR -// Calculation. Never sets userConfig.setSimulatedPower(); #define -// DEBUG_HR_TO_PWR +// Calculation. Never sets userConfig.setSimulatedPower(); +// #define DEBUG_HR_TO_PWR + +// Uncomment to enable HR->PWR enhanced powertable debugging. +// #define DEBUG_POWERTABLE #ifdef USE_TELEGRAM // Max number of telegram messages to send per session diff --git a/src/BLE_Client.cpp b/src/BLE_Client.cpp index 7a98829b..f8b543af 100644 --- a/src/BLE_Client.cpp +++ b/src/BLE_Client.cpp @@ -48,7 +48,7 @@ static void onNotify(BLERemoteCharacteristic *pBLERemoteCharacteristic, uint8_t // BLE Client loop task void bleClientTask(void *pvParameters) { for (;;) { - if (spinBLEClient.doScan && (spinBLEClient.scanRetries > 0)) { + if (spinBLEClient.doScan && (spinBLEClient.scanRetries > 0) && !NimBLEDevice::getScan()->isScanning()) { spinBLEClient.scanRetries--; SS2K_LOG(BLE_CLIENT_LOG_TAG, "Initiating Scan from Client Task:"); spinBLEClient.scanProcess(); @@ -347,24 +347,24 @@ void MyAdvertisedDeviceCallback::onResult(BLEAdvertisedDevice *advertisedDevice) // not specified. SS2K_LOG(BLE_CLIENT_LOG_TAG, "Matching Device Name: %s", aDevName.c_str()); if (advertisedDevice->getServiceUUID() == HEARTSERVICE_UUID) { - if (String(userConfig.getconnectedHeartMonitor()) == "any") { + if (String(userConfig.getConnectedHeartMonitor()) == "any") { SS2K_LOG(BLE_CLIENT_LOG_TAG, "HR String Matched Any"); // continue - } else if (aDevName != String(userConfig.getconnectedHeartMonitor()) || (String(userConfig.getconnectedHeartMonitor()) == "none")) { - SS2K_LOG(BLE_CLIENT_LOG_TAG, "Skipping non-selected HRM |%s|%s", aDevName.c_str(), userConfig.getconnectedHeartMonitor()); + } else if (aDevName != String(userConfig.getConnectedHeartMonitor()) || (String(userConfig.getConnectedHeartMonitor()) == "none")) { + SS2K_LOG(BLE_CLIENT_LOG_TAG, "Skipping non-selected HRM |%s|%s", aDevName.c_str(), userConfig.getConnectedHeartMonitor()); return; - } else if (aDevName == String(userConfig.getconnectedHeartMonitor())) { + } else if (aDevName == String(userConfig.getConnectedHeartMonitor())) { SS2K_LOG(BLE_CLIENT_LOG_TAG, "HR String Matched %s", aDevName.c_str()); } } else { // Already tested -->((advertisedDevice->getServiceUUID()(CYCLINGPOWERSERVICE_UUID) || advertisedDevice->getServiceUUID()(FLYWHEEL_UART_SERVICE_UUID) || // advertisedDevice->getServiceUUID()(FITNESSMACHINESERVICE_UUID))) - if (String(userConfig.getconnectedPowerMeter()) == "any") { + if (String(userConfig.getConnectedPowerMeter()) == "any") { SS2K_LOG(BLE_CLIENT_LOG_TAG, "PM String Matched Any"); // continue - } else if (aDevName != String(userConfig.getconnectedPowerMeter()) || (String(userConfig.getconnectedPowerMeter()) == "none")) { - SS2K_LOG(BLE_CLIENT_LOG_TAG, "Skipping non-selected PM |%s|%s", aDevName.c_str(), userConfig.getconnectedPowerMeter()); + } else if (aDevName != String(userConfig.getConnectedPowerMeter()) || (String(userConfig.getConnectedPowerMeter()) == "none")) { + SS2K_LOG(BLE_CLIENT_LOG_TAG, "Skipping non-selected PM |%s|%s", aDevName.c_str(), userConfig.getConnectedPowerMeter()); return; - } else if (aDevName == String(userConfig.getconnectedPowerMeter())) { + } else if (aDevName == String(userConfig.getConnectedPowerMeter())) { SS2K_LOG(BLE_CLIENT_LOG_TAG, "PM String Matched %s", aDevName.c_str()); } } @@ -384,7 +384,7 @@ void MyAdvertisedDeviceCallback::onResult(BLEAdvertisedDevice *advertisedDevice) } } -void SpinBLEClient::scanProcess() { +void SpinBLEClient::scanProcess(int duration) { this->doScan = false; // Confirming we did the scan SS2K_LOG(BLE_CLIENT_LOG_TAG, "Scanning for BLE servers and putting them into a list..."); @@ -394,7 +394,7 @@ void SpinBLEClient::scanProcess() { pBLEScan->setWindow(67); pBLEScan->setDuplicateFilter(true); pBLEScan->setActiveScan(true); - BLEScanResults foundDevices = pBLEScan->start(10, true); + BLEScanResults foundDevices = pBLEScan->start(duration, true); // Load the scan into a Json String int count = foundDevices.getCount(); @@ -507,13 +507,13 @@ void SpinBLEClient::postConnect(NimBLEClient *pClient) { SS2K_LOG(BLE_CLIENT_LOG_TAG, "Activated Echelon callbacks."); } // spinBLEClient.removeDuplicates(pclient); - BLEDevice::getServer()->updateConnParams(pClient->getConnId(), 400, 400, 0, 250); + BLEDevice::getServer()->updateConnParams(pClient->getConnId(), 400, 400, 2, 1000); return; } if ((this->myBLEDevices[i].charUUID == HEARTCHARACTERISTIC_UUID)) { this->connectedHR = true; SS2K_LOG(BLE_CLIENT_LOG_TAG, "Registered HRM on Connect"); - BLEDevice::getServer()->updateConnParams(pClient->getConnId(), 400, 400, 0, 250); + BLEDevice::getServer()->updateConnParams(pClient->getConnId(), 400, 400, 2, 1000); return; } else { SS2K_LOG(BLE_CLIENT_LOG_TAG, "These did not match|%s|%s|", pClient->getPeerAddress().toString().c_str(), this->myBLEDevices[i].peerAddress.toString().c_str()); diff --git a/src/BLE_Common.cpp b/src/BLE_Common.cpp index f440436b..f511fe29 100644 --- a/src/BLE_Common.cpp +++ b/src/BLE_Common.cpp @@ -123,7 +123,7 @@ void BLECommunications(void *pvParameters) { } else { digitalWrite(LED_PIN, HIGH); } - if (spinBLEClient.doScan && (spinBLEClient.scanRetries > 0)) { + if (spinBLEClient.doScan && (spinBLEClient.scanRetries > 0) && !NimBLEDevice::getScan()->isScanning()) { spinBLEClient.scanRetries--; SS2K_LOG(BLE_CLIENT_LOG_TAG, "Initiating Scan from Client Task:"); spinBLEClient.scanProcess(); diff --git a/src/BLE_Setup.cpp b/src/BLE_Setup.cpp index 178afb2e..a2c645ff 100644 --- a/src/BLE_Setup.cpp +++ b/src/BLE_Setup.cpp @@ -28,10 +28,10 @@ void setupBLE() { // Common BLE setup for both client and server SS2K_LOG(BLE_SETUP_LOG_TAG, "BLE Notify Task Started"); vTaskDelay(100 / portTICK_PERIOD_MS); - if (strcmp(userConfig.getconnectedPowerMeter(), "none") != 0 || strcmp(userConfig.getconnectedHeartMonitor(), "none") != 0) { + if (strcmp(userConfig.getConnectedPowerMeter(), "none") != 0 || strcmp(userConfig.getConnectedHeartMonitor(), "none") != 0) { spinBLEClient.serverScan(true); SS2K_LOG(BLE_SETUP_LOG_TAG, "Scanning"); } - SS2K_LOG(BLE_SETUP_LOG_TAG, "%s %s", userConfig.getconnectedPowerMeter(), userConfig.getconnectedHeartMonitor()); + SS2K_LOG(BLE_SETUP_LOG_TAG, "%s %s", userConfig.getConnectedPowerMeter(), userConfig.getConnectedHeartMonitor()); SS2K_LOG(BLE_SETUP_LOG_TAG, "End BLE Setup"); } diff --git a/src/ERG_Mode.cpp b/src/ERG_Mode.cpp index f779fb2c..7ae7273b 100644 --- a/src/ERG_Mode.cpp +++ b/src/ERG_Mode.cpp @@ -163,13 +163,17 @@ void PowerTable::newEntry(PowerBuffer& powerBuffer) { cad = powerBuffer.powerEntry[i].cad; continue; } +#ifdef DEBUG_POWERTABLE SS2K_LOGW(POWERTABLE_LOG_TAG, "Buf[%d](%dw)(%dpos)(%dcad)", i, powerBuffer.powerEntry[i].watts, powerBuffer.powerEntry[i].targetPosition, powerBuffer.powerEntry[i].cad); +#endif // calculate average watts = (watts + powerBuffer.powerEntry[i].watts) / 2; targetPosition = (targetPosition + powerBuffer.powerEntry[i].targetPosition) / 2; cad = (cad + powerBuffer.powerEntry[i].cad) / 2; } +#ifdef DEBUG_POWERTABLE SS2K_LOG(POWERTABLE_LOG_TAG, "Avg:(%dw)(%dpos)(%dcad)", (int)watts, targetPosition, cad); +#endif // Done with powerBuffer // To start working on the PowerTable, we need to calculate position in the table for the new entry int i = round(watts / POWERTABLE_INCREMENT); diff --git a/src/HTTP_Server_Basic.cpp b/src/HTTP_Server_Basic.cpp index 8718b107..81108aae 100644 --- a/src/HTTP_Server_Basic.cpp +++ b/src/HTTP_Server_Basic.cpp @@ -436,6 +436,7 @@ void HTTP_Server::settingsProcessor() { String tString; bool wasBTUpdate = false; bool wasSettingsUpdate = false; + bool reboot = false; if (!server.arg("ssid").isEmpty()) { tString = server.arg("ssid"); tString.trim(); @@ -528,7 +529,9 @@ void HTTP_Server::settingsProcessor() { wasBTUpdate = true; if (server.arg("blePMDropdown")) { tString = server.arg("blePMDropdown"); - userConfig.setConnectedPowerMeter(server.arg("blePMDropdown")); + if (tString != userConfig.getConnectedPowerMeter()) { + reboot = true; + } } else { userConfig.setConnectedPowerMeter("any"); } @@ -536,13 +539,16 @@ void HTTP_Server::settingsProcessor() { if (!server.arg("bleHRDropdown").isEmpty()) { wasBTUpdate = true; if (server.arg("bleHRDropdown")) { - tString = server.arg("bleHRDropdown"); + bool reset = false; + tString = server.arg("bleHRDropdown"); + if (tString != userConfig.getConnectedHeartMonitor()) { + reboot = true; + } userConfig.setConnectedHeartMonitor(server.arg("bleHRDropdown")); } else { userConfig.setConnectedHeartMonitor("any"); } } - if (!server.arg("session1HR").isEmpty()) { // Needs checking for unrealistic numbers. userPWC.session1HR = server.arg("session1HR").toInt(); } @@ -579,7 +585,7 @@ void HTTP_Server::settingsProcessor() { } else { // Normal response response += "Network settings will be applied at next reboot.
Everything " - "else is availiable immediately.

"; } @@ -589,6 +595,10 @@ void HTTP_Server::settingsProcessor() { userConfig.printFile(); userPWC.saveToLittleFS(); userPWC.printFile(); + if (reboot) { + vTaskDelay(100 / portTICK_PERIOD_MS); + ESP.restart(); + } } void HTTP_Server::stop() { diff --git a/src/Main.cpp b/src/Main.cpp index bfe9cb5b..6c38c0d8 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -168,7 +168,7 @@ void setup() { xTaskCreatePinnedToCore(SS2K::maintenanceLoop, /* Task function. */ "maintenanceLoopFunction", /* name of task. */ - 3500, /* Stack size of task */ + 4000, /* Stack size of task */ NULL, /* parameter of the task */ 1, /* priority of the task */ &maintenanceLoopTask, /* Task handle to keep track of created task */ @@ -228,6 +228,7 @@ void SS2K::maintenanceLoop(void *pvParameters) { if (loopCounter > 4) { ss2k.scanIfShiftersHeld(); ss2k.checkDriverTemperature(); + ss2k.checkBLEReconnect(); #ifdef DEBUG_STACK Serial.printf("Step Task: %d \n", uxTaskGetStackHighWaterMark(moveStepperTask)); @@ -498,3 +499,23 @@ void SS2K::checkSerial() { txCheck++; } } + +void SS2K::checkBLEReconnect() { + static int bleCheck = 0; + if (((userConfig.getConnectedHeartMonitor() != "any" && !spinBLEClient.connectedHR) || (userConfig.getConnectedPowerMeter() != "any" && !spinBLEClient.connectedPM)) && (bleCheck >= BLE_RECONNECT_INTERVAL)) { + bleCheck = 0; + if (((userConfig.getConnectedPowerMeter() == "none") && (userConfig.getConnectedHeartMonitor() == "none"))){ + return; + } + if (!NimBLEDevice::getScan()->isScanning()) { + SS2K_LOG(MAIN_LOG_TAG, "Scanning from Check BLE Reconnect %d", bleCheck); + spinBLEClient.resetDevices(); + spinBLEClient.scanProcess(BLE_RECONNECT_SCAN_DURATION); + } + } + if (NimBLEDevice::getScan()->isScanning()) { + bleCheck = 0; + } else { + bleCheck++; + } +}