diff --git a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/AstroBindingConstants.java b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/AstroBindingConstants.java index 6d7a87d5bf..2afe6959de 100644 --- a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/AstroBindingConstants.java +++ b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/AstroBindingConstants.java @@ -49,14 +49,9 @@ public final class AstroBindingConstants { public static final String EVENT_PHASE_FULL = "FULL"; public static final String EVENT_PHASE_NEW = "NEW"; - public static final String EVENT_PERIGEE = "PERIGEE"; - public static final String EVENT_APOGEE = "APOGEE"; - // event channelIds public static final String EVENT_CHANNEL_ID_MOON_PHASE = "phase#event"; public static final String EVENT_CHANNEL_ID_ECLIPSE = "eclipse#event"; - public static final String EVENT_CHANNEL_ID_PERIGEE = "perigee#event"; - public static final String EVENT_CHANNEL_ID_APOGEE = "apogee#event"; public static final String EVENT_CHANNEL_ID_RISE = "rise#event"; public static final String EVENT_CHANNEL_ID_SET = "set#event"; diff --git a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/calc/MoonCalc.java b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/calc/MoonCalc.java index 624aff0d87..41bb388b6d 100644 --- a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/calc/MoonCalc.java +++ b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/calc/MoonCalc.java @@ -18,14 +18,15 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Calendar; import java.util.Locale; +import java.util.Set; import java.util.TimeZone; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.astro.internal.model.DistanceType; import org.openhab.binding.astro.internal.model.Eclipse; import org.openhab.binding.astro.internal.model.EclipseKind; import org.openhab.binding.astro.internal.model.EclipseType; import org.openhab.binding.astro.internal.model.Moon; -import org.openhab.binding.astro.internal.model.MoonDistance; import org.openhab.binding.astro.internal.model.MoonPhase; import org.openhab.binding.astro.internal.model.MoonPhaseName; import org.openhab.binding.astro.internal.model.Position; @@ -95,16 +96,8 @@ public class MoonCalc { } }); - double decimalYear = DateTimeUtils.getDecimalYear(calendar); - MoonDistance apogee = moon.getApogee(); - double apogeeJd = getApogee(julianDate, decimalYear); - apogee.setDate(DateTimeUtils.toCalendar(apogeeJd, zone, locale)); - apogee.setDistance(getDistance(apogeeJd)); - - MoonDistance perigee = moon.getPerigee(); - double perigeeJd = getPerigee(julianDate, decimalYear); - perigee.setDate(DateTimeUtils.toCalendar(perigeeJd, zone, locale)); - perigee.setDistance(getDistance(perigeeJd)); + Set.of(DistanceType.APOGEE, DistanceType.PERIGEE) + .forEach(type -> moon.setDistance(type, MoonDistanceCalc.get(type, julianDate))); return moon; } @@ -118,9 +111,7 @@ public class MoonCalc { setMoonPhase(calendar, moon, zone, locale); setAzimuthElevationZodiac(julianDate, latitude, longitude, moon); - MoonDistance distance = moon.getDistance(); - distance.setDate(calendar); - distance.setDistance(getDistance(julianDate)); + moon.setDistance(DistanceType.CURRENT, MoonDistanceCalc.calculate(julianDate)); } /** @@ -437,88 +428,6 @@ public class MoonCalc { return eclipseJd; } - /** - * Calculates the date, where the moon is furthest away from the earth. - */ - private double getApogee(double julianDate, double decimalYear) { - double k = Math.floor((decimalYear - 1999.97) * 13.2555) + .5; - double jd = 0; - do { - double t = k / 1325.55; - double d = 171.9179 + 335.9106046 * k - .010025 * t * t - .00001156 * t * t * t - + .000000055 * t * t * t * t; - double m = 347.3477 + 27.1577721 * k - .0008323 * t * t - .000001 * t * t * t; - double f = 316.6109 + 364.5287911 * k - .0125131 * t * t - .0000148 * t * t * t; - jd = 2451534.6698 + 27.55454988 * k - .0006886 * t * t - .000001098 * t * t * t + .0000000052 * t * t - + .4392 * sinDeg(2 * d) + .0684 * sinDeg(4 * d) + (.0456 - .00011 * t) * sinDeg(m) - + (.0426 - .00011 * t) * sinDeg(2 * d - m) + .0212 * sinDeg(2 * f); - jd += -.0189 * sinDeg(d) + .0144 * sinDeg(6 * d) + .0113 * sinDeg(4 * d - m) + .0047 * sinDeg(2 * d + 2 * f) - + .0036 * sinDeg(d + m) + .0035 * sinDeg(8 * d) + .0034 * sinDeg(6 * d - m) - - .0034 * sinDeg(2 * d - 2 * f) + .0022 * sinDeg(2 * d - 2 * m) - .0017 * sinDeg(3 * d); - jd += .0013 * sinDeg(4 * d + 2 * f) + .0011 * sinDeg(8 * d - m) + .001 * sinDeg(4 * d - 2 * m) - + .0009 * sinDeg(10 * d) + .0007 * sinDeg(3 * d + m) + .0006 * sinDeg(2 * m) - + .0005 * sinDeg(2 * d + m) + .0005 * sinDeg(2 * d + 2 * m) + .0004 * sinDeg(6 * d + 2 * f); - jd += .0004 * sinDeg(6 * d - 2 * m) + .0004 * sinDeg(10 * d - m) - .0004 * sinDeg(5 * d) - - .0004 * sinDeg(4 * d - 2 * f) + .0003 * sinDeg(2 * f + m) + .0003 * sinDeg(12 * d) - + .0003 * sinDeg(2 * d + 2 * f - m) - .0003 * sinDeg(d - m); - k += 1; - } while (jd < julianDate); - return jd; - } - - /** - * Calculates the date, where the moon is closest to the earth. - */ - private double getPerigee(double julianDate, double decimalYear) { - double k = Math.floor((decimalYear - 1999.97) * 13.2555); - double jd = 0; - do { - double t = k / 1325.55; - double d = 171.9179 + 335.9106046 * k - .010025 * t * t - .00001156 * t * t * t - + .000000055 * t * t * t * t; - double m = 347.3477 + 27.1577721 * k - .0008323 * t * t - .000001 * t * t * t; - double f = 316.6109 + 364.5287911 * k - .0125131 * t * t - .0000148 * t * t * t; - jd = 2451534.6698 + 27.55454988 * k - .0006886 * t * t - .000001098 * t * t * t + .0000000052 * t * t - - 1.6769 * sinDeg(2 * d) + .4589 * sinDeg(4 * d) - .1856 * sinDeg(6 * d) + .0883 * sinDeg(8 * d); - jd += -(.0773 + .00019 * t) * sinDeg(2 * d - m) + (.0502 - .00013 * t) * sinDeg(m) - .046 * sinDeg(10 * d) - + (.0422 - .00011 * t) * sinDeg(4 * d - m) - .0256 * sinDeg(6 * d - m) + .0253 * sinDeg(12 * d) - + .0237 * sinDeg(d); - jd += .0162 * sinDeg(8 * d - m) - .0145 * sinDeg(14 * d) + .0129 * sinDeg(2 * f) - .0112 * sinDeg(3 * d) - - .0104 * sinDeg(10 * d - m) + .0086 * sinDeg(16 * d) + .0069 * sinDeg(12 * d - m) - + .0066 * sinDeg(5 * d) - .0053 * sinDeg(2 * d + 2 * f); - jd += -.0052 * sinDeg(18 * d) - .0046 * sinDeg(14 * d - m) - .0041 * sinDeg(7 * d) - + .004 * sinDeg(2 * d + m) + .0032 * sinDeg(20 * d) - .0032 * sinDeg(d + m) - + .0031 * sinDeg(16 * d - m); - jd += -.0029 * sinDeg(4 * d + m) - .0027 * sinDeg(2 * d - 2 * m) + .0024 * sinDeg(4 * d - 2 * m) - - .0021 * sinDeg(6 * d - 2 * m) - .0021 * sinDeg(22 * d) - .0021 * sinDeg(18 * d - m); - jd += .0019 * sinDeg(6 * d + m) - .0018 * sinDeg(11 * d) - .0014 * sinDeg(8 * d + m) - - .0014 * sinDeg(4 * d - 2 * f) - .0014 * sinDeg(6 * d - 2 * f) + .0014 * sinDeg(3 * d + m) - - .0014 * sinDeg(5 * d + m) + .0013 * sinDeg(13 * d); - jd += .0013 * sinDeg(20 * d - m) + .0011 * sinDeg(3 * d + 2 * m) - .0011 * sinDeg(4 * d + 2 * f - 2 * m) - - .001 * sinDeg(d + 2 * m) - .0009 * sinDeg(22 * d - m) - .0008 * sinDeg(4 * f) - + .0008 * sinDeg(6 * d - 2 * f) + .0008 * sinDeg(2 * d - 2 * f + m); - jd += .0007 * sinDeg(2 * m) + .0007 * sinDeg(2 * f - m) + .0007 * sinDeg(2 * d + 4 * f) - - .0006 * sinDeg(2 * f - 2 * m) - .0006 * sinDeg(2 * d - 2 * f + 2 * m) + .0006 * sinDeg(24 * d) - + .0005 * sinDeg(4 * d - 4 * f) + .0005 * sinDeg(2 * d + 2 * m) - .0004 * sinDeg(d - m) - + .0027 * sinDeg(9 * d) + .0027 * sinDeg(4 * d + 2 * f); - k += 1; - } while (jd < julianDate); - return jd; - } - - /** - * Calculates the distance from the moon to earth. - */ - private double getDistance(double jd) { - double t = (jd - 2451545) / 36525; - double d = 297.8502042 + 445267.11151686 * t - .00163 * t * t + t * t * t / 545868 - t * t * t * t / 113065000; - double m = 357.5291092 + 35999.0502909 * t - .0001536 * t * t + t * t * t / 24490000; - double m1 = 134.9634114 + 477198.8676313 * t + .008997 * t * t + t * t * t / 69699 - t * t * t * t / 14712000; - double f = 93.27209929999999 + 483202.0175273 * t - .0034029 * t * t - t * t * t / 3526000 - + t * t * t * t / 863310000; - return 385000.56 + getCoefficient(d, m, m1, f) / 1000; - } - private double[] calcMoon(double t) { double p2 = 6.283185307; double arc = 206264.8062; @@ -647,27 +556,6 @@ public class MoonCalc { return ret; } - private double getCoefficient(double d, double m, double m1, double f) { - int[] kd = new int[] { 0, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 1, 0, 2, 0, 0, 4, 0, 4, 2, 2, 1, 1, 2, 2, 4, 2, 0, 2, 2, - 1, 2, 0, 0, 2, 2, 2, 4, 0, 3, 2, 4, 0, 2, 2, 2, 4, 0, 4, 1, 2, 0, 1, 3, 4, 2, 0, 1, 2, 2 }; - int[] km = new int[] { 0, 0, 0, 0, 1, 0, 0, -1, 0, -1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, -1, 0, 0, 0, 1, 0, - -1, 0, -2, 1, 2, -2, 0, 0, -1, 0, 0, 1, -1, 2, 2, 1, -1, 0, 0, -1, 0, 1, 0, 1, 0, 0, -1, 2, 1, 0, 0 }; - int[] km1 = new int[] { 1, -1, 0, 2, 0, 0, -2, -1, 1, 0, -1, 0, 1, 0, 1, 1, -1, 3, -2, -1, 0, -1, 0, 1, 2, 0, - -3, -2, -1, -2, 1, 0, 2, 0, -1, 1, 0, -1, 2, -1, 1, -2, -1, -1, -2, 0, 1, 4, 0, -2, 0, 2, 1, -2, -3, 2, - 1, -1, 3, -1 }; - int[] kf = new int[] { 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, -2, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, -2, 2, 0, 2, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0, 0, -2 }; - int[] kr = new int[] { -20905355, -3699111, -2955968, -569925, 48888, -3149, 246158, -152138, -170733, -204586, - -129620, 108743, 104755, 10321, 0, 79661, -34782, -23210, -21636, 24208, 30824, -8379, -16675, -12831, - -10445, -11650, 14403, -7003, 0, 10056, 6322, -9884, 5751, 0, -4950, 4130, 0, -3958, 0, 3258, 2616, - -1897, -2117, 2354, 0, 0, -1423, -1117, -1571, -1739, 0, -4421, 0, 0, 0, 0, 1165, 0, 0, 8752 }; - double sr = 0; - for (int t = 0; t < 60; t++) { - sr += kr[t] * cosDeg(kd[t] * d + km[t] * m + km1[t] * m1 + kf[t] * f); - } - return sr; - } - /** * Sets the azimuth, elevation and zodiac in the moon object. */ diff --git a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/calc/MoonDistanceCalc.java b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/calc/MoonDistanceCalc.java new file mode 100644 index 0000000000..07e125583d --- /dev/null +++ b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/calc/MoonDistanceCalc.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2010-2026 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.astro.internal.calc; + +import static java.lang.Math.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.astro.internal.model.DistanceType; +import org.openhab.binding.astro.internal.model.MoonDistance; +import org.openhab.binding.astro.internal.util.AstroConstants; +import org.openhab.binding.astro.internal.util.DateTimeUtils; + +/** + * Moon Distance Calculator + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class MoonDistanceCalc { + private static final double ANOMALISTIC_MONTH = 27.55454988; + private static final double JDE_0 = 2451534.6698; + private static final int[] KD = new int[] { 0, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 1, 0, 2, 0, 0, 4, 0, 4, 2, 2, 1, 1, 2, + 2, 4, 2, 0, 2, 2, 1, 2, 0, 0, 2, 2, 2, 4, 0, 3, 2, 4, 0, 2, 2, 2, 4, 0, 4, 1, 2, 0, 1, 3, 4, 2, 0, 1, 2, + 2 }; + private static final int[] KM = new int[] { 0, 0, 0, 0, 1, 0, 0, -1, 0, -1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, + -1, 0, 0, 0, 1, 0, -1, 0, -2, 1, 2, -2, 0, 0, -1, 0, 0, 1, -1, 2, 2, 1, -1, 0, 0, -1, 0, 1, 0, 1, 0, 0, -1, + 2, 1, 0, 0 }; + private static final int[] KM1 = new int[] { 1, -1, 0, 2, 0, 0, -2, -1, 1, 0, -1, 0, 1, 0, 1, 1, -1, 3, -2, -1, 0, + -1, 0, 1, 2, 0, -3, -2, -1, -2, 1, 0, 2, 0, -1, 1, 0, -1, 2, -1, 1, -2, -1, -1, -2, 0, 1, 4, 0, -2, 0, 2, 1, + -2, -3, 2, 1, -1, 3, -1 }; + private static final int[] KF = new int[] { 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, -2, 2, -2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, -2, 2, 0, 2, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0, + 0, -2 }; + private static final int[] KR = new int[] { -20905355, -3699111, -2955968, -569925, 48888, -3149, 246158, -152138, + -170733, -204586, -129620, 108743, 104755, 10321, 0, 79661, -34782, -23210, -21636, 24208, 30824, -8379, + -16675, -12831, -10445, -11650, 14403, -7003, 0, 10056, 6322, -9884, 5751, 0, -4950, 4130, 0, -3958, 0, + 3258, 2616, -1897, -2117, 2354, 0, 0, -1423, -1117, -1571, -1739, 0, -4421, 0, 0, 0, 0, 1165, 0, 0, 8752 }; + + /** + * Calculates the distance from the moon to earth in metres + */ + public static MoonDistance calculate(double jd) { + double t = DateTimeUtils.toJulianCenturies(jd); + double t2 = t * t; + double t3 = t2 * t; + double t4 = t3 * t; + double d = toRadians(297.8502042 + 445267.11151686 * t - .00163 * t2 + t3 / 545868 - t4 / 113065000); + double m = toRadians(AstroConstants.E05_0 + 35999.0502909 * t - .0001536 * t2 + t3 / 24490000); + double m1 = toRadians(134.9634114 + 477198.8676313 * t + .008997 * t2 + t3 / 69699 - t4 / 14712000); + double f = toRadians(93.2720993 + 483202.0175273 * t - .0034029 * t2 - t3 / 3526000 + t4 / 863310000); + return new MoonDistance(jd, 385000560 + getCoefficient(d, m, m1, f)); + } + + public static MoonDistance get(DistanceType type, double julianDate) { + if (DistanceType.CURRENT.equals(type)) { + throw new IllegalArgumentException("MoonDistanceCalc.get only supports APOGEE and PERIGEE"); + } + + double moment = getApogeePerigee(type, julianDate); + return calculate(moment); + } + + private static double getCoefficient(double d, double m, double m1, double f) { + double sr = 0; + for (int t = 0; t < 60; t++) { + sr += KR[t] * cos(KD[t] * d + KM[t] * m + KM1[t] * m1 + KF[t] * f); + } + return sr; + } + + /** + * Calculates the Julian date of the specified lunar distance extreme relative to the earth. + * Depending on the given {@link DistanceType}, this returns either the apogee (furthest distance) + * or the perigee (closest distance) that occurs on or after the given reference date. + * + * @param type the distance type to calculate (APOGEE or PERIGEE) + * @param julianDate the reference Julian date from which to search forward + * @return the Julian date of the requested lunar distance extreme + */ + private static double getApogeePerigee(DistanceType type, double julianDate) { + double k = floor((julianDate - JDE_0) / ANOMALISTIC_MONTH) + (type.equals(DistanceType.APOGEE) ? 0.5 : 0) - 1; + double jd = 0; + do { + double t = k / 1325.55; + double t2 = t * t; + double t3 = t2 * t; + double t4 = t3 * t; + double d = toRadians(171.9179 + 335.9106046 * k - .010025 * t2 - .00001156 * t3 + .000000055 * t4); + double m = toRadians(347.3477 + 27.1577721 * k - .0008323 * t2 - .000001 * t3); + double f = toRadians(316.6109 + 364.5287911 * k - .0125131 * t2 - .0000148 * t3); + jd = JDE_0 + ANOMALISTIC_MONTH * k - .0006886 * t2 - .000001098 * t3 + .0000000052 * t2; + if (DistanceType.APOGEE.equals(type)) { + jd += .4392 * sin(2 * d) + .0684 * sin(4 * d) + (.0456 - .00011 * t) * sin(m) + + (.0426 - .00011 * t) * sin(2 * d - m) + .0212 * sin(2 * f); + jd += -.0189 * sin(d) + .0144 * sin(6 * d) + .0113 * sin(4 * d - m) + .0047 * sin(2 * d + 2 * f) + + .0036 * sin(d + m) + .0035 * sin(8 * d) + .0034 * sin(6 * d - m) - .0034 * sin(2 * d - 2 * f) + + .0022 * sin(2 * d - 2 * m) - .0017 * sin(3 * d); + jd += .0013 * sin(4 * d + 2 * f) + .0011 * sin(8 * d - m) + .001 * sin(4 * d - 2 * m) + + .0009 * sin(10 * d) + .0007 * sin(3 * d + m) + .0006 * sin(2 * m) + .0005 * sin(2 * d + m) + + .0005 * sin(2 * d + 2 * m) + .0004 * sin(6 * d + 2 * f); + jd += .0004 * sin(6 * d - 2 * m) + .0004 * sin(10 * d - m) - .0004 * sin(5 * d) + - .0004 * sin(4 * d - 2 * f) + .0003 * sin(2 * f + m) + .0003 * sin(12 * d) + + .0003 * sin(2 * d + 2 * f - m) - .0003 * sin(d - m); + } else if (DistanceType.PERIGEE.equals(type)) { + jd += -1.6769 * sin(2 * d) + .4589 * sin(4 * d) - .1856 * sin(6 * d) + .0883 * sin(8 * d); + jd += -(.0773 + .00019 * t) * sin(2 * d - m) + (.0502 - .00013 * t) * sin(m) - .046 * sin(10 * d) + + (.0422 - .00011 * t) * sin(4 * d - m) - .0256 * sin(6 * d - m) + .0253 * sin(12 * d) + + .0237 * sin(d); + jd += .0162 * sin(8 * d - m) - .0145 * sin(14 * d) + .0129 * sin(2 * f) - .0112 * sin(3 * d) + - .0104 * sin(10 * d - m) + .0086 * sin(16 * d) + .0069 * sin(12 * d - m) + .0066 * sin(5 * d) + - .0053 * sin(2 * d + 2 * f); + jd += -.0052 * sin(18 * d) - .0046 * sin(14 * d - m) - .0041 * sin(7 * d) + .004 * sin(2 * d + m) + + .0032 * sin(20 * d) - .0032 * sin(d + m) + .0031 * sin(16 * d - m); + jd += -.0029 * sin(4 * d + m) - .0027 * sin(2 * d - 2 * m) + .0024 * sin(4 * d - 2 * m) + - .0021 * sin(6 * d - 2 * m) - .0021 * sin(22 * d) - .0021 * sin(18 * d - m); + jd += .0019 * sin(6 * d + m) - .0018 * sin(11 * d) - .0014 * sin(8 * d + m) - .0014 * sin(4 * d - 2 * f) + - .0014 * sin(6 * d - 2 * f) + .0014 * sin(3 * d + m) - .0014 * sin(5 * d + m) + + .0013 * sin(13 * d); + jd += .0013 * sin(20 * d - m) + .0011 * sin(3 * d + 2 * m) - .0011 * sin(4 * d + 2 * f - 2 * m) + - .001 * sin(d + 2 * m) - .0009 * sin(22 * d - m) - .0008 * sin(4 * f) + + .0008 * sin(6 * d - 2 * f) + .0008 * sin(2 * d - 2 * f + m); + jd += .0007 * sin(2 * m) + .0007 * sin(2 * f - m) + .0007 * sin(2 * d + 4 * f) + - .0006 * sin(2 * f - 2 * m) - .0006 * sin(2 * d - 2 * f + 2 * m) + .0006 * sin(24 * d) + + .0005 * sin(4 * d - 4 * f) + .0005 * sin(2 * d + 2 * m) - .0004 * sin(d - m) + + .0027 * sin(9 * d) + .0027 * sin(4 * d + 2 * f); + } + k += 1; + } while (jd < julianDate); + return jd; + } +} diff --git a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/job/DailyJobMoon.java b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/job/DailyJobMoon.java index 0e66968c82..3c54c93377 100644 --- a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/job/DailyJobMoon.java +++ b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/job/DailyJobMoon.java @@ -15,12 +15,15 @@ package org.openhab.binding.astro.internal.job; import static org.openhab.binding.astro.internal.AstroBindingConstants.*; import static org.openhab.binding.astro.internal.job.Job.scheduleEvent; +import java.time.Instant; import java.util.Calendar; import java.util.Locale; +import java.util.Set; import java.util.TimeZone; import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.astro.internal.handler.AstroThingHandler; +import org.openhab.binding.astro.internal.model.DistanceType; import org.openhab.binding.astro.internal.model.Eclipse; import org.openhab.binding.astro.internal.model.Moon; import org.openhab.binding.astro.internal.model.MoonPhase; @@ -102,14 +105,11 @@ public final class DailyJobMoon extends AbstractJob { } }); - cal = moon.getPerigee().getDate(); - if (cal != null) { - scheduleEvent(handler, cal, EVENT_PERIGEE, EVENT_CHANNEL_ID_PERIGEE, false, zone, locale); - } - cal = moon.getApogee().getDate(); - if (cal != null) { - scheduleEvent(handler, cal, EVENT_APOGEE, EVENT_CHANNEL_ID_APOGEE, false, zone, locale); - } + Set.of(DistanceType.APOGEE, DistanceType.PERIGEE).forEach(type -> { + if (moon.getDistanceType(type).getDate() instanceof Instant theMoment) { + scheduleEvent(handler, theMoment, type.toString(), type.eventName(), false, zone, locale); + } + }); } catch (Exception e) { LOGGER.warn("The daily moon job execution for \"{}\" failed: {}", handler.getThing().getUID(), e.getMessage()); diff --git a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/job/Job.java b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/job/Job.java index 915130444f..9100d8c877 100644 --- a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/job/Job.java +++ b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/job/Job.java @@ -18,6 +18,8 @@ import static org.openhab.binding.astro.internal.util.DateTimeUtils.*; import java.lang.invoke.MethodHandles; import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.Calendar; import java.util.List; import java.util.Locale; @@ -76,14 +78,26 @@ public interface Job extends SchedulerRunnable, Runnable { * @param job the {@link Job} instance to schedule * @param eventAt the {@link Instant} instance denoting scheduled instant */ - static void schedule(AstroThingHandler astroHandler, Job job, Instant eventAt) { - try { + static void schedule(AstroThingHandler astroHandler, Job job, Instant eventAt, ZoneId zone) { + ZonedDateTime now = ZonedDateTime.now(zone); + ZonedDateTime eventZDT = eventAt.atZone(zone); + + if (isSameDay(eventZDT, now) && isTimeGreaterEquals(eventZDT, now)) { astroHandler.schedule(job, eventAt); - } catch (Exception ex) { - LOGGER.error("{}", ex.getMessage(), ex); } } + /** + * Schedules the provided {@link Job} instance + * + * @param astroHandler the {@link AstroThingHandler} instance + * @param job the {@link Job} instance to schedule + * @param eventAt the {@link Instant} instance denoting scheduled instant + */ + static void schedule(AstroThingHandler astroHandler, Job job, Instant eventAt) { + astroHandler.schedule(job, eventAt); + } + /** * Schedules an {@link EventJob} instance * @@ -97,6 +111,19 @@ public interface Job extends SchedulerRunnable, Runnable { scheduleEvent(astroHandler, eventAt, List.of(event), channelId, configAlreadyApplied, zone, locale); } + /** + * Schedules an {@link EventJob} instance + * + * @param astroHandler the {@link AstroThingHandler} instance + * @param eventAt the {@link Instant} instance denoting scheduled instant + * @param event the event ID + * @param channelId the channel ID + */ + static void scheduleEvent(AstroThingHandler astroHandler, Instant eventAt, String event, String channelId, + boolean configAlreadyApplied, TimeZone zone, Locale locale) { + scheduleEvent(astroHandler, eventAt, List.of(event), channelId, configAlreadyApplied, zone, locale); + } + /** * Schedules an {@link EventJob} instance * @@ -126,6 +153,35 @@ public interface Job extends SchedulerRunnable, Runnable { schedule(astroHandler, new CompositeJob(astroHandler, jobs), instant, zone, locale); } + /** + * Schedules an {@link EventJob} instance + * + * @param astroHandler the {@link AstroThingHandler} instance + * @param eventAt the {@link Instant} instance denoting scheduled instant + * @param events the event IDs to schedule + * @param channelId the channel ID + */ + static void scheduleEvent(AstroThingHandler astroHandler, Instant eventAt, List events, String channelId, + boolean configAlreadyApplied, TimeZone zone, Locale locale) { + if (events.isEmpty()) { + return; + } + final Instant instant; + if (!configAlreadyApplied) { + final Channel channel = astroHandler.getThing().getChannel(channelId); + if (channel == null) { + LOGGER.warn("Cannot find channel '{}' for thing '{}'.", channelId, astroHandler.getThing().getUID()); + return; + } + AstroChannelConfig config = channel.getConfiguration().as(AstroChannelConfig.class); + instant = applyConfig(eventAt, config); + } else { + instant = eventAt; + } + List jobs = events.stream().map(e -> new EventJob(astroHandler, channelId, e)).collect(toList()); + schedule(astroHandler, new CompositeJob(astroHandler, jobs), instant, zone.toZoneId()); + } + /** * Schedules {@link Channel} events * diff --git a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/model/DistanceType.java b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/model/DistanceType.java new file mode 100644 index 0000000000..b0db9d3bba --- /dev/null +++ b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/model/DistanceType.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2010-2026 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.astro.internal.model; + +import java.util.Locale; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Various types of observed distances + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public enum DistanceType { + APOGEE, + PERIGEE, + CURRENT; + + public String eventName() { + return this.name().toLowerCase(Locale.ROOT) + "#event"; + } +} diff --git a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/model/Moon.java b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/model/Moon.java index ca13f70d0a..5240f7033b 100644 --- a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/model/Moon.java +++ b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/model/Moon.java @@ -12,6 +12,11 @@ */ package org.openhab.binding.astro.internal.model; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + import org.eclipse.jdt.annotation.NonNullByDefault; /** @@ -21,14 +26,17 @@ import org.eclipse.jdt.annotation.NonNullByDefault; */ @NonNullByDefault public class Moon extends RiseSet implements Planet { + private final Map distances = new HashMap<>(DistanceType.values().length); + private MoonPhase phase = new MoonPhase(); - private MoonDistance apogee = new MoonDistance(); - private MoonDistance perigee = new MoonDistance(); - private MoonDistance distance = new MoonDistance(); private Eclipse eclipse = new Eclipse(EclipseKind.PARTIAL, EclipseKind.TOTAL); private Position position = new Position(); private Zodiac zodiac = Zodiac.NULL; + public Moon() { + EnumSet.allOf(DistanceType.class).forEach(d -> distances.put(d, MoonDistance.NULL)); + } + /** * Returns the moon phase. */ @@ -43,32 +51,26 @@ public class Moon extends RiseSet implements Planet { this.phase = phase; } + public MoonDistance getDistanceType(DistanceType type) { + return Objects.requireNonNull(distances.get(type)); + } + /** * Returns the apogee. */ public MoonDistance getApogee() { - return apogee; - } - - /** - * Sets the apogee. - */ - public void setApogee(MoonDistance apogee) { - this.apogee = apogee; + return getDistanceType(DistanceType.APOGEE); } /** * Returns the perigee. */ public MoonDistance getPerigee() { - return perigee; + return getDistanceType(DistanceType.PERIGEE); } - /** - * Sets the perigee. - */ - public void setPerigee(MoonDistance perigee) { - this.perigee = perigee; + public void setDistance(DistanceType type, MoonDistance moonDistance) { + distances.put(type, moonDistance); } /** @@ -89,14 +91,7 @@ public class Moon extends RiseSet implements Planet { * Returns the current distance. */ public MoonDistance getDistance() { - return distance; - } - - /** - * Sets the current distance. - */ - public void setDistance(MoonDistance distance) { - this.distance = distance; + return getDistanceType(DistanceType.CURRENT); } /** diff --git a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/model/MoonDistance.java b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/model/MoonDistance.java index ed3105e5b2..5af8c92e5d 100644 --- a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/model/MoonDistance.java +++ b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/model/MoonDistance.java @@ -12,55 +12,53 @@ */ package org.openhab.binding.astro.internal.model; -import static org.openhab.core.library.unit.MetricPrefix.KILO; import static org.openhab.core.library.unit.SIUnits.METRE; -import java.util.Calendar; +import java.time.Instant; import javax.measure.quantity.Length; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.astro.internal.util.DateTimeUtils; import org.openhab.core.library.types.QuantityType; /** - * Holds a distance informations. + * Holds a distance information. * * @author Gerhard Riegler - Initial contribution * @author Christoph Weitkamp - Introduced UoM + * @author Gaël L'hopital - Use Instant, made immutable */ @NonNullByDefault public class MoonDistance { + public static final MoonDistance NULL = new MoonDistance(); - private @Nullable Calendar date; - private double distance; + private final @Nullable Instant date; + private final double distance; + + private MoonDistance() { + this.date = null; + this.distance = Double.NaN; + } + + public MoonDistance(double distanceJd, double distance) { + this.date = DateTimeUtils.jdToInstant(distanceJd); + this.distance = distance; + } /** * Returns the date of the calculated distance. */ @Nullable - public Calendar getDate() { + public Instant getDate() { return date; } /** - * Sets the date of the calculated distance. + * Returns the distance in metres. */ - public void setDate(@Nullable Calendar date) { - this.date = date; - } - - /** - * Returns the distance in kilometers. - */ - public QuantityType getDistance() { - return new QuantityType<>(distance, KILO(METRE)); - } - - /** - * Sets the distance in kilometers. - */ - public void setDistance(double kilometer) { - this.distance = kilometer; + public @Nullable QuantityType getDistance() { + return Double.isNaN(distance) ? null : new QuantityType<>(distance, METRE); } } diff --git a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/util/AstroConstants.java b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/util/AstroConstants.java index 0c2fa68f94..170a45c7b4 100644 --- a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/util/AstroConstants.java +++ b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/util/AstroConstants.java @@ -27,6 +27,9 @@ public class AstroConstants { public static final double TROPICAL_YEAR_SECONDS = TROPICAL_YEAR_DAYS * SECONDS_PER_DAY; public static final double SOLAR_MEAN_MOTION_PER_SECOND = MathUtils.TWO_PI / AstroConstants.TROPICAL_YEAR_SECONDS; + /** Constant term of the E5 angle. */ + public static final double E05_0 = 357.52910918; + /** Constructor */ private AstroConstants() { throw new IllegalAccessError("Non-instantiable"); diff --git a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/util/DateTimeUtils.java b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/util/DateTimeUtils.java index 574f43e1be..310d416403 100644 --- a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/util/DateTimeUtils.java +++ b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/util/DateTimeUtils.java @@ -13,6 +13,7 @@ package org.openhab.binding.astro.internal.util; import java.time.Instant; +import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; import java.util.Calendar; import java.util.Locale; @@ -205,6 +206,14 @@ public class DateTimeUtils { && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR); } + /** + * Returns true, if two ZonedDateTime objects are on the same day ignoring time. + */ + public static boolean isSameDay(@Nullable ZonedDateTime zdt1, @Nullable ZonedDateTime zdt2) { + return zdt1 != null && zdt2 != null + && zdt1.toLocalDate().equals(zdt2.withZoneSameInstant(zdt1.getZone()).toLocalDate()); + } + /** * Returns the next Calendar from today. */ @@ -245,6 +254,15 @@ public class DateTimeUtils { return truncCal1.getTimeInMillis() >= truncCal2.getTimeInMillis(); } + /** + * Returns true, if inst1 is greater or equal than inst2, ignoring seconds. + */ + public static boolean isTimeGreaterEquals(ZonedDateTime inst1, ZonedDateTime inst2) { + ZonedDateTime truncInst1 = inst1.truncatedTo(ChronoUnit.MINUTES); + ZonedDateTime truncInst2 = inst2.truncatedTo(ChronoUnit.MINUTES); + return !truncInst1.isBefore(truncInst2); + } + public static Calendar getAdjustedEarliest(Calendar cal, AstroChannelConfig config) { int minutes = getMinutesFromTime(config.earliest); // MainUI sets earliest to 00:00 if unconfigured, which is why zero must be treated as such diff --git a/bundles/org.openhab.binding.astro/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.openhab.binding.astro/src/main/resources/OH-INF/thing/channels.xml index b367022f4d..ab53ea1857 100644 --- a/bundles/org.openhab.binding.astro/src/main/resources/OH-INF/thing/channels.xml +++ b/bundles/org.openhab.binding.astro/src/main/resources/OH-INF/thing/channels.xml @@ -113,6 +113,7 @@ DateTime The start time of the event + calendar Calculation Timestamp @@ -125,6 +126,7 @@ DateTime The end time of the event + calendar Calculation Timestamp @@ -312,6 +314,7 @@ DateTime The DateTime of the next total eclipse + calendar Calculation Timestamp @@ -323,6 +326,7 @@ DateTime The DateTime of the next partial eclipse + calendar Calculation Timestamp @@ -334,6 +338,7 @@ DateTime The DateTime of the next ring eclipse + calendar Calculation Timestamp @@ -411,6 +416,7 @@ DateTime The DateTime the moon is in the first quarter + calendar Calculation Timestamp @@ -422,6 +428,7 @@ DateTime The DateTime the moon is in the third quarter + calendar Calculation Timestamp @@ -433,6 +440,7 @@ DateTime The DateTime for full moon + calendar Calculation Timestamp @@ -444,6 +452,7 @@ DateTime The DateTime for new moon + calendar Calculation Timestamp @@ -570,6 +579,7 @@ DateTime The DateTime when the distance is reached + calendar Calculation Timestamp diff --git a/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/MoonCalcTest.java b/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/MoonCalcTest.java index b7d4ec8ea6..d75bc7d6a5 100644 --- a/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/MoonCalcTest.java +++ b/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/MoonCalcTest.java @@ -48,7 +48,6 @@ public class MoonCalcTest { private static final double AMSTERDAM_LONGITUDE = 4.8978293; private static final int ACCURACY_IN_MILLIS = 5 * 60 * 1000; - private static final int ACCURACY_IN_KILOMETRES = 4; private static final double ACCURACY_IN_DEGREE = 0.3; private @Nullable MoonCalc moonCalc; @@ -79,33 +78,6 @@ public class MoonCalcTest { assertNull(moon.getPhase().getName()); } - @Test - public void testGetMoonInfoForApogeeAccuracy() { - Moon moon = Objects.requireNonNull(moonCalc).getMoonInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, - TIME_ZONE, Locale.ROOT); - - // expected result from haevens-above.com is 406,391 km @ 04 March 2019 12:27 - assertEquals(406391, moon.getApogee().getDistance().doubleValue(), ACCURACY_IN_KILOMETRES); - Calendar apogeeDate = moon.getApogee().getDate(); - assertNotNull(apogeeDate); - assertEquals(MoonCalcTest.newCalendar(2019, Calendar.MARCH, 4, 12, 27, TIME_ZONE).getTimeInMillis(), - apogeeDate.getTimeInMillis(), ACCURACY_IN_MILLIS); - } - - @Test - public void testGetMoonInfoForPerigeeAccuracy() { - Moon moon = Objects.requireNonNull(moonCalc).getMoonInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, - TIME_ZONE, Locale.ROOT); - - // expected result from haevens-above.com is 359,377 km @ 19 February 2019 20:44 - assertEquals(359377, moon.getPerigee().getDistance().doubleValue(), ACCURACY_IN_KILOMETRES); - - Calendar perigeeDate = moon.getPerigee().getDate(); - assertNotNull(perigeeDate); - assertEquals(MoonCalcTest.newCalendar(2019, Calendar.MARCH, 19, 20, 48, TIME_ZONE).getTimeInMillis(), - perigeeDate.getTimeInMillis(), ACCURACY_IN_MILLIS); - } - @Test public void testGetMoonInfoForRiseAccuracy() { Moon moon = Objects.requireNonNull(moonCalc).getMoonInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, @@ -113,7 +85,7 @@ public class MoonCalcTest { Calendar riseStart = moon.getRise().getStart(); assertNotNull(riseStart); - // expected result from haevens-above.com is 03:00 + // expected result from heavens-above.com is 03:00 assertEquals(MoonCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 3, 0, TIME_ZONE).getTimeInMillis(), riseStart.getTimeInMillis(), ACCURACY_IN_MILLIS); } @@ -125,7 +97,7 @@ public class MoonCalcTest { Calendar setStart = moon.getSet().getStart(); assertNotNull(setStart); - // expected result from haevens-above.com is 11:35 + // expected result from heavens-above.com is 11:35 assertEquals(MoonCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 11, 35, TIME_ZONE).getTimeInMillis(), setStart.getTimeInMillis(), ACCURACY_IN_MILLIS); } @@ -137,22 +109,11 @@ public class MoonCalcTest { Moon moon = moonCalc.getMoonInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, TIME_ZONE, Locale.ROOT); moonCalc.setPositionalInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, moon, TIME_ZONE, Locale.ROOT); - // expected result from haevens-above.com is Azimuth: 100.5, altitude -17 + // expected result from heavens-above.com is Azimuth: 100.5, altitude -17 assertEquals(100.5, moon.getPosition().getAzimuth().doubleValue(), ACCURACY_IN_DEGREE); assertEquals(-17, moon.getPosition().getElevation().doubleValue(), ACCURACY_IN_DEGREE); } - @Test - public void testGetMoonInfoForMoonDistanceAccuracy() { - MoonCalc moonCalc = this.moonCalc; - assertNotNull(moonCalc); - Moon moon = moonCalc.getMoonInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, TIME_ZONE, Locale.ROOT); - moonCalc.setPositionalInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, moon, TIME_ZONE, Locale.ROOT); - - // expected result from haevens-above.com is 392612 km - assertEquals(392612, moon.getDistance().getDistance().doubleValue(), ACCURACY_IN_KILOMETRES); - } - @Test public void testGetMoonInfoForMoonPhaseAccuracy() { MoonCalc moonCalc = this.moonCalc; diff --git a/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/MoonDistanceCalcTest.java b/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/MoonDistanceCalcTest.java new file mode 100644 index 0000000000..a0be55227b --- /dev/null +++ b/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/MoonDistanceCalcTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2010-2026 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.astro.internal.calc; + +import static org.junit.jupiter.api.Assertions.*; +import static org.openhab.core.library.unit.MetricPrefix.KILO; +import static org.openhab.core.library.unit.SIUnits.METRE; + +import java.time.Instant; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.TimeZone; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.binding.astro.internal.model.DistanceType; +import org.openhab.binding.astro.internal.model.MoonDistance; +import org.openhab.binding.astro.internal.util.DateTimeUtils; + +/*** + * Specific unit tests to check if {@link MoonCalc} generates correct data for + * Amsterdam city on 27 February 2019. In particular the following cases are + * covered: + *
    + *
  • checks if generated data are the same (with some accuracy) as produced by + * heavens-above.com
  • + *
+ * + * @author Leo Siepel - Initial contribution + * @see Heavens Above Moon + */ +@NonNullByDefault +public class MoonDistanceCalcTest { + + private static final TimeZone TIME_ZONE = TimeZone.getTimeZone("Europe/Amsterdam"); + private static final Calendar FEB_27_2019 = newCalendar(2019, Calendar.FEBRUARY, 27, 1, 0, TIME_ZONE); + + private static final int ACCURACY_IN_MILLIS = 5 * 60 * 1000; + private static final int ACCURACY_IN_KILOMETRES = 4; + + @Test + public void testGetMoonInfoForApogeeAccuracy() { + double jdate = DateTimeUtils.dateToJulianDate(FEB_27_2019); + MoonDistance distance = MoonDistanceCalc.get(DistanceType.APOGEE, jdate); + + // expected result from heavens-above.com is 406,391 km @ 04 March 2019 12:27 + var apogeeDistance = distance.getDistance(); + assertNotNull(apogeeDistance); + var kmDistance = apogeeDistance.toUnit(KILO(METRE)); + assertNotNull(kmDistance); + assertEquals(406391, kmDistance.doubleValue(), ACCURACY_IN_KILOMETRES); + Instant apogeeDate = distance.getDate(); + assertNotNull(apogeeDate); + assertEquals(newCalendar(2019, Calendar.MARCH, 4, 12, 27, TIME_ZONE).getTimeInMillis(), + apogeeDate.toEpochMilli(), ACCURACY_IN_MILLIS); + } + + @Test + public void testGetMoonInfoForPerigeeAccuracy() { + double jdate = DateTimeUtils.dateToJulianDate(FEB_27_2019); + MoonDistance distance = MoonDistanceCalc.get(DistanceType.PERIGEE, jdate); + + // expected result from heavens-above.com is 359,377 km @ 19 February 2019 20:44 + var perigeeDistance = distance.getDistance(); + assertNotNull(perigeeDistance); + var kmDistance = perigeeDistance.toUnit(KILO(METRE)); + assertNotNull(kmDistance); + assertEquals(359377, kmDistance.doubleValue(), ACCURACY_IN_KILOMETRES); + + Instant perigeeDate = distance.getDate(); + assertNotNull(perigeeDate); + assertEquals(newCalendar(2019, Calendar.MARCH, 19, 20, 48, TIME_ZONE).getTimeInMillis(), + perigeeDate.toEpochMilli(), ACCURACY_IN_MILLIS); + } + + @Test + public void testGetMoonInfoForMoonDistanceAccuracy() { + double jdate = DateTimeUtils.dateToJulianDate(FEB_27_2019); + MoonDistance distance = MoonDistanceCalc.calculate(jdate); + + // expected result from heavens-above.com is 392612 km + var currentDistance = distance.getDistance(); + assertNotNull(currentDistance); + var kmDistance = currentDistance.toUnit(KILO(METRE)); + assertNotNull(kmDistance); + assertEquals(392612, kmDistance.doubleValue(), ACCURACY_IN_KILOMETRES); + } + + /*** + * Constructs a GregorianCalendar with the given date and time set + * for the provided time zone. + * + * @param year + * the value used to set the YEAR calendar field in the + * calendar. + * @param month + * the value used to set the MONTH calendar field in the + * calendar. Month value is 0-based. e.g., 0 for January. + * @param dayOfMonth + * the value used to set the DAY_OF_MONTH calendar field + * in the calendar. + * @param hourOfDay + * the value used to set the HOUR_OF_DAY calendar field + * in the calendar. + * @param minute + * the value used to set the MINUTE calendar field in + * the calendar. + * @param zone + * the given time zone. + * @return a {@link Calendar} set to the given date and time in the specified + * time zone, truncated to minute precision. + */ + private static Calendar newCalendar(int year, int month, int dayOfMonth, int hourOfDay, int minute, TimeZone zone) { + Calendar result = new GregorianCalendar(zone, Locale.ROOT); + result.set(year, month, dayOfMonth, hourOfDay, minute); + + return DateTimeUtils.truncateToMinute(result); + } +} diff --git a/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/SunCalcTest.java b/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/SunCalcTest.java index d47743a982..0d1202bba8 100644 --- a/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/SunCalcTest.java +++ b/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/SunCalcTest.java @@ -36,7 +36,7 @@ import org.openhab.binding.astro.internal.util.DateTimeUtils; * covered: *
    *
  • checks if generated data are the same (with some accuracy) as produced by - * haevens-above.com
  • + * heavens-above.com *
  • checks if the generated {@link Sun#getAllRanges()} are consistent with * each other
  • *
@@ -102,7 +102,7 @@ public class SunCalcTest { assertNotNull(range); Calendar cal = range.getStart(); assertNotNull(cal); - // expected result from haevens-above.com is 27 Feb 2019 05:39 till 06:18 + // expected result from heavens-above.com is 27 Feb 2019 05:39 till 06:18 assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 5, 39, AMSTERDAM_TIME_ZONE).getTimeInMillis(), cal.getTimeInMillis(), ACCURACY_IN_MILLIS); cal = range.getEnd(); @@ -120,7 +120,7 @@ public class SunCalcTest { assertNotNull(range); Calendar cal = range.getStart(); assertNotNull(cal); - // expected result from haevens-above.com is 27 Feb 2019 06:18 till 06:58 + // expected result from heavens-above.com is 27 Feb 2019 06:18 till 06:58 assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 6, 18, AMSTERDAM_TIME_ZONE).getTimeInMillis(), cal.getTimeInMillis(), ACCURACY_IN_MILLIS); cal = range.getEnd(); @@ -138,7 +138,7 @@ public class SunCalcTest { assertNotNull(range); Calendar cal = range.getStart(); assertNotNull(cal); - // expected result from haevens-above.com is 27 Feb 2019 06:58 till 07:32 + // expected result from heavens-above.com is 27 Feb 2019 06:58 till 07:32 assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 6, 58, AMSTERDAM_TIME_ZONE).getTimeInMillis(), cal.getTimeInMillis(), ACCURACY_IN_MILLIS); cal = range.getEnd(); @@ -156,7 +156,7 @@ public class SunCalcTest { assertNotNull(range); Calendar cal = range.getStart(); assertNotNull(cal); - // expected result from haevens-above.com is 27 Feb 2019 07:32 + // expected result from heavens-above.com is 27 Feb 2019 07:32 assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 7, 32, AMSTERDAM_TIME_ZONE).getTimeInMillis(), cal.getTimeInMillis(), ACCURACY_IN_MILLIS); } @@ -170,7 +170,7 @@ public class SunCalcTest { assertNotNull(range); Calendar cal = range.getStart(); assertNotNull(cal); - // expected result from haevens-above.com is 27 Feb 2019 12:54 + // expected result from heavens-above.com is 27 Feb 2019 12:54 assertEquals( SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 12, 54, AMSTERDAM_TIME_ZONE).getTimeInMillis(), cal.getTimeInMillis(), ACCURACY_IN_MILLIS); @@ -185,7 +185,7 @@ public class SunCalcTest { assertNotNull(range); Calendar cal = range.getStart(); assertNotNull(cal); - // expected result from haevens-above.com is 27 Feb 2019 18:15 + // expected result from heavens-above.com is 27 Feb 2019 18:15 assertEquals( SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 18, 15, AMSTERDAM_TIME_ZONE).getTimeInMillis(), cal.getTimeInMillis(), ACCURACY_IN_MILLIS); @@ -200,7 +200,7 @@ public class SunCalcTest { assertNotNull(range); Calendar cal = range.getStart(); assertNotNull(cal); - // expected result from haevens-above.com is 27 Feb 2019 18:15 till 18:50 + // expected result from heavens-above.com is 27 Feb 2019 18:15 till 18:50 assertEquals( SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 18, 15, AMSTERDAM_TIME_ZONE).getTimeInMillis(), cal.getTimeInMillis(), ACCURACY_IN_MILLIS); @@ -220,7 +220,7 @@ public class SunCalcTest { assertNotNull(range); Calendar cal = range.getStart(); assertNotNull(cal); - // expected result from haevens-above.com is 27 Feb 2019 18:50 till 19:29 + // expected result from heavens-above.com is 27 Feb 2019 18:50 till 19:29 assertEquals( SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 18, 50, AMSTERDAM_TIME_ZONE).getTimeInMillis(), cal.getTimeInMillis(), ACCURACY_IN_MILLIS); @@ -240,7 +240,7 @@ public class SunCalcTest { assertNotNull(range); Calendar cal = range.getStart(); assertNotNull(cal); - // expected result from haevens-above.com is 27 Feb 2019 19:29 till 20:09 + // expected result from heavens-above.com is 27 Feb 2019 19:29 till 20:09 assertEquals( SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 19, 29, AMSTERDAM_TIME_ZONE).getTimeInMillis(), cal.getTimeInMillis(), ACCURACY_IN_MILLIS); diff --git a/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/zodiac/MoonZodiacCalcTest.java b/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/zodiac/MoonZodiacCalcTest.java index 6736c6e3c9..cd987bac21 100644 --- a/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/zodiac/MoonZodiacCalcTest.java +++ b/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/zodiac/MoonZodiacCalcTest.java @@ -34,7 +34,7 @@ import org.openhab.binding.astro.internal.util.DateTimeUtils; * covered: *
    *
  • checks if generated data are the same (with some accuracy) as produced by - * haevens-above.com
  • + * heavens-above.com *
* * @author Leo Siepel - Initial contribution