From 73f9511128b709b5a465c280498d29d39c687124 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Thu, 27 Jan 2022 20:18:57 +0100 Subject: [PATCH 01/27] Fix sunprogress calculation during night --- apps/circlesclock/app.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 5b7569d63..7c9645159 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -504,12 +504,12 @@ function getSunProgress() { } } else { // during night - if (sunSet < sunRise) { - const upcomingSunRise = sunRise + 60 * 60 * 24; - return 1 - (upcomingSunRise - now) / (upcomingSunRise - sunSet); + if (now < sunRise) { + const prevSunSet = sunSet - 60 * 60 * 24; + return 1- (sunRise - now) / (sunRise - prevSunSet); } else { - const lastSunSet = sunSet - 60 * 60 * 24; - return (now - lastSunSet) / (sunRise - lastSunSet); + const upcomingSunRise = sunRise + 60 * 60 * 24; + return (upcomingSunRise - now) / (upcomingSunRise - sunSet); } } } From d7ecbc865bcd9ad683362629621a17ada6259dcb Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Thu, 27 Jan 2022 20:20:01 +0100 Subject: [PATCH 02/27] Fix icon position if four circles are used --- apps/circlesclock/app.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 7c9645159..50a4c0095 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -100,6 +100,7 @@ const radiusOuter = circleCount == 3 ? 25 : 20; const radiusInner = circleCount == 3 ? 20 : 15; const circleFont = circleCount == 3 ? "Vector:15" : "Vector:12"; const circleFontBig = circleCount == 3 ? "Vector:16" : "Vector:13"; +const iconOffset = circleCount == 3 ? 6 : 8; const defaultCircleTypes = ["steps", "hr", "battery", "weather"]; @@ -226,7 +227,7 @@ function drawSteps(w) { writeCircleText(w, shortValue(steps)); - g.drawImage(shoesIcon, w - 6, h3 + radiusOuter - 6); + g.drawImage(shoesIcon, w - iconOffset, h3 + radiusOuter - iconOffset); } function drawStepsDistance(w) { @@ -248,7 +249,7 @@ function drawStepsDistance(w) { writeCircleText(w, shortValue(stepsDistance)); - g.drawImage(shoesIconGreen, w - 6, h3 + radiusOuter - 6); + g.drawImage(shoesIconGreen, w - iconOffset, h3 + radiusOuter - iconOffset); } function drawHeartRate(w) { @@ -267,7 +268,7 @@ function drawHeartRate(w) { writeCircleText(w, hrtValue != undefined ? hrtValue : "-"); - g.drawImage(heartIcon, w - 6, h3 + radiusOuter - 6); + g.drawImage(heartIcon, w - iconOffset, h3 + radiusOuter - iconOffset); } function drawBattery(w) { @@ -296,7 +297,7 @@ function drawBattery(w) { } writeCircleText(w, battery + '%'); - g.drawImage(icon, w - 6, h3 + radiusOuter - 6); + g.drawImage(icon, w - iconOffset, h3 + radiusOuter - iconOffset); } function drawWeather(w) { @@ -337,7 +338,7 @@ function drawWeather(w) { if (code > 0) { const icon = getWeatherIconByCode(code); - if (icon) g.drawImage(icon, w - 6, h3 + radiusOuter - 10); + if (icon) g.drawImage(icon, w - iconOffset, h3 + radiusOuter - iconOffset); } else { g.drawString("?", w, h3 + radiusOuter); } @@ -389,7 +390,7 @@ function drawSunProgress(w) { writeCircleText(w, text); - g.drawImage(icon, w - 6, h3 + radiusOuter - 6); + g.drawImage(icon, w - iconOffset, h3 + radiusOuter - iconOffset); } From 546c8efa58a16e41a73561c36581da1bae0d7072 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Thu, 27 Jan 2022 21:36:25 +0100 Subject: [PATCH 03/27] Inital support for temperature and pressure from internal watch sensor --- apps/circlesclock/README.md | 5 +++ apps/circlesclock/app.js | 77 ++++++++++++++++++++++++++++++++++- apps/circlesclock/settings.js | 12 +++--- 3 files changed, 86 insertions(+), 8 deletions(-) diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index 242adcf4b..869bc238a 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -14,6 +14,8 @@ It can show the following information (this can be configured): * Temperature inside circle * Condition as icon below circle * Time and progress until next sunrise or sunset (requires [my location app](https://banglejs.com/apps/#mylocation)) + * Temperature from internal watch sensor + * Air pressure from internal watch sensor ## Screenshots ![Screenshot dark theme](screenshot-dark.png) @@ -21,6 +23,9 @@ It can show the following information (this can be configured): ![Screenshot dark theme with four circles](screenshot-dark-4.png) ![Screenshot light theme with four circles](screenshot-light-4.png) +## Ideas +* Make colors configurable + ## Creator Marco ([myxor](https://github.com/myxor)) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 50a4c0095..14efd4539 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -149,6 +149,7 @@ function drawCircle(index) { let type = settings['circle' + index]; if (!type) type = defaultCircleTypes[index - 1]; const w = getCirclePosition(type); + switch (type) { case "steps": drawSteps(w); @@ -169,6 +170,12 @@ function drawCircle(index) { case "sunProgress": drawSunProgress(w); break; + case "temperature": + drawTemperature(w); + break; + case "pressure": + drawPressure(w); + break; case "empty": // we draw nothing here return; @@ -391,7 +398,55 @@ function drawSunProgress(w) { writeCircleText(w, text); g.drawImage(icon, w - iconOffset, h3 + radiusOuter - iconOffset); +} +function drawTemperature(w) { + if (!w) w = getCirclePosition("temperature"); + getPressureValue("temperature").then((temperature) => { + + drawCircleBackground(w); + + if (temperature && temperature > 0) { + const percent = temperature / 100; // TODO: find good max for temperature + drawGauge(w, h3, percent, colorGreen); + } + + drawInnerCircleAndTriangle(w); + + let icon = powerIcon; + let color = colorFg; + if (temperature && temperature > 0) + writeCircleText(w, locale.temp(temperature)); + + g.drawImage(icon, w - iconOffset, h3 + radiusOuter - iconOffset); + + }); +} + +function drawPressure(w) { + if (!w) w = getCirclePosition("pressure"); + getPressureValue("pressure").then((pressure) => { + + drawCircleBackground(w); + + if (pressure && pressure > 0) { + + const minPressure = 870; + const maxPressure = 1080; + const percent = (pressure - minPressure) / (maxPressure - minPressure); + drawGauge(w, h3, percent, colorGreen); + } + + drawInnerCircleAndTriangle(w); + + let icon = powerIcon; + let color = colorFg; + if (pressure && pressure > 0) + writeCircleText(w, pressure); + + g.drawImage(icon, w - iconOffset, h3 + radiusOuter - iconOffset); + + }); } /* @@ -479,7 +534,7 @@ function formatSeconds(s) { function getSunData() { if (location != undefined && location.lat != undefined) { // get today's sunlight times for lat/lon - return SunCalc.getTimes(new Date(), location.lat, location.lon); + return SunCalc ? SunCalc.getTimes(new Date(), location.lat, location.lon) : undefined; } return undefined; } @@ -507,7 +562,7 @@ function getSunProgress() { // during night if (now < sunRise) { const prevSunSet = sunSet - 60 * 60 * 24; - return 1- (sunRise - now) / (sunRise - prevSunSet); + return 1 - (sunRise - now) / (sunRise - prevSunSet); } else { const upcomingSunRise = sunRise + 60 * 60 * 24; return (upcomingSunRise - now) / (upcomingSunRise - sunSet); @@ -608,6 +663,24 @@ function enableHRMSensor() { } } +function getPressureValue(type) { + return new Promise((resolve) => { + if (Bangle.getPressure) { + Bangle.getPressure().then(function(d) { + if (d) { + resolve(d[type]); + } + }).catch(function(e) {}); + } else { + switch (type) { + case "temperature": + resolve(E.getTemperature()); + break; + } + } + }); +} + Bangle.on('lock', function(isLocked) { if (!isLocked) { if (isCircleEnabled("hr")) { diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 1c072fc90..5cb2e9bfc 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -7,8 +7,8 @@ storage.write(SETTINGS_FILE, settings); } - const valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather", "sunprogress", "empty"]; - const namesCircleTypes = ["steps", "distance", "heart", "battery", "weather", "sun progress", "empty"]; + const valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather", "sunprogress", "empty", "temperature", "pressure"]; + const namesCircleTypes = ["steps", "distance", "heart", "battery", "weather", "sun progress", "empty", "temperature", "pressure"]; const weatherData = ["humidity", "wind", "empty"]; @@ -105,25 +105,25 @@ }, 'circle1': { value: settings.circle1 ? valuesCircleTypes.indexOf(settings.circle1) : 0, - min: 0, max: 6, + min: 0, max: valuesCircleTypes.length, format: v => namesCircleTypes[v], onchange: x => save('circle1', valuesCircleTypes[x]), }, 'circle2': { value: settings.circle2 ? valuesCircleTypes.indexOf(settings.circle2) : 2, - min: 0, max: 6, + min: 0, max: valuesCircleTypes.length, format: v => namesCircleTypes[v], onchange: x => save('circle2', valuesCircleTypes[x]), }, 'circle3': { value: settings.circle3 ? valuesCircleTypes.indexOf(settings.circle3) : 3, - min: 0, max: 6, + min: 0, max: valuesCircleTypes.length, format: v => namesCircleTypes[v], onchange: x => save('circle3', valuesCircleTypes[x]), }, 'circle4': { value: settings.circle4 ? valuesCircleTypes.indexOf(settings.circle4) : 4, - min: 0, max: 6, + min: 0, max: valuesCircleTypes.length, format: v => namesCircleTypes[v], onchange: x => save('circle4', valuesCircleTypes[x]), } From 9896b85e16485ea433a23ab72ee8e9ce428c0342 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Thu, 27 Jan 2022 22:20:32 +0100 Subject: [PATCH 04/27] Further support for temperature, air pressure or altitude from internal pressure sensor --- apps/circlesclock/ChangeLog | 1 + apps/circlesclock/README.md | 3 +- apps/circlesclock/app.js | 139 ++++++++++++++++++++++++---------- apps/circlesclock/settings.js | 4 +- 4 files changed, 104 insertions(+), 43 deletions(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index 4a23c944f..fe3fd23fd 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -13,3 +13,4 @@ Load daily steps from Bangle health if available 0.07: Allow configuration of minimal heart rate confidence 0.08: Allow configuration of up to 4 circles in a row +0.09: Support to show temperature, air pressure or altitude from internal pressure sensor diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index 869bc238a..a3b713d76 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -14,8 +14,7 @@ It can show the following information (this can be configured): * Temperature inside circle * Condition as icon below circle * Time and progress until next sunrise or sunset (requires [my location app](https://banglejs.com/apps/#mylocation)) - * Temperature from internal watch sensor - * Air pressure from internal watch sensor + * Temperature, air pressure or altitude from internal pressure sensor ## Screenshots ![Screenshot dark theme](screenshot-dark.png) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 14efd4539..8f223978f 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -9,6 +9,7 @@ const heartIcon = heatshrink.decompress(atob("h0OwYOLkmQhMkgACByVJgESpIFBpEEBAIF const powerIcon = heatshrink.decompress(atob("h0OwYQNsAED7AEDmwEDtu2AgUbtuABwXbBIUN23AAoYOCgEDFIgODABI")); const powerIconGreen = heatshrink.decompress(atob("h0OwYQNkAEDpAEDiQEDkmSAgUJkmABwVJBIUEyVAAoYOCgEBFIgODABI")); const powerIconRed = heatshrink.decompress(atob("h0OwYQNoAEDyAEDkgEDpIFDiVJBweSAgUJkmAAoYZDgQpEBwYAJA")); +const themperatureIcon = heatshrink.decompress(atob("h0OwIFChkAvEBkEHwEeAwXgh+An8A/gGBgYWCA==")); const weatherCloudy = heatshrink.decompress(atob("iEQwYWTgP//+AAoMPAoPwAoN/AocfAgP//0AAgQAB/AFEABgdDAAMDDohMRA")); const weatherSunny = heatshrink.decompress(atob("iEQwYLIg3AAgVgAQMMAo8Am3YAgUB23bAoUNAoIUBjYFCsOwBYoFDDpFgHYI1JI4gFGAAYA=")); @@ -176,6 +177,9 @@ function drawCircle(index) { case "pressure": drawPressure(w); break; + case "altitude": + drawAltitude(w); + break; case "empty": // we draw nothing here return; @@ -402,51 +406,103 @@ function drawSunProgress(w) { function drawTemperature(w) { if (!w) w = getCirclePosition("temperature"); - getPressureValue("temperature").then((temperature) => { - drawCircleBackground(w); + drawCircleBackground(w); + g.setColor(colorFg); - if (temperature && temperature > 0) { - const percent = temperature / 100; // TODO: find good max for temperature - drawGauge(w, h3, percent, colorGreen); - } + const delay = pressureLocked ? 1000 : 0; + setTimeout(() => { + getPressureValue("temperature").then((temperature) => { - drawInnerCircleAndTriangle(w); + pressureLocked = false; - let icon = powerIcon; - let color = colorFg; - if (temperature && temperature > 0) - writeCircleText(w, locale.temp(temperature)); + if (temperature) { + const percent = temperature / 100; // TODO: find good max for temperature + drawGauge(w, h3, percent, colorGreen); + } - g.drawImage(icon, w - iconOffset, h3 + radiusOuter - iconOffset); + drawInnerCircleAndTriangle(w); - }); + if (temperature) + writeCircleText(w, locale.temp(temperature)); + + g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); + + }).catch(() => { + pressureLocked = false; + drawInnerCircleAndTriangle(w); + writeCircleText(w, "?"); + g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); + }); + }, delay); } function drawPressure(w) { if (!w) w = getCirclePosition("pressure"); - getPressureValue("pressure").then((pressure) => { - drawCircleBackground(w); + drawCircleBackground(w); + g.setColor(colorFg); - if (pressure && pressure > 0) { + const delay = pressureLocked ? 1000 : 0; + setTimeout(() => { + getPressureValue("pressure").then((pressure) => { + pressureLocked = false; - const minPressure = 870; - const maxPressure = 1080; - const percent = (pressure - minPressure) / (maxPressure - minPressure); - drawGauge(w, h3, percent, colorGreen); - } + if (pressure && pressure > 0) { + const minPressure = 900; + const maxPressure = 1050; + const percent = (pressure - minPressure) / (maxPressure - minPressure); + drawGauge(w, h3, percent, colorGreen); + } - drawInnerCircleAndTriangle(w); + drawInnerCircleAndTriangle(w); - let icon = powerIcon; - let color = colorFg; - if (pressure && pressure > 0) - writeCircleText(w, pressure); + if (pressure) + writeCircleText(w, pressure); - g.drawImage(icon, w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); - }); + }).catch(() => { + pressureLocked = false; + drawInnerCircleAndTriangle(w); + writeCircleText(w, "?"); + g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); + }); + }, delay); +} + +function drawAltitude(w) { + if (!w) w = getCirclePosition("altitude"); + + drawCircleBackground(w); + g.setColor(colorFg); + + const delay = pressureLocked ? 1000 : 0; + setTimeout(() => { + getPressureValue("altitude").then((altitude) => { + pressureLocked = false; + + if (altitude) { + const min = -1000; + const max = 10000; + const percent = (pressure - min) / (max - min); + drawGauge(w, h3, percent, colorGreen); + } + + drawInnerCircleAndTriangle(w); + + if (altitude) + writeCircleText(w, altitude); + + g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); + + }).catch(() => { + pressureLocked = false; + drawInnerCircleAndTriangle(w); + writeCircleText(w, "?"); + g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); + }); + }, delay); } /* @@ -663,20 +719,25 @@ function enableHRMSensor() { } } +let pressureLocked = false; + function getPressureValue(type) { - return new Promise((resolve) => { + return new Promise((resolve, reject) => { if (Bangle.getPressure) { - Bangle.getPressure().then(function(d) { - if (d) { - resolve(d[type]); - } - }).catch(function(e) {}); - } else { - switch (type) { - case "temperature": - resolve(E.getTemperature()); - break; + if (!pressureLocked) { + pressureLocked = true; + Bangle.getPressure().then(function(d) { + if (d && d[type]) { + resolve(d[type]); + } else { + reject(); + } + }).catch(reject); + } else { + reject(); } + } else { + reject(); } }); } diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 5cb2e9bfc..eb70203a3 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -7,8 +7,8 @@ storage.write(SETTINGS_FILE, settings); } - const valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather", "sunprogress", "empty", "temperature", "pressure"]; - const namesCircleTypes = ["steps", "distance", "heart", "battery", "weather", "sun progress", "empty", "temperature", "pressure"]; + const valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather", "sunprogress", "empty", "temperature", "pressure", "altitude"]; + const namesCircleTypes = ["steps", "distance", "heart", "battery", "weather", "sun progress", "empty", "temperature", "pressure", "altitude"]; const weatherData = ["humidity", "wind", "empty"]; From 075889f4d3ad4ba7a475c0356ab4c9c3ea90f65c Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 28 Jan 2022 10:19:00 +0100 Subject: [PATCH 05/27] Improvements for pressure sensor values --- apps/circlesclock/app.js | 140 ++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 74 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 8f223978f..b17345d42 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -407,102 +407,85 @@ function drawSunProgress(w) { function drawTemperature(w) { if (!w) w = getCirclePosition("temperature"); - drawCircleBackground(w); - g.setColor(colorFg); + getPressureValue("temperature").then((temperature) => { + drawCircleBackground(w); + g.setColor(colorFg); - const delay = pressureLocked ? 1000 : 0; - setTimeout(() => { - getPressureValue("temperature").then((temperature) => { + drawInnerCircleAndTriangle(w); - pressureLocked = false; + if (temperature) { + const min = -40; // TODO: find good min, max for temperature + const max = 85; + const percent = (temperature - min) / (max - min); + drawGauge(w, h3, percent, colorGreen); + } - if (temperature) { - const percent = temperature / 100; // TODO: find good max for temperature - drawGauge(w, h3, percent, colorGreen); - } + if (temperature) + writeCircleText(w, locale.temp(temperature)); - drawInnerCircleAndTriangle(w); + g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); - if (temperature) - writeCircleText(w, locale.temp(temperature)); - - g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); - - }).catch(() => { - pressureLocked = false; - drawInnerCircleAndTriangle(w); - writeCircleText(w, "?"); - g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); - }); - }, delay); + }).catch(() => { + setTimeout(() => { + drawTemperature(); + }, 1000); + }); } function drawPressure(w) { if (!w) w = getCirclePosition("pressure"); - drawCircleBackground(w); - g.setColor(colorFg); + getPressureValue("pressure").then((pressure) => { + drawCircleBackground(w); + g.setColor(colorFg); - const delay = pressureLocked ? 1000 : 0; - setTimeout(() => { - getPressureValue("pressure").then((pressure) => { - pressureLocked = false; + drawInnerCircleAndTriangle(w); - if (pressure && pressure > 0) { - const minPressure = 900; - const maxPressure = 1050; - const percent = (pressure - minPressure) / (maxPressure - minPressure); - drawGauge(w, h3, percent, colorGreen); - } + if (pressure && pressure > 0) { + const minPressure = 900; + const maxPressure = 1050; + const percent = (pressure - minPressure) / (maxPressure - minPressure); + drawGauge(w, h3, percent, colorGreen); + } - drawInnerCircleAndTriangle(w); + if (pressure) + writeCircleText(w, Math.round(pressure)); - if (pressure) - writeCircleText(w, pressure); + g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); - g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); - - }).catch(() => { - pressureLocked = false; - drawInnerCircleAndTriangle(w); - writeCircleText(w, "?"); - g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); - }); - }, delay); + }).catch(() => { + setTimeout(() => { + drawPressure(w); + }, 1000); + }); } function drawAltitude(w) { if (!w) w = getCirclePosition("altitude"); - drawCircleBackground(w); - g.setColor(colorFg); + getPressureValue("altitude").then((altitude) => { + drawCircleBackground(w); + g.setColor(colorFg); - const delay = pressureLocked ? 1000 : 0; - setTimeout(() => { - getPressureValue("altitude").then((altitude) => { - pressureLocked = false; + drawInnerCircleAndTriangle(w); - if (altitude) { - const min = -1000; - const max = 10000; - const percent = (pressure - min) / (max - min); - drawGauge(w, h3, percent, colorGreen); - } + if (altitude) { + const min = 0; + const max = 10000; + const percent = (altitude - min) / (max - min); + drawGauge(w, h3, percent, colorGreen); + } - drawInnerCircleAndTriangle(w); + if (altitude) + writeCircleText(w, locale.distance(Math.round(altitude))); - if (altitude) - writeCircleText(w, altitude); + g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); - g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); - - }).catch(() => { - pressureLocked = false; - drawInnerCircleAndTriangle(w); - writeCircleText(w, "?"); - g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); - }); - }, delay); + }).catch(() => { + setTimeout(() => { + drawAltitude(w); + }, 1000); + }); } /* @@ -720,6 +703,7 @@ function enableHRMSensor() { } let pressureLocked = false; +let lastPressureValue; function getPressureValue(type) { return new Promise((resolve, reject) => { @@ -727,14 +711,22 @@ function getPressureValue(type) { if (!pressureLocked) { pressureLocked = true; Bangle.getPressure().then(function(d) { - if (d && d[type]) { - resolve(d[type]); + pressureLocked = false; + if (d) { + lastPressureValue = d; + if (d[type]) { + resolve(d[type]); + } } else { reject(); } }).catch(reject); } else { - reject(); + if (lastPressureValue && lastPressureValue[type]) { + resolve(lastPressureValue[type]); + } else { + reject(); + } } } else { reject(); From efbd6be868be608f3fccb1a59950f91c9cff4dd3 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 28 Jan 2022 10:19:29 +0100 Subject: [PATCH 06/27] Improve font size choosing for circle inner text --- apps/circlesclock/app.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index b17345d42..c279cd830 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -97,8 +97,9 @@ const circlePosX = [ Math.round(7 * w / parts), // circle4 ]; -const radiusOuter = circleCount == 3 ? 25 : 20; +const radiusOuter = circleCount == 3 ? 25 : 19; const radiusInner = circleCount == 3 ? 20 : 15; +const circleFontSmall = circleCount == 3 ? "Vector:14" : "Vector:11"; const circleFont = circleCount == 3 ? "Vector:15" : "Vector:12"; const circleFontBig = circleCount == 3 ? "Vector:16" : "Vector:13"; const iconOffset = circleCount == 3 ? 6 : 8; @@ -638,8 +639,8 @@ function radians(a) { */ function drawGauge(cx, cy, percent, color) { const offset = 15; - const end = 345; - const radius = radiusInner + 3; + const end = 360 - offset; + const radius = radiusInner + (circleCount == 3 ? 3 : 2); const size = radiusOuter - radiusInner - 2; if (percent <= 0) return; @@ -659,7 +660,8 @@ function drawGauge(cx, cy, percent, color) { function writeCircleText(w, content) { if (content == undefined) return; - g.setFont(content.length < 4 ? circleFontBig : circleFont); + const font = String(content).length > 3 ? circleFontSmall : String(content).length > 2 ? circleFont : circleFontBig; + g.setFont(font); g.setFontAlign(0, 0); g.setColor(colorFg); From 4e7833b808b8c6e846ac18564f4a05dce0cdc807 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 28 Jan 2022 12:02:09 +0100 Subject: [PATCH 07/27] Update readme --- apps/circlesclock/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index a3b713d76..51429cb4b 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -24,6 +24,7 @@ It can show the following information (this can be configured): ## Ideas * Make colors configurable +* Show compass heading ## Creator Marco ([myxor](https://github.com/myxor)) From f9d2d59e60969ea63f75ad71c13079d8cf48a2c6 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 28 Jan 2022 13:19:15 +0100 Subject: [PATCH 08/27] Cache for pressure values to get faster drawing + some layout improvements --- apps/circlesclock/app.js | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index c279cd830..be12342c1 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -70,6 +70,7 @@ const colorGreen = '#008000'; const colorBlue = '#0000ff'; const colorYellow = '#ffff00'; const widgetOffset = showWidgets ? 24 : 0; +const dowOffset = circleCount == 3 ? 22 : 24; // dow offset relative to date const h = g.getHeight() - widgetOffset; const w = g.getWidth(); const hOffset = 30 - widgetOffset; @@ -107,8 +108,6 @@ const defaultCircleTypes = ["steps", "hr", "battery", "weather"]; function draw() { - g.clear(true); - if (!showWidgets) { /* * we are not drawing the widgets as we are taking over the whole screen @@ -125,8 +124,9 @@ function draw() { Bangle.drawWidgets(); } + g.clearRect(0, widgetOffset, w, h2 + 22); g.setColor(colorBg); - g.fillRect(0, widgetOffset, w, h); + g.fillRect(0, widgetOffset, w, h2 + 22); // time g.setFont("Vector:50"); @@ -139,7 +139,7 @@ function draw() { g.setFont("Vector:21"); g.setFontAlign(-1, 0); g.drawString(locale.date(new Date()), w > 180 ? 2 * w / 10 : w / 10, h2); - g.drawString(locale.dow(new Date()), w > 180 ? 2 * w / 10 : w / 10, h2 + 22); + g.drawString(locale.dow(new Date()), w > 180 ? 2 * w / 10 : w / 10, h2 + dowOffset); drawCircle(1); drawCircle(2); @@ -410,7 +410,6 @@ function drawTemperature(w) { getPressureValue("temperature").then((temperature) => { drawCircleBackground(w); - g.setColor(colorFg); drawInnerCircleAndTriangle(w); @@ -438,12 +437,11 @@ function drawPressure(w) { getPressureValue("pressure").then((pressure) => { drawCircleBackground(w); - g.setColor(colorFg); drawInnerCircleAndTriangle(w); if (pressure && pressure > 0) { - const minPressure = 900; + const minPressure = 950; const maxPressure = 1050; const percent = (pressure - minPressure) / (maxPressure - minPressure); drawGauge(w, h3, percent, colorGreen); @@ -466,7 +464,6 @@ function drawAltitude(w) { getPressureValue("altitude").then((altitude) => { drawCircleBackground(w); - g.setColor(colorFg); drawInnerCircleAndTriangle(w); @@ -614,6 +611,7 @@ function getSunProgress() { * Draws the background and the grey circle */ function drawCircleBackground(w) { + g.clearRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); // Draw rectangle background: g.setColor(colorBg); g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); @@ -705,17 +703,22 @@ function enableHRMSensor() { } let pressureLocked = false; -let lastPressureValue; +let pressureCache; function getPressureValue(type) { return new Promise((resolve, reject) => { if (Bangle.getPressure) { if (!pressureLocked) { pressureLocked = true; + if (pressureCache && pressureCache[type]) { + resolve(pressureCache[type]); + } else { + reject(); + } Bangle.getPressure().then(function(d) { pressureLocked = false; if (d) { - lastPressureValue = d; + pressureCache = d; if (d[type]) { resolve(d[type]); } @@ -724,8 +727,8 @@ function getPressureValue(type) { } }).catch(reject); } else { - if (lastPressureValue && lastPressureValue[type]) { - resolve(lastPressureValue[type]); + if (pressureCache && pressureCache[type]) { + resolve(pressureCache[type]); } else { reject(); } @@ -762,6 +765,8 @@ Bangle.on('HRM', function(hrm) { Bangle.setUI("clock"); Bangle.loadWidgets(); +g.clear(true); + draw(); setInterval(draw, 60000); From 2fe7872fd8cf3ea62386744eddee95ccf694fbe7 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 28 Jan 2022 21:48:07 +0100 Subject: [PATCH 09/27] Fix drawing --- apps/circlesclock/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index be12342c1..79b2f7319 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -108,6 +108,7 @@ const defaultCircleTypes = ["steps", "hr", "battery", "weather"]; function draw() { + g.reset(true); if (!showWidgets) { /* * we are not drawing the widgets as we are taking over the whole screen From eacd618eae1591d9ef14bdbee83c2e2c80b1938a Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sat, 29 Jan 2022 13:40:34 +0100 Subject: [PATCH 10/27] Fix drawing --- apps/circlesclock/app.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 79b2f7319..29b8b2cbb 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -108,7 +108,7 @@ const defaultCircleTypes = ["steps", "hr", "battery", "weather"]; function draw() { - g.reset(true); + g.clear(true); if (!showWidgets) { /* * we are not drawing the widgets as we are taking over the whole screen @@ -125,7 +125,6 @@ function draw() { Bangle.drawWidgets(); } - g.clearRect(0, widgetOffset, w, h2 + 22); g.setColor(colorBg); g.fillRect(0, widgetOffset, w, h2 + 22); @@ -742,10 +741,10 @@ function getPressureValue(type) { Bangle.on('lock', function(isLocked) { if (!isLocked) { + draw(); if (isCircleEnabled("hr")) { enableHRMSensor(); } - draw(); } else { Bangle.setHRMPower(0, "circleclock"); } @@ -762,6 +761,15 @@ Bangle.on('HRM', function(hrm) { } }); +Bangle.on('charging', function(charging) { + if (isCircleEnabled("battery")) drawBattery(); +}); + +if (isCircleEnabled("hr")) { + enableHRMSensor(); +} + + Bangle.setUI("clock"); Bangle.loadWidgets(); @@ -770,11 +778,3 @@ g.clear(true); draw(); setInterval(draw, 60000); - -Bangle.on('charging', function(charging) { - if (isCircleEnabled("battery")) drawBattery(); -}); - -if (isCircleEnabled("hr")) { - enableHRMSensor(); -} From 1207fc41303c1baa1700b5d049b588147c3e2d32 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sat, 29 Jan 2022 13:43:35 +0100 Subject: [PATCH 11/27] Update changelog --- apps/circlesclock/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index fe3fd23fd..4e3af24b5 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -14,3 +14,4 @@ 0.07: Allow configuration of minimal heart rate confidence 0.08: Allow configuration of up to 4 circles in a row 0.09: Support to show temperature, air pressure or altitude from internal pressure sensor + Fix sunprogress calculation during night From 40ee16c8730c8c741441cd907af1a08c96d5b544 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sat, 29 Jan 2022 13:47:42 +0100 Subject: [PATCH 12/27] Clean up --- apps/circlesclock/app.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 29b8b2cbb..e4e42f665 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -770,11 +770,8 @@ if (isCircleEnabled("hr")) { } - Bangle.setUI("clock"); Bangle.loadWidgets(); -g.clear(true); - draw(); setInterval(draw, 60000); From 7de40d9c8cdae94e260ed35306e34dd283151ed2 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sat, 29 Jan 2022 21:51:44 +0100 Subject: [PATCH 13/27] Refactor settings menu & make colors of circles configurable --- apps/circlesclock/ChangeLog | 2 + apps/circlesclock/README.md | 1 - apps/circlesclock/app.js | 155 ++++++++++++--------- apps/circlesclock/settings.js | 247 +++++++++++++++++++--------------- 4 files changed, 233 insertions(+), 172 deletions(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index 4e3af24b5..0393613e0 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -15,3 +15,5 @@ 0.08: Allow configuration of up to 4 circles in a row 0.09: Support to show temperature, air pressure or altitude from internal pressure sensor Fix sunprogress calculation during night + Refactor settings menu + Colors of circles can be configured diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index 51429cb4b..325d6f838 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -23,7 +23,6 @@ It can show the following information (this can be configured): ![Screenshot light theme with four circles](screenshot-light-4.png) ## Ideas -* Make colors configurable * Show compass heading ## Creator diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index e4e42f665..520f7f748 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -1,28 +1,24 @@ const locale = require("locale"); -const heatshrink = require("heatshrink"); const storage = require("Storage"); const SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js"); -const shoesIcon = heatshrink.decompress(atob("h0OwYJGgmAAgUBkgECgVJB4cSoAUDyEBkARDpADBhMAyQRBgVAkgmDhIUDAAuQAgY1DAAYA=")); -const shoesIconGreen = heatshrink.decompress(atob("h0OwYJGhIEDgVIAgUEyQKDkmACgcggVACIeQAYMSgIRCgmApIbDiQUDAAkBkAFDGoYAD")); -const heartIcon = heatshrink.decompress(atob("h0OwYOLkmQhMkgACByVJgESpIFBpEEBAIFBCgIFCCgsABwcAgQOCAAMSpAwDyBNM")); -const powerIcon = heatshrink.decompress(atob("h0OwYQNsAED7AEDmwEDtu2AgUbtuABwXbBIUN23AAoYOCgEDFIgODABI")); -const powerIconGreen = heatshrink.decompress(atob("h0OwYQNkAEDpAEDiQEDkmSAgUJkmABwVJBIUEyVAAoYOCgEBFIgODABI")); -const powerIconRed = heatshrink.decompress(atob("h0OwYQNoAEDyAEDkgEDpIFDiVJBweSAgUJkmAAoYZDgQpEBwYAJA")); -const themperatureIcon = heatshrink.decompress(atob("h0OwIFChkAvEBkEHwEeAwXgh+An8A/gGBgYWCA==")); +const shoesIcon = atob("EBCBAAAACAAcAB4AHgAeABwwADgGeAZ4AHgAMAAAAHAAIAAA"); +const heartIcon = atob("EBCBAAAAAAAeeD/8P/x//n/+P/w//B/4D/AH4APAAYAAAAAA"); +const powerIcon = atob("FBSBAAAAAAAAAfgAP8AH/gB/4Af+AH/gB/4Af+AH/gB/4Af+AH/gB/4Af+AH/gB/4AAAAAAA"); +const temperatureIcon = atob("EBCBAAAAAYADwAJAAkADwAPAA8ADwAfgB+AH4AfgA8ABgAAA"); -const weatherCloudy = heatshrink.decompress(atob("iEQwYWTgP//+AAoMPAoPwAoN/AocfAgP//0AAgQAB/AFEABgdDAAMDDohMRA")); -const weatherSunny = heatshrink.decompress(atob("iEQwYLIg3AAgVgAQMMAo8Am3YAgUB23bAoUNAoIUBjYFCsOwBYoFDDpFgHYI1JI4gFGAAYA=")); -const weatherMoon = heatshrink.decompress(atob("iEQwIFCgOAh/wj/4n/8AId//wBBBIoRBCoIZBDoI")); -const weatherPartlyCloudy = heatshrink.decompress(atob("iEQwYQNv0AjgGDn4EDh///gFChwREC4MfxwIBv0//+AC4X4j4FCv/AgfwgED/wIBuAaBBwgFDgP4gf/AAXABwIEBDQQAEA==")); -const weatherRainy = heatshrink.decompress(atob("iEQwYLIg/gAgUB///wAFBh/AgfwgED/wIBuEAj4OCv0AjgaCh/4AocAnAFBFIU4EAM//gRBEAIOBhw1C/AmDAosAC4JNIAAg")); -const weatherPartlyRainy = heatshrink.decompress(atob("h0OwYJGjkAnAFCj+AAgU//4FCuEA8EAg8ch/4gEB4////AAoIIBCIMD/wgCg4bBg/8BwMD+AgBh4ZBDQf/FIIABh4IBgAA==")); -const weatherSnowy = heatshrink.decompress(atob("iEQwYROn/8AocH8AECuAFBh0Agf+CIN/4EDx/4j/x4EAgIIBwAXBAogRFDoopFGoxBGABIA=")); -const weatherFoggy = heatshrink.decompress(atob("iEQwYROn/8AgUB/EfwAFBh/AgfwgED/wIBuEABwd/4EcDQgFDgE4Fosf///8f//A/Lj/xCQIRNA=")); -const weatherStormy = heatshrink.decompress(atob("iEQwYLIg/gAgUB///wAFBh/AgfwgED/wIBuEAj4OCv0AjgaCh/4AoX8gE4AoQpBnAdBF4IRBDQMH/kOHgY7DAo4AOA==")); +const weatherCloudy = atob("EBCBAAAAAAAAAAfgD/Af8H/4//7///////9//z/+AAAAAAAA"); +const weatherSunny = atob("EBCBAAAAAYAQCBAIA8AH4A/wb/YP8A/gB+ARiBAIAYABgAAA"); +const weatherMoon = atob("EBCBAAAAAYAP8B/4P/w//D/8f/5//j/8P/w//B/4D/ABgAAA"); +const weatherPartlyCloudy = atob("EBCBAAAAAAAYQAMAD8AIQBhoW+AOYBwwOBBgHGAGP/wf+AAA"); +const weatherRainy = atob("EBCBAAAAAYAH4AwwOBBgGEAOQAJBgjPOEkgGYAZgA8ABgAAA"); +const weatherPartlyRainy = atob("EBCBAAAAEEAQAAeADMAYaFvoTmAMMDgQIBxhhiGGG9wDwAGA"); +const weatherSnowy = atob("EBCBAAAAAAADwAGAEYg73C50BCAEIC50O9wRiAGAA8AAAAAA"); +const weatherFoggy = atob("EBCBAAAAAAADwAZgDDA4EGAcQAZAAgAAf74AAAAAd/4AAAAA"); +const weatherStormy = atob("EBCBAAAAAYAH4AwwOBBgGEAOQMJAgjmOGcgAgACAAAAAAAAA"); -const sunSetDown = heatshrink.decompress(atob("iEQwIHEgOAAocT5EGtEEkF//wLDg1ggfACoo")); -const sunSetUp = heatshrink.decompress(atob("iEQwIHEgOAAocT5EGtEEkF//wRFgfAg1gBIY")); +const sunSetDown = atob("EBCBAAAAAAABgAAAAAATyAZoBCB//gAAAAAGYAPAAYAAAAAA"); +const sunSetUp = atob("EBCBAAAAAAABgAAAAAATyAZoBCB//gAAAAABgAPABmAAAAAA"); let settings = storage.readJSON("circlesclock.json", 1) || { 'minHR': 40, @@ -42,7 +38,7 @@ let settings = storage.readJSON("circlesclock.json", 1) || { }; // Load step goal from pedometer widget as fallback if (settings.stepGoal == undefined) { - const d = require('Storage').readJSON("wpedom.json", 1) || {}; + const d = storage.readJSON("wpedom.json", 1) || {}; settings.stepGoal = d != undefined && d.settings != undefined ? d.settings.goal : 10000; } @@ -150,7 +146,7 @@ function draw() { function drawCircle(index) { let type = settings['circle' + index]; if (!type) type = defaultCircleTypes[index - 1]; - const w = getCirclePosition(type); + const w = getCircleXPosition(type); switch (type) { case "steps": @@ -199,133 +195,164 @@ let circlePositionsCache = []; */ function getCirclePosition(type) { if (circlePositionsCache[type] >= 0) { - return circlePosX[circlePositionsCache[type]]; + return circlePositionsCache[type]; } for (let i = 1; i <= circleCount; i++) { const setting = settings['circle' + i]; if (setting == type) { circlePositionsCache[type] = i - 1; - return circlePosX[i - 1]; + return i - 1; } } for (let i = 0; i < defaultCircleTypes.length; i++) { if (type == defaultCircleTypes[i] && (!settings || settings['circle' + (i + 1)] == undefined)) { circlePositionsCache[type] = i; - return circlePosX[i]; + return i; } } return undefined; } +function getCircleXPosition(type) { + const circlePos = getCirclePosition(type); + if (circlePos != undefined) { + return circlePosX[circlePos]; + } + return undefined; +} + function isCircleEnabled(type) { return getCirclePosition(type) != undefined; } +function getCircleColor(type) { + const pos = getCirclePosition(type); + const color = settings["circle" + (pos + 1) + "color"]; + if (color && color != "") return color; +} + +function getImage(graphic, color) { + return { + width: 16, + height: 16, + bpp: 1, + transparent: 0, + buffer: E.toArrayBuffer(graphic), + palette: new Uint16Array([colorBg, g.toColor(color)]) + }; +} + function drawSteps(w) { - if (!w) w = getCirclePosition("steps"); + if (!w) w = getCircleXPosition("steps"); const steps = getSteps(); drawCircleBackground(w); + const color = getCircleColor("steps") || colorBlue; + const stepGoal = settings.stepGoal || 10000; if (stepGoal > 0) { let percent = steps / stepGoal; if (stepGoal < steps) percent = 1; - drawGauge(w, h3, percent, colorBlue); + drawGauge(w, h3, percent, color); } drawInnerCircleAndTriangle(w); writeCircleText(w, shortValue(steps)); - g.drawImage(shoesIcon, w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(shoesIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawStepsDistance(w) { - if (!w) w = getCirclePosition("steps"); + if (!w) w = getCircleXPosition("stepsDistance"); const steps = getSteps(); const stepDistance = settings.stepLength || 0.8; const stepsDistance = Math.round(steps * stepDistance); drawCircleBackground(w); + const color = getCircleColor("stepsDistance") || colorGreen; + const stepDistanceGoal = settings.stepDistanceGoal || 8000; if (stepDistanceGoal > 0) { let percent = stepsDistance / stepDistanceGoal; if (stepDistanceGoal < stepsDistance) percent = 1; - drawGauge(w, h3, percent, colorGreen); + drawGauge(w, h3, percent, color); } drawInnerCircleAndTriangle(w); writeCircleText(w, shortValue(stepsDistance)); - g.drawImage(shoesIconGreen, w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(shoesIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawHeartRate(w) { - if (!w) w = getCirclePosition("hr"); + if (!w) w = getCircleXPosition("hr"); drawCircleBackground(w); + const color = getCircleColor("hr") || colorRed; + if (hrtValue != undefined) { const minHR = settings.minHR || 40; const maxHR = settings.maxHR || 200; const percent = (hrtValue - minHR) / (maxHR - minHR); - drawGauge(w, h3, percent, colorRed); + drawGauge(w, h3, percent, color); } drawInnerCircleAndTriangle(w); writeCircleText(w, hrtValue != undefined ? hrtValue : "-"); - g.drawImage(heartIcon, w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(heartIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawBattery(w) { - if (!w) w = getCirclePosition("battery"); + if (!w) w = getCircleXPosition("battery"); const battery = E.getBattery(); drawCircleBackground(w); + let color = getCircleColor("battery") || colorYellow; + if (battery > 0) { const percent = battery / 100; - drawGauge(w, h3, percent, colorYellow); + drawGauge(w, h3, percent, color); } drawInnerCircleAndTriangle(w); - let icon = powerIcon; - let color = colorFg; if (Bangle.isCharging()) { color = colorGreen; - icon = powerIconGreen; } else { if (settings.batteryWarn != undefined && battery <= settings.batteryWarn) { color = colorRed; - icon = powerIconRed; } } writeCircleText(w, battery + '%'); - g.drawImage(icon, w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(powerIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawWeather(w) { - if (!w) w = getCirclePosition("weather"); + if (!w) w = getCircleXPosition("weather"); const weather = getWeather(); const tempString = weather ? locale.temp(weather.temp - 273.15) : undefined; const code = weather ? weather.code : -1; drawCircleBackground(w); + const color = getCircleColor("weather") || colorYellow; + const data = settings.weatherCircleData || "humidity"; switch (data) { case "humidity": const humidity = weather ? weather.hum : undefined; if (humidity >= 0) { - drawGauge(w, h3, humidity / 100, colorYellow); + drawGauge(w, h3, humidity / 100, color); } break; case "wind": @@ -336,7 +363,7 @@ function drawWeather(w) { wind[1] = windAsBeaufort(wind[1]); } // wind goes from 0 to 12 (see https://en.wikipedia.org/wiki/Beaufort_scale) - drawGauge(w, h3, wind[1] / 12, colorYellow); + drawGauge(w, h3, wind[1] / 12, color); } } break; @@ -350,7 +377,7 @@ function drawWeather(w) { if (code > 0) { const icon = getWeatherIconByCode(code); - if (icon) g.drawImage(icon, w - iconOffset, h3 + radiusOuter - iconOffset); + if (icon) g.drawImage(getImage(icon, color), w - iconOffset, h3 + radiusOuter - iconOffset); } else { g.drawString("?", w, h3 + radiusOuter); } @@ -358,27 +385,25 @@ function drawWeather(w) { function drawSunProgress(w) { - if (!w) w = getCirclePosition("sunprogress"); + if (!w) w = getCircleXPosition("sunprogress"); const percent = getSunProgress(); drawCircleBackground(w); - drawGauge(w, h3, percent, colorYellow); + const color = getCircleColor("sunpgrogress") || colorYellow; + + drawGauge(w, h3, percent, color); drawInnerCircleAndTriangle(w); - let icon = powerIcon; - let color = colorFg; + let icon = sunSetDown; if (isDay()) { // day - color = colorFg; icon = sunSetDown; } else { // night - color = colorGrey; icon = sunSetUp; } - g.setColor(color); let text = "?"; const times = getSunData(); @@ -402,28 +427,30 @@ function drawSunProgress(w) { writeCircleText(w, text); - g.drawImage(icon, w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(icon, color), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawTemperature(w) { - if (!w) w = getCirclePosition("temperature"); + if (!w) w = getCircleXPosition("temperature"); getPressureValue("temperature").then((temperature) => { drawCircleBackground(w); + const color = getCircleColor("temperature") || colorGreen; + drawInnerCircleAndTriangle(w); if (temperature) { - const min = -40; // TODO: find good min, max for temperature + const min = -40; const max = 85; const percent = (temperature - min) / (max - min); - drawGauge(w, h3, percent, colorGreen); + drawGauge(w, h3, percent, color); } if (temperature) writeCircleText(w, locale.temp(temperature)); - g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(temperatureIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset); }).catch(() => { setTimeout(() => { @@ -433,24 +460,26 @@ function drawTemperature(w) { } function drawPressure(w) { - if (!w) w = getCirclePosition("pressure"); + if (!w) w = getCircleXPosition("pressure"); getPressureValue("pressure").then((pressure) => { drawCircleBackground(w); + const color = getCircleColor("pressure") || colorGreen; + drawInnerCircleAndTriangle(w); if (pressure && pressure > 0) { const minPressure = 950; const maxPressure = 1050; const percent = (pressure - minPressure) / (maxPressure - minPressure); - drawGauge(w, h3, percent, colorGreen); + drawGauge(w, h3, percent, color); } if (pressure) writeCircleText(w, Math.round(pressure)); - g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(temperatureIcon), w - iconOffset, h3 + radiusOuter - iconOffset); }).catch(() => { setTimeout(() => { @@ -460,24 +489,26 @@ function drawPressure(w) { } function drawAltitude(w) { - if (!w) w = getCirclePosition("altitude"); + if (!w) w = getCircleXPosition("altitude"); getPressureValue("altitude").then((altitude) => { drawCircleBackground(w); + const color = getCircleColor("altitude") || colorGreen; + drawInnerCircleAndTriangle(w); if (altitude) { const min = 0; const max = 10000; const percent = (altitude - min) / (max - min); - drawGauge(w, h3, percent, colorGreen); + drawGauge(w, h3, percent, color); } if (altitude) writeCircleText(w, locale.distance(Math.round(altitude))); - g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(temperatureIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset); }).catch(() => { setTimeout(() => { diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index eb70203a3..cc2ba7a1f 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -10,122 +10,151 @@ const valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather", "sunprogress", "empty", "temperature", "pressure", "altitude"]; const namesCircleTypes = ["steps", "distance", "heart", "battery", "weather", "sun progress", "empty", "temperature", "pressure", "altitude"]; + const valuesColors = ["", "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "#00ffff", "#fff", "#000"]; + const namesColors = ["default", "red", "green", "blue", "yellow", "magenta", "cyan", "white", "black"]; + const weatherData = ["humidity", "wind", "empty"]; - E.showMenu({ - '': { 'title': 'circlesclock' }, - '< Back': back, - 'min heartrate': { - value: "minHR" in settings ? settings.minHR : 40, - min: 0, - max : 250, - step: 5, - format: x => { - return x; + function showMainMenu() { + let menu ={ + '': { 'title': 'Circles clock' }, + /*LANG*/'< Back': back, + /*LANG*/'circle count': { + value: "circleCount" in settings ? settings.circleCount : 3, + min: 3, + max : 4, + step: 1, + onchange: x => save('circleCount', x), }, - onchange: x => save('minHR', x), - }, - 'max heartrate': { - value: "maxHR" in settings ? settings.maxHR : 200, - min: 20, - max : 250, - step: 5, - format: x => { - return x; + /*LANG*/'circle 1': ()=>showCircleMenu(1), + /*LANG*/'circle 2': ()=>showCircleMenu(2), + /*LANG*/'circle 3': ()=>showCircleMenu(3), + /*LANG*/'circle 4': ()=>showCircleMenu(4), + /*LANG*/'heartrate': ()=>showHRMenu(), + /*LANG*/'steps': ()=>showStepMenu(), + /*LANG*/'battery warn': { + value: "batteryWarn" in settings ? settings.batteryWarn : 30, + min: 10, + max : 100, + step: 10, + format: x => { + return x + '%'; + }, + onchange: x => save('batteryWarn', x), }, - onchange: x => save('maxHR', x), - }, - 'hr confidence': { - value: "confidence" in settings ? settings.confidence : 0, - min: 0, - max : 100, - step: 10, - format: x => { - return x; + /*LANG*/'show widgets': { + value: "showWidgets" in settings ? settings.showWidgets : false, + format: () => (settings.showWidgets ? 'Yes' : 'No'), + onchange: x => save('showWidgets', x), }, - onchange: x => save('confidence', x), - }, - 'step goal': { - value: "stepGoal" in settings ? settings.stepGoal : 10000, - min: 2000, - max : 50000, - step: 2000, - format: x => { - return x; + /*LANG*/'weather circle': { + value: settings.weatherCircleData ? weatherData.indexOf(settings.weatherCircleData) : 0, + min: 0, max: 2, + format: v => weatherData[v], + onchange: x => save('weatherCircleData', weatherData[x]), + } + }; + E.showMenu(menu); + } + + function showHRMenu() { + let menu = { + '': { 'title': /*LANG*/'Heartrate' }, + /*LANG*/'< Back': ()=>showMainMenu(), + /*LANG*/'minimum bpm': { + value: "minHR" in settings ? settings.minHR : 40, + min: 0, + max : 250, + step: 5, + format: x => { + return x; + }, + onchange: x => save('minHR', x), }, - onchange: x => save('stepGoal', x), - }, - 'step length': { - value: "stepLength" in settings ? settings.stepLength : 0.8, - min: 0.1, - max : 1.5, - step: 0.01, - format: x => { - return x; + /*LANG*/'maximum bpm': { + value: "maxHR" in settings ? settings.maxHR : 200, + min: 20, + max : 250, + step: 5, + format: x => { + return x; + }, + onchange: x => save('maxHR', x), }, - onchange: x => save('stepLength', x), - }, - 'step dist goal': { - value: "stepDistanceGoal" in settings ? settings.stepDistanceGoal : 8000, - min: 2000, - max : 30000, - step: 1000, - format: x => { - return x; + /*LANG*/'min. confidence': { + value: "confidence" in settings ? settings.confidence : 0, + min: 0, + max : 100, + step: 10, + format: x => { + return x; + }, + onchange: x => save('confidence', x), }, - onchange: x => save('stepDistanceGoal', x), - }, - 'battery warn': { - value: "batteryWarn" in settings ? settings.batteryWarn : 30, - min: 10, - max : 100, - step: 10, - format: x => { - return x + '%'; + }; + E.showMenu(menu); + } + + function showStepMenu() { + let menu = { + '': { 'title': /*LANG*/'Steps' }, + /*LANG*/'< Back': ()=>showMainMenu(), + /*LANG*/'goal': { + value: "stepGoal" in settings ? settings.stepGoal : 10000, + min: 2000, + max : 50000, + step: 2000, + format: x => { + return x; + }, + onchange: x => save('stepGoal', x), }, - onchange: x => save('batteryWarn', x), - }, - 'show widgets': { - value: "showWidgets" in settings ? settings.showWidgets : false, - format: () => (settings.showWidgets ? 'Yes' : 'No'), - onchange: x => save('showWidgets', x), - }, - 'weather circle': { - value: settings.weatherCircleData ? weatherData.indexOf(settings.weatherCircleData) : 0, - min: 0, max: 2, - format: v => weatherData[v], - onchange: x => save('weatherCircleData', weatherData[x]), - }, - 'circle count': { - value: "circleCount" in settings ? settings.circleCount : 3, - min: 3, - max : 4, - step: 1, - onchange: x => save('circleCount', x), - }, - 'circle1': { - value: settings.circle1 ? valuesCircleTypes.indexOf(settings.circle1) : 0, - min: 0, max: valuesCircleTypes.length, - format: v => namesCircleTypes[v], - onchange: x => save('circle1', valuesCircleTypes[x]), - }, - 'circle2': { - value: settings.circle2 ? valuesCircleTypes.indexOf(settings.circle2) : 2, - min: 0, max: valuesCircleTypes.length, - format: v => namesCircleTypes[v], - onchange: x => save('circle2', valuesCircleTypes[x]), - }, - 'circle3': { - value: settings.circle3 ? valuesCircleTypes.indexOf(settings.circle3) : 3, - min: 0, max: valuesCircleTypes.length, - format: v => namesCircleTypes[v], - onchange: x => save('circle3', valuesCircleTypes[x]), - }, - 'circle4': { - value: settings.circle4 ? valuesCircleTypes.indexOf(settings.circle4) : 4, - min: 0, max: valuesCircleTypes.length, - format: v => namesCircleTypes[v], - onchange: x => save('circle4', valuesCircleTypes[x]), - } - }); + /*LANG*/'distance goal': { + value: "stepDistanceGoal" in settings ? settings.stepDistanceGoal : 8000, + min: 2000, + max : 30000, + step: 1000, + format: x => { + return x; + }, + onchange: x => save('stepDistanceGoal', x), + }, + /*LANG*/'step length': { + value: "stepLength" in settings ? settings.stepLength : 0.8, + min: 0.1, + max : 1.5, + step: 0.01, + format: x => { + return x; + }, + onchange: x => save('stepLength', x), + } + }; + E.showMenu(menu); + } + + function showCircleMenu(circleId) { + String circleName = "circle" + circleId; + String colorKey = circleName + "color"; + let menu = { + '': { 'title': /*LANG*/'Circle ' + circleId }, + /*LANG*/'< Back': ()=>showMainMenu(), + /*LANG*/'data': { + value: settings[circleName] ? valuesCircleTypes.indexOf(settings[circleName]) : 0, + min: 0, max: valuesCircleTypes.length, + format: v => namesCircleTypes[v], + onchange: x => save(circleName, valuesCircleTypes[x]), + }, + /*LANG*/'color': { + value: settings[colorKey] ? valuesColors.indexOf(settings[colorKey]) : 0, + min: 0, max: valuesColors.length, + format: v => namesColors[v], + onchange: x => save(colorKey, valuesColors[x]), + }, + }; + E.showMenu(menu); + } + + + showMainMenu(); }); From fdd68f2de2caefa1cd09da44200d97a8777a0246 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sat, 29 Jan 2022 22:33:43 +0100 Subject: [PATCH 14/27] Colorization of icon can be toggled --- apps/circlesclock/app.js | 57 +++++++++++++++++++++-------------- apps/circlesclock/settings.js | 6 ++++ 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 520f7f748..9e921ff5f 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -96,9 +96,9 @@ const circlePosX = [ const radiusOuter = circleCount == 3 ? 25 : 19; const radiusInner = circleCount == 3 ? 20 : 15; -const circleFontSmall = circleCount == 3 ? "Vector:14" : "Vector:11"; -const circleFont = circleCount == 3 ? "Vector:15" : "Vector:12"; -const circleFontBig = circleCount == 3 ? "Vector:16" : "Vector:13"; +const circleFontSmall = circleCount == 3 ? "Vector:14" : "Vector:10"; +const circleFont = circleCount == 3 ? "Vector:15" : "Vector:11"; +const circleFontBig = circleCount == 3 ? "Vector:16" : "Vector:12"; const iconOffset = circleCount == 3 ? 6 : 8; const defaultCircleTypes = ["steps", "hr", "battery", "weather"]; @@ -231,17 +231,30 @@ function getCircleColor(type) { if (color && color != "") return color; } -function getImage(graphic, color) { - return { - width: 16, - height: 16, - bpp: 1, - transparent: 0, - buffer: E.toArrayBuffer(graphic), - palette: new Uint16Array([colorBg, g.toColor(color)]) - }; +function getCircleIconColor(type, color) { + const pos = getCirclePosition(type); + const colorizeIcon = settings["circle" + (pos + 1) + "colorizeIcon"] != undefined; + if (colorizeIcon) { + return color; + } else { + return ""; + } } +function getImage(graphic, color) { + if (!color || color == "") { + return graphic; + } else { + return { + width: 16, + height: 16, + bpp: 1, + transparent: 0, + buffer: E.toArrayBuffer(graphic), + palette: new Uint16Array([colorBg, g.toColor(color)]) + }; + } +} function drawSteps(w) { if (!w) w = getCircleXPosition("steps"); @@ -262,7 +275,7 @@ function drawSteps(w) { writeCircleText(w, shortValue(steps)); - g.drawImage(getImage(shoesIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(shoesIcon, getCircleIconColor("steps", color)), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawStepsDistance(w) { @@ -286,7 +299,7 @@ function drawStepsDistance(w) { writeCircleText(w, shortValue(stepsDistance)); - g.drawImage(getImage(shoesIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(shoesIcon, getCircleIconColor("stepsDistance", color)), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawHeartRate(w) { @@ -307,7 +320,7 @@ function drawHeartRate(w) { writeCircleText(w, hrtValue != undefined ? hrtValue : "-"); - g.drawImage(getImage(heartIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(heartIcon, getCircleIconColor("hr", color)), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawBattery(w) { @@ -334,7 +347,7 @@ function drawBattery(w) { } writeCircleText(w, battery + '%'); - g.drawImage(getImage(powerIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(powerIcon, getCircleIconColor("battery", color)), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawWeather(w) { @@ -377,7 +390,7 @@ function drawWeather(w) { if (code > 0) { const icon = getWeatherIconByCode(code); - if (icon) g.drawImage(getImage(icon, color), w - iconOffset, h3 + radiusOuter - iconOffset); + if (icon) g.drawImage(getImage(icon, getCircleIconColor("weather", color)), w - iconOffset, h3 + radiusOuter - iconOffset); } else { g.drawString("?", w, h3 + radiusOuter); } @@ -427,7 +440,7 @@ function drawSunProgress(w) { writeCircleText(w, text); - g.drawImage(getImage(icon, color), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(icon, getCircleIconColor("sunprogress", color)), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawTemperature(w) { @@ -450,7 +463,7 @@ function drawTemperature(w) { if (temperature) writeCircleText(w, locale.temp(temperature)); - g.drawImage(getImage(temperatureIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(temperatureIcon, getCircleIconColor("temperature", color)), w - iconOffset, h3 + radiusOuter - iconOffset); }).catch(() => { setTimeout(() => { @@ -479,7 +492,7 @@ function drawPressure(w) { if (pressure) writeCircleText(w, Math.round(pressure)); - g.drawImage(getImage(temperatureIcon), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(temperatureIcon, getCircleIconColor("pressure", color)), w - iconOffset, h3 + radiusOuter - iconOffset); }).catch(() => { setTimeout(() => { @@ -508,7 +521,7 @@ function drawAltitude(w) { if (altitude) writeCircleText(w, locale.distance(Math.round(altitude))); - g.drawImage(getImage(temperatureIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(temperatureIcon, getCircleIconColor("altitude", color)), w - iconOffset, h3 + radiusOuter - iconOffset); }).catch(() => { setTimeout(() => { @@ -689,7 +702,7 @@ function drawGauge(cx, cy, percent, color) { function writeCircleText(w, content) { if (content == undefined) return; - const font = String(content).length > 3 ? circleFontSmall : String(content).length > 2 ? circleFont : circleFontBig; + const font = String(content).length > 4 ? circleFontSmall : String(content).length > 3 ? circleFont : circleFontBig; g.setFont(font); g.setFontAlign(0, 0); diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index cc2ba7a1f..fb94ffd52 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -136,6 +136,7 @@ function showCircleMenu(circleId) { String circleName = "circle" + circleId; String colorKey = circleName + "color"; + String colorizeIconKey = circleName + "colorizeIcon"; let menu = { '': { 'title': /*LANG*/'Circle ' + circleId }, /*LANG*/'< Back': ()=>showMainMenu(), @@ -151,6 +152,11 @@ format: v => namesColors[v], onchange: x => save(colorKey, valuesColors[x]), }, + /*LANG*/'colorize icon': { + value: colorizeIconKey in settings ? settings[colorizeIconKey] : false, + format: () => (settings[colorizeIconKey] ? 'Yes' : 'No'), + onchange: x => save(colorizeIconKey, x), + }, }; E.showMenu(menu); } From 686cfe249fb12389aeacf906cab5f6a4484f3a93 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sat, 29 Jan 2022 22:34:56 +0100 Subject: [PATCH 15/27] Update README --- apps/circlesclock/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index 325d6f838..31afd98eb 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -16,6 +16,9 @@ It can show the following information (this can be configured): * Time and progress until next sunrise or sunset (requires [my location app](https://banglejs.com/apps/#mylocation)) * Temperature, air pressure or altitude from internal pressure sensor + +The color of each circle can be configured. + ## Screenshots ![Screenshot dark theme](screenshot-dark.png) ![Screenshot light theme](screenshot-light.png) From 37ecd01c5efcb6aba1803be681eb97eaecd51a38 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sat, 29 Jan 2022 22:43:01 +0100 Subject: [PATCH 16/27] Fix colorize setting reading --- apps/circlesclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 9e921ff5f..064072d05 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -233,7 +233,7 @@ function getCircleColor(type) { function getCircleIconColor(type, color) { const pos = getCirclePosition(type); - const colorizeIcon = settings["circle" + (pos + 1) + "colorizeIcon"] != undefined; + const colorizeIcon = settings["circle" + (pos + 1) + "colorizeIcon"] == true; if (colorizeIcon) { return color; } else { From 41a9cf851df9a0f0047fdd9300e184b7a96e739a Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sat, 29 Jan 2022 22:44:33 +0100 Subject: [PATCH 17/27] Bump version --- apps/circlesclock/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/circlesclock/metadata.json b/apps/circlesclock/metadata.json index bd2ce751b..f426a1681 100644 --- a/apps/circlesclock/metadata.json +++ b/apps/circlesclock/metadata.json @@ -1,7 +1,7 @@ { "id": "circlesclock", "name": "Circles clock", "shortName":"Circles clock", - "version":"0.08", + "version":"0.09", "description": "A clock with three or four circles for different data at the bottom in a probably familiar style", "icon": "app.png", "screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}, {"url":"screenshot-dark-4.png"}, {"url":"screenshot-light-4.png"}], From b02c2f4de889e10f34a8f6b56d58e44b232562bc Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sun, 30 Jan 2022 19:04:15 +0100 Subject: [PATCH 18/27] Fix circle filling --- apps/circlesclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 064072d05..3ab1f93a7 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -94,7 +94,7 @@ const circlePosX = [ Math.round(7 * w / parts), // circle4 ]; -const radiusOuter = circleCount == 3 ? 25 : 19; +const radiusOuter = circleCount == 3 ? 25 : 20; const radiusInner = circleCount == 3 ? 20 : 15; const circleFontSmall = circleCount == 3 ? "Vector:14" : "Vector:10"; const circleFont = circleCount == 3 ? "Vector:15" : "Vector:11"; From 93fb41dfe0f88a7a84c1f6f999c1f21af2b9e585 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sun, 30 Jan 2022 20:28:31 +0100 Subject: [PATCH 19/27] Color depending on value (green -> red, red -> green) --- apps/circlesclock/ChangeLog | 1 + apps/circlesclock/README.md | 5 ++- apps/circlesclock/app.js | 83 ++++++++++++++++++++++------------- apps/circlesclock/settings.js | 4 +- 4 files changed, 59 insertions(+), 34 deletions(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index 0393613e0..4fcdbd653 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -17,3 +17,4 @@ Fix sunprogress calculation during night Refactor settings menu Colors of circles can be configured + Color depending on value (green -> red, red -> green) option diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index 31afd98eb..aa429d5ec 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -17,7 +17,10 @@ It can show the following information (this can be configured): * Temperature, air pressure or altitude from internal pressure sensor -The color of each circle can be configured. +The color of each circle can be configured. The following colors are available: + * Basic colors (red, green, blue, yellow, magenta, cyan, black, white) + * Color depending on value (green -> red, red -> green) + ## Screenshots ![Screenshot dark theme](screenshot-dark.png) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 3ab1f93a7..107e8d450 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -231,16 +231,33 @@ function getCircleColor(type) { if (color && color != "") return color; } -function getCircleIconColor(type, color) { +function getCircleIconColor(type, color, percent) { const pos = getCirclePosition(type); const colorizeIcon = settings["circle" + (pos + 1) + "colorizeIcon"] == true; if (colorizeIcon) { - return color; + return getGradientColor(color, percent); } else { return ""; } } +function getGradientColor(color, percent) { + if (isNaN(percent)) percent = 0; + if (percent > 1) percent = 1; + const colorList = [ + '#00FF00', '#80FF00', '#FFFF00', '#FF8000', '#FF0000' + ]; + if (color == "green-red") { + const colorIndex = Math.round(colorList.length * percent); + return colorList[Math.min(colorIndex, colorList.length) - 1] || "#00ff00"; + } + if (color == "red-green") { + const colorIndex = colorList.length - Math.round(colorList.length * percent); + return colorList[Math.min(colorIndex, colorList.length)] || "#ff0000"; + } + return color; +} + function getImage(graphic, color) { if (!color || color == "") { return graphic; @@ -264,9 +281,10 @@ function drawSteps(w) { const color = getCircleColor("steps") || colorBlue; + let percent; const stepGoal = settings.stepGoal || 10000; if (stepGoal > 0) { - let percent = steps / stepGoal; + percent = steps / stepGoal; if (stepGoal < steps) percent = 1; drawGauge(w, h3, percent, color); } @@ -275,7 +293,7 @@ function drawSteps(w) { writeCircleText(w, shortValue(steps)); - g.drawImage(getImage(shoesIcon, getCircleIconColor("steps", color)), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(shoesIcon, getCircleIconColor("steps", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawStepsDistance(w) { @@ -288,9 +306,10 @@ function drawStepsDistance(w) { const color = getCircleColor("stepsDistance") || colorGreen; + let percent; const stepDistanceGoal = settings.stepDistanceGoal || 8000; if (stepDistanceGoal > 0) { - let percent = stepsDistance / stepDistanceGoal; + percent = stepsDistance / stepDistanceGoal; if (stepDistanceGoal < stepsDistance) percent = 1; drawGauge(w, h3, percent, color); } @@ -299,7 +318,7 @@ function drawStepsDistance(w) { writeCircleText(w, shortValue(stepsDistance)); - g.drawImage(getImage(shoesIcon, getCircleIconColor("stepsDistance", color)), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(shoesIcon, getCircleIconColor("stepsDistance", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawHeartRate(w) { @@ -309,10 +328,12 @@ function drawHeartRate(w) { const color = getCircleColor("hr") || colorRed; + let percent; if (hrtValue != undefined) { const minHR = settings.minHR || 40; const maxHR = settings.maxHR || 200; - const percent = (hrtValue - minHR) / (maxHR - minHR); + percent = (hrtValue - minHR) / (maxHR - minHR); + if (isNaN(percent)) percent = 0; drawGauge(w, h3, percent, color); } @@ -320,7 +341,7 @@ function drawHeartRate(w) { writeCircleText(w, hrtValue != undefined ? hrtValue : "-"); - g.drawImage(getImage(heartIcon, getCircleIconColor("hr", color)), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(heartIcon, getCircleIconColor("hr", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawBattery(w) { @@ -331,8 +352,9 @@ function drawBattery(w) { let color = getCircleColor("battery") || colorYellow; + let percent; if (battery > 0) { - const percent = battery / 100; + percent = battery / 100; drawGauge(w, h3, percent, color); } @@ -347,7 +369,7 @@ function drawBattery(w) { } writeCircleText(w, battery + '%'); - g.drawImage(getImage(powerIcon, getCircleIconColor("battery", color)), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(powerIcon, getCircleIconColor("battery", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawWeather(w) { @@ -359,13 +381,14 @@ function drawWeather(w) { drawCircleBackground(w); const color = getCircleColor("weather") || colorYellow; - + let percent; const data = settings.weatherCircleData || "humidity"; switch (data) { case "humidity": const humidity = weather ? weather.hum : undefined; if (humidity >= 0) { - drawGauge(w, h3, humidity / 100, color); + percent = humidity / 100; + drawGauge(w, h3, percent, color); } break; case "wind": @@ -376,7 +399,8 @@ function drawWeather(w) { wind[1] = windAsBeaufort(wind[1]); } // wind goes from 0 to 12 (see https://en.wikipedia.org/wiki/Beaufort_scale) - drawGauge(w, h3, wind[1] / 12, color); + percent = wind[1] / 12; + drawGauge(w, h3, percent, color); } } break; @@ -390,7 +414,7 @@ function drawWeather(w) { if (code > 0) { const icon = getWeatherIconByCode(code); - if (icon) g.drawImage(getImage(icon, getCircleIconColor("weather", color)), w - iconOffset, h3 + radiusOuter - iconOffset); + if (icon) g.drawImage(getImage(icon, getCircleIconColor("weather", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); } else { g.drawString("?", w, h3 + radiusOuter); } @@ -403,21 +427,13 @@ function drawSunProgress(w) { drawCircleBackground(w); - const color = getCircleColor("sunpgrogress") || colorYellow; + const color = getCircleColor("sunprogress") || colorYellow; drawGauge(w, h3, percent, color); drawInnerCircleAndTriangle(w); let icon = sunSetDown; - if (isDay()) { - // day - icon = sunSetDown; - } else { - // night - icon = sunSetUp; - } - let text = "?"; const times = getSunData(); if (times != undefined) { @@ -432,15 +448,17 @@ function drawSunProgress(w) { } else { text = formatSeconds(sunRise - now); } + icon = sunSetUp; } else { // day, approx sunrise tomorrow: text = formatSeconds(sunSet - now); + icon = sunSetDown; } } writeCircleText(w, text); - g.drawImage(getImage(icon, getCircleIconColor("sunprogress", color)), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(icon, getCircleIconColor("sunprogress", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawTemperature(w) { @@ -452,18 +470,18 @@ function drawTemperature(w) { const color = getCircleColor("temperature") || colorGreen; drawInnerCircleAndTriangle(w); - + let percent; if (temperature) { const min = -40; const max = 85; - const percent = (temperature - min) / (max - min); + percent = (temperature - min) / (max - min); drawGauge(w, h3, percent, color); } if (temperature) writeCircleText(w, locale.temp(temperature)); - g.drawImage(getImage(temperatureIcon, getCircleIconColor("temperature", color)), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(temperatureIcon, getCircleIconColor("temperature", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); }).catch(() => { setTimeout(() => { @@ -482,17 +500,18 @@ function drawPressure(w) { drawInnerCircleAndTriangle(w); + let percent; if (pressure && pressure > 0) { const minPressure = 950; const maxPressure = 1050; - const percent = (pressure - minPressure) / (maxPressure - minPressure); + percent = (pressure - minPressure) / (maxPressure - minPressure); drawGauge(w, h3, percent, color); } if (pressure) writeCircleText(w, Math.round(pressure)); - g.drawImage(getImage(temperatureIcon, getCircleIconColor("pressure", color)), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(temperatureIcon, getCircleIconColor("pressure", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); }).catch(() => { setTimeout(() => { @@ -511,17 +530,18 @@ function drawAltitude(w) { drawInnerCircleAndTriangle(w); + let percent; if (altitude) { const min = 0; const max = 10000; - const percent = (altitude - min) / (max - min); + percent = (altitude - min) / (max - min); drawGauge(w, h3, percent, color); } if (altitude) writeCircleText(w, locale.distance(Math.round(altitude))); - g.drawImage(getImage(temperatureIcon, getCircleIconColor("altitude", color)), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(temperatureIcon, getCircleIconColor("altitude", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); }).catch(() => { setTimeout(() => { @@ -691,6 +711,7 @@ function drawGauge(cx, cy, percent, color) { const startRotation = -offset; const endRotation = startRotation - ((end - offset) * percent); + color = getGradientColor(color, percent); g.setColor(color); for (let i = startRotation; i > endRotation - size; i -= size) { diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index fb94ffd52..ac0a4f696 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -10,8 +10,8 @@ const valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather", "sunprogress", "empty", "temperature", "pressure", "altitude"]; const namesCircleTypes = ["steps", "distance", "heart", "battery", "weather", "sun progress", "empty", "temperature", "pressure", "altitude"]; - const valuesColors = ["", "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "#00ffff", "#fff", "#000"]; - const namesColors = ["default", "red", "green", "blue", "yellow", "magenta", "cyan", "white", "black"]; + const valuesColors = ["", "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "#00ffff", "#fff", "#000", "green-red", "red-green"]; + const namesColors = ["default", "red", "green", "blue", "yellow", "magenta", "cyan", "white", "black", "green->red", "red->green"]; const weatherData = ["humidity", "wind", "empty"]; From 12bf75d92404cd8ac61a445e6f2414a75a039af1 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sun, 30 Jan 2022 20:46:51 +0100 Subject: [PATCH 20/27] Fix battery icon and gauge of barometer values --- apps/circlesclock/app.js | 45 ++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 107e8d450..475b4e86f 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -4,7 +4,7 @@ const SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/maste const shoesIcon = atob("EBCBAAAACAAcAB4AHgAeABwwADgGeAZ4AHgAMAAAAHAAIAAA"); const heartIcon = atob("EBCBAAAAAAAeeD/8P/x//n/+P/w//B/4D/AH4APAAYAAAAAA"); -const powerIcon = atob("FBSBAAAAAAAAAfgAP8AH/gB/4Af+AH/gB/4Af+AH/gB/4Af+AH/gB/4Af+AH/gB/4AAAAAAA"); +const powerIcon = atob("EBCBAAAAA8ADwA/wD/AP8A/wD/AP8A/wD/AP8A/wD/AH4AAA"); const temperatureIcon = atob("EBCBAAAAAYADwAJAAkADwAPAA8ADwAfgB+AH4AfgA8ABgAAA"); const weatherCloudy = atob("EBCBAAAAAAAAAAfgD/Af8H/4//7///////9//z/+AAAAAAAA"); @@ -469,7 +469,6 @@ function drawTemperature(w) { const color = getCircleColor("temperature") || colorGreen; - drawInnerCircleAndTriangle(w); let percent; if (temperature) { const min = -40; @@ -478,15 +477,15 @@ function drawTemperature(w) { drawGauge(w, h3, percent, color); } + + drawInnerCircleAndTriangle(w); + + if (temperature) writeCircleText(w, locale.temp(temperature)); g.drawImage(getImage(temperatureIcon, getCircleIconColor("temperature", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); - }).catch(() => { - setTimeout(() => { - drawTemperature(); - }, 1000); }); } @@ -498,8 +497,6 @@ function drawPressure(w) { const color = getCircleColor("pressure") || colorGreen; - drawInnerCircleAndTriangle(w); - let percent; if (pressure && pressure > 0) { const minPressure = 950; @@ -508,15 +505,15 @@ function drawPressure(w) { drawGauge(w, h3, percent, color); } + + drawInnerCircleAndTriangle(w); + + if (pressure) writeCircleText(w, Math.round(pressure)); g.drawImage(getImage(temperatureIcon, getCircleIconColor("pressure", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); - }).catch(() => { - setTimeout(() => { - drawPressure(w); - }, 1000); }); } @@ -528,8 +525,6 @@ function drawAltitude(w) { const color = getCircleColor("altitude") || colorGreen; - drawInnerCircleAndTriangle(w); - let percent; if (altitude) { const min = 0; @@ -538,15 +533,15 @@ function drawAltitude(w) { drawGauge(w, h3, percent, color); } + + drawInnerCircleAndTriangle(w); + + if (altitude) writeCircleText(w, locale.distance(Math.round(altitude))); g.drawImage(getImage(temperatureIcon, getCircleIconColor("altitude", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); - }).catch(() => { - setTimeout(() => { - drawAltitude(w); - }, 1000); }); } @@ -705,7 +700,7 @@ function drawGauge(cx, cy, percent, color) { const radius = radiusInner + (circleCount == 3 ? 3 : 2); const size = radiusOuter - radiusInner - 2; - if (percent <= 0) return; + if (percent <= 0) return; // no gauge needed if (percent > 1) percent = 1; const startRotation = -offset; @@ -771,14 +766,12 @@ let pressureLocked = false; let pressureCache; function getPressureValue(type) { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { if (Bangle.getPressure) { if (!pressureLocked) { pressureLocked = true; if (pressureCache && pressureCache[type]) { resolve(pressureCache[type]); - } else { - reject(); } Bangle.getPressure().then(function(d) { pressureLocked = false; @@ -787,19 +780,13 @@ function getPressureValue(type) { if (d[type]) { resolve(d[type]); } - } else { - reject(); } - }).catch(reject); + }).catch(() => {}); } else { if (pressureCache && pressureCache[type]) { resolve(pressureCache[type]); - } else { - reject(); } } - } else { - reject(); } }); } From c96a52238f8c81786facedc75a1fcbacd471665e Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sun, 30 Jan 2022 20:55:22 +0100 Subject: [PATCH 21/27] Improve settings sorting --- apps/circlesclock/settings.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index ac0a4f696..7aaad6824 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -7,13 +7,13 @@ storage.write(SETTINGS_FILE, settings); } - const valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather", "sunprogress", "empty", "temperature", "pressure", "altitude"]; - const namesCircleTypes = ["steps", "distance", "heart", "battery", "weather", "sun progress", "empty", "temperature", "pressure", "altitude"]; + const valuesCircleTypes = ["empty", "steps", "stepsDist", "hr", "battery", "weather", "sunprogress", "temperature", "pressure", "altitude"]; + const namesCircleTypes = ["empty", "steps", "distance", "heart", "battery", "weather", "sun", "temperature", "pressure", "altitude"]; const valuesColors = ["", "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "#00ffff", "#fff", "#000", "green-red", "red-green"]; const namesColors = ["default", "red", "green", "blue", "yellow", "magenta", "cyan", "white", "black", "green->red", "red->green"]; - const weatherData = ["humidity", "wind", "empty"]; + const weatherData = ["empty", "humidity", "wind"]; function showMainMenu() { let menu ={ @@ -48,7 +48,7 @@ onchange: x => save('showWidgets', x), }, /*LANG*/'weather circle': { - value: settings.weatherCircleData ? weatherData.indexOf(settings.weatherCircleData) : 0, + value: settings.weatherCircleData ? weatherData.indexOf(settings.weatherCircleData) : 1, min: 0, max: 2, format: v => weatherData[v], onchange: x => save('weatherCircleData', weatherData[x]), @@ -142,13 +142,13 @@ /*LANG*/'< Back': ()=>showMainMenu(), /*LANG*/'data': { value: settings[circleName] ? valuesCircleTypes.indexOf(settings[circleName]) : 0, - min: 0, max: valuesCircleTypes.length, + min: 0, max: valuesCircleTypes.length - 1, format: v => namesCircleTypes[v], onchange: x => save(circleName, valuesCircleTypes[x]), }, /*LANG*/'color': { value: settings[colorKey] ? valuesColors.indexOf(settings[colorKey]) : 0, - min: 0, max: valuesColors.length, + min: 0, max: valuesColors.length - 1, format: v => namesColors[v], onchange: x => save(colorKey, valuesColors[x]), }, From 8fdd4455c49a2f890eae513f42c5cc38e9ce0ac9 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sun, 30 Jan 2022 22:00:34 +0100 Subject: [PATCH 22/27] Fix empty circle data setting when no data is set yet --- apps/circlesclock/settings.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 7aaad6824..ee5a1f29d 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -133,15 +133,18 @@ E.showMenu(menu); } + const defaultCircleTypes = ["steps", "hr", "battery", "weather"]; + function showCircleMenu(circleId) { String circleName = "circle" + circleId; String colorKey = circleName + "color"; String colorizeIconKey = circleName + "colorizeIcon"; + let menu = { '': { 'title': /*LANG*/'Circle ' + circleId }, /*LANG*/'< Back': ()=>showMainMenu(), /*LANG*/'data': { - value: settings[circleName] ? valuesCircleTypes.indexOf(settings[circleName]) : 0, + value: settings[circleName]!=undefined ? valuesCircleTypes.indexOf(settings[circleName]) : valuesCircleTypes.indexOf(defaultCircleTypes[circleId -1]), min: 0, max: valuesCircleTypes.length - 1, format: v => namesCircleTypes[v], onchange: x => save(circleName, valuesCircleTypes[x]), From 069c96f36cc5a2bba351342e8043b7fa2ad9c741 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Mon, 31 Jan 2022 19:16:39 +0100 Subject: [PATCH 23/27] Let us wait a bit before we overwrite "good" HRM values --- apps/circlesclock/app.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 475b4e86f..8b58e0e28 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -477,10 +477,8 @@ function drawTemperature(w) { drawGauge(w, h3, percent, color); } - drawInnerCircleAndTriangle(w); - if (temperature) writeCircleText(w, locale.temp(temperature)); @@ -505,10 +503,8 @@ function drawPressure(w) { drawGauge(w, h3, percent, color); } - drawInnerCircleAndTriangle(w); - if (pressure) writeCircleText(w, Math.round(pressure)); @@ -533,10 +529,8 @@ function drawAltitude(w) { drawGauge(w, h3, percent, color); } - drawInnerCircleAndTriangle(w); - if (altitude) writeCircleText(w, locale.distance(Math.round(altitude))); @@ -803,12 +797,22 @@ Bangle.on('lock', function(isLocked) { }); +let timerHrm; Bangle.on('HRM', function(hrm) { if (isCircleEnabled("hr")) { if (hrm.confidence >= (settings.confidence || 0)) { hrtValue = hrm.bpm; - if (Bangle.isLCDOn()) + if (Bangle.isLCDOn()) { drawHeartRate(); + } + } + // Let us wait a bit before we overwrite "good" HRM values: + if (Bangle.isLCDOn()) { + if (timerHrm) clearTimeout(timerHrm); + timerHrm = setTimeout(() => { + hrtValue = '...'; + drawHeartRate(); + }, 10000); } } }); From cfb834089385f49307937915b158dfb4c643c34c Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Mon, 31 Jan 2022 21:04:30 +0100 Subject: [PATCH 24/27] This is not java ;) --- apps/circlesclock/settings.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index ee5a1f29d..2173c84ae 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -136,11 +136,11 @@ const defaultCircleTypes = ["steps", "hr", "battery", "weather"]; function showCircleMenu(circleId) { - String circleName = "circle" + circleId; - String colorKey = circleName + "color"; - String colorizeIconKey = circleName + "colorizeIcon"; + const circleName = "circle" + circleId; + const colorKey = circleName + "color"; + const colorizeIconKey = circleName + "colorizeIcon"; - let menu = { + const menu = { '': { 'title': /*LANG*/'Circle ' + circleId }, /*LANG*/'< Back': ()=>showMainMenu(), /*LANG*/'data': { From 10c9eeaea0775f05a9b82be9df9008ad419bc2a1 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Mon, 31 Jan 2022 21:07:52 +0100 Subject: [PATCH 25/27] Fix warnings --- apps/circlesclock/app.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 8b58e0e28..3c8cc9f91 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -578,7 +578,6 @@ function getWeatherIconByCode(code) { default: return weatherRainy; } - break; case 6: return weatherSnowy; case 7: @@ -594,11 +593,9 @@ function getWeatherIconByCode(code) { default: return weatherCloudy; } - break; default: return undefined; } - return undefined; } From 15d2e00fa35714a4cf5c36b7396737a360d8fc37 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Tue, 1 Feb 2022 07:50:05 +0100 Subject: [PATCH 26/27] Increase timeout for HRM value reset --- apps/circlesclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 3c8cc9f91..05f9779ef 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -809,7 +809,7 @@ Bangle.on('HRM', function(hrm) { timerHrm = setTimeout(() => { hrtValue = '...'; drawHeartRate(); - }, 10000); + }, 60000); } } }); From bd4366278cf34186c9c858ea9f9d3a7d39858cd0 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Tue, 1 Feb 2022 08:54:21 +0100 Subject: [PATCH 27/27] Make HRM validity period configurable --- apps/circlesclock/ChangeLog | 1 + apps/circlesclock/app.js | 4 ++-- apps/circlesclock/settings.js | 20 +++++++++++++++----- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index 4fcdbd653..58ab4cd48 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -18,3 +18,4 @@ Refactor settings menu Colors of circles can be configured Color depending on value (green -> red, red -> green) option + Good HRM value will not be overwritten so fast anymore diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 05f9779ef..49af2a057 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -803,13 +803,13 @@ Bangle.on('HRM', function(hrm) { drawHeartRate(); } } - // Let us wait a bit before we overwrite "good" HRM values: + // Let us wait before we overwrite "good" HRM values: if (Bangle.isLCDOn()) { if (timerHrm) clearTimeout(timerHrm); timerHrm = setTimeout(() => { hrtValue = '...'; drawHeartRate(); - }, 60000); + }, settings.hrmValidity * 1000 || 30000); } } }); diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 2173c84ae..348d187eb 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -61,23 +61,23 @@ let menu = { '': { 'title': /*LANG*/'Heartrate' }, /*LANG*/'< Back': ()=>showMainMenu(), - /*LANG*/'minimum bpm': { + /*LANG*/'minimum': { value: "minHR" in settings ? settings.minHR : 40, min: 0, max : 250, step: 5, format: x => { - return x; + return x + " bpm"; }, onchange: x => save('minHR', x), }, - /*LANG*/'maximum bpm': { + /*LANG*/'maximum': { value: "maxHR" in settings ? settings.maxHR : 200, min: 20, max : 250, step: 5, format: x => { - return x; + return x + " bpm"; }, onchange: x => save('maxHR', x), }, @@ -87,10 +87,20 @@ max : 100, step: 10, format: x => { - return x; + return x + "%"; }, onchange: x => save('confidence', x), }, + /*LANG*/'valid period': { + value: "hrmValidity" in settings ? settings.hrmValidity : 30, + min: 10, + max : 600, + step: 10, + format: x => { + return x + "s"; + }, + onchange: x => save('hrmValidity', x), + }, }; E.showMenu(menu); }