1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2025-02-23 16:01:13 +01:00

huami: implement repeated activity fetching

Currently, huami only attempts to fetch activities once.

Since sports activity fetching creates an Operation twice per every fetch, we
need to pass around fetchCount variable to keep track of how many fetches has
occured.

Tested on my Amazfit GTR 4.

Signed-off-by: Oleg Vasilev <me@svin.in>
This commit is contained in:
Oleg Vasilev 2023-03-04 17:35:23 +06:00 committed by Gitea
parent d6c8d6b56d
commit 007f070125
4 changed files with 43 additions and 26 deletions

View File

@ -390,7 +390,7 @@ public abstract class Huami2021Support extends HuamiSupport {
new FetchActivityOperation(this).perform(); new FetchActivityOperation(this).perform();
break; break;
case RecordedDataTypes.TYPE_GPS_TRACKS: case RecordedDataTypes.TYPE_GPS_TRACKS:
new FetchSportsSummaryOperation(this).perform(); new FetchSportsSummaryOperation(this, 1).perform();
break; break;
case RecordedDataTypes.TYPE_DEBUGLOGS: case RecordedDataTypes.TYPE_DEBUGLOGS:
new HuamiFetchDebugLogsOperation(this).perform(); new HuamiFetchDebugLogsOperation(this).perform();

View File

@ -87,7 +87,7 @@ public class AmazfitBipSupport extends HuamiSupport {
if (dataTypes == RecordedDataTypes.TYPE_ACTIVITY) { if (dataTypes == RecordedDataTypes.TYPE_ACTIVITY) {
new FetchActivityOperation(this).perform(); new FetchActivityOperation(this).perform();
} else if (dataTypes == RecordedDataTypes.TYPE_GPS_TRACKS) { } else if (dataTypes == RecordedDataTypes.TYPE_GPS_TRACKS) {
new FetchSportsSummaryOperation(this).perform(); new FetchSportsSummaryOperation(this, 1).perform();
} else if (dataTypes == RecordedDataTypes.TYPE_DEBUGLOGS) { } else if (dataTypes == RecordedDataTypes.TYPE_DEBUGLOGS) {
new HuamiFetchDebugLogsOperation(this).perform(); new HuamiFetchDebugLogsOperation(this).perform();
} else { } else {

View File

@ -17,6 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */ along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations; package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations;
import android.text.format.DateUtils;
import android.widget.Toast; import android.widget.Toast;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -29,6 +30,7 @@ import java.io.IOException;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.Logging; import nodomain.freeyourgadget.gadgetbridge.Logging;
import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.R;
@ -64,12 +66,14 @@ public class FetchSportsDetailsOperation extends AbstractFetchOperation {
FetchSportsDetailsOperation(@NonNull BaseActivitySummary summary, FetchSportsDetailsOperation(@NonNull BaseActivitySummary summary,
@NonNull AbstractHuamiActivityDetailsParser detailsParser, @NonNull AbstractHuamiActivityDetailsParser detailsParser,
@NonNull HuamiSupport support, @NonNull HuamiSupport support,
@NonNull String lastSyncTimeKey) { @NonNull String lastSyncTimeKey,
int fetchCount) {
super(support); super(support);
setName("fetching sport details"); setName("fetching sport details");
this.summary = summary; this.summary = summary;
this.detailsParser = detailsParser; this.detailsParser = detailsParser;
this.lastSyncTimeKey = lastSyncTimeKey; this.lastSyncTimeKey = lastSyncTimeKey;
this.fetchCount = fetchCount;
} }
@Override @Override
@ -83,15 +87,6 @@ public class FetchSportsDetailsOperation extends AbstractFetchOperation {
@Override @Override
protected boolean handleActivityFetchFinish(boolean success) { protected boolean handleActivityFetchFinish(boolean success) {
LOG.info(getName() + " has finished round " + fetchCount); LOG.info(getName() + " has finished round " + fetchCount);
// GregorianCalendar lastSyncTimestamp = saveSamples();
// if (lastSyncTimestamp != null && needsAnotherFetch(lastSyncTimestamp)) {
// try {
// startFetching();
// return;
// } catch (IOException ex) {
// LOG.error("Error starting another round of fetching activity data", ex);
// }
// }
boolean parseSuccess = true; boolean parseSuccess = true;
@ -147,18 +142,47 @@ public class FetchSportsDetailsOperation extends AbstractFetchOperation {
} }
} }
final boolean superSuccess = super.handleActivityFetchFinish(success);
if (success && parseSuccess) { if (success && parseSuccess) {
// Always increment the sync timestamp on success, even if we did not get data // Always increment the sync timestamp on success, even if we did not get data
GregorianCalendar endTime = BLETypeConversions.createCalendar(); GregorianCalendar endTime = BLETypeConversions.createCalendar();
endTime.setTime(summary.getEndTime()); endTime.setTime(summary.getEndTime());
saveLastSyncTimestamp(endTime); saveLastSyncTimestamp(endTime);
if (needsAnotherFetch(endTime)) {
FetchSportsSummaryOperation nextOperation = new FetchSportsSummaryOperation(getSupport(), fetchCount);
try {
nextOperation.perform();
} catch (IOException ex) {
LOG.error("Error starting another round of fetching activity data", ex);
}
}
} }
final boolean superSuccess = super.handleActivityFetchFinish(success);
return superSuccess && parseSuccess; return superSuccess && parseSuccess;
} }
private boolean needsAnotherFetch(GregorianCalendar lastSyncTimestamp) {
// We have 2 operations per fetch round: summary + details
if (fetchCount > 10) {
LOG.warn("Already have 5 fetch rounds, not doing another one.");
return false;
}
if (DateUtils.isToday(lastSyncTimestamp.getTimeInMillis())) {
LOG.info("Hopefully no further fetch needed, last synced timestamp is from today.");
return false;
}
if (lastSyncTimestamp.getTimeInMillis() > System.currentTimeMillis()) {
LOG.warn("Not doing another fetch since last synced timestamp is in the future: {}", DateTimeUtils.formatDateTime(lastSyncTimestamp.getTime()));
return false;
}
LOG.info("Doing another fetch since last sync timestamp is still too old: {}", DateTimeUtils.formatDateTime(lastSyncTimestamp.getTime()));
return true;
}
@Override @Override
protected boolean validChecksum(int crc32) { protected boolean validChecksum(int crc32) {
return crc32 == CheckSums.getCRC32(buffer.toByteArray()); return crc32 == CheckSums.getCRC32(buffer.toByteArray());
@ -208,6 +232,7 @@ public class FetchSportsDetailsOperation extends AbstractFetchOperation {
/** /**
* Buffers the given activity summary data. If the total size is reached, * Buffers the given activity summary data. If the total size is reached,
* it is converted to an object and saved in the database. * it is converted to an object and saved in the database.
*
* @param value * @param value
*/ */
@Override @Override

View File

@ -57,9 +57,10 @@ public class FetchSportsSummaryOperation extends AbstractFetchOperation {
private static final Logger LOG = LoggerFactory.getLogger(FetchSportsSummaryOperation.class); private static final Logger LOG = LoggerFactory.getLogger(FetchSportsSummaryOperation.class);
private ByteArrayOutputStream buffer = new ByteArrayOutputStream(140); private ByteArrayOutputStream buffer = new ByteArrayOutputStream(140);
public FetchSportsSummaryOperation(HuamiSupport support) { public FetchSportsSummaryOperation(HuamiSupport support, int fetchCount) {
super(support); super(support);
setName("fetching sport summaries"); setName("fetching sport summaries");
this.fetchCount = fetchCount;
} }
@Override @Override
@ -73,15 +74,6 @@ public class FetchSportsSummaryOperation extends AbstractFetchOperation {
protected boolean handleActivityFetchFinish(boolean success) { protected boolean handleActivityFetchFinish(boolean success) {
LOG.info(getName() + " has finished round " + fetchCount); LOG.info(getName() + " has finished round " + fetchCount);
// GregorianCalendar lastSyncTimestamp = saveSamples();
// if (lastSyncTimestamp != null && needsAnotherFetch(lastSyncTimestamp)) {
// try {
// startFetching();
// return;
// } catch (IOException ex) {
// LOG.error("Error starting another round of fetching activity data", ex);
// }
// }
BaseActivitySummary summary = null; BaseActivitySummary summary = null;
final DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(getDevice()); final DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(getDevice());
@ -124,7 +116,7 @@ public class FetchSportsSummaryOperation extends AbstractFetchOperation {
if (summary != null) { if (summary != null) {
final AbstractHuamiActivityDetailsParser detailsParser = ((HuamiActivitySummaryParser) summaryParser).getDetailsParser(summary); final AbstractHuamiActivityDetailsParser detailsParser = ((HuamiActivitySummaryParser) summaryParser).getDetailsParser(summary);
FetchSportsDetailsOperation nextOperation = new FetchSportsDetailsOperation(summary, detailsParser, getSupport(), getLastSyncTimeKey()); FetchSportsDetailsOperation nextOperation = new FetchSportsDetailsOperation(summary, detailsParser, getSupport(), getLastSyncTimeKey(), fetchCount);
try { try {
nextOperation.perform(); nextOperation.perform();
} catch (IOException ex) { } catch (IOException ex) {