05-29-2018 12:10
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

05-29-2018 12:10
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
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
which all indicates that it was a success
Can any one give me any assistance in working this out
Answered! Go to the Best Answer.
Accepted Solutions
06-05-2018 16:31
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


06-05-2018 16:31
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
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
06-03-2018 23:17
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

06-03-2018 23:17
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
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

06-05-2018 05:41 - edited 06-05-2018 05:43
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

06-05-2018 05:41 - edited 06-05-2018 05:43
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
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
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>

06-05-2018 08:31
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

06-05-2018 08:31
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
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

06-05-2018 09:07
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

06-05-2018 09:07
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
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.

06-05-2018 09:17
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

06-05-2018 09:17
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
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.

06-05-2018 14:30
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

06-05-2018 14:30
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
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

06-05-2018 16:31
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


06-05-2018 16:31
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
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
06-06-2018 02:47
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

06-06-2018 02:47
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Thanks for the feedback and the example, have simplified my code no end.

