[astro] Switching radiation to immutable and Instant (#19949)

* Switching radiation to immutable and Instant

Signed-off-by: clinique <gael@lhopital.org>
This commit is contained in:
Gaël L'hopital
2026-01-04 23:13:32 +01:00
committed by GitHub
parent 1663f77a1d
commit 120b077d1f
7 changed files with 93 additions and 76 deletions
@@ -51,9 +51,10 @@ import org.slf4j.LoggerFactory;
public class AstroActions implements ThingActions {
private final Logger logger = LoggerFactory.getLogger(AstroActions.class);
private @Nullable AstroThingHandler handler;
private final TimeZoneProvider timeZoneProvider;
private @Nullable AstroThingHandler handler;
@Activate
public AstroActions(@Reference TimeZoneProvider timeZoneProvider) {
this.timeZoneProvider = timeZoneProvider;
@@ -0,0 +1,57 @@
/*
* 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 java.time.LocalDate;
import java.time.ZonedDateTime;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.astro.internal.model.Radiation;
import org.openhab.binding.astro.internal.util.MathUtils;
/**
* Calculates the color temperature and brightness depending upon sun positional information
*
* @author Gaël L'hopital - Initial contribution
*/
@NonNullByDefault
public class RadiationCalc {
private static final double SC = 1367; // Solar constant in W/m²
public static Radiation calculate(ZonedDateTime now, double elevation, @Nullable Double altitude) {
double altitudeRatio = (altitude != null) ? 1 / Math.pow((1 - (6.5 / 288) * (altitude / 1000.0)), 5.256) : 1;
double sinAlpha = MathUtils.sinDeg(elevation);
LocalDate date = now.toLocalDate();
int dayOfYear = date.getDayOfYear();
int daysInYear = date.lengthOfYear(); // 365 or 366
// Direct Solar Radiation (in W/m²) at the atmosphere entry
// At sunrise/sunset - calculations limits are reached
double rOut = (elevation > 3 ? SC * (0.034 * Math.cos(MathUtils.TWO_PI * dayOfYear / daysInYear) + 1) : 0)
* sinAlpha;
// 0.6 = transmissivity coefficient
double m = Math.pow(0.6, (Math.sqrt(1229 + Math.pow(614 * sinAlpha, 2)) - 614 * sinAlpha) * altitudeRatio);
// Direct radiation after atmospheric layer
double rDir = rOut * m;
// Diffuse Radiation
double rDiff = rOut * (0.271 - 0.294 * m);
return new Radiation(rDir, rDiff);
}
}
@@ -28,7 +28,6 @@ import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.astro.internal.model.Eclipse;
import org.openhab.binding.astro.internal.model.EclipseType;
import org.openhab.binding.astro.internal.model.Position;
import org.openhab.binding.astro.internal.model.Radiation;
import org.openhab.binding.astro.internal.model.Range;
import org.openhab.binding.astro.internal.model.Season;
import org.openhab.binding.astro.internal.model.Sun;
@@ -45,9 +44,6 @@ import org.openhab.binding.astro.internal.util.MathUtils;
*/
@NonNullByDefault
public class SunCalc {
private static final double J2000 = 2451545.0;
private static final double SC = 1367; // Solar constant in W/m²
private static final double M0 = Math.toRadians(357.5291);
private static final double M1 = Math.toRadians(0.98560028);
private static final double J0 = 0.0009;
@@ -93,37 +89,6 @@ public class SunCalc {
position.setAzimuth(azimuth + 180);
position.setElevation(elevation);
position.setShadeLength(shadeLength);
setRadiationInfo(calendar, elevation, altitude, sun);
}
/**
* Calculates sun radiation data.
*/
private void setRadiationInfo(Calendar calendar, double elevation, @Nullable Double altitude, Sun sun) {
double sinAlpha = MathUtils.sinDeg(elevation);
int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
int daysInYear = calendar.getActualMaximum(Calendar.DAY_OF_YEAR);
// Direct Solar Radiation (in W/m²) at the atmosphere entry
// At sunrise/sunset - calculations limits are reached
double rOut = (elevation > 3) ? SC * (0.034 * MathUtils.cosDeg(360 * dayOfYear / daysInYear) + 1) : 0;
double altitudeRatio = (altitude != null) ? 1 / Math.pow((1 - (6.5 / 288) * (altitude / 1000.0)), 5.256) : 1;
double m = (Math.sqrt(1229 + Math.pow(614 * sinAlpha, 2)) - 614 * sinAlpha) * altitudeRatio;
// Direct radiation after atmospheric layer
// 0.6 = Coefficient de transmissivité
double rDir = rOut * Math.pow(0.6, m) * sinAlpha;
// Diffuse Radiation
double rDiff = rOut * (0.271 - 0.294 * Math.pow(0.6, m)) * sinAlpha;
double rTot = rDir + rDiff;
Radiation radiation = sun.getRadiation();
radiation.setDirect(rDir);
radiation.setDiffuse(rDiff);
radiation.setTotal(rTot);
}
/**
@@ -306,15 +271,15 @@ public class SunCalc {
// all the following methods are translated to java based on the javascript
// calculations of http://www.suncalc.net
private double getJulianCycle(double j, double lw) {
return Math.round(j - J2000 - J0 - lw / MathUtils.TWO_PI);
return Math.round(j - DateTimeUtils.JD_J2000 - J0 - lw / MathUtils.TWO_PI);
}
private double getApproxSolarTransit(double ht, double lw, double n) {
return J2000 + J0 + (ht + lw) / MathUtils.TWO_PI + n;
return DateTimeUtils.JD_J2000 + J0 + (ht + lw) / MathUtils.TWO_PI + n;
}
private double getSolarMeanAnomaly(double js) {
return M0 + M1 * (js - J2000);
return M0 + M1 * (js - DateTimeUtils.JD_J2000);
}
private double getEquationOfCenter(double m) {
@@ -338,7 +303,7 @@ public class SunCalc {
}
private double getSiderealTime(double j, double lw) {
return TH0 + TH1 * (j - J2000) - lw;
return TH0 + TH1 * (j - DateTimeUtils.JD_J2000) - lw;
}
private double getAzimuth(double th, double a, double phi, double d) {
@@ -19,6 +19,7 @@ import static org.openhab.core.types.RefreshType.REFRESH;
import java.lang.invoke.MethodHandles;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
@@ -344,7 +345,9 @@ public abstract class AstroThingHandler extends BaseThingHandler {
public void schedule(Job job, Instant eventAt) {
long sleepTime = Instant.now().until(eventAt, ChronoUnit.MILLIS);
schedule(job, sleepTime);
logger.debug("Scheduled {} in {}ms (at {})", job, sleepTime, eventAt);
if (logger.isDebugEnabled()) {
logger.debug("Scheduled {} in {}ms (at {})", job, sleepTime, eventAt.atZone(ZoneId.systemDefault()));
}
}
private void tidyScheduledFutures() {
@@ -12,6 +12,7 @@
*/
package org.openhab.binding.astro.internal.handler;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Calendar;
@@ -22,6 +23,7 @@ import java.util.TimeZone;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.astro.internal.calc.CircadianCalc;
import org.openhab.binding.astro.internal.calc.RadiationCalc;
import org.openhab.binding.astro.internal.calc.SunCalc;
import org.openhab.binding.astro.internal.job.DailyJobSun;
import org.openhab.binding.astro.internal.job.Job;
@@ -68,12 +70,14 @@ public class SunHandler extends AstroThingHandler {
Double longitude = thingConfig.longitude;
Double altitude = thingConfig.altitude;
Calendar calendar = Calendar.getInstance(zone, locale);
ZonedDateTime now = Instant.now().atZone(zoneId);
sunCalc.setPositionalInfo(calendar, latitude != null ? latitude : 0, longitude != null ? longitude : 0,
altitude != null ? altitude : 0, sun);
sun.getEclipse().setElevations(this, timeZoneProvider);
sun.setCircadian(CircadianCalc.calculate(calendar, sun.getRise(), sun.getSet(), sun.getNoon()));
sun.setRadiation(RadiationCalc.calculate(now, sun.getPosition().getElevationAsDouble(), altitude));
this.sun = sun;
@@ -138,6 +142,6 @@ public class SunHandler extends AstroThingHandler {
public @Nullable Radiation getRadiationAt(ZonedDateTime date) {
Sun localSun = getPositionedSunAt(date);
return localSun.getRadiation();
return RadiationCalc.calculate(date, localSun.getPosition().getElevationAsDouble(), thingConfig.altitude);
}
}
@@ -13,9 +13,12 @@
package org.openhab.binding.astro.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.library.dimension.Intensity;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* Holds the calculated direct, diffuse and total
@@ -25,59 +28,39 @@ import org.openhab.core.library.unit.Units;
*/
@NonNullByDefault
public class Radiation {
public static final Radiation NULL = new Radiation();
private double direct;
private double diffuse;
private double total;
private final double direct;
private final double diffuse;
public Radiation() {
private Radiation() {
this(Double.NaN, Double.NaN);
}
public Radiation(double direct, double diffuse, double total) {
public Radiation(double direct, double diffuse) {
this.direct = direct;
this.diffuse = diffuse;
this.total = total;
}
/**
* Sets the direct radiation.
*/
public void setDirect(double direct) {
this.direct = direct;
}
/**
* Sets the diffuse radiation.
*/
public void setDiffuse(double diffuse) {
this.diffuse = diffuse;
}
/**
* Sets the total radiation.
*/
public void setTotal(double total) {
this.total = total;
}
/**
* Returns the total radiation.
*/
public QuantityType<Intensity> getTotal() {
return new QuantityType<>(total, Units.IRRADIANCE);
public @Nullable QuantityType<Intensity> getTotal() {
return Double.isNaN(direct) || Double.isNaN(diffuse) ? null
: new QuantityType<>(direct + diffuse, Units.IRRADIANCE);
}
/**
* Returns the direct radiation.
*/
public QuantityType<Intensity> getDirect() {
return new QuantityType<>(direct, Units.IRRADIANCE);
public State getDirect() {
return Double.isNaN(direct) ? UnDefType.UNDEF : new QuantityType<>(direct, Units.IRRADIANCE);
}
/**
* Returns the diffuse radiation.
*/
public QuantityType<Intensity> getDiffuse() {
return new QuantityType<>(diffuse, Units.IRRADIANCE);
public State getDiffuse() {
return Double.isNaN(diffuse) ? UnDefType.UNDEF : new QuantityType<>(diffuse, Units.IRRADIANCE);
}
}
@@ -36,7 +36,7 @@ public class Sun extends RiseSet implements Planet {
private Eclipse eclipse = new Eclipse(EclipseKind.PARTIAL, EclipseKind.TOTAL, EclipseKind.RING);
private Radiation radiation = new Radiation();
private Radiation radiation = Radiation.NULL;
private SunPhase phase = new SunPhase();
@@ -239,6 +239,10 @@ public class Sun extends RiseSet implements Planet {
return radiation;
}
public void setRadiation(Radiation radiation) {
this.radiation = radiation;
}
/**
* Sets the sun position.
*/