1
0
Fork 0

Merge branch 'master' of git@github.com:nujw/BangleApps.git

master
nujw 2021-02-21 10:33:15 +13:00
commit 109850bc89
95 changed files with 21087 additions and 528 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ package-lock.json
appdates.csv
.vscode
.idea/
_config.yml

View File

@ -1 +0,0 @@
theme: jekyll-theme-leap-day

130
apps.json
View File

@ -53,7 +53,7 @@
{ "id": "about",
"name": "About",
"icon": "app.png",
"version":"0.06",
"version":"0.07",
"description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers",
"tags": "tool,system",
"allow_emulator":true,
@ -80,7 +80,7 @@
"name": "Notifications (default)",
"shortName":"Notifications",
"icon": "notify.png",
"version":"0.05",
"version":"0.06",
"description": "A handler for displaying notifications that displays them in a bar at the top of the screen",
"tags": "widget",
"type": "notify",
@ -93,7 +93,7 @@
"name": "Fullscreen Notifications",
"shortName":"Notifications",
"icon": "notify.png",
"version":"0.06",
"version":"0.07",
"description": "A handler for displaying notifications that displays them fullscreen. This may not fully restore the screen after on some apps. See `Notifications (default)` for more information about the notifications library.",
"tags": "widget",
"type": "notify",
@ -139,7 +139,7 @@
{ "id": "gbridge",
"name": "Gadgetbridge",
"icon": "app.png",
"version":"0.18",
"version":"0.20",
"description": "The default notification handler for Gadgetbridge notifications from Android",
"tags": "tool,system,android,widget",
"readme": "README.md",
@ -363,7 +363,7 @@
{ "id": "gpsrec",
"name": "GPS Recorder",
"icon": "app.png",
"version":"0.16",
"version":"0.17",
"interface": "interface.html",
"description": "Application that allows you to record a GPS track. Can run in background",
"tags": "tool,outdoors,gps,widget",
@ -1153,7 +1153,7 @@
"name": "Commandline-Clock",
"shortName":"CLI-Clock",
"icon": "app.png",
"version":"0.09",
"version":"0.11",
"description": "Simple CLI-Styled Clock",
"tags": "clock,cli,command,bash,shell",
"type":"clock",
@ -1341,7 +1341,7 @@
"name": "Active Pedometer",
"shortName":"Active Pedometer",
"icon": "app.png",
"version":"0.06",
"version":"0.09",
"description": "Pedometer that filters out arm movement and displays a step goal progress. Steps are saved to a daily file and can be viewed as graph.",
"tags": "outdoors,widget",
"readme": "README.md",
@ -1553,7 +1553,7 @@
"name": "BangleRun",
"shortName": "BangleRun",
"icon": "banglerun.png",
"version": "0.07",
"version": "0.09",
"interface": "interface.html",
"description": "An app for running sessions. Displays info and logs your run for later viewing.",
"tags": "run,running,fitness,outdoors",
@ -1638,7 +1638,7 @@
"name": "Round clock with seconds, minutes and date",
"shortName":"Round Clock",
"icon": "app.png",
"version":"0.03",
"version":"0.04",
"description": "Designed round clock with ticks for minutes and seconds and heart rate indication",
"tags": "clock",
"type": "clock",
@ -2139,7 +2139,7 @@
{ "id": "multiclock",
"name": "Multi Clock",
"icon": "multiclock.png",
"version":"0.11",
"version":"0.12",
"description": "Clock with multiple faces - Big, Analogue, Digital, Text, Time-Date.\n Switch between faces with BTN1 & BTN3",
"readme": "README.md",
"tags": "clock",
@ -2153,8 +2153,6 @@
{"name":"txt.face.js","url":"txt.js"},
{"name":"timdat.face.js","url":"timdat.js"},
{"name":"ped.face.js","url":"ped.js"},
{"name":"gps.face.js","url":"gps.js"},
{"name":"osref.face.js","url":"osref.js"},
{"name":"multiclock.img","url":"multiclock-icon.js","evaluate":true}
]
},
@ -2189,6 +2187,23 @@
{"wildcard":"accelrec.?.csv" }
]
},
{ "id": "accellog",
"name": "Acceleration Logger",
"shortName":"Accel Log",
"icon": "app.png",
"version":"0.01",
"interface": "interface.html",
"description": "Logs XYZ acceleration data to a CSV file that can be downloaded to your PC",
"tags": "outdoor",
"readme": "README.md",
"storage": [
{"name":"accellog.app.js","url":"app.js"},
{"name":"accellog.img","url":"app-icon.js","evaluate":true}
],
"data": [
{"wildcard":"accellog.?.csv" }
]
},
{
"id": "cprassist",
"name":"CPR Assist",
@ -2298,7 +2313,7 @@
"name": "File manager",
"shortName":"FileManager",
"icon": "icons8-filing-cabinet-48.png",
"version":"0.02",
"version":"0.03",
"description": "Simple file manager, allows user to examine watch storage and display, load or delete individual files",
"tags": "tools",
"readme": "README.md",
@ -2655,7 +2670,7 @@
"name": "Low power GPS Service",
"shortName":"GPS Service",
"icon": "gpsservice.png",
"version":"0.03",
"version":"0.04",
"description": "low power GPS widget",
"tags": "gps outdoors navigation",
"readme": "README.md",
@ -2692,5 +2707,92 @@
{"name":"intervals.app.js","url":"intervals.app.js"},
{"name":"intervals.img","url":"intervals-icon.js","evaluate":true}
]
},
{ "id": "planetarium",
"name": "Planetarium",
"shortName":"Planetarium",
"icon": "planetarium.png",
"readme": "README.md",
"version":"0.03",
"description": "Planetarium showing up to 500 stars using the watch location and time",
"tags": "",
"storage": [
{"name":"planetarium.app.js","url":"planetarium.app.js"},
{"name":"planetarium.data.csv","url":"planetarium.data.csv"},
{"name":"planetarium.const.csv","url":"planetarium.const.csv"},
{"name":"planetarium.extra.csv","url":"planetarium.extra.csv"},
{"name":"planetarium.settings.js","url":"settings.js"},
{"name":"planetarium.img","url":"planetarium-icon.js","evaluate":true}
],
"data":[
{"name":"planetarium.json"}
]
},
{ "id": "tapelauncher",
"name": "Tape Launcher",
"icon": "icon.png",
"version":"0.02",
"description": "An App launcher, icons displayed in a horizontal tape, swipe or use buttons",
"readme": "README.md",
"tags": "tool,system,launcher",
"type":"launch",
"storage": [
{"name":"tapelauncher.app.js","url":"app.js"},
{"name":"tapelauncher.img","url":"icon.js","evaluate":true}
]
},
{ "id": "oblique",
"name": "Oblique Strategies",
"icon": "eno.png",
"version": "0.01",
"description": "Oblique Strategies for creativity. Copied from Brian Eno.",
"tags": "tool",
"storage": [
{"name":"oblique.app.js","url":"app.js"},
{"name":"oblique.img","url":"app-icon.js","evaluate":true}
]
},
{ "id": "testuserinput",
"name": "Test User Input",
"shortName":"Test User Input",
"icon": "app.png",
"readme": "README.md",
"version":"0.02",
"description": "Basic app to test the bangle.js input interface. It displays the result in text or a switch on/off image.",
"tags": "input,interface,buttons,touch",
"storage": [
{"name":"testuserinput.app.js","url":"app.js"},
{"name":"testuserinput.img","url":"app-icon.js","evaluate":true}
]
},
{ "id": "gpssetup",
"name": "GPS Setup",
"shortName":"GPS Setup",
"icon": "gpssetup.png",
"version":"0.02",
"description": "Configure the GPS power options and store them in the GPS nvram",
"tags": "gps, tools, outdoors",
"readme": "README.md",
"storage": [
{"name":"gpssetup","url":"gpssetup.js"},
{"name":"gpssetup.settings.js","url":"settings.js"},
{"name":"gpssetup.settings.json","url":"settings.json"},
{"name":"gpssetup.app.js","url":"app.js"},
{"name":"gpssetup.img","url":"icon.js","evaluate":true}
]
},
{ "id": "walkersclock",
"name": "Walkers Clock",
"shortName":"Walkers Clock",
"icon": "walkersclock48.png",
"version":"0.01",
"description": "A larg font watch, displays steps, can switch GPS on/off, displays grid reference",
"type":"clock",
"tags": "clock, gps, tools, outdoors",
"readme": "README.md",
"storage": [
{"name":"walkersclock.app.js","url":"app.js"},
{"name":"walkersclock.img","url":"icon.js","evaluate":true}
]
}
]

View File

@ -155,6 +155,7 @@
// TODO: "no-undef": "warn",
"no-undef": "off",
"no-unused-vars": "off",
"no-useless-escape": "off"
"no-useless-escape": "off",
"no-control-regex" : "off"
}
}

View File

@ -4,3 +4,4 @@
0.04: Actual pixels as of 9 Mar 2020
0.05: Actual pixels as of 27 Apr 2020
0.06: Actual pixels as of 12 Jun 2020
0.07: Pressing a button now exits immediately (fix #618)

File diff suppressed because one or more lines are too long

1
apps/accellog/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: New App!

19
apps/accellog/README.md Normal file
View File

@ -0,0 +1,19 @@
# Acceleration Logger
Logs XYZ acceleration data (at the normal 12.5Hz) to a CSV file that can be downloaded to your PC.
## Usage
* Run the app 'Accel Log' from Bangle.js menu
* Optionally choose a file number if you want to record to multiple different files.
* Choose `Start`
* Acceleration data will now be recording
* When you're done, press `BTN2`
## Downloading Data
* Go to the Bangle.js App Loader
* Connect to your Bangle
* Under `My Apps` look for `Acceleration Logger`
* You'll see a download arrow next to it - click that
* You can now choose to Save or Delete each track you have recorded

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("oFAwhC/AH4A2xAedhGIwA+dAAI+dAAJAcEAJ/fD/4f5hAJIYSo6JIihaKxBATxAACC4YnBAAQ+TD7o/CFRJfTP5a/eb6pEOD/7JFwczAA0ybgwfUkUjD4QaDD6syiMSD4ZABCIa8JD547BCIY/ZHQQ+LD6Z/cHZYf/f6E4D6uCD4gACD6wgBkQACBAYfWABYf/D/4fPwf/ABgf/D6czABBf/P/5f/P/5f/D+WIABwfuAH4A/ADo="))

132
apps/accellog/app.js Normal file
View File

@ -0,0 +1,132 @@
var fileNumber = 0;
var MAXLOGS = 9;
function getFileName(n) {
return "accellog."+n+".csv";
}
function showMenu() {
var menu = {
"" : { title : "Accel Logger" },
"File No" : {
value : fileNumber,
min : 0,
max : MAXLOGS,
onchange : v => { fileNumber=v; }
},
"Start" : function() {
E.showMenu();
startRecord();
},
"View Logs" : function() {
viewLogs();
},
"Exit" : function() {
load();
},
};
E.showMenu(menu);
}
function viewLog(n) {
E.showMessage("Loading...");
var f = require("Storage").open(getFileName(n), "r");
var records = 0, l = "", ll="";
while ((l=f.readLine())!==undefined) {records++;ll=l;}
var length = 0;
if (ll) length = (ll.split(",")[0]|0)/1000;
var menu = {
"" : { title : "Log "+n }
};
menu[records+" Records"] = "";
menu[length+" Seconds"] = "";
menu["DELETE"] = function() {
E.showPrompt("Delete Log "+n).then(ok=>{
if (ok) {
E.showMessage("Erasing...");
f.erase();
viewLogs();
} else viewLog(n);
});
};
menu["< Back"] = function() {
viewLogs();
};
E.showMenu(menu);
}
function viewLogs() {
var menu = {
"" : { title : "Logs" }
};
var hadLogs = false;
for (var i=0;i<=MAXLOGS;i++) {
var f = require("Storage").open(getFileName(i), "r");
if (f.readLine()!==undefined) {
(function(i) {
menu["Log "+i] = () => viewLog(i);
})(i);
hadLogs = true;
}
}
if (!hadLogs)
menu["No Logs Found"] = function(){};
menu["< Back"] = function() { showMenu(); };
E.showMenu(menu);
}
function startRecord(force) {
if (!force) {
// check for existing file
var f = require("Storage").open(getFileName(fileNumber), "r");
if (f.readLine()!==undefined)
return E.showPrompt("Overwrite Log "+fileNumber+"?").then(ok=>{
if (ok) startRecord(true); else showMenu();
});
}
// display
g.clear(1);
Bangle.drawWidgets();
var w = g.getWidth();
var h = g.getHeight();
g.setColor("#ff0000").fillRect(0,h-48,w,h);
g.setColor("#ffffff").setFont("6x8",2).setFontAlign(0,0).drawString("RECORDING", w/2,h-24);
g.setFont("6x8").drawString("Samples:",w/2,h/3 - 20);
g.setFont("6x8").drawString("Time:",w/2,h*2/3 - 20);
g.setFont("6x8",2).setFontAlign(0,0,1).drawString("STOP",w-10,h/2);
// now start writing
f = require("Storage").open(getFileName(fileNumber), "w");
f.write("Time (ms),X,Y,Z\n");
var start = getTime();
var sampleCount = 0;
function accelHandler(accel) {
var t = getTime()-start;
f.write([
t*1000,
accel.x*8192,
accel.y*8192,
accel.z*8192].map(n=>Math.round(n)).join(",")+"\n");
sampleCount++;
g.reset().setFont("6x8",2).setFontAlign(0,0);
g.drawString(" "+sampleCount+" ",w/2,h/3,true);
g.drawString(" "+Math.round(t)+"s ",w/2,h*2/3,true);
}
Bangle.setPollInterval(80); // 12.5 Hz
Bangle.on('accel', accelHandler);
setWatch(()=>{
Bangle.removeListener('accel', accelHandler);
showMenu();
}, BTN2);
}
Bangle.loadWidgets();
Bangle.drawWidgets();
showMenu();

BIN
apps/accellog/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,107 @@
<html>
<head>
<link rel="stylesheet" href="../../css/spectre.min.css">
</head>
<body>
<div id="data"></div>
<script src="../../core/lib/interface.js"></script>
<script>
var dataElement = document.getElementById("data");
function getData() {
// show loading window
Util.showModal("Loading...");
// get the data
dataElement.innerHTML = "";
var promise = Promise.resolve();
Puck.eval('require("Storage").list(/accellog\\..\\.csv\\x01/)',files=>{
if (files.length==0) {
dataElement.innerHTML = "<p>No saved data</p>";
} else {
files.forEach(fn => {
fn = fn.slice(0,-1);
dataElement.innerHTML += `
<div class="card">
<div class="card-header">
<div class="card-title h5">${fn}</div>
</div>
<div class="card-footer">
<button class="btn btn-primary" fn="${fn}" act="save">Save</button>
<button class="btn" fn="${fn}" act="delete">Delete</button>
</div>
</div>`;
promise = promise.then(function() {
document.querySelector(`.btn[fn='${fn}'][act='save']`).addEventListener("click", function() {
Util.readStorageFile(fn, function(data) {
Util.saveCSV(fn.slice(0,-4), data);
});
});
document.querySelector(`.btn[fn='${fn}'][act='delete']`).addEventListener("click", function() {
Util.showModal("Deleting...");
Util.eraseStorageFile(fn, function() {
Util.hideModal();
getData();
});
});
return new Promise(resolve=>{
Puck.eval(`require("Storage").read(${JSON.stringify(fn)})`,csv=>{
fileData[fn] = csv.trim();
var el = document.querySelector(`.card-body[fn='${fn}']`);
el.innerHTML = '<canvas width="400" height="100"></canvas>';
var c = el.firstChild;
var ctx = c.getContext("2d");
var lines = csv.split("\n");
var y = 50, sx = 400/lines.length, sy = 50/8;
function plot(n) {
var last;
ctx.beginPath();
lines.map((l,x)=>{
l = l.split(",");
var yc = y + parseFloat(l[n])*sy;
if (!last) {
ctx.moveTo(0, yc);
} else {
ctx.lineTo(x*sx, yc);
}
last = l;
});
ctx.stroke();
};
ctx.strokeStyle = 'red';
plot(0);
ctx.strokeStyle = 'green';
plot(1);
ctx.strokeStyle = 'blue';
plot(2);
resolve();
});
});
});
});
}
// remove window
Util.hideModal();
});
}
// You can call a utility function to save the data
/*document.getElementById("btnSave").addEventListener("click", function() {
Util.saveCSV("gpsdata", csvData);
});
// Or you can also delete the file
document.getElementById("btnDelete").addEventListener("click", function() {
Util.showModal("Deleting...");
Util.eraseStorageFile("gpspoilog.csv", function() {
Util.hideModal();
getData();
});
});*/
// Called when app starts
function onInit() {
getData();
}
</script>
</body>
</html>

View File

@ -1,7 +1,8 @@
# Acceleration Recorder
This app records a short period of acceleration data from the accelerometer
and
This app records a short period of acceleration data from the accelerometer at
100Hz (starting when acceleration happens) and graphs it, working out max acceleration
and max velocity. Data can also be downloaded to your PC.
## Usage

View File

@ -4,3 +4,6 @@
0.04: Steps are set to 0 in log on new day
0.05: Fix default step/distance display if it hasn't been set up first
0.06: Added WIDGETS.activepedom.getSteps()
0.07: Added settings to be able to hide line1 and line2 so there is no visible widget
0.08: Fixed zero steps issue caused by 0.07
0.09: Prettied up user interface, decluttered graphs

View File

@ -31,6 +31,7 @@ Steps are saved to a datafile every 5 minutes. You can watch a graph using the a
* Step detection sensitivity from firmware can be configured
* Steps are saved to a file and read-in at start (to not lose step progress)
* Settings can be changed in Settings - App/widget settings - Active Pedometer
* Can hide the widget display if required using settings
## Features App

View File

@ -88,28 +88,40 @@
times = undefined;
//steps
var csvFile = storage.open(filename, "r");
csvFile = storage.open(filename, "r");
steps = getArrayFromCSV(csvFile, 1);
first = first + " " + steps[0] + "/" + setting('stepGoal');
last = last + " " + steps[steps.length-1] + "/" + setting('stepGoal');
//define y-axis grid labels
stepsLastEntry = steps[steps.length-1];
if (stepsLastEntry < 1000) gridyValue = 100;
if (stepsLastEntry >= 1000 && stepsLastEntry < 10000) gridyValue = 1000;
if (stepsLastEntry > 10000) gridyValue = 5000;
// the labels on the y axis are fairly unreadable so minimise them
if (stepsLastEntry < 1000) gridyValue = 500;
if (stepsLastEntry >= 1000 && stepsLastEntry < 2000) gridyValue = 1000;
if (stepsLastEntry >= 2000 && stepsLastEntry < 5000) gridyValue = 2000;
if (stepsLastEntry >= 5000 && stepsLastEntry < 10000) gridyValue = 5000;
if (stepsLastEntry >= 10000 && stepsLastEntry < 20000) gridyValue = 10000;
if (stepsLastEntry > 20000) gridyValue = 20000;
//draw
drawMenu();
g.drawString("First: " + first, 10, 30);
g.drawString(" Last: " + last, 10, 40);
// draw the chart
g.clear();
g.setFont("6x8", 2);
g.setColor(1,1,1);
require("graph").drawLine(g, steps, {
//title: "Steps Counted",
//title: "Steps",
axes : true,
gridy : gridyValue,
y : 60, //offset on screen
x : 5, //offset on screen
});
// show steps and duration of the chart
g.setFont("6x8", 2);
g.setColor(0,1,0);
g.drawString("steps", 30, 24);
g.drawString(stepsLastEntry, 30, 44);
g.drawString((history/3600000) + " hrs", 30, 64);
//free memory from big variables
allData = undefined;
allDataFile = undefined;
@ -117,11 +129,46 @@
times = undefined;
}
function getImage() {
return require("heatshrink").decompress(atob("mEwwIGDvAEDgP+ApMD/4FVEZY1FABcP8AFDn/wAod/AocB//4AoUHAokPAokf5/8AocfAoc+j5HDvgFEvEf7+AAoP4AoJCC+E/54qCsE/wYkDn+AAos8AohZDj/AAohrEp4FEs5xEuJfDgF5Aon4GgYFBGgZOBnyJD+EeYgfgj4FEh6VD4AFDh+AAIJMCBoIFFLQQtBgYFCHIIFDjA3BC4I="));
}
function drawMenu() {
var x = 100;
var y = 24;
var stps ="-";
var y_inc = 25;
g.clear();
g.setFont("6x8", 1);
g.drawString("BTN1:Timespan | BTN2:Draw", 20, 10);
g.drawString("Timespan: " + history/1000/60/60 + " hours", 20, 20);
g.setColor(1,1,1);
g.drawImage(getImage(),0 ,60 , {scale:2} );
g.setFont("6x8",2);
// timespan
g.setColor('#7f8c8d');
g.setFontAlign(-1,0);
g.drawString("Timespan", x, y, true);
y += y_inc;
g.setColor('#bdc3c7');
g.drawString(history/1000/60/60 + " hrs" , x, y, true);
// BTN1 info
y += 2*y_inc;
g.setColor('#7f8c8d');
g.setFontAlign(-1,0);
g.drawString("BTN1", x, y, true);
y += y_inc;
g.setColor('#bdc3c7');
g.drawString("Timespan", x, y, true);
// BTN2 info
y += 2*y_inc;
g.setColor('#7f8c8d');
g.setFontAlign(-1,0);
g.drawString("BTN2", x, y, true);
y += y_inc;
g.setColor('#bdc3c7');
g.drawString("Draw", x, y, true);
}
setWatch(function() { //BTN1
@ -140,7 +187,9 @@
}, BTN1, {edge:"rising", debounce:50, repeat:true});
setWatch(function() { //BTN2
g.setFont("6x8", 2);
g.clear();
g.setColor(1,1,1);
g.setFont("6x8", 3);
g.drawString ("Drawing...",30,60);
drawGraph();
}, BTN2, {edge:"rising", debounce:50, repeat:true});
@ -161,5 +210,4 @@
}
drawMenu();
})();

View File

@ -4,7 +4,7 @@
*/
(function(back) {
const SETTINGS_FILE = 'activepedom.settings.json';
const LINES = ['Steps', 'Distance'];
const LINES = ['Steps', 'Distance', 'Hide'];
// initialize with default settings...
let s = {

View File

@ -141,6 +141,7 @@
function draw() {
var height = 23; //width is deined globally
distance = (stepsCounted * setting('stepLength')) / 100 /1000; //distance in km
//Check if same day
@ -155,6 +156,12 @@
}
lastUpdate = date;
// not everyone likes a widget, having refreshed lastUpdate we can exit
if (setting('lineOne') == 'Hide' && setting('lineTwo') == 'Hide') {
settings = 0; //reset settings to save memory
return;
}
g.reset();
g.clearRect(this.x, this.y, this.x+width, this.y+height);

View File

@ -5,3 +5,5 @@
0.05: Complete rewrite. New UI, GPS & HRM Kalman filters, activity logging
0.06: Reading HDOP directly from the GPS event (needs Espruino 2v07 or above)
0.07: Fixed GPS update, added guards against NaN values
0.08: Fix issue with GPS coordinates being wrong after the first one
0.09: Another GPS fix (log raw coordinates - not filtered ones)

View File

@ -1 +1 @@
require("heatshrink").decompress(atob("mEwwMB/4ACx4ED/0DApP8AqAXB84GDg/DAgXj/+DCAUABgIFB4EAv4FCwEAj0PAoJPBgwFEgEfDgMOAoM/AoMegFAAoP8jkA8F/AoM8gP4DgP4nBvD/F4KQfwuAFE+A/CAoPgAofx8A/CKYRwELIIFDLII6BAoZSBLIYeC/0BwAFDgfAGAQFBHgf8g4BBIIUH/wFBSYMPAoXwAog/Bj4FEv4FDDQQCBQoQFCZYYFi/6KE/+P/4A="))
require("heatshrink").decompress(atob("mEwwIHEuAEDgP8ApMDAqAXBjAGD/E8AgUcgF8CAX/BgIFBn//wAFCv//8PwAoP///5Aon/8AcB+IFB4AFB8P/34FBgfj/8fwAFB4f+g4cBg/H/w/Cg+HKQcPx4FEh4/CAoMfAocOj4/CKYRwELIIFDLII6BAoZSBLIYeCgP+v4FD/k/GAQFBHgcD/ABBIIX4gIFBSYPwAoUPAog/B8AFEwAFDDQQCBQoQFCZYYFigCKEgFwgAA=="))

View File

@ -1 +1 @@
!function(){"use strict";const t={STOP:63488,PAUSE:65504,RUN:2016};function n(t,n,r){g.setColor(0),g.fillRect(n-60,r,n+60,r+30),g.setColor(65535),g.drawString(t,n,r)}function r(r){var e;g.setFontVector(30),g.setFontAlign(0,-1,0),n((r.distance/1e3).toFixed(2),60,55),n(function(t){const n=Math.round(t),r=Math.floor(n/3600),e=Math.floor(n/60)%60,o=n%60;return(r?r+":":"")+("0"+e).substr(-2)+":"+("0"+o).substr(-2)}(r.duration),180,55),n(function(t){if(t<.1667)return"__'__\"";const n=Math.round(1e3/t),r=Math.floor(n/60),e=n%60;return("0"+r).substr(-2)+"'"+("0"+e).substr(-2)+'"'}(r.speed),60,115),n(r.hr.toFixed(0),180,115),n(r.steps.toFixed(0),60,175),n(r.cadence.toFixed(0),180,175),g.setFont("6x8",2),g.setColor(r.gpsValid?2016:63488),g.fillRect(0,216,80,240),g.setColor(0),g.drawString("GPS",40,220),g.setColor(65535),g.fillRect(80,216,160,240),g.setColor(0),g.drawString(("0"+(e=new Date).getHours()).substr(-2)+":"+("0"+e.getMinutes()).substr(-2),120,220),g.setColor(t[r.status]),g.fillRect(160,216,240,240),g.setColor(0),g.drawString(r.status,200,220)}function e(t){g.clear(),g.setColor(50712),g.setFont("6x8",2),g.setFontAlign(0,-1,0),g.drawString("DIST (KM)",60,32),g.drawString("TIME",180,32),g.drawString("PACE",60,92),g.drawString("HEART",180,92),g.drawString("STEPS",60,152),g.drawString("CADENCE",180,152),r(t),Bangle.drawWidgets()}var o;function a(t){t.status===o.Stopped&&function(t){const n=(new Date).toISOString().replace(/[-:]/g,""),r=`banglerun_${n.substr(2,6)}_${n.substr(9,6)}`;t.file=require("Storage").open(r,"w"),t.file.write(["timestamp","latitude","longitude","altitude","duration","distance","heartrate","steps"].join(",")+"\n")}(t),t.status===o.Running?t.status=o.Paused:t.status=o.Running,r(t)}!function(t){t.Stopped="STOP",t.Paused="PAUSE",t.Running="RUN"}(o||(o={}));const s={fix:NaN,lat:NaN,lon:NaN,alt:NaN,vel:NaN,dop:NaN,gpsValid:!1,x:NaN,y:NaN,z:NaN,v:NaN,t:NaN,dt:NaN,pError:NaN,vError:NaN,hr:60,hrError:100,file:null,drawing:!1,status:o.Stopped,duration:0,distance:0,speed:0,steps:0,cadence:0};var i;i=s,Bangle.on("GPS",t=>function(t,n){t.lat=n.lat,t.lon=n.lon,t.alt=n.alt,t.vel=n.speed/3.6,t.fix=n.fix,t.dop=n.hdop,t.gpsValid=t.fix>0&&t.dop<=5,function(t){const n=Date.now(),r=(n-t.t)/1e3;if(t.t=n,t.dt+=r,t.status===o.Running&&(t.duration+=r),!t.gpsValid)return;const e=6371008.8+t.alt,a=e*Math.cos(t.lat)*Math.cos(t.lon),s=e*Math.cos(t.lat)*Math.sin(t.lon),i=e*Math.sin(t.lat),d=t.vel;if(!t.x)return t.x=a,t.y=s,t.z=i,t.v=d,t.pError=2.5*t.dop,void(t.vError=.05*t.dop);const u=a-t.x,g=s-t.y,l=i-t.z,c=d-t.v,p=Math.sqrt(u*u+g*g+l*l),f=Math.abs(c);t.pError+=t.v*t.dt,t.dt=0;const N=p+2.5*t.dop,h=f+.05*t.dop,S=t.pError/(t.pError+N)||0,x=t.vError/(t.vError+h)||0;t.x+=u*S,t.y+=g*S,t.z+=l*S,t.v+=c*x,t.pError+=(N-t.pError)*S,t.vError+=(h-t.vError)*x;const E=Math.sqrt(t.x*t.x+t.y*t.y+t.z*t.z);t.lat=180*Math.asin(t.z/E)/Math.PI||0,t.lon=180*Math.atan2(t.y,t.x)/Math.PI||0,t.alt=E-6371008.8,t.status===o.Running&&(t.distance+=p*S,t.speed=t.distance/t.duration||0,t.cadence=60*t.steps/t.duration||0)}(t),r(t),t.gpsValid&&t.status===o.Running&&function(t){t.file.write([Date.now().toFixed(0),t.lat.toFixed(6),t.lon.toFixed(6),t.alt.toFixed(2),t.duration.toFixed(0),t.distance.toFixed(2),t.hr.toFixed(0),t.steps.toFixed(0)].join(",")+"\n")}(t)}(i,t)),Bangle.setGPSPower(1),function(t){Bangle.on("HRM",n=>function(t,n){if(0===n.confidence)return;const r=n.bpm-t.hr,e=Math.abs(r)+101-n.confidence,o=t.hrError/(t.hrError+e)||0;t.hr+=r*o,t.hrError+=(e-t.hrError)*o}(t,n)),Bangle.setHRMPower(1)}(s),function(t){Bangle.on("step",()=>function(t){t.status===o.Running&&(t.steps+=1)}(t))}(s),function(t){Bangle.loadWidgets(),Bangle.on("lcdPower",n=>{t.drawing=n,n&&e(t)}),e(t)}(s),setWatch(()=>a(s),BTN1,{repeat:!0,edge:"falling"}),setWatch(()=>function(t){t.status===o.Paused&&function(t){t.duration=0,t.distance=0,t.speed=0,t.steps=0,t.cadence=0}(t),t.status===o.Running?t.status=o.Paused:t.status=o.Stopped,r(t)}(s),BTN3,{repeat:!0,edge:"falling"})}();
!function(){"use strict";const t={STOP:63488,PAUSE:65504,RUN:2016};function n(t,n,r){g.setColor(0),g.fillRect(n-60,r,n+60,r+30),g.setColor(65535),g.drawString(t,n,r)}function r(r){var e;g.setFontVector(30),g.setFontAlign(0,-1,0),n((r.distance/1e3).toFixed(2),60,55),n(function(t){const n=Math.round(t),r=Math.floor(n/3600),e=Math.floor(n/60)%60,o=n%60;return(r?r+":":"")+("0"+e).substr(-2)+":"+("0"+o).substr(-2)}(r.duration),180,55),n(function(t){if(t<.1667)return"__'__\"";const n=Math.round(1e3/t),r=Math.floor(n/60),e=n%60;return("0"+r).substr(-2)+"'"+("0"+e).substr(-2)+'"'}(r.speed),60,115),n(r.hr.toFixed(0),180,115),n(r.steps.toFixed(0),60,175),n(r.cadence.toFixed(0),180,175),g.setFont("6x8",2),g.setColor(r.gpsValid?2016:63488),g.fillRect(0,216,80,240),g.setColor(0),g.drawString("GPS",40,220),g.setColor(65535),g.fillRect(80,216,160,240),g.setColor(0),g.drawString(("0"+(e=new Date).getHours()).substr(-2)+":"+("0"+e.getMinutes()).substr(-2),120,220),g.setColor(t[r.status]),g.fillRect(160,216,240,240),g.setColor(0),g.drawString(r.status,200,220)}function e(t){g.clear(),g.setColor(50712),g.setFont("6x8",2),g.setFontAlign(0,-1,0),g.drawString("DIST (KM)",60,32),g.drawString("TIME",180,32),g.drawString("PACE",60,92),g.drawString("HEART",180,92),g.drawString("STEPS",60,152),g.drawString("CADENCE",180,152),r(t),Bangle.drawWidgets()}var o;function a(t){t.status===o.Stopped&&function(t){const n=(new Date).toISOString().replace(/[-:]/g,""),r=`banglerun_${n.substr(2,6)}_${n.substr(9,6)}`;t.file=require("Storage").open(r,"w"),t.file.write(["timestamp","latitude","longitude","altitude","duration","distance","heartrate","steps"].join(",")+"\n")}(t),t.status===o.Running?t.status=o.Paused:t.status=o.Running,r(t)}!function(t){t.Stopped="STOP",t.Paused="PAUSE",t.Running="RUN"}(o||(o={}));const s={fix:NaN,lat:NaN,lon:NaN,alt:NaN,vel:NaN,dop:NaN,gpsValid:!1,x:NaN,y:NaN,z:NaN,v:NaN,t:NaN,dt:NaN,pError:NaN,vError:NaN,hr:60,hrError:100,file:null,drawing:!1,status:o.Stopped,duration:0,distance:0,speed:0,steps:0,cadence:0};var i;i=s,Bangle.on("GPS",t=>function(t,n){t.lat=n.lat,t.lon=n.lon,t.alt=n.alt,t.vel=n.speed/3.6,t.fix=n.fix,t.dop=n.hdop,t.gpsValid=t.fix>0&&t.dop<=5,function(t){const n=Date.now();let r=(n-t.t)/1e3;if(isFinite(r)||(r=0),t.t=n,t.dt+=r,t.status===o.Running&&(t.duration+=r),!t.gpsValid)return;const e=6371008.8+t.alt,a=t.lat*Math.PI/180,s=t.lon*Math.PI/180,i=e*Math.cos(a)*Math.cos(s),d=e*Math.cos(a)*Math.sin(s),u=e*Math.sin(a),g=t.vel;if(!t.x)return t.x=i,t.y=d,t.z=u,t.v=g,t.pError=2.5*t.dop,void(t.vError=.05*t.dop);const l=i-t.x,c=d-t.y,p=u-t.z,f=g-t.v,N=Math.sqrt(l*l+c*c+p*p),h=Math.abs(f);t.pError+=t.v*t.dt,t.dt=0;const S=N+2.5*t.dop,E=h+.05*t.dop,w=t.pError/(t.pError+S)||0,x=t.vError/(t.vError+E)||0;t.x+=l*w,t.y+=c*w,t.z+=p*w,t.v+=f*x,t.pError+=(S-t.pError)*w,t.vError+=(E-t.vError)*x,t.status===o.Running&&(t.distance+=N*w,t.speed=t.distance/t.duration||0,t.cadence=60*t.steps/t.duration||0)}(t),r(t),t.gpsValid&&t.status===o.Running&&function(t){t.file.write([Date.now().toFixed(0),t.lat.toFixed(6),t.lon.toFixed(6),t.alt.toFixed(2),t.duration.toFixed(0),t.distance.toFixed(2),t.hr.toFixed(0),t.steps.toFixed(0)].join(",")+"\n")}(t)}(i,t)),Bangle.setGPSPower(1),function(t){Bangle.on("HRM",n=>function(t,n){if(0===n.confidence)return;const r=n.bpm-t.hr,e=Math.abs(r)+101-n.confidence,o=t.hrError/(t.hrError+e)||0;t.hr+=r*o,t.hrError+=(e-t.hrError)*o}(t,n)),Bangle.setHRMPower(1)}(s),function(t){Bangle.on("step",()=>function(t){t.status===o.Running&&(t.steps+=1)}(t))}(s),function(t){Bangle.loadWidgets(),Bangle.on("lcdPower",n=>{t.drawing=n,n&&e(t)}),e(t)}(s),setWatch(()=>a(s),BTN1,{repeat:!0,edge:"falling"}),setWatch(()=>function(t){t.status===o.Paused&&function(t){t.duration=0,t.distance=0,t.speed=0,t.steps=0,t.cadence=0}(t),t.status===o.Running?t.status=o.Paused:t.status=o.Stopped,r(t)}(s),BTN3,{repeat:!0,edge:"falling"})}();

View File

@ -111,6 +111,7 @@ function trackLineToObject(l, hasFileName) {
var t = l.trim().split(",");
var n = hasFileName ? 1 : 0;
var o = {
invalid : t.length < 8,
date : new Date(parseInt(t[n+0])),
lat : parseFloat(t[n+1]),
lon : parseFloat(t[n+2]),
@ -140,7 +141,7 @@ function downloadTrack(trackid, callback) {
function getTrackList() {
Util.showModal("Loading Tracks...");
domTracks.innerHTML = "";
Puck.eval(`require("Storage").list(/banglerun_.*\\1/).map(fn=>{fn=fn.slice(0,-1);var f=require("Storage").open(fn,"r");f.readLine();return fn+","+f.readLine()})`,trackLines=>{
Puck.eval(`require("Storage").list(/banglerun_.*\\x01/).map(fn=>{fn=fn.slice(0,-1);var f=require("Storage").open(fn,"r");f.readLine();return fn+","+f.readLine()})`,trackLines=>{
var html = `<div class="container">
<div class="columns">\n`;
trackLines.forEach(l => {
@ -149,9 +150,9 @@ function getTrackList() {
<div class="column col-12">
<div class="card-header">
<div class="card-title h5">Track ${track.filename}</div>
<div class="card-subtitle text-gray">${track.date.toString().substr(0,24)}</div>
<div class="card-subtitle text-gray">${track.invalid ? "No Data":track.date.toString().substr(0,24)}</div>
</div>
<div class="card-image">
${track.invalid?``:`<div class="card-image">
<iframe
width="100%"
height="250"
@ -159,10 +160,10 @@ function getTrackList() {
src="https://www.google.com/maps/embed/v1/place?key=AIzaSyBxTcwrrVOh2piz7EmIs1Xn4FsRxJWeVH4&q=${track.lat},${track.lon}&zoom=10" allowfullscreen>
</iframe>
</div>
<div class="card-body"></div>
<div class="card-footer">
<div class="card-body"></div>`}
<div class="card-footer">${track.invalid?``:`
<button class="btn btn-primary" trackid="${track.filename}" task="downloadkml">Download KML</button>
<button class="btn btn-primary" trackid="${track.filename}" task="downloadgpx">Download GPX</button>
<button class="btn btn-primary" trackid="${track.filename}" task="downloadgpx">Download GPX</button>`}
<button class="btn btn-default" trackid="${track.filename}" task="delete">Delete</button>
</div>
</div>

View File

@ -22,13 +22,6 @@ function initGps(state: AppState): void {
Bangle.setGPSPower(1);
}
function parseCoordinate(coordinate: string): number {
const pivot = coordinate.indexOf('.') - 2;
const degrees = parseInt(coordinate.substr(0, pivot));
const minutes = parseFloat(coordinate.substr(pivot)) / 60;
return (degrees + minutes) * Math.PI / 180;
}
function readGps(state: AppState, gps: GpsEvent): void {
state.lat = gps.lat;
state.lon = gps.lon;
@ -49,7 +42,8 @@ function readGps(state: AppState, gps: GpsEvent): void {
function updateGps(state: AppState): void {
const t = Date.now();
const dt = (t - state.t) / 1000;
let dt = (t - state.t) / 1000;
if (!isFinite(dt)) dt=0;
state.t = t;
state.dt += dt;
@ -63,9 +57,11 @@ function updateGps(state: AppState): void {
}
const r = EARTH_RADIUS + state.alt;
const x = r * Math.cos(state.lat) * Math.cos(state.lon);
const y = r * Math.cos(state.lat) * Math.sin(state.lon);
const z = r * Math.sin(state.lat);
const lat = state.lat * Math.PI / 180;
const lon = state.lon * Math.PI / 180;
const x = r * Math.cos(lat) * Math.cos(lon);
const y = r * Math.cos(lat) * Math.sin(lon);
const z = r * Math.sin(lat);
const v = state.vel;
if (!state.x) {
@ -101,11 +97,14 @@ function updateGps(state: AppState): void {
state.pError += (pError - state.pError) * pGain;
state.vError += (vError - state.vError) * vGain;
/*// we're not currently updating lat/lon with the kalman filter
// as it seems not to update them correctly at the moment
// and we only use them for logging (where it makes sense to use
// raw GPS coordinates)
const pMag = Math.sqrt(state.x * state.x + state.y * state.y + state.z * state.z);
state.lat = (Math.asin(state.z / pMag) * 180 / Math.PI) || 0;
state.lon = (Math.atan2(state.y, state.x) * 180 / Math.PI) || 0;
state.alt = pMag - EARTH_RADIUS;
state.alt = pMag - EARTH_RADIUS;*/
if (state.status === ActivityStatus.Running) {
state.distance += dpMag * pGain;
@ -114,4 +113,4 @@ function updateGps(state: AppState): void {
}
}
export { initGps, parseCoordinate, readGps, updateGps };
export { initGps, readGps, updateGps };

View File

@ -1,3 +1,5 @@
0.07: Submitted to App Loader
0.08: Fixes issue where face would redraw on wake leading to all memory being used and watch crashing.
0.09: Add BTN1 status line with ID,Fw ver, mem %, battery %
0.10: Icon fixed for transparency
0.11: added Heart Rate Monitor status and ability to turn on/off

View File

@ -9,6 +9,14 @@ A retro VT100 command line style clock
### With BTN1 pressed
* Successive presses of BTN1 will show id, FW version, battery %, memory %
* Successive presses of BTN1 will show Heart rate, Steps, id, FW version, battery %, memory %
![](cli_clock_with_id.jpg)
* BTN2 shows a functional menu that enables the Heart rate monitor to be turned on / off using BTN1
Once the heart rate monitor is ON, you can cycle through the displays to show the heart rate.
## Future Enhancements
* Ability to turn on the GPS and show, lat long, grid ref
* Maybe a simple stopwatch capability

View File

@ -1 +1 @@
require("heatshrink").decompress(atob("kEgwkBiIA/ACBhLB6gqKB6g//B6I4DiDqCB40QB4MBAoIXDB40BAIIPNG44PLAoQvMB5RPEB5JvEBAav1f7wA/ABoA=="))
require("heatshrink").decompress(atob("mEwgRC/AH4Ae/4AEBaPwAgcPBaIvvBZkL8ED6ALHl/4+XgBY89vnw+ALHngDB+gLK3AjKng7JBwJTJgEfO76/iAH4A/ADAA="))

View File

@ -4,13 +4,21 @@ var marginTop = 40;
var flag = false;
var WeekDays = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
var hrtOn = false;
var hrtStr = "Hrt: ??? bpm";
const NONE_MODE = "none";
const ID_MODE = "id";
const VER_MODE = "ver";
const BATT_MODE = "batt";
const MEM_MODE = "mem";
const STEPS_MODE = "step";
const HRT_MODE = "hrt";
const NONE_FN_MODE = "no_fn";
const HRT_FN_MODE = "fn_hrt";
let infoMode = NONE_MODE;
let functionMode = NONE_FN_MODE;
function drawAll(){
updateTime();
@ -54,11 +62,29 @@ function drawInfo(line) {
let str = "";
let col = 0x07E0; // green
//console.log("drawInfo(), infoMode=" + infoMode + " funcMode=" + functionMode);
switch(functionMode) {
case NONE_FN_MODE:
break;
case HRT_FN_MODE:
col = 0x07FF; // cyan
str = "HRM: " + (hrtOn ? "ON" : "OFF");
drawModeLine(line,str,col);
return;
}
switch(infoMode) {
case NONE_MODE:
col = 0x0000;
str = "";
break;
case HRT_MODE:
str = hrtStr;
break;
case STEPS_MODE:
str = "Steps: " + stepsWidget().getSteps();
break;
case ID_MODE:
val = NRF.getAddress().split(":");
str = "Id: " + val[4] + val[5];
@ -75,6 +101,10 @@ function drawInfo(line) {
str = "Battery: " + E.getBattery() + "%";
}
drawModeLine(line,str,col);
}
function drawModeLine(line, str, col) {
g.setColor(col);
g.fillRect(0, marginTop-3+line*30, 239, marginTop+25+line*30);
g.setColor(0,0,0);
@ -83,8 +113,31 @@ function drawInfo(line) {
}
function changeInfoMode() {
switch(functionMode) {
case NONE_FN_MODE:
break;
case HRT_FN_MODE:
hrtOn = !hrtOn;
Bangle.buzz();
Bangle.setHRMPower(hrtOn ? 1 : 0);
if (hrtOn) infoMode = HRT_MODE;
return;
}
switch(infoMode) {
case NONE_MODE:
if (stepsWidget() !== undefined)
infoMode = hrtOn ? HRT_MODE : STEPS_MODE;
else
infoMode = VER_MODE;
break;
case HRT_MODE:
if (stepsWidget() !== undefined)
infoMode = STEPS_MODE;
else
infoMode = VER_MODE;
break;
case STEPS_MODE:
infoMode = ID_MODE;
break;
case ID_MODE:
@ -102,6 +155,37 @@ function changeInfoMode() {
}
}
function changeFunctionMode() {
//console.log("changeFunctionMode()");
switch(functionMode) {
case NONE_FN_MODE:
functionMode = HRT_FN_MODE;
break;
case HRT_FN_MODE:
default:
functionMode = NONE_FN_MODE;
}
//console.log(functionMode);
}
function stepsWidget() {
if (WIDGETS.activepedom !== undefined) {
return WIDGETS.activepedom;
} else if (WIDGETS.wpedom !== undefined) {
return WIDGETS.wpedom;
}
return undefined;
}
Bangle.on('HRM', function(hrm) {
if(hrm.confidence > 90){
hrtStr = "Hrt: " + hrm.bpm + " bpm";
} else {
hrtStr = "Hrt: ??? bpm";
}
});
g.clear();
Bangle.loadWidgets();
Bangle.drawWidgets();
@ -113,3 +197,4 @@ Bangle.on('lcdPower',function(on) {
var click = setInterval(updateTime, 1000);
setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"});
setWatch(() => { changeInfoMode(); drawAll(); }, BTN1, {repeat: true});
setWatch(() => { changeFunctionMode(); drawAll(); }, BTN3, {repeat: true});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 B

After

Width:  |  Height:  |  Size: 348 B

View File

@ -1,2 +1,3 @@
0.01: New app!
0.02: Improve handling of large amounts of files (fix #579)
0.03: Update RegExp use (Was using backreference instead of character code)

View File

@ -91,8 +91,8 @@ function drawMenu() {
function get_pruned_file_list() {
// get storagefile list
var sf = STOR.list(/\1$/).map(s=>s.slice(0,-1));
var sffilter = f=>!sf.includes(f.slice(0,-1)) || f.endsWith("\1");
var sf = STOR.list(/\x01$/).map(s=>s.slice(0,-1));
var sffilter = f=>!sf.includes(f.slice(0,-1)) || f.endsWith("\x01");
// get files - put '.' last
var fl = STOR.list(/^[^\.]/).filter(sffilter);
fl.sort();

View File

@ -18,3 +18,5 @@
Nicer display of alarm clock notifications
0.17: Modified music notification for updated 'notify' library
0.18: Added reporting of step count and HRM (new Gadgetbridges can now log this)
0.19: Support for call incoming/start/end
0.20: Reduce memory usage

View File

@ -2,13 +2,11 @@
// Music handling
const state = {
music: "stop",
musicInfo: {
artist: "",
album: "",
track: ""
},
scrollPos: 0
};
// activity reporting
@ -43,14 +41,6 @@
return event;
}
}
function handleNotificationEvent(event) {
if (event.t === "notify") {
require("notify").show(prettifyNotificationEvent(event));
Bangle.buzz();
} else { // notify-
require("notify").hide(event);
}
}
function updateMusic(options){
if (state.music === "play") {
@ -117,37 +107,6 @@
require("notify").hide("music");
}
}
function handleMusicStateUpdate(event) {
if (state.music !== event.state) {
state.music = event.state
updateMusic({on: true});
}
}
function handleMusicInfoUpdate(event) {
state.musicInfo = event;
updateMusic({on: false});
}
function handleCallEvent(event) {
if (event.cmd === "accept") {
require("notify").show({
size: 55, title: event.name, id: "call",
body: event.number, icon:require("heatshrink").decompress(atob("jEYwIMJj4CCwACJh4CCCIMOAQMGAQMHAQMDAQMBCIMB4PwgHz/EAn4CBj4CBg4CBgACCAAw="))});
Bangle.buzz();
}
}
function handleFindEvent(event) {
if (state.find) {
clearInterval(state.find);
delete state.find;
}
if (event.n)
state.find = setInterval(_=>{
Bangle.buzz();
setTimeout(_=>Bangle.beep(), 1000);
},2000);
}
function handleActivityEvent(event) {
var s = settings();
@ -193,19 +152,52 @@
switch (event.t) {
case "notify":
case "notify-":
handleNotificationEvent(event);
if (event.t === "notify") {
require("notify").show(prettifyNotificationEvent(event));
Bangle.buzz();
} else { // notify-
require("notify").hide(event);
}
break;
case "musicinfo":
handleMusicInfoUpdate(event);
state.musicInfo = event;
updateMusic({on: false});
break;
case "musicstate":
handleMusicStateUpdate(event);
if (state.music !== event.state) {
state.music = event.state
updateMusic({on: true});
}
break;
case "call":
handleCallEvent(event);
var note = { size: 55, title: event.name, id: "call",
body: event.number, icon:require("heatshrink").decompress(atob("jEYwIMJj4CCwACJh4CCCIMOAQMGAQMHAQMDAQMBCIMB4PwgHz/EAn4CBj4CBg4CBgACCAAw="))}
if (event.cmd === "incoming") {
require("notify").show(note);
Bangle.buzz();
} else if (event.cmd === "start") {
require("notify").show(Object.assign(note, {
bgColor : "#008000", titleBgColor : "#00C000",
body: "In progress: "+event.number}));
} else if (event.cmd === "end") {
require("notify").show(Object.assign(note, {
bgColor : "#800000", titleBgColor : "#C00000",
body: "Ended: "+event.number}));
setTimeout(function() {
require("notify").hide({ id: "call" });
}, 2000);
}
break;
case "find":
handleFindEvent(event);
if (state.find) {
clearInterval(state.find);
delete state.find;
}
if (event.n)
state.find = setInterval(_=>{
Bangle.buzz();
setTimeout(_=>Bangle.beep(), 1000);
},2000);
break;
case "act":
handleActivityEvent(event);

View File

@ -18,3 +18,4 @@
0.14: Now use the openstmap lib for map plotting
0.15: Add plotTrack method to allow current track to be plotted on a map (#395)
0.16: Add gpsrec app to Settings menu
0.17: Disable recording if storage is full (fix #574)

View File

@ -29,12 +29,21 @@
periodCtr--;
if (periodCtr<=0) {
periodCtr = settings.period;
try {
if (gpsTrack) gpsTrack.write([
fix.time.getTime(),
fix.lat.toFixed(6),
fix.lon.toFixed(6),
fix.alt
].join(",")+"\n");
} catch(e) {
// If storage.write caused an error, disable
// GPS recording so we don't keep getting errors!
console.log("gpsrec: write error", e);
settings.recording = false;
require("Storage").write("gpsrec.json", settings);
reload();
}
}
}
}

View File

@ -1,3 +1,4 @@
0.01: New App
0.02: Restore to SuperE mode on power off.
0.03: dont reset to SuperE mode on power, as it prevents its general use
0.04: Only turn GPS off if it was previously on (stops other apps/widgets that use GPS getting broken)

View File

@ -3,6 +3,7 @@
var fixToggle = false; // toggles once for each reading
var have_fix = false;
var debug = false;
var gpsPowerEnabled = false;
var last_fix = {
fix: 0,
@ -68,7 +69,10 @@
function gps_power_off() {
//setupSuperE(); // return to expected setup for other apps
if (gpsPowerEnabled) {
gpsPowerEnabled = false;
Bangle.setGPSPower(0);
}
have_fix = false;
fixToggle = false;
last_fix.fix = 0;
@ -86,6 +90,7 @@
function setupGPS() {
Bangle.setGPSPower(1);
gpsPowerEnabled = true;
if (settings.power_mode === "PSMOO") {
setupPSMOO();
@ -280,4 +285,3 @@
reload();
})();

2
apps/gpssetup/ChangeLog Normal file
View File

@ -0,0 +1,2 @@
0.01: First version of GPS Setup app
0.02: Created gppsetup module

109
apps/gpssetup/README.md Normal file
View File

@ -0,0 +1,109 @@
# GPS Setup
An App and module to enable the GPS to be configured into low power mode.
## Goals
To develop an app that configures the GPS to run with the lowest
possible power consumption.
Example power consumption of the GPS while powered on:
* An app that turns on the GPS and constantly displays the screen
will use around 75mA, the battery will last between 3-4 hours.
* Using the GPS with Super-E Power Saving Mode (PSM) with the screen
off most of the time, will consume around 35mA and you might get
10hrs before a recharge.
* Using the GPS in Power Saving Mode On/Off (PSMOO) with suitable
settings can reduce the average consumption to around 15mA. A
simple test using a 120s update period, 6s search period was still
running with 45% battery 20 hours after it started.
## Settings App
The Settings App enables you set the options below. Either start the
App from the launcher or go to Settings, select App/Widgets and then
'GPS Setup'.
When you exit the setup app, the settings will be stored in the
gpssetup.settings.json file, the GPS will be switched on and the
necessary commands sent to the GPS to configure it. The GPS is then
powered off. The GPS configuration is stored in the GPS non-volatile
memory so that next time the GPS is powered, that configuration is
used. These settings will remain for all apps that use the GPS.
- Power Mode:
- **SuperE** - the factory default setup for the GPS. The recommended
power saving mode. If you need frequent (every second) updates on
position, then this is the mode for you.
- **PSMOO** - On/Off power saving mode. Configured by interval and
search time. Choose this mode if you are happy to get a GPS
position update less often (say every 1 or 2 minutes). The longer
the interval the more time the GPS will spend sleeping in low
power mode (7mA) between obtaining fixes (35mA). For walking in
open country an update once every 60 seconds is adequate to put
you within a 6 digit grid refernce sqaure.
- update - the time between two position fix attempts.
- search - the time between two acquisition attempts if the receiver
is unable to get a position fix.
## Module
A module is provided that'll allow you to set GPS configuration from your own
app. To use it:
```
// This will set up the GPS to current saved defaults. It's not normally
// needed unless the watch's battery has run down
require("gpssetup").setPowerMode();
// This sets up the PSMOO mode. update/search are optional in seconds
require("gpssetup").setPowerMode({
power_mode:"PSMOO",
update:optional (default 120),
search:optional (default 5)})
// This sets up SuperE
require("gpssetup").setPowerMode({power_mode:"SuperE"})
```
`setPowerMode` returns a promise, which is completed when the GPS is set up.
So you can for instance do the following to turn the GPS off once it
has been configured:
```
require("gpssetup").setPowerMode().then(function() {
Bangle.setGPSPower(0);
});
```
**Note:** It's not guaranteed that the user will have installed the `gpssetup`
app/module. It might be worth checking for its existence by surrounding the
`require` call with `try...catch` block.
```
var gpssetup;
try {
gpssetup = require("gpssetup")
} catch(e) {
E.showMessage("gpssetup\nnot installed");
}
```
## References
* [UBLOX M8 Receiver Data Sheet](https://www.u-blox.com/sites/default/files/products/documents/u-blox8-M8_ReceiverDescrProtSpec_%28UBX-13003221%29.pdf)
* [UBLOX Power Management App Note](https://www.u-blox.com/sites/default/files/products/documents/PowerManagement_AppNote_%28UBX-13005162%29.pdf)
* Some useful code on Github can be found [here](https://portal.u-blox.com/s/question/0D52p0000925T00CAE/ublox-max-m8q-getting-stuck-when-sleeping-with-extint-pin-control)
and [here](https://github.com/thasti/utrak/blob/master/gps.c)

109
apps/gpssetup/app.js Normal file
View File

@ -0,0 +1,109 @@
/*
* GPS Setup app, hughbarney AT googlemail DOT com
* With thanks to Gordon Williams for support and advice
*
* UBLOX power modes:
* SuperE - will provide updates every second and consume 35mA, 75mA with LCD on
* PSMOO - will sleep for update time and consume around 7mA during that period
* after acquiring satelite fixes the GPS will settle into a cycle of
* obtaining fix, sleeping for update seconds, wake up, get fix and sleep.
*
* See README file for more details
*
*/
Bangle.loadWidgets();
Bangle.drawWidgets();
function log_debug(o) {
//let timestamp = new Date().getTime();
//console.log(timestamp + " : " + o);
}
const SETTINGS_FILE = "gpssetup.settings.json";
let settings = undefined;
let settings_changed = false;
function updateSettings() {
require("Storage").write(SETTINGS_FILE, settings);
settings_changed = true;
}
function loadSettings() {
log_debug("loadSettings()");
settings = require("Storage").readJSON(SETTINGS_FILE,1)||{};
settings.update = settings.update||120;
settings.search = settings.search||5;
settings.power_mode = settings.power_mode||"SuperE";
log_debug(settings);
}
/*********** GPS Power and Setup Functions ******************/
function setupGPS() {
Bangle.setGPSPower(1);
setTimeout(function() {
require("gpssetup").setPowerMode().then(function() {
Bangle.setGPSPower(0);
});
}, 100);
}
/*********** GPS Setup Menu App *****************************/
function showMainMenu() {
var power_options = ["SuperE","PSMOO"];
const mainmenu = {
'': { 'title': 'GPS Setup' },
'< Back': ()=>{exitSetup();},
'Power Mode': {
value: 0 | power_options.indexOf(settings.power_mode),
min: 0, max: 1,
format: v => power_options[v],
onchange: v => {
settings.power_mode = power_options[v];
updateSettings();
},
},
'Update (s)': {
value: settings.update,
min: 10,
max: 1800,
step: 10,
onchange: v => {
settings.update = v;
updateSettings();
}
},
'Search (s)': {
value: settings.search,
min: 1,
max: 65,
step: 1,
onchange: v => {
settings.search = v;
updateSettings();
}
}
};
return E.showMenu(mainmenu);
}
function exitSetup() {
log_debug("exitSetup()");
if (settings_changed) {
log_debug(settings);
E.showMessage("Configuring GPS");
setTimeout(function() {
setupGPS();
setTimeout(function() { load() }, 750);
}, 500);
} else {
load();
}
}
loadSettings();
showMainMenu();

179
apps/gpssetup/gpssetup.js Normal file
View File

@ -0,0 +1,179 @@
const SETTINGS_FILE = "gpssetup.settings.json";
function log_debug(o) {
//let timestamp = new Date().getTime();
//console.log(timestamp + " : " + o);
}
function writeGPScmd(cmd) {
var d = [0xB5,0x62]; // sync chars
d = d.concat(cmd);
var a=0,b=0;
for (var i=2;i<d.length;i++) {
a += d[i];
b += a;
}
d.push(a&255,b&255);
Serial1.write(d);
}
// UBX-CFG-PMS - enable power management - Super-E
function UBX_CFG_PMS() {
log_debug("UBX_CFG_PMS()");
writeGPScmd([0x06,0x86, // msg class + type
8,0,//length
0x00,0x03, 0,0, 0,0, 0,0]);
}
/*
* Extended Power Management
* update and search are in milli seconds
* settings are loaded little endian, lsb first
*
* https://github.com/thasti/utrak/blob/master/gps.c
*/
function UBX_CFG_PM2(update,search) {
log_debug("UBX_CFG_PM2()");
// convert an integer to an array of bytes
function int_2_bytes( x ){
var bytes = [];
var i = 4;
do {
bytes[--i] = x & (255);
x = x>>8;
} while (i);
return bytes;
}
var u = int_2_bytes(update*1000);
var s = int_2_bytes(search*1000);
writeGPScmd([0x06, 0x3B, /* class id */
44, 0, /* length */
0x01, 0x00, 0x00, 0x00, /* v1, reserved 1..3 */
0x00, 0x10, 0x00, 0x00, /* on/off-mode, update ephemeris */
u[3], u[2], u[1], u[0], /* update period, ms, 120s=00 01 D4 C0, 30s= 00 00 75 30 */
s[3], s[2], s[1], s[0], /* search period, ms, 120s, 20s = 00 00 4E 20, 5s = 13 88 */
0x00, 0x00, 0x00, 0x00, /* grid offset */
0x00, 0x00, /* on-time after first fix */
0x01, 0x00, /* minimum acquisition time */
0x00, 0x00, 0x00, 0x00, /* reserved 4,5 */
0x00, 0x00, 0x00, 0x00, /* reserved 6 */
0x00, 0x00, 0x00, 0x00, /* reserved 7 */
0x00, 0x00, 0x00, 0x00, /* reserved 8,9,10 */
0x00, 0x00, 0x00, 0x00]); /* reserved 11 */
}
// enable power saving mode, after configured with PM2
function UBX_CFG_RXM() {
log_debug("UBX_CFG_RXM()");
writeGPScmd([0x06, 0x11, /* UBX-CFG-RXM */
2, 0, /* length */
0x08, 0x01]); /* reserved, enable power save mode */
}
/*
* Save configuration otherwise it will reset when the GPS wakes up
*/
function UBX_CFG_SAVE() {
log_debug("UBX_CFG_SAVE()");
writeGPScmd([0x06, 0x09, // class id
0x0D, 0x00, // length
0x00, 0x00, 0x00, 0x00, // clear mask
0xFF, 0xFF, 0x00, 0x00, // save mask
0x00, 0x00, 0x00, 0x00, // load mask
0x07]); // b2=eeprom b1=flash b0=bat backed ram
}
/*
* Reset to factory settings using clear mask in UBX_CFG_CFG
* https://portal.u-blox.com/s/question/0D52p0000925T00CAE/ublox-max-m8q-getting-stuck-when-sleeping-with-extint-pin-control
*/
function UBX_CFG_RESET() {
log_debug("UBX_CFG_RESET()");
writeGPScmd([0x06, 0x09, // class id
0x0D, 0x00,
0xFF, 0xFB, 0x00, 0x00, // clear mask
0x00, 0x00, 0x00, 0x00, // save mask
0xFF, 0xFF, 0x00, 0x00, // load mask
0x17]);
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function setupSuperE() {
log_debug("setupGPS() Super-E");
return Promise.resolve().then(function() {
UBX_CFG_RESET();
return delay(100);
}).then(function() {
UBX_CFG_PMS();
return delay(20);
}).then(function() {
UBX_CFG_SAVE();
return delay(20);
}).then(function() {
log_debug("Powering GPS Off");
/*
* must be part of the promise chain to ensure that
* setup does not return and powerOff before config functions
* have run
*/
return delay(20);
});
}
function setupPSMOO(settings) {
log_debug("setupGPS() PSMOO");
return Promise.resolve().then(function() {
UBX_CFG_RESET();
return delay(100);
}).then(function() {
UBX_CFG_PM2(settings.update, settings.search);
return delay(20);
}).then(function() {
UBX_CFG_RXM();
return delay(20);
}).then(function() {
UBX_CFG_SAVE();
return delay(20);
}).then(function() {
log_debug("Powering GPS Off");
/*
* must be part of the promise chain to ensure that
* setup does not return and powerOff before config functions
* have run
*/
return delay(20);
});
}
/** Set GPS power mode (assumes GPS on), returns a promise.
Either:
require("gpssetup").setPowerMode() // <-- set up GPS to current saved defaults
require("gpssetup").setPowerMode({power_mode:"PSMOO", update:optional, search:optional}) // <-- PSMOO mode
require("gpssetup").setPowerMode({power_mode:"SuperE"}) // <-- Super E mode
See the README for more information
*/
exports.setPowerMode = function(options) {
settings = require("Storage").readJSON(SETTINGS_FILE,1)||{};
if (options) {
if (options.update) settings.update = options.update;
if (options.search) settings.search = options.search;
if (options.power_mode) settings.power_mode = options.power_mode;
}
settings.update = settings.update||120;
settings.search = settings.search||5;
settings.power_mode = settings.power_mode||"SuperE";
if (options) require("Storage").write(SETTINGS_FILE, settings);
if (settings.power_mode === "PSMOO") {
return setupPSMOO(settings);
} else {
return setupSuperE();
}
};

BIN
apps/gpssetup/gpssetup.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

1
apps/gpssetup/icon.js Normal file
View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/ACmsAAIss1mBwIfZqwABFpwuYC4IADGBYuaDQwuDF5ouYLo4vJIYousCYQOIHJIuUCo4uIHJIuUf4wlGEIQaHFywvHGAguiF5GBEIgbHFzAvJDwwuRvV6F6xLJFxmkAAQuKqwtKPQ4RKFwgwICgobHVRJAJFQOr0owIE5AtNDIYRI0ulGBAuNapYABCRGkGBAuGAoIpNGBIIFGBF6FwuBFygAKGBAulGBgujGBWAF0jpBehIvlqwws1jnCGFOs1heBGFQuBFoYwoFxFWwAwjFw+BAAIMBGEIuMGEIuIeQIQFGDouJ1gSHGDYuSGDYuUGDSzBFYP+dAQuNGBN6F6RcBFyAwHwAvQGAYuSGAheCF54wCAAYuRGAQABwGAC6QuWGAV6FyYA/AH4A2A="))

View File

@ -0,0 +1,4 @@
(function(back) {
// just go right to our app
load("gpssetup.app.js");
})();

View File

@ -0,0 +1 @@
{"power_mode":"SuperE", "update":120, "search":6}

View File

@ -8,3 +8,4 @@
Ensure 'on' is always supplied for translations
0.07: Improve handling of non-ASCII characters (fix #469)
0.08: Added Mavigation units and en_NAV
0.09: Added New Zealand en_NZ

View File

@ -245,6 +245,24 @@ var locales = {
day: "söndag,måndag,tisdag,onsdag,torsdag,fredag,lördag",
trans: { yes: "ja", Yes: "Ja", no: "nej", No: "Nej", ok: "ok", on: "on", off: "off" }
},
"en_NZ": {
lang: "en_NZ",
decimal_point: ".",
thousands_sep: ",",
currency_symbol: "$",
int_curr_symbol: "NZD",
speed: "kph",
distance: { 0: "m", 1: "km" },
temperature: "°C",
ampm: { 0: "am", 1: "pm" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%A, %B %d, %Y", "1": "%d/%m/%y" }, // Sunday, 1 March 2020 // 1/3/20
abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
month: "January,February,March,April,May,June,July,August,September,October,November,December",
abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
// No translation for english...
},
"en_AU": {
lang: "en_AU",
decimal_point: ".",

View File

@ -9,3 +9,4 @@
0.09: Added Pedometer clock
0.10: Added GPS and Grid Ref clock faces
0.11: Updated Pedometer clock to retrieve steps from either wpedom or activepedom
0.12: Removed GPS and Grid Ref clock faces, superceded by GPS setup and Walkers Clock

View File

@ -14,8 +14,6 @@
{"name":"digi.face.js","url":"digi.min.js"},
{"name":"txt.face.js","url":"txt.min.js"},
{"name":"ped.face.js","url":"ped.js"},
{"name":"osref.face.js","url":"osref.js"},
{"name":"gps.face.js","url":"pgs.js"},
{"name":"multiclock.img","url":"multiclock-icon.js","evaluate":true}
]
},

View File

@ -1,95 +0,0 @@
(() => {
function getFace(){
//var img = require("heatshrink").decompress(atob("mEwghC/AH4AKg9wC6t3u4uVC6wWBI6t3uJeVuMQCqcBLisAi4XLxAABFxAXKgc4DBAuBRhQXEDAq7MmYXEwBHEXZYXFGAOqAAKDMmczC4mIC62CC50PC4JIBkQABiIvRmURAAUSjQXSFwMoxGKC6CRFwUSVYgXLPIgXXwMYegoXLJAYXCGBnzGA0hPQIwMgYwGC6gwCC4ZIMC4gYBC604C4ZISmcRVgapQAAMhC6GIJIwXCMBcIxGDDBAuLC4IwGAARGMAAQWGmAXPJQoWMC4pwCCpoXJAB4XXAH4A/ABQA="));
var nofix = 0;
function formatTime(now) {
var fd = now.toUTCString().split(" ");
return fd[4];
}
function timeSince(t) {
var hms = t.split(":");
var now = new Date();
var sn = 3600*(now.getHours()) + 60*(now.getMinutes()) + 1*(now.getSeconds());
var st = 3600*(hms[0]) + 60*(hms[1]) + 1*(hms[2]);
return (sn - st);
}
function draw() {
var gps_on = false;
var fix = {
fix: 0,
alt: 0,
lat: 0,
lon: 0,
speed: 0,
time: 0,
satellites: 0
};
var y_line = 26;
var y_start = 46;
var x_start = 10;
// only attempt to get gps fix if gpsservuce is loaded
if (WIDGETS.gpsservice !== undefined) {
fix = WIDGETS.gpsservice.gps_get_fix();
gps_on = WIDGETS.gpsservice.gps_get_status();
}
g.reset();
g.clearRect(0,24,239,239);
if (fix.fix) {
var time = formatTime(fix.time);
var age = timeSince(time);
g.setFontAlign(-1, -1);
g.setFont("6x8");
g.setFontVector(22);
g.drawString("Alt: " + fix.alt +" m", x_start, y_start, true);
g.drawString("Lat: "+ fix.lat, x_start, y_start + y_line, true);
g.drawString("Lon: " + fix.lon, x_start, y_start + 2*y_line, true);
g.drawString("Time: " + time, x_start, y_start + 3*y_line, true);
g.drawString("Age(s): " + age, x_start, y_start + 4*y_line, true);
g.drawString("Satellites: " + fix.satellites, x_start, y_start + 5*y_line, true);
} else if (gps_on) {
g.setFontAlign(0, 1);
g.setFont("6x8", 2);
g.drawString("GPS Watch", 120, 60);
g.drawString("Waiting for GPS", 120, 80);
nofix = (nofix+1) % 4;
g.drawString(".".repeat(nofix) + " ".repeat(4-nofix), 120, 120);
g.setFontAlign(0,0);
g.drawString(fix.satellites + " satellites", 120, 100);
} else if (!gps_on) {
g.setFontAlign(0, 0);
g.setFont("6x8", 3);
g.drawString("GPS Watch", 120, 80);
g.drawString("GPS is off",120, 160);
}
}
function onSecond(){
var t = new Date();
if ((t.getSeconds() % 5) === 0) draw();
}
return {init:draw, tick:onSecond};
}
return getFace;
})();

View File

@ -1,202 +0,0 @@
(() => {
function getFace(){
var nofix = 0;
function formatTime(now) {
var fd = now.toUTCString().split(" ");
return fd[4];
}
function timeSince(t) {
var hms = t.split(":");
var now = new Date();
var sn = 3600*(now.getHours()) + 60*(now.getMinutes()) + 1*(now.getSeconds());
var st = 3600*(hms[0]) + 60*(hms[1]) + 1*(hms[2]);
return (sn - st);
}
Number.prototype.toRad = function() { return this*Math.PI/180; };
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Ordnance Survey Grid Reference functions (c) Chris Veness 2005-2014 */
/* - www.movable-type.co.uk/scripts/gridref.js */
/* - www.movable-type.co.uk/scripts/latlon-gridref.html */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
function OsGridRef(easting, northing) {
this.easting = 0|easting;
this.northing = 0|northing;
}
OsGridRef.latLongToOsGrid = function(point) {
var lat = point.lat.toRad();
var lon = point.lon.toRad();
var a = 6377563.396, b = 6356256.909; // Airy 1830 major & minor semi-axes
var F0 = 0.9996012717; // NatGrid scale factor on central meridian
var lat0 = (49).toRad(), lon0 = (-2).toRad(); // NatGrid true origin is 49�N,2�W
var N0 = -100000, E0 = 400000; // northing & easting of true origin, metres
var e2 = 1 - (b*b)/(a*a); // eccentricity squared
var n = (a-b)/(a+b), n2 = n*n, n3 = n*n*n;
var cosLat = Math.cos(lat), sinLat = Math.sin(lat);
var nu = a*F0/Math.sqrt(1-e2*sinLat*sinLat); // transverse radius of curvature
var rho = a*F0*(1-e2)/Math.pow(1-e2*sinLat*sinLat, 1.5); // meridional radius of curvature
var eta2 = nu/rho-1;
var Ma = (1 + n + (5/4)*n2 + (5/4)*n3) * (lat-lat0);
var Mb = (3*n + 3*n*n + (21/8)*n3) * Math.sin(lat-lat0) * Math.cos(lat+lat0);
var Mc = ((15/8)*n2 + (15/8)*n3) * Math.sin(2*(lat-lat0)) * Math.cos(2*(lat+lat0));
var Md = (35/24)*n3 * Math.sin(3*(lat-lat0)) * Math.cos(3*(lat+lat0));
var M = b * F0 * (Ma - Mb + Mc - Md); // meridional arc
var cos3lat = cosLat*cosLat*cosLat;
var cos5lat = cos3lat*cosLat*cosLat;
var tan2lat = Math.tan(lat)*Math.tan(lat);
var tan4lat = tan2lat*tan2lat;
var I = M + N0;
var II = (nu/2)*sinLat*cosLat;
var III = (nu/24)*sinLat*cos3lat*(5-tan2lat+9*eta2);
var IIIA = (nu/720)*sinLat*cos5lat*(61-58*tan2lat+tan4lat);
var IV = nu*cosLat;
var V = (nu/6)*cos3lat*(nu/rho-tan2lat);
var VI = (nu/120) * cos5lat * (5 - 18*tan2lat + tan4lat + 14*eta2 - 58*tan2lat*eta2);
var dLon = lon-lon0;
var dLon2 = dLon*dLon, dLon3 = dLon2*dLon, dLon4 = dLon3*dLon, dLon5 = dLon4*dLon, dLon6 = dLon5*dLon;
var N = I + II*dLon2 + III*dLon4 + IIIA*dLon6;
var E = E0 + IV*dLon + V*dLon3 + VI*dLon5;
return new OsGridRef(E, N);
};
/*
* converts northing, easting to standard OS grid reference.
*
* [digits=10] - precision (10 digits = metres)
* to_map_ref(8, 651409, 313177); => 'TG 5140 1317'
* to_map_ref(0, 651409, 313177); => '651409,313177'
*
*/
function to_map_ref(digits, easting, northing) {
if (![ 0,2,4,6,8,10,12,14,16 ].includes(Number(digits))) throw new RangeError(`invalid precision '${digits}'`); // eslint-disable-line comma-spacing
let e = easting;
let n = northing;
// use digits = 0 to return numeric format (in metres) - note northing may be >= 1e7
if (digits == 0) {
const format = { useGrouping: false, minimumIntegerDigits: 6, maximumFractionDigits: 3 };
const ePad = e.toLocaleString('en', format);
const nPad = n.toLocaleString('en', format);
return `${ePad},${nPad}`;
}
// get the 100km-grid indices
const e100km = Math.floor(e / 100000), n100km = Math.floor(n / 100000);
// translate those into numeric equivalents of the grid letters
let l1 = (19 - n100km) - (19 - n100km) % 5 + Math.floor((e100km + 10) / 5);
let l2 = (19 - n100km) * 5 % 25 + e100km % 5;
// compensate for skipped 'I' and build grid letter-pairs
if (l1 > 7) l1++;
if (l2 > 7) l2++;
const letterPair = String.fromCharCode(l1 + 'A'.charCodeAt(0), l2 + 'A'.charCodeAt(0));
// strip 100km-grid indices from easting & northing, and reduce precision
e = Math.floor((e % 100000) / Math.pow(10, 5 - digits / 2));
n = Math.floor((n % 100000) / Math.pow(10, 5 - digits / 2));
// pad eastings & northings with leading zeros
e = e.toString().padStart(digits/2, '0');
n = n.toString().padStart(digits/2, '0');
return `${letterPair} ${e} ${n}`;
}
function draw() {
var gps_on = false;
var fix = {
fix: 0,
alt: 0,
lat: 0,
lon: 0,
speed: 0,
time: 0,
satellites: 0
};
var y_line = 26;
var y_start = 46;
var x_start = 10;
// only attempt to get gps fix if gpsservuce is loaded
if (WIDGETS.gpsservice !== undefined) {
fix = WIDGETS.gpsservice.gps_get_fix();
gps_on = WIDGETS.gpsservice.gps_get_status();
}
g.reset();
g.clearRect(0,24,239,239);
if (fix.fix) {
var time = formatTime(fix.time);
var age = timeSince(time);
var os = OsGridRef.latLongToOsGrid(fix);
var ref = to_map_ref(6, os.easting, os.northing);
age = age >=0 ? age : 0; // avoid -1 etc
g.reset();
g.clearRect(0,24,239,239);
g.setFontAlign(0,0);
g.setFont("Vector");
g.setColor(1,1,1);
g.setFontVector(40);
g.drawString(time, 120, 80);
g.setFontVector(40);
g.setColor(0xFFC0);
g.drawString(ref, 120,140, true);
g.setFont("6x8",2);
g.setColor(1,1,1);
g.drawString(age, 120, 194);
} else if (gps_on) {
g.setFontAlign(0, 1);
g.setFont("6x8", 2);
g.drawString("Gridref Watch", 120, 60);
g.drawString("Waiting for GPS", 120, 80);
nofix = (nofix+1) % 4;
g.drawString(".".repeat(nofix) + " ".repeat(4-nofix), 120, 120);
g.setFontAlign(0,0);
g.drawString(fix.satellites + " satellites", 120, 100);
} else if (!gps_on) {
g.setFontAlign(0, 0);
g.setFont("6x8", 3);
g.drawString("Gridref Watch", 120, 80);
g.drawString("GPS is off", 120, 160);
}
}
function onSecond(){
var t = new Date();
if ((t.getSeconds() % 5) === 0) draw();
}
return {init:draw, tick:onSecond};
}
return getFace;
})();

View File

@ -2,3 +2,4 @@
0.02: Add notification ID option
0.03: Pass `area{x,y,w,h}` to render callback instead of just `y`
0.05: Adjust position of notification src text
0.06: Support background color

View File

@ -41,7 +41,9 @@ function fitWords(text,rows,width) {
src : string // optional source name
body : string // optional body text
icon : string // optional icon (image string)
render function(y) // function callback to render
render : function(y) // function callback to render
bgColor : int/string // optional background color (default black)
titleBgColor : int/string // optional background color for title (default black)
}
*/
/*
@ -83,13 +85,13 @@ exports.show = function(options) {
b = y+h-1, r = x+w-1; // bottom,right
g.setClipRect(x,y, r,b);
// clear area
g.setColor(0).fillRect(x,y, r,b);
g.setColor(options.bgColor||0).fillRect(x,y, r,b);
// bottom border
g.setColor(0x39C7).fillRect(0,b-1, r,b);
b -= 2;h -= 2;
// title bar
if (options.title || options.src) {
g.setColor(0x39C7).fillRect(x,y, r,y+20);
g.setColor(options.titleBgColor||0x39C7).fillRect(x,y, r,y+20);
const title = options.title||options.src;
g.setColor(-1).setFontAlign(-1, -1, 0).setFont("6x8", 2);
g.drawString(title.trim().substring(0, 13), x+25,y+3);

View File

@ -4,3 +4,4 @@
0.04: Pass `area{x,y,w,h}` to render callback instead of just `y`
0.05: Fix `g` corruption issue if .hide gets called twice
0.06: Adjust position of notification src text and notifications without title
0.07: Support background color

View File

@ -37,7 +37,9 @@ function fitWords(text,rows,width) {
src : string // optional source name
body : string // optional body text
icon : string // optional icon (image string)
render function(y) // function callback to render
render : function(y) // function callback to render
bgColor : int/string // optional background color (default black)
titleBgColor : int/string // optional background color for title (default black)
}
*/
exports.show = function(options) {
@ -53,11 +55,11 @@ exports.show = function(options) {
w = 240,
h = size;
// clear screen
g.clear(1);
g.setColor(options.bgColor||0).fillRect(0,0,g.getWidth(),g.getHeight());
// top bar
if (options.title||options.src) {
const title = options.title || options.src
g.setColor(0x39C7).fillRect(x, y, x+w-1, y+30);
g.setColor(options.titleBgColor||0x39C7).fillRect(x, y, x+w-1, y+30);
g.setColor(-1).setFontAlign(-1, -1, 0).setFont("6x8", 3);
g.drawString(title.trim().substring(0, 13), x+5, y+3);
if (options.title && options.src) {

1
apps/oblique/app-icon.js Normal file
View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwkE/4A///zmfzn4fbDhQqBAAQMHj4XJ+SQGh4MDl4vKgMRAAgXEF5X/iAXWkEQIoQ0BC4kTC5UwC4cAC4sSC5XxgIXJkJwDPBAXJiCQCmbEGC5kTn7PBC4vzkMRC5UQgUikYuFmILBC5SwCVYMikMSmf/gaPLEYMBMQMwW4fzgUyL5YwCkQLBAATKBmJfMiIlBB4Q1BBYPwC5oZCiMSOgKUB+RHMkQlBN4MjCYMDC50jiMzgMiYgMBgQXMTYMziM/a4QXBgLvM+MBmcSiYIDkAXBHgQXI+cj+ciOQQABkMibIIXKAAMzmYqBDAUBkEAkRHKLQcgiBJB+bBBgZTBC5MvC4apBU4UAl53Lj4XCbYUCCYIzCC5RsBWwakCQYYXKAAUxBwMRYYUykUyC5swLwMBiESUQM/O5a/COwQYBAIIyBmAXLZ4IsBBoYABgUwBAYXHmUABogFCl4XL/8yiINESIMjNAIvLLoYWDQAYXLLoh1Ckc//7fBC5LUCC4gCBgUQBQoXFWYp1BRwIsBQAoXNn5JBNAgXHdgIAEiH/C4QAGC4kgEgsD+YHFAAYXEEY0v+QuIiMfa4gAh+cz/8z+c/AIIXQAQIVBAwQYQABI="))

29
apps/oblique/app.js Normal file
View File

@ -0,0 +1,29 @@
const strategies = ['Abandon normal instruments', 'Accept advice', 'Accretion', 'A line has two sides', 'Allow an easement (an easement is the abandonment of a stricture)', 'Are there sections? Consider transitions', 'Ask people to work against their better judgement', 'Ask your body', 'Assemble some of the instruments in a group and treat the group', 'Balance the consistency principle with the inconsistency principle', 'Be dirty', 'Breathe more deeply', 'Bridges -build -burn', 'Cascades', 'Change instrument roles', 'Change nothing and continue with immaculate consistency', "Children's voices -speaking -singing", 'Cluster analysis', 'Consider different fading systems', 'Consult other sources -promising -unpromising', 'Convert a melodic element into a rhythmic element', 'Courage!', 'Cut a vital connection', 'Decorate, decorate', "Define an area as `safe' and use it as an anchor", 'Destroy -nothing -the most important thing', 'Discard an axiom', 'Disconnect from desire', 'Discover the recipes you are using and abandon them', 'Distorting time', 'Do nothing for as long as possible', "Don't be afraid of things because they're easy to do", "Don't be frightened of cliches", "Don't be frightened to display your talents", "Don't break the silence", "Don't stress one thing more than another", 'Do something boring', 'Do the washing up', 'Do the words need changing?', 'Do we need holes?', 'Emphasize differences', 'Emphasize repetitions', 'Emphasize the flaws', 'Faced with a choice, do both (given by Dieter Rot)', 'Feedback recordings into an acoustic situation', 'Fill every beat with something', 'Get your neck massaged', 'Ghost echoes', 'Give the game away', 'Give way to your worst impulse', 'Go slowly all the way round the outside', 'Honor thy error as a hidden intention', 'How would you have done it?', 'Humanize something free of error', 'Imagine the music as a moving chain or caterpillar', 'Imagine the music as a set of disconnected events', 'Infinitesimal gradations', 'Intentions -credibility of -nobility of -humility of', 'Into the impossible', 'Is it finished?', 'Is there something missing?', 'Is the tuning appropriate?', 'Just carry on', 'Left channel, right channel, centre channel', 'Listen in total darkness, or in a very large room, very quietly', 'Listen to the quiet voice', 'Look at a very small object, look at its centre', 'Look at the order in which you do things', 'Look closely at the most embarrassing details and amplify them', 'Lowest common denominator check -single beat -single note -single', 'riff', 'Make a blank valuable by putting it in an exquisite frame', 'Make an exhaustive list of everything you might do and do the last', 'thing on the list', 'Make a sudden, destructive unpredictable action; incorporate', 'Mechanicalize something idiosyncratic', 'Mute and continue', 'Only one element of each kind', '(Organic) machinery', 'Overtly resist change', 'Put in earplugs', 'Remember those quiet evenings', 'Remove ambiguities and convert to specifics', 'Remove specifics and convert to ambiguities', 'Repetition is a form of change', 'Reverse', 'Short circuit (example: a man eating peas with the idea that they will', 'improve his virility shovels them straight into his lap)', 'Shut the door and listen from outside', 'Simple subtraction', 'Spectrum analysis', 'Take a break', 'Take away the elements in order of apparent non-importance', 'Tape your mouth (given by Ritva Saarikko)', 'The inconsistency principle', 'The tape is now the music', 'Think of the radio', 'Tidy up', 'Trust in the you of now', 'Turn it upside down', 'Twist the spine', 'Use an old idea', 'Use an unacceptable color', 'Use fewer notes', 'Use filters', 'Use "unqualified" people', 'Water', 'What are you really thinking about just now? Incorporate', 'What is the reality of the situation?', 'What mistakes did you make last time?', 'What would your closest friend do?', "What wouldn't you do?", 'Work at a different speed', 'You are an engineer', 'You can only make one dot at a time', "You don't have to be ashamed of using your own ideas", '[blank white card]']
const spentStrategies = []
function chooseObliqueness() {
const strategy = strategies[Math.floor(Math.random() * strategies.length)];
spentStrategies.push(strategy);
return strategy
}
// app intro
E.showMessage('oblique strategies\n\ncopied from\nbrian eno\n\nclick btn2');
setWatch(() => {
// beep!
Bangle.beep();
// get the strategy
const strategy = chooseObliqueness();
// configure font
g.setFontAlign(0,0);
// show the oblique strategy
E.showMessage(strategy.replace(/\s/g, '\n'));
// clear the screen
setTimeout(() => g.clear(), 10000);
}, BTN2, { repeat: true });

BIN
apps/oblique/eno.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,3 @@
0.01: New App!
0.02: Major speed improvement. Added more stars. Up to 500!
0.03: Added more stars and constellations. Now it shows 20 constellations.

View File

@ -0,0 +1,32 @@
# Planetarium
This planetarium takes your position and time and plots the sky as it is.
No planets, or moon, only stars. It can show the 500 most brilliant stars in the sky.
It shows also constellations. Now it has 20 constellations but this is work in progress. Only northern hemisphere covered now.
I think code is quite optimized already. It runs as fast as I could make it run. If someone has some ideas to speed it up, I could plot more stars.
Basic equations to compute declination and right ascension for stars where taken from this [github repo](https://github.com/Michi83/planetarium). Thanks!
## How to use
The planetarium plots the stars as if you are looking to the sky (with your watch screen pointing downwards). This means, if you have the watch in your wrist, you have to look south to see the stars matching. If you want to look north, just take out the watch from your wrist and make a 180º turn.
## Improvements
I plan to add more constellations as soon as I have time. I am adding the constellations that I know of, but the plan is to add all the main ones (at least for North Hemisphere).
Please note that the watch hardware is limited and computing the stars positions is a quite intensive task for this little processor. This is why it plots only stars and no planets or the moon. For plotting the planets, storage will be a limiting factor as well as computing the position for planets needs more initial data compared with stars.
## Do you want to contribute?
Maybe you want to add some more constellations to the planetarium. As you can see I didn't cover constellations in the south hemisphere. How to do it? It is a bit tedious but it can be done and you will learn the constellations pretty well at the end of it. Steps:
- Open the file `plantearium.data.csv`. There you have the 500 stars that we have in the planetarium. The number of each star is the line number. For instance for Sirius, the star number will be 1.
- Find the two stars that you want to join in your constellation (a constellation line). For identifying a star you have to have a look at the name, usually something like `AL UMA` (alpha star of constellation ursa major). Lets say that you want to join stars 155 and 8 (this is constellation canis menor, that only has a line joining two stars).
- Go to file `planetarium.const.csv` and add two lines for your new constellation. The first one will be the name of the constellation, the second one the pair of stars that you want to join, separated by coma (see the file for examples).
- Do not forget to add a break line after the last constellation.
- Upload the new `planetarium.const.csv` to your bangle (or emulator) and test it out.
What is a constellation star is not in the 500 star list in `planetarium.data.csv`? If you need another star to draw the constellation you can find that star in the full star list (`starinfo/planetarium.stars.csv`) and put it in `planetarium.extra.csv`. That stars will be loaded only when constellations are shown. In order to refer to these extra stars in the `planetarium.const.csv` you have to use the code `e_linenumber`, in order to differentiate them from the stars in the normal file. For instance, to refer to the first star in the file `planetarium.extra.csv`, you will refer it as `e_1`. Do not forget to add an extra line at the end as in the other files.
## Development version
Please check the latest development version [here](https://github.com/pglez82/BangleApps)

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwgkhiIAECp8BCwoABiAWVDBoWKDBgWLMZQuMGBQWNGBAuHjtBGBomHjvRGBhdI7vUMJgLGilE7vdohJHC5MUCoIADDAxGKpoWDJI5ICC44wESJS1IGAR4IJAQXgI4YXJXpAXBoJiBBhEQC5JzCigXTABgXeIBJODC5MdaA4hB6IXLpoNFEIbDFC4zRJboIXJojRC6lEBwdEegXdBIYXDZwIAEeY4ABNgQvEEgfdMIkdBIZTDC4gwELwouGC4MABoyQGHQSCEgAXHSAxSDC7pgDKQJiBL4xcBBIZeBC4cUNIUUC4oJGC4RIEAB4WCC7BgDABxGDGCYWEGCIuFGCIWGGB4uHGB4WIGBouJDBgWLDBQWNMZAVPACAA=="))

View File

@ -0,0 +1,209 @@
/*
* Degrees to radians
*/
function toRadians(degrees)
{
return Math.PI * degrees / 180;
}
/*
* Julian day number
* Assumes a proleptic gregorian calendar where the year 1 is preceded by the
* year 0.
*/
function toJulianDay(year, month, day, hours, minutes, seconds)
{
day += hours / 24 + minutes / 1440 + seconds / 86400;
if(month <= 2)
{
year -= 1;
month += 12;
}
var A = Math.floor(year / 100);
var B = 2 - A + Math.floor(A / 4);
return Math.floor(365.25 * (year + 4716)) + Math.floor(30.6001 * (month + 1)) + day + B - 1524.5;
}
/*
* Sidereal time in Greenwich
*/
function siderealTime(julianDay)
{
var T = (julianDay - 2451545.0) / 36525;
return toRadians(280.46061837 + 360.98564736629 * (julianDay - 2451545.0) + 0.000387933 * T * T - T * T * T / 38710000);
}
/*
* Draws a single star in the sky.
* starPositions is a dictionary that gets modified and it is used later for ploting the constelations
*/
function drawStar(zeta,theta,z,julianDay,latitude,longitude,starInfo,starNumber,starPositions){
let starRA = parseFloat(starInfo[0]);
let starDE = parseFloat(starInfo[1]);
let starMag = parseFloat(starInfo[2]);
var dec = Math.asin(Math.sin(theta) * Math.cos(starDE) * Math.cos(starRA + zeta) + Math.cos(theta) * Math.sin(starDE));
var ascen = Math.atan2(Math.cos(starDE) * Math.sin(starRA + zeta), Math.cos(theta) * Math.cos(starDE) * Math.cos(starRA + zeta) - Math.sin(theta) * Math.sin(starDE)) + z;
var H = siderealTime(julianDay) - longitude - ascen;
//Compute altitude
var alt = Math.asin(Math.sin(latitude) * Math.sin(dec) + Math.cos(latitude) * Math.cos(dec) * Math.cos(H));
if(alt >= 0)
{
//Compute azimuth
var azi = Math.atan2(Math.sin(H), Math.cos(H) * Math.sin(latitude) - Math.tan(dec) * Math.cos(latitude));
var x = size / 2 + size / 2 * Math.cos(alt) * Math.sin(azi);
var y = size / 2 + size / 2 * Math.cos(alt) * Math.cos(azi);
starPositions[starNumber] = [x,y];
var magnitude = starMag<1?2:1;
//Stars between 1.5 and 4 magnitude should get a different colour
var col=1;
if (starMag<=1.5)
col=1;
else if (starMag>1.5 && starMag<2)
col=0.9;
else if (starMag>=2 && starMag<3)
col=0.7;
else if (starMag>=3 && starMag<3.5)
col=0.5;
else
col=0.3;
g.setColor(col,col,col);
g.fillCircle(x, y, magnitude);
if (starMag<1 && settings.starnames)
g.drawString(starInfo[3],x,y+2);
g.flip();
}
}
function plotSky(lat,lon,date){
var longitude = toRadians(-lon);
var latitude = toRadians(lat);
var julianDay = toJulianDay(date.getFullYear(), date.getMonth()+1,date.getDate(),
date.getHours() + date.getTimezoneOffset() / 60,
date.getMinutes(), date.getSeconds());
storage = require('Storage');
f=storage.read("planetarium.data.csv","r");
g.clear();
//Common calculations based only on time
var t = (julianDay - 2451545.0) / 36525;
var zeta = toRadians((2306.2181 * t + 0.30188 * t * t + 0.017998 * t * t * t) / 3600);
var theta = toRadians((2004.3109 * t - 0.42665 * t * t - 0.041833 * t * t * t) / 3600);
var z = toRadians((2306.2181 * t + 1.09468 * t * t + 0.018203 * t * t * t) / 3600);
let starNumber = 0;
var starPositions = {};
var line,linestart = 0;
lineend = f.indexOf("\n");
while (lineend>=0) {
line = f.substring(linestart,lineend);
starNumber++;
//Process the star
starInfo = line.split(',');
drawStar(zeta,theta,z,julianDay,latitude,longitude,starInfo,starNumber,starPositions);
linestart = lineend+1;
lineend = f.indexOf("\n",linestart);
}
if (settings.constellations){
//First plot the extra stars for the constellations
fe=storage.read("planetarium.extra.csv","r");
linenum=linestart = 0;
lineend = fe.indexOf("\n");
let starNumber = 0;
while (lineend>=0) {
line = fe.substring(linestart,lineend);
starNumber++;
starInfo = line.split(',');
drawStar(zeta,theta,z,julianDay,latitude,longitude,starInfo,"e_"+starNumber,starPositions);
linestart = lineend+1;
lineend = fe.indexOf("\n",linestart);
}
//End of ploting extra stars
linenum=linestart = 0;
fc=storage.read("planetarium.const.csv","r");
lineend = fc.indexOf("\n");
while (lineend>=0) {
linenum++;
//In this file, each constelation are two lines. The first one the name, the second the lines joining stars
var name = fc.substring(linestart,lineend);
linestart = lineend+1;
lineend = fc.indexOf("\n",linestart);
var lines = fc.substring(linestart,lineend).split(',');
linestart = lineend+1;
lineend = fc.indexOf("\n",linestart);
g.setColor(0,255,0);
constelationShowing=false;
for (j=0;j<lines.length;j++){
positions = lines[j].split(' ');
positionStar1=starPositions[positions[0]];
positionStar2=starPositions[positions[1]];
//Both stars need to be visible
if (positionStar1 && positionStar2)
{
g.drawLine(positionStar1[0],positionStar1[1],positionStar2[0],positionStar2[1]);
constelationShowing=true;
}
else
constelationShowing=false;
g.flip();
}
//Write the name
if (constelationShowing && settings.consnames)
g.drawString(name,positionStar2[0]+10,positionStar2[1]);
}
}
}
const size = 240; //Bangle size screen
Bangle.setGPSPower(1);
var gps = { fix : 0};
var prevSats = 0;
g.clear();
var settings = require('Storage').readJSON('planetarium.json',1)||
{ starnames:false,constellations:true,consnames:false};
g.setFontAlign(0,0);
Bangle.on('GPS',function(gp) {
date = new Date();
gps = gp;
if (gp.fix) {
lat = gp.lat;
lon = gp.lon;
Bangle.setGPSPower(0);
setTimeout(function() {
plotSky(lat,lon,new Date());},0);
} else {
g.setFont("Vector",20);
g.drawString("Waiting for position",120,120);
g.setFont("Vector",15);
if (gp.satellites>prevSats || prevSats===0){
prevSats = gp.satellites;
g.clearRect(0,150,240,180);
g.drawString("Got "+gp.satellites+" satellites",120,160);
}
g.clearRect(0,180,240,220);
g.drawString("GMT:"+(date.getHours()+date.getTimezoneOffset() / 60)+":"+date.getMinutes()+":"+date.getSeconds(),120,200);
g.drawString(date.getDate()+'/'+date.getMonth()+1+"/"+date.getFullYear(),120,215);
g.flip();
}
});

View File

@ -0,0 +1,40 @@
Orion
7 68,10 53,53 56,28 68
Taurus
13 172,13 340,293 340,29 293,340 276
Canis Menor
155 8
Ursa Major
36 81,87 81,235 87,33 235,33 75,75 40,36 235
Cassiopeia
67 91,74 67,91 110,110 252
Gemini
23 166,16 294,294 44,166 149,230 149,16 23
Cepheus
88 218,215 292,218 292,245 88,292 245,215 218
Perseus
150 62,150 175,175 35,403 62,487 158,384 487,384 158,35 158,487 e_3,e_3 403
Cygnus
19 65,65 90,65 147,466 65,466 189,147 401,213 90
Auriga
6 42,168 6,168 113,113 29,104 29,104 42
Can Maior
1 37,22 178,37 435,435 89,1 e_18,e_18 e_19,e_19 e_20,e_20 e_18,37 277,277 22,450 488,277 488,488 47,1 488,e_21 488,22 495
Bootes
3 118,118 279,279 286,286 180,180 316,316 3
Lupus
140 210,322 140,322 410,410 98,98 234,234 210,98 302,302 362,234 e_1,234 e_2
Leo
21 291,102 270,102 291,96 63,63 241,241 96,96 102,21 241,457 270,457 167
Lyra
5 e_4,e_4 e_5,e_5 221,221 274,274 e_4
Corona Borealis
69 353,353 e_6,69 429,429 e_7,e_7 e_8,e_8 e_9
Herculis
296 135,135 477,477 203,203 296,443 203,443 408,135 127,127 380,e_10 477,464 296,265 e_10,e_10 202
Ursa Minor
50 e_11,e_11 e_14,e_14 e_13,e_13 e_12,e_12 186,186 58,58 e_13
Draco
e_15 131,131 70,70 382,382 e_15,382 187,187 423,423 e_16,e_16 207,207 122,122 e_17,e_17 232,232 342,342 452,452 428
Pegasus
92 85,138 54,54 85,138 92,283 85,283 389,160 85,92 258,258 297,297 83
1 Orion
2 7 68,10 53,53 56,28 68
3 Taurus
4 13 172,13 340,293 340,29 293,340 276
5 Canis Menor
6 155 8
7 Ursa Major
8 36 81,87 81,235 87,33 235,33 75,75 40,36 235
9 Cassiopeia
10 67 91,74 67,91 110,110 252
11 Gemini
12 23 166,16 294,294 44,166 149,230 149,16 23
13 Cepheus
14 88 218,215 292,218 292,245 88,292 245,215 218
15 Perseus
16 150 62,150 175,175 35,403 62,487 158,384 487,384 158,35 158,487 e_3,e_3 403
17 Cygnus
18 19 65,65 90,65 147,466 65,466 189,147 401,213 90
19 Auriga
20 6 42,168 6,168 113,113 29,104 29,104 42
21 Can Maior
22 1 37,22 178,37 435,435 89,1 e_18,e_18 e_19,e_19 e_20,e_20 e_18,37 277,277 22,450 488,277 488,488 47,1 488,e_21 488,22 495
23 Bootes
24 3 118,118 279,279 286,286 180,180 316,316 3
25 Lupus
26 140 210,322 140,322 410,410 98,98 234,234 210,98 302,302 362,234 e_1,234 e_2
27 Leo
28 21 291,102 270,102 291,96 63,63 241,241 96,96 102,21 241,457 270,457 167
29 Lyra
30 5 e_4,e_4 e_5,e_5 221,221 274,274 e_4
31 Corona Borealis
32 69 353,353 e_6,69 429,429 e_7,e_7 e_8,e_8 e_9
33 Herculis
34 296 135,135 477,477 203,203 296,443 203,443 408,135 127,127 380,e_10 477,464 296,265 e_10,e_10 202
35 Ursa Minor
36 50 e_11,e_11 e_14,e_14 e_13,e_13 e_12,e_12 186,186 58,58 e_13
37 Draco
38 e_15 131,131 70,70 382,382 e_15,382 187,187 423,423 e_16,e_16 207,207 122,122 e_17,e_17 232,232 342,342 452,452 428
39 Pegasus
40 92 85,138 54,54 85,138 92,283 85,283 389,160 85,92 258,258 297,297 83

View File

@ -0,0 +1,500 @@
1.768,-0.292,-1.5,Sirius
1.675,-0.920,-0.7,AL CAR
3.734,0.335,-0.0,Arcturus
3.838,-1.062,-0.0,AL1 CEN
4.874,0.677,0.0,Vega
1.382,0.803,0.1,Capella
1.372,-0.143,0.1,Rigel
2.004,0.091,0.4,Procyion
0.426,-0.999,0.5,AL ERI
1.550,0.129,0.5,Betelgeuse
3.682,-1.054,0.6,BE CEN
5.196,0.155,0.8,AL AQL
1.204,0.288,0.8,Aldebaran
4.317,-0.461,1.0,AL SCO
3.513,-0.195,1.0,AL VIR
2.030,0.489,1.1,Pollux
6.011,-0.517,1.2,AL PSA
3.350,-1.042,1.2,BE CRU
5.417,0.790,1.2,Deneb
3.838,-1.062,1.3,AL2 CEN
2.655,0.209,1.4,AL LEO
1.827,-0.506,1.5,EP CMA
1.984,0.557,1.6,Castor
3.258,-1.101,1.6,AL1 CRU
1.984,0.557,1.6,AL GEM
3.278,-0.997,1.6,GA CRU
4.597,-0.648,1.6,LA SCO
1.419,0.111,1.6,Bellatrix
1.424,0.499,1.6,BE TAU
2.414,-1.217,1.7,BE CAR
1.467,-0.021,1.7,EP ORI
5.796,-0.820,1.7,AL GRU
3.377,0.977,1.8,EP UMA
2.136,-0.826,1.8,GA2 VEL
0.892,0.870,1.8,AL PER
2.896,1.078,1.8,AL UMA
1.869,-0.461,1.8,DE CMA
4.818,-0.600,1.9,EP SGR
2.193,-1.039,1.9,EP CAR
3.611,0.861,1.9,ET UMA
4.613,-0.750,1.9,TH SCO
1.569,0.784,1.9,BE AUR
4.401,-1.205,1.9,AL TRA
1.735,0.286,1.9,GA GEM
5.348,-0.990,1.9,AL PAV
2.289,-0.955,2.0,DE VEL
1.670,-0.313,2.0,BE CMA
2.477,-0.151,2.0,AL HYA
0.555,0.409,2.0,AL ARI
0.663,1.558,2.0,Polaris
4.954,-0.459,2.0,SI SGR
0.190,-0.314,2.0,BE CET
1.487,-0.034,2.0,ZE ORI
0.037,0.508,2.1,AL AND
0.304,0.622,2.1,BE AND
1.517,-0.169,2.1,KA ORI
3.694,-0.635,2.1,TH CEN
3.886,1.294,2.1,BE UMI
4.603,0.219,2.1,AL OPH
3.258,-1.101,2.1,AL2 CRU
5.946,-0.818,2.1,BE GRU
0.821,0.715,2.1,BE PER
3.094,0.254,2.1,BE LEO
3.323,-0.855,2.2,GA CEN
5.333,0.703,2.2,GA CYG
2.391,-0.758,2.2,LA VEL
0.177,0.987,2.2,AL CAS
1.449,-0.005,2.2,DE ORI
4.078,0.466,2.2,AL CRB
4.698,0.899,2.2,GA DRA
2.110,-0.698,2.2,ZE PUP
2.431,-1.035,2.2,JO CAR
0.541,0.739,2.3,GA1 AND
0.040,1.032,2.3,BE CAS
3.508,0.959,2.3,ZE UMA
4.408,-0.599,2.3,EP SCO
3.577,-0.933,2.3,EP CEN
3.848,-0.827,2.3,AL LUP
3.820,-0.736,2.3,ET CEN
4.190,-0.395,2.3,DE SCO
2.888,0.984,2.4,BE UMA
0.115,-0.738,2.4,AL PHE
5.691,0.172,2.4,EP PEG
4.636,-0.681,2.4,KA SCO
6.038,0.490,2.4,BE PEG
4.496,-0.274,2.4,ET OPH
3.115,0.937,2.4,GA UMA
5.579,1.092,2.4,AL CEP
1.938,-0.511,2.5,ET CMA
5.438,0.593,2.5,EP CYG
0.247,1.060,2.5,GA CAS
6.042,0.265,2.5,AL PEG
2.453,-0.960,2.5,KA VEL
0.795,0.071,2.5,AL CET
3.646,-0.825,2.5,ZE CEN
2.941,0.358,2.6,DE LEO
4.351,-0.184,2.6,ZE OPH
1.452,-0.311,2.6,AL LEP
3.211,-0.306,2.6,GA CRV
3.178,-0.885,2.6,DE CEN
4.986,-0.522,2.6,ZE SGR
2.705,0.346,2.6,GA1 LEO
4.001,-0.164,2.6,BE LIB
1.570,0.649,2.6,TH AUR
4.213,-0.346,2.6,BE1 SCO
0.500,0.363,2.6,BE ARI
1.482,-0.595,2.6,AL COL
3.292,-0.408,2.6,BE CRV
4.120,0.112,2.6,AL SER
0.374,1.051,2.7,DE CAS
3.642,0.321,2.7,ET BOO
3.921,-0.753,2.7,BE LUP
1.296,0.579,2.7,JO AUR
2.822,-0.863,2.7,MY VEL
3.304,-1.207,2.7,AL MUS
4.585,-0.651,2.7,YP SCO
1.907,-0.647,2.7,PI PUP
3.861,0.473,2.7,EP BOO
4.804,-0.521,2.7,DE SGR
5.176,0.185,2.7,GA AQL
4.251,-0.064,2.7,DE OPH
4.293,1.074,2.7,ET DRA
3.493,-0.641,2.8,JO CEN
3.887,-0.280,2.8,AL2 LIB
2.805,-1.124,2.8,TH CAR
1.464,-0.103,2.8,JO ORI
4.321,0.375,2.8,BE HER
4.640,0.080,2.8,BE OPH
4.080,-0.718,2.8,GA LUP
1.343,-0.089,2.8,BE ERI
4.583,0.913,2.8,BE DRA
0.112,-1.348,2.8,BE HYI
3.208,-1.025,2.8,DE CRU
2.127,-0.424,2.8,RH PUP
4.369,0.552,2.8,ZE HER
4.834,-0.444,2.8,LA SGR
4.345,-0.492,2.8,TA SCO
0.058,0.265,2.8,GA PEG
3.413,0.191,2.8,EP VIR
1.432,-0.362,2.8,BE LEP
1.022,0.556,2.9,ZE PER
4.168,-1.107,2.9,BE TRA
4.561,-0.969,2.9,BE ARA
0.518,-1.075,2.9,AL HYI
5.840,-1.052,2.9,AL TUC
0.993,0.421,2.9,ET TAU
5.170,0.788,2.9,DE CYG
5.703,-0.281,2.9,DE CAP
1.671,0.393,2.9,MY GEM
1.038,0.698,2.9,EP PER
4.010,-1.199,2.9,GA TRA
4.184,-0.456,2.9,PI SCO
4.281,-0.447,2.9,SI SCO
5.017,-0.367,2.9,PI SGR
1.951,0.145,2.9,BE CMI
3.386,0.669,2.9,AL2 CVN
5.635,-0.097,2.9,BE AQR
0.806,0.934,2.9,GA PER
1.789,-0.883,2.9,TA PUP
5.947,0.527,2.9,ET PEG
1.039,-0.236,3.0,GA ERI
3.272,-0.288,3.0,DE CRV
4.590,-0.871,3.0,AL ARA
2.562,-1.136,3.0,YP CAR
5.785,-0.006,3.0,AL AQR
1.762,0.439,3.0,EP GEM
2.556,0.415,3.0,EP LEO
1.318,0.765,3.0,EP AUR
4.738,-0.531,3.0,GA2 SGR
4.998,0.242,3.0,ZE AQL
0.565,0.611,3.0,BE TRI
1.473,0.369,3.0,ZE TAU
3.186,-0.395,3.0,EP CRV
3.486,-0.404,3.0,GA HYA
0.973,0.834,3.0,DE PER
2.922,0.777,3.0,PS UMA
5.733,-0.652,3.0,GA GRU
1.659,-0.525,3.0,ZE CMA
1.846,-0.416,3.0,OK2 CMA
3.805,0.669,3.0,GA BOO
4.658,-0.700,3.0,JO1 SCO
0.608,-0.052,3.0,OK CET
3.620,-0.741,3.0,MY CEN
2.715,0.724,3.0,MY UMA
3.344,-1.189,3.0,BE MUS
4.017,1.254,3.0,GA UMI
5.029,1.181,3.1,DE DRA
4.415,-0.664,3.1,MY1 SCO
5.108,0.488,3.1,BE1 CYG
5.328,-0.258,3.1,BE CAP
2.336,0.104,3.1,ZE HYA
2.835,-0.283,3.1,NY HYA
4.789,-0.642,3.1,ET SGR
5.400,-0.825,3.1,AL IND
1.531,-0.624,3.1,BE COL
2.448,0.600,3.1,AL LYN
2.492,-0.995,3.1,_
3.036,-1.100,3.1,LA CEN
3.923,-0.735,3.1,KA CEN
4.445,-0.977,3.1,ZE ARA
2.353,0.838,3.1,JO UMA
4.516,0.434,3.1,DE HER
4.516,0.642,3.2,PI HER
1.337,0.720,3.2,ET AUR
1.736,-0.754,3.2,NY PUP
2.500,0.902,3.2,TH UMA
4.489,1.147,3.2,ZE DRA
4.912,-0.471,3.2,PH SGR
1.265,0.121,3.2,PI3 ORI
1.333,-0.390,3.2,EP LEP
3.851,-1.134,3.2,AL CIR
4.440,0.164,3.2,KA OPH
5.554,0.528,3.2,ZE CYG
4.668,-0.647,3.2,_
6.193,1.355,3.2,GA CEP
4.020,-0.709,3.2,DE LUP
5.285,-0.014,3.2,TH AQL
5.623,1.232,3.2,BE CEP
0.992,-1.296,3.2,GA HYI
4.269,-0.082,3.2,EP OPH
4.970,0.571,3.2,GA LYR
1.960,-0.756,3.2,SI PUP
4.805,-0.051,3.3,ET SER
0.172,0.539,3.3,DE AND
1.196,-0.961,3.3,AL DOR
1.781,-1.081,3.3,AL PIC
3.693,-0.466,3.3,PI HYA
4.547,-0.436,3.3,TH OPH
5.998,-0.276,3.3,DE AQR
1.636,0.393,3.3,ET GEM
3.945,-0.441,3.3,SI LIB
4.036,1.029,3.3,JO DRA
0.288,-0.815,3.3,BE PHE
1.365,-0.283,3.3,MY LEP
3.209,0.995,3.3,DE UMA
2.678,-1.222,3.3,OM CAR
2.758,-1.077,3.3,_
5.004,-0.483,3.3,TA SGR
4.504,-0.755,3.3,ET SCO
2.048,-0.434,3.3,XI PUP
2.942,0.269,3.3,TH LEO
4.561,-0.984,3.3,GA ARA
4.708,-0.171,3.3,NY OPH
1.110,-1.090,3.4,AL RET
5.807,1.016,3.4,ZE CEP
1.416,-0.042,3.4,ET ORI
1.768,0.225,3.4,XI GEM
2.226,1.060,3.4,OK UMA
5.085,0.054,3.4,DE AQL
3.555,-0.010,3.4,ZE VIR
4.026,-0.780,3.4,EP LUP
0.499,1.111,3.4,EP CAS
2.298,0.112,3.4,EP HYA
3.384,0.059,3.4,DE VIR
0.808,0.678,3.4,RH PER
1.172,0.277,3.4,TH2 TAU
2.693,-1.070,3.4,_
5.940,0.189,3.4,ZE PEG
0.386,-0.756,3.4,GA PHE
0.493,0.516,3.4,AL TRI
3.619,-0.728,3.4,NY CEN
3.981,-0.909,3.4,ZE LUP
4.189,-0.670,3.4,ET LUP
0.778,-0.703,3.4,TH1 ERI
4.653,0.484,3.4,MY HER
5.432,-1.155,3.4,BE PAV
5.434,1.079,3.4,ET CEP
0.214,1.009,3.4,ET CAS
2.404,-1.029,3.4,_
2.691,0.409,3.4,ZE LEO
5.001,-0.085,3.4,LA AQL
0.299,-0.178,3.5,ET CET
2.693,0.749,3.5,LA UMA
4.931,0.582,3.5,BE LYR
0.713,0.056,3.5,GA CET
1.050,0.218,3.5,LA TAU
1.840,-0.488,3.5,SI CMA
2.080,-0.925,3.5,CH CAR
3.995,0.581,3.5,DE BOO
5.231,0.340,3.5,GA SGE
2.960,0.578,3.5,NY UMA
4.514,0.251,3.5,AL1 HER
5.978,0.429,3.5,MY PEG
5.971,-0.896,3.5,EP GRU
0.454,-0.278,3.5,TA CET
3.935,0.705,3.5,BE BOO
4.830,-0.802,3.5,AL TEL
4.964,-0.368,3.5,XI2 SGR
2.166,0.160,3.5,BE CNC
2.536,0.173,3.5,OK LEO
2.650,0.293,3.5,ET LEO
5.976,1.155,3.5,JO CEP
1.172,0.335,3.5,EP TAU
1.920,0.384,3.5,DE GEM
4.143,-0.060,3.5,MY SER
4.376,0.679,3.5,ET HER
5.804,0.108,3.5,TH PEG
0.974,-0.170,3.5,DE ERI
2.604,-0.952,3.5,PH VEL
3.024,-0.556,3.5,XI HYA
4.615,-0.269,3.5,XI SER
1.514,-0.259,3.5,ZE LEP
3.750,-0.804,3.5,JO LUP
0.085,-0.154,3.6,JO CET
0.596,-0.899,3.6,PH ERI
1.125,-0.590,3.6,YP4 ERI
2.964,-0.258,3.6,DE CRT
4.022,-0.633,3.6,PH1 LUP
5.274,-1.155,3.6,DE PAV
0.428,0.849,3.6,51 AND
2.027,0.426,3.6,KA GEM
4.417,-0.664,3.6,MY2 SCO
4.804,1.269,3.6,CH DRA
5.315,-0.219,3.6,AL2 CAP
1.912,0.289,3.6,LA GEM
3.804,0.530,3.6,RH BOO
4.089,-0.491,3.6,YP LIB
3.235,-1.054,3.6,EP CRU
0.367,-0.143,3.6,TH CET
0.894,0.158,3.6,OK TAU
1.386,-0.119,3.6,TA ORI
1.503,-0.392,3.6,GA LEP
1.801,0.593,3.6,TH GEM
2.372,0.823,3.6,KA UMA
2.490,-0.706,3.6,PS VEL
2.030,-0.663,3.6,_
2.664,-0.216,3.6,LA HYA
3.101,0.031,3.6,BE VIR
0.399,0.268,3.6,ET PSC
2.270,-0.924,3.6,OK VEL
3.413,-1.249,3.6,DE MUS
4.427,-0.739,3.6,ZE2 SCO
4.586,-1.059,3.6,DE ARA
4.650,-1.130,3.6,ET PAV
6.030,0.739,3.6,OK AND
0.742,0.476,3.6,41 ARI
1.000,0.420,3.6,27 TAU
5.400,0.255,3.6,BE DEL
3.079,-1.165,3.6,LA MUS
1.134,0.273,3.6,GA TAU
3.323,-0.025,3.6,GA VIR
3.684,1.124,3.6,AL DRA
5.475,-1.020,3.6,BE IND
0.161,0.941,3.7,ZE CAS
1.462,0.173,3.7,LA ORI
4.096,-0.520,3.7,TA LIB
4.741,-0.874,3.7,TH ARA
6.063,-0.370,3.7,88 AQR
2.494,1.101,3.7,23 UMA
4.129,0.269,3.7,BE SER
2.285,-0.579,3.7,AL PYX
3.323,-0.025,3.7,GA VIR
4.048,0.508,3.7,BE CRB
5.673,-0.291,3.7,GA CAP
0.871,-0.380,3.7,TA4 ERI
1.271,0.098,3.7,PI4 ORI
2.554,-1.091,3.7,_
6.096,0.057,3.7,GA PSC
0.506,-0.901,3.7,CH ERI
0.981,0.421,3.7,17 TAU
4.703,0.510,3.7,XI HER
1.555,-0.247,3.7,ET LEP
3.081,0.834,3.7,CH UMA
4.149,0.078,3.7,EP SER
5.216,0.112,3.7,BE AQL
1.284,0.043,3.7,PI5 ORI
1.569,0.947,3.7,DE AUR
3.867,0.033,3.7,109 VIR
5.519,0.767,3.7,XI CYG
5.562,0.664,3.7,TA CYG
0.486,-0.180,3.7,ZE CET
0.929,-0.165,3.7,EP ERI
2.060,-0.708,3.7,_
4.744,0.167,3.7,72 OPH
0.904,0.170,3.7,XI TAU
5.614,-0.391,3.7,ZE CAP
5.989,-0.132,3.7,LA AQR
1.320,0.717,3.8,ZE AUR
2.374,-0.822,3.8,_
4.284,0.334,3.8,GA HER
4.660,0.047,3.8,GA OPH
4.684,0.993,3.8,XI DRA
5.887,1.020,3.8,DE CEP
0.745,0.976,3.8,ET PER
1.147,0.306,3.8,DE1 TAU
1.456,-1.091,3.8,BE DOR
4.406,-1.030,3.8,ET ARA
5.679,-1.351,3.8,NY OCT
5.790,0.442,3.8,JO PEG
0.983,0.743,3.8,NY PER
2.207,-1.154,3.8,BE VOL
4.995,-0.379,3.8,OK SGR
5.049,0.931,3.8,KA CYG
5.409,0.278,3.8,AL DEL
5.444,-0.166,3.8,EP AQR
5.896,0.878,3.8,AL LAC
1.871,-1.230,3.8,GA2 VOL
2.851,-1.027,3.8,_
1.851,0.359,3.8,ZE GEM
1.945,0.485,3.8,JO GEM
5.104,0.903,3.8,JO2 CYG
5.295,0.816,3.8,31 CYG
0.827,0.783,3.8,KA PER
2.579,1.030,3.8,YP UMA
2.705,0.346,3.8,GA2 LEO
4.079,0.184,3.8,DE SER
4.079,0.184,3.8,DE SER
4.623,0.803,3.8,JO HER
1.478,-0.045,3.8,SI ORI
1.533,-0.364,3.8,DE LEP
2.732,-0.294,3.8,MY HYA
1.202,-0.533,3.8,YP2 ERI
2.438,0.642,3.8,38 LYN
2.740,-1.025,3.8,_
4.324,0.035,3.8,LA OPH
5.181,0.323,3.8,DE SGE
6.185,0.811,3.8,LA AND
0.979,0.564,3.8,OK PER
2.851,0.597,3.8,46 LMI
3.658,-0.735,3.8,PH CEN
3.874,-1.380,3.8,AL APS
4.745,0.502,3.8,OK HER
5.184,1.226,3.8,EP DRA
1.172,0.279,3.8,TH1 TAU
2.272,-0.814,3.8,_
2.335,-1.058,3.8,_
2.781,-0.842,3.8,_
3.017,1.210,3.8,LA DRA
4.113,0.459,3.8,GA CRB
4.816,0.380,3.8,109 HER
5.854,-0.024,3.8,GA AQR
0.978,-1.131,3.8,BE RET
1.515,-0.891,3.8,BE PIC
1.667,-0.584,3.8,DE COL
1.897,-0.467,3.8,OM CMA
2.682,-0.735,3.8,_
2.761,0.162,3.8,RH LEO
4.173,0.273,3.8,GA SER
4.256,-1.112,3.8,DE TRA
4.866,-0.144,3.8,AL SCT
1.108,-0.738,3.9,AL HOR
3.306,-0.847,3.9,TA CEN
4.696,0.650,3.9,TH HER
4.772,-0.368,3.9,MY SGR
0.248,0.672,3.9,MY AND
0.838,-0.506,3.9,AL FOR
0.985,0.425,3.9,20 TAU
1.214,-0.250,3.9,53 ERI
1.445,-0.619,3.9,EP COL
1.807,-0.422,3.9,OK1 CMA
3.283,-1.259,3.9,GA MUS
3.288,1.218,3.9,KA DRA
3.659,-0.782,3.9,YP1 CEN
3.979,-0.851,3.9,KA1 LUP
0.041,-0.798,3.9,EP PHE
2.419,0.040,3.9,TH HYA
2.586,0.454,3.9,MY LEO
3.539,-0.688,3.9,_
3.853,-0.099,3.9,MY VIR
4.175,-0.510,3.9,RH SCO
0.770,-0.155,3.9,ET ERI
2.971,-0.951,3.9,PI CEN
3.228,-0.012,3.9,ET VIR
4.275,0.808,3.9,TA HER
4.335,-1.377,3.9,GA APS
5.220,0.612,3.9,ET CYG
2.206,-0.068,3.9,_
5.203,0.018,3.9,ET AQL
6.067,-0.790,3.9,JO GRU
1.061,0.105,3.9,NY TAU
2.295,-0.804,3.9,_
2.530,-0.020,3.9,JO HYA
2.917,-1.029,3.9,_
3.264,-0.877,3.9,SI CEN
4.082,-0.258,3.9,GA LIB
0.298,-0.964,3.9,ZE PHE
4.452,0.540,3.9,EP HER
5.567,0.092,3.9,AL EQU
1.206,-0.059,3.9,NY ERI
2.013,-0.167,3.9,AL MON
5.069,-0.311,3.9,RH1 SGR
0.114,-0.762,3.9,KA PHE
2.289,0.317,3.9,DE CNC
2.984,0.184,3.9,JO LEO
5.485,0.719,3.9,NY CYG
0.398,-0.856,4.0,DE PHE
0.760,0.921,4.0,TA PER
1.731,-0.336,4.0,NY2 CMA
2.015,-1.267,4.0,ZE VOL
3.508,0.959,4.0,ZE UMA
4.149,-0.587,4.0,CH LUP
5.963,0.411,4.0,LA PEG
1.152,-0.594,4.0,43 ERI
1.567,-0.747,4.0,ET COL
1.788,-0.567,4.0,KA CMA
2.024,-0.505,4.0,3 PUP
3.192,-0.914,4.0,RH CEN
4.218,-0.361,4.0,OM1 SCO
5.239,-1.273,4.0,EP PAV
1.534,0.683,4.0,NY AUR
1 1.768 -0.292 -1.5 Sirius
2 1.675 -0.920 -0.7 AL CAR
3 3.734 0.335 -0.0 Arcturus
4 3.838 -1.062 -0.0 AL1 CEN
5 4.874 0.677 0.0 Vega
6 1.382 0.803 0.1 Capella
7 1.372 -0.143 0.1 Rigel
8 2.004 0.091 0.4 Procyion
9 0.426 -0.999 0.5 AL ERI
10 1.550 0.129 0.5 Betelgeuse
11 3.682 -1.054 0.6 BE CEN
12 5.196 0.155 0.8 AL AQL
13 1.204 0.288 0.8 Aldebaran
14 4.317 -0.461 1.0 AL SCO
15 3.513 -0.195 1.0 AL VIR
16 2.030 0.489 1.1 Pollux
17 6.011 -0.517 1.2 AL PSA
18 3.350 -1.042 1.2 BE CRU
19 5.417 0.790 1.2 Deneb
20 3.838 -1.062 1.3 AL2 CEN
21 2.655 0.209 1.4 AL LEO
22 1.827 -0.506 1.5 EP CMA
23 1.984 0.557 1.6 Castor
24 3.258 -1.101 1.6 AL1 CRU
25 1.984 0.557 1.6 AL GEM
26 3.278 -0.997 1.6 GA CRU
27 4.597 -0.648 1.6 LA SCO
28 1.419 0.111 1.6 Bellatrix
29 1.424 0.499 1.6 BE TAU
30 2.414 -1.217 1.7 BE CAR
31 1.467 -0.021 1.7 EP ORI
32 5.796 -0.820 1.7 AL GRU
33 3.377 0.977 1.8 EP UMA
34 2.136 -0.826 1.8 GA2 VEL
35 0.892 0.870 1.8 AL PER
36 2.896 1.078 1.8 AL UMA
37 1.869 -0.461 1.8 DE CMA
38 4.818 -0.600 1.9 EP SGR
39 2.193 -1.039 1.9 EP CAR
40 3.611 0.861 1.9 ET UMA
41 4.613 -0.750 1.9 TH SCO
42 1.569 0.784 1.9 BE AUR
43 4.401 -1.205 1.9 AL TRA
44 1.735 0.286 1.9 GA GEM
45 5.348 -0.990 1.9 AL PAV
46 2.289 -0.955 2.0 DE VEL
47 1.670 -0.313 2.0 BE CMA
48 2.477 -0.151 2.0 AL HYA
49 0.555 0.409 2.0 AL ARI
50 0.663 1.558 2.0 Polaris
51 4.954 -0.459 2.0 SI SGR
52 0.190 -0.314 2.0 BE CET
53 1.487 -0.034 2.0 ZE ORI
54 0.037 0.508 2.1 AL AND
55 0.304 0.622 2.1 BE AND
56 1.517 -0.169 2.1 KA ORI
57 3.694 -0.635 2.1 TH CEN
58 3.886 1.294 2.1 BE UMI
59 4.603 0.219 2.1 AL OPH
60 3.258 -1.101 2.1 AL2 CRU
61 5.946 -0.818 2.1 BE GRU
62 0.821 0.715 2.1 BE PER
63 3.094 0.254 2.1 BE LEO
64 3.323 -0.855 2.2 GA CEN
65 5.333 0.703 2.2 GA CYG
66 2.391 -0.758 2.2 LA VEL
67 0.177 0.987 2.2 AL CAS
68 1.449 -0.005 2.2 DE ORI
69 4.078 0.466 2.2 AL CRB
70 4.698 0.899 2.2 GA DRA
71 2.110 -0.698 2.2 ZE PUP
72 2.431 -1.035 2.2 JO CAR
73 0.541 0.739 2.3 GA1 AND
74 0.040 1.032 2.3 BE CAS
75 3.508 0.959 2.3 ZE UMA
76 4.408 -0.599 2.3 EP SCO
77 3.577 -0.933 2.3 EP CEN
78 3.848 -0.827 2.3 AL LUP
79 3.820 -0.736 2.3 ET CEN
80 4.190 -0.395 2.3 DE SCO
81 2.888 0.984 2.4 BE UMA
82 0.115 -0.738 2.4 AL PHE
83 5.691 0.172 2.4 EP PEG
84 4.636 -0.681 2.4 KA SCO
85 6.038 0.490 2.4 BE PEG
86 4.496 -0.274 2.4 ET OPH
87 3.115 0.937 2.4 GA UMA
88 5.579 1.092 2.4 AL CEP
89 1.938 -0.511 2.5 ET CMA
90 5.438 0.593 2.5 EP CYG
91 0.247 1.060 2.5 GA CAS
92 6.042 0.265 2.5 AL PEG
93 2.453 -0.960 2.5 KA VEL
94 0.795 0.071 2.5 AL CET
95 3.646 -0.825 2.5 ZE CEN
96 2.941 0.358 2.6 DE LEO
97 4.351 -0.184 2.6 ZE OPH
98 1.452 -0.311 2.6 AL LEP
99 3.211 -0.306 2.6 GA CRV
100 3.178 -0.885 2.6 DE CEN
101 4.986 -0.522 2.6 ZE SGR
102 2.705 0.346 2.6 GA1 LEO
103 4.001 -0.164 2.6 BE LIB
104 1.570 0.649 2.6 TH AUR
105 4.213 -0.346 2.6 BE1 SCO
106 0.500 0.363 2.6 BE ARI
107 1.482 -0.595 2.6 AL COL
108 3.292 -0.408 2.6 BE CRV
109 4.120 0.112 2.6 AL SER
110 0.374 1.051 2.7 DE CAS
111 3.642 0.321 2.7 ET BOO
112 3.921 -0.753 2.7 BE LUP
113 1.296 0.579 2.7 JO AUR
114 2.822 -0.863 2.7 MY VEL
115 3.304 -1.207 2.7 AL MUS
116 4.585 -0.651 2.7 YP SCO
117 1.907 -0.647 2.7 PI PUP
118 3.861 0.473 2.7 EP BOO
119 4.804 -0.521 2.7 DE SGR
120 5.176 0.185 2.7 GA AQL
121 4.251 -0.064 2.7 DE OPH
122 4.293 1.074 2.7 ET DRA
123 3.493 -0.641 2.8 JO CEN
124 3.887 -0.280 2.8 AL2 LIB
125 2.805 -1.124 2.8 TH CAR
126 1.464 -0.103 2.8 JO ORI
127 4.321 0.375 2.8 BE HER
128 4.640 0.080 2.8 BE OPH
129 4.080 -0.718 2.8 GA LUP
130 1.343 -0.089 2.8 BE ERI
131 4.583 0.913 2.8 BE DRA
132 0.112 -1.348 2.8 BE HYI
133 3.208 -1.025 2.8 DE CRU
134 2.127 -0.424 2.8 RH PUP
135 4.369 0.552 2.8 ZE HER
136 4.834 -0.444 2.8 LA SGR
137 4.345 -0.492 2.8 TA SCO
138 0.058 0.265 2.8 GA PEG
139 3.413 0.191 2.8 EP VIR
140 1.432 -0.362 2.8 BE LEP
141 1.022 0.556 2.9 ZE PER
142 4.168 -1.107 2.9 BE TRA
143 4.561 -0.969 2.9 BE ARA
144 0.518 -1.075 2.9 AL HYI
145 5.840 -1.052 2.9 AL TUC
146 0.993 0.421 2.9 ET TAU
147 5.170 0.788 2.9 DE CYG
148 5.703 -0.281 2.9 DE CAP
149 1.671 0.393 2.9 MY GEM
150 1.038 0.698 2.9 EP PER
151 4.010 -1.199 2.9 GA TRA
152 4.184 -0.456 2.9 PI SCO
153 4.281 -0.447 2.9 SI SCO
154 5.017 -0.367 2.9 PI SGR
155 1.951 0.145 2.9 BE CMI
156 3.386 0.669 2.9 AL2 CVN
157 5.635 -0.097 2.9 BE AQR
158 0.806 0.934 2.9 GA PER
159 1.789 -0.883 2.9 TA PUP
160 5.947 0.527 2.9 ET PEG
161 1.039 -0.236 3.0 GA ERI
162 3.272 -0.288 3.0 DE CRV
163 4.590 -0.871 3.0 AL ARA
164 2.562 -1.136 3.0 YP CAR
165 5.785 -0.006 3.0 AL AQR
166 1.762 0.439 3.0 EP GEM
167 2.556 0.415 3.0 EP LEO
168 1.318 0.765 3.0 EP AUR
169 4.738 -0.531 3.0 GA2 SGR
170 4.998 0.242 3.0 ZE AQL
171 0.565 0.611 3.0 BE TRI
172 1.473 0.369 3.0 ZE TAU
173 3.186 -0.395 3.0 EP CRV
174 3.486 -0.404 3.0 GA HYA
175 0.973 0.834 3.0 DE PER
176 2.922 0.777 3.0 PS UMA
177 5.733 -0.652 3.0 GA GRU
178 1.659 -0.525 3.0 ZE CMA
179 1.846 -0.416 3.0 OK2 CMA
180 3.805 0.669 3.0 GA BOO
181 4.658 -0.700 3.0 JO1 SCO
182 0.608 -0.052 3.0 OK CET
183 3.620 -0.741 3.0 MY CEN
184 2.715 0.724 3.0 MY UMA
185 3.344 -1.189 3.0 BE MUS
186 4.017 1.254 3.0 GA UMI
187 5.029 1.181 3.1 DE DRA
188 4.415 -0.664 3.1 MY1 SCO
189 5.108 0.488 3.1 BE1 CYG
190 5.328 -0.258 3.1 BE CAP
191 2.336 0.104 3.1 ZE HYA
192 2.835 -0.283 3.1 NY HYA
193 4.789 -0.642 3.1 ET SGR
194 5.400 -0.825 3.1 AL IND
195 1.531 -0.624 3.1 BE COL
196 2.448 0.600 3.1 AL LYN
197 2.492 -0.995 3.1 _
198 3.036 -1.100 3.1 LA CEN
199 3.923 -0.735 3.1 KA CEN
200 4.445 -0.977 3.1 ZE ARA
201 2.353 0.838 3.1 JO UMA
202 4.516 0.434 3.1 DE HER
203 4.516 0.642 3.2 PI HER
204 1.337 0.720 3.2 ET AUR
205 1.736 -0.754 3.2 NY PUP
206 2.500 0.902 3.2 TH UMA
207 4.489 1.147 3.2 ZE DRA
208 4.912 -0.471 3.2 PH SGR
209 1.265 0.121 3.2 PI3 ORI
210 1.333 -0.390 3.2 EP LEP
211 3.851 -1.134 3.2 AL CIR
212 4.440 0.164 3.2 KA OPH
213 5.554 0.528 3.2 ZE CYG
214 4.668 -0.647 3.2 _
215 6.193 1.355 3.2 GA CEP
216 4.020 -0.709 3.2 DE LUP
217 5.285 -0.014 3.2 TH AQL
218 5.623 1.232 3.2 BE CEP
219 0.992 -1.296 3.2 GA HYI
220 4.269 -0.082 3.2 EP OPH
221 4.970 0.571 3.2 GA LYR
222 1.960 -0.756 3.2 SI PUP
223 4.805 -0.051 3.3 ET SER
224 0.172 0.539 3.3 DE AND
225 1.196 -0.961 3.3 AL DOR
226 1.781 -1.081 3.3 AL PIC
227 3.693 -0.466 3.3 PI HYA
228 4.547 -0.436 3.3 TH OPH
229 5.998 -0.276 3.3 DE AQR
230 1.636 0.393 3.3 ET GEM
231 3.945 -0.441 3.3 SI LIB
232 4.036 1.029 3.3 JO DRA
233 0.288 -0.815 3.3 BE PHE
234 1.365 -0.283 3.3 MY LEP
235 3.209 0.995 3.3 DE UMA
236 2.678 -1.222 3.3 OM CAR
237 2.758 -1.077 3.3 _
238 5.004 -0.483 3.3 TA SGR
239 4.504 -0.755 3.3 ET SCO
240 2.048 -0.434 3.3 XI PUP
241 2.942 0.269 3.3 TH LEO
242 4.561 -0.984 3.3 GA ARA
243 4.708 -0.171 3.3 NY OPH
244 1.110 -1.090 3.4 AL RET
245 5.807 1.016 3.4 ZE CEP
246 1.416 -0.042 3.4 ET ORI
247 1.768 0.225 3.4 XI GEM
248 2.226 1.060 3.4 OK UMA
249 5.085 0.054 3.4 DE AQL
250 3.555 -0.010 3.4 ZE VIR
251 4.026 -0.780 3.4 EP LUP
252 0.499 1.111 3.4 EP CAS
253 2.298 0.112 3.4 EP HYA
254 3.384 0.059 3.4 DE VIR
255 0.808 0.678 3.4 RH PER
256 1.172 0.277 3.4 TH2 TAU
257 2.693 -1.070 3.4 _
258 5.940 0.189 3.4 ZE PEG
259 0.386 -0.756 3.4 GA PHE
260 0.493 0.516 3.4 AL TRI
261 3.619 -0.728 3.4 NY CEN
262 3.981 -0.909 3.4 ZE LUP
263 4.189 -0.670 3.4 ET LUP
264 0.778 -0.703 3.4 TH1 ERI
265 4.653 0.484 3.4 MY HER
266 5.432 -1.155 3.4 BE PAV
267 5.434 1.079 3.4 ET CEP
268 0.214 1.009 3.4 ET CAS
269 2.404 -1.029 3.4 _
270 2.691 0.409 3.4 ZE LEO
271 5.001 -0.085 3.4 LA AQL
272 0.299 -0.178 3.5 ET CET
273 2.693 0.749 3.5 LA UMA
274 4.931 0.582 3.5 BE LYR
275 0.713 0.056 3.5 GA CET
276 1.050 0.218 3.5 LA TAU
277 1.840 -0.488 3.5 SI CMA
278 2.080 -0.925 3.5 CH CAR
279 3.995 0.581 3.5 DE BOO
280 5.231 0.340 3.5 GA SGE
281 2.960 0.578 3.5 NY UMA
282 4.514 0.251 3.5 AL1 HER
283 5.978 0.429 3.5 MY PEG
284 5.971 -0.896 3.5 EP GRU
285 0.454 -0.278 3.5 TA CET
286 3.935 0.705 3.5 BE BOO
287 4.830 -0.802 3.5 AL TEL
288 4.964 -0.368 3.5 XI2 SGR
289 2.166 0.160 3.5 BE CNC
290 2.536 0.173 3.5 OK LEO
291 2.650 0.293 3.5 ET LEO
292 5.976 1.155 3.5 JO CEP
293 1.172 0.335 3.5 EP TAU
294 1.920 0.384 3.5 DE GEM
295 4.143 -0.060 3.5 MY SER
296 4.376 0.679 3.5 ET HER
297 5.804 0.108 3.5 TH PEG
298 0.974 -0.170 3.5 DE ERI
299 2.604 -0.952 3.5 PH VEL
300 3.024 -0.556 3.5 XI HYA
301 4.615 -0.269 3.5 XI SER
302 1.514 -0.259 3.5 ZE LEP
303 3.750 -0.804 3.5 JO LUP
304 0.085 -0.154 3.6 JO CET
305 0.596 -0.899 3.6 PH ERI
306 1.125 -0.590 3.6 YP4 ERI
307 2.964 -0.258 3.6 DE CRT
308 4.022 -0.633 3.6 PH1 LUP
309 5.274 -1.155 3.6 DE PAV
310 0.428 0.849 3.6 51 AND
311 2.027 0.426 3.6 KA GEM
312 4.417 -0.664 3.6 MY2 SCO
313 4.804 1.269 3.6 CH DRA
314 5.315 -0.219 3.6 AL2 CAP
315 1.912 0.289 3.6 LA GEM
316 3.804 0.530 3.6 RH BOO
317 4.089 -0.491 3.6 YP LIB
318 3.235 -1.054 3.6 EP CRU
319 0.367 -0.143 3.6 TH CET
320 0.894 0.158 3.6 OK TAU
321 1.386 -0.119 3.6 TA ORI
322 1.503 -0.392 3.6 GA LEP
323 1.801 0.593 3.6 TH GEM
324 2.372 0.823 3.6 KA UMA
325 2.490 -0.706 3.6 PS VEL
326 2.030 -0.663 3.6 _
327 2.664 -0.216 3.6 LA HYA
328 3.101 0.031 3.6 BE VIR
329 0.399 0.268 3.6 ET PSC
330 2.270 -0.924 3.6 OK VEL
331 3.413 -1.249 3.6 DE MUS
332 4.427 -0.739 3.6 ZE2 SCO
333 4.586 -1.059 3.6 DE ARA
334 4.650 -1.130 3.6 ET PAV
335 6.030 0.739 3.6 OK AND
336 0.742 0.476 3.6 41 ARI
337 1.000 0.420 3.6 27 TAU
338 5.400 0.255 3.6 BE DEL
339 3.079 -1.165 3.6 LA MUS
340 1.134 0.273 3.6 GA TAU
341 3.323 -0.025 3.6 GA VIR
342 3.684 1.124 3.6 AL DRA
343 5.475 -1.020 3.6 BE IND
344 0.161 0.941 3.7 ZE CAS
345 1.462 0.173 3.7 LA ORI
346 4.096 -0.520 3.7 TA LIB
347 4.741 -0.874 3.7 TH ARA
348 6.063 -0.370 3.7 88 AQR
349 2.494 1.101 3.7 23 UMA
350 4.129 0.269 3.7 BE SER
351 2.285 -0.579 3.7 AL PYX
352 3.323 -0.025 3.7 GA VIR
353 4.048 0.508 3.7 BE CRB
354 5.673 -0.291 3.7 GA CAP
355 0.871 -0.380 3.7 TA4 ERI
356 1.271 0.098 3.7 PI4 ORI
357 2.554 -1.091 3.7 _
358 6.096 0.057 3.7 GA PSC
359 0.506 -0.901 3.7 CH ERI
360 0.981 0.421 3.7 17 TAU
361 4.703 0.510 3.7 XI HER
362 1.555 -0.247 3.7 ET LEP
363 3.081 0.834 3.7 CH UMA
364 4.149 0.078 3.7 EP SER
365 5.216 0.112 3.7 BE AQL
366 1.284 0.043 3.7 PI5 ORI
367 1.569 0.947 3.7 DE AUR
368 3.867 0.033 3.7 109 VIR
369 5.519 0.767 3.7 XI CYG
370 5.562 0.664 3.7 TA CYG
371 0.486 -0.180 3.7 ZE CET
372 0.929 -0.165 3.7 EP ERI
373 2.060 -0.708 3.7 _
374 4.744 0.167 3.7 72 OPH
375 0.904 0.170 3.7 XI TAU
376 5.614 -0.391 3.7 ZE CAP
377 5.989 -0.132 3.7 LA AQR
378 1.320 0.717 3.8 ZE AUR
379 2.374 -0.822 3.8 _
380 4.284 0.334 3.8 GA HER
381 4.660 0.047 3.8 GA OPH
382 4.684 0.993 3.8 XI DRA
383 5.887 1.020 3.8 DE CEP
384 0.745 0.976 3.8 ET PER
385 1.147 0.306 3.8 DE1 TAU
386 1.456 -1.091 3.8 BE DOR
387 4.406 -1.030 3.8 ET ARA
388 5.679 -1.351 3.8 NY OCT
389 5.790 0.442 3.8 JO PEG
390 0.983 0.743 3.8 NY PER
391 2.207 -1.154 3.8 BE VOL
392 4.995 -0.379 3.8 OK SGR
393 5.049 0.931 3.8 KA CYG
394 5.409 0.278 3.8 AL DEL
395 5.444 -0.166 3.8 EP AQR
396 5.896 0.878 3.8 AL LAC
397 1.871 -1.230 3.8 GA2 VOL
398 2.851 -1.027 3.8 _
399 1.851 0.359 3.8 ZE GEM
400 1.945 0.485 3.8 JO GEM
401 5.104 0.903 3.8 JO2 CYG
402 5.295 0.816 3.8 31 CYG
403 0.827 0.783 3.8 KA PER
404 2.579 1.030 3.8 YP UMA
405 2.705 0.346 3.8 GA2 LEO
406 4.079 0.184 3.8 DE SER
407 4.079 0.184 3.8 DE SER
408 4.623 0.803 3.8 JO HER
409 1.478 -0.045 3.8 SI ORI
410 1.533 -0.364 3.8 DE LEP
411 2.732 -0.294 3.8 MY HYA
412 1.202 -0.533 3.8 YP2 ERI
413 2.438 0.642 3.8 38 LYN
414 2.740 -1.025 3.8 _
415 4.324 0.035 3.8 LA OPH
416 5.181 0.323 3.8 DE SGE
417 6.185 0.811 3.8 LA AND
418 0.979 0.564 3.8 OK PER
419 2.851 0.597 3.8 46 LMI
420 3.658 -0.735 3.8 PH CEN
421 3.874 -1.380 3.8 AL APS
422 4.745 0.502 3.8 OK HER
423 5.184 1.226 3.8 EP DRA
424 1.172 0.279 3.8 TH1 TAU
425 2.272 -0.814 3.8 _
426 2.335 -1.058 3.8 _
427 2.781 -0.842 3.8 _
428 3.017 1.210 3.8 LA DRA
429 4.113 0.459 3.8 GA CRB
430 4.816 0.380 3.8 109 HER
431 5.854 -0.024 3.8 GA AQR
432 0.978 -1.131 3.8 BE RET
433 1.515 -0.891 3.8 BE PIC
434 1.667 -0.584 3.8 DE COL
435 1.897 -0.467 3.8 OM CMA
436 2.682 -0.735 3.8 _
437 2.761 0.162 3.8 RH LEO
438 4.173 0.273 3.8 GA SER
439 4.256 -1.112 3.8 DE TRA
440 4.866 -0.144 3.8 AL SCT
441 1.108 -0.738 3.9 AL HOR
442 3.306 -0.847 3.9 TA CEN
443 4.696 0.650 3.9 TH HER
444 4.772 -0.368 3.9 MY SGR
445 0.248 0.672 3.9 MY AND
446 0.838 -0.506 3.9 AL FOR
447 0.985 0.425 3.9 20 TAU
448 1.214 -0.250 3.9 53 ERI
449 1.445 -0.619 3.9 EP COL
450 1.807 -0.422 3.9 OK1 CMA
451 3.283 -1.259 3.9 GA MUS
452 3.288 1.218 3.9 KA DRA
453 3.659 -0.782 3.9 YP1 CEN
454 3.979 -0.851 3.9 KA1 LUP
455 0.041 -0.798 3.9 EP PHE
456 2.419 0.040 3.9 TH HYA
457 2.586 0.454 3.9 MY LEO
458 3.539 -0.688 3.9 _
459 3.853 -0.099 3.9 MY VIR
460 4.175 -0.510 3.9 RH SCO
461 0.770 -0.155 3.9 ET ERI
462 2.971 -0.951 3.9 PI CEN
463 3.228 -0.012 3.9 ET VIR
464 4.275 0.808 3.9 TA HER
465 4.335 -1.377 3.9 GA APS
466 5.220 0.612 3.9 ET CYG
467 2.206 -0.068 3.9 _
468 5.203 0.018 3.9 ET AQL
469 6.067 -0.790 3.9 JO GRU
470 1.061 0.105 3.9 NY TAU
471 2.295 -0.804 3.9 _
472 2.530 -0.020 3.9 JO HYA
473 2.917 -1.029 3.9 _
474 3.264 -0.877 3.9 SI CEN
475 4.082 -0.258 3.9 GA LIB
476 0.298 -0.964 3.9 ZE PHE
477 4.452 0.540 3.9 EP HER
478 5.567 0.092 3.9 AL EQU
479 1.206 -0.059 3.9 NY ERI
480 2.013 -0.167 3.9 AL MON
481 5.069 -0.311 3.9 RH1 SGR
482 0.114 -0.762 3.9 KA PHE
483 2.289 0.317 3.9 DE CNC
484 2.984 0.184 3.9 JO LEO
485 5.485 0.719 3.9 NY CYG
486 0.398 -0.856 4.0 DE PHE
487 0.760 0.921 4.0 TA PER
488 1.731 -0.336 4.0 NY2 CMA
489 2.015 -1.267 4.0 ZE VOL
490 3.508 0.959 4.0 ZE UMA
491 4.149 -0.587 4.0 CH LUP
492 5.963 0.411 4.0 LA PEG
493 1.152 -0.594 4.0 43 ERI
494 1.567 -0.747 4.0 ET COL
495 1.788 -0.567 4.0 KA CMA
496 2.024 -0.505 4.0 3 PUP
497 3.192 -0.914 4.0 RH CEN
498 4.218 -0.361 4.0 OM1 SCO
499 5.239 -1.273 4.0 EP PAV
500 1.534 0.683 4.0 NY AUR

View File

@ -0,0 +1,21 @@
1.394,-0.230,4.3,LA LEP
1.367,-0.226,4.4,KA LEP
0.825,0.866,4.0,JO PER
4.950,0.644,4.3,DE2 LYR
5.046,0.666,4.4,TH LYR
4.071,0.547,4.1,TH CRB
4.143,0.455,4.6,DE CRB
4.178,0.469,4.2,EP CRB
4.195,0.521,5.0,JO CRB
4.585,0.456,4.4,LA HER
4.591,1.511,4.4,DE UMI
4.265,1.322,5.0,ET UMI
4.119,1.358,4.3,ZE UMI
4.389,1.432,4.2,EP UMI
4.591,0.963,4.9,NY2 DRA
5.042,1.280,4.5,TA DRA
4.197,1.022,4.0,TH DRA
1.816,-0.298,4.4,JO CMA
1.849,-0.273,4.1,GA CMA
1.807,-0.210,4.1,TH CMA
1.724,-0.401,4.5,XI2 CMA
1 1.394 -0.230 4.3 LA LEP
2 1.367 -0.226 4.4 KA LEP
3 0.825 0.866 4.0 JO PER
4 4.950 0.644 4.3 DE2 LYR
5 5.046 0.666 4.4 TH LYR
6 4.071 0.547 4.1 TH CRB
7 4.143 0.455 4.6 DE CRB
8 4.178 0.469 4.2 EP CRB
9 4.195 0.521 5.0 JO CRB
10 4.585 0.456 4.4 LA HER
11 4.591 1.511 4.4 DE UMI
12 4.265 1.322 5.0 ET UMI
13 4.119 1.358 4.3 ZE UMI
14 4.389 1.432 4.2 EP UMI
15 4.591 0.963 4.9 NY2 DRA
16 5.042 1.280 4.5 TA DRA
17 4.197 1.022 4.0 TH DRA
18 1.816 -0.298 4.4 JO CMA
19 1.849 -0.273 4.1 GA CMA
20 1.807 -0.210 4.1 TH CMA
21 1.724 -0.401 4.5 XI2 CMA

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,31 @@
// make sure to enclose the function in parentheses
(function(back) {
let settings = require('Storage').readJSON('planetarium.json',1)||{"starnames":false,"constellations":true,"consnames":false};
function save(key, value) {
settings[key] = value;
require('Storage').write('planetarium.json',settings);
}
const appMenu = {
'': {'title': 'Planetarium Settings'},
'< Back': back,
'Star names': {
value: !!settings.starnames,
format: v =>v?'On':'Off',
onchange: v => {
save('starnames',v);
}},
'Constellations': {
value: !!settings.constellations,
format: v =>v?'On':'Off',
onchange: v => {
save('constellations',v);
}},
'Const. names': {
value: !!settings.consnames,
format: v =>v?'On':'Off',
onchange: v => {
save('consnames',v);
}},
};
E.showMenu(appMenu)
})

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
'''
* This information is from the Yale Bright Star Catalog. First number is the RA (Right ascension) in radians. Careful because in all
* the catalogs this is in Hour angle. We have to convert it to degrees and then to radians.
* The second number is the DE (declination) in radians. In this case in the catalogs is in degrees, just convert to radians.
* Third number is the aparent magnitude
'''
import csv
import math
with open('starsoriginal.csv') as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
for row in csv_reader:
data_read = [row for row in csv_reader]
stars=[]
for row in data_read:
hours = float(row[0])
min = float(row[1])
seg = float(row[2])
rahours = hours+(min+seg/60)/60
radegress = rahours*360/24
radradians = math.radians(radegress)
deg = float(row[3])
dem = float(row[4])
des = float(row[5])
if (deg<0):
desex = deg-(dem+des/60)/60
else:
desex = deg+(dem+des/60)/60
derad = math.radians(desex)
stars.append(['{:.3f}'.format(radradians),'{:.3f}'.format(derad),'{:.1f}'.format(float(row[6])),row[7].strip()])
with open("planetarium.stars.csv", "wt") as fp:
writer = csv.writer(fp, delimiter=",")
# writer.writerow(["your", "header", "foo"]) # write header
writer.writerows(stars)

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,4 @@
0.01: First published version of app
0.02: Added support for locale and 12H clock
0.03: Added HR indication to clock
0.04: Update font size and alignment

View File

@ -23,31 +23,29 @@
// Ssettings
const settings = {
time: {
color: '#f0af00',
shadow: '#CF7500',
color: 0xD6ED17,
font: 'Vector',
size: 60,
middle: screen.middle - 30,
middle: screen.middle,
center: screen.center,
},
date: {
color: '#f0af00',
shadow: '#CF7500',
color: 0xD6ED17,
font: 'Vector',
size: 15,
middle: screen.height - 20, // at bottom of screen
middle: screen.height-17, // at bottom of screen
center: screen.center,
},
circle: {
colormin: '#eeeeee',
colorsec: '#bbbbbb',
colormin: 0x606060,
colorsec: 0x656565,
width: 10,
middle: screen.middle,
center: screen.center,
height: screen.height
},
hr: {
color: '#333333',
color: 0x333333,
size: 10,
x: screen.center,
y: screen.middle + 45

View File

@ -5,4 +5,4 @@
0.05: Add setting to turn vibrate on/off.
0.06: Tweaks to vibration settings.
0.07: Switch to BTN1 for Max toggle and reset function.
1.00 : New features. Added waypoints file and distance to selected waypoint display. Added integration with Low Power GPS service. Save display settings and restore when app restarted.
1.00: New features. Added waypoints file and distance to selected waypoint display. Added integration with GPS Setup module to switch GPS to low power mode when screen off. Save display settings and restore when app restarted.

View File

@ -1,66 +0,0 @@
[
{
"name":"NONE"
},
{
"name":"Omori",
"lat":-38.9058670,
"lon":175.7613350
},
{
"name":"DeltaW",
"lat":-38.9438550,
"lon":175.7676930
},
{
"name":"DeltaE",
"lat":-38.9395240,
"lon":175.7814420
},
{
"name":"BtClub",
"lat":-38.9446020,
"lon":175.8475720
},
{
"name":"Hapua",
"lat":-38.8177750,
"lon":175.8088720
},
{
"name":"MotuTa",
"lat":-38.85454,
"lon":175.94199
},
{
"name":"Nook",
"lat":-38.7848090,
"lon":175.7839440
},
{
"name":"ChryBy",
"lat":-38.7975050,
"lon":175.7551960
},
{
"name":"Waiha",
"lat":-38.7219630,
"lon":175.7481520
},
{
"name":"KwaKwa",
"lat":-38.6632310,
"lon":175.8670320
},
{
"name":"Hatepe",
"lat":-38.8547420,
"lon":176.0089124
},
{
"name":"Kinloc",
"lat":-38.6614442,
"lon":175.9161607
}
]

View File

@ -0,0 +1,2 @@
0.01: Initial version
0.02: Fixed issues with entry in apps.json

View File

@ -0,0 +1,17 @@
# The Tape App Launcher
Reminiscent of a Telegram or Turing machine tape.
![](screenshot.jpg)
## Controls
**BTN1** - move backward to the previous app icon
**BTN2** - run the selected app
**BTN3** - move forward to the next app icon
**Swipe Left** - move forward to the next app icon
**Swipe Right** - move backwards (to the left) to the previous app

79
apps/tapelauncher/app.js Normal file
View File

@ -0,0 +1,79 @@
/*
* Tape Launcher
*
*/
var s = require("Storage");
var apps = s.list(/\.info$/).map(app=>{var a=s.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src};}).filter(app=>app && (app.type=="app" || app.type=="clock" || !app.type));
apps.sort((a,b)=>{
var n=(0|a.sortorder)-(0|b.sortorder);
if (n) return n; // do sortorder first
if (a.name<b.name) return -1;
if (a.name>b.name) return 1;
return 0;
});
var Napps = apps.length;
var selected = 1; // assumes we have at least 2 apps
function draw_icon(pos, id, select) {
var x = ((pos % 3)*80) + 2;
var y = 80;
g.setColor(-1);
g.drawImage(s.read(apps[id].icon),x+2,y+11,{scale:1.625});
if (select) {
g.setColor(1,1,1).drawRect(x,y,x+79,y+99); // white bounding box
}
}
function draw() {
g.setColor(0,0,0).fillRect(0,0,239,239);
if (selected -1 > -1)
draw_icon(0, selected -1, false);
draw_icon(1, selected, true);
if (selected + 1 < Napps)
draw_icon(2, selected + 1, false);
g.setColor(-1).setFontAlign(0,-1,0).setFont("6x8",3);
if (apps[selected].name.length <= 12) {
g.drawString(apps[selected].name, 120, 40, true);
} else {
// some app names are too long for one line
var name = apps[selected].name;
var first = name.substring(0, name.indexOf(" "));
var last = name.substring(name.indexOf(" ") + 1, name.length);
g.drawString(first, 120, 40, true);
g.drawString(last, 120, 200, true);
}
}
Bangle.on("swipe",(dir)=>{
(dir<0) ? nextapp(1) : nextapp(-1);
});
function nextapp(dir){
selected += dir;
if (selected > Napps - 1) {
selected = Napps - 1;
} else if (selected < 0) {
selected = 0;
}
draw();
}
function doselect(){
load(apps[selected].src);
}
setWatch(nextapp.bind(null,-1), BTN1, {repeat:true,edge:"falling"});
setWatch(doselect, BTN2, {repeat:true,edge:"falling"});
setWatch(nextapp.bind(null,1), BTN3, {repeat:true,edge:"falling"});
draw();

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("AH4A/ACXd7vQC6vUpoBBDaQXEDaQXIDZwXMAIQZHC4R6BAAIZJDAwXIDY4XHAAodJ7oXMDpQXSAAiRHhoWN7zFLDY/e9ve9zeMhvQCIIBFC5ARIC5oVNC5EOCpwABC4vuCZYXPCIwXOCJAAFC5gAJ8AXFCpwuHgDjCFqQXC6lN6gbFf5gXEAInd6AXVDYndhoXKBoIbMC5QZLC44AFDpIXNDpQXdhoYMAAbwIC6oZQbxhOKC5gbKC6BUGC6oA/AHgA=="))

BIN
apps/tapelauncher/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

View File

@ -0,0 +1,2 @@
0.01: New App!
0.02: Tweaks for app loader

View File

@ -0,0 +1,40 @@
# Test User Input
This very basic app, allows to *test the bangle.js input interface*, and displays the result in text or a switch on/off image.
Launcher icon
![](testUserInput_ss0.png)
1st screen - Help/Intro
![](testUserInput_ss1.png)
2nd screen - interface and a result
![](testUserInput_ss2.png)
3rd screen - interface and a result
![](testUserInput_ss3.png)
## Usage
Open and see a "help" screen
Interact with buttons or touch screen to print the event or leave the app
## Features
Colours, font, user input, image, load widgets
## Controls
Press left area - Prints Touch1
Press righ area - Prints Touch2
Press center area - Prints Touch3
Swipe Left - Displays Switch OFF image
Swipe Right - Displays Switch ON image
BTN1 - Prints Button1
BTN2 - Prints Button2
BTN3 - Quit to Launcher
## Support
This app is so basic that probably the easiest is to just edit the code
Otherwise you can contact me [here](https://github.com/dapgo)

View File

@ -0,0 +1 @@
E.toArrayBuffer(atob("MDDCAP//Bv7m/RF8AAAAAAAAAAAAAAAAAAAAAP/AAAAAAAAAAAAAD//8AAAAAAAAAAAAP///AAAAAAAAAAAA////wAAAAAAAAAAA////wAAAAAAAAAAD/9X/8AAAAAAAAAAD/1V/8AAAAAAAAAAD/1V/8AAAAAAAAAAD/1V/8AAAAAAAAAAD/1V/8AAAAAAAAAAA/1V/wAAAAAAAAAAA/1V/wAAAAAAAAAAAP1V/AAAAAAAAAAAAD1V8AAAAAAAAAAAAAFVAAAAAAAAAAAAAAFVAAAAAAAAAAAAAAFVAAAAAAAAAAAAAAFVAAAAAAAAAAAAAAFVlQAAAAAAAAAAAAFVlVVQAAAAAAAAAAFVVVVVUAAAAAAAAAFVVVVVVQAAAAAAAAFVVVVVVQAAAAFYAAFVVVVVVUAAAAFWAAFVVVVVVUAAAAFVgAFVVVVVVUAAAAFVaAlVVVVVVUAAAABVWqlVVVVVVUAAAAAVVqlVVVVVVUAAAAAFValVVVVVVYAAAAABVWlVVVVVVoAAAAAAVVlVVVVVWoAAAAAAFVVVVVVVaoAAAAAAFVVVVVVVqoAAAAAABVVVVVVWqoAAAAAAAVVVVVVqqoAAAAAAAFVVVVWqqoAAAAAAABVVVVaqqoAAAAAAAAVVVVqqqgAAAAAAAAFVVWqqqgAAAAAAAABVVaqqqAAAAAAAAAAFVqqqgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"))

135
apps/testuserinput/app.js Normal file
View File

@ -0,0 +1,135 @@
/* Test bangle.js input interface */
var colbackg='#111111';
//var coldarkred='#CC3333';
var colorange='#e56e06';
var colgrey='#f3f3f1'; //'#51504f'; //lighter gray
var v_font1size='16';
var v_clicks='0';
console.log("*** Test input interface ***");
function ClearActiveArea(){
g.setColor(colbackg);
g.fillRect(0,32,239,239); //fill all screen except widget area
g.flip();
}
function ClearBannerArea(){
g.setColor(colgrey);
g.fillRect(50,32,190,85); //fill an specific area
g.flip();
}
function PrintUserInput(boton){
console.log("Pressed touch/BTN",boton);
if (v_clicks=='0') PrintAreas();
ClearBannerArea();
if (boton==' <---') {
var img_off = {
width : 48, height : 48, bpp : 2,
transparent : 0,
palette : new Uint16Array([65535,63968,40283,50781]),
buffer : E.toArrayBuffer(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAAAAAAAAA///9VVVVVVVQAAAD/qq/1VVVVVVVAAAP6qqv9VVVVVVVUAA/qqqv/VVVVVVVVAD+qqq//1VVVVVVVQP6qqq//1VVVVVVVQPqqqr//9VVVVVVVUvqqqr//9VVVVVVVU+qqqv/+uVVVVVVVV+qqqv+quVVVVVVVV+qqq+qqvVVVVVVVV+qqvqqqvVVVVVVVV+qv+qqquVVVVVVVV+r/+qqquVVVVVVVVv//6qqq9VVVVVVVUP//6qqq9VVVVVVVUP//qqqr1VVVVVVVQD//qqqv1VVVVVVVQA/+qqq/VVVVVVVVAAP+qqr9VVVVVVVUAAD/qq/1VVVVVVVAAAA///9VVVVVVVQAAAAA//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"))
};
g.drawImage(img_off,90,35);
}
else if (boton==' --->') {
var img_on = {
width : 48, height : 48, bpp : 2,
transparent : 0,
palette : new Uint16Array([65535,36361,27879,40283]),
buffer : E.toArrayBuffer(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAABVVVVVqqf///AAAAVVVVVWqn////wAAFVVVVVWqf////8AAVVVVVVap//////ABVVVVVVqr//////wBVVVVVVqn//////8FVVVVVVqv//////8FVVVVVWqf///////VVVVVVWq////////VVVVVVWq////////VVVVVVWq////////VVVVVVWq////////VVVVVVWq////////VVVVVVWq////////FVVVVVWqf///////FVVVVVVqv//////8BVVVVVVqn//////8BVVVVVVar//////wAVVVVVVap//////AAFVVVVVWqf////8AAAVVVVVWqn////wAAABVVVVVqqf///AAAAAAAAAAAAA//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"))
};
g.drawImage(img_on,90,35);
}
else
{ //no swipe /slide
g.setColor(colorange);
g.setFontVector(32).drawString(boton, 60, 65);
}
g.flip();
v_clicks++;
}
function PrintBtn1(boton){
console.log("Pressed BTN1");
if (v_clicks=='0') PrintAreas();
PrintUserInput("Button1");
v_clicks++;
}
function PrintBtn2(boton){
console.log("Pressed BTN2");
if (v_clicks=='0') PrintAreas();
PrintUserInput("Button2");
v_clicks++;
}
function PrintHelp(){
console.log("********************************");
console.log("Log: *** Print help in screen");
ClearActiveArea();
g.setColor(0,1,0); //green
g.setFontVector(v_font1size).drawString("To test the input, try :", 30, 90);
g.setFontVector(v_font1size).drawString("Swipe right -->", 30, 115);
g.setFontVector(v_font1size).drawString("Swipe left <--", 30, 130);
g.setFontVector(v_font1size).drawString("Click Left area", 30, 145);
g.setFontVector(v_font1size).drawString("Click Right area", 30,160);
g.setFontVector(v_font1size).drawString("Click Middle area", 30,175);
g.setFontVector(v_font1size).drawString("Press Button1 ", 30,190);
g.setFontVector(v_font1size).drawString("Press Button2 ", 30,205);
g.setFontVector(v_font1size).drawString("Press Button3 to Quit", 30,220);
g.flip();
}
function PrintAreas(){
console.log("********************************");
console.log("Log: *** Print Areas in screen");
ClearActiveArea();
g.setColor(0,1,0); //green
g.drawLine(1, 140, 1, 200);//side border
g.drawLine(239, 140, 239, 200);//side border
g.drawLine(120, 140, 120, 200);//middle of areas
g.setFontVector(v_font1size).drawString("BTN1", 195,45);
g.setFontVector(v_font1size).drawString("BTN2", 195,125);
g.setFontVector(v_font1size).drawString("Quit<--", 130,225);
g.setFontVector(v_font1size).drawString("BTN3", 195,225);
g.setFontVector(v_font1size).drawString("Middle area", 80,120);
g.setFontVector(v_font1size).drawString("Left area", 15, 165);
g.setFontVector(v_font1size).drawString("Right area", 140,165);
g.flip();
}
function UserInput(){
Bangle.on('touch', function(button){
switch(button){
case 1:
PrintUserInput("Touch 1");//left
break;
case 2:
PrintUserInput("Touch 2");//right
break;
case 3:
PrintUserInput("Touch 3");//center 1+2
break;
}
});
//only the name of the function
setWatch(PrintBtn1, BTN1, { repeat: true });
setWatch(PrintBtn2, BTN2, { repeat: true });
setWatch(Bangle.showLauncher, BTN3, { repeat: true });
Bangle.on('swipe', dir => {
if(dir == 1) PrintUserInput(" --->");
else PrintUserInput(" <---");
});
console.log("Log: Input conditions loaded");
} //end of UserInput
//Main code
Bangle.loadWidgets();
Bangle.drawWidgets();
//optional line below widgets area
g.setColor(0,1,0); //green
g.drawLine(60, 30, 180, 30);
g.flip();
//end optional
PrintHelp();
UserInput();

BIN
apps/testuserinput/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

View File

@ -0,0 +1,63 @@
# Walkers Clock
A larg font watch, displays steps, can switch GPS on/off, displays grid reference
The watch works well with GPSsetup, the Activepedom or Widpedom
wdigets. A tiny GPS power widget is waiting in the wings for when
the v2.09 firware is released.
## Features
- Displays the time in large font
- Uses BTN1 to select modeline display (eg battery status or switch between setting when in a function mode
- Uses BTN3 to select the function mode (eg turn on/off GPS, or change GPS display)
- two function menus at present
GPS Power = On/Off
GPS Display = Grid | Speed Alt
when the modeline in CYAN use button BTN1 to switch between options
- Display the current steps if one of the steps widgets is installed
- Ensures that BTN2 requires a 1.5 second press in order to switch to the launcher
this is so you dont accidently switch out of the GPS/watch display with you coat sleeve
- Displays the timestamp of the last GPS fix when the GPS is on
- Buzzes when the GPS aquires a positional satellite fix
- Displays the current OS map grid reference in a large font
- Displays the age of the current GPS position fix in seconds
- Works in tandem with the GPS setup app so that you can reduce the power consumption of the GPS
## BTN1 cycles the information line
- By default the modeline is switched off
- Click BTN1 once and display your steps (if one of the step widgets is installed)
- Click BTN1 again and it will show battery % charge
- Click BTN1 again and it will switch the modeline off
## BTN2 Long press to start the launcher
BTN2 is confiured to respond to a 1.5 second press in order to switch
to the launcher App. Simply press and hold until you hear a buzz and
release. This avoids accidently switching out of the watch app when
clothing catches it.
## BTN3 cycles the function mode
- Click BTN3 once and the GPS ON / OFF menu is displayed
- If the GPS is OFF then pressing BTN1 will turn it ON
- If the GPS is ON then Clicking BTN1 will turn it OFF
When the GPS is ON a second function menu can be displayed by
pressing BTN3 again. This will show options to change the GPS display
on the second line of the watch.
- Grid - will display the GPS position converted to an OS Grid Ref
- Speed - will display the GPS speed inforation supplied in the last GPS fix
- Alt - will display the altitude information
![](gps_osref.jpg)
![](gps_speed.jpg)
![](gps_alt.jpg)
## Future Enhancements
* Ability to turn on the Heart Rate monitor
* Maybe a simple stopwatch capability
* Fix the screen flicker

522
apps/walkersclock/app.js Normal file
View File

@ -0,0 +1,522 @@
/*
* Walkers clock, hugh barney AT googlemail DOT com
*
* A clock that has the following features
* - displays the time in large font
* - uses BTN1 to select modeline display (eg battery status or switch between setting when in a function mode
* - uses BTN3 to select the function mode (eg turn on/off GPS, or change GPS display)
* - two function menus at present
* GPS Power = On/Off
* GPS Display = Grid | Speed Alt
* when the modeline in CYAN use button BTN1 to switch between options
* - display the current steps if one of the steps widgets is installed
* - ensures that BTN2 requires a 1.5 second press in order to switch to the launcher
* this is so you dont accidently switch out of the GPS/watch display with you coat sleeve
* - displays the timestamp of the last GPS fix when the GPS is on
* - buzzes when the GPS aquires a positional satellite fix
* - displays the current OS map grid reference in a large font
* - displays the age of the current GPS position fix in seconds
* - works in tandem with the GPS setup app so that you can reduce the power consumption of the GPS
*
*/
const INFO_NONE = "none";
const INFO_BATT = "batt";
const INFO_STEPS = "step";
const FN_MODE_OFF = "fn_mode_off";
const FN_MODE_GPS = "fn_mode_gps";
const FN_MODE_GDISP = "fn_mode_gdisp";
const GPS_OFF = "gps_off";
const GPS_TIME = "gps_time";
const GPS_SATS = "gps_sats";
const GPS_RUNNING = "gps_running";
const GDISP_OS = "g_osref";
const GDISP_SPEED = "g_speed";
const GDISP_ALT = "g_alt";
const Y_TIME = 40;
const Y_ACTIVITY = 120;
const Y_MODELINE = 200;
let gpsState = GPS_OFF;
let gpsPowerState = false;
let infoMode = INFO_NONE;
let functionMode = FN_MODE_OFF;
let gpsDisplay = GDISP_OS;
let last_steps = undefined;
let firstPress = 0;
let last_fix = {
fix: 0,
alt: 0,
lat: 0,
lon: 0,
speed: 0,
time: 0,
satellites: 0
};
function drawTime() {
var d = new Date();
var da = d.toString().split(" ");
var time = da[4].substr(0,5);
g.reset();
g.clearRect(0,24,239,239);
g.setColor(1,1,1); // white
g.setFontAlign(0, -1);
if (gpsState == GPS_SATS || gpsState == GPS_RUNNING) {
time = last_fix.time.toUTCString().split(" ");
time = time[4];
g.setFont("Vector", 56);
} else {
g.setFont("Vector", 80);
}
g.drawString(time, g.getWidth()/2, Y_TIME);
}
function drawSteps() {
g.setColor(0,255,0); // green
g.setFont("Vector", 60);
g.drawString(getSteps(), g.getWidth()/2, Y_ACTIVITY);
}
function drawActivity() {
if (!gpsPowerState) {
drawSteps();
return;
}
g.setFont("6x8", 3);
g.setColor(1,1,1);
g.setFontAlign(0, -1);
if (gpsState == GPS_TIME) {
g.drawString("Waiting for", g.getWidth()/2, Y_ACTIVITY);
g.drawString("GPS", g.getWidth()/2, Y_ACTIVITY + 30);
return;
}
if (gpsState == GPS_SATS) {
g.drawString("Satellites", g.getWidth()/2, Y_ACTIVITY);
g.drawString(last_fix.satellites, g.getWidth()/2, Y_ACTIVITY + 30);
return;
}
if (gpsState == GPS_RUNNING) {
//console.log("Draw GPS Running");
let time = formatTime(last_fix.time);
let age = timeSince(time);
let os = OsGridRef.latLongToOsGrid(last_fix);
let ref = to_map_ref(6, os.easting, os.northing);
let speed;
if (age < 0) age = 0;
g.setFontVector(40);
g.setColor(0xFFC0);
switch(gpsDisplay) {
case GDISP_OS:
g.drawString(ref, 120, Y_ACTIVITY, true);
break;
case GDISP_SPEED:
speed = last_fix.speed;
speed = speed.toFixed(1);
g.drawString(speed + "kph", 120, Y_ACTIVITY, true);
break;
case GDISP_ALT:
g.drawString(last_fix.alt + "m" , 120, Y_ACTIVITY, true);
break;
}
g.setFont("6x8",2);
g.setColor(1,1,1);
g.drawString(age, 120, Y_ACTIVITY + 46);
}
}
function onTick() {
if (!Bangle.isLCDOn())
return;
if (gpsPowerState) {
drawAll();
return;
}
if (last_steps != getSteps()) {
last_steps = getSteps();
drawAll();
return;
}
var t = new Date();
if (t.getSeconds() === 0 && !gpsPowerState) {
drawAll();
}
}
function drawAll(){
drawTime();
drawActivity(); // steps, hrt or gps
drawInfo();
}
function drawInfo() {
let val;
let str = "";
let col = 0x07E0; // green
//console.log("drawInfo(), infoMode=" + infoMode + " funcMode=" + functionMode);
switch(functionMode) {
case FN_MODE_OFF:
break;
case FN_MODE_GPS:
col = 0x07FF; // cyan
str = "GPS: " + (gpsPowerState ? "ON" : "OFF");
drawModeLine(str,col);
return;
case FN_MODE_GDISP:
col = 0x07FF; // cyan
switch(gpsDisplay) {
case GDISP_OS:
str = "GPS: Grid";
break;
case GDISP_SPEED:
str = "GPS: Speed";
break;
case GDISP_ALT:
str = "GPS: Alt";
break;
}
drawModeLine(str,col);
return;
}
switch(infoMode) {
case INFO_NONE:
col = 0x0000;
str = "";
break;
case INFO_STEPS:
str = "Steps: " + getSteps();
break;
case INFO_BATT:
default:
str = "Battery: " + E.getBattery() + "%";
}
drawModeLine(str,col);
}
function drawModeLine(str, col) {
g.setFont("6x8", 3);
g.setColor(col);
g.fillRect(0, Y_MODELINE - 3, 239, Y_MODELINE + 25);
g.setColor(0,0,0);
g.setFontAlign(0, -1);
g.drawString(str, g.getWidth()/2, Y_MODELINE);
}
function changeInfoMode() {
switch(functionMode) {
case FN_MODE_OFF:
break;
case FN_MODE_GPS:
gpsPowerState = !gpsPowerState;
Bangle.buzz();
Bangle.setGPSPower(gpsPowerState ? 1 : 0);
if (gpsPowerState) {
gpsState = GPS_TIME; // waiting first response so we can display time
Bangle.on('GPS', processFix);
} else {
Bangle.removeListener("GPS", processFix);
gpsState = GPS_OFF;
}
resetLastFix();
// poke the gps widget indicator to change
if (WIDGETS.gps !== undefined) {
WIDGETS.gps.draw();
}
functionMode = FN_MODE_OFF;
infoMode = INFO_NONE;
//drawInfo();
return;
case FN_MODE_GDISP:
switch (gpsDisplay) {
case GDISP_OS:
gpsDisplay = GDISP_SPEED;
break;
case GDISP_SPEED:
gpsDisplay = GDISP_ALT;
break;
case GDISP_ALT:
default:
gpsDisplay = GDISP_OS;
break;
}
}
switch(infoMode) {
case INFO_NONE:
if (stepsWidget() !== undefined)
infoMode = INFO_STEPS;
else
infoMode = INFO_BATT;
break;
case INFO_STEPS:
infoMode = INFO_BATT;
break;
case INFO_BATT:
default:
infoMode = INFO_NONE;
}
//drawInfo();
}
function changeFunctionMode() {
//console.log("changeFunctionMode()");
if (gpsState != GPS_RUNNING) {
switch(functionMode) {
case FN_MODE_OFF:
functionMode = FN_MODE_GPS;
break;
case FN_MODE_GPS:
default:
functionMode = FN_MODE_OFF;
break;
}
} else {
// if GPS is RUNNING then we want the GPS display options first
switch(functionMode) {
case FN_MODE_OFF:
functionMode = FN_MODE_GDISP;
break;
case FN_MODE_GDISP:
functionMode = FN_MODE_GPS;
break;
case FN_MODE_GPS:
default:
functionMode = FN_MODE_OFF;
break;
}
}
infoMode = INFO_NONE; // function mode overrides info mode
}
function resetLastFix() {
last_fix = {
fix: 0,
alt: 0,
lat: 0,
lon: 0,
speed: 0,
time: 0,
satellites: 0
};
}
function processFix(fix) {
last_fix.time = fix.time;
if (gpsState == GPS_TIME)
gpsState = GPS_SATS;
if (fix.fix) {
if (!last_fix.fix) Bangle.buzz(); // buzz on first position
gpsState = GPS_RUNNING;
last_fix = fix;
}
}
function getSteps() {
if (stepsWidget() !== undefined)
return stepsWidget().getSteps();
return "-";
}
function stepsWidget() {
if (WIDGETS.activepedom !== undefined) {
return WIDGETS.activepedom;
} else if (WIDGETS.wpedom !== undefined) {
return WIDGETS.wpedom;
}
return undefined;
}
/************* GPS / OSREF Code **************************/
function formatTime(now) {
var fd = now.toUTCString().split(" ");
return fd[4];
}
function timeSince(t) {
var hms = t.split(":");
var now = new Date();
var sn = 3600*(now.getHours()) + 60*(now.getMinutes()) + 1*(now.getSeconds());
var st = 3600*(hms[0]) + 60*(hms[1]) + 1*(hms[2]);
return (sn - st);
}
Number.prototype.toRad = function() { return this*Math.PI/180; };
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Ordnance Survey Grid Reference functions (c) Chris Veness 2005-2014 */
/* - www.movable-type.co.uk/scripts/gridref.js */
/* - www.movable-type.co.uk/scripts/latlon-gridref.html */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
function OsGridRef(easting, northing) {
this.easting = 0|easting;
this.northing = 0|northing;
}
OsGridRef.latLongToOsGrid = function(point) {
var lat = point.lat.toRad();
var lon = point.lon.toRad();
var a = 6377563.396, b = 6356256.909; // Airy 1830 major & minor semi-axes
var F0 = 0.9996012717; // NatGrid scale factor on central meridian
var lat0 = (49).toRad(), lon0 = (-2).toRad(); // NatGrid true origin is 49�N,2�W
var N0 = -100000, E0 = 400000; // northing & easting of true origin, metres
var e2 = 1 - (b*b)/(a*a); // eccentricity squared
var n = (a-b)/(a+b), n2 = n*n, n3 = n*n*n;
var cosLat = Math.cos(lat), sinLat = Math.sin(lat);
var nu = a*F0/Math.sqrt(1-e2*sinLat*sinLat); // transverse radius of curvature
var rho = a*F0*(1-e2)/Math.pow(1-e2*sinLat*sinLat, 1.5); // meridional radius of curvature
var eta2 = nu/rho-1;
var Ma = (1 + n + (5/4)*n2 + (5/4)*n3) * (lat-lat0);
var Mb = (3*n + 3*n*n + (21/8)*n3) * Math.sin(lat-lat0) * Math.cos(lat+lat0);
var Mc = ((15/8)*n2 + (15/8)*n3) * Math.sin(2*(lat-lat0)) * Math.cos(2*(lat+lat0));
var Md = (35/24)*n3 * Math.sin(3*(lat-lat0)) * Math.cos(3*(lat+lat0));
var M = b * F0 * (Ma - Mb + Mc - Md); // meridional arc
var cos3lat = cosLat*cosLat*cosLat;
var cos5lat = cos3lat*cosLat*cosLat;
var tan2lat = Math.tan(lat)*Math.tan(lat);
var tan4lat = tan2lat*tan2lat;
var I = M + N0;
var II = (nu/2)*sinLat*cosLat;
var III = (nu/24)*sinLat*cos3lat*(5-tan2lat+9*eta2);
var IIIA = (nu/720)*sinLat*cos5lat*(61-58*tan2lat+tan4lat);
var IV = nu*cosLat;
var V = (nu/6)*cos3lat*(nu/rho-tan2lat);
var VI = (nu/120) * cos5lat * (5 - 18*tan2lat + tan4lat + 14*eta2 - 58*tan2lat*eta2);
var dLon = lon-lon0;
var dLon2 = dLon*dLon, dLon3 = dLon2*dLon, dLon4 = dLon3*dLon, dLon5 = dLon4*dLon, dLon6 = dLon5*dLon;
var N = I + II*dLon2 + III*dLon4 + IIIA*dLon6;
var E = E0 + IV*dLon + V*dLon3 + VI*dLon5;
return new OsGridRef(E, N);
};
/*
* converts northing, easting to standard OS grid reference.
*
* [digits=10] - precision (10 digits = metres)
* to_map_ref(8, 651409, 313177); => 'TG 5140 1317'
* to_map_ref(0, 651409, 313177); => '651409,313177'
*
*/
function to_map_ref(digits, easting, northing) {
if (![ 0,2,4,6,8,10,12,14,16 ].includes(Number(digits))) throw new RangeError(`invalid precision '${digits}'`); // eslint-disable-line comma-spacing
let e = easting;
let n = northing;
// use digits = 0 to return numeric format (in metres) - note northing may be >= 1e7
if (digits == 0) {
const format = { useGrouping: false, minimumIntegerDigits: 6, maximumFractionDigits: 3 };
const ePad = e.toLocaleString('en', format);
const nPad = n.toLocaleString('en', format);
return `${ePad},${nPad}`;
}
// get the 100km-grid indices
const e100km = Math.floor(e / 100000), n100km = Math.floor(n / 100000);
// translate those into numeric equivalents of the grid letters
let l1 = (19 - n100km) - (19 - n100km) % 5 + Math.floor((e100km + 10) / 5);
let l2 = (19 - n100km) * 5 % 25 + e100km % 5;
// compensate for skipped 'I' and build grid letter-pairs
if (l1 > 7) l1++;
if (l2 > 7) l2++;
const letterPair = String.fromCharCode(l1 + 'A'.charCodeAt(0), l2 + 'A'.charCodeAt(0));
// strip 100km-grid indices from easting & northing, and reduce precision
e = Math.floor((e % 100000) / Math.pow(10, 5 - digits / 2));
n = Math.floor((n % 100000) / Math.pow(10, 5 - digits / 2));
// pad eastings & northings with leading zeros
e = e.toString().padStart(digits/2, '0');
n = n.toString().padStart(digits/2, '0');
return `${letterPair} ${e} ${n}`;
}
// start a timer and buzz whenn held long enough
function firstPressed() {
firstPress = getTime();
pressTimer = setInterval(longPressCheck, 1500);
}
// if you release too soon there is no buzz as timer is cleared
function thenReleased() {
var dur = getTime() - firstPress;
if (pressTimer) {
clearInterval(pressTimer);
pressTimer = undefined;
}
if ( dur >= 1.5 ) Bangle.showLauncher();
}
// when you feel the buzzer you know you have done a long press
function longPressCheck() {
Bangle.buzz();
if (pressTimer) {
clearInterval(pressTimer);
pressTimer = undefined;
}
}
var pressTimer;
g.clear();
Bangle.loadWidgets();
Bangle.drawWidgets();
drawAll();
Bangle.on('lcdPower',function(on) {
functionMode = FN_MODE_OFF;
infoMode = INFO_NONE;
if (on) drawAll();
});
var click = setInterval(onTick, 5000);
setWatch(() => { changeInfoMode(); drawAll(); }, BTN1, {repeat: true});
setWatch(() => { changeFunctionMode(); drawAll(); }, BTN3, {repeat: true});
// make BTN require a long press (1.5 seconds) to switch to launcher
setWatch(firstPressed, BTN2,{repeat:true,edge:"rising"});
setWatch(thenReleased, BTN2,{repeat:true,edge:"falling"});

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwxH+AH4A/AEcsAAYuuGFIqEF9gFJF/62SACAvvGCgYEwIASqwxVF4mmACQvEGCJcCF65iDF/4vbqwvVd4YeBJgIECAAulq4KDmS/XAAVXJwgvHOAIKCOoQuTGQ1WvYvCvYAGBQdWLwYtUMQwAQGAQuYXgJPCmQEBAAwKDCQKNZlmsAAKECAoQAEX4QQESKh4EDwVXegIvPSKgbBDwMs64ABAoOBAoQAE1gvGTAQwQCINXF4olBFw4KCAAYvCDIQvZABgv/F/4vqCoYvpGAMyF7ICBF6QADEIeBABQuCF4QACFyAwFDwRlCABNWHoUyFyoxEwOIxGBPoIAJMYYvCFyrzEGAIALFwS7TYRYACmQAGSxAtcACaNWwGArizBAwIAININWrgTCF6+GAAYvCA4gACwAKGCQIv/F+qqBAAQvCA4gACXAIKFF67cBAAQvCAwYKFmQGFF6wAZF6YxaFyo1HIBYpcAH4A/AAoA=="))

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB