Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
9 changes: 9 additions & 0 deletions data/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,15 @@ <h2>Reset to Defaults?</h2>
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'
}
};

Expand Down
1 change: 1 addition & 0 deletions include/BLE_Custom_Characteristic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
13 changes: 13 additions & 0 deletions include/SmartSpin_parameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
15 changes: 6 additions & 9 deletions include/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
52 changes: 38 additions & 14 deletions src/BLE_Custom_Characteristic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ This characteristic allows for reading and writing various user configuration pa
#include <BLE_Custom_Characteristic.h>
#include <Constants.h>

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);
Expand All @@ -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();
Expand Down Expand Up @@ -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<uint8_t *>(&rxValue[0]);
NimBLECharacteristic* pCharacteristic = NimBLEDevice::getServer()->getServiceByUUID(SMARTSPIN2K_SERVICE_UUID)->getCharacteristic(SMARTSPIN2K_CHARACTERISTIC_UUID);
uint8_t* pData = reinterpret_cast<uint8_t*>(&rxValue[0]);

#ifdef CUSTOM_CHAR_DEBUG
#define LOG_BUF_APPEND(...) logBufLength += snprintf(logBuf + logBufLength, kLogBufCapacity - logBufLength, __VA_ARGS__)
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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());
Expand All @@ -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)", "******");
Expand All @@ -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());
Expand All @@ -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());
Expand All @@ -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());
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
6 changes: 6 additions & 0 deletions src/HTTP_Server_Basic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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")) {
Expand Down
4 changes: 2 additions & 2 deletions src/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
6 changes: 6 additions & 0 deletions src/SmartSpin_parameters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ void userParameters::setDefaults() {
hMin = INT32_MIN;
hMax = INT32_MIN;
homingSensitivity = DEFAULT_HOMING_SENSITIVITY;
inactivityTimeout = DEFAULT_INACTIVITY_TIMEOUT;
}

//---------------------------------------------------------------------------------
Expand Down Expand Up @@ -108,6 +109,7 @@ String userParameters::returnJSON() {
doc["hMin"] = hMin;
doc["hMax"] = hMax;
doc["homingSensitivity"] = homingSensitivity;
doc["inactivityTimeout"] = inactivityTimeout;

String output;
serializeJson(doc, output);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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();
Expand Down