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

Simulator and File Transfer not copying file as expected

ANSWERED

I am trying to use the FileTransfer API to copy a jpeg file generated by a web service API to the simulator.

The idea is that when the file is copied to the simulator, I give it a specific name and then set that name as the href of the image tag.

I am running the simulator on a Windows 10 pc and have found that the folder on the pc that contains the copied image. which is C:\Users\[username]\AppData\Roaming\Fitbit OS Simulator\ionic\app\apps\1\private\data. If the folder is empty and I run the code for the first time, the file is copied and everything works correctly. If a file exists, it is not overwritten and no error occurs.

I have tried a number of different processes, the current code I have send a unique filename, from the companion, and then on receipt of that file on the app on the simulator, deletes the existing file and then renames the new file to the name that I want it to have.

While the code appears to be doing what I want from my debug messages, the file does not change, this can be seen as the image is the same and so is the date and timestamp of the file.

 

I hope that is clear, here is my code:

On the companion

  let cardno = "1234567890" ;
let destFileName = "qrcode" +new Date().getTime()+".jpeg";
let srcImage = "https://api.qrserver.com/v1/create-qr-code/?size=200x200&border=10&data="+cardno+"&format=jpeg" ;
// Fetch the image from the internet fetch(srcImage).then(function (response) { // We need an arrayBuffer of the file contents return response.arrayBuffer(); }).then(function (data) { // Queue the file for transfer outbox.enqueue(destFilename, data).then(function (ft) { // Queued successfully console.log("Transfer of '" + destFilename + "' successfully queued."); }).catch(function (error) { // Failed to queue throw new Error("Failed to queue '" + destFilename + "'. Error: " + error); }); }).catch(function (error) { // Log the error console.log("Failure: " + error); });

on the app

 



