diff --git a/apps/sixths/ChangeLog b/apps/sixths/ChangeLog index 08c4b83b02..510748fb31 100644 --- a/apps/sixths/ChangeLog +++ b/apps/sixths/ChangeLog @@ -2,3 +2,4 @@ 0.02: better GPS support, adding altitude and temperature support 0.03: minor code improvements 0.04: make height auto-calibration useful and slow ticks to save power +0.05: add ability to navigate to waypoints, better documentation diff --git a/apps/sixths/README.md b/apps/sixths/README.md index 17369c7a07..18aa85bebb 100644 --- a/apps/sixths/README.md +++ b/apps/sixths/README.md @@ -24,17 +24,35 @@ minutes, real distance will be usually higher than approximation. Useful gestures: -F -- disable GPS. -G -- enable GPS for 4 hours in low power mode. -N -- take a note and write it to the log. -S -- enable GPS for 30 minutes in high power mode. + B -- "Battery", show/buzz battery info +D -- "Down", previous waypoint +F -- "oFf", disable GPS. +G -- "Gps", enable GPS for 4 hours in low power mode. +I -- "Info", toggle info display + L -- "aLtimeter", load altimeter app +M -- "Mark", create mark from current position +N -- "Note", take a note and write it to the log. + O -- "Orloj", run orloj app + R -- "Run", run "runplus" app +S -- "Speed", enable GPS for 30 minutes in high power mode. + T -- "Time", buzz current time +U -- "Up", next waypoint +Y -- "compass", reset compass When application detects watch is being worn, it will use vibrations to communicate back to the user. +B -- battery low. E -- acknowledge, gesture understood. T -- start of new hour. +Three colored dots may appear on display. North is on the 12 o'clock +position (top of the display). + +red: this is direction to the waypoint. +green: this is direction you are moving into, according to GPS. +blue: this is direction top of watch faces, according to the compass. + Written by: [Pavel Machek](https://github.com/pavelmachek) ## Future Development @@ -55,4 +73,27 @@ Todo: *) only turn on compass when needed -*) adjust draw timeouts to save power \ No newline at end of file +*) only warn about battery low when it crosses thresholds, update +battery low message + +*) rename "show" to something else -- it collides with built-in + +*) adjust clock according to GPS + +*) show something more reasonable than (NOTEHERE). + +*) hide messages after timeout. + +*) show route lengths after the fact + +*) implement longer recording than "G". + +*) Probably T should be G. + +*) sum gps distances for a day + +*) allow setting up home altitude, or at least disable auto-calibration + +*) show time-to-sunset / sunrise? + +*) one-second updates when gps is active \ No newline at end of file diff --git a/apps/sixths/metadata.json b/apps/sixths/metadata.json index 91492fe1ce..585f23170e 100644 --- a/apps/sixths/metadata.json +++ b/apps/sixths/metadata.json @@ -1,6 +1,6 @@ { "id": "sixths", "name": "Sixth sense", - "version": "0.04", + "version": "0.05", "description": "Clock for outdoor use with GPS support", "icon": "app.png", "readme": "README.md", diff --git a/apps/sixths/sixths.app.js b/apps/sixths/sixths.app.js index 00c83153f0..c5fb3b9cf8 100644 --- a/apps/sixths/sixths.app.js +++ b/apps/sixths/sixths.app.js @@ -3,18 +3,16 @@ // Options you'll want to edit const rest_altitude = 354; -const geoid_to_sea_level = 0; // Maybe BangleJS2 already compensates? const W = g.getWidth(); const H = g.getHeight(); -var cx = 100, cy = 105, sc = 70, -temp = 0, alt = 0, bpm = 0; +var cx = 100, cy = 105, sc = 70, temp = 0, alt = 0, bpm = 0; var buzz = "", /* Set this to transmit morse via vibrations */ inm = "", l = "", /* For incoming morse handling */ in_str = "", - note = "(NOTEHERE)", - debug = "v1119", debug2 = "(otherdb)", debug3 = "(short)"; + note = "", + debug = "v0.04.1", debug2 = "(otherdb)", debug3 = "(short)"; var mode = 0, mode_time = 0; // 0 .. normal, 1 .. note, 2.. mark name var disp_mode = 0; // 0 .. normal, 1 .. small time @@ -45,15 +43,15 @@ var cur_mark = null; // Icons var icon_alt = "\0\x08\x1a\1\x00\x00\x00\x20\x30\x78\x7C\xFE\xFF\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\x00\x00\x00\x00\x00\x00\x00"; -var icon_m = "\0\x08\x1a\1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\x00\x00\x00\x00\x00\x00\x00"; +//var icon_m = "\0\x08\x1a\1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\x00\x00\x00\x00\x00\x00\x00"; var icon_km = "\0\x08\x1a\1\xC3\xC6\xCC\xD8\xF0\xD8\xCC\xC6\xC3\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\x00\x00\x00\x00\x00\x00\x00"; var icon_kph = "\0\x08\x1a\1\xC3\xC6\xCC\xD8\xF0\xD8\xCC\xC6\xC3\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\xFF\x00\xC3\xC3\xFF\xC3\xC3"; var icon_c = "\0\x08\x1a\1\x00\x00\x60\x90\x90\x60\x00\x7F\xFF\xC0\xC0\xC0\xC0\xC0\xFF\x7F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; function toMorse(x) { - var r = ""; + let r = ""; for (var i = 0; i < x.length; i++) { - var c = x[i]; + let c = x[i]; if (c == " ") { r += " "; continue; @@ -113,20 +111,15 @@ function gpsHandleFix(fix) { doBuzz(" ."); prev_fix = fix; } - if (0) { - /* GPS altitude fluctuates a lot, not really usable */ - alt_adjust = cur_altitude - (fix.alt + geoid_to_sea_level); - alt_adjust_mode = "g"; - } if (1) { let now1 = Date(); let now2 = fix.time; - var n1 = now1.getMinutes() * 60 + now1.getSeconds(); - var n2 = now2.getMinutes() * 60 + now2.getSeconds(); + let n1 = now1.getMinutes() * 60 + now1.getSeconds(); + let n2 = now2.getMinutes() * 60 + now2.getSeconds(); debug2 = "te "+(n2-n1)+"s"; } loggps(fix); - var d = calcDistance(fix, prev_fix); + let d = calcDistance(fix, prev_fix); if (d > 30) { prev_fix = fix; gps_dist += d/1000; @@ -135,7 +128,7 @@ function gpsHandleFix(fix) { function gpsHandle() { let msg = ""; if (!last_restart) { - var d = (getTime()-last_pause); + let d = (getTime()-last_pause); if (last_fix) msg = "PL"+ fmtTimeDiff(getTime()-last_fix); else @@ -146,7 +139,7 @@ function gpsHandle() { gpsRestart(); } } else { - var fix = Bangle.getGPSFix(); + let fix = Bangle.getGPSFix(); if (fix && fix.fix && fix.lat) { gpsHandleFix(fix); msg = fix.speed.toFixed(1) + icon_kph; @@ -167,8 +160,8 @@ function gpsHandle() { } } - var d = (getTime()-last_restart); - var d2 = (getTime()-last_fstart); + let d = (getTime()-last_restart); + let d2 = (getTime()-last_fstart); print("gps on, restarted ", d, gps_needed, d2, fix.lat); if (getTime() > gps_speed_limit && (d > gps_needed || (last_fstart && d2 > 10))) { @@ -192,8 +185,11 @@ function markNew() { } function markHandle() { let m = cur_mark; - var msg = m.name + ">" + fmtTimeDiff(getTime()- m.time); - if (m.fix && m.fix.fix) { + let msg = m.name + ">"; + if (m.time) { + msg += fmtTimeDiff(getTime()- m.time); + } + if (prev_fix && prev_fix.fix && m.fix && m.fix.fix) { let s = fmtDist(calcDistance(m.fix, prev_fix)/1000) + icon_km; msg += " " + s; debug = "wp>" + s; @@ -214,6 +210,34 @@ function entryDone() { in_str = 0; mode = 0; } +var waypoints = [], sel_wp = 0; +function loadWPs() { + waypoints = require("Storage").readJSON(`waypoints.json`)||[{}]; + print("Have waypoints", waypoints); +} +function saveWPs() { + require("Storage").writeJSON(`waypoints.json`,waypoints); +} +function selectWP(i) { + sel_wp += i; + if (sel_wp < 0) + sel_wp = 0; + if (sel_wp >= waypoints.length) + sel_wp = waypoints.length - 1; + if (sel_wp < 0) { + show("No WPs", 60); + } + let wp = waypoints[sel_wp]; + cur_mark = {}; + cur_mark.name = wp.name; + cur_mark.gps_dist = 0; /* HACK */ + cur_mark.fix = {}; + cur_mark.fix.fix = 1; + cur_mark.fix.lat = wp.lat; + cur_mark.fix.lon = wp.lon; + show("WP:"+wp.name, 60); + print("Select waypoint: ", cur_mark); +} function inputHandler(s) { print("Ascii: ", s, s[0], s[1]); if (s[0] == '^') { @@ -230,9 +254,9 @@ function inputHandler(s) { return; } switch(s) { - case 'B': + case 'B': { s = ' B'; - var bat = E.getBattery(); + let bat = E.getBattery(); if (bat > 45) s += 'E'; else @@ -240,6 +264,8 @@ function inputHandler(s) { doBuzz(toMorse(s)); show("Bat "+bat+"%", 60); break; + } + case 'D': selectWP(1); break; case 'F': gpsOff(); show("GPS off", 3); break; case 'G': gpsOn(); gps_limit = getTime() + 60*60*4; show("GPS on", 3); break; case 'I': @@ -252,15 +278,17 @@ function inputHandler(s) { case 'M': mode = 2; show("M>", 10); cur_mark = markNew(); mode_time = getTime(); break; case 'N': mode = 1; show(">", 10); mode_time = getTime(); break; case 'O': aload("orloj.app.js"); break; + case 'R': aload("runplus.app.js"); break; case 'S': gpsOn(); gps_limit = getTime() + 60*30; gps_speed_limit = gps_limit; show("GPS on", 3); break; - case 'T': + case 'T': { s = ' T'; - var d = new Date(); + let d = new Date(); s += d.getHours() % 10; s += add0(d.getMinutes()); doBuzz(toMorse(s)); break; - case 'R': aload("run.app.js"); break; + } + case 'U': selectWP(-1); break; case 'Y': doBuzz(buzz); Bangle.resetCompass(); break; } } @@ -378,23 +406,22 @@ function loggps(fix) { } function hourly() { print("hourly"); - var s = ' T'; + let s = ' T'; + let bat = E.getBattery(); + if (bat < 25) { + s = ' B'; + show("Bat "+bat+"%", 60); + } if (is_active) doBuzz(toMorse(s)); - logstamp(""); + //logstamp(""); } function show(msg, timeout) { note = msg; } function fivemin() { print("fivemin"); - var s = ' B'; - var bat = E.getBattery(); - if (bat < 25) { - if (is_active) - doBuzz(toMorse(s)); - show("Bat "+bat+"%", 60); - } + let s = ' B'; try { Bangle.getPressure().then((x) => { cur_altitude = x.altitude; cur_temperature = x.temperature; }, @@ -470,8 +497,9 @@ function drawDot(h, d, s) { g.fillCircle(x,y, 10); } function drawBackground() { - var acc = Bangle.getAccel(); + let acc = Bangle.getAccel(); is_level = (acc.z < -0.95); + Bangle.setCompassPower(!!is_level, "sixths"); if (is_level) { let obj = Bangle.getCompass(); if (obj) { @@ -502,13 +530,6 @@ function drawTime(now) { dot = "."; g.drawString(now.getHours() + dot + add0(now.getMinutes()), W, 90); } -function adjPressure(a) { - var o = Bangle.getOptions(); - print(o); - o.seaLevelPressure = o.seaLevelPressure * m + a; - Bangle.setOptions(o); - var avr = []; -} function draw() { if (disp_mode == 2) { draw_all(); @@ -525,7 +546,11 @@ function draw() { if (gps_on) { msg = gpsHandle(); } else { - msg = note; + let o = Bangle.getOptions(); + msg = o.seaLevelPressure.toFixed(1) + "hPa"; + if (note != "") { + msg = note; + } } drawBackground(); @@ -551,7 +576,7 @@ function draw() { let alt_adjust = cur_altitude - rest_altitude; let abs = Math.abs(alt_adjust); print("adj", alt_adjust); - var o = Bangle.getOptions(); + let o = Bangle.getOptions(); if (abs > 10 && abs < 150) { let a = 0.01; // FIXME: draw is called often compared to alt reading @@ -588,16 +613,16 @@ function draw_all() { let now = new Date(); g.drawString(now.getHours() + ":" + add0(now.getMinutes()) + ":" + add0(now.getSeconds()), 10, 40); - var acc = Bangle.getAccel(); + let acc = Bangle.getAccel(); let ax = 0 + acc.x, ay = 0.75 + acc.y, az = 0.75 + acc.y; let diff = ax * ax + ay * ay + az * az; diff = diff * 3; if (diff > 1) diff = 1; - var co = Bangle.getCompass(); - var step = Bangle.getStepCount(); - var bat = E.getBattery(); + let co = Bangle.getCompass(); + let step = Bangle.getStepCount(); + let bat = E.getBattery(); Bangle.getPressure().then((x) => { alt = x.altitude; temp = x.temperature; }, print); @@ -618,7 +643,7 @@ function draw_all() { g.fillCircle(cx + sc * co.dx / 300, cy + sc * co.dz / 400, 5); } if (1) { - h = co.heading / 360 * 2 * Math.PI; + let h = co.heading / 360 * 2 * Math.PI; g.setColor(0, 0, 0.5); g.fillCircle(cx + sc * Math.sin(h), cy + sc * Math.cos(h), 5); } @@ -635,10 +660,10 @@ function draw_all() { queueDraw(); } function accelTask() { - var tm = 100; - var acc = Bangle.getAccel(); - var en = !Bangle.isLocked(); - var msg; + let tm = 100; + let acc = Bangle.getAccel(); + let en = !Bangle.isLocked(); + let msg = ""; if (en && acc.z < -0.95) { msg = "Level"; doBuzz(".-.."); @@ -654,14 +679,14 @@ function accelTask() { doBuzz("..-"); tm = 3000; } - + print(msg); setTimeout(accelTask, tm); } function buzzTask() { if (buzz != "") { - var now = buzz[0]; + let now = buzz[0]; buzz = buzz.substring(1); - var dot = 100; + let dot = 100; if (now == " ") { setTimeout(buzzTask, 300); } else if (now == ".") { @@ -675,13 +700,14 @@ function buzzTask() { } else print("Unknown character -- ", now, buzz); } } +var last_acc; function aliveTask() { function cmp(s) { let d = acc[s] - last_acc[s]; return d < -0.03 || d > 0.03; } // HRM seems to detect hand quite nicely - acc = Bangle.getAccel(); + let acc = Bangle.getAccel(); is_active = false; if (cmp("x") || cmp("y") || cmp("z")) { print("active"); @@ -700,7 +726,8 @@ function lockHandler(locked) { } function queueDraw() { - if (getTime() - last_unlocked > 5*60) + let next; + if (getTime() - last_unlocked > 3*60) next = 60000; else next = 1000; @@ -716,8 +743,6 @@ function start() { Bangle.on("drag", touchHandler); Bangle.on("lock", lockHandler); - if (0) - Bangle.on("accel", accelHandler); if (0) { Bangle.setCompassPower(1, "sixths"); Bangle.setBarometerPower(1, "sixths"); @@ -729,8 +754,10 @@ function start() { } draw(); + loadWPs(); buzzTask(); - //accelTask(); + if (0) + accelTask(); if (1) { last_acc = Bangle.getAccel();