153 lines
4.6 KiB
Python
153 lines
4.6 KiB
Python
# environment/pysky.py
|
|
|
|
import logging
|
|
from datetime import datetime, timedelta
|
|
from math import acos, asin, ceil, cos, degrees, fmod
|
|
from math import pi as PI
|
|
from math import radians, sin, sqrt
|
|
|
|
from constants import Coordinate
|
|
from tools.julian import from_julian, julian_date
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class Sun:
|
|
|
|
@staticmethod
|
|
def _calc(location: Coordinate, date: datetime, elevation: float = 0.0) -> dict:
|
|
J_date = julian_date(date)
|
|
n = ceil(J_date - (2451545.0 + 0.0009) + 69.184 / 86400.0) - 1
|
|
J_ = n + 0.0009 - location.long / 360.0
|
|
M_degrees = fmod(357.5291 + 0.98560028 * J_, 360)
|
|
M_radians = radians(M_degrees)
|
|
C_degrees = (
|
|
1.9148 * sin(M_radians)
|
|
+ 0.02 * sin(2 * M_radians)
|
|
+ 0.0003 * sin(3 * M_radians)
|
|
)
|
|
L_degrees = fmod(M_degrees + C_degrees + 180.0 + 102.9372, 360)
|
|
Lambda_radians = radians(L_degrees)
|
|
J_transit = (
|
|
2451545.0 + J_ + 0.0053 * sin(M_radians) - 0.0069 * sin(2 * Lambda_radians)
|
|
)
|
|
sin_d = sin(Lambda_radians) * sin(radians(23.4397))
|
|
cos_d = cos(asin(sin_d))
|
|
some_cos = (
|
|
sin(radians(-0.833 - 2.076 * sqrt(elevation) / 60.0))
|
|
- sin(radians(location.lat)) * sin_d
|
|
) / (cos(radians(location.lat)) * cos_d)
|
|
|
|
try:
|
|
w0_radians = acos(some_cos)
|
|
except ValueError:
|
|
return {"sunrise": "--:--", "sunset": "--:--"}
|
|
|
|
w0_degrees = degrees(w0_radians)
|
|
j_rise = J_transit - w0_degrees / 360
|
|
j_set = J_transit + w0_degrees / 360
|
|
|
|
sunset_time = from_julian(j_set)
|
|
sunrise_time = from_julian(j_rise)
|
|
|
|
return {
|
|
"sunrise": f"{sunrise_time.hour:02d}:{sunrise_time.minute:02d}",
|
|
"sunset": f"{sunset_time.hour:02d}:{sunset_time.minute:02d}",
|
|
}
|
|
|
|
@staticmethod
|
|
def get_sunset_sunrise(location: Coordinate, date: datetime | None = None) -> dict:
|
|
if date is None:
|
|
date = datetime.now()
|
|
logger.debug("Calculating Sun trajectory...")
|
|
return Sun._calc(location, date)
|
|
|
|
|
|
class Moon:
|
|
|
|
@staticmethod
|
|
def _illumination_name(illumination: float, waxing: bool = True) -> str:
|
|
if illumination > 0.996:
|
|
return "Fullmåne"
|
|
elif illumination > 0.57:
|
|
return "Tilltagande halvmåne" if waxing else "Avtagande halvmåne"
|
|
elif illumination > 0.43:
|
|
return "Halvmåne (tilltagande)" if waxing else "Halvmåne (avtagande)"
|
|
elif illumination > 0.02:
|
|
return "Tilltagande skära" if waxing else "Avtagande skära"
|
|
else:
|
|
return "Nymåne"
|
|
|
|
@staticmethod
|
|
def _constrain(d: float) -> float:
|
|
t = d % 360
|
|
if t < 0:
|
|
t += 360
|
|
return t
|
|
|
|
@staticmethod
|
|
def _get_illuminated_fraction(jd: float) -> float:
|
|
toRad = PI / 180.0
|
|
T = (jd - 2451545) / 36525.0
|
|
D = (
|
|
Moon._constrain(
|
|
297.8501921
|
|
+ 445267.1114034 * T
|
|
- 0.0018819 * T * T
|
|
+ 1.0 / 545868.0 * T * T * T
|
|
- 1.0 / 113065000.0 * T * T * T * T
|
|
)
|
|
* toRad
|
|
)
|
|
M = (
|
|
Moon._constrain(
|
|
357.5291092
|
|
+ 35999.0502909 * T
|
|
- 0.0001536 * T * T
|
|
+ 1.0 / 24490000.0 * T * T * T
|
|
)
|
|
* toRad
|
|
)
|
|
Mp = (
|
|
Moon._constrain(
|
|
134.9633964
|
|
+ 477198.8675055 * T
|
|
+ 0.0087414 * T * T
|
|
+ 1.0 / 69699.0 * T * T * T
|
|
- 1.0 / 14712000.0 * T * T * T * T
|
|
)
|
|
* toRad
|
|
)
|
|
i = (
|
|
Moon._constrain(
|
|
180
|
|
- D * 180 / PI
|
|
- 6.289 * sin(Mp)
|
|
+ 2.1 * sin(M)
|
|
- 1.274 * sin(2 * D - Mp)
|
|
- 0.658 * sin(2 * D)
|
|
- 0.214 * sin(2 * Mp)
|
|
- 0.11 * sin(D)
|
|
)
|
|
* toRad
|
|
)
|
|
return (1 + cos(i)) / 2
|
|
|
|
@staticmethod
|
|
def get_illumination(date: datetime | None = None) -> dict:
|
|
if date is None:
|
|
date = datetime.now()
|
|
logger.debug("Calculating Moon illumination...")
|
|
|
|
i = Moon._get_illuminated_fraction(julian_date(date))
|
|
i_future = Moon._get_illuminated_fraction(
|
|
julian_date(date + timedelta(seconds=1))
|
|
)
|
|
waxing = i_future > i
|
|
|
|
return {
|
|
"moon_illumination": round(i, 4),
|
|
"moon_phase": Moon._illumination_name(i, waxing),
|
|
"waxing": waxing,
|
|
}
|