Compare commits

...

4 Commits

Author SHA1 Message Date
Roberto Viola
53a41b35e2 build fix 2022-12-16 11:57:51 +01:00
Roberto Viola
1f178ff3fa using lastrunstate in order to set speed and inclination 2022-12-16 11:44:09 +01:00
Sunguk Lee
fd3cc25732 Initial send device state signal of kingsmith r2 to homeform 2022-12-16 11:12:02 +01:00
Sunguk Lee
64e9052f25 Initial implement start/stop control of KingSmith R2 when press start/pause/stop buttons
This patch is not perfect.
If a user doesn't do workout, treadmill will stop automatically,
but an UI of the application couldn't update anything.

Also in the timing issue, sometimes changeing `ControlMode` or `runState` command
just return `Error` packet.
I think, sending message too early (before finishing handshake) could
make the problem.

Fully implement needs passing the signal to homeform or MainApp.
And also it needs more complex state machine for handling buttons.
(eg; press the start button & press the pause button before
finish start treadmill action, pause action never call)
2022-12-16 11:11:40 +01:00
2 changed files with 116 additions and 61 deletions

View File

@@ -25,6 +25,12 @@ kingsmithr2treadmill::kingsmithr2treadmill(uint32_t pollDeviceTime, bool noConso
if (forceInitInclination > 0) {
lastInclination = forceInitInclination;
}
if (lastControlMode != UNKNOWN_CONTROL_MODE) {
lastControlMode = UNKNOWN_CONTROL_MODE;
}
if (lastRunState != UNKNOWN_RUN_STATE) {
lastRunState = UNKNOWN_RUN_STATE;
}
refresh = new QTimer(this);
initDone = false;
@@ -120,8 +126,11 @@ void kingsmithr2treadmill::update() {
QSettings settings;
// ******************************************* virtual treadmill init *************************************
if (!firstInit && !virtualTreadMill && !virtualBike) {
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
bool virtual_device_force_bike = settings.value(QZSettings::virtual_device_force_bike, QZSettings::default_virtual_device_force_bike).toBool();
bool virtual_device_enabled =
settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
bool virtual_device_force_bike =
settings.value(QZSettings::virtual_device_force_bike, QZSettings::default_virtual_device_force_bike)
.toBool();
if (virtual_device_enabled) {
if (!virtual_device_force_bike) {
debug("creating virtual treadmill interface...");
@@ -151,74 +160,84 @@ void kingsmithr2treadmill::update() {
// writeCharacteristic(QStringLiteral(""), QStringLiteral("noOp"), false, true);
}
// byte 3 - 4 = elapsed time
// byte 17 = inclination
if (requestSpeed != -1) {
if (requestSpeed != currentSpeed().value() && requestSpeed >= 0 && requestSpeed <= 22) {
emit debug(QStringLiteral("writing speed ") + QString::number(requestSpeed));
if (lastRunState == KINGSMITH_R2_RUN_STATE::START) {
if (requestSpeed != -1) {
if (requestSpeed != currentSpeed().value() && requestSpeed >= 0 && requestSpeed <= 22) {
emit debug(QStringLiteral("writing speed ") + QString::number(requestSpeed));
double inc = Inclination.value();
if (requestInclination != -100) {
double inc = Inclination.value();
if (requestInclination != -100) {
// only 0.5 steps ara available
requestInclination = qRound(requestInclination * 2.0) / 2.0;
inc = requestInclination;
requestInclination = -100;
// only 0.5 steps ara available
requestInclination = qRound(requestInclination * 2.0) / 2.0;
inc = requestInclination;
requestInclination = -100;
}
forceSpeedOrIncline(requestSpeed, inc);
}
forceSpeedOrIncline(requestSpeed, inc);
requestSpeed = -1;
}
requestSpeed = -1;
}
if (requestInclination != -100) {
if(requestInclination < 0)
requestInclination = 0;
// only 0.5 steps ara available
requestInclination = qRound(requestInclination * 2.0) / 2.0;
if (requestInclination != currentInclination().value() && requestInclination >= 0 &&
requestInclination <= 15) {
emit debug(QStringLiteral("writing incline ") + QString::number(requestInclination));
if (requestInclination != -100) {
if (requestInclination < 0)
requestInclination = 0;
// only 0.5 steps ara available
requestInclination = qRound(requestInclination * 2.0) / 2.0;
if (requestInclination != currentInclination().value() && requestInclination >= 0 &&
requestInclination <= 15) {
emit debug(QStringLiteral("writing incline ") + QString::number(requestInclination));
double speed = currentSpeed().value();
if (requestSpeed != -1) {
double speed = currentSpeed().value();
if (requestSpeed != -1) {
speed = requestSpeed;
requestSpeed = -1;
speed = requestSpeed;
requestSpeed = -1;
}
forceSpeedOrIncline(speed, requestInclination);
}
forceSpeedOrIncline(speed, requestInclination);
requestInclination = -100;
}
requestInclination = -100;
}
if (requestStart != -1) {
emit debug(QStringLiteral("starting..."));
if (lastSpeed == 0.0) {
lastSpeed = 0.5;
if (requestStop != -1) {
emit debug(QStringLiteral("stopping..."));
if (lastRunState != STOP) {
writeCharacteristic(QStringLiteral("props runState 0"), QStringLiteral("stopping"), false, true);
}
// don't go to standby mode automatically
requestStop = -1;
}
// btinit(true);
requestStart = -1;
emit tapeStarted();
}
if (requestStop != -1) {
emit debug(QStringLiteral("stopping..."));
requestStop = -1;
}
if (requestFanSpeed != -1) {
emit debug(QStringLiteral("changing fan speed..."));
if (requestFanSpeed != -1) {
emit debug(QStringLiteral("changing fan speed..."));
// sendChangeFanSpeed(requestFanSpeed);
requestFanSpeed = -1;
}
if (requestIncreaseFan != -1) {
emit debug(QStringLiteral("increasing fan speed..."));
// sendChangeFanSpeed(requestFanSpeed);
requestFanSpeed = -1;
}
if (requestIncreaseFan != -1) {
emit debug(QStringLiteral("increasing fan speed..."));
// sendChangeFanSpeed(FanSpeed + 1);
requestIncreaseFan = -1;
} else if (requestDecreaseFan != -1) {
emit debug(QStringLiteral("decreasing fan speed..."));
// sendChangeFanSpeed(FanSpeed + 1);
requestIncreaseFan = -1;
} else if (requestDecreaseFan != -1) {
emit debug(QStringLiteral("decreasing fan speed..."));
// sendChangeFanSpeed(FanSpeed - 1);
requestDecreaseFan = -1;
}
// sendChangeFanSpeed(FanSpeed - 1);
requestDecreaseFan = -1;
}
} else if (lastRunState == KINGSMITH_R2_RUN_STATE::STOP ||
lastRunState == KINGSMITH_R2_RUN_STATE::UNKNOWN_RUN_STATE)
if (requestStart != -1) {
emit debug(QStringLiteral("starting..."));
if (lastControlMode != MANUAL) {
writeCharacteristic(QStringLiteral("props ControlMode 1"),
QStringLiteral("turn on treadmill to manual mode"), false, true);
}
if (lastRunState != START) {
writeCharacteristic(QStringLiteral("props runState 1"), QStringLiteral("starting"), false, true);
}
if (lastSpeed == 0.0) {
lastSpeed = 0.5;
}
requestStart = -1;
emit tapeStarted();
}
}
}
@@ -276,11 +295,16 @@ void kingsmithr2treadmill::characteristicChanged(const QLowEnergyCharacteristic
QStringList _props = data.split(QStringLiteral(" "), QString::SkipEmptyParts);
for (int i = 1; i < _props.size(); i += 2) {
QString key = _props.at(i);
// Error key only can have error code
// props Error "ErrorCode" -5000
if (!key.compare(QStringLiteral("Error"))) {
break;
}
// skip string params
if (!key.compare(QStringLiteral("mcu_version")) || !key.compare(QStringLiteral("goal"))) {
continue;
}
if(i+1 >= _props.count()) {
if (i + 1 >= _props.count()) {
qDebug() << "error decoding" << i;
return;
}
@@ -291,6 +315,9 @@ void kingsmithr2treadmill::characteristicChanged(const QLowEnergyCharacteristic
double speed = props.value("CurrentSpeed", 0);
Cadence = props.value("spm", 0);
KINGSMITH_R2_CONTROL_MODE controlMode =
(KINGSMITH_R2_CONTROL_MODE)(int)props.value("ControlMode", (double)UNKNOWN_CONTROL_MODE);
KINGSMITH_R2_RUN_STATE runState = (KINGSMITH_R2_RUN_STATE)(int)props.value("runState", (double)UNKNOWN_RUN_STATE);
// TODO:
// - RunningDistance (int; meter) : update each 10miters / 0.01 mile
@@ -299,6 +326,9 @@ void kingsmithr2treadmill::characteristicChanged(const QLowEnergyCharacteristic
// - RunningTotalTime (int; sec)
// - spm (int) : steps per minute
// TODO: check 'ControlMode' and 'runState' of treadmill side
// then update current running status of application.
#ifdef Q_OS_ANDROID
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
Heart = (uint8_t)KeepAwakeHelper::heart();
@@ -329,7 +359,8 @@ void kingsmithr2treadmill::characteristicChanged(const QLowEnergyCharacteristic
if (!firstCharacteristicChanged) {
if (watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()))
KCal +=
((((0.048 * ((double)watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat())) + 1.19) *
((((0.048 * ((double)watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat())) +
1.19) *
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
200.0) /
(60000.0 / ((double)lastTimeCharacteristicChanged.msecsTo(
@@ -364,6 +395,25 @@ void kingsmithr2treadmill::characteristicChanged(const QLowEnergyCharacteristic
// lastInclination = incline;
}
if (lastControlMode != controlMode) {
lastControlMode = controlMode;
if (controlMode != UNKNOWN_CONTROL_MODE) {
emit debug(QStringLiteral("kingsmith r2 is ready"));
initDone = true;
}
}
if (lastRunState != runState) {
lastRunState = runState;
// TODO define bitflag enums to bluetoothdevice
switch (runState) {
case STOP:
// emit deviceStateChanged(1);
break;
case START:
// emit deviceStateChanged(2);
break;
}
}
firstCharacteristicChanged = false;
}
@@ -392,7 +442,7 @@ void kingsmithr2treadmill::btinit(bool startTape) {
writeCharacteristic(QStringLiteral("servers getProp 1 2 7 12 23 24 31"), QStringLiteral("init"), false, true);
// TODO need reset BurnCalories & RunningDistance
initDone = true;
// initDone = true;
}
void kingsmithr2treadmill::stateChanged(QLowEnergyService::ServiceState state) {

View File

@@ -80,6 +80,11 @@ class kingsmithr2treadmill : public treadmill {
QDateTime lastTimeCharacteristicChanged;
bool firstCharacteristicChanged = true;
enum KINGSMITH_R2_CONTROL_MODE { AUTOMODE = 0, MANUAL, STANDBY, UNKNOWN_CONTROL_MODE };
enum KINGSMITH_R2_RUN_STATE { STOP = 0, START, UNKNOWN_RUN_STATE };
KINGSMITH_R2_CONTROL_MODE lastControlMode = UNKNOWN_CONTROL_MODE;
KINGSMITH_R2_RUN_STATE lastRunState = UNKNOWN_RUN_STATE;
QTimer *refresh;
virtualtreadmill *virtualTreadMill = nullptr;
virtualbike *virtualBike = 0;