Watch Face : Clarity (and variations)

Clarity

This Watch Face delivers a wealth of information, available at a glance. Date and time, sun and moon data based on your latest known position, activity data and history, current elevation and UTC time/date.

*** Tested with D2 Bravo firmware 2.30 ***

*** Battery icon only displayed if charge < 50%. Sunset and Sunrise only displayed if a location is saved as last-known-location. If you reset the watch or update firmware, this data is deleted. You have to acquire position again before sunset/sunrise can be displayed. ***


Variations available:

- Clarity (this watch face - has most data displayed)
- Clarity Pilot (no activity data to declutter) https://apps.garmin.com/en-US/apps/3dee8af7-7c49-4ca6-9c14-2845f9ad718b
- Clarity Activity (no UTC time, replaced with steps count) https://apps.garmin.com/en-US/apps/369974bf-ca84-4f7c-bb03-afaf7e8ff3d2


Watch face features:

- Bluetooth status: icon only displayed when phone is connected
- Battery status: icon only displayed when level under 50%. Battery icon filled to reflect charge level. If charge under 30%, a label displaying the exact charge level in % is added. This is to declutter/improve clarity.
- Date: Displayed in your watch selected language.
- Time: Hours (black) and minutes (accent color dark red during day and dark blue during night). Minutes displayed as dash at screen border, in accent color.
- Sun and moon data: Moon icon reflects current moon cycle. Sunrise time (after sun icon) and sunset time (after moon icon) at your latest known location. Time to next sunrise/sunset.
- Move bar displayed on the left side of the graph. It appears if you don't move for too long, according to the watch Move Bar feature. In accent color.
- Histogram graph displaying steps in last 7 days (in dark grey) + today's steps slightly larger (in accent color), as counted by the watch activity monitor. Average target over 8 days is displayed as a horizontal line in accent color.
- Distance elapsed since beginning of day, as counted by the watch activity monitor.
- Calories burned since beginning of day, as counted by the watch activity monitor.
- Current altitude measured by the pressure sensor (can be set automatically with METAR if you have the D2 for best accuracy).
- UTC time ("Z" stands for "Zulu"). If the UTC date is different that the local date, UTC date is displayed too to avoid confusion. Minutes have accent color to remind the main clock.

Sunset and sunrise times

Calculation for these two items are very long (1 to 2 seconds) and are only done when necessary (watch face started, position changed significantly, sunset/sunrise just happened...), and not once per second, so as to optimize power. There should be only 3 calculations per day if the location isn't changed significantly.

Known bugs

- Power consumption is high and may drain the battery in a few days. This is due to Connect IQ framework not enabling reduction in refresh rate correctly (in my current opinion)
- Low power mode is not activated as often as I hoped. This is due to the watch firmware, not to this watch face.
- Time to next sunrise/sunset could sometimes be displayed inappropriately (e.g. 13:-05 instead of 14:55 or something similar).

