Compare commits

...

18 Commits

Author SHA1 Message Date
Roberto Viola
eb869c3971 in order to avoid auto start if the qz app is set to treadmill and speed to 0 2023-09-22 17:28:03 +02:00
Roberto Viola
4f1bbcf5cc works! 2023-09-22 16:46:13 +02:00
Roberto Viola
3df1a1417e ping event 2023-09-22 16:16:37 +02:00
Roberto Viola
140d6cffd4 Update MainController.swift 2023-09-22 16:03:50 +02:00
Roberto Viola
0bf6be09e1 Update lockscreen.mm 2023-09-22 15:57:05 +02:00
Roberto Viola
59e8792edc start button removed 2023-09-22 15:55:18 +02:00
Roberto Viola
3867927b02 it builds 2023-09-22 15:49:02 +02:00
Roberto Viola
bcb2798b81 Merge branch 'master' into apple_watch_auto_start_stop 2023-09-22 15:16:40 +02:00
Roberto Viola
cc7e349eb2 Merge branch 'master' into apple_watch_auto_start_stop 2023-09-01 09:53:23 +02:00
Roberto Viola
0f57b5fc10 Merge branch 'master' into apple_watch_auto_start_stop 2023-07-25 16:29:45 +02:00
Roberto Viola
725d6cadb1 wrote the code, test required! 2023-07-25 16:27:59 +02:00
Roberto Viola
d7c499a009 Update AppDelegate.swift 2023-07-06 09:26:14 +02:00
Roberto Viola
5d9e28715f distance added to ipad 2023-07-06 09:25:38 +02:00
Roberto Viola
6f3c386915 try to accomodate the xcode 15 beta 1 request for watchos depoyment target must be 6 or above 2023-06-21 09:54:35 +02:00
Roberto Viola
f80550dbb8 Merge branch 'master' into ios17 2023-06-21 09:32:56 +02:00
Roberto Viola
c5ca080dd8 let's send to test flight 2023-06-09 13:33:53 +02:00
Roberto Viola
b6bd3bdb2c tested! 2023-06-09 12:11:50 +02:00
Roberto Viola
26325aa62e Update WatchWorkoutTracking.swift 2023-06-08 22:20:47 +02:00
14 changed files with 204 additions and 117 deletions

View File

@@ -4089,7 +4089,7 @@
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 5.0;
WATCHOS_DEPLOYMENT_TARGET = 6.0;
};
name = Debug;
};
@@ -4181,7 +4181,7 @@
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
VALIDATE_PRODUCT = YES;
WATCHOS_DEPLOYMENT_TARGET = 5.0;
WATCHOS_DEPLOYMENT_TARGET = 6.0;
};
name = Release;
};
@@ -4295,7 +4295,7 @@
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 5.0;
WATCHOS_DEPLOYMENT_TARGET = 6.0;
};
name = Debug;
};
@@ -4406,7 +4406,7 @@
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
VALIDATE_PRODUCT = YES;
WATCHOS_DEPLOYMENT_TARGET = 5.0;
WATCHOS_DEPLOYMENT_TARGET = 6.0;
};
name = Release;
};

View File

@@ -18,30 +18,26 @@ class MainController: WKInterfaceController {
@IBOutlet weak var heartRateLabel: WKInterfaceLabel!
@IBOutlet weak var startButton: WKInterfaceButton!
@IBOutlet weak var cmbSports: WKInterfacePicker!
static var start: Bool! = false
let pedometer = CMPedometer()
var sport: Int = 0
//enum WORKOUT_EVENT_STATE { STARTED = 0, PAUSED = 1, RESUMED = 2, STOPPED = 3 };
public static var workout_state = 3;
override func awake(withContext context: Any?) {
super.awake(withContext: context)
let sports: [WKPickerItem] = [WKPickerItem(),WKPickerItem(),WKPickerItem(),WKPickerItem(),WKPickerItem()]
sports[0].title = "Bike"
sports[1].title = "Run"
sports[2].title = "Walk"
sports[3].title = "Elliptical"
sports[4].title = "Rowing"
cmbSports.setItems(sports)
sport = UserDefaults.standard.value(forKey: "sport") as? Int ?? 0
cmbSports.setSelectedItemIndex(sport)
WatchKitConnection.shared.delegate = self
WatchKitConnection.shared.startSession()
_ = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(MainController.onesec), userInfo: nil, repeats: true)
// Configure interface objects here.
print("AWAKE")
}
@IBAction func changeSport(_ value: Int) {
self.sport = value
UserDefaults.standard.set(value, forKey: "sport")
UserDefaults.standard.synchronize()
@objc func onesec() {
WatchKitConnection.shared.sendMessage(message: ["ping":
"0" as AnyObject])
}
override func willActivate() {
@@ -49,6 +45,8 @@ class MainController: WKInterfaceController {
super.willActivate()
print("WILL ACTIVE")
WorkoutTracking.shared.fetchStepCounts()
WorkoutTracking.shared.delegate = self
if CMPedometer.isStepCountingAvailable() {
pedometer.startUpdates(from: Date()) { pedometerData, error in
guard let pedometerData = pedometerData, error == nil else { return }
@@ -68,23 +66,31 @@ class MainController: WKInterfaceController {
}
extension MainController {
@IBAction func startWorkout() {
if(!MainController.start){
MainController.start = true
startButton.setTitle("Stop")
WorkoutTracking.authorizeHealthKit()
WorkoutTracking.shared.setSport(sport)
WorkoutTracking.shared.startWorkOut()
WorkoutTracking.shared.delegate = self
WatchKitConnection.shared.delegate = self
WatchKitConnection.shared.startSession()
}
else {
MainController.start = false
startButton.setTitle("Start")
WorkoutTracking.shared.stopWorkOut()
public static func syncWorkoutState(state: Int) {
if(state != workout_state) {
switch state {
case 0:
if(WorkoutTracking.speed > 0) {
WorkoutTracking.authorizeHealthKit()
WorkoutTracking.shared.startWorkOut()
workout_state = state
}
case 1:
WorkoutTracking.shared.pauseWorkout()
workout_state = state
case 2:
WorkoutTracking.shared.resumeWorkout()
workout_state = state
case 3:
WorkoutTracking.shared.stopWorkOut()
workout_state = state
default:
print("error!")
}
}
}
}
@@ -107,6 +113,7 @@ extension MainController: WorkoutTrackingDelegate {
WorkoutTracking.speed = WatchKitConnection.speed
WorkoutTracking.power = WatchKitConnection.power
WorkoutTracking.cadence = WatchKitConnection.cadence
WorkoutTracking.workout_state = WatchKitConnection.workout_state
if Locale.current.measurementSystem != "Metric" {
self.distanceLabel.setText("Distance \(String(format:"%.2f", WorkoutTracking.distance))")

View File

@@ -27,6 +27,10 @@ class WatchKitConnection: NSObject {
public static var speed = 0.0
public static var cadence = 0.0
public static var power = 0.0
//enum WORKOUT_EVENT_STATE { STARTED = 0, PAUSED = 1, RESUMED = 2, STOPPED = 3 };
public static var workout_state = 3;
weak var delegate: WatchKitConnectionDelegate?
private override init() {
@@ -76,6 +80,13 @@ extension WatchKitConnection: WatchKitConnectionProtocol {
WatchKitConnection.power = dPower
let dCadence = Double(result["cadence"] as! Double)
WatchKitConnection.cadence = dCadence
let iWorkout_type = Int(result["workout_type"] as! Int)
WorkoutTracking.shared.setSport(iWorkout_type)
let iWorkout_state = Int(result["workout_state"] as! Int)
WatchKitConnection.workout_state = iWorkout_state
MainController.syncWorkoutState(state: WatchKitConnection.workout_state)
}, errorHandler: { (error) in
print(error)
})

View File

@@ -21,6 +21,8 @@ protocol WorkoutTrackingProtocol {
static func authorizeHealthKit()
func startWorkOut()
func stopWorkOut()
func pauseWorkout()
func resumeWorkout()
func fetchStepCounts()
}
@@ -34,11 +36,12 @@ class WorkoutTracking: NSObject {
public static var speed = Double()
public static var power = Double()
public static var cadence = Double()
public static var workout_state = 3;
public static var lastDateMetric = Date()
var sport: Int = 0
let healthStore = HKHealthStore()
let configuration = HKWorkoutConfiguration()
var workoutSession: HKWorkoutSession!
var workoutSession: HKWorkoutSession! = nil
var workoutBuilder: HKLiveWorkoutBuilder!
weak var delegate: WorkoutTrackingDelegate?
@@ -109,16 +112,18 @@ extension WorkoutTracking {
func setSport(_ sport: Int) {
self.sport = sport
}
private func configWorkout() {
// enum BLUETOOTH_TYPE { UNKNOWN = 0, TREADMILL, BIKE, ROWING, ELLIPTICAL };
var activityType = HKWorkoutActivityType.cycling
if self.sport == 1 {
activityType = HKWorkoutActivityType.running
} else if self.sport == 2 {
activityType = HKWorkoutActivityType.walking
} else if self.sport == 3 {
activityType = HKWorkoutActivityType.elliptical
// TODO
//} else if self.sport == 2 {
// activityType = HKWorkoutActivityType.walking
} else if self.sport == 4 {
activityType = HKWorkoutActivityType.elliptical
} else if self.sport == 3 {
activityType = HKWorkoutActivityType.rowing
}
@@ -188,6 +193,20 @@ extension WorkoutTracking: WorkoutTrackingProtocol {
}
}
func pauseWorkout() {
if((workoutSession) != nil) {
workoutSession.pause()
}
}
func resumeWorkout() {
if((workoutSession) != nil) {
workoutSession.resume()
} else {
startWorkOut()
}
}
func startWorkOut() {
WorkoutTracking.lastDateMetric = Date()
print("Start workout")
@@ -206,91 +225,92 @@ extension WorkoutTracking: WorkoutTrackingProtocol {
}
func stopWorkOut() {
print("Stop workout")
workoutSession.stopActivity(with: Date())
workoutSession.end()
guard let quantityType = HKQuantityType.quantityType(
forIdentifier: .activeEnergyBurned) else {
return
}
if((workoutSession) != nil) {
print("Stop workout")
workoutSession.stopActivity(with: Date())
workoutSession.end()
let unit = HKUnit.kilocalorie()
let totalEnergyBurned = WorkoutTracking.kcal
let quantity = HKQuantity(unit: unit,
doubleValue: totalEnergyBurned)
let sample = HKCumulativeQuantitySeriesSample(type: quantityType,
quantity: quantity,
start: workoutSession.startDate!,
end: Date())
workoutBuilder.add([sample]) {(success, error) in}
guard let quantityType = HKQuantityType.quantityType(
forIdentifier: .activeEnergyBurned) else {
return
}
let unitDistance = HKUnit.mile()
let miles = WorkoutTracking.distance
let quantityMiles = HKQuantity(unit: unitDistance,
doubleValue: miles)
if(sport == 0) {
let unit = HKUnit.kilocalorie()
let totalEnergyBurned = WorkoutTracking.kcal
let quantity = HKQuantity(unit: unit,
doubleValue: totalEnergyBurned)
guard let quantityTypeDistance = HKQuantityType.quantityType(
let sample = HKCumulativeQuantitySeriesSample(type: quantityType,
quantity: quantity,
start: workoutSession.startDate!,
end: Date())
workoutBuilder.add([sample]) {(success, error) in}
let unitDistance = HKUnit.mile()
let miles = WorkoutTracking.distance
let quantityMiles = HKQuantity(unit: unitDistance,
doubleValue: miles)
if(sport == 0) {
guard let quantityTypeDistance = HKQuantityType.quantityType(
forIdentifier: .distanceCycling) else {
return
}
let sampleDistance = HKCumulativeQuantitySeriesSample(type: quantityTypeDistance,
quantity: quantityMiles,
start: workoutSession.startDate!,
end: Date())
workoutBuilder.add([sampleDistance]) {(success, error) in
if let error = error {
print(error)
return
}
self.workoutBuilder.endCollection(withEnd: Date()) { (success, error) in
let sampleDistance = HKCumulativeQuantitySeriesSample(type: quantityTypeDistance,
quantity: quantityMiles,
start: workoutSession.startDate!,
end: Date())
workoutBuilder.add([sampleDistance]) {(success, error) in
if let error = error {
print(error)
}
self.workoutBuilder.finishWorkout{ (workout, error) in
self.workoutBuilder.endCollection(withEnd: Date()) { (success, error) in
if let error = error {
print(error)
}
workout?.setValue(quantityMiles, forKey: "totalDistance")
self.workoutBuilder.finishWorkout{ (workout, error) in
if let error = error {
print(error)
}
workout?.setValue(quantityMiles, forKey: "totalDistance")
}
}
}
}
} else {
guard let quantityTypeDistance = HKQuantityType.quantityType(
forIdentifier: .distanceWalkingRunning) else {
return
}
let sampleDistance = HKCumulativeQuantitySeriesSample(type: quantityTypeDistance,
quantity: quantityMiles,
start: workoutSession.startDate!,
end: Date())
workoutBuilder.add([sampleDistance]) {(success, error) in
if let error = error {
print(error)
} else {
guard let quantityTypeDistance = HKQuantityType.quantityType(
forIdentifier: .distanceWalkingRunning) else {
return
}
self.workoutBuilder.endCollection(withEnd: Date()) { (success, error) in
let sampleDistance = HKCumulativeQuantitySeriesSample(type: quantityTypeDistance,
quantity: quantityMiles,
start: workoutSession.startDate!,
end: Date())
workoutBuilder.add([sampleDistance]) {(success, error) in
if let error = error {
print(error)
}
self.workoutBuilder.finishWorkout{ (workout, error) in
self.workoutBuilder.endCollection(withEnd: Date()) { (success, error) in
if let error = error {
print(error)
}
workout?.setValue(quantityMiles, forKey: "totalDistance")
self.workoutBuilder.finishWorkout{ (workout, error) in
if let error = error {
print(error)
}
workout?.setValue(quantityMiles, forKey: "totalDistance")
}
}
}
}
}
}

View File

@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="20037" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Tpn-rd-UUX">
<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="22154" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Tpn-rd-UUX">
<device id="watch38"/>
<dependencies>
<deployment identifier="watchOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="20006"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="22022"/>
</dependencies>
<scenes>
<!--Main-->
@@ -13,11 +12,6 @@
<controller identifier="Main" hidesWhenLoading="NO" id="Tpn-rd-UUX" customClass="MainController" customModule="watchkit_Extension">
<items>
<label width="136" alignment="left" text="QZ Fitness" textAlignment="center" id="SlU-M7-WGB"/>
<button width="1" alignment="left" title="Start" id="vZg-X8-uY5">
<connections>
<action selector="startWorkout" destination="Tpn-rd-UUX" id="UaW-pR-tn6"/>
</connections>
</button>
<label width="136" alignment="left" text="Heart Rate" id="Nda-m1-XRw"/>
<label width="136" alignment="left" text="Step Counts" id="HpA-e9-6YV"/>
<label width="136" alignment="left" text="Calories" id="Szi-Jp-J3S"/>
@@ -33,7 +27,6 @@
<outlet property="cmbSports" destination="OTR-HF-vYb" id="Ws5-w9-ZT8"/>
<outlet property="distanceLabel" destination="eRf-NJ-6If" id="ZE2-OB-jqN"/>
<outlet property="heartRateLabel" destination="Nda-m1-XRw" id="1la-8R-3jG"/>
<outlet property="startButton" destination="vZg-X8-uY5" id="pJc-09-kfV"/>
<outlet property="stepCountsLabel" destination="HpA-e9-6YV" id="Z88-ej-6oG"/>
<outlet property="userNameLabel" destination="SlU-M7-WGB" id="Y2O-Lg-bDx"/>
</connections>

View File

@@ -245,6 +245,8 @@ void bluetoothdevice::update_hr_from_external() {
#ifndef IO_UNDER_QT
lockscreen h;
long appleWatchHeartRate = h.heartRate();
h.setWorkoutType(deviceType());
h.setWorkoutState(lastState);
h.setKcal(KCal.value());
h.setDistance(Distance.value());
h.setSpeed(Speed.value());

View File

@@ -502,6 +502,8 @@ void fitshowtreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
if (heartRateBeltName.startsWith(QStringLiteral("Disabled")) && !disable_hr_frommachinery) {
#if defined(Q_OS_IOS) && !defined(IO_UNDER_QT)
long appleWatchHeartRate = h->heartRate();
h->setWorkoutType(deviceType());
h->setWorkoutState(lastState);
h->setKcal(KCal.value());
h->setDistance(Distance.value());
h->setSpeed(Speed.value());

View File

@@ -411,10 +411,10 @@ homeform::homeform(QQmlApplicationEngine *engine, bluetooth *bl) {
this->engine = engine;
connect(bluetoothManager, &bluetooth::bluetoothDeviceConnected, this, &homeform::bluetoothDeviceConnected);
connect(bluetoothManager, &bluetooth::bluetoothDeviceDisconnected, this, &homeform::bluetoothDeviceDisconnected);
connect(bluetoothManager, &bluetooth::deviceFound, this, &homeform::deviceFound);
connect(bluetoothManager, &bluetooth::deviceConnected, this, &homeform::deviceConnected);
connect(bluetoothManager, &bluetooth::deviceFound, this, &homeform::deviceFound);
connect(bluetoothManager, &bluetooth::ftmsAccessoryConnected, this, &homeform::ftmsAccessoryConnected);
connect(bluetoothManager, &bluetooth::deviceConnected, this, &homeform::trainProgramSignals);
connect(bluetoothManager, &bluetooth::deviceConnected, this, &homeform::deviceConnected);
connect(this, &homeform::workoutNameChanged, this->userTemplateManager,
&TemplateInfoSenderBuilder::onWorkoutNameChanged);
connect(this, &homeform::workoutStartDateChanged, this->userTemplateManager,

View File

@@ -53,7 +53,31 @@ var pedometer = CMPedometer()
{
return WatchKitConnection.stepCadence;
}
@objc public func setWorkoutType(workout_type: Int) -> Void
{
var sender: String
if UIDevice.current.userInterfaceIdiom == .pad {
sender = "PAD"
} else {
sender = "PHONE"
}
WatchKitConnection.workout_type = workout_type;
Server.server?.send(createString(sender: sender))
}
@objc public func setWorkoutState(workout_state: Int) -> Void
{
var sender: String
if UIDevice.current.userInterfaceIdiom == .pad {
sender = "PAD"
} else {
sender = "PHONE"
}
WatchKitConnection.workout_state = workout_state;
Server.server?.send(createString(sender: sender))
}
@objc public func setDistance(distance: Double) -> Void
{
var sender: String
@@ -115,7 +139,7 @@ var pedometer = CMPedometer()
}
func createString(sender: String) -> String {
return "SENDER=\(sender)#HR=\(WatchKitConnection.currentHeartRate)#KCAL=\(WatchKitConnection.kcal)#BCAD=\(WatchKitConnection.cadence)#SPD=\(WatchKitConnection.speed)#PWR=\(WatchKitConnection.power)#CAD=\(WatchKitConnection.stepCadence)#ODO=\(WatchKitConnection.distance)#";
return "SENDER=\(sender)#HR=\(WatchKitConnection.currentHeartRate)#KCAL=\(WatchKitConnection.kcal)#BCAD=\(WatchKitConnection.cadence)#SPD=\(WatchKitConnection.speed)#PWR=\(WatchKitConnection.power)#CAD=\(WatchKitConnection.stepCadence)#ODO=\(WatchKitConnection.distance)#STA=\(WatchKitConnection.workout_state)#TYP=\(WatchKitConnection.workout_type)#";
}
@objc func updateHeartRate() {

View File

@@ -109,6 +109,14 @@ class Connection {
if sender?.contains("PAD") ?? false && message.contains("PWR=") {
let pwr : String = message.slice(from: "PWR=", to: "#") ?? ""
WatchKitConnection.power = (Double(pwr) ?? 0)
}
if sender?.contains("PAD") ?? false && message.contains("TYP=") {
let workout_type : String = message.slice(from: "TYP=", to: "#") ?? ""
WatchKitConnection.workout_type = (Int(workout_type) ?? 0)
}
if sender?.contains("PAD") ?? false && message.contains("STA=") {
let workout_state : String = message.slice(from: "STA=", to: "#") ?? ""
WatchKitConnection.workout_type = (Int(workout_state) ?? 0)
}
}
}

View File

@@ -29,6 +29,12 @@ class WatchKitConnection: NSObject {
static var power = 0.0
static var cadence = 0.0
//enum WORKOUT_EVENT_STATE { STARTED = 0, PAUSED = 1, RESUMED = 2, STOPPED = 3 };
static var workout_state = 3
// enum BLUETOOTH_TYPE { UNKNOWN = 0, TREADMILL, BIKE, ROWING, ELLIPTICAL };
static var workout_type = 1
private override init() {
super.init()
}
@@ -136,6 +142,8 @@ extension WatchKitConnection: WCSessionDelegate {
replyValues["cadence"] = WatchKitConnection.cadence
replyValues["power"] = WatchKitConnection.power
replyValues["speed"] = WatchKitConnection.speed
replyValues["workout_state"] = Double(WatchKitConnection.workout_state)
replyValues["workout_type"] = Double(WatchKitConnection.workout_type)
replyHandler(replyValues)

View File

@@ -12,6 +12,8 @@ class lockscreen {
void setSpeed(double speed);
void setPower(double power);
void setCadence(double cadence);
void setWorkoutType(int workout_type);
void setWorkoutState(int workout_state);
// virtualbike
void virtualbike_ios();

View File

@@ -69,6 +69,14 @@ void lockscreen::setSpeed(double speed)
[h setSpeedWithSpeed:speed];
}
void lockscreen::setWorkoutType(int workout_type)
{
[h setWorkoutTypeWithWorkout_type:workout_type];
}
void lockscreen::setWorkoutState(int workout_state)
{
[h setWorkoutStateWithWorkout_state:workout_state];
}
void lockscreen::virtualbike_ios()
{

View File

@@ -721,6 +721,8 @@ void m3ibike::processAdvertising(const QByteArray &data) {
if (heartRateBeltDisabled) {
#if defined(Q_OS_IOS) && !defined(IO_UNDER_QT)
long appleWatchHeartRate = h->heartRate();
h->setWorkoutType(deviceType());
h->setWorkoutState(lastState);
h->setKcal(KCal.value());
h->setDistance(Distance.value());
h->setSpeed(Speed.value());