diff --git a/apps/powermanager/ChangeLog b/apps/powermanager/ChangeLog index 5560f00bc..8ccf678de 100644 --- a/apps/powermanager/ChangeLog +++ b/apps/powermanager/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Allow forcing monotonic battery voltage/percentage diff --git a/apps/powermanager/README.md b/apps/powermanager/README.md index f2cfcdf3e..434ec814e 100644 --- a/apps/powermanager/README.md +++ b/apps/powermanager/README.md @@ -1,6 +1,10 @@ # Power manager -Manages settings for charging. You can set a warning threshold to be able to disconnect the charger at a given percentage. Also allows to set the battery calibration offset. +Manages settings for charging. +Features: +* Warning threshold to be able to disconnect the charger at a given percentage +* Set the battery calibration offset. +* Force monotonic battery percentage or voltage ## Internals diff --git a/apps/powermanager/boot.js b/apps/powermanager/boot.js index ff4ba8932..077e24413 100644 --- a/apps/powermanager/boot.js +++ b/apps/powermanager/boot.js @@ -26,4 +26,26 @@ Bangle.on("charging",handleCharging); handleCharging(Bangle.isCharging()); } + + if (settings.forceMonoPercentage){ + var p = (E.getBattery()+E.getBattery()+E.getBattery()+E.getBattery())/4; + var op = E.getBattery; + E.getBattery = function() { + var current = Math.round((op()+op()+op()+op())/4); + if (Bangle.isCharging() && current > p) p = current; + if (!Bangle.isCharging() && current < p) p = current; + return p; + }; + } + + if (settings.forceMonoVoltage){ + var v = (NRF.getBattery()+NRF.getBattery()+NRF.getBattery()+NRF.getBattery())/4; + var ov = NRF.getBattery; + NRF.getBattery = function() { + var current = (ov()+ov()+ov()+ov())/4; + if (Bangle.isCharging() && current > v) v = current; + if (!Bangle.isCharging() && current < v) v = current; + return v; + }; + } })(); diff --git a/apps/powermanager/default.json b/apps/powermanager/default.json index a6d8412b2..6c929dc38 100644 --- a/apps/powermanager/default.json +++ b/apps/powermanager/default.json @@ -1,4 +1,6 @@ { "warnEnabled": false, - "warn": 96 + "warn": 96, + "forceMonoVoltage": false, + "forceMonoPercentage": false } diff --git a/apps/powermanager/metadata.json b/apps/powermanager/metadata.json index 3ad31ba1e..2bb531099 100644 --- a/apps/powermanager/metadata.json +++ b/apps/powermanager/metadata.json @@ -2,7 +2,7 @@ "id": "powermanager", "name": "Power Manager", "shortName": "Power Manager", - "version": "0.01", + "version": "0.02", "description": "Allow configuration of warnings and thresholds for battery charging and display.", "icon": "app.png", "type": "bootloader", diff --git a/apps/powermanager/settings.js b/apps/powermanager/settings.js index c8aa057fa..8af873e5f 100644 --- a/apps/powermanager/settings.js +++ b/apps/powermanager/settings.js @@ -24,6 +24,20 @@ 'title': 'Power Manager' }, '< Back': back, + 'Monotonic percentage': { + value: !!settings.forceMonoPercentage, + format: v => settings.forceMonoPercentage ? "On" : "Off", + onchange: v => { + writeSettings("forceMonoPercentage", v); + } + }, + 'Monotonic voltage': { + value: !!settings.forceMonoVoltage, + format: v => settings.forceMonoVoltage ? "On" : "Off", + onchange: v => { + writeSettings("forceMonoVoltage", v); + } + }, 'Charge warning': function() { E.showMenu(submenu_chargewarn); }, diff --git a/backup.js b/backup.js new file mode 100644 index 000000000..d40121fb2 --- /dev/null +++ b/backup.js @@ -0,0 +1,114 @@ +/* Code to handle Backup/Restore functionality */ + +const BACKUP_STORAGEFILE_DIR = "storage-files"; + +function bangleDownload() { + var zip = new JSZip(); + Progress.show({title:"Scanning...",sticky:true}); + var normalFiles, storageFiles; + console.log("Listing normal files..."); + Comms.listFiles({sf:false}).then(f => { + normalFiles = f; + console.log(" - "+f.join(",")); + console.log("Listing StorageFiles..."); + return Comms.listFiles({sf:true}); + }).then(f => { + storageFiles = f; + console.log(" - "+f.join(",")); + var fileCount = normalFiles.length + storageFiles.length; + var promise = Promise.resolve(); + // Normal files + normalFiles.forEach((filename,n) => { + promise = promise.then(() => { + Progress.hide({sticky: true}); + var percent = n/fileCount; + Progress.show({title:`Download ${filename}`,sticky:true,min:percent,max:percent,percent:0}); + return Comms.readFile(filename).then(data => zip.file(filename,data)); + }); + }); + // Storage files + if (storageFiles.length) { + var zipStorageFiles = zip.folder(BACKUP_STORAGEFILE_DIR); + storageFiles.forEach((filename,n) => { + promise = promise.then(() => { + Progress.hide({sticky: true}); + var percent = (normalFiles.length+n)/fileCount; + Progress.show({title:`Download ${filename}`,sticky:true,min:percent,max:percent,percent:0}); + return Comms.readStorageFile(filename).then(data => zipStorageFiles.file(filename,data)); + }); + }); + } + console.log("Listing StorageFiles..."); + return promise; + }).then(() => { + return zip.generateAsync({type:"blob"}); + }).then(content => { + Progress.hide({ sticky: true }); + showToast('Backup complete!', 'success'); + Espruino.Core.Utils.fileSaveDialog(content, "Banglejs backup.zip"); + }).catch(err => { + Progress.hide({ sticky: true }); + showToast('Backup failed, ' + err, 'error'); + }); +} + +function bangleUpload() { + Espruino.Core.Utils.fileOpenDialog({ + id:"backup", + type:"arraybuffer", + mimeType:".zip,application/zip"}, function(data) { + if (data===undefined) return; + var promise = Promise.resolve(); + var zip = new JSZip(); + var cmds = ""; + zip.loadAsync(data).then(function(zip) { + return showPrompt("Restore from ZIP","Are you sure? This will remove all existing apps"); + }).then(()=>{ + Progress.show({title:`Reading ZIP`}); + zip.forEach(function (path, file){ + console.log("path"); + promise = promise + .then(() => file.async("string")) + .then(data => { + console.log("decoded", path); + if (path.startsWith(BACKUP_STORAGEFILE_DIR)) { + path = path.substr(BACKUP_STORAGEFILE_DIR.length+1); + cmds += AppInfo.getStorageFileUploadCommands(path, data)+"\n"; + } else if (!path.includes("/")) { + cmds += AppInfo.getFileUploadCommands(path, data)+"\n"; + } else console.log("Ignoring "+path); + }); + }); + return promise; + }) + .then(() => { + Progress.hide({sticky:true}); + Progress.show({title:`Erasing...`}); + return Comms.removeAllApps(); }) + .then(() => { + Progress.hide({sticky:true}); + Progress.show({title:`Restoring...`, sticky:true}); + return Comms.showMessage(`Restoring...`); }) + .then(() => Comms.write("\x10"+Comms.getProgressCmd()+"\n")) + .then(() => Comms.uploadCommandList(cmds, 0, cmds.length)) + .then(() => Comms.showMessage(Const.MESSAGE_RELOAD)) + .then(() => { + Progress.hide({sticky:true}); + showToast('Restore complete!', 'success'); + }) + .catch(err => { + Progress.hide({sticky:true}); + showToast('Restore failed, ' + err, 'error'); + }); + return promise; + }); +} + +window.addEventListener('load', (event) => { + document.getElementById("downloadallapps").addEventListener("click",event=>{ + bangleDownload(); + }); + document.getElementById("uploadallapps").addEventListener("click",event=>{ + bangleUpload(); + }); +}); diff --git a/core b/core index affb0b15b..05f97e6ad 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit affb0b15b41eb35a1548373831af7001bad64435 +Subproject commit 05f97e6ade4605ac7a6105def52a34280f4f0c4d diff --git a/css/main.css b/css/main.css index f4850babe..a986df22e 100644 --- a/css/main.css +++ b/css/main.css @@ -81,7 +81,7 @@ a.btn.btn-link.dropdown-toggle { min-height: 8em; } -.tile-content { position: relative; } +.tile-content { position: relative; word-break: break-all; } .link-github { position:absolute; top: 36px; diff --git a/index.html b/index.html index 6c9a21bf8..a418b48eb 100644 --- a/index.html +++ b/index.html @@ -131,6 +131,8 @@
++