inbox.onnewfile = function () {
const FILENAME = "qrcode.jpeg"; var fileName;
var image = document.getElementById("image");
fileName = inbox.nextFile(); if(fileName){ console.log(fileName + " received"); if(fileExists(FILENAME)){ image.href = "" ; fs.unlinkSync(FILENAME); if(!fileExists(FILENAME)) console.log(FILENAME +" deleted"); } fs.renameSync(fileName, FILENAME);
console.log(fileName + " renamed to " + FILENAME); }

 My log shows the following

Capture.PNG

which all indicates that it was a success 

 

Can any one give me any assistance in working this out

 

 

Best Answer
0 Votes
1 BEST ANSWER

Accepted Solutions

Unfortunately the UI doesn't update if you reuse the same filename, even if you've replaced the contents of the file.

 

Use your generated filename, but just keep track of it. That's what the photo-picker demo does. https://github.com/Fitbit/sdk-photo-picker/blob/master/app/index.js#L42

View best answer in original post

Best Answer
8 REPLIES 8

I copied your code and ran it.  It runs fine.  The file is copied down, the prior one deleted and the new one renamed.  Timestamps are correct. 

The only changes I made to your code was to create the fileExists method and correct the capitalization of the variable destFileName, only the declaration had the capital N.

Rich

Best Answer
0 Votes

Rich,

 

Thanks for feed back but I can not get it to work as expected. and I am having some strange results, I don't know if it is Windows 10 or the Simulator. As I personally don't have a ionic or versa at the moment (stuck with a blaze) I cant see what happens in the real world.

 

I have made some changes to the code and here is what I have noted.

Even though I am deleting the file using fs.unlinkSync()  before calling inbox.nextFile(), the created date stays the same although the content and modified date are changing, so it does appear that the update is occurring, just not how I expected.

 

What does not appear to be happening is the display of the new version of file. Which only occurs when I restart the application.

 

I set the image.href to "/private/data/" + FILENAME every time the image changes, but it does not change on the simulator.

 

I have added code to

  • rename the image.href to "icon.png" 
  • delete the FILENAME,
  • getting the new version
  • reset the image.href to "/private/data/" + FILENAME 

But the image does not change.

If I stop the app and restart it it picks up the latest FILENAME

 

Here is my full code, full of debug and worry. Show me where I am going wrong Smiley Sad

 

app/device-settings.js

import { me } from "appbit";
import * as fs from "fs";
import * as messaging from "messaging";

const SETTINGS_TYPE = "cbor";
const SETTINGS_FILE = "settings.cbor";

let settings, onsettingschange;

export function initialize(callback) {
  settings = loadSettings();
  onsettingschange = callback;
  onsettingschange(settings);
}

// Received message containing settings data
messaging.peerSocket.addEventListener("message", function(evt) {
  console.log("Device Setting Changed:"+evt.data.key+"="+JSON.stringify(evt.data.value));
  settings[evt.data.key] = evt.data.value;
  onsettingschange(settings);
})

// Register for the unload event
me.addEventListener("unload", saveSettings);

// Load settings from filesystem
function loadSettings() {
  console.log("Loading Settings");
  try {
    return fs.readFileSync(SETTINGS_FILE, SETTINGS_TYPE);
  } catch (ex) {
    return {};
  }
}

// Save settings to the filesystem
function saveSettings() {
  console.log("Saving Settings");
  fs.writeFileSync(SETTINGS_FILE, settings, SETTINGS_TYPE);
}

app/index.js

import document from "document";
import { inbox } from "file-transfer"
import * as fs from "fs";
import * as simpleSettings from "device-settings";
import { display } from "display";

display.autoOff = true;

var image = document.getElementById("image");
var activeFileName ;

function settingsCallback(data) {
  activeFileName = "" ;
  if (!data) {
    return;
  }
  if (data.cardno){
    activeFileName = buildFileName(data.cardno.name) ;
    console.log("Active File Name : " + activeFileName)  
  }
/*  
  if (data.cardno_old){
    var fileName = buildFileName(data.cardno_old.name) ;
    if( fileExists(fileName)){
      console.log("Deleting Old File :" + fileName) ;
      fs.unlinkSync( fileName)
    }
  }
*/  
}

console.log("Initalizing Application")
simpleSettings.initialize(settingsCallback);

// First rule - check if there is a file in the inbox
newFile() ;


// Event occurs when new file(s) are received
inbox.onnewfile = function () {
  image.href = "icon.png";
  if(fileExists(activeFileName)){
    fs.unlinkSync(activeFileName);
    console.log(activeFileName + " Exists : " + (fileExists(activeFileName) == true)) ;
  }
  
  newFile();
};

function newFile(){
  var fileName;
  do {
    // If there is a file, move it from staging into the application folder
    fileName = inbox.nextFile();
    if (fileName) {
      console.log(fileName + " recieved");
    }
  } while (fileName);
  
  setDisplay() ;
}

function setDisplay()
{
  var fileName = activeFileName ;
  // If a jpg exists then we need to show the jpg and hide the text
    if(fileExists(fileName)){
      console.log("image.href=["+ image.href +"]");
      console.log("File Exists...Show Image");
      image.href = "/private/data/"+activeFileName ;
      show(image) ;
      hide(document.getElementById("noimage"));
    }
  else{
    console.log("No File Exists...Show Text") ;
    show(document.getElementById("noimage"));
  }
}

function buildFileName(cardno){
  return "qrcode.jpeg" ;
}


function hide( elm )
{
  elm.style.display = "none";  // hidden
}

function show( elm )
{
  elm.style.display = "inline"; // visible
}

function fileExists(fileName){
  try {
    fs.readFileSync(fileName);
  }
  catch(e) {
    return false ;
  }  
  return true ;
}

companion/companion-settings.js

import * as messaging from "messaging";
import { settingsStorage } from "settings";

var onsettingschange;

export function initialize(callback) {
  onsettingschange = callback ;
  
  settingsStorage.addEventListener("change", evt => {
    if (evt.oldValue !== evt.newValue) {
      onsettingschange(evt);
      console.log("Companion Setting Changed:" + evt.key + "=" + evt.newValue);
      sendValue(evt.key, evt.newValue);
      sendValue(evt.key+"_old", evt.oldValue);
    }
  });
}

function sendValue(key, val) {
  if(val) {
    sendSettingData({
      key: key,
      value: JSON.parse(val)
    });
  }
}

function sendSettingData(data) {
  if (messaging.peerSocket.readyState === messaging.peerSocket.OPEN) {
    console.log("Sending Data " + JSON.stringify(data)) ;
    messaging.peerSocket.send(data);
  } else {
    console.log("No peerSocket connection");
  }
}

companion/index.js

import * as simpleSettings from "companion-settings";
import { outbox } from "file-transfer"

simpleSettings.initialize(settingsCallback);

function settingsCallback(evt) {
  console.log("In Companion settingsCallback") 
  if (!evt) {
    return;
  }
  // Extract the card number && pass it to the QRCode Generator
  sendQRCode(JSON.parse(evt.newValue).name);
}



function sendQRCode(cardno) {

  let srcImage = "https://api.qrserver.com/v1/create-qr-code/?size=200x200&margin=10&data="+cardno+"&format=jpeg" ;

  console.log(srcImage);
  
  // Destination filename
  let destFilename = buildFileName(cardno) ;

  // Fetch the image from the internet
  fetch(srcImage).then(function (response) {
    // We need an arrayBuffer of the file contents
    return response.arrayBuffer();
  }).then(function (data) {
    // Queue the file for transfer
    outbox.enqueue(destFilename, data).then(function (ft) {
      // Queued successfully
      console.log("Transfer of '" + destFilename + "' successfully queued.");
    }).catch(function (error) {
      // Failed to queue
      throw new Error("Failed to queue '" + destFilename + "'. Error: " + error);
    });
  }).catch(function (error) {
    // Log the error
    console.log("Failure: " + error);
  });
}

function buildFileName(cardno){
  return "qrcode.jpeg" ;
}

settings/index.jsx

console.log("Settings Stared")

function Card(props) {
  return (
    <Page>
      <Section
        title={<Text bold align="center">Card</Text>}>
        <TextInput
          settingsKey="cardno"
          label="Card No."
        />
      </Section>
    </Page>
  );
}

registerSettingsPage(Card);

 

 

 resources/index.gui

<svg id="root">
  <text id ="noimage"
    x="50%" y="50%" 
    text-anchor="middle"
    fill="red"
    display="none">
    No Card Defined
  </text>
  <section x="50%-100" y="50%-100" width="200" height="200">
    <image id ="image"
      x="0" y="0" 
      href=""
      display="none"         
      load="sync" />
  </section>
</svg>

 

 

 

 

 

 

 

Best Answer
0 Votes

I've had no trouble in the past redrawing items on the screen but I've not used an image or tried to refresh an image.  It seems like you system simply isn't recognizing that the file has changed.  Maybe it is the created data that's causing the problem.  If the date doesn't change perhaps the system doesn't think the file has changed, hence the no update.  Have you tried changing the name each time, so the href changes?  I'm setting up a test application to try a few things without the file transfer (although I see nothing wrong with any of your code yet). 

Rich

Best Answer
0 Votes

I do have a version where I change the filename, suffixing the card number to the file name, that does appear to work.

But I am curious to understand why it does not appear to update the href especially as the file content has changed.

Can live with the version I have for now.

 

Best Answer
0 Votes

The display won't update unnecessarily.  So if it's using the created date (which should have changed but apparently isn't), it won't update. I confirmed that it works with the different file name.  So at least we're getting the same results.  The problem may be that the simulator is running on windows and the watch OS is probably some variant of linux.  I can check the original app on my Versa later to today and let you know if it works there.

Best Answer
0 Votes

I can't follow up on my promise to try it out on  my Versa.  The fitbit app on my android phone is aborting trying to get into the apps.  I'll get back to you when I get that fixed.

Rich

Best Answer
0 Votes

Unfortunately the UI doesn't update if you reuse the same filename, even if you've replaced the contents of the file.

 

Use your generated filename, but just keep track of it. That's what the photo-picker demo does. https://github.com/Fitbit/sdk-photo-picker/blob/master/app/index.js#L42

Best Answer

Thanks for the feedback and the example,  have simplified my code no end.

Best Answer
0 Votes