-
hi @ChrisHardie pairing with Android should be possible via Chrome + WebBLE. iPhone is a little trickier. When you say pair to access internet what are you planning to accomplish?
Checkout the threads on GadgetBridge
In a nutshell, if you have a hosted web application, on Android it is a breeze. You even get notifications via GadgetBridge.
On iOS you need to buy an app (very reasonably priced) to access the web application because Safari doesn't have WebBLE support yet. I don't think there is a GadgetBridge equivalent on iOS yet. I could be wrong.
-
The ?[255] error comes when you had code saved to flash which you were executing from, and then you erase the flash memory while you're still executing that code :) If, after an eraseAll, you do reset() or load() everything will be fine.
Bingo, that did it... Thanks.
I think I should probably just get rid of the 'My Files' tab now since the IDE handles it in a more sane way (and allows you to download StorageFile files directly). Do you have any objections to that?
Nopes, no issues. I will take efforts to figure out how the IDE handles it though :D (I saw the post, just haven't gotten around to reviewing it yet).
In terms of file size, I believe each 'chunk' is about 4k, and you get around 255 chunks - so you can save about one megabyte of data. Right now only the first megabyte of flash is actually exposed to JS apps, so that's really all you can store.
That's cool. Knowing limits helps work backwards :-). I shall now make efforts towards being more succinct in my data storage attempts. It is a watch after all :-)
1MB of data is a lot though - it'll take ages to download. Do you really need to store data at that granularity?
True. It does take a while (I haven't messed with baud rates so whatever default speed it is) to transfer the maxed out file. However, looks like my current inefficient data storage is filling up in about 8-10 hours of HR and Step counts. I would love for it to last a day. So my task is cut-out :-)
This post is resolved for everything I started with, but one last question if I may: Any plans to make the rest of the memory available to apps ? If not via StorageFile maybe a new namespace like Archive or something so we can move files from 'active' storage area to 'Archive' area from time to time? 4Mb will also run out at some point... just good to know :-)
-
I got the 'file too big' error again and unfortunately, since it wasn't handled, it led to the file system getting corrupted again. The only way to recover is
require("Storage").eraseAll()
and start from scratch.I'll put in some defensive code to handle the file too big error and try a file rollover until
require("Storage").getFree()
returns a lowish number. -
I think point 3. above is resolved after restructuring my code (ref: comment in my other post ). Now to see if I get the large file issue again.
-
Thanks @Gordon and @allObjects for the pointers. I did something hopefully in line with your suggestions and it seems to work! Wahooooo!
Here's how I added to the global
Bangle
name spaceBangle.AppLog = { currentFile: null, lock: false, init: (filename) => { try{ if(filename != null && filename != ''){ Bangle.AppLog.currentFile = s.open(filename, "a"); } else{ console.error("Log file name not provided"); } } catch(ex){ console.log("Failed to create file", ex); } }, write : (sentence) => { if(Bangle.AppLog.lock != true){ Bangle.AppLog.currentFile.write(sentence + "\n"); } }, clearLog: () => { Bangle.AppLog.lock = true; Bangle.AppLog.currentFile = null; require("Storage").open("ftclog", "w").erase(); Bangle.AppLog.lock = false; load(); } };
Calling
Bangle.AppLog.clearlog()
from the python script does the trick. Allftclog
files get removed, the app gets reloaded and I am left with a grin on my face :DAlso, as suggested by @Gordon I used the
load()
function inclearLog()
and it works like a treatThanks again.
P.S. I should really save the incoming filename so I don't have to hardcode it in the
clearLog()
:D -
Interesting update. This time when I called eraseAll I got this instead. I think I've corrupted the system overall, better start from scratch, brb.
UPDATE: Please ignore this, possibly a red-herring from an unclean file-system.
[255] ?[255] ?[255] ?[255] ?[255] ?[255]... ^ in function called from system Uncaught SyntaxError: Got ?[255] expected EOF at line 1 col 1 ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255]... ^ in function called from system Uncaught SyntaxError: Got ?[255] expected EOF at line 1 col 1 ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255]... ^ in function called from system Uncaught SyntaxError: Got ?[255] expected EOF at line 1 col 1 ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ?[255] ^ in function called from system at line 1 col 1
-
I am having a few issues with large files
"My files" tab seems to crash if it tries to show all the segments with an error like follows:
<BLE> Unable to decode "[\".boot0\",\".bootcde\",\"%2Bboot\",\"%2Bsetting\",\"-setting\",\"%40setting\",\"*setting\",\"%2Babout\",\"-about\",\"*about\",\"%2Bsbt\",\"%3Dsbt\",\"%2Bsbat\",\"%3Dsbat\",\"%2Bfitclck\",\"-fitclck\",\"*fitclck\",\"ftclog%01\",\"ftclog%02\",\"ftclog%03\",\"ftclog%04\",\"ftclog%05\",\"ftclog%06\",\"ftclog%07\",\"ftclog%08\",\"ftclog%09\",\"ftclog%0A\",\"ftclog%0B\",\"ftclog%0C\",\"ftclog%0D\",\"ftclog%0E\",\"ftclog%0F\",\"ftclog%10\",\"ftclog%11\",\"ftclog%12\",\"ftclog%13\",\"ftclog%14\",\"ftclog%15\",\"ftclog%16\",\"ftclog%17\",\"ftclog%18\",\"ftclog%19\",\"ftclog%1A\",\"ftclog%1B\",\"ftclog%1C\",\"ftclog%1D\",\"ftclog%1E\",\"ftclog%1F\",\"ftclog%20\",\"ftclog!\",\"ftclog%22\",\"ftclog%23\",\"ftclog%24\",\"ftclog%25\",\"ftclog%26\",\"ftclog'\",\"ftclog(\",\"ftclog)\",\"ftclog*\",\"ftclog%2B\",\"ftclog%2C\",\"ftclog-\",\"ftclog.\",\"ftclog%2F\",\"ftclog0\",\"ftclog1\",\"ftclog2\",\"ftclog3\",\"ftclog4\",\"ftclog5\",\"ftclog6\",\"ftclog7\",\"ftclog8\",\"ftclog9\",\"ftclog%3A\",\"ftclog%3B\",\"ftclog%3C\",\"ftclog%3D\",\"ftclog%3E\",\"ftclog%3F\",\"ftclog%40\",\"ftclogA\",\"ftclogB\",\"ftclogC\",\"ftclogD\",\"ftclogE\",\"ftclogF\",\"ftclogG\",\"ftclogH\",\"ftclogI\",\"ftclogJ\",\"ftclogK\",\"ftclogL\",\"ftclogM\",\"ftclogN\",\"ftclogO\",\"ftclogP\",\"ftclogQ\",\"ftclogR\",\"ftclogS\",\"ftclogT\",\"ftclogU\",\"ftclogV\",\"ftclogW\",\"ftclogX\",\"ftclogY\",\"ftclogZ\",\"ftclog%5B\",\"ftclog%5C\",\"ftclog%5D\",\"ftclog%5E\",\"ftclog_\",\"ftclog%60\",\"ftcloga\",\"ftclogb\",\"ftclogc\",\"ftclogd\",\"ftcloge\",\"ftclogf\",\"ftclogg\",\"ftclogh\",\"ftclogi\",\"ftclogj\",\"ftclogk\",\"ftclogl\",\"ftclogm\",\"ftclogn\",\"ftclogo\",\"ftclogp\",\"ftclogq\",\"ftclogr\",\"ftclogs\",\"ftclogt\",\"ftclogu\",\"ftclogv\",\"ftclogw\",\"ftclogx\",\"ftclogy\",\"ftclogz\",\"ftclog%7B\",\"ftclog%7C\",\"ftclog%7D\",\"ftclog~\",\"ftclog%7F\",\"ftclog%80\",\"ftclog%81\",\"ftclog%82\",\"ftclog%83\",\"ftclog%84\",\"ftclog%85\",\"ftclog%86\",\"ftclog%87\",\"ftclog%88\",\"ftclog%89\",\"ftclog%8A\",\"ftclog%8B\",\"ftclog%8C\",\"ftclog%8D\",\"ftclog%8E\",\"ftclog%8F\",\"ftclog%90\",\"ftclog%91\",\"ftclog%92\",\"ftclog%93\",\"ftclog%94\",\"ftclog%95\",\"ftclog%96\",\"ftclog%97\",\"ftclog%98\",\"ftclog%99\",\"ftclog%9A\",\"ftclog%9B\",\"ftclog%9C\",\"ftclog%9D\",\"ftclog%9E\",\"ftclog%9F\",\"ftclog%A0\",\"ftclog%A1\",\"ftclog%A2\",\"ftclog%A3\",\"ftclog%A4\",\"ftclog%A5\",\"ftclog%A6\",\"ftclog%A7\",\"ftclog%A8\",\"ftclog%A9\",\"ftclog%AA\",\"ftclog%AB\",\"ftclog%AC\",\"ftclog%AD\",\"ftclog%AE\",\"ftclog%AF\",\"ftclog%B0\",\"ftclog%B1\",\"ftclog%B2\",\"ftclog%B3\",\"ftclog%B4\",\"ftclog%B5\",\"ftclog%B6\",\"ftclog%B7\",\"ftclog%B8\",\"ftclog%B9\",\"ftclog%BA\",\"ftclog%BB\",\"ftclog%BC\",\"ftclog%BD\",\"ftclog%BE\",\"ftclog%BF\",\"ftclog%C0\",\"ftclog%C1\",\"ftclog%C2\",\"ftclog%C3\",\"ftclog%C4\",\"ftclog%C5\",\"ftclog%C6\",\"ftclog%C7\",\"ftclog%C8\",\"ftclog%C9\",\"ftclog%CA\",\"ftclog%CB\",\"ftclog%CC\",\"ftclog%CD\",\"ftclog%CE\",\"ftclog%CF\",\"ftclog%D0\",\"ftclog%D1\",\"ftclog%D2\",\"ftclog%D3\",\"ftclog%D4\",\"ftclog%D5\",\"ftclog%D6\",\"ftclog%D7\",\"ftclog%D8\",\"ftclog%D9\",\"ftclog%DA\",\"ftclog%DB\",\"ftclog%DC\",\"ftclog%DD\",\"ftclog%DE\",\"ftclog%DF\",\"ftclog%E0\",\"ftclog%E1\",\"ftclog%E2\",\"ftclog%E3\",\"ftclog%E4\",\"ftclog%E5\",\"ftclog%E6\",\"ftclog%E7\",\"ftclog%E8\",\"ftclog%E9\",\"ftclog%EA\",\"ftclog%EB\",\"ftclog%EC\",\"ftclog%ED\",\"ftclog%EE\",\"ftclog%EF\",\"ftclog%F0\",\"ftclog%F1\",\"ftclog%F2\",\"ftclog%F3\",\"ftclog%F4\",\"ftclog%F5\",\"ftclog%F6\",\"ftclog%F7\",\"ftclog%F8\"]\r", got URIError: URI malformed
The above file
ftclog
is actually less than an Mb. But Bangle stops writing to it after a certain point and throws 'file too big' error. Question is, how big a file can I write? Should it be 4Mb-Firmware size? Is that transparent if I useStorageFile
or are there some tricks I am missing.
Update : Removed 3rd point which is unrelated to large files.
-
Thanks @Gordon
I never thought of putting the file handle in global area and manipulate it from there (me and my obsession with encapsulation). I shall do that and post the results here :-).
-
Thanks @Gordon... I did start using the
getAccel
on everystep
event to get the accelerometer values. Now I am treating the 'step' event as a throttle for the 'accel' event. I tried loggingaccel
event, and it turned out to be a firehose that filled up the internal memory very quickly. So the plan is to try and find patterns inaccel
data and then 'tune' the event appropriately.Getting some exciting
accel
readings at current sensitivity level. I will also play around with the Options.The issue with context was a non-issue. It is still to do with file save but again, separate thread :-)... I have removed it from the title and marked this one as resolved.
Cheers.
-
Thanks for the update @Gordon. Can we have a "Debug To" settings in the settings app, can we use it to toggle the logging on to Console/LCD/None?
I see uses for log being written to the LCD when I am coding, for example currently my watch is looping "Unable to open file" and previously it was showing "File too big" [Different issue again, I'll report it separately] :-).
-
Super awesome! I was planning to make one myself, but this will do just fine :-). Many thanks @MaBe :-)
-
I have a problem of mostly my own making. My clock app writes various sensor settings to a log file and I have a python script that I can use to connect to the watch and download this log file (which is split by Bangle).
However, deleting the files via the script doesn't quite have any effect on the files because my app I believe holds on to the file handle and keeps writing to the same file.
To work around this, I put in a watch reboot usingE.reboot()
and this I believe clears the file handle and the files are actually gone for good and after reboot the app restarts and opens a new file handle.Now rebooting is a bazooka where a restart App would just do. If I could invoke a function on the app to tell it to reopen the file, that would be even more precise. Long-pressing BTN3 already does a reload, how can I mimic this via code?
There is also the possibility I am using the StorageFile API incorrectly. There isn't a
StorageFile.close()
orStorage.close()
so I didn't think I would need to close the file after each update and open it before each update.Any suggested approaches welcome. Thanks
Python script for sync
Custom BangleJS AppUpdate: Reboot actually doesn't work. It leaves the watch storage in an inconsistent state and the app is unable to update the file anymore. Keeps throwing
Uncaught Error: Unable to find or create file
. Basically I have to now invokeStorage.eraseAll()
and start fresh :(I'll have to think of a custom roll-over or something so the older log files are cleared out after it has been synced with a laptop.
-
The UI of the watch face seems to get corrupted ever so often after I installed this version.
{ "VERSION": "2v04.99", "GIT_COMMIT": "3bd026c", "BOARD": "BANGLEJS", "FLASH": 524288, "SPIFLASH": 4194304, "STORAGE": 1048576, "RAM": 65536, "SERIAL": "a0cf0da6-7b6c234d", "CONSOLE": "Bluetooth", "MODULES": "Flash,Storage,heatshrink,tensorflow,graphical_menu", "EXPTR": 536883676 }
I am using a modified
mclock
app.
Looks like everytime I connect to console or disconnect from console it logs something to the screen pushing the buffer up. This results in the next paint (onlcdPower
) picking up the wrong corrupted buffer and keeps repainting it until the next corruption happens. As seen in the next image, the time is actually1:12 am
.Initially I thought I wasn't repainting the widgets on
lcdpower
event hence it looked corrupted. Now after repainting the widget area, the widgets show up correctly but as you can see there is a bit of corruption above the widget as well.My code is here
It is based off the beta version ofmclock
with some modifications. I've updated how the widgets are loaded and painted as per latest version ofmclock
.Reloading the app by long-pressing button 3 temporarily resolves this. (I have also lost Button 2 click so can't get to settings, but that's a different issue I believe, still digging into that).
-
@AkosLukacs how does localhost work without https? WebBLE is meant to work on https only... then again... I don't have Chrome... I am using Chromium... maybe that's the difference... Google bends the rules when it comes to it's brand I guess :D
-
If you publish the github.io page for your repo, I can do one better, install it on my Beta watch :-)
Update I see it is available, hold on... :-)
Unfortunately I cannot deploy the
WorkoutHearRateMonitor
because it throws an error regarding the icon being missing. Should a quick fix. Happy to try again when you have fixed it :-) -
Okay, I am a numpty... I think I hit enter by mistake and now I can't seem to edit the original post anymore... here is what I wanted to say
I finally got around to incorporating the 'step' event in my code and it seems to fire rather easily, e.g. even when I am typing with the watch on.
Now of course step calculation with accelerometer is buggy in every sport watch I have seen, so I am fine that we have to 'train' the Bangle better. So in this respect I have a few requests:
Can the callback get the 'raw' values based on which the decision is being made? That way we can dig in and try to find patterns to get it closer to real.
I noticed the callback function doesn't seem to be in the right context. This could just be my code but the only difference between how I have assigned callbacks for
HRM
orgps
events, is there is a dedicatepower
call for each. I'll try to use the good ol'_this
and fix it.
I didn't feel like filing a bug in repo because I didn't have anything positive to contribute on how to fix it. So apologies if this is in the wrong place.
-
Hi @Gordon, thank you for the updates.
Looks like my real wishlist is I rtfm :D :D :D. if
storage.read('filname').length
will give mesize
I am happy to use that :)
Regarding the wildcard, it is a very low prio thing and a requirement that came up from me doing something wrong. I had ended up with loads of my log files with \xNN in the end even though the root file was deleted. I don't exactly know what triggered it, becauseStorageFile.erase()
works reliably. So I tried to loop though these rouge files and delete them one at a time, but that didn't work. Eventually I ran out of space and did aeraseAll
and reset everything. I was wondering if a wildcard delete would help in these cases.I will now go and read up on all the other pointers you have provided :-).
I am building my dashboard using NodeJS, SQLite and Mapbox. Coincidentally I started with the BangleApps repo and wanted to add a tab myself :-) but then got into a tangle with WebBLE and https (maybe I'll revisit with ngrok), and since I do most of my hacking during my commute on train, being able to code and test without internet became the driver to look for a more
offline
solution.That said I will happily add a tab that shows maps and GPS data from the GPS widget. How are you storing the data NEMA sentences or JSON ?
I understand the problems with minification. I have created a
dev
folder in myBangleApps
fork (image attached) for my app only and I run a Gulp script to minify and move it to the actualapps
folder. I guess to do this on commit you'll need some kind of pre-commit hook? I vaguely remember that kind of thing being possible, I can lookup details on this if this looks like an easy enough approach. (Of course the gulp script will need some refinement :-)... )Oh one more request, is there a way to introduce a user selectable GPS polling rate? I want to progressively dock down polling rate once I loose GPS signal so it saves battery. Currently I am very abrupt about it, if I loose GPS for 2/3 minutes, boom, power off GPS so I have to manually restart it. I guess I could build a timer functionality to wake up and test, if that's the only way from a h/w perspective I am fine, no need to build an API feature.
-
Hi @Gordon,
Apologies for not submitting an app, mine isn't 'complete' yet :-( but I guess I bit off more than I could chew. However, I have managed to form a wish-list:More options in Storage API. Currently I miss a
sizeofFile
and aerase("myfile*")
option. First one more than the second :-)Some guidance on how to build multi feature apps. My app for example is a clock face that does, GPS and HR when asked to (button trigger). I plan to introduce step counter as well. Should I build each as a widget or bake it into a clock app? Currently the eventing system seems to work well in one app, but I haven't tested it fully.
Lots more guidance on how to start with recording gestures so it can be fed back to the AI engine. A lot of it might be outside BangleJS eco-system (more to do with TensorFlow Lite) so some links on where to get started for a noob like me would be really nice
Also is the minify on deploy feature being built or has it been made redundant with ability to load files off flash. Asking because I had to move my development work to a separate
dev
folder which then isgulp
-ed and sent into theApps
folder as a minified file.
Apologies for not updating the firmware yet. I promise to do it this week :-)
I have managed to sync between the watch and laptop using Python and currently focused on building a dashboard that pulls in the GPS data and shows pretty maps. The Python script has lots of hard-coded values so at best a pre-alpha quality script, but it will not delete anything off your watch, so you are safe ;-)
P.S. Let me know if I shouldn't use the name 'Bangle' in my repos, or happy to rename any if the official repo wants them.
-
@Gordon thanks... works perfectly with
StorageFile
. Silly me 🥴, I was trying to use Storage.read or something. -
@Gordon just to clarify, once the file increases in size and starts getting the shard marker in the end we have to use the shard marker in the name when we do a read, correct?
// say I have written a big file called 'myfile' var s = require("Storage"); // print(s.read("myfile")); // would return undefined print(s.read("myfile\1")); // returns the first block of the file.
I am getting this behaviour, I am still on the default beta version firmware that came with my KS Beta unit.
-
Okay, as per this example from bleak, Darwin aka OSX doesn't work with MAC address, it needs the funky string ID of the device.
-
Brilliant! Finally got something to work...
bleak
works on my laptop.The example gives the impression that the mac address of the BangleJS is good enough to connect to it, but that didn't work. So instead I commented out the command
run
and used the discoverrun
to first get the address. It came out as a long set of strings for all the nearby BLE devices, thankfully it identified Bangle as follows (I've mangled the last 5 characters).0DB07D6F-8F0F-4CB3-A801-0D9A868XX9XX: Bangle.js ed8a
I then used this as the address and the following code came back with a list of files though it is still a bit mangled, but it's a start.
import asyncio import array from bleak import discover from bleak import BleakClient address = "0DB07D6F-8F0F-4CB3-A801-0D9A868XX9XX" UUID_NORDIC_TX = "6e400002-b5a3-f393-e0a9-e50e24dcca9e" UUID_NORDIC_RX = "6e400003-b5a3-f393-e0a9-e50e24dcca9e" command = b"\x03\x10var f = require('Storage')\n\x10 print(f.list())\n\x10print('Hello World')\n" def uart_data_received(sender, data): print("RX> {0}".format(data)) # You can scan for devices with: # async def run(): # devices = await discover() # for d in devices: # print(d) print("Connecting...") async def run(address, loop): async with BleakClient(address, loop=loop) as client: print("Connected") await client.start_notify(UUID_NORDIC_RX, uart_data_received) print("Writing command") c=command while len(c)>0: await client.write_gatt_char(UUID_NORDIC_TX, bytearray(c[0:20]), True) c = c[20:] print("Waiting for data") await asyncio.sleep(1.0, loop=loop) # wait for a response print("Done!") loop = asyncio.get_event_loop() loop.run_until_complete(run(address, loop)) # loop.run_until_complete(run())
-
@ConorONeill Thanks... and @Gordon woah... how did I miss that... Thanks a ton... Given noble is unhappy on my laptop, I'll give Python a go...
-
@ConorONeill thanks for the heads up... I was having trouble with my dev environment, first OSX baulked, but I don't have full XCode (only bare minimum) installed, so I thought I would try Linux.
Then my linux box baulked, someone has messed the apt-repository index files and it won't install anything.
So my third step was to setup a Pi... This is where I had left it until I saw your note. Will proceed with caution.
Any alternates you know of?
@AkosLukacs yeah I think all I need to do it stick the self signed cert into the Trusted Keystore, now if I could only find a reliable documentation on how to do that on OSX. The cert generated by OSX Keystore isn't accepted by http-server (node app) and the one generated by openssl isn't accepted into the Keystore atm.
Might come back to this if Noble fails.
Haa you noticed... well, the
write
function is called by various Bangle events likeGPS
,HRM
andstep
. These are asynchronous, I didn't want them to try to write to the file while I am trying to clear the log. It may loose a few readings, that's fine for now.The code does clear logs successfully without corrupting the file system, but now I have hit the next issue. If the file reaches max-size and fails to write, the file system gets corrupt yet again. Going to attempt a few strategies to mitigate :-). First up compression to enable more data :-)