mirror of https://github.com/espruino/BangleApps
200 lines
6.5 KiB
JavaScript
200 lines
6.5 KiB
JavaScript
exports = {
|
|
// define en-/disable function, restarts the service to make changes take effect
|
|
setEnabled: function(enable, logfile, powersaving) {
|
|
// check if sleeplog is available
|
|
if (typeof global.sleeplog !== "object") return;
|
|
|
|
// set default logfile
|
|
if ((typeof logfile !== "string" || !logfile.endsWith(".log")) &&
|
|
logfile !== false) logfile = "sleeplog.log";
|
|
|
|
// stop if enabled
|
|
if (global.sleeplog.enabled) global.sleeplog.stop();
|
|
|
|
// define storage and filename
|
|
var storage = require("Storage");
|
|
var filename = "sleeplog.json";
|
|
|
|
// change enabled value in settings
|
|
storage.writeJSON(filename, Object.assign(storage.readJSON(filename, true) || {}, {
|
|
enabled: enable,
|
|
logfile: logfile,
|
|
powersaving: powersaving || false
|
|
}));
|
|
|
|
// force changes to take effect by executing the boot script
|
|
eval(storage.read("sleeplog.boot.js"));
|
|
|
|
// clear variables
|
|
storage = undefined;
|
|
filename = undefined;
|
|
return true;
|
|
},
|
|
|
|
// define read log function
|
|
// sorting: latest first, format:
|
|
// [[number, int, float, string], [...], ... ]
|
|
// - number // timestamp in ms
|
|
// - int // status: 0 = unknown, 1 = not worn, 2 = awake, 3 = sleeping
|
|
// - float // internal temperature
|
|
// - string // additional information
|
|
readLog: function(logfile, since, until) {
|
|
// check/set logfile
|
|
if (typeof logfile !== "string" || !logfile.endsWith(".log")) {
|
|
logfile = (global.sleeplog || {}).logfile || "sleeplog.log";
|
|
}
|
|
|
|
// check if since is in the future
|
|
if (since > Date()) return [];
|
|
|
|
// read logfile
|
|
var log = require("Storage").read(logfile);
|
|
// return empty log
|
|
if (!log) return [];
|
|
// decode data if needed
|
|
if (log[0] !== "[") log = atob(log);
|
|
// do a simple check before parsing
|
|
if (!log.startsWith("[[") || !log.endsWith("]]")) return [];
|
|
log = JSON.parse(log) || [];
|
|
|
|
// check if filtering is needed
|
|
if (since || until) {
|
|
// search for latest entry befor since
|
|
if (since) since = (log.find(element => element[0] <= since) || [0])[0];
|
|
// filter selected time period
|
|
log = log.filter(element => (element[0] >= since) && (element[0] <= (until || 1E14)));
|
|
}
|
|
|
|
// output log
|
|
return log;
|
|
},
|
|
|
|
// define write log function, append or replace log depending on input
|
|
// append input if array length >1 and element[0] >9E11
|
|
// replace log with input if at least one entry like above is inside another array
|
|
writeLog: function(logfile, input) {
|
|
// check/set logfile
|
|
if (typeof logfile !== "string" || !logfile.endsWith(".log")) {
|
|
if (!global.sleeplog || sleeplog.logfile === false) return;
|
|
logfile = sleeplog.logfile || "sleeplog.log";
|
|
}
|
|
|
|
// check if input is an array
|
|
if (typeof input !== "object" || typeof input.length !== "number") return;
|
|
|
|
// check for entry plausibility
|
|
if (input.length > 1 && input[0] * 1 > 9E11) {
|
|
// read log
|
|
var log = this.readLog(logfile);
|
|
|
|
// remove last state if it was unknown and less then 5min ago
|
|
if (log.length > 0 && log[0][1] === 0 &&
|
|
Math.floor(Date.now()) - log[0][0] < 3E5) log.shift();
|
|
|
|
// add entry at the first position if it has changed
|
|
if (log.length === 0 || input.some((e, index) => index > 0 && input[index] !== log[0][index])) log.unshift(input);
|
|
|
|
// map log as input
|
|
input = log;
|
|
}
|
|
|
|
// check and if neccessary reduce logsize to prevent low mem
|
|
if (input.length > 750) input = input.slice(-750);
|
|
|
|
// simple check for log plausibility
|
|
if (input[0].length > 1 && input[0][0] * 1 > 9E11) {
|
|
// write log to storage
|
|
require("Storage").write(logfile, btoa(JSON.stringify(input)));
|
|
return true;
|
|
}
|
|
},
|
|
|
|
// define log to humanreadable string function
|
|
// sorting: latest last, format:
|
|
// "{substring of ISO date} - {status} for {duration}min\n..."
|
|
getReadableLog: function(printLog, since, until, logfile) {
|
|
// read log and check
|
|
var log = this.readLog(logfile, since, until);
|
|
if (!log.length) return;
|
|
// reverse array to set last timestamp to the end
|
|
log.reverse();
|
|
|
|
// define status description and log string
|
|
var statusText = ["unknown ", "not worn", "awake ", "sleeping"];
|
|
var logString = [];
|
|
|
|
// rewrite each entry
|
|
log.forEach((element, index) => {
|
|
logString[index] = "" +
|
|
Date(element[0] - Date().getTimezoneOffset() * 6E4).toISOString().substr(0, 19).replace("T", " ") + " - " +
|
|
statusText[element[1]] +
|
|
(index === log.length - 1 ?
|
|
element.length < 3 ? "" : " ".repeat(12) :
|
|
" for " + ("" + Math.round((log[index + 1][0] - element[0]) / 60000)).padStart(4) + "min"
|
|
) +
|
|
(element[2] ? " | Temp: " + ("" + element[2]).padEnd(5) + "°C" : "") +
|
|
(element[3] ? " | " + element[3] : "");
|
|
});
|
|
logString = logString.join("\n");
|
|
|
|
// if set print and return string
|
|
if (printLog) {
|
|
print(logString);
|
|
print("- first", Date(log[0][0]));
|
|
print("- last", Date(log[log.length - 1][0]));
|
|
var period = log[log.length - 1][0] - log[0][0];
|
|
print("- period= " + Math.floor(period / 864E5) + "d " + Math.floor(period % 864E5 / 36E5) + "h " + Math.floor(period % 36E5 / 6E4) + "min");
|
|
}
|
|
return logString;
|
|
},
|
|
|
|
// define function to eliminate some errors inside the log
|
|
restoreLog: function(logfile) {
|
|
// read log and check
|
|
var log = this.readLog(logfile);
|
|
if (!log.length) return;
|
|
|
|
// define output variable to show number of changes
|
|
var output = log.length;
|
|
|
|
// remove non decremental entries
|
|
log = log.filter((element, index) => log[index][0] >= (log[index + 1] || [0])[0]);
|
|
|
|
// write log
|
|
this.writeLog(logfile, log);
|
|
|
|
// return difference in length
|
|
return output - log.length;
|
|
},
|
|
|
|
// define function to reinterpret worn status based on given temperature threshold
|
|
reinterpretTemp: function(logfile, tempthresh) {
|
|
// read log and check
|
|
var log = this.readLog(logfile);
|
|
if (!log.length) return;
|
|
|
|
// set default tempthresh
|
|
tempthresh = tempthresh || (global.sleeplog ? sleeplog.tempthresh : 27);
|
|
|
|
// define output variable to show number of changes
|
|
var output = 0;
|
|
|
|
// remove non decremental entries
|
|
log = log.map(element => {
|
|
if (element[2]) {
|
|
var tmp = element[1];
|
|
element[1] = element[2] > tempthresh ? 3 : 1;
|
|
if (tmp !== element[1]) output++;
|
|
}
|
|
return element;
|
|
});
|
|
|
|
// write log
|
|
this.writeLog(logfile, log);
|
|
|
|
// return output
|
|
return output;
|
|
}
|
|
|
|
};
|