Compare commits

...

2 Commits

Author SHA1 Message Date
Roberto Viola
8604f5bda5 Update homeform.h 2024-07-11 18:11:50 +02:00
Roberto Viola
def4683f69 starting 2024-07-11 17:46:32 +02:00
4 changed files with 176 additions and 0 deletions

165
src/googlefit.h Normal file
View File

@@ -0,0 +1,165 @@
#ifndef GOOGLEFIT_H
#define GOOGLEFIT_H
#if __has_include("secret.h")
#include "secret.h"
#endif
#include <QtNetwork>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QtNetwork>
#include <QOAuth2AuthorizationCodeFlow>
#include <QDesktopServices>
class GoogleFitAuth : public QObject
{
Q_OBJECT
public:
explicit GoogleFitAuth(QObject *parent = nullptr) : QObject(parent)
{
oauth2 = new QOAuth2AuthorizationCodeFlow(this);
oauth2->setScope("https://www.googleapis.com/auth/fitness.activity.write");
connect(oauth2, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser,
&QDesktopServices::openUrl);
connect(oauth2, &QOAuth2AuthorizationCodeFlow::granted, this, &GoogleFitAuth::onGranted);
// Configura le impostazioni del client OAuth2
oauth2->setAuthorizationUrl(QUrl("https://accounts.google.com/o/oauth2/auth"));
oauth2->setAccessTokenUrl(QUrl("https://oauth2.googleapis.com/token"));
oauth2->setClientIdentifier("YOUR_CLIENT_ID");
oauth2->setClientIdentifierSharedKey("YOUR_CLIENT_SECRET");
}
void authenticate()
{
oauth2->grant();
}
QString getAccessToken() const
{
return oauth2->token();
}
signals:
void authenticated();
private slots:
void onGranted()
{
qDebug() << "Authentication successful!";
qDebug() << "Access Token:" << oauth2->token();
emit authenticated();
}
private:
QOAuth2AuthorizationCodeFlow *oauth2;
};
class GoogleFitUploader : public QObject
{
Q_OBJECT
public:
explicit GoogleFitUploader(QObject *parent = nullptr) : QObject(parent) {
if(!auth)
auth = new GoogleFitAuth();
auth->authenticate();
}
struct WorkoutDataPoint {
qint64 timestamp; // in seconds
int cadence;
int watts;
double speed;
double distance;
int heartRate;
};
void uploadWorkout(const QVector<WorkoutDataPoint>& dataPoints)
{
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished, this, &GoogleFitUploader::onReplyFinished);
QUrl url("https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate");
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", QString("Bearer %1").arg(auth->getAccessToken()).toUtf8());
QJsonObject requestBody;
requestBody["minStartTimeNs"] = QString::number(dataPoints.first().timestamp * 1000000);
requestBody["maxEndTimeNs"] = QString::number(dataPoints.last().timestamp * 1000000);
QJsonArray dataSources;
dataSources.append(createDataSource("com.google.cycling.pedaling.cadence", "rpm"));
dataSources.append(createDataSource("com.google.cycling.pedaling.cumulative", "watts"));
dataSources.append(createDataSource("com.google.speed", "m/s"));
dataSources.append(createDataSource("com.google.distance.delta", "m"));
dataSources.append(createDataSource("com.google.heart_rate.bpm", "bpm"));
requestBody["dataSources"] = dataSources;
QJsonArray dataset;
for (const auto& point : dataPoints) {
dataset.append(createDataPoint("com.google.cycling.pedaling.cadence", point.timestamp, point.cadence));
dataset.append(createDataPoint("com.google.cycling.pedaling.cumulative", point.timestamp, point.watts));
dataset.append(createDataPoint("com.google.speed", point.timestamp, point.speed));
dataset.append(createDataPoint("com.google.distance.delta", point.timestamp, point.distance));
dataset.append(createDataPoint("com.google.heart_rate.bpm", point.timestamp, point.heartRate));
}
requestBody["dataset"] = dataset;
QJsonDocument jsonDoc(requestBody);
manager->post(request, jsonDoc.toJson());
}
private:
GoogleFitAuth* auth = nullptr;
QJsonObject createDataSource(const QString& dataType, const QString& unit)
{
QJsonObject dataSource;
QJsonObject dataTypeObj;
dataTypeObj["name"] = dataType;
QJsonArray fieldArray;
QJsonObject fieldObj;
fieldObj["name"] = "value";
fieldObj["format"] = "floatPoint";
if (!unit.isEmpty()) {
fieldObj["units"] = unit;
}
fieldArray.append(fieldObj);
dataTypeObj["field"] = fieldArray;
dataSource["dataType"] = dataTypeObj;
return dataSource;
}
QJsonObject createDataPoint(const QString& dataType, qint64 timestampSeconds, double value)
{
QJsonObject dataPoint;
dataPoint["dataTypeName"] = dataType;
dataPoint["startTimeNanos"] = QString::number(timestampSeconds * 1000000000);
dataPoint["endTimeNanos"] = QString::number(timestampSeconds * 1000000000);
dataPoint["value"] = QJsonArray{QJsonObject{{"fpVal", value}}};
return dataPoint;
}
private slots:
void onReplyFinished(QNetworkReply *reply)
{
if (reply->error() == QNetworkReply::NoError) {
qDebug() << "Workout uploaded successfully!";
} else {
qDebug() << "Error uploading workout:" << reply->errorString();
}
reply->deleteLater();
}
};
#endif // GOOGLEFIT_H

View File

@@ -6167,6 +6167,14 @@ void homeform::strava_refreshtoken() {
bool homeform::strava_upload_file(const QByteArray &data, const QString &remotename) {
GoogleFitUploader::WorkoutDataPoint p;
p.cadence = 100;
p.distance = 10;
p.heartRate = 100;
p.speed = 10;
p.timestamp = QDateTime::currentSecsSinceEpoch();
p.watts = 100;
googleFit.uploadWorkout(QVector<GoogleFitUploader::WorkoutDataPoint>({p}));
strava_refreshtoken();
QSettings settings;

View File

@@ -4,6 +4,7 @@
#include "PathController.h"
#include "bluetooth.h"
#include "fit_profile.hpp"
#include "GoogleFit.h"
#include "gpx.h"
#include "peloton.h"
#include "qmdnsengine/browser.h"
@@ -659,6 +660,7 @@ class homeform : public QObject {
QOAuth2AuthorizationCodeFlow *strava = nullptr;
QNetworkAccessManager *manager = nullptr;
QOAuthHttpServerReplyHandler *stravaReplyHandler = nullptr;
GoogleFitUploader googleFit;
bool paused = false;
bool stopped = false;

View File

@@ -289,6 +289,7 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
INCLUDEPATH += fit-sdk/ devices/
HEADERS += \
$$PWD/GoogleFit.h \
$$PWD/devices/crossrope/crossrope.h \
$$PWD/devices/focustreadmill/focustreadmill.h \
$$PWD/devices/jumprope.h \