mirror of https://github.com/espruino/BangleApps
Added first version of CRP Assist app
parent
76b51f5074
commit
6ca8262b51
25
apps.json
25
apps.json
|
@ -2033,5 +2033,30 @@
|
||||||
{"name":"widancs.wid.js","url":"ancs.min.js"},
|
{"name":"widancs.wid.js","url":"ancs.min.js"},
|
||||||
{"name":"widancs.settings.js","url":"settings.js"}
|
{"name":"widancs.settings.js","url":"settings.js"}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cprassist",
|
||||||
|
"name":"CPR Assist",
|
||||||
|
"icon":"cprassist-icon.png",
|
||||||
|
"version": "0.01",
|
||||||
|
"readme": "README.md",
|
||||||
|
"description": "Provides assistance while performing a CPR",
|
||||||
|
"tags": "tool,firstaid",
|
||||||
|
"allow_emulator": true,
|
||||||
|
"storage": [
|
||||||
|
{
|
||||||
|
"name": "cprassist.app.js",
|
||||||
|
"url": "cprassist.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cprassist.img",
|
||||||
|
"url": "cprassist-icon.js",
|
||||||
|
"evaluate": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cprassist.settings.js",
|
||||||
|
"url": "settings.js"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: New App!
|
|
@ -0,0 +1,24 @@
|
||||||
|
# CPR Assist
|
||||||
|
|
||||||
|
Provides assistance while performing a CPR
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The app alternates between the phases for
|
||||||
|
chest compression and rescue breaths in an in an endless loop.
|
||||||
|
In the chest compression phase the the watch will provide a
|
||||||
|
buzz at a rate of 100 rpm for 30 repetitions.
|
||||||
|
A longer buzz introduces an interval of 4 seconds to perform
|
||||||
|
2 rescue breaths.
|
||||||
|
A ratio of chest compressions to rescue breaths is also
|
||||||
|
displayed in the bottom of the screen.
|
||||||
|
|
||||||
|
The number of repetitions for chest compression and
|
||||||
|
rescue breaths, the rpm rate and the duration of the
|
||||||
|
rescue breath phase can be adjusted in the settings.
|
||||||
|
See e.g. [CPR on Wikipedia](https://en.wikipedia.org/wiki/Cardiopulmonary_resuscitation)
|
||||||
|
for futher information and updates on the recommendations.
|
||||||
|
|
||||||
|
## Attributions
|
||||||
|
|
||||||
|
Icon source: https://commons.wikimedia.org/wiki/File:ISO_7010_E003_-_First_aid_sign.svg
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwwhC/AH4Arg93AB1wC/dxkQACi4XRuf/AAU3C/4X/C+sTmYABn4XD+YICmIXJl4TDAA/yC/4X/C+LXXAAdzC4c3BQgX/C/4X0uMiAAUXC6IAKC+wA/AH4AkA=="))
|
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
|
@ -0,0 +1,79 @@
|
||||||
|
const SETTINGS_FILE = 'cprassist.settings.json';
|
||||||
|
const SHORT_BUZZ_PERIOD = 80;
|
||||||
|
const LONG_BUZZ_PERIOD = 800;
|
||||||
|
|
||||||
|
Bangle.setLCDTimeout(undefined); // do not deaktivate display while running this app
|
||||||
|
|
||||||
|
let settings;
|
||||||
|
|
||||||
|
function setting(key) {
|
||||||
|
const DEFAULTS = {
|
||||||
|
'compression_count': 30,
|
||||||
|
'breath_count': 2,
|
||||||
|
'compression_rpm': 100,
|
||||||
|
'breath_period_sec': 4
|
||||||
|
};
|
||||||
|
if (!settings) {
|
||||||
|
const storage = require("Storage");
|
||||||
|
settings = storage.readJSON(SETTINGS_FILE, 1) || {};
|
||||||
|
}
|
||||||
|
return (key in settings)
|
||||||
|
? settings[key]
|
||||||
|
: DEFAULTS[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
let counter = setting('compression_count');
|
||||||
|
|
||||||
|
function provideFeedback() {
|
||||||
|
let period = counter > 0
|
||||||
|
? SHORT_BUZZ_PERIOD
|
||||||
|
: LONG_BUZZ_PERIOD;
|
||||||
|
try {
|
||||||
|
Bangle.buzz(period, 1.0);
|
||||||
|
} catch(err) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawHeart() {
|
||||||
|
g.fillCircle(40, 92, 12);
|
||||||
|
g.fillCircle(60, 92, 12);
|
||||||
|
g.fillPoly([29, 98, 50, 120, 71, 98]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateScreen() {
|
||||||
|
const colors = [0xFFFF, 0x9492];
|
||||||
|
g.reset().clearRect(0, 50, 250, 150);
|
||||||
|
if (counter > 0) {
|
||||||
|
g.setFont("Vector", 40).setFontAlign(0, 0);
|
||||||
|
g.setColor(colors[counter%2]);
|
||||||
|
drawHeart();
|
||||||
|
g.drawString(counter + "", g.getWidth()/2, 100);
|
||||||
|
} else {
|
||||||
|
g.setFont("Vector", 20).setFontAlign(0, 0);
|
||||||
|
g.drawString("RESCUE", g.getWidth()/2, 70);
|
||||||
|
g.drawString("BREATHS", g.getWidth()/2, 120);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tick() {
|
||||||
|
provideFeedback();
|
||||||
|
updateScreen();
|
||||||
|
if (counter == 0) {
|
||||||
|
var reset = function() {
|
||||||
|
counter = setting('compression_count');
|
||||||
|
clearInterval(interval);
|
||||||
|
interval = setInterval(tick, 60000/setting('compression_rpm'));
|
||||||
|
};
|
||||||
|
clearInterval(interval);
|
||||||
|
interval = setInterval(reset, setting('breath_period_sec')*1000);
|
||||||
|
}
|
||||||
|
counter -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
interval = setInterval(tick, 60000/setting('compression_rpm'));
|
||||||
|
|
||||||
|
g.clear(1).setFont("6x8");
|
||||||
|
g.drawString(setting('compression_count') + ' / ' + setting('breath_count'), 30, 200);
|
||||||
|
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
Bangle.drawWidgets();
|
|
@ -0,0 +1,64 @@
|
||||||
|
// This file should contain exactly one function, which shows the app's settings
|
||||||
|
/**
|
||||||
|
* @param {function} back Use back() to return to settings menu
|
||||||
|
*/
|
||||||
|
(function(back) {
|
||||||
|
const SETTINGS_FILE = 'cprassist.settings.json';
|
||||||
|
|
||||||
|
// initialize with default settings...
|
||||||
|
let s = {
|
||||||
|
'compression_count': 30,
|
||||||
|
'breath_count': 2,
|
||||||
|
'compression_rpm': 100,
|
||||||
|
'breath_period_sec': 4
|
||||||
|
};
|
||||||
|
// ...and overwrite them with any saved values
|
||||||
|
// This way saved values are preserved if a new version adds more settings
|
||||||
|
const storage = require('Storage');
|
||||||
|
const saved = storage.readJSON(SETTINGS_FILE, 1) || {};
|
||||||
|
for (const key in saved) {
|
||||||
|
s[key] = saved[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a function to safe a specific setting
|
||||||
|
function save(key) {
|
||||||
|
return function(value) {
|
||||||
|
s[key] = value;
|
||||||
|
storage.write(SETTINGS_FILE, s);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const menu = {
|
||||||
|
'': { 'title': 'CPR Assist' },
|
||||||
|
'< Back': back,
|
||||||
|
'chest compr.': {
|
||||||
|
value: s.compression_count,
|
||||||
|
min: 1,
|
||||||
|
max: 200,
|
||||||
|
step: 1,
|
||||||
|
onchange: save('compression_count'),
|
||||||
|
},
|
||||||
|
'rescue breaths': {
|
||||||
|
value: s.breath_count,
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
step: 1,
|
||||||
|
onchange: save('breath_count'),
|
||||||
|
},
|
||||||
|
'rpm': {
|
||||||
|
value: s.compression_rpm,
|
||||||
|
min: 1,
|
||||||
|
max: 200,
|
||||||
|
step: 10,
|
||||||
|
onchange: save('compression_rpm'),
|
||||||
|
},
|
||||||
|
'breaths period': {
|
||||||
|
value: s.breath_period_sec,
|
||||||
|
min: 1,
|
||||||
|
max: 60,
|
||||||
|
step: 1,
|
||||||
|
onchange: save('breath_period_sec'),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
E.showMenu(menu);
|
||||||
|
});
|
Loading…
Reference in New Issue