Cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Companion unloading while transferring files

ANSWERED

I'm working on a clock face that I want to be customizable using remote images. I have it functioning but I've been noticing that the companion can unload in the middle of my code and leave the settings and companion in a bad state.

The flow of the code is essentially:

  1. User picks the images they want to use in the settings, then clicks save
  2. This updates the settings and companion loads the remote images
  3. Once fetched the companion transfers them to the watch one at a time waiting for each one to complete
  4. When all have been transferred a message is sent to the watch to use the images

I noticed that if the transfers take too long or they happen to start just before the companion unloads my code will get partway through the process, the companion will unload, and things will be in a bad state. It's weird that the companion will unload even if the settings just changed again. Is there anyway to keep the companion alive until the process is finished or at least ensure it doesn't unload if the settings just changed again?

This is essentially the code in the companion that's a problem:

private async handleSettingsChanged(): Promise<void> {
	await transferRemoteAsset("file1", "https://example.com");
	await transferRemoteAsset("file2", "https://example.com");
	await transferRemoteAsset("file3", "https://example.com");
	
	messaging.peerSocket.send();
}

private async transferRemoteAsset(name: string, remotePath: string): Promise<void> {
	console.info(`Requesting remote asset ${remotePath}`);

	//Get the remote data
	const request: Request = new Request(`${RemoteAssetBaseUrl}${remotePath}`);
	const response: Response = await fetch(request);

	if (response.ok == false) {
		throw new Error(`HTTP error! Status: ${response.status}`);
	}

	const remoteData: ArrayBuffer = await response.arrayBuffer();

	console.info(`Received remote asset beginning transfer as ${name}`);

	//Start the transfer of the data
	const transfer: FileTransfer = await outbox.enqueue(name, remoteData);

	//Listen for the transfer to finish
	return new Promise((resolve, reject) => {
		var handler = () => {
			if (transfer.readyState == "transferred") {
				console.info(`Completed transfer of ${name}`);
				resolve();
			} else if (transfer.readyState == "error" || transfer.readyState == "canceled") {
				reject(new Error("Transfer encountered and error or was canceled"));
			}
		}

		transfer.onchange = (e) => handler();
		handler();

		setTimeout(() => {
			reject(new Error("Timeout exceeded waiting for transfer"));
		}, Constants.TransferTimeout * 1000);
	});
}
Best Answer
0 Votes
1 BEST ANSWER

Accepted Solutions

That's very strange. Are the files especially large? If you're using the ImagePicker, they'll only be about 30kB, which is fine.

You could try sending a tiny file from watch to companion (like a ping) every so often (and just discard it when received); that should keep the companion interested for a while.

Peter McLennan
Gondwana Software

View best answer in original post

Best Answer
6 REPLIES 6

That's very strange. Are the files especially large? If you're using the ImagePicker, they'll only be about 30kB, which is fine.

You could try sending a tiny file from watch to companion (like a ping) every so often (and just discard it when received); that should keep the companion interested for a while.

Peter McLennan
Gondwana Software
Best Answer

I noticed the issue when I sent a large file, a 400kb TXI file, but I can get around that issue by sending a JPG instead as that will work in this case.

Giving it more thought I think I need to reconsider how I'm sending the data in the first place. I built the code on the assumption the companion would always be running/would wait for my code to complete and that was a mistake. I think I'll rework my code but the idea of sending a file from the app is a good idea as it will force the companion to load if it's been unloaded. Thanks!

Best Answer
0 Votes

There's a wake-interval thing you can use to wake the companion every five minutes, but that may not help in your situation.

I know that PNG get automatically converted to TXI in some situations, but that may only be on installation. TXI are uncompressed (usually), so large.

Peter McLennan
Gondwana Software
Best Answer
0 Votes

Hi @ayqueue - it is odd but the companion may disconnect anytime if the watch loses connection with the Fitbit App which can happen with the new V4 Fitbit App.

Check if this is random or a consistent failure, and try logout of the Fitbit App, swipe off the active window and in Android clear the storage cache and force stop it before restarting the phone, and the watch.

Also bear in mind that the Fitbit App syncs automatically at times and this could interfere with other ongoing activities so try syncing first before transferring.  It should give you about a 15 minute window.

Author | ch, passion for improvement.

Best Answer
0 Votes

I ended up reworking my code and it seems better but now I'm finding that when the companion is unloaded then reloaded (due to settings change, which is expected) the peerSocket doesn't open the connection. My code is super basic:

import { peerSocket } from "messaging";

peerSocket.addEventListener("open", (evt) => {
    console.log("Ready to send or receive messages");
});

 I basically see this in the logs:

  1. App starts
  2. "Ready to send or receive messages"
  3. Companion unloaded
  4. Settings change
  5. Companion loaded
  6. Companion unloaded

I would have expected the connection to open again after 5. This is all happening within 30 seconds, it's not like a significant amount of time has passed.

Am I just misunderstanding how the companion works? Should it not always re-stablish a connection when it's reloaded?

Best Answer
0 Votes

I've experienced the same problem. I ended up using File Transfer to avoid it. Latency is higher but so is reliability.

Peter McLennan
Gondwana Software
Best Answer