Clarity
I came up with this name initially because I wanted to make a watch face that's clear. Now I added so much data that it's a little cramped and not as clear as I initially imagined. If you have suggestions to improve clarity/readability, let me know.
  • 50ms is the execution time for calculating sunrise and sunset on my fenix 3.
    I converted this to monkey c: https://github.com/mourner/suncalc/
  • Former Member
    Former Member over 9 years ago
    Hi,
    That is a fatastic app and i use it on my Fenix 3. So when you make these new configurable app I was very happy. I can confirm it crack when configure the app tru android Connect, but when you use Garmin at you PC it doesn't crack but make background and minute to black. If you try to change it, it just change it back to bkack when you save it again.
    If you try to change it with Garmin Connect on you Android, you can't delete the app and you will have fail on you garmin connect to.
    To get you watch and Mobil phone function again, you need to delete the app from you PC.

    That is just a awesome work you gave done here!&#128077;&#128077;&#128077;

    Kim
  • This is my implementation. I did not check performance yet on real watch.

    How to call my function. Parameters are latitude, longitude, year, month, day, timezone in hours.
    [PHP]
    var sunRiseSunSetToday = calculateSunRiseSunSet(54, 4, 2015, 12, 03, Sys.getClockTime().timeZoneOffset / 3600);
    var sunRiseToday = sunRiseSunSetToday[0] + ":" + sunRiseSunSetToday[1];
    var sunSetToday = sunRiseSunSetToday[2] + ":" + sunRiseSunSetToday[3];

    Sys.println("sun rise: " + sunRiseToday);
    Sys.println("sun set: " + sunSetToday);[/PHP]

    functions for calculation:

    [PHP]
    static function abs(num) {
    if (num < 0) {
    return -1*num;
    } else {
    return num;
    }
    }

    static function floor(x) {
    return (1.0*x).toNumber();
    }

    static function calculateSunRiseSunSet(dfLat, dfLon, iYear, iMonth, iDay, dfTimeZone) {
    // Declare and initialize variables
    var result = new [4];

    var dfHourRise = 99.0, dfHourSet = 99.0; // hour of event
    var dfMinRise = 99.0, dfMinSet = 99.0; // minute of event

    var bSunriseToday = false; // flag for sunrise on this date
    var bSunsetToday = false; // flag for sunset on this date
    var bSunUpAllDay = false; // flag for sun up all day
    var bSunDownAllDay = false; // flag for sun down all day

    var bSunrise = false; // sunrise during hour checked
    var bSunset = false; // sunset during hour checked
    var bGregorian = false; // flag for Gregorian calendar
    var iJulian; // Julian day
    var iCount; // a simple counter
    var iSign;

    var dfSinLat, dfCosLat; // sin and cos of latitude
    var dfZenith; // Z: Zenith
    // Many variables have undocumented meanings,
    // and so are translated rather directly to avoid confusion:
    var dfAA1 = 0, dfAA2 = 0;
    var dfDD1 = 0, dfDD2 = 0;
    var dfC0;
    var dfK1;
    var dfP;
    var dfJ;
    var dfJ3;
    var dfA;
    var dfA0, dfA2, dfA5;
    var dfD0, dfD1, dfD2, dfD5;
    var dfDA, dfDD;
    var dfH0, dfH1, dfH2;
    var dfL0, dfL2;
    var dfT, dfT0, dfTT;
    var dfV0, dfV1, dfV2;

    var origTimeZone;

    origTimeZone = dfTimeZone;

    // Break out day, month, and year from date provided.
    // (This is necesary for the math algorithms.)

    // Convert time zone hours to decimal days
    dfTimeZone = dfTimeZone / 24.0;

    // NOTE: (7 Feb 2001)
    // It (and this algorithm) assumes that the time zone is
    // positive west, instead of the standard negative west.
    // Classes calling SunriseSunset will be assuming that
    // times zones are specified in negative west, so here the
    // sign is changed so that the SUNUP algorithm works:
    dfTimeZone = -dfTimeZone;

    // Convert longitude to fraction
    dfLon = dfLon / 360.0;

    // Convert calendar date to Julian date:
    // Check to see if it's later than 1583: Gregorian calendar
    // When declared, bGregorian is initialized to false.
    // ** Consider making a separate class of this function. **
    if (iYear >= 1583) {
    bGregorian = true;
    }
    dfJ = -floor(7.0 * (floor((iMonth + 9.0) / 12.0) + iYear) / 4.0) + floor(iMonth * 275.0 / 9.0) + iDay + 1721027.0 + iYear * 367.0;

    if (bGregorian) {
    if ((iMonth - 9.0) < 0.0) {
    iSign = -1;
    } else {
    iSign = 1;
    }
    dfA = abs(iMonth - 9.0);
    dfJ3 = -floor((floor(floor(iYear + (1.0 * iSign) * floor(dfA / 7.0))/ 100.0) + 1.0) * 0.75);
    dfJ = dfJ + dfJ3 + 2.0;
    }
    iJulian = (dfJ - 1.0).toNumber();

    dfT = iJulian - 2451545.0 + 0.5;
    dfTT = dfT / 36525.0 + 1.0; // centuries since 1900

    // Calculate local sidereal time at 0h in zone time
    dfT0 = (dfT * 8640184.813 / 36525.0
    + 24110.5
    + dfTimeZone * 86636.6
    + dfLon * 86400.0
    )
    / 86400.0;
    dfT0 = dfT0 - floor(dfT0);
    dfT0 = dfT0 * 2.0 * Math.PI;
    dfT = dfT + dfTimeZone;

    // Get Sun's position
    for (iCount = 0; iCount <= 1; iCount++) // Loop thru only twice
    {
    // Calculate Sun's right ascension and declination
    // at the start and end of each day.
    // Fundamental arguments
    // from van Flandern and Pulkkinen, 1979

    // declare local temporary doubles for calculations
    var dfGG;
    var dfLL;
    var dfSS;
    var dfUU;
    var dfVV;
    var dfWW;

    dfLL = 0.779072 + 0.00273790931 * dfT;
    dfLL = dfLL - floor(dfLL);
    dfLL = dfLL * 2.0 * Math.PI;

    dfGG = 0.993126 + 0.0027377785 * dfT;
    dfGG = dfGG - floor(dfGG);
    dfGG = dfGG * 2.0 * Math.PI;

    dfVV = 0.39785 * Math.sin(dfLL) - 0.01000 * Math.sin(dfLL - dfGG) + 0.00333 * Math.sin(dfLL + dfGG) - 0.00021 * Math.sin(dfLL) * dfTT;

    dfUU = 1 - 0.03349 * Math.cos(dfGG) - 0.00014 * Math.cos(dfLL * 2.0) + 0.00008 * Math.cos(dfLL);
    dfWW = -0.00010 - 0.04129 * Math.sin(dfLL * 2.0) + 0.03211 * Math.sin(dfGG) - 0.00104 * Math.sin(2.0 * dfLL - dfGG) - 0.00035 * Math.sin(2.0 * dfLL + dfGG)- 0.00008 * Math.sin(dfGG) * dfTT;

    // Compute Sun's RA and Dec
    dfSS = dfWW / Math.sqrt(dfUU - dfVV * dfVV);
    dfA5 = dfLL
    + Math.atan(dfSS / Math.sqrt(1.0 - dfSS * dfSS));

    dfSS = dfVV / Math.sqrt(dfUU);
    dfD5 = Math.atan(dfSS / Math.sqrt(1 - dfSS * dfSS));

    // Set values and increment t
    if (iCount == 0) {
    dfAA1 = dfA5;
    dfDD1 = dfD5;
    } else {
    dfAA2 = dfA5;
    dfDD2 = dfD5;
    }
    dfT = dfT + 1.0;
    } // end of Get Sun's Position for loop

    if (dfAA2 < dfAA1) {
    dfAA2 = dfAA2 + 2.0 * Math.PI;
    }
    // SUNUP.BAS 150

    dfZenith = Math.PI * 90.833 / 180.0;
    dfSinLat = Math.sin(dfLat * Math.PI / 180.0);
    dfCosLat = Math.cos(dfLat * Math.PI / 180.0);

    dfA0 = dfAA1;
    dfD0 = dfDD1;
    dfDA = dfAA2 - dfAA1;
    dfDD = dfDD2 - dfDD1;

    dfK1 = 15.0 * 1.0027379 * Math.PI / 180.0;

    // Initialize sunrise and sunset times, and other variables
    // hr and min are set to impossible times to make errors obvious
    dfHourRise = 99.0;
    dfMinRise = 99.0;
    dfHourSet = 99.0;
    dfMinSet = 99.0;
    dfV0 = 0.0;
    dfV2 = 0.0;

    // Test each hour to see if the Sun crosses the horizon
    // and which way it is heading.
    for (iCount = 0; iCount < 24; iCount++) {
    var tempA;
    var tempB;
    var tempD;
    var tempE;

    dfC0 = iCount * 1.0;
    dfP = (dfC0 + 1.0) / 24.0;
    dfA2 = dfAA1 + dfP * dfDA;
    dfD2 = dfDD1 + dfP * dfDD;
    dfL0 = dfT0 + dfC0 * dfK1;
    dfL2 = dfL0 + dfK1;
    dfH0 = dfL0 - dfA0;
    dfH2 = dfL2 - dfA2;
    // hour angle at half hour
    dfH1 = (dfH2 + dfH0) / 2.0;
    // declination at half hour
    dfD1 = (dfD2 + dfD0) / 2.0;

    // Set value of dfV0 only if this is the first hour,
    // otherwise, it will get set to the last dfV2
    if (iCount == 0) {
    dfV0 = dfSinLat * Math.sin(dfD0) + dfCosLat * Math.cos(dfD0) * Math.cos(dfH0) - Math.cos(dfZenith);
    } else {
    dfV0 = dfV2; // That is, dfV2 from the previous hour.
    }

    dfV2 = dfSinLat * Math.sin(dfD2)
    + dfCosLat * Math.cos(dfD2) * Math.cos(dfH2)
    - Math.cos(dfZenith);

    // if dfV0 and dfV2 have the same sign, then proceed to next hr
    if ((dfV0 >= 0.0 && dfV2 >= 0.0) // both are positive
    || (dfV0 < 0.0 && dfV2 < 0.0) // both are negative
    ) {
    // Break iteration and proceed to test next hour
    dfA0 = dfA2;
    dfD0 = dfD2;
    continue;
    }

    dfV1 = dfSinLat * Math.sin(dfD1) + dfCosLat * Math.cos(dfD1) * Math.cos(dfH1) - Math.cos(dfZenith);

    tempA = 2.0 * dfV2 - 4.0 * dfV1 + 2.0 * dfV0;
    tempB = 4.0 * dfV1 - 3.0 * dfV0 - dfV2;
    tempD = tempB * tempB - 4.0 * tempA * dfV0;

    if (tempD < 0.0) {
    // Break iteration and proceed to test next hour
    dfA0 = dfA2;
    dfD0 = dfD2;
    continue;
    }

    tempD = Math.sqrt(tempD);

    // Determine occurence of sunrise or sunset.

    // Flags to identify occurrence during this day are
    // bSunriseToday and bSunsetToday, and are initialized false.
    // These are set true only if sunrise or sunset occurs
    // at any point in the hourly loop. Never set to false.

    // Flags to identify occurrence during this hour:
    bSunrise = false; // reset before test
    bSunset = false; // reset before test

    if (dfV0 < 0.0 && dfV2 > 0.0) { // sunrise occurs this hour
    bSunrise = true;
    bSunriseToday = true; // sunrise occurred today
    }

    if (dfV0 > 0.0 && dfV2 < 0.0) { // sunset occurs this hour
    bSunset = true;
    bSunsetToday = true; // sunset occurred today
    }

    tempE = (tempD - tempB) / (2.0 * tempA);
    if (tempE > 1.0 || tempE < 0.0) {
    tempE = (-tempD - tempB) / (2.0 * tempA);
    }
    // Set values of hour and minute of sunset or sunrise
    // only if sunrise/set occurred this hour.
    if (bSunrise) {
    dfHourRise = floor(dfC0 + tempE + 1.0 / 120.0);
    dfMinRise = floor((dfC0 + tempE + 1.0 / 120.0 - dfHourRise) * 60.0);
    }

    if (bSunset) {
    dfHourSet = floor(dfC0 + tempE + 1.0 / 120.0);
    dfMinSet = floor((dfC0 + tempE + 1.0 / 120.0 - dfHourSet) * 60.0);
    }

    // Change settings of variables for next loop
    dfA0 = dfA2;
    dfD0 = dfD2;

    } // end of loop testing each hour for an event

    // After having checked all hours, set flags if no rise or set
    // bSunUpAllDay and bSundownAllDay are initialized as false
    if (!bSunriseToday && !bSunsetToday) {
    if (dfV2 < 0.0) {
    bSunDownAllDay = true;
    } else {
    bSunUpAllDay = true;
    }
    }

    // set result to output array
    result[0] = dfHourRise;
    result[1] = dfMinRise;
    result[2] = dfHourSet;
    result[3] = dfMinSet;

    return result;
    }
    [/PHP]

    But do not ask me how it works. I have no clue. I copied this from some java code and just translate it to Monkey C.
  • I'm using Clarity Activity right now and love it. I tried the beta version on my fenix 3 running the 6.19 beta firmware and could not get it to work at all. The watch just displayed the default digital watch face, which I assume means Clarity Beta was crashing. Anything I can do to help diagnose the issue?
  • Same here fenix 3 firmware 6.19. Tried using clarity beta the face shows up but when changing the different colors and fields it crashes.
  • It looks promising, but I'm not able to configure it, either via Garmin Connect or via Garmin Express. In GC it crashes and returns to the default digital watch face and in Garmin Express the changes are not saved.
  • Former Member
    Former Member over 9 years ago
    Ive been following and occasionally use the Clarity watch face on my Fenix 3. The newest version of Clarity 1.3.3 is leaps and bounds above the previous version. The one hiccup on the old version I had was the battery life. Ive been running this newer version on my F3 with beta 6.63 for a couple days now and still at 80%. Bravo...

    However, I cant seem to get the MILITARY layout to work. Right now I am using Pilot which is fine but I much prefer Military layout.

    Am I doing something wrong?
  • Just installed Clarity and I'm using the 'Simple' layout with the 'Sun Times' arc. Congrats to the developer for the functionality and aesthetics!

    I have a question. What is this arrow below the time? Pressure trend? If so, it doesn't seem to work, although I got a couple of storm alerts on my watch the last hours.

    Also, a thought. Maybe the 'Sun Times' arc start should be at the 6 o'clock position and not at 0. This is way 'night' will be at the bottom of the screen and 'day' at the top. Also the position of the pointer would make more sense throughout the day.
  • Just installed Clarity and I'm using the 'Simple' layout with the 'Sun Times' arc. Congrats to the developer for the functionality and aesthetics!

    I have a question. What is this arrow below the time? Pressure trend? If so, it doesn't seem to work, although I got a couple of storm alerts on my watch the last hours.

    Also, a thought. Maybe the 'Sun Times' arc start should be at the 6 o'clock position and not at 0. This is way 'night' will be at the bottom of the screen and 'day' at the top. Also the position of the pointer would make more sense throughout the day.


    Yes, the arrow is for pressure trend, but it isn't active yet. I hope he can figure it out, that would be nice to know at a glance. But, he hasn't been active here since 12-1-15. Hopefully he isn't gone for good.

    I think "Clarity" is the most useful watch face in the store.