diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a51b8f6..6a0a986b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Removed >0 watts requirement to compute ERG. +- Removed sizes for JSON strings since they're dynamic now. +- Added variable inactivity timeout. - Filter cadence for crazy values. Only >0 && <250 now accepted. - Filter watts for crazy values. Only >0 && <3000 now accepted. - Fixed bug where scans may not happen even when configured devices aren't connected. diff --git a/data/settings.html b/data/settings.html index 836446cd..bd0bcac6 100644 --- a/data/settings.html +++ b/data/settings.html @@ -179,6 +179,15 @@

Reset to Defaults?

tooltip: 'Use cadence to calculate power output', tooltipText: 'Use the PowerTable for Power instead of PM', defaultValue: false + }, + inactivityTimeout: { + type: 'slider', + title: 'Inactivity Reboot Timeout', + tooltip: 'Idle time before auto-reboot', + tooltipText: 'Automatically reboot if device is inactive (no power, HR, or cadence changes) for this duration. Minimum 1 minute, maximum 48 hours.', + min: 1, max: 2880, step: 15, + defaultValue: 30, + unit: 'min' } }; diff --git a/include/BLE_Custom_Characteristic.h b/include/BLE_Custom_Characteristic.h index 441fe4ad..983f4901 100644 --- a/include/BLE_Custom_Characteristic.h +++ b/include/BLE_Custom_Characteristic.h @@ -63,6 +63,7 @@ const uint8_t BLE_hMax = 0x2B; // Maximum homing value const uint8_t BLE_homingSensitivity = 0x2C; // Homing sensitivity value const uint8_t BLE_pTab4Pwr = 0x2D; // Use power values for power table const uint8_t BLE_UDPLogging = 0x2E; // Enable or disable UDP logging +const uint8_t BLE_inactivityTimeout = 0x2F; // Inactivity reboot timeout in minutes class BLE_ss2kCustomCharacteristic { public: diff --git a/include/SmartSpin_parameters.h b/include/SmartSpin_parameters.h index 1fd58f1e..31ff7333 100644 --- a/include/SmartSpin_parameters.h +++ b/include/SmartSpin_parameters.h @@ -139,6 +139,7 @@ class userParameters { int32_t hMax = INT32_MIN; bool FTMSControlPointWrite = false; int homingSensitivity = DEFAULT_HOMING_SENSITIVITY; // Use default from settings.h + int inactivityTimeout = DEFAULT_INACTIVITY_TIMEOUT; String ssid; String password; String connectedPowerMeter = CONNECTED_POWER_METER; @@ -225,6 +226,18 @@ class userParameters { void setHomingSensitivity(int sensitivity) { homingSensitivity = sensitivity; } int getHomingSensitivity() { return homingSensitivity; } + void setInactivityTimeout(unsigned long timeout) { + // Clamp value between min and max + if (timeout < MIN_INACTIVITY_TIMEOUT) { + inactivityTimeout = MIN_INACTIVITY_TIMEOUT; + } else if (timeout > MAX_INACTIVITY_TIMEOUT) { + inactivityTimeout = MAX_INACTIVITY_TIMEOUT; + } else { + inactivityTimeout = timeout; + } + } + unsigned long getInactivityTimeout() { return inactivityTimeout; } + void setDefaults(); String returnJSON(); void saveToLittleFS(); diff --git a/include/settings.h b/include/settings.h index afc2d535..2c619a44 100644 --- a/include/settings.h +++ b/include/settings.h @@ -103,6 +103,12 @@ const char* const DEFAULT_PASSWORD = "password"; // This is used to set the upper travel limit for the motor. #define DEFAULT_MAX_WATTS 1000 +// Inactivity timeout for automatic reboot +// Time in minutes before reboot when no activity is detected +#define DEFAULT_INACTIVITY_TIMEOUT 30 +#define MIN_INACTIVITY_TIMEOUT 1 +#define MAX_INACTIVITY_TIMEOUT 2880 // 48 hours + // Minimum resistance on a Peloton Bike. // This is used to set the lower travel limit for the motor. #define MIN_PELOTON_RESISTANCE 5 @@ -264,15 +270,6 @@ constexpr const char* ANY = "any"; // The client will be disconnected. #define BLE_CLIENT_DISCONNECT_TIMEOUT 5000 -#ifndef DEBUG_LOG_BUFFER_SIZE -#define DEBUG_LOG_BUFFER_SIZE 600 -#endif - -// Max size of userconfig -#define USERCONFIG_JSON_SIZE 2000 + DEBUG_LOG_BUFFER_SIZE - -#define RUNTIMECONFIG_JSON_SIZE 1000 + DEBUG_LOG_BUFFER_SIZE - // Uncomment to use guardrails for ERG mode in the stepper loop. // #define ERG_GUARDRAILS diff --git a/src/BLE_Custom_Characteristic.cpp b/src/BLE_Custom_Characteristic.cpp index ecef6582..cd09e8dc 100644 --- a/src/BLE_Custom_Characteristic.cpp +++ b/src/BLE_Custom_Characteristic.cpp @@ -88,7 +88,7 @@ This characteristic allows for reading and writing various user configuration pa #include #include -void BLE_ss2kCustomCharacteristic::setupService(NimBLEServer *pServer) { +void BLE_ss2kCustomCharacteristic::setupService(NimBLEServer* pServer) { pSmartSpin2kService = spinBLEServer.pServer->createService(SMARTSPIN2K_SERVICE_UUID); smartSpin2kCharacteristic = pSmartSpin2kService->createCharacteristic(SMARTSPIN2K_CHARACTERISTIC_UUID, NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::INDICATE | NIMBLE_PROPERTY::NOTIFY); @@ -99,17 +99,17 @@ void BLE_ss2kCustomCharacteristic::setupService(NimBLEServer *pServer) { void BLE_ss2kCustomCharacteristic::update() {} -void ss2kCustomCharacteristicCallbacks::onWrite(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &connInfo) { +void ss2kCustomCharacteristicCallbacks::onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) { std::string rxValue = pCharacteristic->getValue(); // SS2K_LOG(CUSTOM_CHAR_LOG_TAG, "Write from %s", connInfo.getAddress().toString().c_str()); BLE_ss2kCustomCharacteristic::process(rxValue); } -void ss2kCustomCharacteristicCallbacks::onSubscribe(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &connInfo, uint16_t subValue) { +void ss2kCustomCharacteristicCallbacks::onSubscribe(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, uint16_t subValue) { SS2K_LOG(CUSTOM_CHAR_LOG_TAG, "Subscribe from %s", connInfo.getAddress().toString().c_str()); NimBLEDevice::setMTU(515); } -void ss2kCustomCharacteristicCallbacks::onStatus(NimBLECharacteristic *pCharacteristic, int code) { +void ss2kCustomCharacteristicCallbacks::onStatus(NimBLECharacteristic* pCharacteristic, int code) { // loop through and accumulate the data into a C++ string #ifdef CUSTOM_CHAR_DEBUG std::string characteristicValue = pCharacteristic->getValue(); @@ -137,8 +137,8 @@ void BLE_ss2kCustomCharacteristic::process(std::string rxValue) { if (NimBLEDevice::getServer()->getServiceByUUID(SMARTSPIN2K_SERVICE_UUID) == nullptr) { return; } - NimBLECharacteristic *pCharacteristic = NimBLEDevice::getServer()->getServiceByUUID(SMARTSPIN2K_SERVICE_UUID)->getCharacteristic(SMARTSPIN2K_CHARACTERISTIC_UUID); - uint8_t *pData = reinterpret_cast(&rxValue[0]); + NimBLECharacteristic* pCharacteristic = NimBLEDevice::getServer()->getServiceByUUID(SMARTSPIN2K_SERVICE_UUID)->getCharacteristic(SMARTSPIN2K_CHARACTERISTIC_UUID); + uint8_t* pData = reinterpret_cast(&rxValue[0]); #ifdef CUSTOM_CHAR_DEBUG #define LOG_BUF_APPEND(...) logBufLength += snprintf(logBuf + logBufLength, kLogBufCapacity - logBufLength, __VA_ARGS__) @@ -166,7 +166,7 @@ void BLE_ss2kCustomCharacteristic::process(std::string rxValue) { returnString = userConfig->getFirmwareUpdateURL(); } else if (rxValue[0] == cc_write) { returnValue[0] = cc_success; - String str = (char *)pData; + String str = (char*)pData; str.remove(0, 2); userConfig->setFirmwareUpdateURL(str); LOG_BUF_APPEND("(%s)", userConfig->getFirmwareUpdateURL()); @@ -257,7 +257,7 @@ void BLE_ss2kCustomCharacteristic::process(std::string rxValue) { returnString = userConfig->getDeviceName(); } else if (rxValue[0] == cc_write) { returnValue[0] = cc_success; - String str = (char *)pData; + String str = (char*)pData; str.remove(0, 2); userConfig->setDeviceName(str); LOG_BUF_APPEND("(%s)", userConfig->getDeviceName()); @@ -420,7 +420,7 @@ void BLE_ss2kCustomCharacteristic::process(std::string rxValue) { returnString = userConfig->getSsid(); } else if (rxValue[0] == cc_write) { returnValue[0] = cc_success; - String str = (char *)pData; + String str = (char*)pData; str.remove(0, 2); userConfig->setSsid(str); LOG_BUF_APPEND("(%s)", userConfig->getSsid()); @@ -434,7 +434,7 @@ void BLE_ss2kCustomCharacteristic::process(std::string rxValue) { returnString = userConfig->getPassword(); } else if (rxValue[0] == cc_write) { returnValue[0] = cc_success; - String str = (char *)pData; + String str = (char*)pData; str.remove(0, 2); userConfig->setPassword(str); LOG_BUF_APPEND("(%s)", "******"); @@ -448,7 +448,7 @@ void BLE_ss2kCustomCharacteristic::process(std::string rxValue) { returnString = userConfig->getFoundDevices(); } else if (rxValue[0] == cc_write) { returnValue[0] = cc_success; - String str = (char *)pData; + String str = (char*)pData; str.remove(0, 2); userConfig->setFoundDevices(str); LOG_BUF_APPEND("(%s)", userConfig->getFoundDevices()); @@ -462,7 +462,7 @@ void BLE_ss2kCustomCharacteristic::process(std::string rxValue) { returnString = userConfig->getConnectedPowerMeter(); } else if (rxValue[0] == cc_write) { returnValue[0] = cc_success; - String str = (char *)pData; + String str = (char*)pData; str.remove(0, 2); userConfig->setConnectedPowerMeter(str); LOG_BUF_APPEND("(%s)", userConfig->getConnectedPowerMeter()); @@ -476,7 +476,7 @@ void BLE_ss2kCustomCharacteristic::process(std::string rxValue) { returnString = userConfig->getConnectedHeartMonitor(); } else if (rxValue[0] == cc_write) { returnValue[0] = cc_success; - String str = (char *)pData; + String str = (char*)pData; str.remove(0, 2); userConfig->setConnectedHeartMonitor(str); LOG_BUF_APPEND("(%s)", userConfig->getConnectedHeartMonitor()); @@ -758,7 +758,7 @@ void BLE_ss2kCustomCharacteristic::process(std::string rxValue) { } if (rxValue[0] == cc_write) { returnValue[0] = cc_success; - int32_t hMin = int32_t((uint8_t)(rxValue[2]) << 0 | (uint8_t)(rxValue[3]) << 8 | (uint8_t)(rxValue[4]) << 16 | (uint8_t)(rxValue[5]) << 24); + int32_t hMin = int32_t((uint8_t)(rxValue[2]) << 0 | (uint8_t)(rxValue[3]) << 8 | (uint8_t)(rxValue[4]) << 16 | (uint8_t)(rxValue[5]) << 24); userConfig->setHMin(hMin); rtConfig->setMinStep(hMin); LOG_BUF_APPEND(" (%d)", hMin); @@ -828,6 +828,25 @@ void BLE_ss2kCustomCharacteristic::process(std::string rxValue) { } break; + case BLE_inactivityTimeout: { // 0x2F + LOG_BUF_APPEND("<-inactivityTimeout"); + int timeout = userConfig->getInactivityTimeout(); + if (rxValue[0] == cc_read) { + returnValue[0] = cc_success; + returnValue[2] = (uint8_t)(timeout & 0xff); + returnValue[3] = (uint8_t)((timeout >> 8) & 0xff); + returnValue[4] = (uint8_t)((timeout >> 16) & 0xff); + returnValue[5] = (uint8_t)((timeout >> 24) & 0xff); + returnLength += 4; + } + if (rxValue[0] == cc_write) { + returnValue[0] = cc_success; + int newTimeout = rxValue[2] | (rxValue[3] << 8) | (rxValue[4] << 16) | (rxValue[5] << 24); + userConfig->setInactivityTimeout(newTimeout); + LOG_BUF_APPEND("(%d min)", userConfig->getInactivityTimeout()); + } + } break; + default: LOG_BUF_APPEND("<-Unknown Characteristic"); returnValue[0] = cc_error; @@ -1015,4 +1034,9 @@ void BLE_ss2kCustomCharacteristic::parseNemit() { BLE_ss2kCustomCharacteristic::notify(BLE_UDPLogging); return; } + if (userConfig->getInactivityTimeout() != _oldParams.getInactivityTimeout()) { + _oldParams.setInactivityTimeout(userConfig->getInactivityTimeout()); + BLE_ss2kCustomCharacteristic::notify(BLE_inactivityTimeout); + return; + } } diff --git a/src/HTTP_Server_Basic.cpp b/src/HTTP_Server_Basic.cpp index dbb14cc2..0bf76056 100644 --- a/src/HTTP_Server_Basic.cpp +++ b/src/HTTP_Server_Basic.cpp @@ -657,6 +657,12 @@ void HTTP_Server::settingsProcessor() { userConfig->setPowerCorrectionFactor(powerCorrectionFactor); } } + if (!server.arg("inactivityTimeout").isEmpty()) { + uint64_t inactivityTimeout = server.arg("inactivityTimeout").toInt(); + if (inactivityTimeout >= MIN_INACTIVITY_TIMEOUT && inactivityTimeout <= MAX_INACTIVITY_TIMEOUT) { + userConfig->setInactivityTimeout(inactivityTimeout); + } + } if (!server.arg("blePMDropdown").isEmpty()) { wasBTUpdate = true; if (server.arg("blePMDropdown")) { diff --git a/src/Main.cpp b/src/Main.cpp index 5dd92226..ca82dde1 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -296,9 +296,9 @@ void SS2K::maintenanceLoop(void* pvParameters) { static float _oldTargetIncline = 0.0f; if (_oldHR == rtConfig->hr.getValue() && _oldWatts == rtConfig->watts.getValue() && _oldTargetIncline == rtConfig->getTargetIncline()) { // Inactivity detected - if (((millis() - rebootTimer) > 1800000)) { + if (((millis() - rebootTimer) > userConfig->getInactivityTimeout() * 60000)) { // Timer expired - SS2K_LOG(MAIN_LOG_TAG, "Rebooting due to inactivity."); + SS2K_LOG(MAIN_LOG_TAG, "Rebooting due to inactivity. Timeout: %d min", userConfig->getInactivityTimeout()); ss2k->rebootFlag = true; logHandler.writeLogs(); webSocketAppender.Loop(); diff --git a/src/SmartSpin_parameters.cpp b/src/SmartSpin_parameters.cpp index 25fe1c68..e3b63b26 100644 --- a/src/SmartSpin_parameters.cpp +++ b/src/SmartSpin_parameters.cpp @@ -71,6 +71,7 @@ void userParameters::setDefaults() { hMin = INT32_MIN; hMax = INT32_MIN; homingSensitivity = DEFAULT_HOMING_SENSITIVITY; + inactivityTimeout = DEFAULT_INACTIVITY_TIMEOUT; } //--------------------------------------------------------------------------------- @@ -108,6 +109,7 @@ String userParameters::returnJSON() { doc["hMin"] = hMin; doc["hMax"] = hMax; doc["homingSensitivity"] = homingSensitivity; + doc["inactivityTimeout"] = inactivityTimeout; String output; serializeJson(doc, output); @@ -160,6 +162,7 @@ void userParameters::saveToLittleFS() { doc["hMin"] = hMin; doc["hMax"] = hMax; doc["homingSensitivity"] = homingSensitivity; + doc["inactivityTimeout"] = inactivityTimeout; // Serialize JSON to file if (serializeJson(doc, file) == 0) { @@ -250,6 +253,9 @@ JsonDocument doc; if (!doc["homingSensitivity"].isNull()) { setHomingSensitivity(doc["homingSensitivity"]); } + if (!doc["inactivityTimeout"].isNull()) { + setInactivityTimeout(doc["inactivityTimeout"]); + } SS2K_LOG(CONFIG_LOG_TAG, "Config File Loaded: %s", configFILENAME); file.close();