added new app

master
Niko Komin 2023-08-29 11:32:03 -07:00
parent b75c2751c9
commit 6c4d3f41a5
11 changed files with 250 additions and 0 deletions

View File

@ -0,0 +1 @@
1.0: first working version of App

20
apps/nightwatch/README.md Normal file
View File

@ -0,0 +1,20 @@
# The Nightwatch
Snuggle into your sleeping bag, hang the Bangle on the tent wall
and check the screen before you fall asleep:
![](screenshot.png)
![](screenshot2.png)
Reads temperature and pressure sensor. Shows current, maximal and minimal values
since the start of the app. Also show a graph of the last 20 measures.
Swipe left/right between values.
Screen is updated periodically, time step is configurable in settings.
# Creator
[Niko Komin](https://www.laikaundfreunde.de/niko-komin/)

View File

@ -0,0 +1,16 @@
{
"id":"nightwatch",
"readme":"README.md",
"name":"The Nightwatch",
"shortName":"Nightwatch",
"supports" : ["BANGLEJS2"],
"icon":"nightwatch.icon.png",
"screenshots" : [ { "url":"screenshot.png","url":"screenshot2.png" } ],
"version":"1.0",
"description":"Logs sensor readings (currently T and p), show min/max and graph.",
"tags": "tools,outdoors",
"storage": [
{"name":"nightwatch.app.js","url":"nightwatch.app.js"},
{"name":"nightwatch.img","url":"nightwatch.icon.js","evaluate":true}
]
}

View File

@ -0,0 +1,6 @@
require("Storage").write("nightwatch.info",{
"id":"nightwatch",
"name":"nightwatch",
"src":"nightwatch.app.js",
"icon":"nightwatch.icon.png"
});

View File

@ -0,0 +1,175 @@
// PTLOGGER
// MEASURES p AND T PERIODICALLY AND UPDATES MIN & MAX VALS
// DISPLAYS EITHER OF BOTH
var settings = Object.assign({
dt: 5, //time interval in minutes
}, require('Storage').readJSON("nightwatch.json", true) || {});
let dt = settings.dt;
delete settings;
var timerID;
const highColor = '#35b779';//#6dcd59;
const lowColor = '#eb005c';//#3d4a89;//#482878;
const normColor = '#000000';
const historyAmnt = 24;
const TData = {
ondisplay:true,
unit: '\xB0C',
accuracy: 1,
value : 100, t_value:'0:00',
values : new Array(historyAmnt),
maxval : -100, t_max:'0:00',
minval : 100, t_min:'0:00'
};
const PData = {
ondisplay:false,
unit: 'mbar',
accuracy: 0,
value : 0, t_value:'0:00',
values : new Array(historyAmnt),
maxval : 0, t_max:'0:00',
minval : 10000, t_min:'0:00'
};
function minMaxString(val,accuracy,unit,time){
return time+' '+val.toFixed(accuracy)+unit;
// return val.toFixed(accuracy)+unit+'('+time+')';
}
function updateScreen() {
// what are we showing right now?
let data;
if (TData.ondisplay){data = TData;}
else {data = PData;}
// make strings
let valueString = data.value.toFixed(data.accuracy)+data.unit;
let minString = minMaxString(data.minval, data.accuracy, data.unit, data.t_min);
let maxString = minMaxString(data.maxval, data.accuracy, data.unit, data.t_max);
// LETS PAINT
g.clear();
g.setFontAlign(0, 0);
// MINUM AND MAXIMUM VALUES AND TIMES
g.setFont("Vector:18");
g.setColor(normColor);
g.drawString(maxString, g.getWidth() / 2, 11);
g.drawString(minString, g.getWidth() / 2, g.getHeight() - 11);
g.setColor(normColor);
// TIME OF LAST MEASURE AND SIZE OF INTERVAL
g.setFontAlign(-1, 0);
g.drawString(data.t_value, 0, g.getHeight()/2 - 25);
g.setFontAlign(1, 0);
g.drawString('dt='+dt+'min', g.getWidth() , g.getHeight()/2 - 25);
////////////////////////////////////////////////////////////
// GRAPH OF MEASUREMENT HISTORY
g.setFont("Vector:16");
const graphHeight=35;
const graphWidth=g.getWidth()-30;
const graphLocX = 15;
const graphLocY = g.getHeight() - 16 - 18 - graphHeight;
// DRAW SOME KIND OF AXES
g.setColor(0.4,0.4,0.4);
g.drawRect(graphLocX,graphLocY,graphLocX+graphWidth,graphLocY+graphHeight);
g.drawLine(graphLocX,graphLocY+graphHeight/2,graphLocX+graphWidth,graphLocY+graphHeight/2);
g.drawLine(graphLocX+graphWidth/2,graphLocY,graphLocX+graphWidth/2,graphLocY+graphHeight);
g.drawLine(graphLocX+graphWidth/4,graphLocY,graphLocX+graphWidth/4,graphLocY+graphHeight);
g.drawLine(graphLocX+3*graphWidth/4,graphLocY,graphLocX+3*graphWidth/4,graphLocY+graphHeight);
g.setColor(normColor);
// DRAW LINE
require("graph").drawLine(g, data.values, {
x:graphLocX,
y:graphLocY,
width:graphWidth,
height:graphHeight
});
let graphMax=Math.max.apply(Math,data.values);
let graphMin=Math.min.apply(Math,data.values);
g.setFontAlign(0, 0);
g.setColor(highColor);
g.drawString(graphMax.toFixed(data.accuracy), g.getWidth()/2, g.getHeight() - 16 - 18 - graphHeight);
g.setColor(lowColor);
g.drawString(graphMin.toFixed(data.accuracy), g.getWidth()/2, g.getHeight() - 16 - 18);
g.setColor(normColor);
let historyLength = (historyAmnt*dt >= 60)?('-'+historyAmnt*dt/60+'h'):('-'+historyAmnt*dt+'"');
g.drawString(historyLength,25, g.getHeight() - 16 - 18 - graphHeight/2);
////////////////////////////////////////////////////////////
// LAST MEASURE
g.setFontAlign(0, 0);
g.setFont('Vector:36');
g.drawString(valueString, g.getWidth() / 2, g.getHeight() / 2);
data.ondisplay = true;
}
function updateMinMax( data, currentValue ){
data.values.push(currentValue);
data.values.shift();
data.value=currentValue;
let now = new Date();
data.t_value = now.getHours()+':'+String(now.getMinutes()).padStart(2, '0');
if (currentValue < data.minval){data.t_min=data.t_value;data.minval = currentValue;}
if (currentValue > data.maxval){data.t_max=data.t_value;data.maxval = currentValue;}
}
function switchDisplay(){
if (TData.ondisplay) {TData.ondisplay=false;PData.ondisplay=true;updateScreen();}
else {PData.ondisplay=false;TData.ondisplay=true;updateScreen();}
}
function settingsPage(){
Bangle.on('swipe',function (){});
eval(require("Storage").read("nightwatch.settings.js"))(()=>load());
Bangle.on('swipe',switchDisplay);
console.log(3);
}
function handlePressureSensorReading(data) {
updateMinMax(TData,data.temperature);
updateMinMax(PData,data.pressure);
}
function startup(){
// testing in emulator
// handlePressureSensorReading({ "temperature": 28.64251302083, "pressure": 1004.66520303803, "altitude": 71.72072902749 });
// updateScreen();
// ON STARTUP:
// fill current reading into data,
// before `updateMinMax` uses it
Bangle.getPressure().then(d=>{TData.value=d.temperature;
TData.values.fill(d.temperature);
PData.value=d.pressure;
PData.values.fill(d.pressure);
handlePressureSensorReading(d);
updateScreen();});
Bangle.on('swipe',switchDisplay);
//Bangle.on('tap',settingsPage);
timerID = setInterval( function() {
Bangle.getPressure().then(d=>{handlePressureSensorReading(d);updateScreen();});
}, dt * 60000);
}
startup();

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEw4MA///ospETUQAgc//gFDv4FF/wFP/4FF/5PCgIFChF/AoWA/1/+YFBx/+g4EBAAPAFAIEBEgUDBQYAN/E/AgQvDDoXHDocH4wFDgf8v4RCDooAMj/4AoZcBcM8DOAgFFgJSDAqQAhA=="))

Binary file not shown.

After

Width:  |  Height:  |  Size: 959 B

View File

@ -0,0 +1,6 @@
require("Storage").write("nightwatch.info",{
"id":"nightwatch",
"name":"The Nightwatch",
"src":"nightwatch.app.js",
"icon":"nightwatch.icon.png"
});

View File

@ -0,0 +1,25 @@
(function(back) {
var FILE = "nightwatch.json";
// Load settings
var settings = Object.assign({
dt: 30,
}, require('Storage').readJSON(FILE, true) || {});
function writeSettings() {
require('Storage').writeJSON(FILE, settings);
}
// Show the menu
E.showMenu({
"" : { "title" : "nightwatch" },
"< Back" : () => back(),
'log freq (min)': {
value: 0|settings.dt, // 0| converts undefined to 0
min: 1, max: 60,
onchange: v => {
settings.dt = v;
writeSettings();
}
},
});
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB