Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sunrise 0.07: account for altitude, use suncalc module #3103

Closed
wants to merge 15 commits into from

Conversation

bobrippling
Copy link
Collaborator

This continues the great job done by @g-rden in #3063, bringing in those changes but adjusting for the sinLUT changes mentioned in the previous PR.

@bobrippling
Copy link
Collaborator Author

@thyttan I'll merge this in, just wanted a second opinion before doing so - all ok by you?

solarNoonX = xFromTime(SunCalc.getTimes(now, lat, lon, alt).solarNoon);
sr = Locale.time(SunCalc.getTimes(now, lat, lon, alt).sunrise, 1);
ss = Locale.time(SunCalc.getTimes(now, lat, lon, alt).sunset, 1);
fillSineLUT();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fillSineLUT() isn't defined and so crashes the app on my watch with:

Uncaught ReferenceError: "fillSineLUT" is not defined
 at line 160 col 3 in sunrise.app.js
  fillSineLUT();
  ^
in function "initDay" called from line 243 col 11 in sunrise.app.js
  initDay();
          ^
in function "main" called from line 249 col 6 in sunrise.app.js
main();
     ^
Uncaught Error: Unhandled promise rejection: Error: Unhandled promise rejection: undefined
in function "getAltitude" called from line 154 col 15 in sunrise.app.js
getAltitude();
            ^
in function "initDay" called from line 170 col 13 in sunrise.app.js
    initDay();
            ^
in function "renderScreen" called from line 210 col 16 in sunrise.app.js
  renderScreen();
               ^
in function called from system
 at line 160 col 3 in sunrise.app.js
  fillSineLUT();
  ^
in function "initDay" called from line 170 col 13 in sunrise.app.js
    initDay();
            ^
in function "renderScreen" called from line 210 col 16 in sunrise.app.js
  renderScreen();
               ^
in function called from system

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I comment it out the app seems to work though :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... but the sun doesn't snap to the sine curve anymore. Maybe that can be tracked back to this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes - @g-rden's comment below is spot on for fixing this

}

function initDay () {
getAltitude();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what I did, but I got this uncaught undefined:

Uncaught undefined
in function "getAltitude" called from line 154 col 15 in sunrise.app.js
getAltitude();
            ^
in function "initDay" called from line 243 col 11 in sunrise.app.js
  initDay();
          ^
in function "main" called from line 249 col 6 in sunrise.app.js
main();
     ^
Uncaught Error: Unhandled promise rejection: undefined
> 

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got it now again just after starting the app.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting! I wonder if this is app-specific or another way of triggering what we see in the recorder PR

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I should reset my watch to see if it's something with my current setup.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's interesting - I don't see it when running either the broken or fixed version of this app, perhaps it's a strange bug on your device. What firmware are you on?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, but I think I've seen it on 2v19 stable and one or two 2v19.xx ones. Currently using 2v19.74.

Have not come around to backup and reset my watch yet. But will do that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, good luck! I'll keep my eye out for it appearing again too

@thyttan
Copy link
Collaborator

thyttan commented Nov 28, 2023

Some images showing some weird drawing behavior like said here: #3103 (comment).

image
First draw on app launch.

image
Clicking around, moving the sun and redrawing the time. Font color isn't stable and artifacts left since previous time/position (font issue also present on v0.06).

image
Another example, similar to the second picture above.

@bobrippling
Copy link
Collaborator Author

Ah thanks for checking, think I must've been asleep - I'll sort out that function and the sun being off

@g-rden
Copy link
Contributor

g-rden commented Nov 29, 2023

sorry to dump this like that but i don't have much time rn.
there still were some things that were neede for the sinLUT.
this works for me

// banglejs app made by pancake

const LOCATION_FILE = 'mylocation.json';
let location;

Bangle.setUI('clock');
Bangle.loadWidgets();
// requires the myLocation app
function loadLocation () {
  try {
    return require('Storage').readJSON(LOCATION_FILE, 1);
  } catch (e) {
    return { lat: 41.38, lon: 2.168 };
  }
}

const latlon = loadLocation() || {};
const lat = latlon.lat || 41.38;
const lon = latlon.lon || 2.168;

const w = g.getWidth();
const h = g.getHeight();

let sunRiseX;
let sunSetX;
let solarNoonX;

let pos = 0;
let realTime = true;
const r = 10;

let frames = 0; // amount of pending frames to render (0 if none)
let curPos = 0; // x position of the sun
let realPos = 0; // x position of the sun depending on currentime

let day;
let now = new Date();

let sr; // sunrise formatted as time
let ss; // sunset formatted as time

let slope; // slope for sea leve line
let yint; // y-intercept for sea leve line

const Locale = require("locale");
const SunCalc = require("suncalc");

let alt = 0; // altitude

let daystart = new Date();
daystart.setHours(0);
daystart.setMinutes(0);
daystart.setSeconds(0);

function getAltitude () {
  const p = Bangle.getPressure();
  if (p) {
    p.then(d => {
      if (d) alt = d.altitude;
    });
  }
}

function drawSinuses () {
  // messy because 1d array for 2 axes
  const array = [];
  const sinStep = 12;
  let i;
  g.setColor(1, 1, 1);

  for (i = 0; i <= w - sinStep; i += sinStep) {
    array.push(i, ypos(i));
  }
  array.push(w, ypos(w));
  g.drawPoly(array, false);
  print(array.length);
}

function calcSeaLevel () {
  slope = (ypos(sunSetX) - ypos(sunRiseX)) /
          (sunSetX - sunRiseX);
  yint = ypos(sunSetX) - slope * sunSetX;
}

function drawSeaLevel () {
  // sea level line

  g.setColor(0, 0.5, 1);

  g.drawLine(0, yint, w, slope * w + yint);
  g.drawLine(0, yint + 1, w, slope * w + yint + 1);
}

function drawTimes () {
  g.setColor(1, 1, 1);
  g.setFont('6x8', 2);
  g.drawString(sr, 6, h - 20);
  g.drawString(ss, w - 64, h - 20);
}

function drawGlow () {
  g.setColor(0.2, 0.2, 0);
  // wide glow
  if (pos > sunRiseX && pos < sunSetX) {
    g.fillCircle(pos, ypos(pos), r + 20);
    g.setColor(0.5, 0.5, 0);
  }
  // smol glow
  g.fillCircle(pos, ypos(pos), r + 8);
}

function ypos (x) {
  return (h / 1.7) + (32 * Math.sin(-(2 * Math.PI * x / w
                                    - (Math.PI * solarNoonX) / w)));
}

function xFromTime (time) {
  return Math.round((w / 24) * (time.getHours() + time.getMinutes() / 60));
}

function drawBall () {
  // glow
  if (pos > sunRiseX && pos < sunSetX) {
    g.setColor(1, 1, 1);
  } else {
    g.setColor(0.5, 0.5, 0);
  }
  g.fillCircle(pos, ypos(pos), r);
  g.setColor(1, 1, 0);
  g.drawCircle(pos, ypos(pos), r);
}

function drawClock () {
  let posTime;

  if (realTime) {
    posTime = now;

    // day-month
    const mo = now.getMonth() + 1;
    const da = now.getDate();
    g.setFont('6x8', 2);
    g.drawString(da + '/' + mo, 6, 30);
  } else {
    posTime = new Date(24 * 3600 * (pos / w) * 1000 +
                       60 * now.getTimezoneOffset() * 1000);
  }
  g.setFont('Vector', 30);
  g.setColor(realTime, 1, 1);
  g.drawString(Locale.time(posTime, 1), w / 1.9, 32);
}

function initDay () {
  getAltitude();
  sunRiseX = xFromTime(SunCalc.getTimes(now, lat, lon, alt).sunrise);
  sunSetX = xFromTime(SunCalc.getTimes(now, lat, lon, alt).sunset);
  solarNoonX = xFromTime(SunCalc.getTimes(now, lat, lon, alt).solarNoon);
  sr = Locale.time(SunCalc.getTimes(now, lat, lon, alt).sunrise, 1);
  ss = Locale.time(SunCalc.getTimes(now, lat, lon, alt).sunset, 1);
  //fillSineLUT();
  calcSeaLevel();

  day = now.getDate();
}

function renderScreen () {
  now = new Date();

  if (day != now.getDate()) {
    initDay();
  }

  g.setColor(0, 0, 0);
  g.fillRect(0, 30, w, h);
  realPos = xFromTime(now);

  if (realTime) {
    pos = realPos;
  }

  // limit to screen bounds
  if (pos < 0) {
    pos = 0;
  } else if (pos > 175) {
    pos = 175;
  }

  Bangle.drawWidgets();

  drawGlow();
  drawSinuses();
  drawSeaLevel();
  drawTimes();
  drawClock();
  drawBall();
}

Bangle.on('drag', function (tap, top) {
  if (tap.y < h / 3) {
    initialAnimation();
  } else {
    pos = tap.x;
    realTime = false;
    renderScreen();
  }
});

Bangle.on('lock', () => {
  realTime = true;
  renderScreen();
});

function initialAnimationFrame () {
  if (frames >= 1) {
    let distance = (realPos - pos) / frames;
    renderScreen();
    pos += distance;
    frames--;
    setTimeout(initialAnimationFrame, 50);
  } else {
    realTime = true;
    renderScreen();
  }
}

function initialAnimation () {
  realPos = xFromTime(now);
  const distance = Math.abs(realPos - pos);
  frames = distance / 16;
  realTime = false;
  initialAnimationFrame();
}

function renderAndQueue() {
  setTimeout(renderAndQueue, 60000 - (Date.now() % 60000));
  renderScreen();
}

function main () {
  g.setBgColor(0, 0, 0);
  g.clear();

  initDay();

  renderAndQueue();
  initialAnimation();
}

main();

@bobrippling
Copy link
Collaborator Author

sorry to dump this like that but i don't have much time rn.
there still were some things that were neede for the sinLUT.
this works for me

Yes that's sorted it nicely, thank you!

I notice the sea slope is flat on either version of the code, I've tried with a few locations so I'll need to fix that before this PR is ready too

@bobrippling bobrippling marked this pull request as draft November 29, 2023 22:03
@g-rden
Copy link
Contributor

g-rden commented Nov 29, 2023

Flat, like completely horizontal? It's not that for me, depending on location. And it should not be very steep, it might have been incorrect in the past, idk anymore.

To try out locations you have to set const lat, cont lon and replace now.getTimezoneOffset() with the correct value for the location and compare times with example https://www.suncalc.org. And if you want, set now to another time. Sorry if that's all obvious

@bobrippling
Copy link
Collaborator Author

Flat, like completely horizontal?

Yes I think so - shall double check and debug it to confirm. Thanks for the usage details, didn't know about the website link in particular!

@bobrippling
Copy link
Collaborator Author

I've tried with multiple locations and I always see slope == 0, perhaps I've not got the right locations?

@g-rden
Copy link
Contributor

g-rden commented Dec 12, 2023

What are the values of ss and sr? Are they correct?

@bobrippling
Copy link
Collaborator Author

Yes, here's the console output - sadly very short daylight hours this time of year!

{
  "ss": "15:38",
  "sr": " 8:22"
 }
slope = 0

@g-rden
Copy link
Contributor

g-rden commented Dec 20, 2023

Sorry, it took me until now to check. I can't get the slope to have the wrong angle. If interception of the slope and the sun sine graph is at the sunrise/sunset time then the angle of the slope ought to be correct. But I doubt that is the case, because you say the slope is exactly 0 and not a very tiny number. I am out of ideas.

y = y2;
x += sinStep; // no need to draw all steps

for (i = 0; i <= w - sinStep; i += sinStep) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sine function can look crooked at the right side of the screen.

It should be like this instead:
for (i = 0; i <= w; i += sinStep) {

The 'w - sinStep' made sense before, but not anymore.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah thank you - sorted that now

@bobrippling
Copy link
Collaborator Author

Sorry, it took me until now to check. I can't get the slope to have the wrong angle

No worries, if the code on the branch works ok for you, I'm happy to merge it and I can investigate specifics of my setup

@bobrippling bobrippling deleted the sunrise-0.07 branch April 20, 2024 10:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants