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

Send data from settings to app FitBit

Hi,

 

I'm trying to send an image from settings panel on FitBit app to my app on the FitBit Sense, but I have a problem: I receive the file but I cannot read the content.

 

This is my code:

 

app/index.js:

import { inbox } from "file-transfer";
import * as document from "document";
import * as fs from "fs";

let imageShower = document.getElementById("image");

inbox.onnewfile = () => {
  let fileName;
  
  while (fileName = inbox.nextFile()) {
    if(fileName) {
      console.log(`${fileName} onnewfile`);
      if(checkForFile(fileName)) {
        applySettings(fileName);
      }
    }
  }
};

function applySettings(fileName) {
  console.log(`${fileName} start applySettings`);
  let buff = fs.readFileSync(fileName, "cbor");
  console.log(`content: ${buff}`);
  //imageShower.href = "icon.png";
  console.log(`${fileName} end applySettings`);
}

function checkForFile(fileName) {
  var dirIter;
  var listDir = fs.listDirSync("");
  while((dirIter = listDir.next()) && !dirIter.done) {
    if (dirIter.value === fileName) {
      console.log(`fileName: ${dirIter.value}`);
      console.log(`bytes: ${fs.statSync(fileName).size}`);    
      console.log(`exists?: ${fs.existsSync(fileName)}`);
      
      return true;
    }
  }
  return false;
}
companion/index.js:

import { settingsStorage } from "settings";
import { Image } from "image";
import { encode } from "cbor";
import { outbox } from "file-transfer";

settingsStorage.onchange = function(evt) {
  if (evt.key === "background-image") {
    compressAndTransferImage(evt.newValue);
  }
};

function compressAndTransferImage(settingsValue) {
  let base64 = "";
  const imageData = JSON.parse(settingsValue);
  Image.from(imageData.imageUri)
    .then(image =>
      image.export("image/jpeg", {
        background: "#FFFFFF",
        quality: 100
      })
    )
    .then(buffer => outbox.enqueue(`${Date.now()}.txt`, encode("{ \"base64\" : \"" + arrayBufferToBase64(buffer) + "\" }")))
    //.then(buffer => console.log("{ \"base64\" : \"" + arrayBufferToBase64(buffer) + "\" }"))
    .then(fileTransfer => {
      console.log(`Enqueued ${fileTransfer.name}`);
    });
}

function arrayBufferToBase64(buffer) {
    var binary = '';
    var bytes = new Uint8Array(buffer);
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
        binary += String.fromCharCode(bytes[ i ]);
    }
    return btoa(binary);
}

function base64ToArrayBuffer(base64) {
    var binary_string = atob(base64);
    var len = binary_string.length;
    var bytes = new Uint8Array( len );
    for (var i = 0; i < len; i++)        {
        bytes[i] = binary_string.charCodeAt(i);
    }
    return bytes.buffer;
}
settings/index.jsx:

function mySettings(props) {
  let screenWidth = 950;
  let screenHeight = 950;

  return (
    <Page>
        <ImagePicker
          title="Background Image"
          description="Pick an image to use as your background."
          label="Pick a Background Image"
          sublabel="Background image picker"
          settingsKey="background-image"
          imageWidth={ screenWidth }
          imageHeight={ screenHeight }
        />
    </Page>
  );
}

registerSettingsPage(mySettings);

 

 

These are the logs:

app/index.js:33,7 fileName: 1636303006974.txt
app/index.js:34,7 bytes: 105326
app/index.js:35,7 exists?: true
app/index.js:21,3 1636303006974.txt start applySettings
app/index.js:25,3 1636303006974.txt end applySettings
 
And this is the generated string:
{ "base64" : "base64ofmyimage" }
 
Could you help me?
Thank you.
Best Answer
0 Votes
12 REPLIES 12

It's possible that you're double-encoding your data. I think the API returns base64-encoded data by default. Have a look here.

Peter McLennan
Gondwana Software
Best Answer
0 Votes

Hi,

 

i resolved the problem of the empty file, adding "/private/data/" to the path; now I have the base64 on the app: how can I assign ths to the Image on the view? trying .href, .src, .image with no success.

 

Thank you.

Best Answer
0 Votes

href.

Your screenWidth and screenHeight may cause issues; the device doesn't like to resize images. Plus, sending over BT is slow, and there's little benefit to sending excess resolution unless you're planning panning.

Peter McLennan
Gondwana Software
Best Answer
0 Votes

Mmm the thing is that if I manually set the image (uploading on resource folder), it works; if the problem was the resize, I would see at least a part of the image, but instead seems that the image does not change.

Best Answer
0 Votes

Be sure to test on watch rather than sim (watch is more restricted).

Did you investigate the possibility of double-encoding? Checking file sizes might be a clue.

Peter McLennan
Gondwana Software
Best Answer
0 Votes

Yes, I'm using the device, not the simulator; The base64 sent and received are the same.

Best Answer

Compare file size with the file that you put directly into the resources folder. (This might be an apples-vs-oranges comparison if resizing is involved; try to avoid that.) I still worry that you're base64-encoding a base64-encoded stream.

Peter McLennan
Gondwana Software
Best Answer
0 Votes

The size is the same and the produced base64 (if I put it on a base64 converter) is correct.

It could be a problem utilizing a jpeg? I read in some thread about jpeg to txi conversion.

 

Thank you.

Best Answer
0 Votes

JPG doesn't get converted to TXI; only PNG does. However, there are some restrictions on JPG formats (eg, no progressive encoding). But if you can view the image when saved directly to resources, it's okay.

Peter McLennan
Gondwana Software
Best Answer
0 Votes

The problem is that the base64 is correct, but the image is not being showed in the Versa...

Best Answer
0 Votes

Have you tried setting imageWidth and imageHeight to the exact size of the <image>? The watch doesn't like resizing. If it can't resize something quickly, you'll see nothing rather than a partial image.

 

I'm still unclear why you're doing your own base64 encoding and decoding. The Fitbit API doesn't require it and the Fitbit example doesn't do it. It could just make the file transfer time slower and introduce another source of bugs.

Peter McLennan
Gondwana Software
Best Answer
0 Votes

Hi, 

 

is there an example project to test and deploy on my Sense? So I'll try and debug how it works.

 

Thank you.

Best Answer
0 Votes